[DDK]
[reactos.git] / irc / TechBot / Compression / Streams / StreamManipulator.cs
1 // StreamManipulator.cs
2 // Copyright (C) 2001 Mike Krueger
3 //
4 // This file was translated from java, it was part of the GNU Classpath
5 // Copyright (C) 2001 Free Software Foundation, Inc.
6 //
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License
9 // as published by the Free Software Foundation; either version 2
10 // of the License, or (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 //
21 // Linking this library statically or dynamically with other modules is
22 // making a combined work based on this library. Thus, the terms and
23 // conditions of the GNU General Public License cover the whole
24 // combination.
25 //
26 // As a special exception, the copyright holders of this library give you
27 // permission to link this library with independent modules to produce an
28 // executable, regardless of the license terms of these independent
29 // modules, and to copy and distribute the resulting executable under
30 // terms of your choice, provided that you also meet, for each linked
31 // independent module, the terms and conditions of the license of that
32 // module. An independent module is a module which is not derived from
33 // or based on this library. If you modify this library, you may extend
34 // this exception to your version of the library, but you are not
35 // obligated to do so. If you do not wish to do so, delete this
36 // exception statement from your version.
37
38 using System;
39
40 namespace ICSharpCode.SharpZipLib.Zip.Compression.Streams
41 {
42
43 /// <summary>
44 /// This class allows us to retrieve a specified amount of bits from
45 /// the input buffer, as well as copy big byte blocks.
46 ///
47 /// It uses an int buffer to store up to 31 bits for direct
48 /// manipulation. This guarantees that we can get at least 16 bits,
49 /// but we only need at most 15, so this is all safe.
50 ///
51 /// There are some optimizations in this class, for example, you must
52 /// never peek more then 8 bits more than needed, and you must first
53 /// peek bits before you may drop them. This is not a general purpose
54 /// class but optimized for the behaviour of the Inflater.
55 ///
56 /// authors of the original java version : John Leuner, Jochen Hoenicke
57 /// </summary>
58 public class StreamManipulator
59 {
60 private byte[] window;
61 private int window_start = 0;
62 private int window_end = 0;
63
64 private uint buffer = 0;
65 private int bits_in_buffer = 0;
66
67 /// <summary>
68 /// Get the next n bits but don't increase input pointer. n must be
69 /// less or equal 16 and if you if this call succeeds, you must drop
70 /// at least n-8 bits in the next call.
71 /// </summary>
72 /// <returns>
73 /// the value of the bits, or -1 if not enough bits available. */
74 /// </returns>
75 public int PeekBits(int n)
76 {
77 if (bits_in_buffer < n) {
78 if (window_start == window_end) {
79 return -1; // ok
80 }
81 buffer |= (uint)((window[window_start++] & 0xff |
82 (window[window_start++] & 0xff) << 8) << bits_in_buffer);
83 bits_in_buffer += 16;
84 }
85 return (int)(buffer & ((1 << n) - 1));
86 }
87
88 /// <summary>
89 /// Drops the next n bits from the input. You should have called peekBits
90 /// with a bigger or equal n before, to make sure that enough bits are in
91 /// the bit buffer.
92 /// </summary>
93 public void DropBits(int n)
94 {
95 buffer >>= n;
96 bits_in_buffer -= n;
97 }
98
99 /// <summary>
100 /// Gets the next n bits and increases input pointer. This is equivalent
101 /// to peekBits followed by dropBits, except for correct error handling.
102 /// </summary>
103 /// <returns>
104 /// the value of the bits, or -1 if not enough bits available.
105 /// </returns>
106 public int GetBits(int n)
107 {
108 int bits = PeekBits(n);
109 if (bits >= 0) {
110 DropBits(n);
111 }
112 return bits;
113 }
114
115 /// <summary>
116 /// Gets the number of bits available in the bit buffer. This must be
117 /// only called when a previous peekBits() returned -1.
118 /// </summary>
119 /// <returns>
120 /// the number of bits available.
121 /// </returns>
122 public int AvailableBits {
123 get {
124 return bits_in_buffer;
125 }
126 }
127
128 /// <summary>
129 /// Gets the number of bytes available.
130 /// </summary>
131 /// <returns>
132 /// the number of bytes available.
133 /// </returns>
134 public int AvailableBytes {
135 get {
136 return window_end - window_start + (bits_in_buffer >> 3);
137 }
138 }
139
140 /// <summary>
141 /// Skips to the next byte boundary.
142 /// </summary>
143 public void SkipToByteBoundary()
144 {
145 buffer >>= (bits_in_buffer & 7);
146 bits_in_buffer &= ~7;
147 }
148
149 public bool IsNeedingInput {
150 get {
151 return window_start == window_end;
152 }
153 }
154
155 /// <summary>
156 /// Copies length bytes from input buffer to output buffer starting
157 /// at output[offset]. You have to make sure, that the buffer is
158 /// byte aligned. If not enough bytes are available, copies fewer
159 /// bytes.
160 /// </summary>
161 /// <param name="output">
162 /// the buffer.
163 /// </param>
164 /// <param name="offset">
165 /// the offset in the buffer.
166 /// </param>
167 /// <param name="length">
168 /// the length to copy, 0 is allowed.
169 /// </param>
170 /// <returns>
171 /// the number of bytes copied, 0 if no byte is available.
172 /// </returns>
173 public int CopyBytes(byte[] output, int offset, int length)
174 {
175 if (length < 0) {
176 throw new ArgumentOutOfRangeException("length negative");
177 }
178 if ((bits_in_buffer & 7) != 0) {
179 /* bits_in_buffer may only be 0 or 8 */
180 throw new InvalidOperationException("Bit buffer is not aligned!");
181 }
182
183 int count = 0;
184 while (bits_in_buffer > 0 && length > 0) {
185 output[offset++] = (byte) buffer;
186 buffer >>= 8;
187 bits_in_buffer -= 8;
188 length--;
189 count++;
190 }
191 if (length == 0) {
192 return count;
193 }
194
195 int avail = window_end - window_start;
196 if (length > avail) {
197 length = avail;
198 }
199 System.Array.Copy(window, window_start, output, offset, length);
200 window_start += length;
201
202 if (((window_start - window_end) & 1) != 0) {
203 /* We always want an even number of bytes in input, see peekBits */
204 buffer = (uint)(window[window_start++] & 0xff);
205 bits_in_buffer = 8;
206 }
207 return count + length;
208 }
209
210 public StreamManipulator()
211 {
212 }
213
214 public void Reset()
215 {
216 buffer = (uint)(window_start = window_end = bits_in_buffer = 0);
217 }
218
219 public void SetInput(byte[] buf, int off, int len)
220 {
221 if (window_start < window_end) {
222 throw new InvalidOperationException("Old input was not completely processed");
223 }
224
225 int end = off + len;
226
227 /* We want to throw an ArrayIndexOutOfBoundsException early. The
228 * check is very tricky: it also handles integer wrap around.
229 */
230 if (0 > off || off > end || end > buf.Length) {
231 throw new ArgumentOutOfRangeException();
232 }
233
234 if ((len & 1) != 0) {
235 /* We always want an even number of bytes in input, see peekBits */
236 buffer |= (uint)((buf[off++] & 0xff) << bits_in_buffer);
237 bits_in_buffer += 8;
238 }
239
240 window = buf;
241 window_start = off;
242 window_end = end;
243 }
244 }
245 }