257 lines
8.7 KiB
C#
257 lines
8.7 KiB
C#
// OutputWindow.cs
|
|
//
|
|
// Copyright (C) 2001 Mike Krueger
|
|
//
|
|
// This file was translated from java, it was part of the GNU Classpath
|
|
// Copyright (C) 2001 Free Software Foundation, Inc.
|
|
//
|
|
// This program is free software; you can redistribute it and/or
|
|
// modify it under the terms of the GNU General Public License
|
|
// as published by the Free Software Foundation; either version 2
|
|
// of the License, or (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program; if not, write to the Free Software
|
|
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
//
|
|
// Linking this library statically or dynamically with other modules is
|
|
// making a combined work based on this library. Thus, the terms and
|
|
// conditions of the GNU General Public License cover the whole
|
|
// combination.
|
|
//
|
|
// As a special exception, the copyright holders of this library give you
|
|
// permission to link this library with independent modules to produce an
|
|
// executable, regardless of the license terms of these independent
|
|
// modules, and to copy and distribute the resulting executable under
|
|
// terms of your choice, provided that you also meet, for each linked
|
|
// independent module, the terms and conditions of the license of that
|
|
// module. An independent module is a module which is not derived from
|
|
// or based on this library. If you modify this library, you may extend
|
|
// this exception to your version of the library, but you are not
|
|
// obligated to do so. If you do not wish to do so, delete this
|
|
// exception statement from your version.
|
|
|
|
using System;
|
|
|
|
namespace PdfSharp.SharpZipLib.Zip.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.<br/>
|
|
/// Author of the original java version: John Leuner
|
|
/// </summary>
|
|
internal class OutputWindow
|
|
{
|
|
#region Constants
|
|
const int WindowSize = 1 << 15;
|
|
const int WindowMask = WindowSize - 1;
|
|
#endregion
|
|
|
|
#region Instance Fields
|
|
byte[] window = new byte[WindowSize]; //The window is 2^15 bytes
|
|
int windowEnd;
|
|
int windowFilled;
|
|
#endregion
|
|
|
|
/// <summary>
|
|
/// Write a byte to this output window
|
|
/// </summary>
|
|
/// <param name="value">value to write</param>
|
|
/// <exception cref="InvalidOperationException">
|
|
/// if window is full
|
|
/// </exception>
|
|
public void Write(int value)
|
|
{
|
|
if (windowFilled++ == WindowSize)
|
|
{
|
|
throw new InvalidOperationException("Window full");
|
|
}
|
|
window[windowEnd++] = (byte)value;
|
|
windowEnd &= WindowMask;
|
|
}
|
|
|
|
|
|
private void SlowRepeat(int repStart, int length, int distance)
|
|
{
|
|
while (length-- > 0)
|
|
{
|
|
window[windowEnd++] = window[repStart++];
|
|
windowEnd &= WindowMask;
|
|
repStart &= WindowMask;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Append a byte pattern already in the window itself
|
|
/// </summary>
|
|
/// <param name="length">length of pattern to copy</param>
|
|
/// <param name="distance">distance from end of window pattern occurs</param>
|
|
/// <exception cref="InvalidOperationException">
|
|
/// If the repeated data overflows the window
|
|
/// </exception>
|
|
public void Repeat(int length, int distance)
|
|
{
|
|
if ((windowFilled += length) > WindowSize)
|
|
{
|
|
throw new InvalidOperationException("Window full");
|
|
}
|
|
|
|
int repStart = (windowEnd - distance) & WindowMask;
|
|
int border = WindowSize - length;
|
|
if ((repStart <= border) && (windowEnd < border))
|
|
{
|
|
if (length <= distance)
|
|
{
|
|
System.Array.Copy(window, repStart, window, windowEnd, length);
|
|
windowEnd += length;
|
|
}
|
|
else
|
|
{
|
|
// We have to copy manually, since the repeat pattern overlaps.
|
|
while (length-- > 0)
|
|
{
|
|
window[windowEnd++] = window[repStart++];
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SlowRepeat(repStart, length, distance);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Copy from input manipulator to internal window
|
|
/// </summary>
|
|
/// <param name="input">source of data</param>
|
|
/// <param name="length">length of data to copy</param>
|
|
/// <returns>the number of bytes copied</returns>
|
|
public int CopyStored(StreamManipulator input, int length)
|
|
{
|
|
length = Math.Min(Math.Min(length, WindowSize - windowFilled), input.AvailableBytes);
|
|
int copied;
|
|
|
|
int tailLen = WindowSize - windowEnd;
|
|
if (length > tailLen)
|
|
{
|
|
copied = input.CopyBytes(window, windowEnd, tailLen);
|
|
if (copied == tailLen)
|
|
{
|
|
copied += input.CopyBytes(window, 0, length - tailLen);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
copied = input.CopyBytes(window, windowEnd, length);
|
|
}
|
|
|
|
windowEnd = (windowEnd + copied) & WindowMask;
|
|
windowFilled += copied;
|
|
return copied;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Copy dictionary to window
|
|
/// </summary>
|
|
/// <param name="dictionary">source dictionary</param>
|
|
/// <param name="offset">offset of start in source dictionary</param>
|
|
/// <param name="length">length of dictionary</param>
|
|
/// <exception cref="InvalidOperationException">
|
|
/// If window isnt empty
|
|
/// </exception>
|
|
public void CopyDict(byte[] dictionary, int offset, int length)
|
|
{
|
|
if (dictionary == null)
|
|
{
|
|
throw new ArgumentNullException("dictionary");
|
|
}
|
|
|
|
if (windowFilled > 0)
|
|
{
|
|
throw new InvalidOperationException();
|
|
}
|
|
|
|
if (length > WindowSize)
|
|
{
|
|
offset += length - WindowSize;
|
|
length = WindowSize;
|
|
}
|
|
System.Array.Copy(dictionary, offset, window, 0, length);
|
|
windowEnd = length & WindowMask;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get remaining unfilled space in window
|
|
/// </summary>
|
|
/// <returns>Number of bytes left in window</returns>
|
|
public int GetFreeSpace()
|
|
{
|
|
return WindowSize - windowFilled;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get bytes available for output in window
|
|
/// </summary>
|
|
/// <returns>Number of bytes filled</returns>
|
|
public int GetAvailable()
|
|
{
|
|
return windowFilled;
|
|
}
|
|
|
|
/// <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 copyEnd = windowEnd;
|
|
if (len > windowFilled)
|
|
{
|
|
len = windowFilled;
|
|
}
|
|
else
|
|
{
|
|
copyEnd = (windowEnd - windowFilled + len) & WindowMask;
|
|
}
|
|
|
|
int copied = len;
|
|
int tailLen = len - copyEnd;
|
|
|
|
if (tailLen > 0)
|
|
{
|
|
System.Array.Copy(window, WindowSize - tailLen, output, offset, tailLen);
|
|
offset += tailLen;
|
|
len = copyEnd;
|
|
}
|
|
System.Array.Copy(window, copyEnd - len, output, offset, len);
|
|
windowFilled -= copied;
|
|
if (windowFilled < 0)
|
|
{
|
|
throw new InvalidOperationException();
|
|
}
|
|
return copied;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Reset by clearing window so <see cref="GetAvailable">GetAvailable</see> returns 0
|
|
/// </summary>
|
|
public void Reset()
|
|
{
|
|
windowFilled = windowEnd = 0;
|
|
}
|
|
}
|
|
}
|