public bool ReadGzipHeader() { while (true) { int bits; switch (gzipHeaderSubstate) { case GZIPHeaderState.ReadingID1: bits = input.GetBits(8); if (bits < 0) { return(false); } if (bits != 0x1F) { throw new InvalidDataException("SR.CorruptedGZipHeader"); } gzipHeaderSubstate = GZIPHeaderState.ReadingID2; goto case GZIPHeaderState.ReadingID2; case GZIPHeaderState.ReadingID2: bits = input.GetBits(8); if (bits < 0) { return(false); } if (bits != 0x8b) { throw new InvalidDataException("SR.CorruptedGZipHeader"); } gzipHeaderSubstate = GZIPHeaderState.ReadingCM; goto case GZIPHeaderState.ReadingCM; case GZIPHeaderState.ReadingCM: bits = input.GetBits(8); if (bits < 0) { return(false); } if (bits != 0x8) { // compression mode must be 8 (deflate) throw new InvalidDataException("SR.UnknownCompressionMode"); } gzipHeaderSubstate = GZIPHeaderState.ReadingFLG;; goto case GZIPHeaderState.ReadingFLG; case GZIPHeaderState.ReadingFLG: bits = input.GetBits(8); if (bits < 0) { return(false); } gzip_header_flag = bits; gzipHeaderSubstate = GZIPHeaderState.ReadingMMTime; loopCounter = 0; // 4 MMTIME bytes goto case GZIPHeaderState.ReadingMMTime; case GZIPHeaderState.ReadingMMTime: bits = 0; while (loopCounter < 4) { bits = input.GetBits(8); if (bits < 0) { return(false); } loopCounter++; } gzipHeaderSubstate = GZIPHeaderState.ReadingXFL; loopCounter = 0; goto case GZIPHeaderState.ReadingXFL; case GZIPHeaderState.ReadingXFL: // ignore XFL bits = input.GetBits(8); if (bits < 0) { return(false); } gzipHeaderSubstate = GZIPHeaderState.ReadingOS; goto case GZIPHeaderState.ReadingOS; case GZIPHeaderState.ReadingOS: // ignore OS bits = input.GetBits(8); if (bits < 0) { return(false); } gzipHeaderSubstate = GZIPHeaderState.ReadingXLen1; goto case GZIPHeaderState.ReadingXLen1; case GZIPHeaderState.ReadingXLen1: if ((gzip_header_flag & ExtraFieldsFlag) == 0) { goto case GZIPHeaderState.ReadingFileName; } bits = input.GetBits(8); if (bits < 0) { return(false); } gzip_header_xlen = bits; gzipHeaderSubstate = GZIPHeaderState.ReadingXLen2; goto case GZIPHeaderState.ReadingXLen2; case GZIPHeaderState.ReadingXLen2: bits = input.GetBits(8); if (bits < 0) { return(false); } gzip_header_xlen |= (bits << 8); gzipHeaderSubstate = GZIPHeaderState.ReadingXLenData; loopCounter = 0; // 0 bytes of XLEN data read so far goto case GZIPHeaderState.ReadingXLenData; case GZIPHeaderState.ReadingXLenData: bits = 0; while (loopCounter < gzip_header_xlen) { bits = input.GetBits(8); if (bits < 0) { return(false); } loopCounter++; } gzipHeaderSubstate = GZIPHeaderState.ReadingFileName; loopCounter = 0; goto case GZIPHeaderState.ReadingFileName; case GZIPHeaderState.ReadingFileName: if ((gzip_header_flag & FileNameFlag) == 0) { gzipHeaderSubstate = GZIPHeaderState.ReadingComment; goto case GZIPHeaderState.ReadingComment; } do { bits = input.GetBits(8); if (bits < 0) { return(false); } if (bits == 0) { // see '\0' in the file name string break; } } while (true); gzipHeaderSubstate = GZIPHeaderState.ReadingComment; goto case GZIPHeaderState.ReadingComment; case GZIPHeaderState.ReadingComment: if ((gzip_header_flag & CommentFlag) == 0) { gzipHeaderSubstate = GZIPHeaderState.ReadingCRC16Part1; goto case GZIPHeaderState.ReadingCRC16Part1; } do { bits = input.GetBits(8); if (bits < 0) { return(false); } if (bits == 0) { // see '\0' in the file name string break; } } while (true); gzipHeaderSubstate = GZIPHeaderState.ReadingCRC16Part1; goto case GZIPHeaderState.ReadingCRC16Part1; case GZIPHeaderState.ReadingCRC16Part1: if ((gzip_header_flag & CRCFlag) == 0) { gzipHeaderSubstate = GZIPHeaderState.Done; goto case GZIPHeaderState.Done; } bits = input.GetBits(8); // ignore crc if (bits < 0) { return(false); } gzipHeaderSubstate = GZIPHeaderState.ReadingCRC16Part2; goto case GZIPHeaderState.ReadingCRC16Part2; case GZIPHeaderState.ReadingCRC16Part2: bits = input.GetBits(8); // ignore crc if (bits < 0) { return(false); } gzipHeaderSubstate = GZIPHeaderState.Done; goto case GZIPHeaderState.Done; case GZIPHeaderState.Done: return(true); default: Debug.Assert(false, "We should not reach unknown state!"); throw new InvalidDataException("SR.UnknownState"); } } }
//Each block of compressed data begins with 3 header bits // containing the following data: // first bit BFINAL // next 2 bits BTYPE // Note that the header bits do not necessarily begin on a byte // boundary, since a block does not necessarily occupy an integral // number of bytes. // BFINAL is set if and only if this is the last block of the data // set. // BTYPE specifies how the data are compressed, as follows: // 00 - no compression // 01 - compressed with fixed Huffman codes // 10 - compressed with dynamic Huffman codes // 11 - reserved (error) // The only difference between the two compressed cases is how the // Huffman codes for the literal/length and distance alphabets are // defined. // // This function returns true for success (end of block or output window is full,) // false if we are short of input // private bool Decode() { bool eob = false; bool result = false; if (Finished()) { return true; } if (_usingGzip) { if (_state == InflaterState.ReadingGZIPHeader) { if (!_gZipDecoder.ReadGzipHeader()) { return false; } _state = InflaterState.ReadingBFinal; } else if (_state == InflaterState.StartReadingGZIPFooter || _state == InflaterState.ReadingGZIPFooter) { if (!_gZipDecoder.ReadGzipFooter()) return false; _state = InflaterState.VerifyingGZIPFooter; return true; } } if (_state == InflaterState.ReadingBFinal) { // reading bfinal bit // Need 1 bit if (!_input.EnsureBitsAvailable(1)) return false; _bfinal = _input.GetBits(1); _state = InflaterState.ReadingBType; } if (_state == InflaterState.ReadingBType) { // Need 2 bits if (!_input.EnsureBitsAvailable(2)) { _state = InflaterState.ReadingBType; return false; } blockType = (BlockType) _input.GetBits(2); if (blockType == BlockType.Dynamic) { _state = InflaterState.ReadingNumLitCodes; } else if (blockType == BlockType.Static) { _literalLengthTree = HuffmanTree.StaticLiteralLengthTree; _distanceTree = HuffmanTree.StaticDistanceTree; _state = InflaterState.DecodeTop; } else if (blockType == BlockType.Uncompressed) { _state = InflaterState.UncompressedAligning; } else { throw new InvalidDataException("SR.UnknownBlockType"); } } if (blockType == BlockType.Dynamic) { if (_state < InflaterState.DecodeTop) { // we are reading the header result = DecodeDynamicBlockHeader(); } else { result = DecodeBlock(out eob); // this can returns true when output is full } } else if (blockType == BlockType.Static) { result = DecodeBlock(out eob); } else if (blockType == BlockType.Uncompressed) { result = DecodeUncompressedBlock(out eob); } else { throw new InvalidDataException("SR.UnknownBlockType"); } // // If we reached the end of the block and the block we were decoding had // bfinal=1 (final block) // if (eob && (_bfinal != 0)) { if (_usingGzip) _state = InflaterState.StartReadingGZIPFooter; else _state = InflaterState.Done; } return result; }