in src/ICSharpCode.SharpZipLib/GZip/GzipInputStream.cs [168:310]
private bool ReadHeader()
{
// Initialize CRC for this block
crc = new Crc32();
// Make sure there is data in file. We can't rely on ReadLeByte() to fill the buffer, as this could be EOF,
// which is fine, but ReadLeByte() throws an exception if it doesn't find data, so we do this part ourselves.
if (inputBuffer.Available <= 0)
{
inputBuffer.Fill();
if (inputBuffer.Available <= 0)
{
// No header, EOF.
return false;
}
}
var headCRC = new Crc32();
// 1. Check the two magic bytes
var magic = inputBuffer.ReadLeByte();
headCRC.Update(magic);
if (magic != GZipConstants.ID1)
{
throw new GZipException("Error GZIP header, first magic byte doesn't match");
}
magic = inputBuffer.ReadLeByte();
if (magic != GZipConstants.ID2)
{
throw new GZipException("Error GZIP header, second magic byte doesn't match");
}
headCRC.Update(magic);
// 2. Check the compression type (must be 8)
var compressionType = inputBuffer.ReadLeByte();
if (compressionType != GZipConstants.CompressionMethodDeflate)
{
throw new GZipException("Error GZIP header, data not in deflate format");
}
headCRC.Update(compressionType);
// 3. Check the flags
var flagsByte = inputBuffer.ReadLeByte();
headCRC.Update(flagsByte);
// 3.1 Check the reserved bits are zero
if ((flagsByte & 0xE0) != 0)
{
throw new GZipException("Reserved flag bits in GZIP header != 0");
}
var flags = (GZipFlags)flagsByte;
// 4.-6. Skip the modification time, extra flags, and OS type
for (int i = 0; i < 6; i++)
{
headCRC.Update(inputBuffer.ReadLeByte());
}
// 7. Read extra field
if (flags.HasFlag(GZipFlags.FEXTRA))
{
// XLEN is total length of extra subfields, we will skip them all
var len1 = inputBuffer.ReadLeByte();
var len2 = inputBuffer.ReadLeByte();
headCRC.Update(len1);
headCRC.Update(len2);
int extraLen = (len2 << 8) | len1; // gzip is LSB first
for (int i = 0; i < extraLen; i++)
{
headCRC.Update(inputBuffer.ReadLeByte());
}
}
// 8. Read file name
if (flags.HasFlag(GZipFlags.FNAME))
{
var fname = new byte[1024];
var fnamePos = 0;
int readByte;
while ((readByte = inputBuffer.ReadLeByte()) > 0)
{
if (fnamePos < 1024)
{
fname[fnamePos++] = (byte)readByte;
}
headCRC.Update(readByte);
}
headCRC.Update(readByte);
fileName = GZipConstants.Encoding.GetString(fname, 0, fnamePos);
}
else
{
fileName = null;
}
// 9. Read comment
if (flags.HasFlag(GZipFlags.FCOMMENT))
{
int readByte;
while ((readByte = inputBuffer.ReadLeByte()) > 0)
{
headCRC.Update(readByte);
}
headCRC.Update(readByte);
}
// 10. Read header CRC
if (flags.HasFlag(GZipFlags.FHCRC))
{
int tempByte;
int crcval = inputBuffer.ReadLeByte();
if (crcval < 0)
{
throw new EndOfStreamException("EOS reading GZIP header");
}
tempByte = inputBuffer.ReadLeByte();
if (tempByte < 0)
{
throw new EndOfStreamException("EOS reading GZIP header");
}
crcval = (crcval << 8) | tempByte;
if (crcval != ((int)headCRC.Value & 0xffff))
{
throw new GZipException("Header CRC value mismatch");
}
}
readGZIPHeader = true;
return true;
}