/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
- // Based on Mike Krueger's SharpZipLib, Copyright (C) 2001 (GNU license).
- // Authors of the original java version: Jochen Hoenicke, John Leuner
- // See http://www.ISeeSharpCode.com for more information.
-
- using System;
-
- namespace Delta.Utilities.Compression.Streams
- {
- /// <summary>
- /// Contains the output from the Inflation process.
- /// We need to have a window so that we can refer backwards into the
- /// output stream to repeat stuff.
- /// </summary>
- public class OutputWindow
- {
- #region Constants
- /// <summary>
- /// Window size
- /// </summary>
- private const int WindowSize = 1 << 15;
-
- /// <summary>
- /// Window mask
- /// </summary>
- private const int WindowMask = WindowSize - 1;
- #endregion
-
- #region Private
-
- #region window (Private)
- /// <summary>
- /// The window is 2^15 bytes
- /// </summary>
- /// <returns>Byte</returns>
- private readonly byte[] window = new byte[WindowSize];
- #endregion
-
- #region windowEnd (Private)
- /// <summary>
- /// Window end
- /// </summary>
- /// <returns>0</returns>
- private int windowEnd;
- #endregion
-
- #region windowFilled (Private)
- /// <summary>
- /// Window filled
- /// </summary>
- /// <returns>0</returns>
- private int windowFilled;
- #endregion
-
- #endregion
-
- #region Write (Public)
- /// <summary>
- /// Write a byte to this output window
- /// </summary>
- /// <param name="abyte">value to write</param>
- /// <exception cref="InvalidOperationException">
- /// if window is full
- /// </exception>
- public void Write(int abyte)
- {
- if (windowFilled++ == WindowSize)
- {
- throw new InvalidOperationException("Window full");
- } // if (windowFilled++)
- window[windowEnd++] = (byte)abyte;
- windowEnd &= WindowMask;
- }
- #endregion
-
- #region Repeat (Public)
- /// <summary>
- /// Append a byte pattern already in the window itself
- /// </summary>
- /// <param name="len">length of pattern to copy</param>
- /// <param name="dist">distance from end of window pattern occurs</param>
- /// <exception cref="InvalidOperationException">
- /// If the repeated data overflows the window
- /// </exception>
- public void Repeat(int len, int dist)
- {
- if ((windowFilled += len) > WindowSize)
- {
- throw new InvalidOperationException("Window full");
- } // if (windowFilled)
-
- int rep_start = (windowEnd - dist) & WindowMask;
- int border = WindowSize - len;
- if (rep_start <= border && windowEnd < border)
- {
- if (len <= dist)
- {
- Array.Copy(window, rep_start, window, windowEnd, len);
- windowEnd += len;
- } // if (len)
- else
- {
- // We have to copy manually, since the repeat pattern overlaps.
- while (len-- > 0)
- {
- window[windowEnd++] = window[rep_start++];
- } // while (len--)
- } // else
- } // if (rep_start)
- else
- {
- SlowRepeat(rep_start, len, dist);
- } // else
- }
- #endregion
-
- #region CopyStored (Public)
- /// <summary>
- /// Copy from input manipulator to internal window
- /// </summary>
- /// <param name="input">source of data</param>
- /// <param name="len">length of data to copy</param>
- /// <returns>the number of bytes copied</returns>
- public int CopyStored(StreamManipulator input, int len)
- {
- len = Math.Min(Math.Min(len, WindowSize - windowFilled),
- input.AvailableBytes);
- int copied;
-
- int tailLen = WindowSize - windowEnd;
- if (len > tailLen)
- {
- copied = input.CopyBytes(window, windowEnd, tailLen);
- if (copied == tailLen)
- {
- copied += input.CopyBytes(window, 0, len - tailLen);
- } // if (copied)
- } // if (len)
- else
- {
- copied = input.CopyBytes(window, windowEnd, len);
- } // else
-
- windowEnd = (windowEnd + copied) & WindowMask;
- windowFilled += copied;
- return copied;
- }
- #endregion
-
- #region CopyDict (Public)
- /// <summary>
- /// Copy dictionary to window
- /// </summary>
- /// <param name="dict">source dictionary</param>
- /// <param name="offset">offset of start in source dictionary</param>
- /// <param name="len">length of dictionary</param>
- /// <exception cref="InvalidOperationException">
- /// If window isnt empty
- /// </exception>
- public void CopyDict(byte[] dict, int offset, int len)
- {
- if (windowFilled > 0)
- {
- throw new InvalidOperationException();
- } // if (windowFilled)
-
- if (len > WindowSize)
- {
- offset += len - WindowSize;
- len = WindowSize;
- } // if (len)
- Array.Copy(dict, offset, window, 0, len);
- windowEnd = len & WindowMask;
- }
- #endregion
-
- #region GetFreeSpace (Public)
- /// <summary>
- /// Get remaining unfilled space in window
- /// </summary>
- /// <returns>Number of bytes left in window</returns>
- public int GetFreeSpace()
- {
- return WindowSize - windowFilled;
- }
- #endregion
-
- #region GetAvailable (Public)
- /// <summary>
- /// Get bytes available for output in window
- /// </summary>
- /// <returns>Number of bytes filled</returns>
- public int GetAvailable()
- {
- return windowFilled;
- }
- #endregion
-
- #region CopyOutput (Public)
- /// <summary>
- /// Copy contents of window to output
- /// </summary>
- /// <param name="output">buffer to copy to</param>
- /// <param name="offset">offset to start at</param>
- /// <param name="len">number of bytes to count</param>
- /// <returns>The number of bytes copied</returns>
- /// <exception cref="InvalidOperationException">
- /// If a window underflow occurs
- /// </exception>
- public int CopyOutput(byte[] output, int offset, int len)
- {
- int copy_end = windowEnd;
- if (len > windowFilled)
- {
- len = windowFilled;
- } // if (len)
- else
- {
- copy_end = (windowEnd - windowFilled + len) & WindowMask;
- } // else
-
- int copied = len;
- int tailLen = len - copy_end;
-
- if (tailLen > 0)
- {
- Array.Copy(window, WindowSize - tailLen, output, offset,
- tailLen);
- offset += tailLen;
- len = copy_end;
- } // if (tailLen)
- Array.Copy(window, copy_end - len, output, offset, len);
- windowFilled -= copied;
- if (windowFilled < 0)
- {
- throw new InvalidOperationException();
- } // if (windowFilled)
- return copied;
- }
- #endregion
-
- #region Reset (Public)
- /// <summary>
- /// Reset by clearing window so <see cref="GetAvailable">GetAvailable</see>
- /// returns 0.
- /// </summary>
- public void Reset()
- {
- windowFilled = windowEnd = 0;
- }
- #endregion
-
- #region Methods (Private)
-
- #region SlowRepeat
- /// <summary>
- /// Slow repeat
- /// </summary>
- /// <param name="repStart">Rep start</param>
- /// <param name="len">Len</param>
- /// <param name="dist">Dist</param>
- private void SlowRepeat(int repStart, int len, int dist)
- {
- while (len-- > 0)
- {
- window[windowEnd++] = window[repStart++];
- windowEnd &= WindowMask;
- repStart &= WindowMask;
- } // while (len--)
- }
- #endregion
-
- #endregion
- }
- }