Пример #1
0
 /// <summary>Creates a new (pure Java) gzip decompressor.</summary>
 public BuiltInGzipDecompressor()
 {
     // if read as LE short int
     // 'true' (nowrap) => Inflater will handle raw deflate stream only
     state = BuiltInGzipDecompressor.GzipStateLabel.HeaderBasic;
     crc.Reset();
 }
Пример #2
0
 // 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;
     }
 }
Пример #3
0
 /// <summary>
 /// Resets everything, including the input buffer, regardless of whether the
 /// current gzip substream is finished.</p>
 /// </summary>
 public virtual void Reset()
 {
     lock (this)
     {
         // could optionally emit INFO message if state != GzipStateLabel.FINISHED
         inflater.Reset();
         state = BuiltInGzipDecompressor.GzipStateLabel.HeaderBasic;
         crc.Reset();
         userBufOff                  = userBufLen = 0;
         localBufOff                 = 0;
         headerBytesRead             = 0;
         trailerBytesRead            = 0;
         numExtraFieldBytesRemaining = -1;
         hasExtraField               = false;
         hasFilename                 = false;
         hasComment                  = false;
         hasHeaderCRC                = false;
     }
 }
Пример #4
0
 /// <summary>Parse the gzip header (assuming we're in the appropriate state).</summary>
 /// <remarks>
 /// Parse the gzip header (assuming we're in the appropriate state).
 /// In order to deal with degenerate cases (e.g., user buffer is one byte
 /// long), we copy (some) header bytes to another buffer.  (Filename,
 /// comment, and extra-field bytes are simply skipped.)</p>
 /// See http://www.ietf.org/rfc/rfc1952.txt for the gzip spec.  Note that
 /// no version of gzip to date (at least through 1.4.0, 2010-01-20) supports
 /// the FHCRC header-CRC16 flagbit; instead, the implementation treats it
 /// as a multi-file continuation flag (which it also doesn't support). :-(
 /// Sun's JDK v6 (1.6) supports the header CRC, however, and so do we.
 /// </remarks>
 /// <exception cref="System.IO.IOException"/>
 private void ExecuteHeaderState()
 {
     // this can happen because DecompressorStream's decompress() is written
     // to call decompress() first, setInput() second:
     if (userBufLen <= 0)
     {
         return;
     }
     // "basic"/required header:  somewhere in first 10 bytes
     if (state == BuiltInGzipDecompressor.GzipStateLabel.HeaderBasic)
     {
         int n = Math.Min(userBufLen, 10 - localBufOff);
         // (or 10-headerBytesRead)
         CheckAndCopyBytesToLocal(n);
         // modifies userBufLen, etc.
         if (localBufOff >= 10)
         {
             // should be strictly ==
             ProcessBasicHeader();
             // sig, compression method, flagbits
             localBufOff = 0;
             // no further need for basic header
             state = BuiltInGzipDecompressor.GzipStateLabel.HeaderExtraField;
         }
     }
     if (userBufLen <= 0)
     {
         return;
     }
     // optional header stuff (extra field, filename, comment, header CRC)
     if (state == BuiltInGzipDecompressor.GzipStateLabel.HeaderExtraField)
     {
         if (hasExtraField)
         {
             // 2 substates:  waiting for 2 bytes => get numExtraFieldBytesRemaining,
             // or already have 2 bytes & waiting to finish skipping specified length
             if (numExtraFieldBytesRemaining < 0)
             {
                 int n = Math.Min(userBufLen, 2 - localBufOff);
                 CheckAndCopyBytesToLocal(n);
                 if (localBufOff >= 2)
                 {
                     numExtraFieldBytesRemaining = ReadUShortLE(localBuf, 0);
                     localBufOff = 0;
                 }
             }
             if (numExtraFieldBytesRemaining > 0 && userBufLen > 0)
             {
                 int n = Math.Min(userBufLen, numExtraFieldBytesRemaining);
                 CheckAndSkipBytes(n);
                 // modifies userBufLen, etc.
                 numExtraFieldBytesRemaining -= n;
             }
             if (numExtraFieldBytesRemaining == 0)
             {
                 state = BuiltInGzipDecompressor.GzipStateLabel.HeaderFilename;
             }
         }
         else
         {
             state = BuiltInGzipDecompressor.GzipStateLabel.HeaderFilename;
         }
     }
     if (userBufLen <= 0)
     {
         return;
     }
     if (state == BuiltInGzipDecompressor.GzipStateLabel.HeaderFilename)
     {
         if (hasFilename)
         {
             bool doneWithFilename = CheckAndSkipBytesUntilNull();
             if (!doneWithFilename)
             {
                 return;
             }
         }
         // exit early:  used up entire buffer without hitting NULL
         state = BuiltInGzipDecompressor.GzipStateLabel.HeaderComment;
     }
     if (userBufLen <= 0)
     {
         return;
     }
     if (state == BuiltInGzipDecompressor.GzipStateLabel.HeaderComment)
     {
         if (hasComment)
         {
             bool doneWithComment = CheckAndSkipBytesUntilNull();
             if (!doneWithComment)
             {
                 return;
             }
         }
         // exit early:  used up entire buffer
         state = BuiltInGzipDecompressor.GzipStateLabel.HeaderCrc;
     }
     if (userBufLen <= 0)
     {
         return;
     }
     if (state == BuiltInGzipDecompressor.GzipStateLabel.HeaderCrc)
     {
         if (hasHeaderCRC)
         {
             System.Diagnostics.Debug.Assert((localBufOff < 2));
             int n = Math.Min(userBufLen, 2 - localBufOff);
             CopyBytesToLocal(n);
             if (localBufOff >= 2)
             {
                 long headerCRC = ReadUShortLE(localBuf, 0);
                 if (headerCRC != (crc.GetValue() & unchecked ((int)(0xffff))))
                 {
                     throw new IOException("gzip header CRC failure");
                 }
                 localBufOff = 0;
                 crc.Reset();
                 state = BuiltInGzipDecompressor.GzipStateLabel.DeflateStream;
             }
         }
         else
         {
             crc.Reset();
             // will reuse for CRC-32 of uncompressed data
             state = BuiltInGzipDecompressor.GzipStateLabel.DeflateStream;
         }
     }
 }
