Statistics
| Branch: | Revision:

root / trunk / hammock / src / net35 / ICSharpCode.SharpZipLib.Silverlight / Zip / Compression / Streams / StreamManipulator.cs @ 0eea575a

History | View | Annotate | Download (10.1 kB)

1
// StreamManipulator.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
    /// This class allows us to retrieve a specified number 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 than 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
        #region Instance Fields
61
        private byte[] window_;
62
        private int windowStart_;
63
        private int windowEnd_;
64
		
65
        private uint buffer_;
66
        private int bitsInBuffer_;
67
        #endregion
68

    
69
        /// <summary>
70
        /// Get the next sequence of bits but don't increase input pointer.  bitCount must be
71
        /// less or equal 16 and if this call succeeds, you must drop
72
        /// at least n - 8 bits in the next call.
73
        /// </summary>
74
        /// <param name="bitCount">The number of bits to peek.</param>
75
        /// <returns>
76
        /// the value of the bits, or -1 if not enough bits available.  */
77
        /// </returns>
78
        public int PeekBits(int bitCount)
79
        {
80
            if (bitsInBuffer_ < bitCount) {
81
                if (windowStart_ == windowEnd_) {
82
                    return -1; // ok
83
                }
84
                buffer_ |= (uint)((window_[windowStart_++] & 0xff |
85
                                   (window_[windowStart_++] & 0xff) << 8) << bitsInBuffer_);
86
                bitsInBuffer_ += 16;
87
            }
88
            return (int)(buffer_ & ((1 << bitCount) - 1));
89
        }
90
		
91
        /// <summary>
92
        /// Drops the next n bits from the input.  You should have called PeekBits
93
        /// with a bigger or equal n before, to make sure that enough bits are in
94
        /// the bit buffer.
95
        /// </summary>
96
        /// <param name="bitCount">The number of bits to drop.</param>
97
        public void DropBits(int bitCount)
98
        {
99
            buffer_ >>= bitCount;
100
            bitsInBuffer_ -= bitCount;
101
        }
102
		
103
        /// <summary>
104
        /// Gets the next n bits and increases input pointer.  This is equivalent
105
        /// to <see cref="PeekBits"/> followed by <see cref="DropBits"/>, except for correct error handling.
106
        /// </summary>
107
        /// <param name="bitCount">The number of bits to retrieve.</param>
108
        /// <returns>
109
        /// the value of the bits, or -1 if not enough bits available.
110
        /// </returns>
111
        public int GetBits(int bitCount)
112
        {
113
            int bits = PeekBits(bitCount);
114
            if (bits >= 0) {
115
                DropBits(bitCount);
116
            }
117
            return bits;
118
        }
119
		
120
        /// <summary>
121
        /// Gets the number of bits available in the bit buffer.  This must be
122
        /// only called when a previous PeekBits() returned -1.
123
        /// </summary>
124
        /// <returns>
125
        /// the number of bits available.
126
        /// </returns>
127
        public int AvailableBits {
128
            get {
129
                return bitsInBuffer_;
130
            }
131
        }
132
		
133
        /// <summary>
134
        /// Gets the number of bytes available.
135
        /// </summary>
136
        /// <returns>
137
        /// The number of bytes available.
138
        /// </returns>
139
        public int AvailableBytes {
140
            get {
141
                return windowEnd_ - windowStart_ + (bitsInBuffer_ >> 3);
142
            }
143
        }
144
		
145
        /// <summary>
146
        /// Skips to the next byte boundary.
147
        /// </summary>
148
        public void SkipToByteBoundary()
149
        {
150
            buffer_ >>= (bitsInBuffer_ & 7);
151
            bitsInBuffer_ &= ~7;
152
        }
153

    
154
        /// <summary>
155
        /// Returns true when SetInput can be called
156
        /// </summary>
157
        public bool IsNeedingInput {
158
            get {
159
                return windowStart_ == windowEnd_;
160
            }
161
        }
162
		
163
        /// <summary>
164
        /// Copies bytes from input buffer to output buffer starting
165
        /// at output[offset].  You have to make sure, that the buffer is
