Merge pull request #5714 from alexischr/update_bockbuild
[mono.git] / mono / benchmark / zipmark.cs
1 // zipmark.cs\r
2 // (This file is the NZipLib sources with a crude benchmark class attached -\r
3 //  2002-15-05 Dan Lewis <dihlewis@yahoo.co.uk>)\r
4 // -------------------------------------------------------------------------\r
5 //\r
6 // NZipLib source:\r
7 // Copyright (C) 2001 Mike Krueger\r
8 //\r
9 // This file was translated from java, it was part of the GNU Classpath\r
10 // Copyright (C) 2001 Free Software Foundation, Inc.\r
11 //\r
12 // This program is free software; you can redistribute it and/or\r
13 // modify it under the terms of the GNU General Public License\r
14 // as published by the Free Software Foundation; either version 2\r
15 // of the License, or (at your option) any later version.\r
16 //\r
17 // This program is distributed in the hope that it will be useful,\r
18 // but WITHOUT ANY WARRANTY; without even the implied warranty of\r
19 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
20 // GNU General Public License for more details.\r
21 //\r
22 // You should have received a copy of the GNU General Public License\r
23 // along with this program; if not, write to the Free Software\r
24 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\r
25 //\r
26 // As a special exception, if you link this library with other files to\r
27 // produce an executable, this library does not by itself cause the\r
28 // resulting executable to be covered by the GNU General Public License.\r
29 // This exception does not however invalidate any other reasons why the\r
30 // executable file might be covered by the GNU General Public License.\r
31 \r
32 using System;\r
33 using System.IO;\r
34 using NZlib.Streams;\r
35 using NZlib.Checksums;\r
36 using NZlib.Compression;\r
37 \r
38 class ZipMark {\r
39         static int Iterations = 1000;\r
40         static int BlockSize = 1024;\r
41 \r
42         public static void Main (string [] args)\r
43         {\r
44                 if (args.Length == 0 || args.Length > 3) {\r
45                         Console.WriteLine ("Usage: zipmark FILE [ITERATIONS] [BLOCKSIZE]");\r
46                         return;\r
47                 }\r
48         \r
49                 string filename = args [0];\r
50                 FileInfo file = new FileInfo (filename);\r
51                 if (!file.Exists) {\r
52                         Console.WriteLine ("Couldn't find file {0}", filename);\r
53                         return;\r
54                 }\r
55 \r
56                 FileStream fs = file.OpenRead ();\r
57 \r
58                 byte [] raw = new byte [file.Length];\r
59                 int count = fs.Read (raw, 0, (int)file.Length);\r
60                 fs.Close ();\r
61 \r
62                 if (count != file.Length) {\r
63                         Console.WriteLine ("Couldn't read file {0}", filename);\r
64                         return;\r
65                 }\r
66 \r
67                 Deflater def = new Deflater (Deflater.BEST_COMPRESSION, false);\r
68                 Inflater inf = new Inflater (false);\r
69 \r
70                 // 1. Count deflated size\r
71 \r
72                 int cooked_size = Deflate (def, raw, null);\r
73                 byte [] cooked = new byte [cooked_size];\r
74 \r
75                 // 2. Deflate & Inflate\r
76 \r
77                 if (args.Length > 1)\r
78                         Iterations = Int32.Parse (args [1]);\r
79                 if (args.Length > 2)\r
80                         BlockSize = Int32.Parse (args [2]);\r
81 \r
82                 for (int i = 0; i < Iterations; ++ i) {\r
83                         Deflate (def, raw, cooked);\r
84                         Inflate (inf, cooked, raw);\r
85                 }\r
86 \r
87                 return;\r
88         }\r
89 \r
90         static int Deflate (Deflater def, byte [] src, byte [] dest)\r
91         {\r
92                 bool count;\r
93                 int offset, length, remain;\r
94                 \r
95                 if (dest == null) {\r
96                         dest = new byte [BlockSize];\r
97                         count = true;\r
98                 } else\r
99                         count = false;\r
100                 \r
101                 def.Reset ();\r
102                 def.SetInput (src);\r
103 \r
104                 offset = 0;\r
105                 while (!def.IsFinished) {\r
106                         if (def.IsNeedingInput)\r
107                                 def.Finish ();\r
108 \r
109                         remain = Math.Min (dest.Length - offset, BlockSize);\r
110                         if (remain == 0)\r
111                                 break;\r
112 \r
113                         length = def.Deflate (dest, offset, remain);\r
114                         if (!count)\r
115                                 offset += length;\r
116                 }\r
117 \r
118                 return def.TotalOut;\r
119         }\r
120 \r
121         static int Inflate (Inflater inf, byte [] src, byte [] dest)\r
122         {\r
123                 int offset, length, remain;\r
124         \r
125                 inf.Reset ();\r
126                 inf.SetInput (src);\r
127 \r
128                 offset = 0;\r
129                 while (!inf.IsNeedingInput) {\r
130                         remain = Math.Min (dest.Length - offset, BlockSize);\r
131                         if (remain == 0)\r
132                                 break;\r
133 \r
134                         length = inf.Inflate (dest, offset, remain);\r
135                         offset += length;\r
136                 }\r
137 \r
138                 return inf.TotalOut;\r
139         }\r
140 }\r
141 \r
142 // ----------------------  NZipLib sources from here on --------------------------\r
143 \r
144 namespace NZlib.Compression {\r
145         \r
146         /// <summary>\r
147         /// This is the Deflater class.  The deflater class compresses input\r
148         /// with the deflate algorithm described in RFC 1951.  It has several\r
149         /// compression levels and three different strategies described below.\r
150         ///\r
151         /// This class is <i>not</i> thread safe.  This is inherent in the API, due\r
152         /// to the split of deflate and setInput.\r
153         /// \r
154         /// author of the original java version : Jochen Hoenicke\r
155         /// </summary>\r
156         public class Deflater\r
157         {\r
158                 /// <summary>\r
159                 /// The best and slowest compression level.  This tries to find very\r
160                 /// long and distant string repetitions.\r
161                 /// </summary>\r
162                 public static  int BEST_COMPRESSION = 9;\r
163                 \r
164                 /// <summary>\r
165                 /// The worst but fastest compression level.\r
166                 /// </summary>\r
167                 public static  int BEST_SPEED = 1;\r
168                 \r
169                 /// <summary>\r
170                 /// The default compression level.\r
171                 /// </summary>\r
172                 public static  int DEFAULT_COMPRESSION = -1;\r
173                 \r
174                 /// <summary>\r
175                 /// This level won't compress at all but output uncompressed blocks.\r
176                 /// </summary>\r
177                 public static  int NO_COMPRESSION = 0;\r
178                 \r
179                 /// <summary>\r
180                 /// The default strategy.\r
181                 /// </summary>\r
182                 public static  int DEFAULT_STRATEGY = 0;\r
183                 \r
184                 \r
185                 /// <summary>\r
186                 /// This strategy will only allow longer string repetitions.  It is\r
187                 /// useful for random data with a small character set.\r
188                 /// </summary>\r
189                 public static  int FILTERED = 1;\r
190                 \r
191                 /// <summary>\r
192                 /// This strategy will not look for string repetitions at all.  It\r
193                 /// only encodes with Huffman trees (which means, that more common\r
194                 /// characters get a smaller encoding.\r
195                 /// </summary>\r
196                 public static  int HUFFMAN_ONLY = 2;\r
197                 \r
198                 /// <summary>\r
199                 /// The compression method.  This is the only method supported so far.\r
200                 /// There is no need to use this constant at all.\r
201                 /// </summary>\r
202                 public static  int DEFLATED = 8;\r
203                 \r
204                 /*\r
205                 * The Deflater can do the following state transitions:\r
206                         *\r
207                         * (1) -> INIT_STATE   ----> INIT_FINISHING_STATE ---.\r
208                         *        /  | (2)      (5)                         |\r
209                         *       /   v          (5)                         |\r
210                         *   (3)| SETDICT_STATE ---> SETDICT_FINISHING_STATE |(3)\r
211                         *       \   | (3)                 |        ,-------'\r
212                         *        |  |                     | (3)   /\r
213                         *        v  v          (5)        v      v\r
214                         * (1) -> BUSY_STATE   ----> FINISHING_STATE\r
215                         *                                | (6)\r
216                         *                                v\r
217                         *                           FINISHED_STATE\r
218                         *    \_____________________________________/\r
219                         *          | (7)\r
220                         *          v\r
221                         *        CLOSED_STATE\r
222                         *\r
223                         * (1) If we should produce a header we start in INIT_STATE, otherwise\r
224                         *     we start in BUSY_STATE.\r
225                         * (2) A dictionary may be set only when we are in INIT_STATE, then\r
226                         *     we change the state as indicated.\r
227                         * (3) Whether a dictionary is set or not, on the first call of deflate\r
228                         *     we change to BUSY_STATE.\r
229                         * (4) -- intentionally left blank -- :)\r
230                         * (5) FINISHING_STATE is entered, when flush() is called to indicate that\r
231                         *     there is no more INPUT.  There are also states indicating, that\r
232                         *     the header wasn't written yet.\r
233                         * (6) FINISHED_STATE is entered, when everything has been flushed to the\r
234                         *     internal pending output buffer.\r
235                         * (7) At any time (7)\r
236                         *\r
237                         */\r
238                         \r
239                 private static  int IS_SETDICT              = 0x01;\r
240                 private static  int IS_FLUSHING             = 0x04;\r
241                 private static  int IS_FINISHING            = 0x08;\r
242                 \r
243                 private static  int INIT_STATE              = 0x00;\r
244                 private static  int SETDICT_STATE           = 0x01;\r
245 //              private static  int INIT_FINISHING_STATE    = 0x08;\r
246 //              private static  int SETDICT_FINISHING_STATE = 0x09;\r
247                 private static  int BUSY_STATE              = 0x10;\r
248                 private static  int FLUSHING_STATE          = 0x14;\r
249                 private static  int FINISHING_STATE         = 0x1c;\r
250                 private static  int FINISHED_STATE          = 0x1e;\r
251                 private static  int CLOSED_STATE            = 0x7f;\r
252                 \r
253                 /// <summary>\r
254                 /// Compression level.\r
255                 /// </summary>\r
256                 private int level;\r
257                 \r
258                 /// <summary>\r
259                 /// should we include a header.\r
260                 /// </summary>\r
261                 private bool noHeader;\r
262                 \r
263 //              /// <summary>\r
264 //              /// Compression strategy.\r
265 //              /// </summary>\r
266 //              private int strategy;\r
267                 \r
268                 /// <summary>\r
269                 /// The current state.\r
270                 /// </summary>\r
271                 private int state;\r
272                 \r
273                 /// <summary>\r
274                 /// The total bytes of output written.\r
275                 /// </summary>\r
276                 private int totalOut;\r
277                 \r
278                 /// <summary>\r
279                 /// The pending output.\r
280                 /// </summary>\r
281                 private DeflaterPending pending;\r
282                 \r
283                 /// <summary>\r
284                 /// The deflater engine.\r
285                 /// </summary>\r
286                 private DeflaterEngine engine;\r
287                 \r
288                 /// <summary>\r
289                 /// Creates a new deflater with default compression level.\r
290                 /// </summary>\r
291                 public Deflater() : this(DEFAULT_COMPRESSION, false)\r
292                 {\r
293                         \r
294                 }\r
295                 \r
296                 /// <summary>\r
297                 /// Creates a new deflater with given compression level.\r
298                 /// </summary>\r
299                 /// <param name="lvl">\r
300                 /// the compression level, a value between NO_COMPRESSION\r
301                 /// and BEST_COMPRESSION, or DEFAULT_COMPRESSION.\r
302                 /// </param>\r
303                 /// <exception cref="System.ArgumentOutOfRangeException">if lvl is out of range.</exception>\r
304                 public Deflater(int lvl) : this(lvl, false)\r
305                 {\r
306                         \r
307                 }\r
308                 \r
309                 /// <summary>\r
310                 /// Creates a new deflater with given compression level.\r
311                 /// </summary>\r
312                 /// <param name="lvl">\r
313                 /// the compression level, a value between NO_COMPRESSION\r
314                 /// and BEST_COMPRESSION.\r
315                 /// </param>\r
316                 /// <param name="nowrap">\r
317                 /// true, if we should suppress the deflate header at the\r
318                 /// beginning and the adler checksum at the end of the output.  This is\r
319                 /// useful for the GZIP format.\r
320                 /// </param>\r
321                 /// <exception cref="System.ArgumentOutOfRangeException">if lvl is out of range.</exception>\r
322                 public Deflater(int lvl, bool nowrap)\r
323                 {\r
324                         if (lvl == DEFAULT_COMPRESSION) {\r
325                                 lvl = 6;\r
326                         } else if (lvl < NO_COMPRESSION || lvl > BEST_COMPRESSION) {\r
327                                 throw new ArgumentOutOfRangeException("lvl");\r
328                         }\r
329                         \r
330                         pending = new DeflaterPending();\r
331                         engine = new DeflaterEngine(pending);\r
332                         this.noHeader = nowrap;\r
333                         SetStrategy(DEFAULT_STRATEGY);\r
334                         SetLevel(lvl);\r
335                         Reset();\r
336                 }\r
337                 \r
338                 \r
339                 /// <summary>\r
340                 /// Resets the deflater.  The deflater acts afterwards as if it was\r
341                 /// just created with the same compression level and strategy as it\r
342                 /// had before.\r
343                 /// </summary>\r
344                 public void Reset()\r
345                 {\r
346                         state = (noHeader ? BUSY_STATE : INIT_STATE);\r
347                         totalOut = 0;\r
348                         pending.Reset();\r
349                         engine.Reset();\r
350                 }\r
351                 \r
352                 /// <summary>\r
353                 /// Gets the current adler checksum of the data that was processed so far.\r
354                 /// </summary>\r
355                 public int Adler {\r
356                         get {\r
357                                 return engine.Adler;\r
358                         }\r
359                 }\r
360                 \r
361                 /// <summary>\r
362                 /// Gets the number of input bytes processed so far.\r
363                 /// </summary>\r
364                 public int TotalIn {\r
365                         get {\r
366                                 return engine.TotalIn;\r
367                         }\r
368                 }\r
369                 \r
370                 /// <summary>\r
371                 /// Gets the number of output bytes so far.\r
372                 /// </summary>\r
373                 public int TotalOut {\r
374                         get {\r
375                                 return totalOut;\r
376                         }\r
377                 }\r
378                 \r
379                 /// <summary>\r
380                 /// Flushes the current input block.  Further calls to deflate() will\r
381                 /// produce enough output to inflate everything in the current input\r
382                 /// block.  This is not part of Sun's JDK so I have made it package\r
383                 /// private.  It is used by DeflaterOutputStream to implement\r
384                 /// flush().\r
385                 /// </summary>\r
386                 public void Flush() \r
387                 {\r
388                         state |= IS_FLUSHING;\r
389                 }\r
390                 \r
391                 /// <summary>\r
392                 /// Finishes the deflater with the current input block.  It is an error\r
393                 /// to give more input after this method was called.  This method must\r
394                 /// be called to force all bytes to be flushed.\r
395                 /// </summary>\r
396                 public void Finish() \r
397                 {\r
398                         state |= IS_FLUSHING | IS_FINISHING;\r
399                 }\r
400                 \r
401                 /// <summary>\r
402                 /// Returns true if the stream was finished and no more output bytes\r
403                 /// are available.\r
404                 /// </summary>\r
405                 public bool IsFinished {\r
406                         get {\r
407                                 return state == FINISHED_STATE && pending.IsFlushed;\r
408                         }\r
409                 }\r
410                 \r
411                 /// <summary>\r
412                 /// Returns true, if the input buffer is empty.\r
413                 /// You should then call setInput(). \r
414                 /// NOTE: This method can also return true when the stream\r
415                 /// was finished.\r
416                 /// </summary>\r
417                 public bool IsNeedingInput {\r
418                         get {\r
419                                 return engine.NeedsInput();\r
420                         }\r
421                 }\r
422                 \r
423                 /// <summary>\r
424                 /// Sets the data which should be compressed next.  This should be only\r
425                 /// called when needsInput indicates that more input is needed.\r
426                 /// If you call setInput when needsInput() returns false, the\r
427                 /// previous input that is still pending will be thrown away.\r
428                 /// The given byte array should not be changed, before needsInput() returns\r
429                 /// true again.\r
430                 /// This call is equivalent to <code>setInput(input, 0, input.length)</code>.\r
431                 /// </summary>\r
432                 /// <param name="input">\r
433                 /// the buffer containing the input data.\r
434                 /// </param>\r
435                 /// <exception cref="System.InvalidOperationException">\r
436                 /// if the buffer was finished() or ended().\r
437                 /// </exception>\r
438                 public void SetInput(byte[] input)\r
439                 {\r
440                         SetInput(input, 0, input.Length);\r
441                 }\r
442                 \r
443                 /// <summary>\r
444                 /// Sets the data which should be compressed next.  This should be\r
445                 /// only called when needsInput indicates that more input is needed.\r
446                 /// The given byte array should not be changed, before needsInput() returns\r
447                 /// true again.\r
448                 /// </summary>\r
449                 /// <param name="input">\r
450                 /// the buffer containing the input data.\r
451                 /// </param>\r
452                 /// <param name="off">\r
453                 /// the start of the data.\r
454                 /// </param>\r
455                 /// <param name="len">\r
456                 /// the length of the data.\r
457                 /// </param>\r
458                 /// <exception cref="System.InvalidOperationException">\r
459                 /// if the buffer was finished() or ended() or if previous input is still pending.\r
460                 /// </exception>\r
461                 public void SetInput(byte[] input, int off, int len)\r
462                 {\r
463                         if ((state & IS_FINISHING) != 0) {\r
464                                 throw new InvalidOperationException("finish()/end() already called");\r
465                         }\r
466                         engine.SetInput(input, off, len);\r
467                 }\r
468                 \r
469                 /// <summary>\r
470                 /// Sets the compression level.  There is no guarantee of the exact\r
471                 /// position of the change, but if you call this when needsInput is\r
472                 /// true the change of compression level will occur somewhere near\r
473                 /// before the end of the so far given input.\r
474                 /// </summary>\r
475                 /// <param name="lvl">\r
476                 /// the new compression level.\r
477                 /// </param>\r
478                 public void SetLevel(int lvl)\r
479                 {\r
480                         if (lvl == DEFAULT_COMPRESSION) {\r
481                                 lvl = 6;\r
482                         } else if (lvl < NO_COMPRESSION || lvl > BEST_COMPRESSION) {\r
483                                 throw new ArgumentOutOfRangeException("lvl");\r
484                         }\r
485                         \r
486                         \r
487                         if (level != lvl) {\r
488                                 level = lvl;\r
489                                 engine.SetLevel(lvl);\r
490                         }\r
491                 }\r
492                 \r
493                 /// <summary>\r
494                 /// Sets the compression strategy. Strategy is one of\r
495                 /// DEFAULT_STRATEGY, HUFFMAN_ONLY and FILTERED.  For the exact\r
496                 /// position where the strategy is changed, the same as for\r
497                 /// setLevel() applies.\r
498                 /// </summary>\r
499                 /// <param name="stgy">\r
500                 /// the new compression strategy.\r
501                 /// </param>\r
502                 public void SetStrategy(int stgy)\r
503                 {\r
504                         if (stgy != DEFAULT_STRATEGY && stgy != FILTERED && stgy != HUFFMAN_ONLY) {\r
505                             throw new Exception();\r
506                         }\r
507                         engine.Strategy = stgy;\r
508                 }\r
509                 \r
510                 /// <summary>\r
511                 /// Deflates the current input block to the given array.  It returns\r
512                 /// the number of bytes compressed, or 0 if either\r
513                 /// needsInput() or finished() returns true or length is zero.\r
514                 /// </summary>\r
515                 /// <param name="output">\r
516                 /// the buffer where to write the compressed data.\r
517                 /// </param>\r
518                 public int Deflate(byte[] output)\r
519                 {\r
520                         return Deflate(output, 0, output.Length);\r
521                 }\r
522                 \r
523                 /// <summary>\r
524                 /// Deflates the current input block to the given array.  It returns\r
525                 /// the number of bytes compressed, or 0 if either\r
526                 /// needsInput() or finished() returns true or length is zero.\r
527                 /// </summary>\r
528                 /// <param name="output">\r
529                 /// the buffer where to write the compressed data.\r
530                 /// </param>\r
531                 /// <param name="offset">\r
532                 /// the offset into the output array.\r
533                 /// </param>\r
534                 /// <param name="length">\r
535                 /// the maximum number of bytes that may be written.\r
536                 /// </param>\r
537                 /// <exception cref="System.InvalidOperationException">\r
538                 /// if end() was called.\r
539                 /// </exception>\r
540                 /// <exception cref="System.ArgumentOutOfRangeException">\r
541                 /// if offset and/or length don't match the array length.\r
542                 /// </exception>\r
543                 public int Deflate(byte[] output, int offset, int length)\r
544                 {\r
545                         int origLength = length;\r
546                         \r
547                         if (state == CLOSED_STATE) {\r
548                                 throw new InvalidOperationException("Deflater closed");\r
549                         }\r
550                         \r
551                         if (state < BUSY_STATE) {\r
552                                 /* output header */\r
553                                 int header = (DEFLATED +\r
554                                               ((DeflaterConstants.MAX_WBITS - 8) << 4)) << 8;\r
555                                 int level_flags = (level - 1) >> 1;\r
556                                 if (level_flags < 0 || level_flags > 3) {\r
557                                         level_flags = 3;\r
558                                 }\r
559                                 header |= level_flags << 6;\r
560                                 if ((state & IS_SETDICT) != 0) {\r
561                                         /* Dictionary was set */\r
562                                         header |= DeflaterConstants.PRESET_DICT;\r
563                                 }\r
564                                 header += 31 - (header % 31);\r
565                                 \r
566                                 \r
567                                 pending.WriteShortMSB(header);\r
568                                 if ((state & IS_SETDICT) != 0) {\r
569                                         int chksum = engine.Adler;\r
570                                         engine.ResetAdler();\r
571                                         pending.WriteShortMSB(chksum >> 16);\r
572                                         pending.WriteShortMSB(chksum & 0xffff);\r
573                                 }\r
574                                 \r
575                                 state = BUSY_STATE | (state & (IS_FLUSHING | IS_FINISHING));\r
576                         }\r
577                         \r
578                         for (;;) {\r
579                                 int count = pending.Flush(output, offset, length);\r
580                                 offset   += count;\r
581                                 totalOut += count;\r
582                                 length   -= count;\r
583                                 \r
584                                 if (length == 0 || state == FINISHED_STATE) {\r
585                                         break;\r
586                                 }\r
587                                 \r
588                                 if (!engine.Deflate((state & IS_FLUSHING) != 0, (state & IS_FINISHING) != 0)) {\r
589                                         if (state == BUSY_STATE) {\r
590                                                 /* We need more input now */\r
591                                                 return origLength - length;\r
592                                         } else if (state == FLUSHING_STATE) {\r
593                                                 if (level != NO_COMPRESSION) {\r
594                                                         /* We have to supply some lookahead.  8 bit lookahead\r
595                                                          * are needed by the zlib inflater, and we must fill\r
596                                                          * the next byte, so that all bits are flushed.\r
597                                                          */\r
598                                                         int neededbits = 8 + ((-pending.BitCount) & 7);\r
599                                                         while (neededbits > 0) {\r
600                                                                 /* write a static tree block consisting solely of\r
601                                                                  * an EOF:\r
602                                                                  */\r
603                                                                 pending.WriteBits(2, 10);\r
604                                                                 neededbits -= 10;\r
605                                                         }\r
606                                                 }\r
607                                                 state = BUSY_STATE;\r
608                                         } else if (state == FINISHING_STATE) {\r
609                                                 pending.AlignToByte();\r
610                                                 /* We have completed the stream */\r
611                                                 if (!noHeader) {\r
612                                                         int adler = engine.Adler;\r
613                                                         pending.WriteShortMSB(adler >> 16);\r
614                                                         pending.WriteShortMSB(adler & 0xffff);\r
615                                                 }\r
616                                                 state = FINISHED_STATE;\r
617                                         }\r
618                                 }\r
619                         }\r
620                         return origLength - length;\r
621                 }\r
622                 \r
623                 /// <summary>\r
624                 /// Sets the dictionary which should be used in the deflate process.\r
625                 /// This call is equivalent to <code>setDictionary(dict, 0, dict.Length)</code>.\r
626                 /// </summary>\r
627                 /// <param name="dict">\r
628                 /// the dictionary.\r
629                 /// </param>\r
630                 /// <exception cref="System.InvalidOperationException">\r
631                 /// if setInput () or deflate () were already called or another dictionary was already set.\r
632                 /// </exception>\r
633                 public void SetDictionary(byte[] dict)\r
634                 {\r
635                         SetDictionary(dict, 0, dict.Length);\r
636                 }\r
637                 \r
638                 /// <summary>\r
639                 /// Sets the dictionary which should be used in the deflate process.\r
640                 /// The dictionary should be a byte array containing strings that are\r
641                 /// likely to occur in the data which should be compressed.  The\r
642                 /// dictionary is not stored in the compressed output, only a\r
643                 /// checksum.  To decompress the output you need to supply the same\r
644                 /// dictionary again.\r
645                 /// </summary>\r
646                 /// <param name="dict">\r
647                 /// the dictionary.\r
648                 /// </param>\r
649                 /// <param name="offset">\r
650                 /// an offset into the dictionary.\r
651                 /// </param>\r
652                 /// <param name="length">\r
653                 /// the length of the dictionary.\r
654                 /// </param>\r
655                 /// <exception cref="System.InvalidOperationException">\r
656                 /// if setInput () or deflate () were already called or another dictionary was already set.\r
657                 /// </exception>\r
658                 public void SetDictionary(byte[] dict, int offset, int length)\r
659                 {\r
660                         if (state != INIT_STATE) {\r
661                                 throw new InvalidOperationException();\r
662                         }\r
663                         \r
664                         state = SETDICT_STATE;\r
665                         engine.SetDictionary(dict, offset, length);\r
666                 }\r
667         }\r
668 }\r
669 \r
670 namespace NZlib.Compression {\r
671         \r
672         /// <summary>\r
673         /// This class contains constants used for the deflater.\r
674         /// </summary>\r
675         public class DeflaterConstants \r
676         {\r
677                 public const bool DEBUGGING = false;\r
678                 \r
679                 public const int STORED_BLOCK = 0;\r
680                 public const int STATIC_TREES = 1;\r
681                 public const int DYN_TREES    = 2;\r
682                 public const int PRESET_DICT  = 0x20;\r
683                 \r
684                 public const int DEFAULT_MEM_LEVEL = 8;\r
685                 \r
686                 public const int MAX_MATCH = 258;\r
687                 public const int MIN_MATCH = 3;\r
688                 \r
689                 public const int MAX_WBITS = 15;\r
690                 public const int WSIZE = 1 << MAX_WBITS;\r
691                 public const int WMASK = WSIZE - 1;\r
692                 \r
693                 public const int HASH_BITS = DEFAULT_MEM_LEVEL + 7;\r
694                 public const int HASH_SIZE = 1 << HASH_BITS;\r
695                 public const int HASH_MASK = HASH_SIZE - 1;\r
696                 public const int HASH_SHIFT = (HASH_BITS + MIN_MATCH - 1) / MIN_MATCH;\r
697                 \r
698                 public const int MIN_LOOKAHEAD = MAX_MATCH + MIN_MATCH + 1;\r
699                 public const int MAX_DIST = WSIZE - MIN_LOOKAHEAD;\r
700                 \r
701                 public const int PENDING_BUF_SIZE = 1 << (DEFAULT_MEM_LEVEL + 8);\r
702                 public static int MAX_BLOCK_SIZE = Math.Min(65535, PENDING_BUF_SIZE-5);\r
703                 \r
704                 public const int DEFLATE_STORED = 0;\r
705                 public const int DEFLATE_FAST   = 1;\r
706                 public const int DEFLATE_SLOW   = 2;\r
707                 \r
708                 public static int[] GOOD_LENGTH = { 0, 4, 4, 4, 4, 8,  8,  8,  32,  32 };\r
709                 public static int[] MAX_LAZY    = { 0, 4, 5, 6, 4,16, 16, 32, 128, 258 };\r
710                 public static int[] NICE_LENGTH = { 0, 8,16,32,16,32,128,128, 258, 258 };\r
711                 public static int[] MAX_CHAIN   = { 0, 4, 8,32,16,32,128,256,1024,4096 };\r
712                 public static int[] COMPR_FUNC  = { 0, 1, 1, 1, 1, 2,  2,  2,   2,   2 };\r
713         }\r
714 }\r
715 \r
716 namespace NZlib.Compression {\r
717         \r
718         public class DeflaterEngine : DeflaterConstants \r
719         {\r
720                 private  static int TOO_FAR = 4096;\r
721                 \r
722                 private int ins_h;\r
723 //              private byte[] buffer;\r
724                 private short[] head;\r
725                 private short[] prev;\r
726                 \r
727                 private int matchStart, matchLen;\r
728                 private bool prevAvailable;\r
729                 private int blockStart;\r
730                 private int strstart, lookahead;\r
731                 private byte[] window;\r
732                 \r
733                 private int strategy, max_chain, max_lazy, niceLength, goodLength;\r
734                 \r
735                 /// <summary>\r
736                 /// The current compression function.\r
737                 /// </summary>\r
738                 private int comprFunc;\r
739                 \r
740                 /// <summary>\r
741                 /// The input data for compression.\r
742                 /// </summary>\r
743                 private byte[] inputBuf;\r
744                 \r
745                 /// <summary>\r
746                 /// The total bytes of input read.\r
747                 /// </summary>\r
748                 private int totalIn;\r
749                 \r
750                 /// <summary>\r
751                 /// The offset into inputBuf, where input data starts.\r
752                 /// </summary>\r
753                 private int inputOff;\r
754                 \r
755                 /// <summary>\r
756                 /// The end offset of the input data.\r
757                 /// </summary>\r
758                 private int inputEnd;\r
759                 \r
760                 private DeflaterPending pending;\r
761                 private DeflaterHuffman huffman;\r
762                 \r
763                 /// <summary>\r
764                 /// The adler checksum\r
765                 /// </summary>\r
766                 private Adler32 adler;\r
767                 \r
768                 public DeflaterEngine(DeflaterPending pending) \r
769                 {\r
770                         this.pending = pending;\r
771                         huffman = new DeflaterHuffman(pending);\r
772                         adler = new Adler32();\r
773                         \r
774                         window = new byte[2*WSIZE];\r
775                         head   = new short[HASH_SIZE];\r
776                         prev   = new short[WSIZE];\r
777                         \r
778                         /* We start at index 1, to avoid a implementation deficiency, that\r
779                         * we cannot build a repeat pattern at index 0.\r
780                         */\r
781                         blockStart = strstart = 1;\r
782                 }\r
783                 \r
784                 public void Reset()\r
785                 {\r
786                         huffman.Reset();\r
787                         adler.Reset();\r
788                         blockStart = strstart = 1;\r
789                         lookahead = 0;\r
790                         totalIn   = 0;\r
791                         prevAvailable = false;\r
792                         matchLen = MIN_MATCH - 1;\r
793                         \r
794                         for (int i = 0; i < HASH_SIZE; i++) {\r
795                                 head[i] = 0;\r
796                         }\r
797                         \r
798                         for (int i = 0; i < WSIZE; i++) {\r
799                                 prev[i] = 0;\r
800                         }\r
801                 }\r
802                 \r
803                 public void ResetAdler()\r
804                 {\r
805                         adler.Reset();\r
806                 }\r
807                 \r
808                 public int Adler {\r
809                         get {\r
810                                 return (int)adler.Value;\r
811                         }\r
812                 }\r
813                 \r
814                 public int TotalIn {\r
815                         get {\r
816                                 return totalIn;\r
817                         }\r
818                 }\r
819                 \r
820                 public int Strategy {\r
821                         get {\r
822                                 return strategy;\r
823                         }\r
824                         set {\r
825                                 strategy = value;\r
826                         }\r
827                 }\r
828                 \r
829                 public void SetLevel(int lvl)\r
830                 {\r
831                         goodLength = DeflaterConstants.GOOD_LENGTH[lvl];\r
832                         max_lazy   = DeflaterConstants.MAX_LAZY[lvl];\r
833                         niceLength = DeflaterConstants.NICE_LENGTH[lvl];\r
834                         max_chain  = DeflaterConstants.MAX_CHAIN[lvl];\r
835                         \r
836                         if (DeflaterConstants.COMPR_FUNC[lvl] != comprFunc) {\r
837 //                              if (DeflaterConstants.DEBUGGING) {\r
838 //                                      Console.WriteLine("Change from "+comprFunc +" to "\r
839 //                                                        + DeflaterConstants.COMPR_FUNC[lvl]);\r
840 //                              }\r
841                                 switch (comprFunc) {\r
842                                         case DEFLATE_STORED:\r
843                                                 if (strstart > blockStart) {\r
844                                                         huffman.FlushStoredBlock(window, blockStart,\r
845                                                                                  strstart - blockStart, false);\r
846                                                         blockStart = strstart;\r
847                                                 }\r
848                                                 UpdateHash();\r
849                                                 break;\r
850                                         case DEFLATE_FAST:\r
851                                                 if (strstart > blockStart) {\r
852                                                         huffman.FlushBlock(window, blockStart, strstart - blockStart,\r
853                                                                            false);\r
854                                                         blockStart = strstart;\r
855                                                 }\r
856                                                 break;\r
857                                         case DEFLATE_SLOW:\r
858                                                 if (prevAvailable) {\r
859                                                         huffman.TallyLit(window[strstart-1] & 0xff);\r
860                                                 }\r
861                                                 if (strstart > blockStart) {\r
862                                                         huffman.FlushBlock(window, blockStart, strstart - blockStart,\r
863                                                                            false);\r
864                                                         blockStart = strstart;\r
865                                                 }\r
866                                                 prevAvailable = false;\r
867                                                 matchLen = MIN_MATCH - 1;\r
868                                                 break;\r
869                                 }\r
870                                 comprFunc = COMPR_FUNC[lvl];\r
871                         }\r
872                 }\r
873                 \r
874                 private void UpdateHash() \r
875                 {\r
876 //                      if (DEBUGGING) {\r
877 //                              Console.WriteLine("updateHash: "+strstart);\r
878 //                      }\r
879                         ins_h = (window[strstart] << HASH_SHIFT) ^ window[strstart + 1];\r
880                 }\r
881                 \r
882                 private int InsertString() \r
883                 {\r
884                         short match;\r
885                         int hash = ((ins_h << HASH_SHIFT) ^ window[strstart + (MIN_MATCH -1)]) & HASH_MASK;\r
886                         \r
887 //                      if (DEBUGGING) {\r
888 //                              if (hash != (((window[strstart] << (2*HASH_SHIFT)) ^ \r
889 //                                            (window[strstart + 1] << HASH_SHIFT) ^ \r
890 //                                            (window[strstart + 2])) & HASH_MASK)) {\r
891 //                                              throw new Exception("hash inconsistent: "+hash+"/"\r
892 //                                                                  +window[strstart]+","\r
893 //                                                                  +window[strstart+1]+","\r
894 //                                                                  +window[strstart+2]+","+HASH_SHIFT);\r
895 //                                      }\r
896 //                      }\r
897                         \r
898                         prev[strstart & WMASK] = match = head[hash];\r
899                         head[hash] = (short)strstart;\r
900                         ins_h = hash;\r
901                         return match & 0xffff;\r
902                 }\r
903                 \r
904                 public void FillWindow()\r
905                 {\r
906                         while (lookahead < DeflaterConstants.MIN_LOOKAHEAD && inputOff < inputEnd) {\r
907                                 int more = 2*WSIZE - lookahead - strstart;\r
908                                 \r
909                                 /* If the window is almost full and there is insufficient lookahead,\r
910                                 * move the upper half to the lower one to make room in the upper half.\r
911                                 */\r
912                                 if (strstart >= WSIZE + MAX_DIST) {\r
913                                         System.Array.Copy(window, WSIZE, window, 0, WSIZE);\r
914                                         matchStart -= WSIZE;\r
915                                         strstart -= WSIZE;\r
916                                         blockStart -= WSIZE;\r
917                                         \r
918                                         /* Slide the hash table (could be avoided with 32 bit values\r
919                                          * at the expense of memory usage).\r
920                                          */\r
921                                          for (int i = 0; i < HASH_SIZE; i++) {\r
922                                                 int m = head[i];\r
923                                                 head[i] = m >= WSIZE ? (short) (m - WSIZE) : (short)0;\r
924                                          }\r
925                                          more += WSIZE;\r
926                                 }\r
927                                 \r
928                                 if (more > inputEnd - inputOff) {\r
929                                         more = inputEnd - inputOff;\r
930                                 }\r
931                                 \r
932                                 System.Array.Copy(inputBuf, inputOff, window, strstart + lookahead, more);\r
933                                 adler.Update(inputBuf, inputOff, more);\r
934                                 inputOff  += more;\r
935                                 totalIn   += more;\r
936                                 lookahead += more;\r
937                                 \r
938                                 if (lookahead >= MIN_MATCH) {\r
939                                         UpdateHash();\r
940                                 }\r
941                         }\r
942                 }\r
943                 \r
944                 private bool FindLongestMatch(int curMatch) \r
945                 {\r
946                         int chainLength = this.max_chain;\r
947                         int niceLength  = this.niceLength;\r
948                         short[] prev    = this.prev;\r
949                         int scan        = this.strstart;\r
950                         int match;\r
951                         int best_end = this.strstart + matchLen;\r
952                         int best_len = Math.Max(matchLen, MIN_MATCH - 1);\r
953                         \r
954                         int limit = Math.Max(strstart - MAX_DIST, 0);\r
955                         \r
956                         int strend = strstart + MAX_MATCH - 1;\r
957                         byte scan_end1 = window[best_end - 1];\r
958                         byte scan_end  = window[best_end];\r
959                         \r
960                         /* Do not waste too much time if we already have a good match: */\r
961                         if (best_len >= this.goodLength) {\r
962                                 chainLength >>= 2;\r
963                         }\r
964                         \r
965                         /* Do not look for matches beyond the end of the input. This is necessary\r
966                         * to make deflate deterministic.\r
967                         */\r
968                         if (niceLength > lookahead) {\r
969                                 niceLength = lookahead;\r
970                         }\r
971                         \r
972                         if (DeflaterConstants.DEBUGGING && strstart > 2*WSIZE - MIN_LOOKAHEAD) {\r
973                             throw new InvalidOperationException("need lookahead");\r
974                         }\r
975                         \r
976                         do {\r
977                                 if (DeflaterConstants.DEBUGGING && curMatch >= strstart) {\r
978                                         throw new InvalidOperationException("future match");\r
979                                 }\r
980                                 if (window[curMatch + best_len] != scan_end      || \r
981                                     window[curMatch + best_len - 1] != scan_end1 || \r
982                                     window[curMatch] != window[scan]             || \r
983                                     window[curMatch+1] != window[scan + 1]) {\r
984                                     continue;\r
985                                 }\r
986                                 \r
987                                 match = curMatch + 2;\r
988                                 scan += 2;\r
989                                 \r
990                                 /* We check for insufficient lookahead only every 8th comparison;\r
991                                 * the 256th check will be made at strstart+258.\r
992                                 */\r
993                                 while (window[++scan] == window[++match] && \r
994                                        window[++scan] == window[++match] && \r
995                                        window[++scan] == window[++match] && \r
996                                        window[++scan] == window[++match] && \r
997                                        window[++scan] == window[++match] && \r
998                                        window[++scan] == window[++match] && \r
999                                        window[++scan] == window[++match] && \r
1000                                        window[++scan] == window[++match] && scan < strend) ;\r
1001                                 \r
1002                                 if (scan > best_end) {\r
1003                                         //      if (DeflaterConstants.DEBUGGING && ins_h == 0)\r
1004                                         //        System.err.println("Found match: "+curMatch+"-"+(scan-strstart));\r
1005                                         matchStart = curMatch;\r
1006                                         best_end = scan;\r
1007                                         best_len = scan - strstart;\r
1008                                         if (best_len >= niceLength) {\r
1009                                                 break;\r
1010                                         }\r
1011                                         \r
1012                                         scan_end1  = window[best_end-1];\r
1013                                         scan_end   = window[best_end];\r
1014                                 }\r
1015                                 scan = strstart;\r
1016                         } while ((curMatch = (prev[curMatch & WMASK] & 0xffff)) > limit && --chainLength != 0);\r
1017                         \r
1018                         matchLen = Math.Min(best_len, lookahead);\r
1019                         return matchLen >= MIN_MATCH;\r
1020                 }\r
1021                 \r
1022                 public void SetDictionary(byte[] buffer, int offset, int length) \r
1023                 {\r
1024                         if (DeflaterConstants.DEBUGGING && strstart != 1) {\r
1025                                 throw new InvalidOperationException("strstart not 1");\r
1026                         }\r
1027                         adler.Update(buffer, offset, length);\r
1028                         if (length < MIN_MATCH) {\r
1029                                 return;\r
1030                         }\r
1031                         if (length > MAX_DIST) {\r
1032                                 offset += length - MAX_DIST;\r
1033                                 length = MAX_DIST;\r
1034                         }\r
1035                         \r
1036                         System.Array.Copy(buffer, offset, window, strstart, length);\r
1037                         \r
1038                         UpdateHash();\r
1039                         --length;\r
1040                         while (--length > 0) {\r
1041                                 InsertString();\r
1042                                 strstart++;\r
1043                         }\r
1044                         strstart += 2;\r
1045                         blockStart = strstart;\r
1046                 }\r
1047                 \r
1048                 private bool DeflateStored(bool flush, bool finish)\r
1049                 {\r
1050                         if (!flush && lookahead == 0) {\r
1051                                 return false;\r
1052                         }\r
1053                         \r
1054                         strstart += lookahead;\r
1055                         lookahead = 0;\r
1056                         \r
1057                         int storedLen = strstart - blockStart;\r
1058                         \r
1059                         if ((storedLen >= DeflaterConstants.MAX_BLOCK_SIZE) || /* Block is full */\r
1060                                 (blockStart < WSIZE && storedLen >= MAX_DIST) ||   /* Block may move out of window */\r
1061                                 flush) {\r
1062                                 bool lastBlock = finish;\r
1063                                 if (storedLen > DeflaterConstants.MAX_BLOCK_SIZE) {\r
1064                                         storedLen = DeflaterConstants.MAX_BLOCK_SIZE;\r
1065                                         lastBlock = false;\r
1066                                 }\r
1067                                 \r
1068 //                              if (DeflaterConstants.DEBUGGING) {\r
1069 //                                      Console.WriteLine("storedBlock["+storedLen+","+lastBlock+"]");\r
1070 //                              }\r
1071                                         \r
1072                                 huffman.FlushStoredBlock(window, blockStart, storedLen, lastBlock);\r
1073                                 blockStart += storedLen;\r
1074                                 return !lastBlock;\r
1075                         }\r
1076                         return true;\r
1077                 }\r
1078                 \r
1079                 private bool DeflateFast(bool flush, bool finish)\r
1080                 {\r
1081                         if (lookahead < MIN_LOOKAHEAD && !flush) {\r
1082                                 return false;\r
1083                         }\r
1084                         \r
1085                         while (lookahead >= MIN_LOOKAHEAD || flush) {\r
1086                                 if (lookahead == 0) {\r
1087                                         /* We are flushing everything */\r
1088                                         huffman.FlushBlock(window, blockStart, strstart - blockStart, finish);\r
1089                                         blockStart = strstart;\r
1090                                         return false;\r
1091                                 }\r
1092                                 \r
1093                                 int hashHead;\r
1094                                 if (lookahead >= MIN_MATCH && \r
1095                                     (hashHead = InsertString()) != 0 && \r
1096                                     strategy != Deflater.HUFFMAN_ONLY && \r
1097                                     strstart - hashHead <= MAX_DIST && \r
1098                                     FindLongestMatch(hashHead)) {\r
1099                                         /* longestMatch sets matchStart and matchLen */\r
1100 //                                      if (DeflaterConstants.DEBUGGING) {\r
1101 //                                              for (int i = 0 ; i < matchLen; i++) {\r
1102 //                                                      if (window[strstart+i] != window[matchStart + i]) {\r
1103 //                                                              throw new Exception();\r
1104 //                                                      }\r
1105 //                                              }\r
1106 //                                      }\r
1107                                         \r
1108                                         huffman.TallyDist(strstart - matchStart, matchLen);\r
1109                                         \r
1110                                         lookahead -= matchLen;\r
1111                                         if (matchLen <= max_lazy && lookahead >= MIN_MATCH) {\r
1112                                                 while (--matchLen > 0) {\r
1113                                                         ++strstart;\r
1114                                                         InsertString();\r
1115                                                 }\r
1116                                                 ++strstart;\r
1117                                         } else {\r
1118                                                 strstart += matchLen;\r
1119                                                 if (lookahead >= MIN_MATCH - 1) {\r
1120                                                         UpdateHash();\r
1121                                                 }\r
1122                                         }\r
1123                                         matchLen = MIN_MATCH - 1;\r
1124                                         continue;\r
1125                                 } else {\r
1126                                         /* No match found */\r
1127                                         huffman.TallyLit(window[strstart] & 0xff);\r
1128                                         ++strstart;\r
1129                                         --lookahead;\r
1130                                 }\r
1131                                 \r
1132                                 if (huffman.IsFull()) {\r
1133                                         bool lastBlock = finish && lookahead == 0;\r
1134                                         huffman.FlushBlock(window, blockStart, strstart - blockStart,\r
1135                                                            lastBlock);\r
1136                                         blockStart = strstart;\r
1137                                         return !lastBlock;\r
1138                                 }\r
1139                         }\r
1140                         return true;\r
1141                 }\r
1142                 \r
1143                 private bool DeflateSlow(bool flush, bool finish)\r
1144                 {\r
1145                         if (lookahead < MIN_LOOKAHEAD && !flush) {\r
1146                                 return false;\r
1147                         }\r
1148                         \r
1149                         while (lookahead >= MIN_LOOKAHEAD || flush) {\r
1150                                 if (lookahead == 0) {\r
1151                                         if (prevAvailable) {\r
1152                                                 huffman.TallyLit(window[strstart-1] & 0xff);\r
1153                                         }\r
1154                                         prevAvailable = false;\r
1155                                         \r
1156                                         /* We are flushing everything */\r
1157                                         if (DeflaterConstants.DEBUGGING && !flush) {\r
1158                                                 throw new Exception("Not flushing, but no lookahead");\r
1159                                         }\r
1160                                         huffman.FlushBlock(window, blockStart, strstart - blockStart,\r
1161                                                            finish);\r
1162                                         blockStart = strstart;\r
1163                                         return false;\r
1164                                 }\r
1165                                 \r
1166                                 int prevMatch = matchStart;\r
1167                                 int prevLen = matchLen;\r
1168                                 if (lookahead >= MIN_MATCH) {\r
1169                                         int hashHead = InsertString();\r
1170                                         if (strategy != Deflater.HUFFMAN_ONLY && hashHead != 0 && strstart - hashHead <= MAX_DIST && FindLongestMatch(hashHead))\r
1171                                                 {\r
1172                                                         /* longestMatch sets matchStart and matchLen */\r
1173                                                         \r
1174                                                         /* Discard match if too small and too far away */\r
1175                                                         if (matchLen <= 5 && (strategy == Deflater.FILTERED || (matchLen == MIN_MATCH && strstart - matchStart > TOO_FAR))) {\r
1176                                                                 matchLen = MIN_MATCH - 1;\r
1177                                                         }\r
1178                                                 }\r
1179                                 }\r
1180                                 \r
1181                                 /* previous match was better */\r
1182                                 if (prevLen >= MIN_MATCH && matchLen <= prevLen) {\r
1183 //                                      if (DeflaterConstants.DEBUGGING) {\r
1184 //                                              for (int i = 0 ; i < matchLen; i++) {\r
1185 //                                                      if (window[strstart-1+i] != window[prevMatch + i])\r
1186 //                                                              throw new Exception();\r
1187 //                                              }\r
1188 //                                      }\r
1189                                         huffman.TallyDist(strstart - 1 - prevMatch, prevLen);\r
1190                                         prevLen -= 2;\r
1191                                         do {\r
1192                                                 strstart++;\r
1193                                                 lookahead--;\r
1194                                                 if (lookahead >= MIN_MATCH) {\r
1195                                                         InsertString();\r
1196                                                 }\r
1197                                         } while (--prevLen > 0);\r
1198                                         strstart ++;\r
1199                                         lookahead--;\r
1200                                         prevAvailable = false;\r
1201                                         matchLen = MIN_MATCH - 1;\r
1202                                 } else {\r
1203                                         if (prevAvailable) {\r
1204                                                 huffman.TallyLit(window[strstart-1] & 0xff);\r
1205                                         }\r
1206                                         prevAvailable = true;\r
1207                                         strstart++;\r
1208                                         lookahead--;\r
1209                                 }\r
1210                                 \r
1211                                 if (huffman.IsFull()) {\r
1212                                         int len = strstart - blockStart;\r
1213                                         if (prevAvailable) {\r
1214                                                 len--;\r
1215                                         }\r
1216                                         bool lastBlock = (finish && lookahead == 0 && !prevAvailable);\r
1217                                         huffman.FlushBlock(window, blockStart, len, lastBlock);\r
1218                                         blockStart += len;\r
1219                                         return !lastBlock;\r
1220                                 }\r
1221                         }\r
1222                         return true;\r
1223                 }\r
1224                 \r
1225                 public bool Deflate(bool flush, bool finish)\r
1226                 {\r
1227                         bool progress;\r
1228                         do {\r
1229                                 FillWindow();\r
1230                                 bool canFlush = flush && inputOff == inputEnd;\r
1231 //                              if (DeflaterConstants.DEBUGGING) {\r
1232 //                                      Console.WriteLine("window: ["+blockStart+","+strstart+","\r
1233 //                                                        +lookahead+"], "+comprFunc+","+canFlush);\r
1234 //                              }\r
1235                                 switch (comprFunc) {\r
1236                                         case DEFLATE_STORED:\r
1237                                                 progress = DeflateStored(canFlush, finish);\r
1238                                         break;\r
1239                                         case DEFLATE_FAST:\r
1240                                                 progress = DeflateFast(canFlush, finish);\r
1241                                         break;\r
1242                                         case DEFLATE_SLOW:\r
1243                                                 progress = DeflateSlow(canFlush, finish);\r
1244                                         break;\r
1245                                         default:\r
1246                                                 throw new InvalidOperationException("unknown comprFunc");\r
1247                                 }\r
1248                         } while (pending.IsFlushed && progress); /* repeat while we have no pending output and progress was made */\r
1249                         return progress;\r
1250                 }\r
1251                 \r
1252                 public void SetInput(byte[] buf, int off, int len)\r
1253                 {\r
1254                         if (inputOff < inputEnd) {\r
1255                                 throw new InvalidOperationException("Old input was not completely processed");\r
1256                         }\r
1257                         \r
1258                         int end = off + len;\r
1259                         \r
1260                         /* We want to throw an ArrayIndexOutOfBoundsException early.  The\r
1261                         * check is very tricky: it also handles integer wrap around.\r
1262                         */\r
1263                         if (0 > off || off > end || end > buf.Length) {\r
1264                                 throw new ArgumentOutOfRangeException();\r
1265                         }\r
1266                         \r
1267                         inputBuf = buf;\r
1268                         inputOff = off;\r
1269                         inputEnd = end;\r
1270                 }\r
1271                 \r
1272                 public bool NeedsInput()\r
1273                 {\r
1274                         return inputEnd == inputOff;\r
1275                 }\r
1276         }\r
1277 }\r
1278 \r
1279 namespace NZlib.Compression {\r
1280         \r
1281         /// <summary>\r
1282         /// This is the DeflaterHuffman class.\r
1283         /// \r
1284         /// This class is <i>not</i> thread safe.  This is inherent in the API, due\r
1285         /// to the split of deflate and setInput.\r
1286         /// \r
1287         /// author of the original java version : Jochen Hoenicke\r
1288         /// </summary>\r
1289         public class DeflaterHuffman\r
1290         {\r
1291                 private static  int BUFSIZE = 1 << (DeflaterConstants.DEFAULT_MEM_LEVEL + 6);\r
1292                 private static  int LITERAL_NUM = 286;\r
1293                 private static  int DIST_NUM = 30;\r
1294                 private static  int BITLEN_NUM = 19;\r
1295                 private static  int REP_3_6    = 16;\r
1296                 private static  int REP_3_10   = 17;\r
1297                 private static  int REP_11_138 = 18;\r
1298                 private static  int EOF_SYMBOL = 256;\r
1299                 private static  int[] BL_ORDER = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };\r
1300                 \r
1301                 private static byte[] bit4Reverse = {\r
1302                         0,\r
1303                         8,\r
1304                         4,\r
1305                         12,\r
1306                         2,\r
1307                         10,\r
1308                         6,\r
1309                         14,\r
1310                         1,\r
1311                         9,\r
1312                         5,\r
1313                         13,\r
1314                         3,\r
1315                         11,\r
1316                         7,\r
1317                         15\r
1318                 };\r
1319                 \r
1320                 \r
1321                 public class Tree \r
1322                 {\r
1323                         public short[] freqs;\r
1324                         public short[] codes;\r
1325                         public byte[]  length;\r
1326                         public int[]   bl_counts;\r
1327                         public int     minNumCodes, numCodes;\r
1328                         public int     maxLength;\r
1329                         DeflaterHuffman dh;\r
1330                         \r
1331                         public Tree(DeflaterHuffman dh, int elems, int minCodes, int maxLength) \r
1332                         {\r
1333                                 this.dh =  dh;\r
1334                                 this.minNumCodes = minCodes;\r
1335                                 this.maxLength  = maxLength;\r
1336                                 freqs  = new short[elems];\r
1337                                 bl_counts = new int[maxLength];\r
1338                         }\r
1339                         \r
1340                         public void Reset() \r
1341                         {\r
1342                                 for (int i = 0; i < freqs.Length; i++) {\r
1343                                         freqs[i] = 0;\r
1344                                 }\r
1345                                 codes = null;\r
1346                                 length = null;\r
1347                         }\r
1348                         \r
1349                         public void WriteSymbol(int code)\r
1350                         {\r
1351 //                              if (DeflaterConstants.DEBUGGING) {\r
1352 //                                      freqs[code]--;\r
1353 //                                      //        Console.Write("writeSymbol("+freqs.length+","+code+"): ");\r
1354 //                              }\r
1355                                 dh.pending.WriteBits(codes[code] & 0xffff, length[code]);\r
1356                         }\r
1357                         \r
1358                         public void CheckEmpty()\r
1359                         {\r
1360                                 bool empty = true;\r
1361                                 for (int i = 0; i < freqs.Length; i++) {\r
1362                                         if (freqs[i] != 0) {\r
1363                                                 Console.WriteLine("freqs["+i+"] == "+freqs[i]);\r
1364                                                 empty = false;\r
1365                                         }\r
1366                                 }\r
1367                                 if (!empty) {\r
1368                                         throw new Exception();\r
1369                                 }\r
1370                                 Console.WriteLine("checkEmpty suceeded!");\r
1371                         }\r
1372                         \r
1373                         public void SetStaticCodes(short[] stCodes, byte[] stLength)\r
1374                         {\r
1375                                 codes = stCodes;\r
1376                                 length = stLength;\r
1377                         }\r
1378                         \r
1379                         public void BuildCodes() \r
1380                         {\r
1381                                 int numSymbols = freqs.Length;\r
1382                                 int[] nextCode = new int[maxLength];\r
1383                                 int code = 0;\r
1384                                 codes = new short[freqs.Length];\r
1385                                 \r
1386 //                              if (DeflaterConstants.DEBUGGING) {\r
1387 //                                      Console.WriteLine("buildCodes: "+freqs.Length);\r
1388 //                              }\r
1389                                 \r
1390                                 for (int bits = 0; bits < maxLength; bits++) {\r
1391                                         nextCode[bits] = code;\r
1392                                         code += bl_counts[bits] << (15 - bits);\r
1393 //                                      if (DeflaterConstants.DEBUGGING) {\r
1394 //                                              Console.WriteLine("bits: "+(bits+1)+" count: "+bl_counts[bits]\r
1395 //                                                                +" nextCode: "+code); // HACK : Integer.toHexString(\r
1396 //                                      }\r
1397                                 }\r
1398                                 if (DeflaterConstants.DEBUGGING && code != 65536) {\r
1399                                         throw new Exception("Inconsistent bl_counts!");\r
1400                                 }\r
1401                                 \r
1402                                 for (int i=0; i < numCodes; i++) {\r
1403                                         int bits = length[i];\r
1404                                         if (bits > 0) {\r
1405 //                                              if (DeflaterConstants.DEBUGGING) {\r
1406 //                                                              Console.WriteLine("codes["+i+"] = rev(" + nextCode[bits-1]+")," // HACK : Integer.toHexString(\r
1407 //                                                                                +bits);\r
1408 //                                              }\r
1409                                                 codes[i] = BitReverse(nextCode[bits-1]);\r
1410                                                 nextCode[bits-1] += 1 << (16 - bits);\r
1411                                         }\r
1412                                 }\r
1413                         }\r
1414                         \r
1415                         private void BuildLength(int[] childs)\r
1416                         {\r
1417                                 this.length = new byte [freqs.Length];\r
1418                                 int numNodes = childs.Length / 2;\r
1419                                 int numLeafs = (numNodes + 1) / 2;\r
1420                                 int overflow = 0;\r
1421                                 \r
1422                                 for (int i = 0; i < maxLength; i++) {\r
1423                                         bl_counts[i] = 0;\r
1424                                 }\r
1425                                 \r
1426                                 /* First calculate optimal bit lengths */\r
1427                                 int[] lengths = new int[numNodes];\r
1428                                 lengths[numNodes-1] = 0;\r
1429                                 \r
1430                                 for (int i = numNodes - 1; i >= 0; i--) {\r
1431                                         if (childs[2*i+1] != -1) {\r
1432                                                 int bitLength = lengths[i] + 1;\r
1433                                                 if (bitLength > maxLength) {\r
1434                                                         bitLength = maxLength;\r
1435                                                         overflow++;\r
1436                                                 }\r
1437                                                 lengths[childs[2*i]] = lengths[childs[2*i+1]] = bitLength;\r
1438                                         } else {\r
1439                                                 /* A leaf node */\r
1440                                                 int bitLength = lengths[i];\r
1441                                                 bl_counts[bitLength - 1]++;\r
1442                                                 this.length[childs[2*i]] = (byte) lengths[i];\r
1443                                         }\r
1444                                 }\r
1445                                 \r
1446 //                              if (DeflaterConstants.DEBUGGING) {\r
1447 //                                      Console.WriteLine("Tree "+freqs.Length+" lengths:");\r
1448 //                                      for (int i=0; i < numLeafs; i++) {\r
1449 //                                              Console.WriteLine("Node "+childs[2*i]+" freq: "+freqs[childs[2*i]]\r
1450 //                                                                + " len: "+length[childs[2*i]]);\r
1451 //                                      }\r
1452 //                              }\r
1453                                 \r
1454                                 if (overflow == 0) {\r
1455                                         return;\r
1456                                 }\r
1457                                 \r
1458                                 int incrBitLen = maxLength - 1;\r
1459                                 do {\r
1460                                         /* Find the first bit length which could increase: */\r
1461                                         while (bl_counts[--incrBitLen] == 0)\r
1462                                                 ;\r
1463                                         \r
1464                                         /* Move this node one down and remove a corresponding\r
1465                                         * amount of overflow nodes.\r
1466                                         */\r
1467                                         do {\r
1468                                                 bl_counts[incrBitLen]--;\r
1469                                                 bl_counts[++incrBitLen]++;\r
1470                                                 overflow -= 1 << (maxLength - 1 - incrBitLen);\r
1471                                         } while (overflow > 0 && incrBitLen < maxLength - 1);\r
1472                                 } while (overflow > 0);\r
1473                                 \r
1474                                 /* We may have overshot above.  Move some nodes from maxLength to\r
1475                                 * maxLength-1 in that case.\r
1476                                 */\r
1477                                 bl_counts[maxLength-1] += overflow;\r
1478                                 bl_counts[maxLength-2] -= overflow;\r
1479                                 \r
1480                                 /* Now recompute all bit lengths, scanning in increasing\r
1481                                 * frequency.  It is simpler to reconstruct all lengths instead of\r
1482                                 * fixing only the wrong ones. This idea is taken from 'ar'\r
1483                                 * written by Haruhiko Okumura.\r
1484                                 *\r
1485                                 * The nodes were inserted with decreasing frequency into the childs\r
1486                                 * array.\r
1487                                 */\r
1488                                 int nodePtr = 2 * numLeafs;\r
1489                                 for (int bits = maxLength; bits != 0; bits--) {\r
1490                                         int n = bl_counts[bits-1];\r
1491                                         while (n > 0) {\r
1492                                                 int childPtr = 2*childs[nodePtr++];\r
1493                                                 if (childs[childPtr + 1] == -1) {\r
1494                                                         /* We found another leaf */\r
1495                                                         length[childs[childPtr]] = (byte) bits;\r
1496                                                         n--;\r
1497                                                 }\r
1498                                         }\r
1499                                 }\r
1500 //                              if (DeflaterConstants.DEBUGGING) {\r
1501 //                                      Console.WriteLine("*** After overflow elimination. ***");\r
1502 //                                      for (int i=0; i < numLeafs; i++) {\r
1503 //                                              Console.WriteLine("Node "+childs[2*i]+" freq: "+freqs[childs[2*i]]\r
1504 //                                                                + " len: "+length[childs[2*i]]);\r
1505 //                                      }\r
1506 //                              }\r
1507                         }\r
1508                         \r
1509                         public void BuildTree()\r
1510                         {\r
1511                                 int numSymbols = freqs.Length;\r
1512                                 \r
1513                                 /* heap is a priority queue, sorted by frequency, least frequent\r
1514                                 * nodes first.  The heap is a binary tree, with the property, that\r
1515                                 * the parent node is smaller than both child nodes.  This assures\r
1516                                 * that the smallest node is the first parent.\r
1517                                 *\r
1518                                 * The binary tree is encoded in an array:  0 is root node and\r
1519                                 * the nodes 2*n+1, 2*n+2 are the child nodes of node n.\r
1520                                 */\r
1521                                 int[] heap = new int[numSymbols];\r
1522                                 int heapLen = 0;\r
1523                                 int maxCode = 0;\r
1524                                 for (int n = 0; n < numSymbols; n++) {\r
1525                                         int freq = freqs[n];\r
1526                                         if (freq != 0) {\r
1527                                                 /* Insert n into heap */\r
1528                                                 int pos = heapLen++;\r
1529                                                 int ppos;\r
1530                                                 while (pos > 0 && freqs[heap[ppos = (pos - 1) / 2]] > freq) {\r
1531                                                         heap[pos] = heap[ppos];\r
1532                                                         pos = ppos;\r
1533                                                 }\r
1534                                                 heap[pos] = n;\r
1535                                                 \r
1536                                                 maxCode = n;\r
1537                                         }\r
1538                                 }\r
1539                                 \r
1540                                 /* We could encode a single literal with 0 bits but then we\r
1541                                 * don't see the literals.  Therefore we force at least two\r
1542                                 * literals to avoid this case.  We don't care about order in\r
1543                                 * this case, both literals get a 1 bit code.\r
1544                                 */\r
1545                                 while (heapLen < 2) {\r
1546                                         int node = maxCode < 2 ? ++maxCode : 0;\r
1547                                         heap[heapLen++] = node;\r
1548                                 }\r
1549                                 \r
1550                                 numCodes = Math.Max(maxCode + 1, minNumCodes);\r
1551                                 \r
1552                                 int numLeafs = heapLen;\r
1553                                 int[] childs = new int[4*heapLen - 2];\r
1554                                 int[] values = new int[2*heapLen - 1];\r
1555                                 int numNodes = numLeafs;\r
1556                                 for (int i = 0; i < heapLen; i++) {\r
1557                                         int node = heap[i];\r
1558                                         childs[2*i]   = node;\r
1559                                         childs[2*i+1] = -1;\r
1560                                         values[i] = freqs[node] << 8;\r
1561                                         heap[i] = i;\r
1562                                 }\r
1563                                 \r
1564                                 /* Construct the Huffman tree by repeatedly combining the least two\r
1565                                 * frequent nodes.\r
1566                                 */\r
1567                                 do {\r
1568                                         int first = heap[0];\r
1569                                         int last  = heap[--heapLen];\r
1570                                         \r
1571                                         /* Propagate the hole to the leafs of the heap */\r
1572                                         int ppos = 0;\r
1573                                         int path = 1;\r
1574                                         while (path < heapLen) {\r
1575                                                 if (path + 1 < heapLen && values[heap[path]] > values[heap[path+1]]) {\r
1576                                                         path++;\r
1577                                                 }\r
1578                                                 \r
1579                                                 heap[ppos] = heap[path];\r
1580                                                 ppos = path;\r
1581                                                 path = path * 2 + 1;\r
1582                                         }\r
1583                                         \r
1584                                         /* Now propagate the last element down along path.  Normally\r
1585                                         * it shouldn't go too deep.\r
1586                                         */\r
1587                                         int lastVal = values[last];\r
1588                                         while ((path = ppos) > 0 && values[heap[ppos = (path - 1)/2]] > lastVal) {\r
1589                                                 heap[path] = heap[ppos];\r
1590                                         }\r
1591                                         heap[path] = last;\r
1592                                         \r
1593                                         \r
1594                                         int second = heap[0];\r
1595                                         \r
1596                                         /* Create a new node father of first and second */\r
1597                                         last = numNodes++;\r
1598                                         childs[2*last] = first;\r
1599                                         childs[2*last+1] = second;\r
1600                                         int mindepth = Math.Min(values[first] & 0xff, values[second] & 0xff);\r
1601                                         values[last] = lastVal = values[first] + values[second] - mindepth + 1;\r
1602                                         \r
1603                                         /* Again, propagate the hole to the leafs */\r
1604                                         ppos = 0;\r
1605                                         path = 1;\r
1606                                         while (path < heapLen) {\r
1607                                                 if (path + 1 < heapLen && values[heap[path]] > values[heap[path+1]]) {\r
1608                                                         path++;\r
1609                                                 }\r
1610                                                 \r
1611                                                 heap[ppos] = heap[path];\r
1612                                                 ppos = path;\r
1613                                                 path = ppos * 2 + 1;\r
1614                                         }\r
1615                                         \r
1616                                         /* Now propagate the new element down along path */\r
1617                                         while ((path = ppos) > 0 && values[heap[ppos = (path - 1)/2]] > lastVal) {\r
1618                                                 heap[path] = heap[ppos];\r
1619                                         }\r
1620                                         heap[path] = last;\r
1621                                 } while (heapLen > 1);\r
1622                                 \r
1623                                 if (heap[0] != childs.Length / 2 - 1) {\r
1624                                         throw new Exception("Weird!");\r
1625                                 }\r
1626                                 BuildLength(childs);\r
1627                         }\r
1628                         \r
1629                         public int GetEncodedLength()\r
1630                         {\r
1631                                 int len = 0;\r
1632                                 for (int i = 0; i < freqs.Length; i++) {\r
1633                                         len += freqs[i] * length[i];\r
1634                                 }\r
1635                                 return len;\r
1636                         }\r
1637                         \r
1638                         public void CalcBLFreq(Tree blTree) \r
1639                         {\r
1640                                 int max_count;               /* max repeat count */\r
1641                                 int min_count;               /* min repeat count */\r
1642                                 int count;                   /* repeat count of the current code */\r
1643                                 int curlen = -1;             /* length of current code */\r
1644                                 \r
1645                                 int i = 0;\r
1646                                 while (i < numCodes) {\r
1647                                         count = 1;\r
1648                                         int nextlen = length[i];\r
1649                                         if (nextlen == 0) {\r
1650                                                 max_count = 138;\r
1651                                                 min_count = 3;\r
1652                                         } else {\r
1653                                                 max_count = 6;\r
1654                                                 min_count = 3;\r
1655                                                 if (curlen != nextlen) {\r
1656                                                         blTree.freqs[nextlen]++;\r
1657                                                         count = 0;\r
1658                                                 }\r
1659                                         }\r
1660                                         curlen = nextlen;\r
1661                                         i++;\r
1662                                         \r
1663                                         while (i < numCodes && curlen == length[i]) {\r
1664                                                 i++;\r
1665                                                 if (++count >= max_count) {\r
1666                                                         break;\r
1667                                                 }\r
1668                                         }\r
1669                                         \r
1670                                         if (count < min_count) {\r
1671                                                 blTree.freqs[curlen] += (short)count;\r
1672                                         } else if (curlen != 0) {\r
1673                                                 blTree.freqs[REP_3_6]++;\r
1674                                         } else if (count <= 10) {\r
1675                                                 blTree.freqs[REP_3_10]++;\r
1676                                         } else {\r
1677                                                 blTree.freqs[REP_11_138]++;\r
1678                                         }\r
1679                                 }\r
1680                         }\r
1681                         \r
1682                         public void WriteTree(Tree blTree)\r
1683                         {\r
1684                                 int max_count;               /* max repeat count */\r
1685                                 int min_count;               /* min repeat count */\r
1686                                 int count;                   /* repeat count of the current code */\r
1687                                 int curlen = -1;             /* length of current code */\r
1688                                 \r
1689                                 int i = 0;\r
1690                                 while (i < numCodes) {\r
1691                                         count = 1;\r
1692                                         int nextlen = length[i];\r
1693                                         if (nextlen == 0) {\r
1694                                                 max_count = 138;\r
1695                                                 min_count = 3;\r
1696                                         } else {\r
1697                                                 max_count = 6;\r
1698                                                 min_count = 3;\r
1699                                                 if (curlen != nextlen) {\r
1700                                                         blTree.WriteSymbol(nextlen);\r
1701                                                         count = 0;\r
1702                                                 }\r
1703                                         }\r
1704                                         curlen = nextlen;\r
1705                                         i++;\r
1706                                         \r
1707                                         while (i < numCodes && curlen == length[i]) {\r
1708                                                 i++;\r
1709                                                 if (++count >= max_count) {\r
1710                                                         break;\r
1711                                                 }\r
1712                                         }\r
1713                                         \r
1714                                         if (count < min_count) {\r
1715                                                 while (count-- > 0) {\r
1716                                                         blTree.WriteSymbol(curlen);\r
1717                                                 }\r
1718                                         }\r
1719                                         else if (curlen != 0) {\r
1720                                                 blTree.WriteSymbol(REP_3_6);\r
1721                                                 dh.pending.WriteBits(count - 3, 2);\r
1722                                         } else if (count <= 10) {\r
1723                                                 blTree.WriteSymbol(REP_3_10);\r
1724                                                 dh.pending.WriteBits(count - 3, 3);\r
1725                                         } else {\r
1726                                                 blTree.WriteSymbol(REP_11_138);\r
1727                                                 dh.pending.WriteBits(count - 11, 7);\r
1728                                         }\r
1729                                 }\r
1730                         }\r
1731                 }\r
1732                 \r
1733                 public DeflaterPending pending;\r
1734                 private Tree literalTree, distTree, blTree;\r
1735                 \r
1736                 private short[] d_buf;\r
1737                 private byte[] l_buf;\r
1738                 private int last_lit;\r
1739                 private int extra_bits;\r
1740                 \r
1741                 private static short[] staticLCodes;\r
1742                 private static byte[]  staticLLength;\r
1743                 private static short[] staticDCodes;\r
1744                 private static byte[]  staticDLength;\r
1745                 \r
1746                 /// <summary>\r
1747                 /// Reverse the bits of a 16 bit value.\r
1748                 /// </summary>\r
1749                 public static short BitReverse(int value) \r
1750                 {\r
1751                         return (short) (bit4Reverse[value & 0xF] << 12\r
1752                                         | bit4Reverse[(value >> 4) & 0xF] << 8\r
1753                                         | bit4Reverse[(value >> 8) & 0xF] << 4\r
1754                                         | bit4Reverse[value >> 12]);\r
1755                 }\r
1756                 \r
1757                 \r
1758                 static DeflaterHuffman() \r
1759                 {\r
1760                         /* See RFC 1951 3.2.6 */\r
1761                         /* Literal codes */\r
1762                         staticLCodes = new short[LITERAL_NUM];\r
1763                         staticLLength = new byte[LITERAL_NUM];\r
1764                         int i = 0;\r
1765                         while (i < 144) {\r
1766                                 staticLCodes[i] = BitReverse((0x030 + i) << 8);\r
1767                                 staticLLength[i++] = 8;\r
1768                         }\r
1769                         while (i < 256) {\r
1770                                 staticLCodes[i] = BitReverse((0x190 - 144 + i) << 7);\r
1771                                 staticLLength[i++] = 9;\r
1772                         }\r
1773                         while (i < 280) {\r
1774                                 staticLCodes[i] = BitReverse((0x000 - 256 + i) << 9);\r
1775                                 staticLLength[i++] = 7;\r
1776                         }\r
1777                         while (i < LITERAL_NUM) {\r
1778                                 staticLCodes[i] = BitReverse((0x0c0 - 280 + i)  << 8);\r
1779                                 staticLLength[i++] = 8;\r
1780                         }\r
1781                         \r
1782                         /* Distant codes */\r
1783                         staticDCodes = new short[DIST_NUM];\r
1784                         staticDLength = new byte[DIST_NUM];\r
1785                         for (i = 0; i < DIST_NUM; i++) {\r
1786                                 staticDCodes[i] = BitReverse(i << 11);\r
1787                                 staticDLength[i] = 5;\r
1788                         }\r
1789                 }\r
1790                 \r
1791                 public DeflaterHuffman(DeflaterPending pending)\r
1792                 {\r
1793                         this.pending = pending;\r
1794                         \r
1795                         literalTree = new Tree(this, LITERAL_NUM, 257, 15);\r
1796                         distTree    = new Tree(this, DIST_NUM, 1, 15);\r
1797                         blTree      = new Tree(this, BITLEN_NUM, 4, 7);\r
1798                         \r
1799                         d_buf = new short[BUFSIZE];\r
1800                         l_buf = new byte [BUFSIZE];\r
1801                 }\r
1802                 \r
1803                 public void Reset() \r
1804                 {\r
1805                         last_lit = 0;\r
1806                         extra_bits = 0;\r
1807                         literalTree.Reset();\r
1808                         distTree.Reset();\r
1809                         blTree.Reset();\r
1810                 }\r
1811                 \r
1812                 private int L_code(int len) \r
1813                 {\r
1814                         if (len == 255) {\r
1815                                 return 285;\r
1816                         }\r
1817                         \r
1818                         int code = 257;\r
1819                         while (len >= 8) {\r
1820                                 code += 4;\r
1821                                 len >>= 1;\r
1822                         }\r
1823                         return code + len;\r
1824                 }\r
1825                 \r
1826                 private int D_code(int distance) \r
1827                 {\r
1828                         int code = 0;\r
1829                         while (distance >= 4) {\r
1830                                 code += 2;\r
1831                                 distance >>= 1;\r
1832                         }\r
1833                         return code + distance;\r
1834                 }\r
1835                 \r
1836                 public void SendAllTrees(int blTreeCodes)\r
1837                 {\r
1838                         blTree.BuildCodes();\r
1839                         literalTree.BuildCodes();\r
1840                         distTree.BuildCodes();\r
1841                         pending.WriteBits(literalTree.numCodes - 257, 5);\r
1842                         pending.WriteBits(distTree.numCodes - 1, 5);\r
1843                         pending.WriteBits(blTreeCodes - 4, 4);\r
1844                         for (int rank = 0; rank < blTreeCodes; rank++) {\r
1845                                 pending.WriteBits(blTree.length[BL_ORDER[rank]], 3);\r
1846                         }\r
1847                         literalTree.WriteTree(blTree);\r
1848                         distTree.WriteTree(blTree);\r
1849 //                      if (DeflaterConstants.DEBUGGING) {\r
1850 //                              blTree.CheckEmpty();\r
1851 //                      }\r
1852                 }\r
1853                 \r
1854                 public void CompressBlock()\r
1855                 {\r
1856                         for (int i = 0; i < last_lit; i++) {\r
1857                                 int litlen = l_buf[i] & 0xff;\r
1858                                 int dist = d_buf[i];\r
1859                                 if (dist-- != 0) {\r
1860 //                                      if (DeflaterConstants.DEBUGGING) {\r
1861 //                                              Console.Write("["+(dist+1)+","+(litlen+3)+"]: ");\r
1862 //                                      }\r
1863                                         \r
1864                                         int lc = L_code(litlen);\r
1865                                         literalTree.WriteSymbol(lc);\r
1866                                         \r
1867                                         int bits = (lc - 261) / 4;\r
1868                                         if (bits > 0 && bits <= 5) {\r
1869                                                 pending.WriteBits(litlen & ((1 << bits) - 1), bits);\r
1870                                         }\r
1871                                         \r
1872                                         int dc = D_code(dist);\r
1873                                         distTree.WriteSymbol(dc);\r
1874                                         \r
1875                                         bits = dc / 2 - 1;\r
1876                                         if (bits > 0) {\r
1877                                                 pending.WriteBits(dist & ((1 << bits) - 1), bits);\r
1878                                         }\r
1879                                 } else {\r
1880 //                                      if (DeflaterConstants.DEBUGGING) {\r
1881 //                                              if (litlen > 32 && litlen < 127) {\r
1882 //                                                      Console.Write("("+(char)litlen+"): ");\r
1883 //                                              } else {\r
1884 //                                                      Console.Write("{"+litlen+"}: ");\r
1885 //                                              }\r
1886 //                                      }\r
1887                                         literalTree.WriteSymbol(litlen);\r
1888                                 }\r
1889                         }\r
1890 //                      if (DeflaterConstants.DEBUGGING) {\r
1891 //                              Console.Write("EOF: ");\r
1892 //                      }\r
1893                         literalTree.WriteSymbol(EOF_SYMBOL);\r
1894 //                      if (DeflaterConstants.DEBUGGING) {\r
1895 //                              literalTree.CheckEmpty();\r
1896 //                              distTree.CheckEmpty();\r
1897 //                      }\r
1898                 }\r
1899                 \r
1900                 public void FlushStoredBlock(byte[] stored, int stored_offset, int stored_len, bool lastBlock)\r
1901                 {\r
1902 //                      if (DeflaterConstants.DEBUGGING) {\r
1903 //                              Console.WriteLine("Flushing stored block "+ stored_len);\r
1904 //                      }\r
1905                         pending.WriteBits((DeflaterConstants.STORED_BLOCK << 1)\r
1906                                           + (lastBlock ? 1 : 0), 3);\r
1907                         pending.AlignToByte();\r
1908                         pending.WriteShort(stored_len);\r
1909                         pending.WriteShort(~stored_len);\r
1910                         pending.WriteBlock(stored, stored_offset, stored_len);\r
1911                         Reset();\r
1912                 }\r
1913                 \r
1914                 public void FlushBlock(byte[] stored, int stored_offset, int stored_len, bool lastBlock)\r
1915                 {\r
1916                         literalTree.freqs[EOF_SYMBOL]++;\r
1917                         \r
1918                         /* Build trees */\r
1919                         literalTree.BuildTree();\r
1920                         distTree.BuildTree();\r
1921                         \r
1922                         /* Calculate bitlen frequency */\r
1923                         literalTree.CalcBLFreq(blTree);\r
1924                         distTree.CalcBLFreq(blTree);\r
1925                         \r
1926                         /* Build bitlen tree */\r
1927                         blTree.BuildTree();\r
1928                         \r
1929                         int blTreeCodes = 4;\r
1930                         for (int i = 18; i > blTreeCodes; i--) {\r
1931                                 if (blTree.length[BL_ORDER[i]] > 0) {\r
1932                                         blTreeCodes = i+1;\r
1933                                 }\r
1934                         }\r
1935                         int opt_len = 14 + blTreeCodes * 3 + blTree.GetEncodedLength() + \r
1936                                       literalTree.GetEncodedLength() + distTree.GetEncodedLength() + \r
1937                                       extra_bits;\r
1938                         \r
1939                         int static_len = extra_bits;\r
1940                         for (int i = 0; i < LITERAL_NUM; i++) {\r
1941                                 static_len += literalTree.freqs[i] * staticLLength[i];\r
1942                         }\r
1943                         for (int i = 0; i < DIST_NUM; i++) {\r
1944                                 static_len += distTree.freqs[i] * staticDLength[i];\r
1945                         }\r
1946                         if (opt_len >= static_len) {\r
1947                                 /* Force static trees */\r
1948                                 opt_len = static_len;\r
1949                         }\r
1950                         \r
1951                         if (stored_offset >= 0 && stored_len+4 < opt_len >> 3) {\r
1952                                 /* Store Block */\r
1953 //                              if (DeflaterConstants.DEBUGGING) {\r
1954 //                                      Console.WriteLine("Storing, since " + stored_len + " < " + opt_len\r
1955 //                                                        + " <= " + static_len);\r
1956 //                              }\r
1957                                 FlushStoredBlock(stored, stored_offset, stored_len, lastBlock);\r
1958                         } else if (opt_len == static_len) {\r
1959                                 /* Encode with static tree */\r
1960                                 pending.WriteBits((DeflaterConstants.STATIC_TREES << 1) + (lastBlock ? 1 : 0), 3);\r
1961                                 literalTree.SetStaticCodes(staticLCodes, staticLLength);\r
1962                                 distTree.SetStaticCodes(staticDCodes, staticDLength);\r
1963                                 CompressBlock();\r
1964                                 Reset();\r
1965                         } else {\r
1966                                 /* Encode with dynamic tree */\r
1967                                 pending.WriteBits((DeflaterConstants.DYN_TREES << 1) + (lastBlock ? 1 : 0), 3);\r
1968                                 SendAllTrees(blTreeCodes);\r
1969                                 CompressBlock();\r
1970                                 Reset();\r
1971                         }\r
1972                 }\r
1973                 \r
1974                 public bool IsFull()\r
1975                 {\r
1976                         return last_lit + 16 >= BUFSIZE; // HACK: This was == 'last_lit == BUFSIZE', but errors occured with DeflateFast\r
1977                 }\r
1978                 \r
1979                 public bool TallyLit(int lit)\r
1980                 {\r
1981 //                      if (DeflaterConstants.DEBUGGING) {\r
1982 //                              if (lit > 32 && lit < 127) {\r
1983 //                                      Console.WriteLine("("+(char)lit+")");\r
1984 //                              } else {\r
1985 //                                      Console.WriteLine("{"+lit+"}");\r
1986 //                              }\r
1987 //                      }\r
1988                         d_buf[last_lit] = 0;\r
1989                         l_buf[last_lit++] = (byte)lit;\r
1990                         literalTree.freqs[lit]++;\r
1991                         return IsFull();\r
1992                 }\r
1993                 \r
1994                 public bool TallyDist(int dist, int len)\r
1995                 {\r
1996 //                      if (DeflaterConstants.DEBUGGING) {\r
1997 //                              Console.WriteLine("["+dist+","+len+"]");\r
1998 //                      }\r
1999                         \r
2000                         d_buf[last_lit]   = (short)dist;\r
2001                         l_buf[last_lit++] = (byte)(len - 3);\r
2002                         \r
2003                         int lc = L_code(len - 3);\r
2004                         literalTree.freqs[lc]++;\r
2005                         if (lc >= 265 && lc < 285) {\r
2006                                 extra_bits += (lc - 261) / 4;\r
2007                         }\r
2008                         \r
2009                         int dc = D_code(dist - 1);\r
2010                         distTree.freqs[dc]++;\r
2011                         if (dc >= 4) {\r
2012                                 extra_bits += dc / 2 - 1;\r
2013                         }\r
2014                         return IsFull();\r
2015                 }\r
2016         }\r
2017 }\r
2018 \r
2019 namespace NZlib.Compression {\r
2020         \r
2021         /// <summary>\r
2022         /// This class stores the pending output of the Deflater.\r
2023         /// \r
2024         /// author of the original java version : Jochen Hoenicke\r
2025         /// </summary>\r
2026         public class DeflaterPending : PendingBuffer\r
2027         {\r
2028                 public DeflaterPending() : base(DeflaterConstants.PENDING_BUF_SIZE)\r
2029                 {\r
2030                 }\r
2031         }\r
2032 }\r
2033 \r
2034 namespace NZlib.Compression {\r
2035         \r
2036         /// <summary>\r
2037         /// Inflater is used to decompress data that has been compressed according\r
2038         /// to the "deflate" standard described in rfc1950.\r
2039         ///\r
2040         /// The usage is as following.  First you have to set some input with\r
2041         /// <code>setInput()</code>, then inflate() it.  If inflate doesn't\r
2042         /// inflate any bytes there may be three reasons:\r
2043         /// <ul>\r
2044         /// <li>needsInput() returns true because the input buffer is empty.\r
2045         /// You have to provide more input with <code>setInput()</code>.\r
2046         /// NOTE: needsInput() also returns true when, the stream is finished.\r
2047         /// </li>\r
2048         /// <li>needsDictionary() returns true, you have to provide a preset\r
2049         ///    dictionary with <code>setDictionary()</code>.</li>\r
2050         /// <li>finished() returns true, the inflater has finished.</li>\r
2051         /// </ul>\r
2052         /// Once the first output byte is produced, a dictionary will not be\r
2053         /// needed at a later stage.\r
2054         ///\r
2055         /// author of the original java version : John Leuner, Jochen Hoenicke\r
2056         /// </summary>\r
2057         public class Inflater\r
2058         {\r
2059                 /// <summary>\r
2060                 /// Copy lengths for literal codes 257..285\r
2061                 /// </summary>\r
2062                 private static int[] CPLENS = {\r
2063                         3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,\r
2064                         35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258\r
2065                 };\r
2066                 \r
2067                 /// <summary>\r
2068                 /// Extra bits for literal codes 257..285\r
2069                 /// </summary>\r
2070                 private static int[] CPLEXT = {\r
2071                         0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,\r
2072                         3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0\r
2073                 };\r
2074                 \r
2075                 /// <summary>\r
2076                 /// Copy offsets for distance codes 0..29\r
2077                 /// </summary>\r
2078                 private static int[] CPDIST = {\r
2079                         1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,\r
2080                         257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,\r
2081                         8193, 12289, 16385, 24577\r
2082                 };\r
2083                 \r
2084                 /// <summary>\r
2085                 /// Extra bits for distance codes\r
2086                 /// </summary>\r
2087                 private static int[] CPDEXT = {\r
2088                         0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,\r
2089                         7, 7, 8, 8, 9, 9, 10, 10, 11, 11,\r
2090                         12, 12, 13, 13\r
2091                 };\r
2092                 \r
2093                 /// <summary>\r
2094                 /// This are the state in which the inflater can be.\r
2095                 /// </summary>\r
2096                 private const int DECODE_HEADER           = 0;\r
2097                 private const int DECODE_DICT             = 1;\r
2098                 private const int DECODE_BLOCKS           = 2;\r
2099                 private const int DECODE_STORED_LEN1      = 3;\r
2100                 private const int DECODE_STORED_LEN2      = 4;\r
2101                 private const int DECODE_STORED           = 5;\r
2102                 private const int DECODE_DYN_HEADER       = 6;\r
2103                 private const int DECODE_HUFFMAN          = 7;\r
2104                 private const int DECODE_HUFFMAN_LENBITS  = 8;\r
2105                 private const int DECODE_HUFFMAN_DIST     = 9;\r
2106                 private const int DECODE_HUFFMAN_DISTBITS = 10;\r
2107                 private const int DECODE_CHKSUM           = 11;\r
2108                 private const int FINISHED                = 12;\r
2109                 \r
2110                 /// <summary>\r
2111                 /// This variable contains the current state.\r
2112                 /// </summary>\r
2113                 private int mode;\r
2114                 \r
2115                 /// <summary>\r
2116                 /// The adler checksum of the dictionary or of the decompressed\r
2117                 /// stream, as it is written in the header resp. footer of the\r
2118                 /// compressed stream. \r
2119                 /// Only valid if mode is DECODE_DICT or DECODE_CHKSUM.\r
2120                 /// </summary>\r
2121                 private int readAdler;\r
2122                 \r
2123                 /// <summary>\r
2124                 /// The number of bits needed to complete the current state.  This\r
2125                 /// is valid, if mode is DECODE_DICT, DECODE_CHKSUM,\r
2126                 /// DECODE_HUFFMAN_LENBITS or DECODE_HUFFMAN_DISTBITS.\r
2127                 /// </summary>\r
2128                 private int neededBits;\r
2129                 private int repLength, repDist;\r
2130                 private int uncomprLen;\r
2131                 \r
2132                 /// <summary>\r
2133                 /// True, if the last block flag was set in the last block of the\r
2134                 /// inflated stream.  This means that the stream ends after the\r
2135                 /// current block.\r
2136                 /// </summary>\r
2137                 private bool isLastBlock;\r
2138                 \r
2139                 /// <summary>\r
2140                 /// The total number of inflated bytes.\r
2141                 /// </summary>\r
2142                 private int totalOut;\r
2143                 \r
2144                 /// <summary>\r
2145                 /// The total number of bytes set with setInput().  This is not the\r
2146                 /// value returned by getTotalIn(), since this also includes the\r
2147                 /// unprocessed input.\r
2148                 /// </summary>\r
2149                 private int totalIn;\r
2150                 \r
2151                 /// <summary>\r
2152                 /// This variable stores the nowrap flag that was given to the constructor.\r
2153                 /// True means, that the inflated stream doesn't contain a header nor the\r
2154                 /// checksum in the footer.\r
2155                 /// </summary>\r
2156                 private bool nowrap;\r
2157                 \r
2158                 private StreamManipulator input;\r
2159                 private OutputWindow outputWindow;\r
2160                 private InflaterDynHeader dynHeader;\r
2161                 private InflaterHuffmanTree litlenTree, distTree;\r
2162                 private Adler32 adler;\r
2163                 \r
2164                 /// <summary>\r
2165                 /// Creates a new inflater.\r
2166                 /// </summary>\r
2167                 public Inflater() : this(false)\r
2168                 {\r
2169                 }\r
2170                 \r
2171                 /// <summary>\r
2172                 /// Creates a new inflater.\r
2173                 /// </summary>\r
2174                 /// <param name="nowrap">\r
2175                 /// true if no header and checksum field appears in the\r
2176                 /// stream.  This is used for GZIPed input.  For compatibility with\r
2177                 /// Sun JDK you should provide one byte of input more than needed in\r
2178                 /// this case.\r
2179                 /// </param>\r
2180                 public Inflater(bool nowrap)\r
2181                 {\r
2182                         this.nowrap = nowrap;\r
2183                         this.adler = new Adler32();\r
2184                         input = new StreamManipulator();\r
2185                         outputWindow = new OutputWindow();\r
2186                         mode = nowrap ? DECODE_BLOCKS : DECODE_HEADER;\r
2187                 }\r
2188                 \r
2189                 /// <summary>\r
2190                 /// Resets the inflater so that a new stream can be decompressed.  All\r
2191                 /// pending input and output will be discarded.\r
2192                 /// </summary>\r
2193                 public void Reset()\r
2194                 {\r
2195                         mode = nowrap ? DECODE_BLOCKS : DECODE_HEADER;\r
2196                         totalIn = totalOut = 0;\r
2197                         input.Reset();\r
2198                         outputWindow.Reset();\r
2199                         dynHeader = null;\r
2200                         litlenTree = null;\r
2201                         distTree = null;\r
2202                         isLastBlock = false;\r
2203                         adler.Reset();\r
2204                 }\r
2205                 \r
2206                 /// <summary>\r
2207                 /// Decodes the deflate header.\r
2208                 /// </summary>\r
2209                 /// <returns>\r
2210                 /// false if more input is needed.\r
2211                 /// </returns>\r
2212                 /// <exception cref="System.FormatException">\r
2213                 /// if header is invalid.\r
2214                 /// </exception>\r
2215                 private bool DecodeHeader()\r
2216                 {\r
2217                         int header = input.PeekBits(16);\r
2218                         if (header < 0) {\r
2219                                 return false;\r
2220                         }\r
2221                         input.DropBits(16);\r
2222                         /* The header is written in "wrong" byte order */\r
2223                         header = ((header << 8) | (header >> 8)) & 0xffff;\r
2224                         if (header % 31 != 0) {\r
2225                                 throw new FormatException("Header checksum illegal");\r
2226                         }\r
2227                         \r
2228                         if ((header & 0x0f00) != (Deflater.DEFLATED << 8)) {\r
2229                                 throw new FormatException("Compression Method unknown");\r
2230                         }\r
2231                         \r
2232                         /* Maximum size of the backwards window in bits.\r
2233                         * We currently ignore this, but we could use it to make the\r
2234                         * inflater window more space efficient. On the other hand the\r
2235                         * full window (15 bits) is needed most times, anyway.\r
2236                         int max_wbits = ((header & 0x7000) >> 12) + 8;\r
2237                         */\r
2238                         \r
2239                         if ((header & 0x0020) == 0) { // Dictionary flag?\r
2240                                 mode = DECODE_BLOCKS;\r
2241                         } else {\r
2242                                 mode = DECODE_DICT;\r
2243                                 neededBits = 32;\r
2244                         }\r
2245                         return true;\r
2246                 }\r
2247                 \r
2248                 /// <summary>\r
2249                 /// Decodes the dictionary checksum after the deflate header.\r
2250                 /// </summary>\r
2251                 /// <returns>\r
2252                 /// false if more input is needed.\r
2253                 /// </returns>\r
2254                 private bool DecodeDict()\r
2255                 {\r
2256                         while (neededBits > 0) {\r
2257                                 int dictByte = input.PeekBits(8);\r
2258                                 if (dictByte < 0) {\r
2259                                         return false;\r
2260                                 }\r
2261                                 input.DropBits(8);\r
2262                                 readAdler = (readAdler << 8) | dictByte;\r
2263                                 neededBits -= 8;\r
2264                         }\r
2265                         return false;\r
2266                 }\r
2267                 \r
2268                 /// <summary>\r
2269                 /// Decodes the huffman encoded symbols in the input stream.\r
2270                 /// </summary>\r
2271                 /// <returns>\r
2272                 /// false if more input is needed, true if output window is\r
2273                 /// full or the current block ends.\r
2274                 /// </returns>\r
2275                 /// <exception cref="System.FormatException">\r
2276                 /// if deflated stream is invalid.\r
2277                 /// </exception>\r
2278                 private bool DecodeHuffman()\r
2279                 {\r
2280                         int free = outputWindow.GetFreeSpace();\r
2281                         while (free >= 258) {\r
2282                                 int symbol;\r
2283                                 switch (mode) {\r
2284                                         case DECODE_HUFFMAN:\r
2285                                                 /* This is the inner loop so it is optimized a bit */\r
2286                                                 while (((symbol = litlenTree.GetSymbol(input)) & ~0xff) == 0) {\r
2287                                                         outputWindow.Write(symbol);\r
2288                                                         if (--free < 258) {\r
2289                                                                 return true;\r
2290                                                         }\r
2291                                                 }\r
2292                                                 if (symbol < 257) {\r
2293                                                         if (symbol < 0) {\r
2294                                                                 return false;\r
2295                                                         } else {\r
2296                                                                 /* symbol == 256: end of block */\r
2297                                                                 distTree = null;\r
2298                                                                 litlenTree = null;\r
2299                                                                 mode = DECODE_BLOCKS;\r
2300                                                                 return true;\r
2301                                                         }\r
2302                                                 }\r
2303                                                 \r
2304                                                 try {\r
2305                                                         repLength = CPLENS[symbol - 257];\r
2306                                                         neededBits = CPLEXT[symbol - 257];\r
2307                                                 } catch (Exception) {\r
2308                                                         throw new FormatException("Illegal rep length code");\r
2309                                                 }\r
2310                                                 goto case DECODE_HUFFMAN_LENBITS;/* fall through */\r
2311                                         case DECODE_HUFFMAN_LENBITS:\r
2312                                                 if (neededBits > 0) {\r
2313                                                         mode = DECODE_HUFFMAN_LENBITS;\r
2314                                                         int i = input.PeekBits(neededBits);\r
2315                                                         if (i < 0) {\r
2316                                                                 return false;\r
2317                                                         }\r
2318                                                         input.DropBits(neededBits);\r
2319                                                         repLength += i;\r
2320                                                 }\r
2321                                                 mode = DECODE_HUFFMAN_DIST;\r
2322                                                 goto case DECODE_HUFFMAN_DIST;/* fall through */\r
2323                                         case DECODE_HUFFMAN_DIST:\r
2324                                                 symbol = distTree.GetSymbol(input);\r
2325                                                 if (symbol < 0) {\r
2326                                                         return false;\r
2327                                                 }\r
2328                                                 try {\r
2329                                                         repDist = CPDIST[symbol];\r
2330                                                         neededBits = CPDEXT[symbol];\r
2331                                                 } catch (Exception) {\r
2332                                                         throw new FormatException("Illegal rep dist code");\r
2333                                                 }\r
2334                                                 \r
2335                                                 goto case DECODE_HUFFMAN_DISTBITS;/* fall through */\r
2336                                         case DECODE_HUFFMAN_DISTBITS:\r
2337                                                 if (neededBits > 0) {\r
2338                                                         mode = DECODE_HUFFMAN_DISTBITS;\r
2339                                                         int i = input.PeekBits(neededBits);\r
2340                                                         if (i < 0) {\r
2341                                                                 return false;\r
2342                                                         }\r
2343                                                         input.DropBits(neededBits);\r
2344                                                         repDist += i;\r
2345                                                 }\r
2346                                                 outputWindow.Repeat(repLength, repDist);\r
2347                                                 free -= repLength;\r
2348                                                 mode = DECODE_HUFFMAN;\r
2349                                                 break;\r
2350                                         default:\r
2351                                                 throw new FormatException();\r
2352                                 }\r
2353                         }\r
2354                         return true;\r
2355                 }\r
2356                 \r
2357                 /// <summary>\r
2358                 /// Decodes the adler checksum after the deflate stream.\r
2359                 /// </summary>\r
2360                 /// <returns>\r
2361                 /// false if more input is needed.\r
2362                 /// </returns>\r
2363                 /// <exception cref="System.FormatException">\r
2364                 /// DataFormatException, if checksum doesn't match.\r
2365                 /// </exception>\r
2366                 private bool DecodeChksum()\r
2367                 {\r
2368                         while (neededBits > 0) {\r
2369                                 int chkByte = input.PeekBits(8);\r
2370                                 if (chkByte < 0) {\r
2371                                         return false;\r
2372                                 }\r
2373                                 input.DropBits(8);\r
2374                                 readAdler = (readAdler << 8) | chkByte;\r
2375                                 neededBits -= 8;\r
2376                         }\r
2377                         if ((int) adler.Value != readAdler) {\r
2378                                 throw new FormatException("Adler chksum doesn't match: "\r
2379                                                           + (int)adler.Value\r
2380                                                           + " vs. " + readAdler);\r
2381                         }\r
2382                         mode = FINISHED;\r
2383                         return false;\r
2384                 }\r
2385                 \r
2386                 /// <summary>\r
2387                 /// Decodes the deflated stream.\r
2388                 /// </summary>\r
2389                 /// <returns>\r
2390                 /// false if more input is needed, or if finished.\r
2391                 /// </returns>\r
2392                 /// <exception cref="System.FormatException">\r
2393                 /// DataFormatException, if deflated stream is invalid.\r
2394                 /// </exception>\r
2395                 private bool Decode()\r
2396                 {\r
2397                         switch (mode) {\r
2398                                 case DECODE_HEADER:\r
2399                                         return DecodeHeader();\r
2400                                 case DECODE_DICT:\r
2401                                         return DecodeDict();\r
2402                                 case DECODE_CHKSUM:\r
2403                                         return DecodeChksum();\r
2404                                 \r
2405                                 case DECODE_BLOCKS:\r
2406                                         if (isLastBlock) {\r
2407                                                 if (nowrap) {\r
2408                                                         mode = FINISHED;\r
2409                                                         return false;\r
2410                                                 } else {\r
2411                                                         input.SkipToByteBoundary();\r
2412                                                         neededBits = 32;\r
2413                                                         mode = DECODE_CHKSUM;\r
2414                                                         return true;\r
2415                                                 }\r
2416                                         }\r
2417                                         \r
2418                                         int type = input.PeekBits(3);\r
2419                                         if (type < 0) {\r
2420                                                 return false;\r
2421                                         }\r
2422                                         input.DropBits(3);\r
2423                                         \r
2424                                         if ((type & 1) != 0) {\r
2425                                                 isLastBlock = true;\r
2426                                         }\r
2427                                         switch (type >> 1) {\r
2428                                                 case DeflaterConstants.STORED_BLOCK:\r
2429                                                         input.SkipToByteBoundary();\r
2430                                                         mode = DECODE_STORED_LEN1;\r
2431                                                         break;\r
2432                                                 case DeflaterConstants.STATIC_TREES:\r
2433                                                         litlenTree = InflaterHuffmanTree.defLitLenTree;\r
2434                                                         distTree = InflaterHuffmanTree.defDistTree;\r
2435                                                         mode = DECODE_HUFFMAN;\r
2436                                                         break;\r
2437                                                 case DeflaterConstants.DYN_TREES:\r
2438                                                         dynHeader = new InflaterDynHeader();\r
2439                                                         mode = DECODE_DYN_HEADER;\r
2440                                                         break;\r
2441                                                 default:\r
2442                                                         throw new FormatException("Unknown block type "+type);\r
2443                                         }\r
2444                                         return true;\r
2445                                 \r
2446                                 case DECODE_STORED_LEN1: {\r
2447                                         if ((uncomprLen = input.PeekBits(16)) < 0) {\r
2448                                                 return false;\r
2449                                         }\r
2450                                         input.DropBits(16);\r
2451                                         mode = DECODE_STORED_LEN2;\r
2452                                 }\r
2453                                 goto case DECODE_STORED_LEN2; /* fall through */\r
2454                                 case DECODE_STORED_LEN2: {\r
2455                                         int nlen = input.PeekBits(16);\r
2456                                         if (nlen < 0) {\r
2457                                                 return false;\r
2458                                         }\r
2459                                         input.DropBits(16);\r
2460                                         if (nlen != (uncomprLen ^ 0xffff)) {\r
2461                                                 throw new FormatException("broken uncompressed block");\r
2462                                         }\r
2463                                         mode = DECODE_STORED;\r
2464                                 }\r
2465                                 goto case DECODE_STORED;/* fall through */\r
2466                                 case DECODE_STORED: {\r
2467                                         int more = outputWindow.CopyStored(input, uncomprLen);\r
2468                                         uncomprLen -= more;\r
2469                                         if (uncomprLen == 0) {\r
2470                                                 mode = DECODE_BLOCKS;\r
2471                                                 return true;\r
2472                                         }\r
2473                                         return !input.IsNeedingInput;\r
2474                                 }\r
2475                                 \r
2476                                 case DECODE_DYN_HEADER:\r
2477                                         if (!dynHeader.Decode(input)) {\r
2478                                                 return false;\r
2479                                         }\r
2480                                         \r
2481                                         litlenTree = dynHeader.BuildLitLenTree();\r
2482                                         distTree = dynHeader.BuildDistTree();\r
2483                                         mode = DECODE_HUFFMAN;\r
2484                                         goto case DECODE_HUFFMAN; /* fall through */\r
2485                                 case DECODE_HUFFMAN:\r
2486                                 case DECODE_HUFFMAN_LENBITS:\r
2487                                 case DECODE_HUFFMAN_DIST:\r
2488                                 case DECODE_HUFFMAN_DISTBITS:\r
2489                                         return DecodeHuffman();\r
2490                                 case FINISHED:\r
2491                                         return false;\r
2492                                 default:\r
2493                                         throw new FormatException();\r
2494                         }\r
2495                 }\r
2496                         \r
2497                 /// <summary>\r
2498                 /// Sets the preset dictionary.  This should only be called, if\r
2499                 /// needsDictionary() returns true and it should set the same\r
2500                 /// dictionary, that was used for deflating.  The getAdler()\r
2501                 /// function returns the checksum of the dictionary needed.\r
2502                 /// </summary>\r
2503                 /// <param name="buffer">\r
2504                 /// the dictionary.\r
2505                 /// </param>\r
2506                 /// <exception cref="System.InvalidOperationException">\r
2507                 /// if no dictionary is needed.\r
2508                 /// </exception>\r
2509                 /// <exception cref="System.ArgumentException">\r
2510                 /// if the dictionary checksum is wrong.\r
2511                 /// </exception>\r
2512                 public void SetDictionary(byte[] buffer)\r
2513                 {\r
2514                         SetDictionary(buffer, 0, buffer.Length);\r
2515                 }\r
2516                 \r
2517                 /// <summary>\r
2518                 /// Sets the preset dictionary.  This should only be called, if\r
2519                 /// needsDictionary() returns true and it should set the same\r
2520                 /// dictionary, that was used for deflating.  The getAdler()\r
2521                 /// function returns the checksum of the dictionary needed.\r
2522                 /// </summary>\r
2523                 /// <param name="buffer">\r
2524                 /// the dictionary.\r
2525                 /// </param>\r
2526                 /// <param name="off">\r
2527                 /// the offset into buffer where the dictionary starts.\r
2528                 /// </param>\r
2529                 /// <param name="len">\r
2530                 /// the length of the dictionary.\r
2531                 /// </param>\r
2532                 /// <exception cref="System.InvalidOperationException">\r
2533                 /// if no dictionary is needed.\r
2534                 /// </exception>\r
2535                 /// <exception cref="System.ArgumentException">\r
2536                 /// if the dictionary checksum is wrong.\r
2537                 /// </exception>\r
2538                 /// <exception cref="System.ArgumentOutOfRangeException">\r
2539                 /// if the off and/or len are wrong.\r
2540                 /// </exception>\r
2541                 public void SetDictionary(byte[] buffer, int off, int len)\r
2542                 {\r
2543                         if (!IsNeedingDictionary) {\r
2544                                 throw new InvalidOperationException();\r
2545                         }\r
2546                         \r
2547                         adler.Update(buffer, off, len);\r
2548                         if ((int) adler.Value != readAdler) {\r
2549                                 throw new ArgumentException("Wrong adler checksum");\r
2550                         }\r
2551                         adler.Reset();\r
2552                         outputWindow.CopyDict(buffer, off, len);\r
2553                         mode = DECODE_BLOCKS;\r
2554                 }\r
2555                 \r
2556                 /// <summary>\r
2557                 /// Sets the input.  This should only be called, if needsInput()\r
2558                 /// returns true.\r
2559                 /// </summary>\r
2560                 /// <param name="buf">\r
2561                 /// the input.\r
2562                 /// </param>\r
2563                 /// <exception cref="System.InvalidOperationException">\r
2564                 /// if no input is needed.\r
2565                 /// </exception>\r
2566                 public void SetInput(byte[] buf)\r
2567                 {\r
2568                         SetInput(buf, 0, buf.Length);\r
2569                 }\r
2570                 \r
2571                 /// <summary>\r
2572                 /// Sets the input.  This should only be called, if needsInput()\r
2573                 /// returns true.\r
2574                 /// </summary>\r
2575                 /// <param name="buf">\r
2576                 /// the input.\r
2577                 /// </param>\r
2578                 /// <param name="off">\r
2579                 /// the offset into buffer where the input starts.\r
2580                 /// </param>\r
2581                 /// <param name="len">\r
2582                 /// the length of the input.\r
2583                 /// </param>\r
2584                 /// <exception cref="System.InvalidOperationException">\r
2585                 /// if no input is needed.\r
2586                 /// </exception>\r
2587                 /// <exception cref="System.ArgumentOutOfRangeException">\r
2588                 /// if the off and/or len are wrong.\r
2589                 /// </exception>\r
2590                 public void SetInput(byte[] buf, int off, int len)\r
2591                 {\r
2592                         input.SetInput(buf, off, len);\r
2593                         totalIn += len;\r
2594                 }\r
2595                 \r
2596                 /// <summary>\r
2597                 /// Inflates the compressed stream to the output buffer.  If this\r
2598                 /// returns 0, you should check, whether needsDictionary(),\r
2599                 /// needsInput() or finished() returns true, to determine why no\r
2600                 /// further output is produced.\r
2601                 /// </summary>\r
2602                 /// <param name = "buf">\r
2603                 /// the output buffer.\r
2604                 /// </param>\r
2605                 /// <returns>\r
2606                 /// the number of bytes written to the buffer, 0 if no further\r
2607                 /// output can be produced.\r
2608                 /// </returns>\r
2609                 /// <exception cref="System.ArgumentOutOfRangeException">\r
2610                 /// if buf has length 0.\r
2611                 /// </exception>\r
2612                 /// <exception cref="System.FormatException">\r
2613                 /// if deflated stream is invalid.\r
2614                 /// </exception>\r
2615                 public int Inflate(byte[] buf)\r
2616                 {\r
2617                         return Inflate(buf, 0, buf.Length);\r
2618                 }\r
2619                 \r
2620                 /// <summary>\r
2621                 /// Inflates the compressed stream to the output buffer.  If this\r
2622                 /// returns 0, you should check, whether needsDictionary(),\r
2623                 /// needsInput() or finished() returns true, to determine why no\r
2624                 /// further output is produced.\r
2625                 /// </summary>\r
2626                 /// <param name = "buf">\r
2627                 /// the output buffer.\r
2628                 /// </param>\r
2629                 /// <param name = "off">\r
2630                 /// the offset into buffer where the output should start.\r
2631                 /// </param>\r
2632                 /// <param name = "len">\r
2633                 /// the maximum length of the output.\r
2634                 /// </param>\r
2635                 /// <returns>\r
2636                 /// the number of bytes written to the buffer, 0 if no further output can be produced.\r
2637                 /// </returns>\r
2638                 /// <exception cref="System.ArgumentOutOfRangeException">\r
2639                 /// if len is &lt;= 0.\r
2640                 /// </exception>\r
2641                 /// <exception cref="System.ArgumentOutOfRangeException">\r
2642                 /// if the off and/or len are wrong.\r
2643                 /// </exception>\r
2644                 /// <exception cref="System.FormatException">\r
2645                 /// if deflated stream is invalid.\r
2646                 /// </exception>\r
2647                 public int Inflate(byte[] buf, int off, int len)\r
2648                 {\r
2649                         if (len <= 0) {\r
2650                                 throw new ArgumentOutOfRangeException("len <= 0");\r
2651                         }\r
2652                         int count = 0;\r
2653                         int more;\r
2654                         do {\r
2655                                 if (mode != DECODE_CHKSUM) {\r
2656                                         /* Don't give away any output, if we are waiting for the\r
2657                                         * checksum in the input stream.\r
2658                                         *\r
2659                                         * With this trick we have always:\r
2660                                         *   needsInput() and not finished()\r
2661                                         *   implies more output can be produced.\r
2662                                         */\r
2663                                         more = outputWindow.CopyOutput(buf, off, len);\r
2664                                         adler.Update(buf, off, more);\r
2665                                         off += more;\r
2666                                         count += more;\r
2667                                         totalOut += more;\r
2668                                         len -= more;\r
2669                                         if (len == 0) {\r
2670                                                 return count;\r
2671                                         }\r
2672                                 }\r
2673                         } while (Decode() || (outputWindow.GetAvailable() > 0 &&\r
2674                                               mode != DECODE_CHKSUM));\r
2675                         return count;\r
2676                 }\r
2677                 \r
2678                 /// <summary>\r
2679                 /// Returns true, if the input buffer is empty.\r
2680                 /// You should then call setInput(). \r
2681                 /// NOTE: This method also returns true when the stream is finished.\r
2682                 /// </summary>\r
2683                 public bool IsNeedingInput {\r
2684                         get {\r
2685                                 return input.IsNeedingInput;\r
2686                         }\r
2687                 }\r
2688                 \r
2689                 /// <summary>\r
2690                 /// Returns true, if a preset dictionary is needed to inflate the input.\r
2691                 /// </summary>\r
2692                 public bool IsNeedingDictionary {\r
2693                         get {\r
2694                                 return mode == DECODE_DICT && neededBits == 0;\r
2695                         }\r
2696                 }\r
2697                 \r
2698                 /// <summary>\r
2699                 /// Returns true, if the inflater has finished.  This means, that no\r
2700                 /// input is needed and no output can be produced.\r
2701                 /// </summary>\r
2702                 public bool IsFinished {\r
2703                         get {\r
2704                                 return mode == FINISHED && outputWindow.GetAvailable() == 0;\r
2705                         }\r
2706                 }\r
2707                 \r
2708                 /// <summary>\r
2709                 /// Gets the adler checksum.  This is either the checksum of all\r
2710                 /// uncompressed bytes returned by inflate(), or if needsDictionary()\r
2711                 /// returns true (and thus no output was yet produced) this is the\r
2712                 /// adler checksum of the expected dictionary.\r
2713                 /// </summary>\r
2714                 /// <returns>\r
2715                 /// the adler checksum.\r
2716                 /// </returns>\r
2717                 public int Adler {\r
2718                         get {\r
2719                                 return IsNeedingDictionary ? readAdler : (int) adler.Value;\r
2720                         }\r
2721                 }\r
2722                 \r
2723                 /// <summary>\r
2724                 /// Gets the total number of output bytes returned by inflate().\r
2725                 /// </summary>\r
2726                 /// <returns>\r
2727                 /// the total number of output bytes.\r
2728                 /// </returns>\r
2729                 public int TotalOut {\r
2730                         get {\r
2731                                 return totalOut;\r
2732                         }\r
2733                 }\r
2734                 \r
2735                 /// <summary>\r
2736                 /// Gets the total number of processed compressed input bytes.\r
2737                 /// </summary>\r
2738                 /// <returns>\r
2739                 /// the total number of bytes of processed input bytes.\r
2740                 /// </returns>\r
2741                 public int TotalIn {\r
2742                         get {\r
2743                                 return totalIn - RemainingInput;\r
2744                         }\r
2745                 }\r
2746                 \r
2747                 /// <summary>\r
2748                 /// Gets the number of unprocessed input.  Useful, if the end of the\r
2749                 /// stream is reached and you want to further process the bytes after\r
2750                 /// the deflate stream.\r
2751                 /// </summary>\r
2752                 /// <returns>\r
2753                 /// the number of bytes of the input which were not processed.\r
2754                 /// </returns>\r
2755                 public int RemainingInput {\r
2756                         get {\r
2757                                 return input.AvailableBytes;\r
2758                         }\r
2759                 }\r
2760         }\r
2761 }\r
2762 \r
2763 namespace NZlib.Compression {\r
2764         \r
2765         public class InflaterDynHeader\r
2766         {\r
2767                 private const int LNUM   = 0;\r
2768                 private const int DNUM   = 1;\r
2769                 private const int BLNUM  = 2;\r
2770                 private const int BLLENS = 3;\r
2771                 private const int LLENS  = 4;\r
2772                 private const int DLENS  = 5;\r
2773                 private const int LREPS  = 6;\r
2774                 private const int DREPS  = 7;\r
2775                 private const int FINISH = 8;\r
2776                 \r
2777                 private byte[] blLens;\r
2778                 private byte[] litlenLens;\r
2779                 private byte[] distLens;\r
2780                 \r
2781                 private InflaterHuffmanTree blTree;\r
2782                 \r
2783                 private int mode;\r
2784                 private int lnum, dnum, blnum;\r
2785                 private int repBits;\r
2786                 private byte repeatedLen;\r
2787                 private int ptr;\r
2788                 \r
2789                 private static int[] BL_ORDER = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };\r
2790                 \r
2791                 public InflaterDynHeader()\r
2792                 {\r
2793                 }\r
2794                 \r
2795                 public bool Decode(StreamManipulator input)\r
2796                 {\r
2797                         decode_loop:\r
2798                         for (;;) {\r
2799                                 switch (mode) {\r
2800                                         case LNUM:\r
2801                                                 lnum = input.PeekBits(5);\r
2802                                                 if (lnum < 0) {\r
2803                                                         return false;\r
2804                                                 }\r
2805                                                 lnum += 257;\r
2806                                                 input.DropBits(5);\r
2807                                                 litlenLens = new byte[lnum];\r
2808                                                 //          System.err.println("LNUM: "+lnum);\r
2809                                                 mode = DNUM;\r
2810                                                 goto case DNUM;/* fall through */\r
2811                                         case DNUM:\r
2812                                                 dnum = input.PeekBits(5);\r
2813                                                 if (dnum < 0) {\r
2814                                                         return false;\r
2815                                                 }\r
2816                                                 dnum++;\r
2817                                                 input.DropBits(5);\r
2818                                                 distLens = new byte[dnum];\r
2819                                                 //          System.err.println("DNUM: "+dnum);\r
2820                                                 mode = BLNUM;\r
2821                                                 goto case BLNUM;/* fall through */\r
2822                                         case BLNUM:\r
2823                                                 blnum = input.PeekBits(4);\r
2824                                                 if (blnum < 0) {\r
2825                                                         return false;\r
2826                                                 }\r
2827                                                 blnum += 4;\r
2828                                                 input.DropBits(4);\r
2829                                                 blLens = new byte[19];\r
2830                                                 ptr = 0;\r
2831                                                 //          System.err.println("BLNUM: "+blnum);\r
2832                                                 mode = BLLENS;\r
2833                                                 goto case BLLENS;/* fall through */\r
2834                                         case BLLENS:\r
2835                                                 while (ptr < blnum) {\r
2836                                                         int len = input.PeekBits(3);\r
2837                                                         if (len < 0) {\r
2838                                                                 return false;\r
2839                                                         }\r
2840                                                         input.DropBits(3);\r
2841                                                         //              System.err.println("blLens["+BL_ORDER[ptr]+"]: "+len);\r
2842                                                         blLens[BL_ORDER[ptr]] = (byte) len;\r
2843                                                         ptr++;\r
2844                                                 }\r
2845                                                 blTree = new InflaterHuffmanTree(blLens);\r
2846                                                 blLens = null;\r
2847                                                 ptr = 0;\r
2848                                                 mode = LLENS;\r
2849                                                 goto case LLENS;/* fall through */\r
2850                                         case LLENS:\r
2851                                                 while (ptr < lnum) {\r
2852                                                         int symbol = blTree.GetSymbol(input);\r
2853                                                         if (symbol < 0) {\r
2854                                                                 return false;\r
2855                                                         }\r
2856                                                         switch (symbol) {\r
2857                                                                 default:\r
2858                                                                         //                  System.err.println("litlenLens["+ptr+"]: "+symbol);\r
2859                                                                         litlenLens[ptr++] = (byte) symbol;\r
2860                                                                         break;\r
2861                                                                 case 16: /* repeat last len 3-6 times */\r
2862                                                                         if (ptr == 0) {\r
2863                                                                                 throw new Exception("Repeating, but no prev len");\r
2864                                                                         }\r
2865                                                                         \r
2866                                                                         //                  System.err.println("litlenLens["+ptr+"]: repeat");\r
2867                                                                         repeatedLen = litlenLens[ptr-1];\r
2868                                                                         repBits = 2;\r
2869                                                                         for (int i = 3; i-- > 0; ) {\r
2870                                                                                 if (ptr >= lnum) {\r
2871                                                                                         throw new Exception();\r
2872                                                                                 }\r
2873                                                                                 litlenLens[ptr++] = repeatedLen;\r
2874                                                                         }\r
2875                                                                         mode = LREPS;\r
2876                                                                         goto decode_loop;\r
2877                                                                 case 17: /* repeat zero 3-10 times */\r
2878                                                                         //                  System.err.println("litlenLens["+ptr+"]: zero repeat");\r
2879                                                                         repeatedLen = 0;\r
2880                                                                         repBits = 3;\r
2881                                                                         for (int i = 3; i-- > 0; ) {\r
2882                                                                                 if (ptr >= lnum) {\r
2883                                                                                         throw new Exception();\r
2884                                                                                 }\r
2885                                                                                 litlenLens[ptr++] = repeatedLen;\r
2886                                                                         }\r
2887                                                                         mode = LREPS;\r
2888                                                                         goto decode_loop;\r
2889                                                                 case 18: /* repeat zero 11-138 times */\r
2890                                                                         //                  System.err.println("litlenLens["+ptr+"]: zero repeat");\r
2891                                                                         repeatedLen = 0;\r
2892                                                                         repBits = 7;\r
2893                                                                         for (int i = 11; i-- > 0; ) {\r
2894                                                                                 if (ptr >= lnum) {\r
2895                                                                                         throw new Exception();\r
2896                                                                                 }\r
2897                                                                                 litlenLens[ptr++] = repeatedLen;\r
2898                                                                         }\r
2899                                                                         mode = LREPS;\r
2900                                                                         goto decode_loop;\r
2901                                                         }\r
2902                                                 }\r
2903                                                 ptr = 0;\r
2904                                                 mode = DLENS;\r
2905                                                 goto case DLENS;/* fall through */\r
2906                                                 case DLENS:\r
2907                                                         while (ptr < dnum) {\r
2908                                                                 int symbol = blTree.GetSymbol(input);\r
2909                                                                 if (symbol < 0) {\r
2910                                                                         return false;\r
2911                                                                 }\r
2912                                                                 switch (symbol) {\r
2913                                                                         default:\r
2914                                                                                 distLens[ptr++] = (byte) symbol;\r
2915                                                                                 //                  System.err.println("distLens["+ptr+"]: "+symbol);\r
2916                                                                                 break;\r
2917                                                                         case 16: /* repeat last len 3-6 times */\r
2918                                                                                 if (ptr == 0) {\r
2919                                                                                         throw new Exception("Repeating, but no prev len");\r
2920                                                                                 }\r
2921                                                                                 //                  System.err.println("distLens["+ptr+"]: repeat");\r
2922                                                                                 repeatedLen = distLens[ptr-1];\r
2923                                                                                 repBits = 2;\r
2924                                                                                 for (int i = 3; i-- > 0; ) {\r
2925                                                                                         if (ptr >= dnum) {\r
2926                                                                                                 throw new Exception();\r
2927                                                                                         }\r
2928                                                                                         distLens[ptr++] = repeatedLen;\r
2929                                                                                 }\r
2930                                                                                 mode = DREPS;\r
2931                                                                                 goto decode_loop;\r
2932                                                                         case 17: /* repeat zero 3-10 times */\r
2933                                                                                 //                  System.err.println("distLens["+ptr+"]: repeat zero");\r
2934                                                                                 repeatedLen = 0;\r
2935                                                                                 repBits = 3;\r
2936                                                                                 for (int i = 3; i-- > 0; ) {\r
2937                                                                                         if (ptr >= dnum) {\r
2938                                                                                                 throw new Exception();\r
2939                                                                                         }\r
2940                                                                                         distLens[ptr++] = repeatedLen;\r
2941                                                                                 }\r
2942                                                                                 mode = DREPS;\r
2943                                                                                 goto decode_loop;\r
2944                                                                         case 18: /* repeat zero 11-138 times */\r
2945                                                                                 //                  System.err.println("distLens["+ptr+"]: repeat zero");\r
2946                                                                                 repeatedLen = 0;\r
2947                                                                                 repBits = 7;\r
2948                                                                                 for (int i = 11; i-- > 0; ) {\r
2949                                                                                         if (ptr >= dnum) {\r
2950                                                                                                 throw new Exception();\r
2951                                                                                         }\r
2952                                                                                         distLens[ptr++] = repeatedLen;\r
2953                                                                                 }\r
2954                                                                                 mode = DREPS;\r
2955                                                                                 goto decode_loop;\r
2956                                                                 }\r
2957                                                         }\r
2958                                                         mode = FINISH;\r
2959                                                 return true;\r
2960                                         case LREPS:\r
2961                                                 {\r
2962                                                         int count = input.PeekBits(repBits);\r
2963                                                         if (count < 0) {\r
2964                                                                 return false;\r
2965                                                         }\r
2966                                                         input.DropBits(repBits);\r
2967                                                         //            System.err.println("litlenLens repeat: "+repBits);\r
2968                                                         while (count-- > 0) {\r
2969                                                                 if (ptr >= lnum) {\r
2970                                                                         throw new Exception();\r
2971                                                                 }\r
2972                                                                 litlenLens[ptr++] = repeatedLen;\r
2973                                                         }\r
2974                                                 }\r
2975                                                 mode = LLENS;\r
2976                                                 goto decode_loop;\r
2977                                         case DREPS:\r
2978                                                 {\r
2979                                                         int count = input.PeekBits(repBits);\r
2980                                                         if (count < 0) {\r
2981                                                                 return false;\r
2982                                                         }\r
2983                                                         input.DropBits(repBits);\r
2984                                                         while (count-- > 0) {\r
2985                                                                 if (ptr >= dnum) {\r
2986                                                                         throw new Exception();\r
2987                                                                 }\r
2988                                                                 distLens[ptr++] = repeatedLen;\r
2989                                                         }\r
2990                                                 }\r
2991                                                 mode = DLENS;\r
2992                                                 goto decode_loop;\r
2993                                 }\r
2994                         }\r
2995                 }\r
2996                 \r
2997                 public InflaterHuffmanTree BuildLitLenTree()\r
2998                 {\r
2999                         return new InflaterHuffmanTree(litlenLens);\r
3000                 }\r
3001                 \r
3002                 public InflaterHuffmanTree BuildDistTree()\r
3003                 {\r
3004                         return new InflaterHuffmanTree(distLens);\r
3005                 }\r
3006         }\r
3007 }\r
3008 \r
3009 namespace NZlib.Compression {\r
3010         \r
3011         public class InflaterHuffmanTree \r
3012         {\r
3013                 private static int MAX_BITLEN = 15;\r
3014                 private short[] tree;\r
3015                 \r
3016                 public static InflaterHuffmanTree defLitLenTree, defDistTree;\r
3017                 \r
3018                 static InflaterHuffmanTree()\r
3019                 {\r
3020                         try {\r
3021                                 byte[] codeLengths = new byte[288];\r
3022                                 int i = 0;\r
3023                                 while (i < 144) {\r
3024                                         codeLengths[i++] = 8;\r
3025                                 }\r
3026                                 while (i < 256) {\r
3027                                         codeLengths[i++] = 9;\r
3028                                 }\r
3029                                 while (i < 280) {\r
3030                                         codeLengths[i++] = 7;\r
3031                                 }\r
3032                                 while (i < 288) {\r
3033                                         codeLengths[i++] = 8;\r
3034                                 }\r
3035                                 defLitLenTree = new InflaterHuffmanTree(codeLengths);\r
3036                                 \r
3037                                 codeLengths = new byte[32];\r
3038                                 i = 0;\r
3039                                 while (i < 32) {\r
3040                                         codeLengths[i++] = 5;\r
3041                                 }\r
3042                                 defDistTree = new InflaterHuffmanTree(codeLengths);\r
3043                         } catch (Exception) {\r
3044                                 throw new ApplicationException("InflaterHuffmanTree: static tree length illegal");\r
3045                         }\r
3046                 }\r
3047                 \r
3048                 /// <summary>\r
3049                 /// Constructs a Huffman tree from the array of code lengths.\r
3050                 /// </summary>\r
3051                 /// <param name = "codeLengths">\r
3052                 /// the array of code lengths\r
3053                 /// </param>\r
3054                 public InflaterHuffmanTree(byte[] codeLengths)\r
3055                 {\r
3056                         BuildTree(codeLengths);\r
3057                 }\r
3058                 \r
3059                 private void BuildTree(byte[] codeLengths)\r
3060                 {\r
3061                         int[] blCount  = new int[MAX_BITLEN + 1];\r
3062                         int[] nextCode = new int[MAX_BITLEN + 1];\r
3063                         \r
3064                         for (int i = 0; i < codeLengths.Length; i++) {\r
3065                                 int bits = codeLengths[i];\r
3066                                 if (bits > 0)\r
3067                                         blCount[bits]++;\r
3068                         }\r
3069                         \r
3070                         int code = 0;\r
3071                         int treeSize = 512;\r
3072                         for (int bits = 1; bits <= MAX_BITLEN; bits++) {\r
3073                                 nextCode[bits] = code;\r
3074                                 code += blCount[bits] << (16 - bits);\r
3075                                 if (bits >= 10) {\r
3076                                         /* We need an extra table for bit lengths >= 10. */\r
3077                                         int start = nextCode[bits] & 0x1ff80;\r
3078                                         int end   = code & 0x1ff80;\r
3079                                         treeSize += (end - start) >> (16 - bits);\r
3080                                 }\r
3081                         }\r
3082                         if (code != 65536) {\r
3083                                 throw new Exception("Code lengths don't add up properly.");\r
3084                         }\r
3085                         /* Now create and fill the extra tables from longest to shortest\r
3086                         * bit len.  This way the sub trees will be aligned.\r
3087                         */\r
3088                         tree = new short[treeSize];\r
3089                         int treePtr = 512;\r
3090                         for (int bits = MAX_BITLEN; bits >= 10; bits--) {\r
3091                                 int end   = code & 0x1ff80;\r
3092                                 code -= blCount[bits] << (16 - bits);\r
3093                                 int start = code & 0x1ff80;\r
3094                                 for (int i = start; i < end; i += 1 << 7) {\r
3095                                         tree[DeflaterHuffman.BitReverse(i)] = (short) ((-treePtr << 4) | bits);\r
3096                                         treePtr += 1 << (bits-9);\r
3097                                 }\r
3098                         }\r
3099                         \r
3100                         for (int i = 0; i < codeLengths.Length; i++) {\r
3101                                 int bits = codeLengths[i];\r
3102                                 if (bits == 0) {\r
3103                                         continue;\r
3104                                 }\r
3105                                 code = nextCode[bits];\r
3106                                 int revcode = DeflaterHuffman.BitReverse(code);\r
3107                                 if (bits <= 9) {\r
3108                                         do {\r
3109                                                 tree[revcode] = (short) ((i << 4) | bits);\r
3110                                                 revcode += 1 << bits;\r
3111                                         } while (revcode < 512);\r
3112                                 } else {\r
3113                                         int subTree = tree[revcode & 511];\r
3114                                         int treeLen = 1 << (subTree & 15);\r
3115                                         subTree = -(subTree >> 4);\r
3116                                         do {\r
3117                                                 tree[subTree | (revcode >> 9)] = (short) ((i << 4) | bits);\r
3118                                                 revcode += 1 << bits;\r
3119                                         } while (revcode < treeLen);\r
3120                                 }\r
3121                                 nextCode[bits] = code + (1 << (16 - bits));\r
3122                         }\r
3123                         \r
3124                 }\r
3125                 \r
3126                 /// <summary>\r
3127                 /// Reads the next symbol from input.  The symbol is encoded using the\r
3128                 /// huffman tree.\r
3129                 /// </summary>\r
3130                 /// <param name="input">\r
3131                 /// input the input source.\r
3132                 /// </param>\r
3133                 /// <returns>\r
3134                 /// the next symbol, or -1 if not enough input is available.\r
3135                 /// </returns>\r
3136                 public int GetSymbol(StreamManipulator input)\r
3137                 {\r
3138                         int lookahead, symbol;\r
3139                         if ((lookahead = input.PeekBits(9)) >= 0) {\r
3140                                 if ((symbol = tree[lookahead]) >= 0) {\r
3141                                         input.DropBits(symbol & 15);\r
3142                                         return symbol >> 4;\r
3143                                 }\r
3144                                 int subtree = -(symbol >> 4);\r
3145                                 int bitlen = symbol & 15;\r
3146                                 if ((lookahead = input.PeekBits(bitlen)) >= 0) {\r
3147                                         symbol = tree[subtree | (lookahead >> 9)];\r
3148                                         input.DropBits(symbol & 15);\r
3149                                         return symbol >> 4;\r
3150                                 } else {\r
3151                                         int bits = input.AvailableBits;\r
3152                                         lookahead = input.PeekBits(bits);\r
3153                                         symbol = tree[subtree | (lookahead >> 9)];\r
3154                                         if ((symbol & 15) <= bits) {\r
3155                                                 input.DropBits(symbol & 15);\r
3156                                                 return symbol >> 4;\r
3157                                         } else {\r
3158                                                 return -1;\r
3159                                         }\r
3160                                 }\r
3161                         } else {\r
3162                                 int bits = input.AvailableBits;\r
3163                                 lookahead = input.PeekBits(bits);\r
3164                                 symbol = tree[lookahead];\r
3165                                 if (symbol >= 0 && (symbol & 15) <= bits) {\r
3166                                         input.DropBits(symbol & 15);\r
3167                                         return symbol >> 4;\r
3168                                 } else {\r
3169                                         return -1;\r
3170                                 }\r
3171                         }\r
3172                 }\r
3173         }\r
3174 }\r
3175 \r
3176 namespace NZlib.Compression {\r
3177         \r
3178         /// <summary>\r
3179         /// This class is general purpose class for writing data to a buffer.\r
3180         /// \r
3181         /// It allows you to write bits as well as bytes\r
3182         /// Based on DeflaterPending.java\r
3183         /// \r
3184         /// author of the original java version : Jochen Hoenicke\r
3185         /// </summary>\r
3186         public class PendingBuffer\r
3187         {\r
3188                 protected byte[] buf;\r
3189                 int    start;\r
3190                 int    end;\r
3191                 \r
3192                 uint    bits;\r
3193                 int    bitCount;\r
3194                 \r
3195                 public PendingBuffer() : this( 4096 )\r
3196                 {\r
3197                         \r
3198                 }\r
3199                 \r
3200                 public PendingBuffer(int bufsize)\r
3201                 {\r
3202                         buf = new byte[bufsize];\r
3203                 }\r
3204                 \r
3205                 public void Reset() \r
3206                 {\r
3207                         start = end = bitCount = 0;\r
3208                 }\r
3209                 \r
3210                 public void WriteByte(int b)\r
3211                 {\r
3212                         if (DeflaterConstants.DEBUGGING && start != 0)\r
3213                                 throw new Exception();\r
3214                         buf[end++] = (byte) b;\r
3215                 }\r
3216                 \r
3217                 public void WriteShort(int s)\r
3218                 {\r
3219                         if (DeflaterConstants.DEBUGGING && start != 0) {\r
3220                                 throw new Exception();\r
3221                         }\r
3222                         buf[end++] = (byte) s;\r
3223                         buf[end++] = (byte) (s >> 8);\r
3224                 }\r
3225                 \r
3226                 public void WriteInt(int s)\r
3227                 {\r
3228                         if (DeflaterConstants.DEBUGGING && start != 0) {\r
3229                                 throw new Exception();\r
3230                         }\r
3231                         buf[end++] = (byte) s;\r
3232                         buf[end++] = (byte) (s >> 8);\r
3233                         buf[end++] = (byte) (s >> 16);\r
3234                         buf[end++] = (byte) (s >> 24);\r
3235                 }\r
3236                 \r
3237                 public void WriteBlock(byte[] block, int offset, int len)\r
3238                 {\r
3239                         if (DeflaterConstants.DEBUGGING && start != 0) {\r
3240                                 throw new Exception();\r
3241                         }\r
3242                         System.Array.Copy(block, offset, buf, end, len);\r
3243                         end += len;\r
3244                 }\r
3245                 \r
3246                 public int BitCount {\r
3247                         get {\r
3248                                 return bitCount;\r
3249                         }\r
3250                 }\r
3251                 \r
3252                 public void AlignToByte() \r
3253                 {\r
3254                         if (DeflaterConstants.DEBUGGING && start != 0) {\r
3255                                 throw new Exception();\r
3256                         }\r
3257                         if (bitCount > 0) {\r
3258                                 buf[end++] = (byte) bits;\r
3259                                 if (bitCount > 8) {\r
3260                                         buf[end++] = (byte) (bits >> 8);\r
3261                                 }\r
3262                         }\r
3263                         bits = 0;\r
3264                         bitCount = 0;\r
3265                 }\r
3266                 \r
3267                 public void WriteBits(int b, int count)\r
3268                 {\r
3269                         if (DeflaterConstants.DEBUGGING && start != 0) {\r
3270                                 throw new Exception();\r
3271                         }\r
3272 //                      if (DeflaterConstants.DEBUGGING) {\r
3273 //                              Console.WriteLine("writeBits("+b+","+count+")");\r
3274 //                      }\r
3275                         bits |= (uint)(b << bitCount);\r
3276                         bitCount += count;\r
3277                         if (bitCount >= 16) {\r
3278                                 buf[end++] = (byte) bits;\r
3279                                 buf[end++] = (byte) (bits >> 8);\r
3280                                 bits >>= 16;\r
3281                                 bitCount -= 16;\r
3282                         }\r
3283                 }\r
3284                 \r
3285                 public void WriteShortMSB(int s) \r
3286                 {\r
3287                         if (DeflaterConstants.DEBUGGING && start != 0) {\r
3288                                 throw new Exception();\r
3289                         }\r
3290                         buf[end++] = (byte) (s >> 8);\r
3291                         buf[end++] = (byte) s;\r
3292                 }\r
3293                 \r
3294                 public bool IsFlushed {\r
3295                         get {\r
3296                                 return end == 0;\r
3297                         }\r
3298                 }\r
3299                 \r
3300                 /// <summary>\r
3301                 /// Flushes the pending buffer into the given output array.  If the\r
3302                 /// output array is to small, only a partial flush is done.\r
3303                 /// </summary>\r
3304                 /// <param name="output">\r
3305                 /// the output array;\r
3306                 /// </param>\r
3307                 /// <param name="offset">\r
3308                 /// the offset into output array;\r
3309                 /// </param>\r
3310                 /// <param name="length">               \r
3311                 /// length the maximum number of bytes to store;\r
3312                 /// </param>\r
3313                 /// <exception name="ArgumentOutOfRangeException">\r
3314                 /// IndexOutOfBoundsException if offset or length are invalid.\r
3315                 /// </exception>\r
3316                 public int Flush(byte[] output, int offset, int length) \r
3317                 {\r
3318                         if (bitCount >= 8) {\r
3319                                 buf[end++] = (byte) bits;\r
3320                                 bits >>= 8;\r
3321                                 bitCount -= 8;\r
3322                         }\r
3323                         if (length > end - start) {\r
3324                                 length = end - start;\r
3325                                 System.Array.Copy(buf, start, output, offset, length);\r
3326                                 start = 0;\r
3327                                 end = 0;\r
3328                         } else {\r
3329                                 System.Array.Copy(buf, start, output, offset, length);\r
3330                                 start += length;\r
3331                         }\r
3332                         return length;\r
3333                 }\r
3334                 \r
3335                 public byte[] ToByteArray()\r
3336                 {\r
3337                         byte[] ret = new byte[ end - start ];\r
3338                         System.Array.Copy(buf, start, ret, 0, ret.Length);\r
3339                         start = 0;\r
3340                         end = 0;\r
3341                         return ret;\r
3342                 }\r
3343         }\r
3344 }       \r
3345 \r
3346 namespace NZlib.Checksums {\r
3347         \r
3348         /// <summary>\r
3349         /// Computes Adler32 checksum for a stream of data. An Adler32\r
3350         /// checksum is not as reliable as a CRC32 checksum, but a lot faster to\r
3351         /// compute.\r
3352         /// \r
3353         /// The specification for Adler32 may be found in RFC 1950.\r
3354         /// ZLIB Compressed Data Format Specification version 3.3)\r
3355         /// \r
3356         /// \r
3357         /// From that document:\r
3358         /// \r
3359         ///      "ADLER32 (Adler-32 checksum)\r
3360         ///       This contains a checksum value of the uncompressed data\r
3361         ///       (excluding any dictionary data) computed according to Adler-32\r
3362         ///       algorithm. This algorithm is a 32-bit extension and improvement\r
3363         ///       of the Fletcher algorithm, used in the ITU-T X.224 / ISO 8073\r
3364         ///       standard.\r
3365         /// \r
3366         ///       Adler-32 is composed of two sums accumulated per byte: s1 is\r
3367         ///       the sum of all bytes, s2 is the sum of all s1 values. Both sums\r
3368         ///       are done modulo 65521. s1 is initialized to 1, s2 to zero.  The\r
3369         ///       Adler-32 checksum is stored as s2*65536 + s1 in most-\r
3370         ///       significant-byte first (network) order."\r
3371         /// \r
3372         ///  "8.2. The Adler-32 algorithm\r
3373         /// \r
3374         ///    The Adler-32 algorithm is much faster than the CRC32 algorithm yet\r
3375         ///    still provides an extremely low probability of undetected errors.\r
3376         /// \r
3377         ///    The modulo on unsigned long accumulators can be delayed for 5552\r
3378         ///    bytes, so the modulo operation time is negligible.  If the bytes\r
3379         ///    are a, b, c, the second sum is 3a + 2b + c + 3, and so is position\r
3380         ///    and order sensitive, unlike the first sum, which is just a\r
3381         ///    checksum.  That 65521 is prime is important to avoid a possible\r
3382         ///    large class of two-byte errors that leave the check unchanged.\r
3383         ///    (The Fletcher checksum uses 255, which is not prime and which also\r
3384         ///    makes the Fletcher check insensitive to single byte changes 0 -\r
3385         ///    255.)\r
3386         /// \r
3387         ///    The sum s1 is initialized to 1 instead of zero to make the length\r
3388         ///    of the sequence part of s2, so that the length does not have to be\r
3389         ///    checked separately. (Any sequence of zeroes has a Fletcher\r
3390         ///    checksum of zero.)"\r
3391         /// </summary>\r
3392         /// <see cref="NZlib.Streams.InflaterInputStream"/>\r
3393         /// <see cref="NZlib.Streams.DeflaterOutputStream"/>\r
3394         public sealed class Adler32 : IChecksum\r
3395         {\r
3396                 /// <summary>\r
3397                 /// largest prime smaller than 65536\r
3398                 /// </summary>\r
3399                 readonly static uint BASE = 65521;\r
3400                 \r
3401                 uint checksum;\r
3402                 \r
3403                 /// <summary>\r
3404                 /// Returns the Adler32 data checksum computed so far.\r
3405                 /// </summary>\r
3406                 public long Value {\r
3407                         get {\r
3408                                 return (long) checksum & 0xFFFFFFFFL;\r
3409                         }\r
3410                 }\r
3411                 \r
3412                 /// <summary>\r
3413                 /// Creates a new instance of the <code>Adler32</code> class.\r
3414                 /// The checksum starts off with a value of 1.\r
3415                 /// </summary>\r
3416                 public Adler32()\r
3417                 {\r
3418                         Reset();\r
3419                 }\r
3420                 \r
3421                 /// <summary>\r
3422                 /// Resets the Adler32 checksum to the initial value.\r
3423                 /// </summary>\r
3424                 public void Reset()\r
3425                 {\r
3426                         checksum = 1; //Initialize to 1\r
3427                 }\r
3428                 \r
3429                 /// <summary>\r
3430                 /// Updates the checksum with the byte b.\r
3431                 /// </summary>\r
3432                 /// <param name="bval">\r
3433                 /// the data value to add. The high byte of the int is ignored.\r
3434                 /// </param>\r
3435                 public void Update(int bval)\r
3436                 {\r
3437                         //We could make a length 1 byte array and call update again, but I\r
3438                         //would rather not have that overhead\r
3439                         uint s1 = checksum & 0xFFFF;\r
3440                         uint s2 = checksum >> 16;\r
3441                         \r
3442                         s1 = (s1 + ((uint)bval & 0xFF)) % BASE;\r
3443                         s2 = (s1 + s2) % BASE;\r
3444                         \r
3445                         checksum = (s2 << 16) + s1;\r
3446                 }\r
3447                 \r
3448                 /// <summary>\r
3449                 /// Updates the checksum with the bytes taken from the array.\r
3450                 /// </summary>\r
3451                 /// <param name="buffer">\r
3452                 /// buffer an array of bytes\r
3453                 /// </param>\r
3454                 public void Update(byte[] buffer)\r
3455                 {\r
3456                         Update(buffer, 0, buffer.Length);\r
3457                 }\r
3458                 \r
3459                 /// <summary>\r
3460                 /// Updates the checksum with the bytes taken from the array.\r
3461                 /// </summary>\r
3462                 /// <param name="buf">\r
3463                 /// an array of bytes\r
3464                 /// </param>\r
3465                 /// <param name="off">\r
3466                 /// the start of the data used for this update\r
3467                 /// </param>\r
3468                 /// <param name="len">\r
3469                 /// the number of bytes to use for this update\r
3470                 /// </param>\r
3471                 public void Update(byte[] buf, int off, int len)\r
3472                 {\r
3473                         if (buf == null) {\r
3474                                 throw new ArgumentNullException("buf");\r
3475                         }\r
3476                         \r
3477                         if (off < 0 || len < 0 || off + len > buf.Length) {\r
3478                                 throw new ArgumentOutOfRangeException();\r
3479                         }\r
3480                         \r
3481                         //(By Per Bothner)\r
3482                         uint s1 = checksum & 0xFFFF;\r
3483                         uint s2 = checksum >> 16;\r
3484                         \r
3485                         while (len > 0) {\r
3486                                 // We can defer the modulo operation:\r
3487                                 // s1 maximally grows from 65521 to 65521 + 255 * 3800\r
3488                                 // s2 maximally grows by 3800 * median(s1) = 2090079800 < 2^31\r
3489                                 int n = 3800;\r
3490                                 if (n > len) {\r
3491                                         n = len;\r
3492                                 }\r
3493                                 len -= n;\r
3494                                 while (--n >= 0) {\r
3495                                         s1 = s1 + (uint)(buf[off++] & 0xFF);\r
3496                                         s2 = s2 + s1;\r
3497                                 }\r
3498                                 s1 %= BASE;\r
3499                                 s2 %= BASE;\r
3500                         }\r
3501                         \r
3502                         checksum = (s2 << 16) | s1;\r
3503                 }\r
3504         }\r
3505 }\r
3506 \r
3507 namespace NZlib.Checksums {\r
3508         \r
3509         /// <summary>\r
3510         /// Generate a table for a byte-wise 32-bit CRC calculation on the polynomial:\r
3511         /// x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1.\r
3512         ///\r
3513         /// Polynomials over GF(2) are represented in binary, one bit per coefficient,\r
3514         /// with the lowest powers in the most significant bit.  Then adding polynomials\r
3515         /// is just exclusive-or, and multiplying a polynomial by x is a right shift by\r
3516         /// one.  If we call the above polynomial p, and represent a byte as the\r
3517         /// polynomial q, also with the lowest power in the most significant bit (so the\r
3518         /// byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p,\r
3519         /// where a mod b means the remainder after dividing a by b.\r
3520         ///\r
3521         /// This calculation is done using the shift-register method of multiplying and\r
3522         /// taking the remainder.  The register is initialized to zero, and for each\r
3523         /// incoming bit, x^32 is added mod p to the register if the bit is a one (where\r
3524         /// x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by\r
3525         /// x (which is shifting right by one and adding x^32 mod p if the bit shifted\r
3526         /// out is a one).  We start with the highest power (least significant bit) of\r
3527         /// q and repeat for all eight bits of q.\r
3528         ///\r
3529         /// The table is simply the CRC of all possible eight bit values.  This is all\r
3530         /// the information needed to generate CRC's on data a byte at a time for all\r
3531         /// combinations of CRC register values and incoming bytes.\r
3532         /// </summary>\r
3533         public sealed class Crc32 : IChecksum\r
3534         {\r
3535                 readonly static uint CrcSeed = 0xFFFFFFFF;\r
3536                 \r
3537                 readonly static uint[] CrcTable = new uint[] {\r
3538                         0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419,\r
3539                         0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4,\r
3540                         0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07,\r
3541                         0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,\r
3542                         0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856,\r
3543                         0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,\r
3544                         0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4,\r
3545                         0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,\r
3546                         0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3,\r
3547                         0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A,\r
3548                         0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599,\r
3549                         0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,\r
3550                         0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190,\r
3551                         0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F,\r
3552                         0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E,\r
3553                         0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,\r
3554                         0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED,\r
3555                         0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,\r
3556                         0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3,\r
3557                         0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,\r
3558                         0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A,\r
3559                         0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5,\r
3560                         0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010,\r
3561                         0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,\r
3562                         0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17,\r
3563                         0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6,\r
3564                         0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615,\r
3565                         0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,\r
3566                         0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344, \r
3567                         0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,\r
3568                         0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A,\r
3569                         0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,\r
3570                         0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1,\r
3571                         0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C,\r
3572                         0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF,\r
3573                         0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,\r
3574                         0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE,\r
3575                         0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31,\r
3576                         0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C,\r
3577                         0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,\r
3578                         0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B,\r
3579                         0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,\r
3580                         0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1,\r
3581                         0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,\r
3582                         0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278,\r
3583                         0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7,\r
3584                         0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66,\r
3585                         0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,\r
3586                         0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605,\r
3587                         0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8,\r
3588                         0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, \r
3589                         0x2D02EF8D\r
3590                 };\r
3591                 \r
3592                 /// <summary>\r
3593                 /// The crc data checksum so far.\r
3594                 /// </summary>\r
3595                 uint crc = 0;\r
3596                 \r
3597                 /// <summary>\r
3598                 /// Returns the CRC32 data checksum computed so far.\r
3599                 /// </summary>\r
3600                 public long Value {\r
3601                         get {\r
3602                                 return (long)crc;\r
3603                         }\r
3604                 }\r
3605                 \r
3606                 /// <summary>\r
3607                 /// Resets the CRC32 data checksum as if no update was ever called.\r
3608                 /// </summary>\r
3609                 public void Reset() \r
3610                 { \r
3611                         crc = 0; \r
3612                 }\r
3613                 \r
3614                 /// <summary>\r
3615                 /// Updates the checksum with the int bval.\r
3616                 /// </summary>\r
3617                 /// <param name = "bval">\r
3618                 /// the byte is taken as the lower 8 bits of bval\r
3619                 /// </param>\r
3620                 public void Update(int bval)\r
3621                 {\r
3622                         crc ^= CrcSeed;\r
3623                         crc  = CrcTable[(crc ^ bval) & 0xFF] ^ (crc >> 8);\r
3624                         crc ^= CrcSeed;\r
3625                 }\r
3626                 \r
3627                 /// <summary>\r
3628                 /// Updates the checksum with the bytes taken from the array.\r
3629                 /// </summary>\r
3630                 /// <param name="buffer">\r
3631                 /// buffer an array of bytes\r
3632                 /// </param>\r
3633                 public void Update(byte[] buffer)\r
3634                 {\r
3635                         Update(buffer, 0, buffer.Length);\r
3636                 }\r
3637                 \r
3638                 /// <summary>\r
3639                 /// Adds the byte array to the data checksum.\r
3640                 /// </summary>\r
3641                 /// <param name = "buf">\r
3642                 /// the buffer which contains the data\r
3643                 /// </param>\r
3644                 /// <param name = "off">\r
3645                 /// the offset in the buffer where the data starts\r
3646                 /// </param>\r
3647                 /// <param name = "len">\r
3648                 /// the length of the data\r
3649                 /// </param>\r
3650                 public void Update(byte[] buf, int off, int len)\r
3651                 {\r
3652                         if (buf == null) {\r
3653                                 throw new ArgumentNullException("buf");\r
3654                         }\r
3655                         \r
3656                         if (off < 0 || len < 0 || off + len > buf.Length) {\r
3657                                 throw new ArgumentOutOfRangeException();\r
3658                         }\r
3659                         \r
3660                         crc ^= CrcSeed;\r
3661                         \r
3662                         while (--len >= 0) {\r
3663                                 crc = CrcTable[(crc ^ buf[off++]) & 0xFF] ^ (crc >> 8);\r
3664                         }\r
3665                         \r
3666                         crc ^= CrcSeed;\r
3667                 }\r
3668         }\r
3669 }\r
3670 \r
3671 namespace NZlib.Checksums {\r
3672         \r
3673         /// <summary>\r
3674         /// Interface to compute a data checksum used by checked input/output streams.\r
3675         /// A data checksum can be updated by one byte or with a byte array. After each\r
3676         /// update the value of the current checksum can be returned by calling\r
3677         /// <code>getValue</code>. The complete checksum object can also be reset\r
3678         /// so it can be used again with new data.\r
3679         /// </summary>\r
3680         public interface IChecksum\r
3681         {\r
3682                 /// <summary>\r
3683                 /// Returns the data checksum computed so far.\r
3684                 /// </summary>\r
3685                 long Value {\r
3686                         get;\r
3687                 }\r
3688                 \r
3689                 /// <summary>\r
3690                 /// Resets the data checksum as if no update was ever called.\r
3691                 /// </summary>\r
3692                 void Reset();\r
3693                 \r
3694                 /// <summary>\r
3695                 /// Adds one byte to the data checksum.\r
3696                 /// </summary>\r
3697                 /// <param name = "bval">\r
3698                 /// the data value to add. The high byte of the int is ignored.\r
3699                 /// </param>\r
3700                 void Update(int bval);\r
3701                 \r
3702                 /// <summary>\r
3703                 /// Updates the data checksum with the bytes taken from the array.\r
3704                 /// </summary>\r
3705                 /// <param name="buffer">\r
3706                 /// buffer an array of bytes\r
3707                 /// </param>\r
3708                 void Update(byte[] buffer);\r
3709                 \r
3710                 /// <summary>\r
3711                 /// Adds the byte array to the data checksum.\r
3712                 /// </summary>\r
3713                 /// <param name = "buf">\r
3714                 /// the buffer which contains the data\r
3715                 /// </param>\r
3716                 /// <param name = "off">\r
3717                 /// the offset in the buffer where the data starts\r
3718                 /// </param>\r
3719                 /// <param name = "len">\r
3720                 /// the length of the data\r
3721                 /// </param>\r
3722                 void Update(byte[] buf, int off, int len);\r
3723         }\r
3724 }\r
3725 \r
3726 namespace NZlib.Streams {\r
3727         \r
3728         /// <summary>\r
3729         /// Contains the output from the Inflation process.\r
3730         /// We need to have a window so that we can refer backwards into the output stream\r
3731         /// to repeat stuff.\r
3732         ///\r
3733         /// author of the original java version : John Leuner\r
3734         /// </summary>\r
3735         public class OutputWindow\r
3736         {\r
3737                 private static int WINDOW_SIZE = 1 << 15;\r
3738                 private static int WINDOW_MASK = WINDOW_SIZE - 1;\r
3739                 \r
3740                 private byte[] window = new byte[WINDOW_SIZE]; //The window is 2^15 bytes\r
3741                 private int window_end  = 0;\r
3742                 private int window_filled = 0;\r
3743                 \r
3744                 public void Write(int abyte)\r
3745                 {\r
3746                         if (window_filled++ == WINDOW_SIZE) {\r
3747                                 throw new InvalidOperationException("Window full");\r
3748                         }\r
3749                         window[window_end++] = (byte) abyte;\r
3750                         window_end &= WINDOW_MASK;\r
3751                 }\r
3752                 \r
3753                 \r
3754                 private void SlowRepeat(int rep_start, int len, int dist)\r
3755                 {\r
3756                         while (len-- > 0) {\r
3757                                 window[window_end++] = window[rep_start++];\r
3758                                 window_end &= WINDOW_MASK;\r
3759                                 rep_start &= WINDOW_MASK;\r
3760                         }\r
3761                 }\r
3762                 \r
3763                 public void Repeat(int len, int dist)\r
3764                 {\r
3765                         if ((window_filled += len) > WINDOW_SIZE) {\r
3766                                 throw new InvalidOperationException("Window full");\r
3767                         }\r
3768                         \r
3769                         int rep_start = (window_end - dist) & WINDOW_MASK;\r
3770                         int border = WINDOW_SIZE - len;\r
3771                         if (rep_start <= border && window_end < border) {\r
3772                                 if (len <= dist) {\r
3773                                         System.Array.Copy(window, rep_start, window, window_end, len);\r
3774                                         window_end += len;\r
3775                                 }                               else {\r
3776                                         /* We have to copy manually, since the repeat pattern overlaps.\r
3777                                         */\r
3778                                         while (len-- > 0) {\r
3779                                                 window[window_end++] = window[rep_start++];\r
3780                                         }\r
3781                                 }\r
3782                         } else {\r
3783                                 SlowRepeat(rep_start, len, dist);\r
3784                         }\r
3785                 }\r
3786                 \r
3787                 public int CopyStored(StreamManipulator input, int len)\r
3788                 {\r
3789                         len = Math.Min(Math.Min(len, WINDOW_SIZE - window_filled), input.AvailableBytes);\r
3790                         int copied;\r
3791                         \r
3792                         int tailLen = WINDOW_SIZE - window_end;\r
3793                         if (len > tailLen) {\r
3794                                 copied = input.CopyBytes(window, window_end, tailLen);\r
3795                                 if (copied == tailLen) {\r
3796                                         copied += input.CopyBytes(window, 0, len - tailLen);\r
3797                                 }\r
3798                         } else {\r
3799                                 copied = input.CopyBytes(window, window_end, len);\r
3800                         }\r
3801                         \r
3802                         window_end = (window_end + copied) & WINDOW_MASK;\r
3803                         window_filled += copied;\r
3804                         return copied;\r
3805                 }\r
3806                 \r
3807                 public void CopyDict(byte[] dict, int offset, int len)\r
3808                 {\r
3809                         if (window_filled > 0) {\r
3810                                 throw new InvalidOperationException();\r
3811                         }\r
3812                         \r
3813                         if (len > WINDOW_SIZE) {\r
3814                                 offset += len - WINDOW_SIZE;\r
3815                                 len = WINDOW_SIZE;\r
3816                         }\r
3817                         System.Array.Copy(dict, offset, window, 0, len);\r
3818                         window_end = len & WINDOW_MASK;\r
3819                 }\r
3820                 \r
3821                 public int GetFreeSpace()\r
3822                 {\r
3823                         return WINDOW_SIZE - window_filled;\r
3824                 }\r
3825                 \r
3826                 public int GetAvailable()\r
3827                 {\r
3828                         return window_filled;\r
3829                 }\r
3830                 \r
3831                 public int CopyOutput(byte[] output, int offset, int len)\r
3832                 {\r
3833                         int copy_end = window_end;\r
3834                         if (len > window_filled) {\r
3835                                 len = window_filled;\r
3836                         } else {\r
3837                                 copy_end = (window_end - window_filled + len) & WINDOW_MASK;\r
3838                         }\r
3839                         \r
3840                         int copied = len;\r
3841                         int tailLen = len - copy_end;\r
3842                         \r
3843                         if (tailLen > 0) {\r
3844                                 System.Array.Copy(window, WINDOW_SIZE - tailLen,\r
3845                                                   output, offset, tailLen);\r
3846                                 offset += tailLen;\r
3847                                 len = copy_end;\r
3848                         }\r
3849                         System.Array.Copy(window, copy_end - len, output, offset, len);\r
3850                         window_filled -= copied;\r
3851                         if (window_filled < 0) {\r
3852                                 throw new InvalidOperationException();\r
3853                         }\r
3854                         return copied;\r
3855                 }\r
3856                 \r
3857                 public void Reset()\r
3858                 {\r
3859                         window_filled = window_end = 0;\r
3860                 }\r
3861         }\r
3862 }\r
3863 \r
3864 namespace NZlib.Streams {\r
3865         \r
3866         /// <summary>\r
3867         /// This class allows us to retrieve a specified amount of bits from\r
3868         /// the input buffer, as well as copy big byte blocks.\r
3869         ///\r
3870         /// It uses an int buffer to store up to 31 bits for direct\r
3871         /// manipulation.  This guarantees that we can get at least 16 bits,\r
3872         /// but we only need at most 15, so this is all safe.\r
3873         ///\r
3874         /// There are some optimizations in this class, for example, you must\r
3875         /// never peek more then 8 bits more than needed, and you must first\r
3876         /// peek bits before you may drop them.  This is not a general purpose\r
3877         /// class but optimized for the behaviour of the Inflater.\r
3878         ///\r
3879         /// authors of the original java version : John Leuner, Jochen Hoenicke\r
3880         /// </summary>\r
3881         public class StreamManipulator\r
3882         {\r
3883                 private byte[] window;\r
3884                 private int window_start = 0;\r
3885                 private int window_end = 0;\r
3886                 \r
3887                 private uint buffer = 0;\r
3888                 private int bits_in_buffer = 0;\r
3889                 \r
3890                 /// <summary>\r
3891                 /// Get the next n bits but don't increase input pointer.  n must be\r
3892                 /// less or equal 16 and if you if this call succeeds, you must drop\r
3893                 /// at least n-8 bits in the next call.\r
3894                 /// </summary>\r
3895                 /// <returns>\r
3896                 /// the value of the bits, or -1 if not enough bits available.  */\r
3897                 /// </returns>\r
3898                 public int PeekBits(int n)\r
3899                 {\r
3900                         if (bits_in_buffer < n) {\r
3901                                 if (window_start == window_end) {\r
3902                                         return -1;\r
3903                                 }\r
3904                                 buffer |= (uint)((window[window_start++] & 0xff |\r
3905                                                  (window[window_start++] & 0xff) << 8) << bits_in_buffer);\r
3906                                 bits_in_buffer += 16;\r
3907                         }\r
3908                         return (int)(buffer & ((1 << n) - 1));\r
3909                 }\r
3910                 \r
3911                 /// <summary>\r
3912                 /// Drops the next n bits from the input.  You should have called peekBits\r
3913                 /// with a bigger or equal n before, to make sure that enough bits are in\r
3914                 /// the bit buffer.\r
3915                 /// </summary>\r
3916                 public void DropBits(int n)\r
3917                 {\r
3918                         buffer >>= n;\r
3919                         bits_in_buffer -= n;\r
3920                 }\r
3921                 \r
3922                 /// <summary>\r
3923                 /// Gets the next n bits and increases input pointer.  This is equivalent\r
3924                 /// to peekBits followed by dropBits, except for correct error handling.\r
3925                 /// </summary>\r
3926                 /// <returns>\r
3927                 /// the value of the bits, or -1 if not enough bits available.\r
3928                 /// </returns>\r
3929                 public int GetBits(int n)\r
3930                 {\r
3931                         int bits = PeekBits(n);\r
3932                         if (bits >= 0) {\r
3933                                 DropBits(n);\r
3934                         }\r
3935                         return bits;\r
3936                 }\r
3937                 \r
3938                 /// <summary>\r
3939                 /// Gets the number of bits available in the bit buffer.  This must be\r
3940                 /// only called when a previous peekBits() returned -1.\r
3941                 /// </summary>\r
3942                 /// <returns>\r
3943                 /// the number of bits available.\r
3944                 /// </returns>\r
3945                 public int AvailableBits {\r
3946                         get {\r
3947                                 return bits_in_buffer;\r
3948                         }\r
3949                 }\r
3950                 \r
3951                 /// <summary>\r
3952                 /// Gets the number of bytes available.\r
3953                 /// </summary>\r
3954                 /// <returns>\r
3955                 /// the number of bytes available.\r
3956                 /// </returns>\r
3957                 public int AvailableBytes {\r
3958                         get {\r
3959                                 return window_end - window_start + (bits_in_buffer >> 3);\r
3960                         }\r
3961                 }\r
3962                 \r
3963                 /// <summary>\r
3964                 /// Skips to the next byte boundary.\r
3965                 /// </summary>\r
3966                 public void SkipToByteBoundary()\r
3967                 {\r
3968                         buffer >>= (bits_in_buffer & 7);\r
3969                         bits_in_buffer &= ~7;\r
3970                 }\r
3971                 \r
3972                 public bool IsNeedingInput {\r
3973                         get {\r
3974                                 return window_start == window_end;\r
3975                         }\r
3976                 }\r
3977                 \r
3978                 /// <summary>\r
3979                 /// Copies length bytes from input buffer to output buffer starting\r
3980                 /// at output[offset].  You have to make sure, that the buffer is\r
3981                 /// byte aligned.  If not enough bytes are available, copies fewer\r
3982                 /// bytes.\r
3983                 /// </summary>\r
3984                 /// <param name="output">\r
3985                 /// the buffer.\r
3986                 /// </param>\r
3987                 /// <param name="offset">\r
3988                 /// the offset in the buffer.\r
3989                 /// </param>\r
3990                 /// <param name="length">\r
3991                 /// the length to copy, 0 is allowed.\r
3992                 /// </param>\r
3993                 /// <returns>\r
3994                 /// the number of bytes copied, 0 if no byte is available.\r
3995                 /// </returns>\r
3996                 public int CopyBytes(byte[] output, int offset, int length)\r
3997                 {\r
3998                         if (length < 0) {\r
3999                                 throw new ArgumentOutOfRangeException("length negative");\r
4000                         }\r
4001                         if ((bits_in_buffer & 7) != 0)   {\r
4002                                 /* bits_in_buffer may only be 0 or 8 */\r
4003                                 throw new InvalidOperationException("Bit buffer is not aligned!");\r
4004                         }\r
4005                         \r
4006                         int count = 0;\r
4007                         while (bits_in_buffer > 0 && length > 0) {\r
4008                                 output[offset++] = (byte) buffer;\r
4009                                 buffer >>= 8;\r
4010                                 bits_in_buffer -= 8;\r
4011                                 length--;\r
4012                                 count++;\r
4013                         }\r
4014                         if (length == 0) {\r
4015                                 return count;\r
4016                         }\r
4017                         \r
4018                         int avail = window_end - window_start;\r
4019                         if (length > avail) {\r
4020                                 length = avail;\r
4021                         }\r
4022                         System.Array.Copy(window, window_start, output, offset, length);\r
4023                         window_start += length;\r
4024                         \r
4025                         if (((window_start - window_end) & 1) != 0) {\r
4026                                 /* We always want an even number of bytes in input, see peekBits */\r
4027                                 buffer = (uint)(window[window_start++] & 0xff);\r
4028                                 bits_in_buffer = 8;\r
4029                         }\r
4030                         return count + length;\r
4031                 }\r
4032                 \r
4033                 public StreamManipulator()\r
4034                 {\r
4035                 }\r
4036                 \r
4037                 public void Reset()\r
4038                 {\r
4039                         buffer = (uint)(window_start = window_end = bits_in_buffer = 0);\r
4040                 }\r
4041                 \r
4042                 public void SetInput(byte[] buf, int off, int len)\r
4043                 {\r
4044                         if (window_start < window_end) {\r
4045                                 throw new InvalidOperationException("Old input was not completely processed");\r
4046                         }\r
4047                         \r
4048                         int end = off + len;\r
4049                         \r
4050                         /* We want to throw an ArrayIndexOutOfBoundsException early.  The\r
4051                         * check is very tricky: it also handles integer wrap around.\r
4052                         */\r
4053                         if (0 > off || off > end || end > buf.Length) {\r
4054                                 throw new ArgumentOutOfRangeException();\r
4055                         }\r
4056                         \r
4057                         if ((len & 1) != 0) {\r
4058                                 /* We always want an even number of bytes in input, see peekBits */\r
4059                                 buffer |= (uint)((buf[off++] & 0xff) << bits_in_buffer);\r
4060                                 bits_in_buffer += 8;\r
4061                         }\r
4062                         \r
4063                         window = buf;\r
4064                         window_start = off;\r
4065                         window_end = end;\r
4066                 }\r
4067         }\r
4068 }\r