root / trunk / hammock / src / net35 / ICSharpCode.SharpZipLib.Silverlight / Zip / Compression / Streams / OutputWindow.cs @ 0eea575a
History | View | Annotate | Download (8.8 kB)
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 |
namespace ICSharpCode.SharpZipLib.Silverlight.Zip.Compression.Streams |
42 |
{ |
43 |
/// <summary> |
44 |
/// Contains the output from the Inflation process. |
45 |
/// We need to have a window so that we can refer backwards into the output stream |
46 |
/// to repeat stuff.<br/> |
47 |
/// Author of the original java version : John Leuner |
48 |
/// </summary> |
49 |
public class OutputWindow |
50 |
{ |
51 |
#region Constants |
52 |
|
53 |
private const int WindowMask = WindowSize - 1; |
54 |
private const int WindowSize = 1 << 15; |
55 |
|
56 |
#endregion |
57 |
|
58 |
#region Instance Fields |
59 |
|
60 |
private readonly byte[] window = new byte[WindowSize]; //The window is 2^15 bytes |
61 |
private int windowEnd; |
62 |
private int windowFilled; |
63 |
|
64 |
#endregion |
65 |
|
66 |
/// <summary> |
67 |
/// Write a byte to this output window |
68 |
/// </summary> |
69 |
/// <param name="value">value to write</param> |
70 |
/// <exception cref="InvalidOperationException"> |
71 |
/// if window is full |
72 |
/// </exception> |
73 |
public void Write(int value) |
74 |
{ |
75 |
if (windowFilled++ == WindowSize) |
76 |
{ |
77 |
throw new InvalidOperationException("Window full"); |
78 |
} |
79 |
window[windowEnd++] = (byte) value; |
80 |
windowEnd &= WindowMask; |
81 |
} |
82 |
|
83 |
private void SlowRepeat(int repStart, int length) |
84 |
{ |
85 |
while (length-- > 0) |
86 |
{ |
87 |
window[windowEnd++] = window[repStart++]; |
88 |
windowEnd &= WindowMask; |
89 |
repStart &= WindowMask; |
90 |
} |
91 |
} |
92 |
|
93 |
/// <summary> |
94 |
/// Append a byte pattern already in the window itself |
95 |
/// </summary> |
96 |
/// <param name="length">length of pattern to copy</param> |
97 |
/// <param name="distance">distance from end of window pattern occurs</param> |
98 |
/// <exception cref="InvalidOperationException"> |
99 |
/// If the repeated data overflows the window |
100 |
/// </exception> |
101 |
public void Repeat(int length, int distance) |
102 |
{ |
103 |
if ((windowFilled += length) > WindowSize) |
104 |
{ |
105 |
throw new InvalidOperationException("Window full"); |
106 |
} |
107 |
|
108 |
var repStart = (windowEnd - distance) & WindowMask; |
109 |
var border = WindowSize - length; |
110 |
if ((repStart <= border) && (windowEnd < border)) |
111 |
{ |
112 |
if (length <= distance) |
113 |
{ |
114 |
Array.Copy(window, repStart, window, windowEnd, length); |
115 |
windowEnd += length; |
116 |
} |
117 |
else |
118 |
{ |
119 |
// We have to copy manually, since the repeat pattern overlaps. |
120 |
while (length-- > 0) |
121 |
{ |
122 |
window[windowEnd++] = window[repStart++]; |
123 |
} |
124 |
} |
125 |
} |
126 |
else |
127 |
{ |
128 |
SlowRepeat(repStart, length); |
129 |
} |
130 |
} |
131 |
|
132 |
/// <summary> |
133 |
/// Copy from input manipulator to internal window |
134 |
/// </summary> |
135 |
/// <param name="input">source of data</param> |
136 |
/// <param name="length">length of data to copy</param> |
137 |
/// <returns>the number of bytes copied</returns> |
138 |
public int CopyStored(StreamManipulator input, int length) |
139 |
{ |
140 |
length = Math.Min(Math.Min(length, WindowSize - windowFilled), input.AvailableBytes); |
141 |
int copied; |
142 |
|
143 |
var tailLen = WindowSize - windowEnd; |
144 |
if (length > tailLen) |
145 |
{ |
146 |
copied = input.CopyBytes(window, windowEnd, tailLen); |
147 |
if (copied == tailLen) |
148 |
{ |
149 |
copied += input.CopyBytes(window, 0, length - tailLen); |
150 |
} |
151 |
} |
152 |
else |
153 |
{ |
154 |
copied = input.CopyBytes(window, windowEnd, length); |
155 |
} |
156 |
|
157 |
windowEnd = (windowEnd + copied) & WindowMask; |
158 |
windowFilled += copied; |
159 |
return copied; |
160 |
} |
161 |
|
162 |
/// <summary> |
163 |
/// Copy dictionary to window |
164 |
/// </summary> |
165 |
/// <param name="dictionary">source dictionary</param> |
166 |
/// <param name="offset">offset of start in source dictionary</param> |
167 |
/// <param name="length">length of dictionary</param> |
168 |
/// <exception cref="InvalidOperationException"> |
169 |
/// If window isnt empty |
170 |
/// </exception> |
171 |
public void CopyDict(byte[] dictionary, int offset, int length) |
172 |
{ |
173 |
if (dictionary == null) |
174 |
{ |
175 |
throw new ArgumentNullException("dictionary"); |
176 |
} |
177 |
|
178 |
if (windowFilled > 0) |
179 |
{ |
180 |
throw new InvalidOperationException(); |
181 |
} |
182 |
|
183 |
if (length > WindowSize) |
184 |
{ |
185 |
offset += length - WindowSize; |
186 |
length = WindowSize; |
187 |
} |
188 |
Array.Copy(dictionary, offset, window, 0, length); |
189 |
windowEnd = length & WindowMask; |
190 |
} |
191 |
|
192 |
/// <summary> |
193 |
/// Get remaining unfilled space in window |
194 |
/// </summary> |
195 |
/// <returns>Number of bytes left in window</returns> |
196 |
public int GetFreeSpace() |
197 |
{ |
198 |
return WindowSize - windowFilled; |
199 |
} |
200 |
|
201 |
/// <summary> |
202 |
/// Get bytes available for output in window |
203 |
/// </summary> |
204 |
/// <returns>Number of bytes filled</returns> |
205 |
public int GetAvailable() |
206 |
{ |
207 |
return windowFilled; |
208 |
} |
209 |
|
210 |
/// <summary> |
211 |
/// Copy contents of window to output |
212 |
/// </summary> |
213 |
/// <param name="output">buffer to copy to</param> |
214 |
/// <param name="offset">offset to start at</param> |
215 |
/// <param name="len">number of bytes to count</param> |
216 |
/// <returns>The number of bytes copied</returns> |
217 |
/// <exception cref="InvalidOperationException"> |
218 |
/// If a window underflow occurs |
219 |
/// </exception> |
220 |
public int CopyOutput(byte[] output, int offset, int len) |
221 |
{ |
222 |
var copyEnd = windowEnd; |
223 |
if (len > windowFilled) |
224 |
{ |
225 |
len = windowFilled; |
226 |
} |
227 |
else |
228 |
{ |
229 |
copyEnd = (windowEnd - windowFilled + len) & WindowMask; |
230 |
} |
231 |
|
232 |
var copied = len; |
233 |
var tailLen = len - copyEnd; |
234 |
|
235 |
if (tailLen > 0) |
236 |
{ |
237 |
Array.Copy(window, WindowSize - tailLen, output, offset, tailLen); |
238 |
offset += tailLen; |
239 |
len = copyEnd; |
240 |
} |
241 |
Array.Copy(window, copyEnd - len, output, offset, len); |
242 |
windowFilled -= copied; |
243 |
if (windowFilled < 0) |
244 |
{ |
245 |
throw new InvalidOperationException(); |
246 |
} |
247 |
return copied; |
248 |
} |
249 |
|
250 |
/// <summary> |
251 |
/// Reset by clearing window so <see cref="GetAvailable">GetAvailable</see> returns 0 |
252 |
/// </summary> |
253 |
public void Reset() |
254 |
{ |
255 |
windowFilled = windowEnd = 0; |
256 |
} |
257 |
} |
258 |
} |