| 1 | // OutputWindow.cs
|
|---|
| 2 | //
|
|---|
| 3 | // Copyright (C) 2001 Mike Krueger
|
|---|
| 4 | //
|
|---|
| 5 | // This file was translated from java, it was part of the GNU Classpath
|
|---|
| 6 | // Copyright (C) 2001 Free Software Foundation, Inc.
|
|---|
| 7 | //
|
|---|
| 8 | // This program is free software; you can redistribute it and/or
|
|---|
| 9 | // modify it under the terms of the GNU General Public License
|
|---|
| 10 | // as published by the Free Software Foundation; either version 2
|
|---|
| 11 | // of the License, or (at your option) any later version.
|
|---|
| 12 | //
|
|---|
| 13 | // This program is distributed in the hope that it will be useful,
|
|---|
| 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|---|
| 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|---|
| 16 | // GNU General Public License for more details.
|
|---|
| 17 | //
|
|---|
| 18 | // You should have received a copy of the GNU General Public License
|
|---|
| 19 | // along with this program; if not, write to the Free Software
|
|---|
| 20 | // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|---|
| 21 | //
|
|---|
| 22 | // Linking this library statically or dynamically with other modules is
|
|---|
| 23 | // making a combined work based on this library. Thus, the terms and
|
|---|
| 24 | // conditions of the GNU General Public License cover the whole
|
|---|
| 25 | // combination.
|
|---|
| 26 | //
|
|---|
| 27 | // As a special exception, the copyright holders of this library give you
|
|---|
| 28 | // permission to link this library with independent modules to produce an
|
|---|
| 29 | // executable, regardless of the license terms of these independent
|
|---|
| 30 | // modules, and to copy and distribute the resulting executable under
|
|---|
| 31 | // terms of your choice, provided that you also meet, for each linked
|
|---|
| 32 | // independent module, the terms and conditions of the license of that
|
|---|
| 33 | // module. An independent module is a module which is not derived from
|
|---|
| 34 | // or based on this library. If you modify this library, you may extend
|
|---|
| 35 | // this exception to your version of the library, but you are not
|
|---|
| 36 | // obligated to do so. If you do not wish to do so, delete this
|
|---|
| 37 | // exception statement from your version.
|
|---|
| 38 |
|
|---|
| 39 | using System;
|
|---|
| 40 |
|
|---|
| 41 |
|
|---|
| 42 | namespace ICSharpCode.SharpZipLib.Zip.Compression.Streams
|
|---|
| 43 | {
|
|---|
| 44 |
|
|---|
| 45 | /// <summary>
|
|---|
| 46 | /// Contains the output from the Inflation process.
|
|---|
| 47 | /// We need to have a window so that we can refer backwards into the output stream
|
|---|
| 48 | /// to repeat stuff.<br/>
|
|---|
| 49 | /// Author of the original java version : John Leuner
|
|---|
| 50 | /// </summary>
|
|---|
| 51 | public class OutputWindow
|
|---|
| 52 | {
|
|---|
| 53 | #region Constants
|
|---|
| 54 | const int WindowSize = 1 << 15;
|
|---|
| 55 | const int WindowMask = WindowSize - 1;
|
|---|
| 56 | #endregion
|
|---|
| 57 |
|
|---|
| 58 | #region Instance Fields
|
|---|
| 59 | byte[] window = new byte[WindowSize]; //The window is 2^15 bytes
|
|---|
| 60 | int windowEnd;
|
|---|
| 61 | int windowFilled;
|
|---|
| 62 | #endregion
|
|---|
| 63 |
|
|---|
| 64 | /// <summary>
|
|---|
| 65 | /// Write a byte to this output window
|
|---|
| 66 | /// </summary>
|
|---|
| 67 | /// <param name="value">value to write</param>
|
|---|
| 68 | /// <exception cref="InvalidOperationException">
|
|---|
| 69 | /// if window is full
|
|---|
| 70 | /// </exception>
|
|---|
| 71 | public void Write(int value)
|
|---|
| 72 | {
|
|---|
| 73 | if (windowFilled++ == WindowSize) {
|
|---|
| 74 | throw new InvalidOperationException("Window full");
|
|---|
| 75 | }
|
|---|
| 76 | window[windowEnd++] = (byte) value;
|
|---|
| 77 | windowEnd &= WindowMask;
|
|---|
| 78 | }
|
|---|
| 79 |
|
|---|
| 80 |
|
|---|
| 81 | private void SlowRepeat(int repStart, int length, int distance)
|
|---|
| 82 | {
|
|---|
| 83 | while (length-- > 0) {
|
|---|
| 84 | window[windowEnd++] = window[repStart++];
|
|---|
| 85 | windowEnd &= WindowMask;
|
|---|
| 86 | repStart &= WindowMask;
|
|---|
| 87 | }
|
|---|
| 88 | }
|
|---|
| 89 |
|
|---|
| 90 | /// <summary>
|
|---|
| 91 | /// Append a byte pattern already in the window itself
|
|---|
| 92 | /// </summary>
|
|---|
| 93 | /// <param name="length">length of pattern to copy</param>
|
|---|
| 94 | /// <param name="distance">distance from end of window pattern occurs</param>
|
|---|
| 95 | /// <exception cref="InvalidOperationException">
|
|---|
| 96 | /// If the repeated data overflows the window
|
|---|
| 97 | /// </exception>
|
|---|
| 98 | public void Repeat(int length, int distance)
|
|---|
| 99 | {
|
|---|
| 100 | if ((windowFilled += length) > WindowSize) {
|
|---|
| 101 | throw new InvalidOperationException("Window full");
|
|---|
| 102 | }
|
|---|
| 103 |
|
|---|
| 104 | int repStart = (windowEnd - distance) & WindowMask;
|
|---|
| 105 | int border = WindowSize - length;
|
|---|
| 106 | if ( (repStart <= border) && (windowEnd < border) ) {
|
|---|
| 107 | if (length <= distance) {
|
|---|
| 108 | System.Array.Copy(window, repStart, window, windowEnd, length);
|
|---|
| 109 | windowEnd += length;
|
|---|
| 110 | } else {
|
|---|
| 111 | // We have to copy manually, since the repeat pattern overlaps.
|
|---|
| 112 | while (length-- > 0) {
|
|---|
| 113 | window[windowEnd++] = window[repStart++];
|
|---|
| 114 | }
|
|---|
| 115 | }
|
|---|
| 116 | } else {
|
|---|
| 117 | SlowRepeat(repStart, length, distance);
|
|---|
| 118 | }
|
|---|
| 119 | }
|
|---|
| 120 |
|
|---|
| 121 | /// <summary>
|
|---|
| 122 | /// Copy from input manipulator to internal window
|
|---|
| 123 | /// </summary>
|
|---|
| 124 | /// <param name="input">source of data</param>
|
|---|
| 125 | /// <param name="length">length of data to copy</param>
|
|---|
| 126 | /// <returns>the number of bytes copied</returns>
|
|---|
| 127 | public int CopyStored(StreamManipulator input, int length)
|
|---|
| 128 | {
|
|---|
| 129 | length = Math.Min(Math.Min(length, WindowSize - windowFilled), input.AvailableBytes);
|
|---|
| 130 | int copied;
|
|---|
| 131 |
|
|---|
| 132 | int tailLen = WindowSize - windowEnd;
|
|---|
| 133 | if (length > tailLen) {
|
|---|
| 134 | copied = input.CopyBytes(window, windowEnd, tailLen);
|
|---|
| 135 | if (copied == tailLen) {
|
|---|
| 136 | copied += input.CopyBytes(window, 0, length - tailLen);
|
|---|
| 137 | }
|
|---|
| 138 | } else {
|
|---|
| 139 | copied = input.CopyBytes(window, windowEnd, length);
|
|---|
| 140 | }
|
|---|
| 141 |
|
|---|
| 142 | windowEnd = (windowEnd + copied) & WindowMask;
|
|---|
| 143 | windowFilled += copied;
|
|---|
| 144 | return copied;
|
|---|
| 145 | }
|
|---|
| 146 |
|
|---|
| 147 | /// <summary>
|
|---|
| 148 | /// Copy dictionary to window
|
|---|
| 149 | /// </summary>
|
|---|
| 150 | /// <param name="dictionary">source dictionary</param>
|
|---|
| 151 | /// <param name="offset">offset of start in source dictionary</param>
|
|---|
| 152 | /// <param name="length">length of dictionary</param>
|
|---|
| 153 | /// <exception cref="InvalidOperationException">
|
|---|
| 154 | /// If window isnt empty
|
|---|
| 155 | /// </exception>
|
|---|
| 156 | public void CopyDict(byte[] dictionary, int offset, int length)
|
|---|
| 157 | {
|
|---|
| 158 | if ( dictionary == null ) {
|
|---|
| 159 | throw new ArgumentNullException("dictionary");
|
|---|
| 160 | }
|
|---|
| 161 |
|
|---|
| 162 | if (windowFilled > 0) {
|
|---|
| 163 | throw new InvalidOperationException();
|
|---|
| 164 | }
|
|---|
| 165 |
|
|---|
| 166 | if (length > WindowSize) {
|
|---|
| 167 | offset += length - WindowSize;
|
|---|
| 168 | length = WindowSize;
|
|---|
| 169 | }
|
|---|
| 170 | System.Array.Copy(dictionary, offset, window, 0, length);
|
|---|
| 171 | windowEnd = length & WindowMask;
|
|---|
| 172 | }
|
|---|
| 173 |
|
|---|
| 174 | /// <summary>
|
|---|
| 175 | /// Get remaining unfilled space in window
|
|---|
| 176 | /// </summary>
|
|---|
| 177 | /// <returns>Number of bytes left in window</returns>
|
|---|
| 178 | public int GetFreeSpace()
|
|---|
| 179 | {
|
|---|
| 180 | return WindowSize - windowFilled;
|
|---|
| 181 | }
|
|---|
| 182 |
|
|---|
| 183 | /// <summary>
|
|---|
| 184 | /// Get bytes available for output in window
|
|---|
| 185 | /// </summary>
|
|---|
| 186 | /// <returns>Number of bytes filled</returns>
|
|---|
| 187 | public int GetAvailable()
|
|---|
| 188 | {
|
|---|
| 189 | return windowFilled;
|
|---|
| 190 | }
|
|---|
| 191 |
|
|---|
| 192 | /// <summary>
|
|---|
| 193 | /// Copy contents of window to output
|
|---|
| 194 | /// </summary>
|
|---|
| 195 | /// <param name="output">buffer to copy to</param>
|
|---|
| 196 | /// <param name="offset">offset to start at</param>
|
|---|
| 197 | /// <param name="len">number of bytes to count</param>
|
|---|
| 198 | /// <returns>The number of bytes copied</returns>
|
|---|
| 199 | /// <exception cref="InvalidOperationException">
|
|---|
| 200 | /// If a window underflow occurs
|
|---|
| 201 | /// </exception>
|
|---|
| 202 | public int CopyOutput(byte[] output, int offset, int len)
|
|---|
| 203 | {
|
|---|
| 204 | int copyEnd = windowEnd;
|
|---|
| 205 | if (len > windowFilled) {
|
|---|
| 206 | len = windowFilled;
|
|---|
| 207 | } else {
|
|---|
| 208 | copyEnd = (windowEnd - windowFilled + len) & WindowMask;
|
|---|
| 209 | }
|
|---|
| 210 |
|
|---|
| 211 | int copied = len;
|
|---|
| 212 | int tailLen = len - copyEnd;
|
|---|
| 213 |
|
|---|
| 214 | if (tailLen > 0) {
|
|---|
| 215 | System.Array.Copy(window, WindowSize - tailLen, output, offset, tailLen);
|
|---|
| 216 | offset += tailLen;
|
|---|
| 217 | len = copyEnd;
|
|---|
| 218 | }
|
|---|
| 219 | System.Array.Copy(window, copyEnd - len, output, offset, len);
|
|---|
| 220 | windowFilled -= copied;
|
|---|
| 221 | if (windowFilled < 0) {
|
|---|
| 222 | throw new InvalidOperationException();
|
|---|
| 223 | }
|
|---|
| 224 | return copied;
|
|---|
| 225 | }
|
|---|
| 226 |
|
|---|
| 227 | /// <summary>
|
|---|
| 228 | /// Reset by clearing window so <see cref="GetAvailable">GetAvailable</see> returns 0
|
|---|
| 229 | /// </summary>
|
|---|
| 230 | public void Reset()
|
|---|
| 231 | {
|
|---|
| 232 | windowFilled = windowEnd = 0;
|
|---|
| 233 | }
|
|---|
| 234 | }
|
|---|
| 235 | }
|
|---|