1*9573673dSchristos // 2*9573673dSchristos // � Copyright Henrik Ravn 2004 3*9573673dSchristos // 4*9573673dSchristos // Use, modification and distribution are subject to the Boost Software License, Version 1.0. 5*9573673dSchristos // (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6*9573673dSchristos // 7*9573673dSchristos 8*9573673dSchristos using System; 9*9573673dSchristos using System.Diagnostics; 10*9573673dSchristos using System.Runtime.InteropServices; 11*9573673dSchristos 12*9573673dSchristos namespace DotZLib 13*9573673dSchristos { 14*9573673dSchristos 15*9573673dSchristos /// <summary> 16*9573673dSchristos /// Implements a data compressor, using the deflate algorithm in the ZLib dll 17*9573673dSchristos /// </summary> 18*9573673dSchristos public sealed class Deflater : CodecBase 19*9573673dSchristos { 20*9573673dSchristos #region Dll imports 21*9573673dSchristos [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl, CharSet=CharSet.Ansi)] deflateInit_(ref ZStream sz, int level, string vs, int size)22*9573673dSchristos private static extern int deflateInit_(ref ZStream sz, int level, string vs, int size); 23*9573673dSchristos 24*9573673dSchristos [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)] deflate(ref ZStream sz, int flush)25*9573673dSchristos private static extern int deflate(ref ZStream sz, int flush); 26*9573673dSchristos 27*9573673dSchristos [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)] deflateReset(ref ZStream sz)28*9573673dSchristos private static extern int deflateReset(ref ZStream sz); 29*9573673dSchristos 30*9573673dSchristos [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)] deflateEnd(ref ZStream sz)31*9573673dSchristos private static extern int deflateEnd(ref ZStream sz); 32*9573673dSchristos #endregion 33*9573673dSchristos 34*9573673dSchristos /// <summary> 35*9573673dSchristos /// Constructs an new instance of the <c>Deflater</c> 36*9573673dSchristos /// </summary> 37*9573673dSchristos /// <param name="level">The compression level to use for this <c>Deflater</c></param> Deflater(CompressLevel level)38*9573673dSchristos public Deflater(CompressLevel level) : base() 39*9573673dSchristos { 40*9573673dSchristos int retval = deflateInit_(ref _ztream, (int)level, Info.Version, Marshal.SizeOf(_ztream)); 41*9573673dSchristos if (retval != 0) 42*9573673dSchristos throw new ZLibException(retval, "Could not initialize deflater"); 43*9573673dSchristos 44*9573673dSchristos resetOutput(); 45*9573673dSchristos } 46*9573673dSchristos 47*9573673dSchristos /// <summary> 48*9573673dSchristos /// Adds more data to the codec to be processed. 49*9573673dSchristos /// </summary> 50*9573673dSchristos /// <param name="data">Byte array containing the data to be added to the codec</param> 51*9573673dSchristos /// <param name="offset">The index of the first byte to add from <c>data</c></param> 52*9573673dSchristos /// <param name="count">The number of bytes to add</param> 53*9573673dSchristos /// <remarks>Adding data may, or may not, raise the <c>DataAvailable</c> event</remarks> Add(byte[] data, int offset, int count)54*9573673dSchristos public override void Add(byte[] data, int offset, int count) 55*9573673dSchristos { 56*9573673dSchristos if (data == null) throw new ArgumentNullException(); 57*9573673dSchristos if (offset < 0 || count < 0) throw new ArgumentOutOfRangeException(); 58*9573673dSchristos if ((offset+count) > data.Length) throw new ArgumentException(); 59*9573673dSchristos 60*9573673dSchristos int total = count; 61*9573673dSchristos int inputIndex = offset; 62*9573673dSchristos int err = 0; 63*9573673dSchristos 64*9573673dSchristos while (err >= 0 && inputIndex < total) 65*9573673dSchristos { 66*9573673dSchristos copyInput(data, inputIndex, Math.Min(total - inputIndex, kBufferSize)); 67*9573673dSchristos while (err >= 0 && _ztream.avail_in > 0) 68*9573673dSchristos { 69*9573673dSchristos err = deflate(ref _ztream, (int)FlushTypes.None); 70*9573673dSchristos if (err == 0) 71*9573673dSchristos while (_ztream.avail_out == 0) 72*9573673dSchristos { 73*9573673dSchristos OnDataAvailable(); 74*9573673dSchristos err = deflate(ref _ztream, (int)FlushTypes.None); 75*9573673dSchristos } 76*9573673dSchristos inputIndex += (int)_ztream.total_in; 77*9573673dSchristos } 78*9573673dSchristos } 79*9573673dSchristos setChecksum( _ztream.adler ); 80*9573673dSchristos } 81*9573673dSchristos 82*9573673dSchristos 83*9573673dSchristos /// <summary> 84*9573673dSchristos /// Finishes up any pending data that needs to be processed and handled. 85*9573673dSchristos /// </summary> Finish()86*9573673dSchristos public override void Finish() 87*9573673dSchristos { 88*9573673dSchristos int err; 89*9573673dSchristos do 90*9573673dSchristos { 91*9573673dSchristos err = deflate(ref _ztream, (int)FlushTypes.Finish); 92*9573673dSchristos OnDataAvailable(); 93*9573673dSchristos } 94*9573673dSchristos while (err == 0); 95*9573673dSchristos setChecksum( _ztream.adler ); 96*9573673dSchristos deflateReset(ref _ztream); 97*9573673dSchristos resetOutput(); 98*9573673dSchristos } 99*9573673dSchristos 100*9573673dSchristos /// <summary> 101*9573673dSchristos /// Closes the internal zlib deflate stream 102*9573673dSchristos /// </summary> CleanUp()103*9573673dSchristos protected override void CleanUp() { deflateEnd(ref _ztream); } 104*9573673dSchristos 105*9573673dSchristos } 106*9573673dSchristos } 107