using System; namespace ICSharpCode.SharpZipLib.Zip.Compression { /// /// This class is general purpose class for writing data to a buffer. /// /// It allows you to write bits as well as bytes /// Based on DeflaterPending.java /// /// author of the original java version : Jochen Hoenicke /// public class PendingBuffer { #region Instance Fields /// /// Internal work buffer /// readonly byte[] buffer; int start; int end; uint bits; int bitCount; #endregion #region Constructors /// /// construct instance using default buffer size of 4096 /// public PendingBuffer() : this(4096) { } /// /// construct instance using specified buffer size /// /// /// size to use for internal buffer /// public PendingBuffer(int bufferSize) { buffer = new byte[bufferSize]; } #endregion /// /// Clear internal state/buffers /// public void Reset() { start = end = bitCount = 0; } /// /// Write a byte to buffer /// /// /// The value to write /// public void WriteByte(int value) { #if DebugDeflation if (DeflaterConstants.DEBUGGING && (start != 0) ) { throw new SharpZipBaseException("Debug check: start != 0"); } #endif buffer[end++] = unchecked((byte)value); } /// /// Write a short value to buffer LSB first /// /// /// The value to write. /// public void WriteShort(int value) { #if DebugDeflation if (DeflaterConstants.DEBUGGING && (start != 0) ) { throw new SharpZipBaseException("Debug check: start != 0"); } #endif buffer[end++] = unchecked((byte)value); buffer[end++] = unchecked((byte)(value >> 8)); } /// /// write an integer LSB first /// /// The value to write. public void WriteInt(int value) { #if DebugDeflation if (DeflaterConstants.DEBUGGING && (start != 0) ) { throw new SharpZipBaseException("Debug check: start != 0"); } #endif buffer[end++] = unchecked((byte)value); buffer[end++] = unchecked((byte)(value >> 8)); buffer[end++] = unchecked((byte)(value >> 16)); buffer[end++] = unchecked((byte)(value >> 24)); } /// /// Write a block of data to buffer /// /// data to write /// offset of first byte to write /// number of bytes to write public void WriteBlock(byte[] block, int offset, int length) { #if DebugDeflation if (DeflaterConstants.DEBUGGING && (start != 0) ) { throw new SharpZipBaseException("Debug check: start != 0"); } #endif System.Array.Copy(block, offset, buffer, end, length); end += length; } /// /// The number of bits written to the buffer /// public int BitCount { get { return bitCount; } } /// /// Align internal buffer on a byte boundary /// public void AlignToByte() { #if DebugDeflation if (DeflaterConstants.DEBUGGING && (start != 0) ) { throw new SharpZipBaseException("Debug check: start != 0"); } #endif if (bitCount > 0) { buffer[end++] = unchecked((byte)bits); if (bitCount > 8) { buffer[end++] = unchecked((byte)(bits >> 8)); } } bits = 0; bitCount = 0; } /// /// Write bits to internal buffer /// /// source of bits /// number of bits to write public void WriteBits(int b, int count) { #if DebugDeflation if (DeflaterConstants.DEBUGGING && (start != 0) ) { throw new SharpZipBaseException("Debug check: start != 0"); } // if (DeflaterConstants.DEBUGGING) { // //Console.WriteLine("writeBits("+b+","+count+")"); // } #endif bits |= (uint)(b << bitCount); bitCount += count; if (bitCount >= 16) { buffer[end++] = unchecked((byte)bits); buffer[end++] = unchecked((byte)(bits >> 8)); bits >>= 16; bitCount -= 16; } } /// /// Write a short value to internal buffer most significant byte first /// /// value to write public void WriteShortMSB(int s) { #if DebugDeflation if (DeflaterConstants.DEBUGGING && (start != 0) ) { throw new SharpZipBaseException("Debug check: start != 0"); } #endif buffer[end++] = unchecked((byte)(s >> 8)); buffer[end++] = unchecked((byte)s); } /// /// Indicates if buffer has been flushed /// public bool IsFlushed { get { return end == 0; } } /// /// Flushes the pending buffer into the given output array. If the /// output array is to small, only a partial flush is done. /// /// The output array. /// The offset into output array. /// The maximum number of bytes to store. /// The number of bytes flushed. public int Flush(byte[] output, int offset, int length) { if (bitCount >= 8) { buffer[end++] = unchecked((byte)bits); bits >>= 8; bitCount -= 8; } if (length > end - start) { length = end - start; System.Array.Copy(buffer, start, output, offset, length); start = 0; end = 0; } else { System.Array.Copy(buffer, start, output, offset, length); start += length; } return length; } /// /// Convert internal buffer to byte array. /// Buffer is empty on completion /// /// /// The internal buffer contents converted to a byte array. /// public byte[] ToByteArray() { AlignToByte(); byte[] result = new byte[end - start]; System.Array.Copy(buffer, start, result, 0, result.Length); start = 0; end = 0; return result; } } }