3 // Copyright (C) 2001 Mike Krueger
\r
5 // This file was translated from java, it was part of the GNU Classpath
\r
6 // Copyright (C) 2001 Free Software Foundation, Inc.
\r
8 // This program is free software; you can redistribute it and/or
\r
9 // modify it under the terms of the GNU General Public License
\r
10 // as published by the Free Software Foundation; either version 2
\r
11 // of the License, or (at your option) any later version.
\r
13 // This program is distributed in the hope that it will be useful,
\r
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
16 // GNU General Public License for more details.
\r
18 // You should have received a copy of the GNU General Public License
\r
19 // along with this program; if not, write to the Free Software
\r
20 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
\r
22 // Linking this library statically or dynamically with other modules is
\r
23 // making a combined work based on this library. Thus, the terms and
\r
24 // conditions of the GNU General Public License cover the whole
\r
27 // As a special exception, the copyright holders of this library give you
\r
28 // permission to link this library with independent modules to produce an
\r
29 // executable, regardless of the license terms of these independent
\r
30 // modules, and to copy and distribute the resulting executable under
\r
31 // terms of your choice, provided that you also meet, for each linked
\r
32 // independent module, the terms and conditions of the license of that
\r
33 // module. An independent module is a module which is not derived from
\r
34 // or based on this library. If you modify this library, you may extend
\r
35 // this exception to your version of the library, but you are not
\r
36 // obligated to do so. If you do not wish to do so, delete this
\r
37 // exception statement from your version.
\r
41 namespace ICSharpCode.SharpZipLib.Zip.Compression.Streams
\r
45 /// Contains the output from the Inflation process.
\r
46 /// We need to have a window so that we can refer backwards into the output stream
\r
47 /// to repeat stuff.<br/>
\r
48 /// Author of the original java version : John Leuner
\r
50 public class OutputWindow
\r
52 private static int WINDOW_SIZE = 1 << 15;
\r
53 private static int WINDOW_MASK = WINDOW_SIZE - 1;
\r
55 private byte[] window = new byte[WINDOW_SIZE]; //The window is 2^15 bytes
\r
56 private int windowEnd = 0;
\r
57 private int windowFilled = 0;
\r
60 /// Write a byte to this output window
\r
62 /// <param name="abyte">value to write</param>
\r
63 /// <exception cref="InvalidOperationException">
\r
64 /// if window is full
\r
66 public void Write(int abyte)
\r
68 if (windowFilled++ == WINDOW_SIZE) {
\r
69 throw new InvalidOperationException("Window full");
\r
71 window[windowEnd++] = (byte) abyte;
\r
72 windowEnd &= WINDOW_MASK;
\r
76 private void SlowRepeat(int repStart, int len, int dist)
\r
79 window[windowEnd++] = window[repStart++];
\r
80 windowEnd &= WINDOW_MASK;
\r
81 repStart &= WINDOW_MASK;
\r
86 /// Append a byte pattern already in the window itself
\r
88 /// <param name="len">length of pattern to copy</param>
\r
89 /// <param name="dist">distance from end of window pattern occurs</param>
\r
90 /// <exception cref="InvalidOperationException">
\r
91 /// If the repeated data overflows the window
\r
93 public void Repeat(int len, int dist)
\r
95 if ((windowFilled += len) > WINDOW_SIZE) {
\r
96 throw new InvalidOperationException("Window full");
\r
99 int rep_start = (windowEnd - dist) & WINDOW_MASK;
\r
100 int border = WINDOW_SIZE - len;
\r
101 if (rep_start <= border && windowEnd < border) {
\r
103 System.Array.Copy(window, rep_start, window, windowEnd, len);
\r
106 /* We have to copy manually, since the repeat pattern overlaps. */
\r
107 while (len-- > 0) {
\r
108 window[windowEnd++] = window[rep_start++];
\r
112 SlowRepeat(rep_start, len, dist);
\r
117 /// Copy from input manipulator to internal window
\r
119 /// <param name="input">source of data</param>
\r
120 /// <param name="len">length of data to copy</param>
\r
121 /// <returns>the number of bytes copied</returns>
\r
122 public int CopyStored(StreamManipulator input, int len)
\r
124 len = Math.Min(Math.Min(len, WINDOW_SIZE - windowFilled), input.AvailableBytes);
\r
127 int tailLen = WINDOW_SIZE - windowEnd;
\r
128 if (len > tailLen) {
\r
129 copied = input.CopyBytes(window, windowEnd, tailLen);
\r
130 if (copied == tailLen) {
\r
131 copied += input.CopyBytes(window, 0, len - tailLen);
\r
134 copied = input.CopyBytes(window, windowEnd, len);
\r
137 windowEnd = (windowEnd + copied) & WINDOW_MASK;
\r
138 windowFilled += copied;
\r
143 /// Copy dictionary to window
\r
145 /// <param name="dict">source dictionary</param>
\r
146 /// <param name="offset">offset of start in source dictionary</param>
\r
147 /// <param name="len">length of dictionary</param>
\r
148 /// <exception cref="InvalidOperationException">
\r
149 /// If window isnt empty
\r
151 public void CopyDict(byte[] dict, int offset, int len)
\r
153 if (windowFilled > 0) {
\r
154 throw new InvalidOperationException();
\r
157 if (len > WINDOW_SIZE) {
\r
158 offset += len - WINDOW_SIZE;
\r
161 System.Array.Copy(dict, offset, window, 0, len);
\r
162 windowEnd = len & WINDOW_MASK;
\r
166 /// Get remaining unfilled space in window
\r
168 /// <returns>Number of bytes left in window</returns>
\r
169 public int GetFreeSpace()
\r
171 return WINDOW_SIZE - windowFilled;
\r
175 /// Get bytes available for output in window
\r
177 /// <returns>Number of bytes filled</returns>
\r
178 public int GetAvailable()
\r
180 return windowFilled;
\r
184 /// Copy contents of window to output
\r
186 /// <param name="output">buffer to copy to</param>
\r
187 /// <param name="offset">offset to start at</param>
\r
188 /// <param name="len">number of bytes to count</param>
\r
189 /// <returns>The number of bytes copied</returns>
\r
190 /// <exception cref="InvalidOperationException">
\r
191 /// If a window underflow occurs
\r
193 public int CopyOutput(byte[] output, int offset, int len)
\r
195 int copy_end = windowEnd;
\r
196 if (len > windowFilled) {
\r
197 len = windowFilled;
\r
199 copy_end = (windowEnd - windowFilled + len) & WINDOW_MASK;
\r
203 int tailLen = len - copy_end;
\r
206 System.Array.Copy(window, WINDOW_SIZE - tailLen, output, offset, tailLen);
\r
210 System.Array.Copy(window, copy_end - len, output, offset, len);
\r
211 windowFilled -= copied;
\r
212 if (windowFilled < 0) {
\r
213 throw new InvalidOperationException();
\r
219 /// Reset by clearing window so <see cref="GetAvailable">GetAvailable</see> returns 0
\r
221 public void Reset()
\r
223 windowFilled = windowEnd = 0;
\r