root/trunk/Updater/ICSharpCode.SharpZipLib/Zip/Compression/Streams/StreamManipulator.cs @ 597

Wersja 597, 9.1 KB (wprowadzona przez marek, 17 years temu)

re #165

Line 
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
39using System;
40
41namespace ICSharpCode.SharpZipLib.Zip.Compression.Streams
42{
43       
44        /// <summary>
45        /// This class allows us to retrieve a specified number of bits from
46        /// the input buffer, as well as copy big byte blocks.
47        ///
48        /// It uses an int buffer to store up to 31 bits for direct
49        /// manipulation.  This guarantees that we can get at least 16 bits,
50        /// but we only need at most 15, so this is all safe.
51        ///
52        /// There are some optimizations in this class, for example, you must
53        /// never peek more than 8 bits more than needed, and you must first
54        /// peek bits before you may drop them.  This is not a general purpose
55        /// class but optimized for the behaviour of the Inflater.
56        ///
57        /// authors of the original java version : John Leuner, Jochen Hoenicke
58        /// </summary>
59        public class StreamManipulator
60        {
61                #region Constructors
62                /// <summary>
63                /// Constructs a default StreamManipulator with all buffers empty
64                /// </summary>
65                public StreamManipulator()
66                {
67                }
68                #endregion
69
70                /// <summary>
71                /// Get the next sequence of bits but don't increase input pointer.  bitCount must be
72                /// less or equal 16 and if this call succeeds, you must drop
73                /// at least n - 8 bits in the next call.
74                /// </summary>
75                /// <param name="bitCount">The number of bits to peek.</param>
76                /// <returns>
77                /// the value of the bits, or -1 if not enough bits available.  */
78                /// </returns>
79                public int PeekBits(int bitCount)
80                {
81                        if (bitsInBuffer_ < bitCount) {
82                                if (windowStart_ == windowEnd_) {
83                                        return -1; // ok
84                                }
85                                buffer_ |= (uint)((window_[windowStart_++] & 0xff |
86                                                                 (window_[windowStart_++] & 0xff) << 8) << bitsInBuffer_);
87                                bitsInBuffer_ += 16;
88                        }
89                        return (int)(buffer_ & ((1 << bitCount) - 1));
90                }
91               
92                /// <summary>
93                /// Drops the next n bits from the input.  You should have called PeekBits
94                /// with a bigger or equal n before, to make sure that enough bits are in
95                /// the bit buffer.
96                /// </summary>
97                /// <param name="bitCount">The number of bits to drop.</param>
98                public void DropBits(int bitCount)
99                {
100                        buffer_ >>= bitCount;
101                        bitsInBuffer_ -= bitCount;
102                }
103               
104                /// <summary>
105                /// Gets the next n bits and increases input pointer.  This is equivalent
106                /// to <see cref="PeekBits"/> followed by <see cref="DropBits"/>, except for correct error handling.
107                /// </summary>
108                /// <param name="bitCount">The number of bits to retrieve.</param>
109                /// <returns>
110                /// the value of the bits, or -1 if not enough bits available.
111                /// </returns>
112                public int GetBits(int bitCount)
113                {
114                        int bits = PeekBits(bitCount);
115                        if (bits >= 0) {
116                                DropBits(bitCount);
117                        }
118                        return bits;
119                }
120               
121                /// <summary>
122                /// Gets the number of bits available in the bit buffer.  This must be
123                /// only called when a previous PeekBits() returned -1.
124                /// </summary>
125                /// <returns>
126                /// the number of bits available.
127                /// </returns>
128                public int AvailableBits {
129                        get {
130                                return bitsInBuffer_;
131                        }
132                }
133               
134                /// <summary>
135                /// Gets the number of bytes available.
136                /// </summary>
137                /// <returns>
138                /// The number of bytes available.
139                /// </returns>
140                public int AvailableBytes {
141                        get {
142                                return windowEnd_ - windowStart_ + (bitsInBuffer_ >> 3);
143                        }
144                }
145               
146                /// <summary>
147                /// Skips to the next byte boundary.
148                /// </summary>
149                public void SkipToByteBoundary()
150                {
151                        buffer_ >>= (bitsInBuffer_ & 7);
152                        bitsInBuffer_ &= ~7;
153                }
154
155                /// <summary>
156                /// Returns true when SetInput can be called
157                /// </summary>
158                public bool IsNeedingInput {
159                        get {
160                                return windowStart_ == windowEnd_;
161                        }
162                }
163               
164                /// <summary>
165                /// Copies bytes from input buffer to output buffer starting
166                /// at output[offset].  You have to make sure, that the buffer is
167                /// byte aligned.  If not enough bytes are available, copies fewer
168                /// bytes.
169                /// </summary>
170                /// <param name="output">
171                /// The buffer to copy bytes to.
172                /// </param>
173                /// <param name="offset">
174                /// The offset in the buffer at which copying starts
175                /// </param>
176                /// <param name="length">
177                /// The length to copy, 0 is allowed.
178                /// </param>
179                /// <returns>
180                /// The number of bytes copied, 0 if no bytes were available.
181                /// </returns>
182                /// <exception cref="ArgumentOutOfRangeException">
183                /// Length is less than zero
184                /// </exception>
185                /// <exception cref="InvalidOperationException">
186                /// Bit buffer isnt byte aligned
187                /// </exception>
188                public int CopyBytes(byte[] output, int offset, int length)
189                {
190                        if (length < 0) {
191                                throw new ArgumentOutOfRangeException("length");
192                        }
193
194                        if ((bitsInBuffer_ & 7) != 0) {
195                                // bits_in_buffer may only be 0 or a multiple of 8
196                                throw new InvalidOperationException("Bit buffer is not byte aligned!");
197                        }
198                       
199                        int count = 0;
200                        while ((bitsInBuffer_ > 0) && (length > 0)) {
201                                output[offset++] = (byte) buffer_;
202                                buffer_ >>= 8;
203                                bitsInBuffer_ -= 8;
204                                length--;
205                                count++;
206                        }
207                       
208                        if (length == 0) {
209                                return count;
210                        }
211                       
212                        int avail = windowEnd_ - windowStart_;
213                        if (length > avail) {
214                                length = avail;
215                        }
216                        System.Array.Copy(window_, windowStart_, output, offset, length);
217                        windowStart_ += length;
218                       
219                        if (((windowStart_ - windowEnd_) & 1) != 0) {
220                                // We always want an even number of bytes in input, see peekBits
221                                buffer_ = (uint)(window_[windowStart_++] & 0xff);
222                                bitsInBuffer_ = 8;
223                        }
224                        return count + length;
225                }
226               
227                /// <summary>
228                /// Resets state and empties internal buffers
229                /// </summary>
230                public void Reset()
231                {
232                        buffer_ = 0;
233                        windowStart_ = windowEnd_ = bitsInBuffer_ = 0;
234                }
235
236                /// <summary>
237                /// Add more input for consumption.
238                /// Only call when IsNeedingInput returns true
239                /// </summary>
240                /// <param name="buffer">data to be input</param>
241                /// <param name="offset">offset of first byte of input</param>
242                /// <param name="count">number of bytes of input to add.</param>
243                public void SetInput(byte[] buffer, int offset, int count)
244                {
245                        if ( buffer == null ) {
246                                throw new ArgumentNullException("buffer");
247                        }
248
249                        if ( offset < 0 ) {
250#if NETCF_1_0
251                                throw new ArgumentOutOfRangeException("offset");
252#else
253                                throw new ArgumentOutOfRangeException("offset", "Cannot be negative");
254#endif                         
255                        }
256
257                        if ( count < 0 ) {
258#if NETCF_1_0
259                                throw new ArgumentOutOfRangeException("count");
260#else
261                                throw new ArgumentOutOfRangeException("count", "Cannot be negative");
262#endif                         
263                        }
264
265                        if (windowStart_ < windowEnd_) {
266                                throw new InvalidOperationException("Old input was not completely processed");
267                        }
268                       
269                        int end = offset + count;
270                       
271                        // We want to throw an ArrayIndexOutOfBoundsException early.
272                        // Note the check also handles integer wrap around.
273                        if ((offset > end) || (end > buffer.Length) ) {
274                                throw new ArgumentOutOfRangeException("count");
275                        }
276                       
277                        if ((count & 1) != 0) {
278                                // We always want an even number of bytes in input, see PeekBits
279                                buffer_ |= (uint)((buffer[offset++] & 0xff) << bitsInBuffer_);
280                                bitsInBuffer_ += 8;
281                        }
282                       
283                        window_ = buffer;
284                        windowStart_ = offset;
285                        windowEnd_ = end;
286                }
287
288                #region Instance Fields
289                private byte[] window_;
290                private int windowStart_;
291                private int windowEnd_;
292
293                private uint buffer_;
294                private int bitsInBuffer_;
295                #endregion
296        }
297}
Notatka: Zobacz TracBrowser aby uzyskać więcej informacji.