75 lines
2.1 KiB
C#

// Originally copyright (c) 2009 Dino Chiesa and Microsoft Corporation.
// All rights reserved.
// See license.txt, section Ionic.Zlib license
#if __MonoCS__
using System;
using System.IO;
namespace Ionic.Zlib {
internal class DeflateStream {
ZlibCodec z;
bool _leaveOpen;
byte[] workBuffer;
Stream _stream;
public DeflateStream( Stream stream, bool leaveOpen ) {
_stream = stream;
_leaveOpen = leaveOpen;
workBuffer = new byte[16384]; // TODO: 1024 bytes?
z = new ZlibCodec();
}
public void Dispose() {
z.EndInflate();
z = null;
if( !_leaveOpen )
_stream.Dispose();
_stream = null;
}
public int Read( byte[] buffer, int offset, int count ) {
// According to MS documentation, any implementation of the IO.Stream.Read function must:
// (a) throw an exception if offset & count reference an invalid part of the buffer,
// or if count < 0, or if buffer is null
// (b) return 0 only upon EOF, or if count = 0
// (c) if not EOF, then return at least 1 byte, up to <count> bytes
if( count == 0 ) return 0;
int rc = 0;
// set up the output of the deflate/inflate codec:
z.OutputBuffer = buffer;
z.NextOut = offset;
z.AvailableBytesOut = count;
z.InputBuffer = workBuffer;
bool endOfInput = false;
do {
// need data in _workingBuffer in order to deflate/inflate. Here, we check if we have any.
if( z.AvailableBytesIn == 0 && !endOfInput ) {
// No data available, so try to Read data from the captive stream.
z.NextIn = 0;
z.AvailableBytesIn = _stream.Read(workBuffer, 0, workBuffer.Length);
if( z.AvailableBytesIn == 0 )
endOfInput = true;
}
rc = z.Inflate();
if (endOfInput && rc == RCode.BufferError)
return 0;
if (rc != RCode.Okay && rc != RCode.StreamEnd)
throw new InvalidDataException( "inflating: rc=" + rc );
if ((endOfInput || rc == RCode.StreamEnd) && z.AvailableBytesOut == count)
break; // nothing more to read
} while( z.AvailableBytesOut > 0 && !endOfInput && rc == RCode.Okay );
return count - z.AvailableBytesOut;
}
}
}
#endif