📄 inflaterinputstream.cs
字号:
this.len = (int)baseInputStream.Length;
} else {
this.len = 0;
}
}
/// <summary>
/// Returns 0 once the end of the stream (EOF) has been reached.
/// Otherwise returns 1.
/// </summary>
public virtual int Available {
get {
return inf.IsFinished ? 0 : 1;
}
}
/// <summary>
/// Closes the input stream. When <see cref="IsStreamOwner"></see>
/// is true the underlying stream is also closed.
/// </summary>
public override void Close()
{
if ( isStreamOwner ) {
baseInputStream.Close();
}
}
int readChunkSize = 0;
/// <summary>
/// Sets the size of chunks to read from the input stream
/// 0 means as larger as possible.
/// </summary>
/// <remarks>
/// Used to handle decryption where the length of stream is unknown.
/// </remarks>
protected int BufferReadSize {
get {
return readChunkSize;
}
set {
readChunkSize = value;
}
}
/// <summary>
/// Fill input buffer with a chunk of data.
/// </summary>
protected void FillInputBuffer()
{
if (readChunkSize <= 0) {
len = baseInputStream.Read(buf, 0, buf.Length);
} else {
len = baseInputStream.Read(buf, 0, readChunkSize);
}
}
/// <summary>
/// Fills the buffer with more data to decompress.
/// </summary>
/// <exception cref="SharpZipBaseException">
/// Stream ends early
/// </exception>
protected void Fill()
{
FillInputBuffer();
if (keys != null) {
DecryptBlock(buf, 0, len);
}
#if READ_SINGLE_WHEN_DECRYPTING
// This solves some decryption problems but there are still some lurking.
// At issue is exactly where the stream and decryption should finish.
if (keys == null) {
len = baseInputStream.Read(buf, 0, buf.Length);
} else {
len = baseInputStream.Read(buf, 0, 1);
}
if (keys != null) {
DecryptBlock(buf, 0, len);
}
#endif
#if STANDARD
len = baseInputStream.Read(buf, 0, buf.Length);
if (keys != null) {
DecryptBlock(buf, 0, System.Math.Min((int)(csize - inf.TotalIn), len));
}
#endif
if (len <= 0) {
throw new SharpZipBaseException("Deflated stream ends early.");
}
inf.SetInput(buf, 0, len);
}
/// <summary>
/// Reads one byte of decompressed data.
///
/// The byte is baseInputStream the lower 8 bits of the int.
/// </summary>
/// <returns>
/// The byte read cast to an int, or -1 on end of stream.
/// </returns>
public override int ReadByte()
{
int nread = Read(onebytebuffer, 0, 1); // read one byte
if (nread > 0) {
return onebytebuffer[0] & 0xff;
}
return -1; // ok
}
/// <summary>
/// Decompresses data into the byte array
/// </summary>
/// <param name ="b">
/// The array to read and decompress data into
/// </param>
/// <param name ="off">
/// The offset indicating where the data should be placed
/// </param>
/// <param name ="len">
/// The number of bytes to decompress
/// </param>
/// <returns>The number of bytes read. Zero signals the end of stream</returns>
/// <exception cref="SharpZipBaseException">
/// Inflater needs a dictionary
/// </exception>
public override int Read(byte[] b, int off, int len)
{
for (;;) {
int count;
try {
count = inf.Inflate(b, off, len);
} catch (Exception e) {
throw new SharpZipBaseException(e.ToString());
}
if (count > 0) {
return count;
}
if (inf.IsNeedingDictionary) {
throw new SharpZipBaseException("Need a dictionary");
} else if (inf.IsFinished) {
return 0;
} else if (inf.IsNeedingInput) {
Fill();
} else {
throw new InvalidOperationException("Don't know what to do");
}
}
}
/// <summary>
/// Skip specified number of bytes of uncompressed data
/// </summary>
/// <param name ="n">
/// Number of bytes to skip
/// </param>
/// <returns>
/// The number of bytes skipped, zero if the end of
/// stream has been reached
/// </returns>
/// <exception cref="ArgumentOutOfRangeException">
/// Number of bytes to skip is zero or less
/// </exception>
public long Skip(long n)
{
if (n <= 0) {
throw new ArgumentOutOfRangeException("n");
}
// v0.80 Skip by seeking if underlying stream supports it...
if (baseInputStream.CanSeek) {
baseInputStream.Seek(n, SeekOrigin.Current);
return n;
} else {
int len = 2048;
if (n < len) {
len = (int) n;
}
byte[] tmp = new byte[len];
return (long)baseInputStream.Read(tmp, 0, tmp.Length);
}
}
#region Encryption stuff
// TODO Refactor this code. The presence of Zip specific code in this low level class is wrong
/// <summary>
/// A buffer used for decrypting data. Used to hold Zip crypto header.
/// </summary>
protected byte[] cryptbuffer = null;
uint[] keys = null;
/// <summary>
/// Decrypt a single byte
/// </summary>
/// <returns>plain text byte value</returns>
protected byte DecryptByte()
{
uint temp = ((keys[2] & 0xFFFF) | 2);
return (byte)((temp * (temp ^ 1)) >> 8);
}
/// <summary>
/// Decrypt cipher text block, updating keys
/// </summary>
/// <param name="buf">Data to decrypt</param>
/// <param name="off">Offset of first byte to process</param>
/// <param name="len">Number of bytes to process</param>
protected void DecryptBlock(byte[] buf, int off, int len)
{
for (int i = off; i < off + len; ++i) {
buf[i] ^= DecryptByte();
UpdateKeys(buf[i]);
}
}
/// <summary>
/// Initialise the decryption keys
/// </summary>
/// <param name="password">The password used to initialise the keys</param>
protected void InitializePassword(string password)
{
keys = new uint[] {
0x12345678,
0x23456789,
0x34567890
};
for (int i = 0; i < password.Length; ++i) {
UpdateKeys((byte)password[i]);
}
}
/// <summary>
/// Update the decryption keys
/// </summary>
/// <param name="ch">Character to update the keys with</param>
protected void UpdateKeys(byte ch)
{
keys[0] = Crc32.ComputeCrc32(keys[0], ch);
keys[1] = keys[1] + (byte)keys[0];
keys[1] = keys[1] * 134775813 + 1;
keys[2] = Crc32.ComputeCrc32(keys[2], (byte)(keys[1] >> 24));
}
/// <summary>
/// Clear any cryptographic state.
/// </summary>
protected void StopDecrypting()
{
keys = null;
cryptbuffer = null;
}
#endregion
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -