PageRenderTime 416ms CodeModel.GetById 201ms app.highlight 10ms RepoModel.GetById 202ms app.codeStats 0ms

/Utilities/Compression/Streams/OutputWindow.cs

#
C# | 274 lines | 164 code | 25 blank | 85 comment | 16 complexity | ad2ddd2520b8eb3818b50c8839afafb2 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;
  6
  7namespace Delta.Utilities.Compression.Streams
  8{
  9	/// <summary>
 10	/// Contains the output from the Inflation process.
 11	/// We need to have a window so that we can refer backwards into the
 12	/// output stream to repeat stuff.
 13	/// </summary>
 14	public class OutputWindow
 15	{
 16		#region Constants
 17		/// <summary>
 18		/// Window size
 19		/// </summary>
 20		private const int WindowSize = 1 << 15;
 21
 22		/// <summary>
 23		/// Window mask
 24		/// </summary>
 25		private const int WindowMask = WindowSize - 1;
 26		#endregion
 27
 28		#region Private
 29
 30		#region window (Private)
 31		/// <summary>
 32		/// The window is 2^15 bytes
 33		/// </summary>
 34		/// <returns>Byte</returns>
 35		private readonly byte[] window = new byte[WindowSize];
 36		#endregion
 37
 38		#region windowEnd (Private)
 39		/// <summary>
 40		/// Window end
 41		/// </summary>
 42		/// <returns>0</returns>
 43		private int windowEnd;
 44		#endregion
 45
 46		#region windowFilled (Private)
 47		/// <summary>
 48		/// Window filled
 49		/// </summary>
 50		/// <returns>0</returns>
 51		private int windowFilled;
 52		#endregion
 53
 54		#endregion
 55
 56		#region Write (Public)
 57		/// <summary>
 58		/// Write a byte to this output window
 59		/// </summary>
 60		/// <param name="abyte">value to write</param>
 61		/// <exception cref="InvalidOperationException">
 62		/// if window is full
 63		/// </exception>
 64		public void Write(int abyte)
 65		{
 66			if (windowFilled++ == WindowSize)
 67			{
 68				throw new InvalidOperationException("Window full");
 69			} // if (windowFilled++)
 70			window[windowEnd++] = (byte)abyte;
 71			windowEnd &= WindowMask;
 72		}
 73		#endregion
 74
 75		#region Repeat (Public)
 76		/// <summary>
 77		/// Append a byte pattern already in the window itself
 78		/// </summary>
 79		/// <param name="len">length of pattern to copy</param>
 80		/// <param name="dist">distance from end of window pattern occurs</param>
 81		/// <exception cref="InvalidOperationException">
 82		/// If the repeated data overflows the window
 83		/// </exception>
 84		public void Repeat(int len, int dist)
 85		{
 86			if ((windowFilled += len) > WindowSize)
 87			{
 88				throw new InvalidOperationException("Window full");
 89			} // if (windowFilled)
 90
 91			int rep_start = (windowEnd - dist) & WindowMask;
 92			int border = WindowSize - len;
 93			if (rep_start <= border && windowEnd < border)
 94			{
 95				if (len <= dist)
 96				{
 97					Array.Copy(window, rep_start, window, windowEnd, len);
 98					windowEnd += len;
 99				} // if (len)
100				else
101				{
102					// We have to copy manually, since the repeat pattern overlaps.
103					while (len-- > 0)
104					{
105						window[windowEnd++] = window[rep_start++];
106					} // while (len--)
107				} // else
108			} // if (rep_start)
109			else
110			{
111				SlowRepeat(rep_start, len, dist);
112			} // else
113		}
114		#endregion
115
116		#region CopyStored (Public)
117		/// <summary>
118		/// Copy from input manipulator to internal window
119		/// </summary>
120		/// <param name="input">source of data</param>
121		/// <param name="len">length of data to copy</param>
122		/// <returns>the number of bytes copied</returns>
123		public int CopyStored(StreamManipulator input, int len)
124		{
125			len = Math.Min(Math.Min(len, WindowSize - windowFilled),
126				input.AvailableBytes);
127			int copied;
128
129			int tailLen = WindowSize - windowEnd;
130			if (len > tailLen)
131			{
132				copied = input.CopyBytes(window, windowEnd, tailLen);
133				if (copied == tailLen)
134				{
135					copied += input.CopyBytes(window, 0, len - tailLen);
136				} // if (copied)
137			} // if (len)
138			else
139			{
140				copied = input.CopyBytes(window, windowEnd, len);
141			} // else
142
143			windowEnd = (windowEnd + copied) & WindowMask;
144			windowFilled += copied;
145			return copied;
146		}
147		#endregion
148
149		#region CopyDict (Public)
150		/// <summary>
151		/// Copy dictionary to window
152		/// </summary>
153		/// <param name="dict">source dictionary</param>
154		/// <param name="offset">offset of start in source dictionary</param>
155		/// <param name="len">length of dictionary</param>
156		/// <exception cref="InvalidOperationException">
157		/// If window isnt empty
158		/// </exception>
159		public void CopyDict(byte[] dict, int offset, int len)
160		{
161			if (windowFilled > 0)
162			{
163				throw new InvalidOperationException();
164			} // if (windowFilled)
165
166			if (len > WindowSize)
167			{
168				offset += len - WindowSize;
169				len = WindowSize;
170			} // if (len)
171			Array.Copy(dict, offset, window, 0, len);
172			windowEnd = len & WindowMask;
173		}
174		#endregion
175
176		#region GetFreeSpace (Public)
177		/// <summary>
178		/// Get remaining unfilled space in window
179		/// </summary>
180		/// <returns>Number of bytes left in window</returns>
181		public int GetFreeSpace()
182		{
183			return WindowSize - windowFilled;
184		}
185		#endregion
186
187		#region GetAvailable (Public)
188		/// <summary>
189		/// Get bytes available for output in window
190		/// </summary>
191		/// <returns>Number of bytes filled</returns>
192		public int GetAvailable()
193		{
194			return windowFilled;
195		}
196		#endregion
197
198		#region CopyOutput (Public)
199		/// <summary>
200		/// Copy contents of window to output
201		/// </summary>
202		/// <param name="output">buffer to copy to</param>
203		/// <param name="offset">offset to start at</param>
204		/// <param name="len">number of bytes to count</param>
205		/// <returns>The number of bytes copied</returns>
206		/// <exception cref="InvalidOperationException">
207		/// If a window underflow occurs
208		/// </exception>
209		public int CopyOutput(byte[] output, int offset, int len)
210		{
211			int copy_end = windowEnd;
212			if (len > windowFilled)
213			{
214				len = windowFilled;
215			} // if (len)
216			else
217			{
218				copy_end = (windowEnd - windowFilled + len) & WindowMask;
219			} // else
220
221			int copied = len;
222			int tailLen = len - copy_end;
223
224			if (tailLen > 0)
225			{
226				Array.Copy(window, WindowSize - tailLen, output, offset,
227					tailLen);
228				offset += tailLen;
229				len = copy_end;
230			} // if (tailLen)
231			Array.Copy(window, copy_end - len, output, offset, len);
232			windowFilled -= copied;
233			if (windowFilled < 0)
234			{
235				throw new InvalidOperationException();
236			} // if (windowFilled)
237			return copied;
238		}
239		#endregion
240
241		#region Reset (Public)
242		/// <summary>
243		/// Reset by clearing window so <see cref="GetAvailable">GetAvailable</see>
244		/// returns 0.
245		/// </summary>
246		public void Reset()
247		{
248			windowFilled = windowEnd = 0;
249		}
250		#endregion
251
252		#region Methods (Private)
253
254		#region SlowRepeat
255		/// <summary>
256		/// Slow repeat
257		/// </summary>
258		/// <param name="repStart">Rep start</param>
259		/// <param name="len">Len</param>
260		/// <param name="dist">Dist</param>
261		private void SlowRepeat(int repStart, int len, int dist)
262		{
263			while (len-- > 0)
264			{
265				window[windowEnd++] = window[repStart++];
266				windowEnd &= WindowMask;
267				repStart &= WindowMask;
268			} // while (len--)
269		}
270		#endregion
271
272		#endregion
273	}
274}