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