// PendingBuffer.cs // // Copyright (C) 2001 Mike Krueger // Copyright (C) 2004 John Reilly // // This file was translated from java, it was part of the GNU Classpath // Copyright (C) 2001 Free Software Foundation, Inc. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // // Linking this library statically or dynamically with other modules is // making a combined work based on this library. Thus, the terms and // conditions of the GNU General Public License cover the whole // combination. // // As a special exception, the copyright holders of this library give you // permission to link this library with independent modules to produce an // executable, regardless of the license terms of these independent // modules, and to copy and distribute the resulting executable under // terms of your choice, provided that you also meet, for each linked // independent module, the terms and conditions of the license of that // module. An independent module is a module which is not derived from // or based on this library. If you modify this library, you may extend // this exception to your version of the library, but you are not // obligated to do so. If you do not wish to do so, delete this // exception statement from your version. using System; namespace CommonMPQ.SharpZipLib.Zip.Compression { /// <summary> /// 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 /// </summary> public class PendingBuffer { #region Instance Fields /// <summary> /// Internal work buffer /// </summary> byte[] buffer_; int start; int end; uint bits; int bitCount; #endregion #region Constructors /// <summary> /// construct instance using default buffer size of 4096 /// </summary> public PendingBuffer() : this( 4096 ) { } /// <summary> /// construct instance using specified buffer size /// </summary> /// <param name="bufferSize"> /// size to use for internal buffer /// </param> public PendingBuffer(int bufferSize) { buffer_ = new byte[bufferSize]; } #endregion /// <summary> /// Clear internal state/buffers /// </summary> public void Reset() { start = end = bitCount = 0; } /// <summary> /// Write a byte to buffer /// </summary> /// <param name="value"> /// The value to write /// </param> 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); } /// <summary> /// Write a short value to buffer LSB first /// </summary> /// <param name="value"> /// The value to write. /// </param> 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)); } /// <summary> /// write an integer LSB first /// </summary> /// <param name="value">The value to write.</param> 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)); } /// <summary> /// Write a block of data to buffer /// </summary> /// <param name="block">data to write</param> /// <param name="offset">offset of first byte to write</param> /// <param name="length">number of bytes to write</param> 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; } /// <summary> /// The number of bits written to the buffer /// </summary> public int BitCount { get { return bitCount; } } /// <summary> /// Align internal buffer on a byte boundary /// </summary> 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; } /// <summary> /// Write bits to internal buffer /// </summary> /// <param name="b">source of bits</param> /// <param name="count">number of bits to write</param> 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; } } /// <summary> /// Write a short value to internal buffer most significant byte first /// </summary> /// <param name="s">value to write</param> 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); } /// <summary> /// Indicates if buffer has been flushed /// </summary> public bool IsFlushed { get { return end == 0; } } /// <summary> /// Flushes the pending buffer into the given output array. If the /// output array is to small, only a partial flush is done. /// </summary> /// <param name="output">The output array.</param> /// <param name="offset">The offset into output array.</param> /// <param name="length">The maximum number of bytes to store.</param> /// <returns>The number of bytes flushed.</returns> 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; } /// <summary> /// Convert internal buffer to byte array. /// Buffer is empty on completion /// </summary> /// <returns> /// The internal buffer contents converted to a byte array. /// </returns> public byte[] ToByteArray() { byte[] result = new byte[end - start]; System.Array.Copy(buffer_, start, result, 0, result.Length); start = 0; end = 0; return result; } } }