Пример #5
0
 // note:  might be zero
 /// <summary>
 /// Decompress the data (gzip header, deflate stream, gzip trailer) in the
 /// provided buffer.
 /// </summary>
 /// <returns>the number of decompressed bytes placed into b</returns>
 /// <exception cref="System.IO.IOException"/>
 public virtual int Decompress(byte[] b, int off, int len)
 {
     lock (this)
     {
         /* From the caller's perspective, this is where the state machine lives.
          * The code is written such that we never return from decompress() with
          * data remaining in userBuf unless we're in FINISHED state and there was
          * data beyond the current gzip member (e.g., we're within a concatenated
          * gzip stream).  If this ever changes, {@link #needsInput()} will also
          * need to be modified (i.e., uncomment the userBufLen condition).
          *
          * The actual deflate-stream processing (decompression) is handled by
          * Java's Inflater class.  Unlike the gzip header/trailer code (execute*
          * methods below), the deflate stream is never copied; Inflater operates
          * directly on the user's buffer.
          */
         int numAvailBytes = 0;
         if (state != BuiltInGzipDecompressor.GzipStateLabel.DeflateStream)
         {
             ExecuteHeaderState();
             if (userBufLen <= 0)
             {
                 return(numAvailBytes);
             }
         }
         // "executeDeflateStreamState()"
         if (state == BuiltInGzipDecompressor.GzipStateLabel.DeflateStream)
         {
             // hand off user data (or what's left of it) to Inflater--but note that
             // Inflater may not have consumed all of previous bufferload (e.g., if
             // data highly compressed or output buffer very small), in which case
             // userBufLen will be zero
             if (userBufLen > 0)
             {
                 inflater.SetInput(userBuf, userBufOff, userBufLen);
                 userBufOff += userBufLen;
                 userBufLen  = 0;
             }
             // now decompress it into b[]
             try
             {
                 numAvailBytes = inflater.Inflate(b, off, len);
             }
             catch (SharpZipBaseException dfe)
             {
                 throw new IOException(dfe.Message);
             }
             crc.Update(b, off, numAvailBytes);
             // CRC-32 is on _uncompressed_ data
             if (inflater.IsFinished)
             {
                 state = BuiltInGzipDecompressor.GzipStateLabel.TrailerCrc;
                 int bytesRemaining = inflater.RemainingInput;
                 System.Diagnostics.Debug.Assert((bytesRemaining >= 0), "logic error: Inflater finished; byte-count is inconsistent"
                                                 );
                 // could save a copy of userBufLen at call to inflater.setInput() and
                 // verify that bytesRemaining <= origUserBufLen, but would have to
                 // be a (class) member variable...seems excessive for a sanity check
                 userBufOff -= bytesRemaining;
                 userBufLen  = bytesRemaining;
             }
             else
             {
                 // or "+=", but guaranteed 0 coming in
                 return(numAvailBytes);
             }
         }
         // minor optimization
         ExecuteTrailerState();
         return(numAvailBytes);
     }
 }