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