// 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 Close() { z.EndInflate(); z = null; if( !_leaveOpen ) _stream.Close(); _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 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