// switching to Inflater now /// <summary>Parse the gzip trailer (assuming we're in the appropriate state).</summary> /// <remarks> /// Parse the gzip trailer (assuming we're in the appropriate state). /// In order to deal with degenerate cases (e.g., user buffer is one byte /// long), we copy trailer bytes (all 8 of 'em) to a local buffer.</p> /// See http://www.ietf.org/rfc/rfc1952.txt for the gzip spec. /// </remarks> /// <exception cref="System.IO.IOException"/> private void ExecuteTrailerState() { if (userBufLen <= 0) { return; } // verify that the CRC-32 of the decompressed stream matches the value // stored in the gzip trailer if (state == BuiltInGzipDecompressor.GzipStateLabel.TrailerCrc) { // localBuf was empty before we handed off to Inflater, so we handle this // exactly like header fields System.Diagnostics.Debug.Assert((localBufOff < 4)); // initially 0, but may need multiple calls int n = Math.Min(userBufLen, 4 - localBufOff); CopyBytesToLocal(n); if (localBufOff >= 4) { long streamCRC = ReadUIntLE(localBuf, 0); if (streamCRC != crc.GetValue()) { throw new IOException("gzip stream CRC failure"); } localBufOff = 0; crc.Reset(); state = BuiltInGzipDecompressor.GzipStateLabel.TrailerSize; } } if (userBufLen <= 0) { return; } // verify that the mod-2^32 decompressed stream size matches the value // stored in the gzip trailer if (state == BuiltInGzipDecompressor.GzipStateLabel.TrailerSize) { System.Diagnostics.Debug.Assert((localBufOff < 4)); // initially 0, but may need multiple calls int n = Math.Min(userBufLen, 4 - localBufOff); CopyBytesToLocal(n); // modifies userBufLen, etc. if (localBufOff >= 4) { // should be strictly == long inputSize = ReadUIntLE(localBuf, 0); if (inputSize != (inflater.GetBytesWritten() & unchecked ((long)(0xffffffffL)))) { throw new IOException("stored gzip size doesn't match decompressed size"); } localBufOff = 0; state = BuiltInGzipDecompressor.GzipStateLabel.Finished; } } if (state == BuiltInGzipDecompressor.GzipStateLabel.Finished) { return; } }