1 using System; 2 3 namespace ICSharpCode.SharpZipLib.Zip.Compression 4 { 5 /// <summary> 6 /// This class is general purpose class for writing data to a buffer. 7 /// 8 /// It allows you to write bits as well as bytes 9 /// Based on DeflaterPending.java 10 /// 11 /// author of the original java version : Jochen Hoenicke 12 /// </summary> 13 public class PendingBuffer 14 { 15 readonly 16 #region Instance Fields 17 /// <summary> 18 /// Internal work buffer 19 /// </summary> 20 byte[] buffer_; 21 22 int start; 23 int end; 24 25 uint bits; 26 int bitCount; 27 #endregion 28 29 #region Constructors 30 /// <summary> 31 /// construct instance using default buffer size of 4096 32 /// </summary> PendingBuffer()33 public PendingBuffer() : this(4096) 34 { 35 } 36 37 /// <summary> 38 /// construct instance using specified buffer size 39 /// </summary> 40 /// <param name="bufferSize"> 41 /// size to use for internal buffer 42 /// </param> PendingBuffer(int bufferSize)43 public PendingBuffer(int bufferSize) 44 { 45 buffer_ = new byte[bufferSize]; 46 } 47 48 #endregion 49 50 /// <summary> 51 /// Clear internal state/buffers 52 /// </summary> Reset()53 public void Reset() 54 { 55 start = end = bitCount = 0; 56 } 57 58 /// <summary> 59 /// Write a byte to buffer 60 /// </summary> 61 /// <param name="value"> 62 /// The value to write 63 /// </param> WriteByte(int value)64 public void WriteByte(int value) 65 { 66 #if DebugDeflation 67 if (DeflaterConstants.DEBUGGING && (start != 0) ) 68 { 69 throw new SharpZipBaseException("Debug check: start != 0"); 70 } 71 #endif 72 buffer_[end++] = unchecked((byte)value); 73 } 74 75 /// <summary> 76 /// Write a short value to buffer LSB first 77 /// </summary> 78 /// <param name="value"> 79 /// The value to write. 80 /// </param> WriteShort(int value)81 public void WriteShort(int value) 82 { 83 #if DebugDeflation 84 if (DeflaterConstants.DEBUGGING && (start != 0) ) 85 { 86 throw new SharpZipBaseException("Debug check: start != 0"); 87 } 88 #endif 89 buffer_[end++] = unchecked((byte)value); 90 buffer_[end++] = unchecked((byte)(value >> 8)); 91 } 92 93 /// <summary> 94 /// write an integer LSB first 95 /// </summary> 96 /// <param name="value">The value to write.</param> WriteInt(int value)97 public void WriteInt(int value) 98 { 99 #if DebugDeflation 100 if (DeflaterConstants.DEBUGGING && (start != 0) ) 101 { 102 throw new SharpZipBaseException("Debug check: start != 0"); 103 } 104 #endif 105 buffer_[end++] = unchecked((byte)value); 106 buffer_[end++] = unchecked((byte)(value >> 8)); 107 buffer_[end++] = unchecked((byte)(value >> 16)); 108 buffer_[end++] = unchecked((byte)(value >> 24)); 109 } 110 111 /// <summary> 112 /// Write a block of data to buffer 113 /// </summary> 114 /// <param name="block">data to write</param> 115 /// <param name="offset">offset of first byte to write</param> 116 /// <param name="length">number of bytes to write</param> WriteBlock(byte[] block, int offset, int length)117 public void WriteBlock(byte[] block, int offset, int length) 118 { 119 #if DebugDeflation 120 if (DeflaterConstants.DEBUGGING && (start != 0) ) 121 { 122 throw new SharpZipBaseException("Debug check: start != 0"); 123 } 124 #endif 125 System.Array.Copy(block, offset, buffer_, end, length); 126 end += length; 127 } 128 129 /// <summary> 130 /// The number of bits written to the buffer 131 /// </summary> 132 public int BitCount { 133 get { 134 return bitCount; 135 } 136 } 137 138 /// <summary> 139 /// Align internal buffer on a byte boundary 140 /// </summary> AlignToByte()141 public void AlignToByte() 142 { 143 #if DebugDeflation 144 if (DeflaterConstants.DEBUGGING && (start != 0) ) 145 { 146 throw new SharpZipBaseException("Debug check: start != 0"); 147 } 148 #endif 149 if (bitCount > 0) { 150 buffer_[end++] = unchecked((byte)bits); 151 if (bitCount > 8) { 152 buffer_[end++] = unchecked((byte)(bits >> 8)); 153 } 154 } 155 bits = 0; 156 bitCount = 0; 157 } 158 159 /// <summary> 160 /// Write bits to internal buffer 161 /// </summary> 162 /// <param name="b">source of bits</param> 163 /// <param name="count">number of bits to write</param> WriteBits(int b, int count)164 public void WriteBits(int b, int count) 165 { 166 #if DebugDeflation 167 if (DeflaterConstants.DEBUGGING && (start != 0) ) 168 { 169 throw new SharpZipBaseException("Debug check: start != 0"); 170 } 171 172 // if (DeflaterConstants.DEBUGGING) { 173 // //Console.WriteLine("writeBits("+b+","+count+")"); 174 // } 175 #endif 176 bits |= (uint)(b << bitCount); 177 bitCount += count; 178 if (bitCount >= 16) { 179 buffer_[end++] = unchecked((byte)bits); 180 buffer_[end++] = unchecked((byte)(bits >> 8)); 181 bits >>= 16; 182 bitCount -= 16; 183 } 184 } 185 186 /// <summary> 187 /// Write a short value to internal buffer most significant byte first 188 /// </summary> 189 /// <param name="s">value to write</param> WriteShortMSB(int s)190 public void WriteShortMSB(int s) 191 { 192 #if DebugDeflation 193 if (DeflaterConstants.DEBUGGING && (start != 0) ) 194 { 195 throw new SharpZipBaseException("Debug check: start != 0"); 196 } 197 #endif 198 buffer_[end++] = unchecked((byte)(s >> 8)); 199 buffer_[end++] = unchecked((byte)s); 200 } 201 202 /// <summary> 203 /// Indicates if buffer has been flushed 204 /// </summary> 205 public bool IsFlushed { 206 get { 207 return end == 0; 208 } 209 } 210 211 /// <summary> 212 /// Flushes the pending buffer into the given output array. If the 213 /// output array is to small, only a partial flush is done. 214 /// </summary> 215 /// <param name="output">The output array.</param> 216 /// <param name="offset">The offset into output array.</param> 217 /// <param name="length">The maximum number of bytes to store.</param> 218 /// <returns>The number of bytes flushed.</returns> Flush(byte[] output, int offset, int length)219 public int Flush(byte[] output, int offset, int length) 220 { 221 if (bitCount >= 8) { 222 buffer_[end++] = unchecked((byte)bits); 223 bits >>= 8; 224 bitCount -= 8; 225 } 226 227 if (length > end - start) { 228 length = end - start; 229 System.Array.Copy(buffer_, start, output, offset, length); 230 start = 0; 231 end = 0; 232 } else { 233 System.Array.Copy(buffer_, start, output, offset, length); 234 start += length; 235 } 236 return length; 237 } 238 239 /// <summary> 240 /// Convert internal buffer to byte array. 241 /// Buffer is empty on completion 242 /// </summary> 243 /// <returns> 244 /// The internal buffer contents converted to a byte array. 245 /// </returns> ToByteArray()246 public byte[] ToByteArray() 247 { 248 AlignToByte(); 249 250 byte[] result = new byte[end - start]; 251 System.Array.Copy(buffer_, start, result, 0, result.Length); 252 start = 0; 253 end = 0; 254 return result; 255 } 256 } 257 } 258