PageRenderTime 99ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/Utilities/Compression/Streams/OutputWindow.cs

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