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

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

re #165

Line 
1// Inflater.cs
2//
3// Copyright (C) 2001 Mike Krueger
4// Copyright (C) 2004 John Reilly
5//
6// This file was translated from java, it was part of the GNU Classpath
7// Copyright (C) 2001 Free Software Foundation, Inc.
8//
9// This program is free software; you can redistribute it and/or
10// modify it under the terms of the GNU General Public License
11// as published by the Free Software Foundation; either version 2
12// of the License, or (at your option) any later version.
13//
14// This program is distributed in the hope that it will be useful,
15// but WITHOUT ANY WARRANTY; without even the implied warranty of
16// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17// GNU General Public License for more details.
18//
19// You should have received a copy of the GNU General Public License
20// along with this program; if not, write to the Free Software
21// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22//
23// Linking this library statically or dynamically with other modules is
24// making a combined work based on this library.  Thus, the terms and
25// conditions of the GNU General Public License cover the whole
26// combination.
27//
28// As a special exception, the copyright holders of this library give you
29// permission to link this library with independent modules to produce an
30// executable, regardless of the license terms of these independent
31// modules, and to copy and distribute the resulting executable under
32// terms of your choice, provided that you also meet, for each linked
33// independent module, the terms and conditions of the license of that
34// module.  An independent module is a module which is not derived from
35// or based on this library.  If you modify this library, you may extend
36// this exception to your version of the library, but you are not
37// obligated to do so.  If you do not wish to do so, delete this
38// exception statement from your version.
39
40using System;
41
42using ICSharpCode.SharpZipLib.Checksums;
43using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
44
45namespace ICSharpCode.SharpZipLib.Zip.Compression
46{
47        /// <summary>
48        /// Inflater is used to decompress data that has been compressed according
49        /// to the "deflate" standard described in rfc1951.
50        ///
51        /// By default Zlib (rfc1950) headers and footers are expected in the input.
52        /// You can use constructor <code> public Inflater(bool noHeader)</code> passing true
53        /// if there is no Zlib header information
54        ///
55        /// The usage is as following.  First you have to set some input with
56        /// <code>SetInput()</code>, then Inflate() it.  If inflate doesn't
57        /// inflate any bytes there may be three reasons:
58        /// <ul>
59        /// <li>IsNeedingInput() returns true because the input buffer is empty.
60        /// You have to provide more input with <code>SetInput()</code>.
61        /// NOTE: IsNeedingInput() also returns true when, the stream is finished.
62        /// </li>
63        /// <li>IsNeedingDictionary() returns true, you have to provide a preset
64        ///    dictionary with <code>SetDictionary()</code>.</li>
65        /// <li>IsFinished returns true, the inflater has finished.</li>
66        /// </ul>
67        /// Once the first output byte is produced, a dictionary will not be
68        /// needed at a later stage.
69        ///
70        /// author of the original java version : John Leuner, Jochen Hoenicke
71        /// </summary>
72        public class Inflater
73        {
74                #region Constants/Readonly
75                /// <summary>
76                /// Copy lengths for literal codes 257..285
77                /// </summary>
78                static readonly int[] CPLENS = {
79                                                                  3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
80                                                                  35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258
81                                                          };
82               
83                /// <summary>
84                /// Extra bits for literal codes 257..285
85                /// </summary>
86                static readonly int[] CPLEXT = {
87                                                                  0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
88                                                                  3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0
89                                                          };
90               
91                /// <summary>
92                /// Copy offsets for distance codes 0..29
93                /// </summary>
94                static readonly int[] CPDIST = {
95                                                                1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
96                                                                257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
97                                                                8193, 12289, 16385, 24577
98                                                          };
99               
100                /// <summary>
101                /// Extra bits for distance codes
102                /// </summary>
103                static readonly int[] CPDEXT = {
104                                                                0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
105                                                                7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
106                                                                12, 12, 13, 13
107                                                          };
108               
109                /// <summary>
110                /// These are the possible states for an inflater
111                /// </summary>
112                const int DECODE_HEADER           = 0;
113                const int DECODE_DICT             = 1;
114                const int DECODE_BLOCKS           = 2;
115                const int DECODE_STORED_LEN1      = 3;
116                const int DECODE_STORED_LEN2      = 4;
117                const int DECODE_STORED           = 5;
118                const int DECODE_DYN_HEADER       = 6;
119                const int DECODE_HUFFMAN          = 7;
120                const int DECODE_HUFFMAN_LENBITS  = 8;
121                const int DECODE_HUFFMAN_DIST     = 9;
122                const int DECODE_HUFFMAN_DISTBITS = 10;
123                const int DECODE_CHKSUM           = 11;
124                const int FINISHED                = 12;
125                #endregion
126
127                #region Instance Fields
128                /// <summary>
129                /// This variable contains the current state.
130                /// </summary>
131                int mode;
132               
133                /// <summary>
134                /// The adler checksum of the dictionary or of the decompressed
135                /// stream, as it is written in the header resp. footer of the
136                /// compressed stream.
137                /// Only valid if mode is DECODE_DICT or DECODE_CHKSUM.
138                /// </summary>
139                int readAdler;
140               
141                /// <summary>
142                /// The number of bits needed to complete the current state.  This
143                /// is valid, if mode is DECODE_DICT, DECODE_CHKSUM,
144                /// DECODE_HUFFMAN_LENBITS or DECODE_HUFFMAN_DISTBITS.
145                /// </summary>
146                int neededBits;
147                int repLength;
148                int repDist;
149                int uncomprLen;
150               
151                /// <summary>
152                /// True, if the last block flag was set in the last block of the
153                /// inflated stream.  This means that the stream ends after the
154                /// current block.
155                /// </summary>
156                bool isLastBlock;
157               
158                /// <summary>
159                /// The total number of inflated bytes.
160                /// </summary>
161                long totalOut;
162               
163                /// <summary>
164                /// The total number of bytes set with setInput().  This is not the
165                /// value returned by the TotalIn property, since this also includes the
166                /// unprocessed input.
167                /// </summary>
168                long totalIn;
169               
170                /// <summary>
171                /// This variable stores the noHeader flag that was given to the constructor.
172                /// True means, that the inflated stream doesn't contain a Zlib header or
173                /// footer.
174                /// </summary>
175                bool noHeader;
176               
177                StreamManipulator input;
178                OutputWindow outputWindow;
179                InflaterDynHeader dynHeader;
180                InflaterHuffmanTree litlenTree, distTree;
181                Adler32 adler;
182                #endregion
183               
184                #region Constructors
185                /// <summary>
186                /// Creates a new inflater or RFC1951 decompressor
187                /// RFC1950/Zlib headers and footers will be expected in the input data
188                /// </summary>
189                public Inflater() : this(false)
190                {
191                }
192               
193                /// <summary>
194                /// Creates a new inflater.
195                /// </summary>
196                /// <param name="noHeader">
197                /// True if no RFC1950/Zlib header and footer fields are expected in the input data
198                ///
199                /// This is used for GZIPed/Zipped input.
200                ///
201                /// For compatibility with
202                /// Sun JDK you should provide one byte of input more than needed in
203                /// this case.
204                /// </param>
205                public Inflater(bool noHeader)
206                {
207                        this.noHeader = noHeader;
208                        this.adler = new Adler32();
209                        input = new StreamManipulator();
210                        outputWindow = new OutputWindow();
211                        mode = noHeader ? DECODE_BLOCKS : DECODE_HEADER;
212                }
213                #endregion
214
215                /// <summary>
216                /// Resets the inflater so that a new stream can be decompressed.  All
217                /// pending input and output will be discarded.
218                /// </summary>
219                public void Reset()
220                {
221                        mode = noHeader ? DECODE_BLOCKS : DECODE_HEADER;
222                        totalIn = 0;
223                        totalOut = 0;
224                        input.Reset();
225                        outputWindow.Reset();
226                        dynHeader = null;
227                        litlenTree = null;
228                        distTree = null;
229                        isLastBlock = false;
230                        adler.Reset();
231                }
232               
233                /// <summary>
234                /// Decodes a zlib/RFC1950 header.
235                /// </summary>
236                /// <returns>
237                /// False if more input is needed.
238                /// </returns>
239                /// <exception cref="SharpZipBaseException">
240                /// The header is invalid.
241                /// </exception>
242                private bool DecodeHeader()
243                {
244                        int header = input.PeekBits(16);
245                        if (header < 0) {
246                                return false;
247                        }
248                        input.DropBits(16);
249                       
250                        // The header is written in "wrong" byte order
251                        header = ((header << 8) | (header >> 8)) & 0xffff;
252                        if (header % 31 != 0) {
253                                throw new SharpZipBaseException("Header checksum illegal");
254                        }
255                       
256                        if ((header & 0x0f00) != (Deflater.DEFLATED << 8)) {
257                                throw new SharpZipBaseException("Compression Method unknown");
258                        }
259                       
260                        /* Maximum size of the backwards window in bits.
261                        * We currently ignore this, but we could use it to make the
262                        * inflater window more space efficient. On the other hand the
263                        * full window (15 bits) is needed most times, anyway.
264                        int max_wbits = ((header & 0x7000) >> 12) + 8;
265                        */
266                       
267                        if ((header & 0x0020) == 0) { // Dictionary flag?
268                                mode = DECODE_BLOCKS;
269                        } else {
270                                mode = DECODE_DICT;
271                                neededBits = 32;
272                        }
273                        return true;
274                }
275               
276                /// <summary>
277                /// Decodes the dictionary checksum after the deflate header.
278                /// </summary>
279                /// <returns>
280                /// False if more input is needed.
281                /// </returns>
282                private bool DecodeDict()
283                {
284                        while (neededBits > 0) {
285                                int dictByte = input.PeekBits(8);
286                                if (dictByte < 0) {
287                                        return false;
288                                }
289                                input.DropBits(8);
290                                readAdler = (readAdler << 8) | dictByte;
291                                neededBits -= 8;
292                        }
293                        return false;
294                }
295               
296                /// <summary>
297                /// Decodes the huffman encoded symbols in the input stream.
298                /// </summary>
299                /// <returns>
300                /// false if more input is needed, true if output window is
301                /// full or the current block ends.
302                /// </returns>
303                /// <exception cref="SharpZipBaseException">
304                /// if deflated stream is invalid.
305                /// </exception>
306                private bool DecodeHuffman()
307                {
308                        int free = outputWindow.GetFreeSpace();
309                        while (free >= 258)
310                        {
311                                int symbol;
312                                switch (mode)
313                                {
314                                        case DECODE_HUFFMAN:
315                                                // This is the inner loop so it is optimized a bit
316                                                while (((symbol = litlenTree.GetSymbol(input)) & ~0xff) == 0)
317                                                {
318                                                        outputWindow.Write(symbol);
319                                                        if (--free < 258)
320                                                        {
321                                                                return true;
322                                                        }
323                                                }
324                                               
325                                                if (symbol < 257)
326                                                {
327                                                        if (symbol < 0)
328                                                        {
329                                                                return false;
330                                                        }
331                                                        else
332                                                        {
333                                                                // symbol == 256: end of block
334                                                                distTree = null;
335                                                                litlenTree = null;
336                                                                mode = DECODE_BLOCKS;
337                                                                return true;
338                                                        }
339                                                }
340                                               
341                                                try
342                                                {
343                                                        repLength = CPLENS[symbol - 257];
344                                                        neededBits = CPLEXT[symbol - 257];
345                                                }
346                                                catch (Exception)
347                                                {
348                                                        throw new SharpZipBaseException("Illegal rep length code");
349                                                }
350                                                goto case DECODE_HUFFMAN_LENBITS; // fall through
351                                               
352                                        case DECODE_HUFFMAN_LENBITS:
353                                                if (neededBits > 0)
354                                                {
355                                                        mode = DECODE_HUFFMAN_LENBITS;
356                                                        int i = input.PeekBits(neededBits);
357                                                        if (i < 0)
358                                                        {
359                                                                return false;
360                                                        }
361                                                        input.DropBits(neededBits);
362                                                        repLength += i;
363                                                }
364                                                mode = DECODE_HUFFMAN_DIST;
365                                                goto case DECODE_HUFFMAN_DIST; // fall through
366                                               
367                                        case DECODE_HUFFMAN_DIST:
368                                                symbol = distTree.GetSymbol(input);
369                                                if (symbol < 0)
370                                                {
371                                                        return false;
372                                                }
373                                               
374                                                try
375                                                {
376                                                        repDist = CPDIST[symbol];
377                                                        neededBits = CPDEXT[symbol];
378                                                }
379                                                catch (Exception)
380                                                {
381                                                        throw new SharpZipBaseException("Illegal rep dist code");
382                                                }
383                                               
384                                                goto case DECODE_HUFFMAN_DISTBITS; // fall through
385                                               
386                                        case DECODE_HUFFMAN_DISTBITS:
387                                                if (neededBits > 0)
388                                                {
389                                                        mode = DECODE_HUFFMAN_DISTBITS;
390                                                        int i = input.PeekBits(neededBits);
391                                                        if (i < 0)
392                                                        {
393                                                                return false;
394                                                        }
395                                                        input.DropBits(neededBits);
396                                                        repDist += i;
397                                                }
398                                               
399                                                outputWindow.Repeat(repLength, repDist);
400                                                free -= repLength;
401                                                mode = DECODE_HUFFMAN;
402                                                break;
403                                       
404                                        default:
405                                                throw new SharpZipBaseException("Inflater unknown mode");
406                                }
407                        }
408                        return true;
409                }
410               
411                /// <summary>
412                /// Decodes the adler checksum after the deflate stream.
413                /// </summary>
414                /// <returns>
415                /// false if more input is needed.
416                /// </returns>
417                /// <exception cref="SharpZipBaseException">
418                /// If checksum doesn't match.
419                /// </exception>
420                private bool DecodeChksum()
421                {
422                        while (neededBits > 0) {
423                                int chkByte = input.PeekBits(8);
424                                if (chkByte < 0) {
425                                        return false;
426                                }
427                                input.DropBits(8);
428                                readAdler = (readAdler << 8) | chkByte;
429                                neededBits -= 8;
430                        }
431
432                        if ((int) adler.Value != readAdler) {
433                                throw new SharpZipBaseException("Adler chksum doesn't match: " + (int)adler.Value + " vs. " + readAdler);
434                        }
435
436                        mode = FINISHED;
437                        return false;
438                }
439               
440                /// <summary>
441                /// Decodes the deflated stream.
442                /// </summary>
443                /// <returns>
444                /// false if more input is needed, or if finished.
445                /// </returns>
446                /// <exception cref="SharpZipBaseException">
447                /// if deflated stream is invalid.
448                /// </exception>
449                private bool Decode()
450                {
451                        switch (mode) {
452                                case DECODE_HEADER:
453                                        return DecodeHeader();
454
455                                case DECODE_DICT:
456                                        return DecodeDict();
457
458                                case DECODE_CHKSUM:
459                                        return DecodeChksum();
460                               
461                                case DECODE_BLOCKS:
462                                        if (isLastBlock) {
463                                                if (noHeader) {
464                                                        mode = FINISHED;
465                                                        return false;
466                                                } else {
467                                                        input.SkipToByteBoundary();
468                                                        neededBits = 32;
469                                                        mode = DECODE_CHKSUM;
470                                                        return true;
471                                                }
472                                        }
473                                       
474                                        int type = input.PeekBits(3);
475                                        if (type < 0) {
476                                                return false;
477                                        }
478                                        input.DropBits(3);
479                                       
480                                        if ((type & 1) != 0) {
481                                                isLastBlock = true;
482                                        }
483                                        switch (type >> 1){
484                                                case DeflaterConstants.STORED_BLOCK:
485                                                        input.SkipToByteBoundary();
486                                                        mode = DECODE_STORED_LEN1;
487                                                        break;
488                                                case DeflaterConstants.STATIC_TREES:
489                                                        litlenTree = InflaterHuffmanTree.defLitLenTree;
490                                                        distTree = InflaterHuffmanTree.defDistTree;
491                                                        mode = DECODE_HUFFMAN;
492                                                        break;
493                                                case DeflaterConstants.DYN_TREES:
494                                                        dynHeader = new InflaterDynHeader();
495                                                        mode = DECODE_DYN_HEADER;
496                                                        break;
497                                                default:
498                                                        throw new SharpZipBaseException("Unknown block type " + type);
499                                        }
500                                        return true;
501                               
502                                case DECODE_STORED_LEN1:
503                                {
504                                        if ((uncomprLen = input.PeekBits(16)) < 0) {
505                                                return false;
506                                        }
507                                        input.DropBits(16);
508                                        mode = DECODE_STORED_LEN2;
509                                }
510                                        goto case DECODE_STORED_LEN2; // fall through
511                                       
512                                case DECODE_STORED_LEN2:
513                                {
514                                        int nlen = input.PeekBits(16);
515                                        if (nlen < 0) {
516                                                return false;
517                                        }
518                                        input.DropBits(16);
519                                        if (nlen != (uncomprLen ^ 0xffff)) {
520                                                throw new SharpZipBaseException("broken uncompressed block");
521                                        }
522                                        mode = DECODE_STORED;
523                                }
524                                        goto case DECODE_STORED; // fall through
525                                       
526                                case DECODE_STORED:
527                                {
528                                        int more = outputWindow.CopyStored(input, uncomprLen);
529                                        uncomprLen -= more;
530                                        if (uncomprLen == 0) {
531                                                mode = DECODE_BLOCKS;
532                                                return true;
533                                        }
534                                        return !input.IsNeedingInput;
535                                }
536                               
537                                case DECODE_DYN_HEADER:
538                                        if (!dynHeader.Decode(input)) {
539                                                return false;
540                                        }
541                                       
542                                        litlenTree = dynHeader.BuildLitLenTree();
543                                        distTree = dynHeader.BuildDistTree();
544                                        mode = DECODE_HUFFMAN;
545                                        goto case DECODE_HUFFMAN; // fall through
546                                       
547                                case DECODE_HUFFMAN:
548                                case DECODE_HUFFMAN_LENBITS:
549                                case DECODE_HUFFMAN_DIST:
550                                case DECODE_HUFFMAN_DISTBITS:
551                                        return DecodeHuffman();
552                               
553                                case FINISHED:
554                                        return false;
555                               
556                                default:
557                                        throw new SharpZipBaseException("Inflater.Decode unknown mode");
558                        }
559                }
560                       
561                /// <summary>
562                /// Sets the preset dictionary.  This should only be called, if
563                /// needsDictionary() returns true and it should set the same
564                /// dictionary, that was used for deflating.  The getAdler()
565                /// function returns the checksum of the dictionary needed.
566                /// </summary>
567                /// <param name="buffer">
568                /// The dictionary.
569                /// </param>
570                public void SetDictionary(byte[] buffer)
571                {
572                        SetDictionary(buffer, 0, buffer.Length);
573                }
574               
575                /// <summary>
576                /// Sets the preset dictionary.  This should only be called, if
577                /// needsDictionary() returns true and it should set the same
578                /// dictionary, that was used for deflating.  The getAdler()
579                /// function returns the checksum of the dictionary needed.
580                /// </summary>
581                /// <param name="buffer">
582                /// The dictionary.
583                /// </param>
584                /// <param name="index">
585                /// The index into buffer where the dictionary starts.
586                /// </param>
587                /// <param name="count">
588                /// The number of bytes in the dictionary.
589                /// </param>
590                /// <exception cref="System.InvalidOperationException">
591                /// No dictionary is needed.
592                /// </exception>
593                /// <exception cref="SharpZipBaseException">
594                /// The adler checksum for the buffer is invalid
595                /// </exception>
596                public void SetDictionary(byte[] buffer, int index, int count)
597                {
598                        if ( buffer == null ) {
599                                throw new ArgumentNullException("buffer");
600                        }
601
602                        if ( index < 0 ) {
603                                throw new ArgumentOutOfRangeException("index");
604                        }
605
606                        if ( count < 0 ) {
607                                throw new ArgumentOutOfRangeException("count");
608                        }
609
610                        if (!IsNeedingDictionary) {
611                                throw new InvalidOperationException("Dictionary is not needed");
612                        }
613                       
614                        adler.Update(buffer, index, count);
615
616                        if ((int)adler.Value != readAdler) {
617                                throw new SharpZipBaseException("Wrong adler checksum");
618                        }
619                        adler.Reset();
620                        outputWindow.CopyDict(buffer, index, count);
621                        mode = DECODE_BLOCKS;
622                }
623               
624                /// <summary>
625                /// Sets the input.  This should only be called, if needsInput()
626                /// returns true.
627                /// </summary>
628                /// <param name="buffer">
629                /// the input.
630                /// </param>
631                public void SetInput(byte[] buffer)
632                {
633                        SetInput(buffer, 0, buffer.Length);
634                }
635               
636                /// <summary>
637                /// Sets the input.  This should only be called, if needsInput()
638                /// returns true.
639                /// </summary>
640                /// <param name="buffer">
641                /// The source of input data
642                /// </param>
643                /// <param name="index">
644                /// The index into buffer where the input starts.
645                /// </param>
646                /// <param name="count">
647                /// The number of bytes of input to use.
648                /// </param>
649                /// <exception cref="System.InvalidOperationException">
650                /// No input is needed.
651                /// </exception>
652                /// <exception cref="System.ArgumentOutOfRangeException">
653                /// The index and/or count are wrong.
654                /// </exception>
655                public void SetInput(byte[] buffer, int index, int count)
656                {
657                        input.SetInput(buffer, index, count);
658                        totalIn += (long)count;
659                }
660               
661                /// <summary>
662                /// Inflates the compressed stream to the output buffer.  If this
663                /// returns 0, you should check, whether IsNeedingDictionary(),
664                /// IsNeedingInput() or IsFinished() returns true, to determine why no
665                /// further output is produced.
666                /// </summary>
667                /// <param name="buffer">
668                /// the output buffer.
669                /// </param>
670                /// <returns>
671                /// The number of bytes written to the buffer, 0 if no further
672                /// output can be produced.
673                /// </returns>
674                /// <exception cref="System.ArgumentOutOfRangeException">
675                /// if buffer has length 0.
676                /// </exception>
677                /// <exception cref="System.FormatException">
678                /// if deflated stream is invalid.
679                /// </exception>
680                public int Inflate(byte[] buffer)
681                {
682                        if ( buffer == null )
683                        {
684                                throw new ArgumentNullException("buffer");
685                        }
686
687                        return Inflate(buffer, 0, buffer.Length);
688                }
689               
690                /// <summary>
691                /// Inflates the compressed stream to the output buffer.  If this
692                /// returns 0, you should check, whether needsDictionary(),
693                /// needsInput() or finished() returns true, to determine why no
694                /// further output is produced.
695                /// </summary>
696                /// <param name="buffer">
697                /// the output buffer.
698                /// </param>
699                /// <param name="offset">
700                /// the offset in buffer where storing starts.
701                /// </param>
702                /// <param name="count">
703                /// the maximum number of bytes to output.
704                /// </param>
705                /// <returns>
706                /// the number of bytes written to the buffer, 0 if no further output can be produced.
707                /// </returns>
708                /// <exception cref="System.ArgumentOutOfRangeException">
709                /// if count is less than 0.
710                /// </exception>
711                /// <exception cref="System.ArgumentOutOfRangeException">
712                /// if the index and / or count are wrong.
713                /// </exception>
714                /// <exception cref="System.FormatException">
715                /// if deflated stream is invalid.
716                /// </exception>
717                public int Inflate(byte[] buffer, int offset, int count)
718                {
719                        if ( buffer == null )
720                        {
721                                throw new ArgumentNullException("buffer");
722                        }
723
724                        if ( count < 0 ) {
725#if NETCF_1_0
726                                throw new ArgumentOutOfRangeException("count");
727#else
728                                throw new ArgumentOutOfRangeException("count", "count cannot be negative");
729#endif
730                        }
731
732                        if ( offset < 0 ) {
733#if NETCF_1_0
734                                throw new ArgumentOutOfRangeException("offset");
735#else
736                                throw new ArgumentOutOfRangeException("offset", "offset cannot be negative");
737#endif
738                        }
739
740                        if ( offset + count > buffer.Length ) {
741                                throw new ArgumentException("count exceeds buffer bounds");
742                        }
743
744                        // Special case: count may be zero
745                        if (count == 0)
746                        {
747                                if (!IsFinished) { // -jr- 08-Nov-2003 INFLATE_BUG fix..
748                                        Decode();
749                                }
750                                return 0;
751                        }
752
753                        int bytesCopied = 0;
754
755                        do {
756                                if (mode != DECODE_CHKSUM) {
757                                        /* Don't give away any output, if we are waiting for the
758                                        * checksum in the input stream.
759                                        *
760                                        * With this trick we have always:
761                                        *   IsNeedingInput() and not IsFinished()
762                                        *   implies more output can be produced.
763                                        */
764                                        int more = outputWindow.CopyOutput(buffer, offset, count);
765                                        if ( more > 0 ) {
766                                                adler.Update(buffer, offset, more);
767                                                offset += more;
768                                                bytesCopied += more;
769                                                totalOut += (long)more;
770                                                count -= more;
771                                                if (count == 0) {
772                                                        return bytesCopied;
773                                                }
774                                        }
775                                }
776                        } while (Decode() || ((outputWindow.GetAvailable() > 0) && (mode != DECODE_CHKSUM)));
777                        return bytesCopied;
778                }
779               
780                /// <summary>
781                /// Returns true, if the input buffer is empty.
782                /// You should then call setInput().
783                /// NOTE: This method also returns true when the stream is finished.
784                /// </summary>
785                public bool IsNeedingInput {
786                        get {
787                                return input.IsNeedingInput;
788                        }
789                }
790               
791                /// <summary>
792                /// Returns true, if a preset dictionary is needed to inflate the input.
793                /// </summary>
794                public bool IsNeedingDictionary {
795                        get {
796                                return mode == DECODE_DICT && neededBits == 0;
797                        }
798                }
799               
800                /// <summary>
801                /// Returns true, if the inflater has finished.  This means, that no
802                /// input is needed and no output can be produced.
803                /// </summary>
804                public bool IsFinished {
805                        get {
806                                return mode == FINISHED && outputWindow.GetAvailable() == 0;
807                        }
808                }
809               
810                /// <summary>
811                /// Gets the adler checksum.  This is either the checksum of all
812                /// uncompressed bytes returned by inflate(), or if needsDictionary()
813                /// returns true (and thus no output was yet produced) this is the
814                /// adler checksum of the expected dictionary.
815                /// </summary>
816                /// <returns>
817                /// the adler checksum.
818                /// </returns>
819                public int Adler {
820                        get {
821                                return IsNeedingDictionary ? readAdler : (int) adler.Value;
822                        }
823                }
824               
825                /// <summary>
826                /// Gets the total number of output bytes returned by Inflate().
827                /// </summary>
828                /// <returns>
829                /// the total number of output bytes.
830                /// </returns>
831                public long TotalOut {
832                        get {
833                                return totalOut;
834                        }
835                }
836               
837                /// <summary>
838                /// Gets the total number of processed compressed input bytes.
839                /// </summary>
840                /// <returns>
841                /// The total number of bytes of processed input bytes.
842                /// </returns>
843                public long TotalIn {
844                        get {
845                                return totalIn - (long)RemainingInput;
846                        }
847                }
848               
849                /// <summary>
850                /// Gets the number of unprocessed input bytes.  Useful, if the end of the
851                /// stream is reached and you want to further process the bytes after
852                /// the deflate stream.
853                /// </summary>
854                /// <returns>
855                /// The number of bytes of the input which have not been processed.
856                /// </returns>
857                public int RemainingInput {
858                        // TODO: This should be a long?
859                        get {
860                                return input.AvailableBytes;
861                        }
862                }
863        }
864}
Notatka: Zobacz TracBrowser aby uzyskać więcej informacji.