PageRenderTime 65ms CodeModel.GetById 30ms app.highlight 13ms RepoModel.GetById 17ms app.codeStats 0ms

/Utilities/Compression/Streams/InflaterInputBuffer.cs

#
C# | 416 lines | 255 code | 38 blank | 123 comment | 24 complexity | c2767bc60c923d23e6ca6e7b8c9a204b MD5 | raw file
  1// Based on Mike Krueger's SharpZipLib, Copyright (C) 2001 (GNU license).
  2// Authors of the original java version: Jochen Hoenicke, John Leuner
  3// See http://www.ISeeSharpCode.com for more information.
  4
  5using System;
  6using System.IO;
  7using System.Security.Cryptography;
  8using Delta.Utilities.Compression.Inflaters;
  9
 10namespace Delta.Utilities.Compression.Streams
 11{
 12	/// <summary>
 13	/// An input buffer customized for use by <see cref="InflaterInputStream"/>
 14	/// </summary>
 15	/// <remarks>
 16	/// The buffer supports decryption of incoming data.
 17	/// </remarks>
 18	public class InflaterInputBuffer
 19	{
 20		#region RawLength (Public)
 21		/// <summary>
 22		/// Get the length of bytes bytes in the <see cref="GetRawData"/>
 23		/// </summary>
 24		public int RawLength
 25		{
 26			get
 27			{
 28				return rawLength;
 29			} // get
 30		}
 31		#endregion
 32
 33		/*
 34		/// <summary>
 35		/// Get the contents of the raw data buffer.
 36		/// </summary>
 37		/// <remarks>This may contain encrypted data.</remarks>
 38		public byte[] RawData
 39		{
 40			get
 41			{
 42				return rawData;
 43			} // get
 44		} // RawData
 45		*/
 46
 47		#region ClearTextLength (Public)
 48		/// <summary>
 49		/// Get the number of useable bytes in <see cref="GetClearText"/>
 50		/// </summary>
 51		public int ClearTextLength
 52		{
 53			get
 54			{
 55				return clearTextLength;
 56			} // get
 57		}
 58		#endregion
 59
 60		/*warning CA1819, use GetClearText instead
 61		/// <summary>
 62		/// Get the contents of the clear text buffer.
 63		/// </summary>
 64		public byte[] ClearText
 65		{
 66			get
 67			{
 68				return clearText;
 69			} // get
 70		} // ClearText
 71		*/
 72
 73		#region Available (Public)
 74		/// <summary>
 75		/// Get/set the number of bytes available
 76		/// </summary>
 77		public int Available
 78		{
 79			get
 80			{
 81				return available;
 82			} // get
 83			set
 84			{
 85				available = value;
 86			} // set
 87		}
 88		#endregion
 89
 90		#region CryptoTransform (Public)
 91		/// <summary>
 92		/// Get/set the <see cref="ICryptoTransform"/> to apply to any data.
 93		/// </summary>
 94		/// <remarks>Set this value to null to have no transform applied.</remarks>
 95		public ICryptoTransform CryptoTransform
 96		{
 97			set
 98			{
 99				cryptoTransform = value;
100				if (cryptoTransform != null)
101				{
102					if (rawData == clearText)
103					{
104						if (internalClearText == null)
105						{
106							internalClearText = new byte[4096];
107						} // if (internalClearText)
108						clearText = internalClearText;
109					} // if (rawData)
110					clearTextLength = rawLength;
111					if (available > 0)
112					{
113						cryptoTransform.TransformBlock(rawData, rawLength - available,
114							available, clearText, rawLength - available);
115					} // if (available)
116				} // if (cryptoTransform)
117				else
118				{
119					clearText = rawData;
120					clearTextLength = rawLength;
121				} // else
122			} // set
123		}
124		#endregion
125
126		#region Private
127
128		#region rawLength (Private)
129		/// <remarks>
130		/// The raw length
131		/// </remarks>
132		private int rawLength;
133		#endregion
134
135		#region rawData (Private)
136		/// <remarks>
137		/// The data inside the buffer
138		/// </remarks>
139		private readonly byte[] rawData;
140		#endregion
141
142		#region clearTextLength (Private)
143		/// <remarks>
144		/// Clear Text Length
145		/// </remarks>
146		private int clearTextLength;
147		#endregion
148
149		#region clearText (Private)
150		/// <remarks>
151		/// The clear Text
152		/// </remarks>
153		private byte[] clearText;
154		#endregion
155
156		#region internalClearText (Private)
157		/// <remarks>
158		/// Internal Clear Text
159		/// </remarks>
160		private byte[] internalClearText;
161		#endregion
162
163		#region available (Private)
164		/// <remarks>
165		/// Available
166		/// </remarks>
167		private int available;
168		#endregion
169
170		#region cryptoTransform (Private)
171		/// <remarks>
172		/// cryptoTransform
173		/// </remarks>
174		private ICryptoTransform cryptoTransform;
175		#endregion
176
177		#region inputStream (Private)
178		/// <remarks>
179		/// The input stream
180		/// </remarks>
181		private readonly Stream inputStream;
182		#endregion
183
184		#endregion
185
186		#region Constructors
187		/// <summary>
188		/// Initialise a new instance of <see cref="InflaterInputBuffer"/>
189		/// </summary>
190		/// <param name="stream">The stream to buffer.</param>
191		public InflaterInputBuffer(Stream stream)
192		{
193			inputStream = stream;
194			rawData = new byte[4096];
195			clearText = rawData;
196		}
197		#endregion
198
199		#region GetRawData (Public)
200		/// <summary>
201		/// Get the contents of the raw data buffer.
202		/// </summary>
203		/// <remarks>This may contain encrypted data.</remarks>
204		public byte[] GetRawData()
205		{
206			return rawData;
207		}
208		#endregion
209
210		#region GetClearText (Public)
211		/// <summary>
212		/// Get the contents of the clear text buffer.
213		/// </summary>
214		public byte[] GetClearText()
215		{
216			return clearText;
217		}
218		#endregion
219
220		#region SetInflaterInput (Public)
221		/// <summary>
222		/// Call <see cref="Inflater.SetInput(byte[])"/> passing the current clear
223		/// text buffer contents.
224		/// </summary>
225		/// <param name="inflater">The inflater to set input for.</param>
226		public void SetInflaterInput(Inflater inflater)
227		{
228			if (available > 0)
229			{
230				inflater.SetInput(clearText, clearTextLength - available, available);
231				available = 0;
232			} // if (available)
233		}
234		#endregion
235
236		#region Fill (Public)
237		/// <summary>
238		/// Fill the buffer from the underlying input stream.
239		/// </summary>
240		public void Fill()
241		{
242			rawLength = 0;
243			int toRead = rawData.Length;
244
245			while (toRead > 0)
246			{
247				int count = inputStream.Read(rawData, rawLength, toRead);
248				if (count <= 0)
249				{
250					if (rawLength == 0)
251					{
252						throw new CompressionException("Unexpected EOF");
253					} // if (rawLength)
254					break;
255				} // if (count)
256				rawLength += count;
257				toRead -= count;
258			} // while (toRead)
259
260			if (cryptoTransform != null)
261			{
262				clearTextLength = cryptoTransform.TransformBlock(
263					rawData, 0, rawLength, clearText, 0);
264			} // if (cryptoTransform)
265			else
266			{
267				clearTextLength = rawLength;
268			} // else
269
270			available = clearTextLength;
271		}
272		#endregion
273
274		#region ReadRawBuffer (Public)
275		/// <summary>
276		/// Read a buffer directly from the input stream
277		/// </summary>
278		/// <param name="buffer">The buffer to fill</param>
279		/// <returns>Returns the number of bytes read.</returns>
280		public int ReadRawBuffer(byte[] buffer)
281		{
282			return ReadRawBuffer(buffer, 0, buffer.Length);
283		}
284
285		// ReadRawBuffer(buffer)
286
287		/// <summary>
288		/// Read a buffer directly from the input stream
289		/// </summary>
290		/// <param name="outBuffer">The buffer to read into</param>
291		/// <param name="offset">The offset to start reading data into.</param>
292		/// <param name="length">The number of bytes to read.</param>
293		/// <returns>Returns the number of bytes read.</returns>
294		public int ReadRawBuffer(byte[] outBuffer, int offset, int length)
295		{
296			if (length <= 0)
297			{
298				throw new ArgumentOutOfRangeException("length");
299			} // if (length)
300
301			int currentOffset = offset;
302			int currentLength = length;
303
304			while (currentLength > 0)
305			{
306				if (available <= 0)
307				{
308					Fill();
309					if (available <= 0)
310					{
311						return 0;
312					} // if (available)
313				} // if (available)
314				int toCopy = Math.Min(currentLength, available);
315				Array.Copy(rawData, rawLength - available,
316					outBuffer, currentOffset, toCopy);
317				currentOffset += toCopy;
318				currentLength -= toCopy;
319				available -= toCopy;
320			} // while (currentLength)
321			return length;
322		}
323		#endregion
324
325		#region ReadClearTextBuffer (Public)
326		/// <summary>
327		/// Read clear text data from the input stream.
328		/// </summary>
329		/// <param name="outBuffer">The buffer to add data to.</param>
330		/// <param name="offset">The offset to start adding data at.</param>
331		/// <param name="length">The number of bytes to read.</param>
332		/// <returns>Returns the number of bytes actually read.</returns>
333		public int ReadClearTextBuffer(byte[] outBuffer, int offset, int length)
334		{
335			if (length <= 0)
336			{
337				throw new ArgumentOutOfRangeException("length");
338			} // if (length)
339
340			int currentOffset = offset;
341			int currentLength = length;
342
343			while (currentLength > 0)
344			{
345				if (available <= 0)
346				{
347					Fill();
348					if (available <= 0)
349					{
350						return 0;
351					} // if (available)
352				} // if (available)
353
354				int toCopy = Math.Min(currentLength, available);
355				Array.Copy(clearText, clearTextLength - available,
356					outBuffer, currentOffset, toCopy);
357				currentOffset += toCopy;
358				currentLength -= toCopy;
359				available -= toCopy;
360			} // while (currentLength)
361			return length;
362		}
363		#endregion
364
365		#region ReadLeByte (Public)
366		/// <summary>
367		/// Read a byte from the input stream.
368		/// </summary>
369		/// <returns>Returns the byte read.</returns>
370		public int ReadLeByte()
371		{
372			if (available <= 0)
373			{
374				Fill();
375				if (available <= 0)
376				{
377					throw new ZipException("EOF in header");
378				} // if (available)
379			} // if (available)
380			byte result = (byte)(rawData[rawLength - available] & 0xff);
381			available -= 1;
382			return result;
383		}
384		#endregion
385
386		#region ReadLeShort (Public)
387		/// <summary>
388		/// Read an unsigned short in little endian byte order.
389		/// </summary>
390		public int ReadLeShort()
391		{
392			return ReadLeByte() | (ReadLeByte() << 8);
393		}
394		#endregion
395
396		#region ReadLeInt (Public)
397		/// <summary>
398		/// Read an int in little endian byte order.
399		/// </summary>
400		public int ReadLeInt()
401		{
402			return ReadLeShort() | (ReadLeShort() << 16);
403		}
404		#endregion
405
406		#region ReadLeLong (Public)
407		/// <summary>
408		/// Read an int baseInputStream little endian byte order.
409		/// </summary>
410		public long ReadLeLong()
411		{
412			return ReadLeInt() | (ReadLeInt() << 32);
413		}
414		#endregion
415	}
416}