166
        /// byte aligned.  If not enough bytes are available, copies fewer
167
        /// bytes.
168
        /// </summary>
169
        /// <param name="output">
170
        /// The buffer to copy bytes to.
171
        /// </param>
172
        /// <param name="offset">
173
        /// The offset in the buffer at which copying starts
174
        /// </param>
175
        /// <param name="length">
176
        /// The length to copy, 0 is allowed.
177
        /// </param>
178
        /// <returns>
179
        /// The number of bytes copied, 0 if no bytes were available.
180
        /// </returns>
181
        /// <exception cref="ArgumentOutOfRangeException">
182
        /// Length is less than zero
183
        /// </exception>
184
        /// <exception cref="InvalidOperationException">
185
        /// Bit buffer isnt byte aligned
186
        /// </exception>
187
        public int CopyBytes(byte[] output, int offset, int length)
188
        {
189
            if (length < 0) {
190
                throw new ArgumentOutOfRangeException("length");
191
            }
192

    
193
            if ((bitsInBuffer_ & 7) != 0) {
194
                // bits_in_buffer may only be 0 or a multiple of 8
195
                throw new InvalidOperationException("Bit buffer is not byte aligned!");
196
            }
197
			
198
            int count = 0;
199
            while ((bitsInBuffer_ > 0) && (length > 0)) {
200
                output[offset++] = (byte) buffer_;
201
                buffer_ >>= 8;
202
                bitsInBuffer_ -= 8;
203
                length--;
204
                count++;
205
            }
206
			
207
            if (length == 0) {
208
                return count;
209
            }
210
			
211
            int avail = windowEnd_ - windowStart_;
212
            if (length > avail) {
213
                length = avail;
214
            }
215
            Array.Copy(window_, windowStart_, output, offset, length);
216
            windowStart_ += length;
217
			
218
            if (((windowStart_ - windowEnd_) & 1) != 0) {
219
                // We always want an even number of bytes in input, see peekBits
220
                buffer_ = (uint)(window_[windowStart_++] & 0xff);
221
                bitsInBuffer_ = 8;
222
            }
223
            return count + length;
224
        }
225
		
226
        /// <summary>
227
        /// Resets state and empties internal buffers
228
        /// </summary>
229
        public void Reset()
230
        {
231
            buffer_ = 0;
232
            windowStart_ = windowEnd_ = bitsInBuffer_ = 0;
233
        }
234

    
235
        /// <summary>
236
        /// Add more input for consumption.
237
        /// Only call when IsNeedingInput returns true
238
        /// </summary>
239
        /// <param name="buffer">data to be input</param>
240
        /// <param name="offset">offset of first byte of input</param>
241
        /// <param name="count">number of bytes of input to add.</param>
242
        public void SetInput(byte[] buffer, int offset, int count)
243
        {
244
            if ( buffer == null ) {
245
                throw new ArgumentNullException("buffer");
246
            }
247

    
248
            if ( offset < 0 ) {
249
                throw new ArgumentOutOfRangeException("offset", "Cannot be negative");		
250
            }
251

    
252
            if ( count < 0 ) {
253
                throw new ArgumentOutOfRangeException("count", "Cannot be negative");		
254
            }
255

    
256
            if (windowStart_ < windowEnd_) {
257
                throw new InvalidOperationException("Old input was not completely processed");
258
            }
259
			
260
            int end = offset + count;
261
			
262
            // We want to throw an ArrayIndexOutOfBoundsException early.
263
            // Note the check also handles integer wrap around.
264
            if ((offset > end) || (end > buffer.Length) ) {
265
                throw new ArgumentOutOfRangeException("count");
266
            }
267
			
268
            if ((count & 1) != 0) {
269
                // We always want an even number of bytes in input, see PeekBits
270
                buffer_ |= (uint)((buffer[offset++] & 0xff) << bitsInBuffer_);
271
                bitsInBuffer_ += 8;
272
            }
273
			
274
            window_ = buffer;
275
            windowStart_ = offset;
276
            windowEnd_ = end;
277
        }
278
    }
279
}