Statistics
| Branch: | Revision:

root / trunk / hammock / src / net35 / ICSharpCode.SharpZipLib.Silverlight / Zip / Compression / DeflaterEngine.cs @ 0eea575a

History | View | Annotate | Download (25.9 kB)

1
// DeflaterEngine.cs
2
//
3
// Copyright (C) 2001 Mike Krueger
4
// Copyright (C) 2004 John Reilly
5
//
6
// This file was translated from java, it was part of the GNU Classpath
7
// Copyright (C) 2001 Free Software Foundation, Inc.
8
//
9
// This program is free software; you can redistribute it and/or
10
// modify it under the terms of the GNU General Public License
11
// as published by the Free Software Foundation; either version 2
12
// of the License, or (at your option) any later version.
13
//
14
// This program is distributed in the hope that it will be useful,
15
// but WITHOUT ANY WARRANTY; without even the implied warranty of
16
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
// GNU General Public License for more details.
18
//
19
// You should have received a copy of the GNU General Public License
20
// along with this program; if not, write to the Free Software
21
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22
//
23
// Linking this library statically or dynamically with other modules is
24
// making a combined work based on this library.  Thus, the terms and
25
// conditions of the GNU General Public License cover the whole
26
// combination.
27
// 
28
// As a special exception, the copyright holders of this library give you
29
// permission to link this library with independent modules to produce an
30
// executable, regardless of the license terms of these independent
31
// modules, and to copy and distribute the resulting executable under
32
// terms of your choice, provided that you also meet, for each linked
33
// independent module, the terms and conditions of the license of that
34
// module.  An independent module is a module which is not derived from
35
// or based on this library.  If you modify this library, you may extend
36
// this exception to your version of the library, but you are not
37
// obligated to do so.  If you do not wish to do so, delete this
38
// exception statement from your version.
39

    
40
using System;
41
using ICSharpCode.SharpZipLib.Silverlight.Checksums;
42
using ICSharpCode.SharpZipLib.Silverlight.Zip.Compression;
43

    
44
namespace ICSharpCode.SharpZipLib.Silverlight.Zip.Compression
45
{
46
    /// <summary>
47
    /// Strategies for deflater
48
    /// </summary>
49
    public enum DeflateStrategy 
50
    {
51
        /// <summary>
52
        /// The default strategy
53
        /// </summary>
54
        Default  = 0,
55
		
56
        /// <summary>
57
        /// This strategy will only allow longer string repetitions.  It is
58
        /// useful for random data with a small character set.
59
        /// </summary>
60
        Filtered = 1,
61

    
62
			
63
        /// <summary>
64
        /// This strategy will not look for string repetitions at all.  It
65
        /// only encodes with Huffman trees (which means, that more common
66
        /// characters get a smaller encoding.
67
        /// </summary>
68
        HuffmanOnly = 2
69
    }
70

    
71
    /// <summary>
72
    /// Low level compression engine for deflate algorithm which uses a 32K sliding window
73
    /// with secondary compression from Huffman/Shannon-Fano codes.
74
    /// </summary>
75
    public class DeflaterEngine : DeflaterConstants 
76
    {
77
        #region Constants
78
        const int TooFar = 4096;
79
        #endregion
80
		
81
        #region Constructors
82
        /// <summary>
83
        /// Construct instance with pending buffer
84
        /// </summary>
85
        /// <param name="pending">
86
        /// Pending buffer to use
87
        /// </param>>
88
        public DeflaterEngine(DeflaterPending pending) 
89
        {
90
            this.pending = pending;
91
            huffman = new DeflaterHuffman(pending);
92
            adler = new Adler32();
93
			
94
            window = new byte[2 * WSIZE];
95
            head   = new short[HASH_SIZE];
96
            prev   = new short[WSIZE];
97
			
98
            // We start at index 1, to avoid an implementation deficiency, that
99
            // we cannot build a repeat pattern at index 0.
100
            blockStart = strstart = 1;
101
        }
102

    
103
        #endregion
104

    
105
        /// <summary>
106
        /// Deflate drives actual compression of data
107
        /// </summary>
108
        /// <param name="flush">True to flush input buffers</param>
109
        /// <param name="finish">Finish deflation with the current input.</param>
110
        /// <returns>Returns true if progress has been made.</returns>
111
        public bool Deflate(bool flush, bool finish)
112
        {
113
            bool progress;
114
            do 
115
            {
116
                FillWindow();
117
                var canFlush = flush && (inputOff == inputEnd);
118
                switch (compressionFunction) 
119
                {
120
                    case DEFLATE_STORED:
121
                        progress = DeflateStored(canFlush, finish);
122
                        break;
123
                    case DEFLATE_FAST:
124
                        progress = DeflateFast(canFlush, finish);
125
                        break;
126
                    case DEFLATE_SLOW:
127
                        progress = DeflateSlow(canFlush, finish);
128
                        break;
129
                    default:
130
                        throw new InvalidOperationException("unknown compressionFunction");
131
                }
132
            } while (pending.IsFlushed && progress); // repeat while we have no pending output and progress was made
133
            return progress;
134
        }
135

    
136
        /// <summary>
137
        /// Sets input data to be deflated.  Should only be called when <code>NeedsInput()</code>
138
        /// returns true
139
        /// </summary>
140
        /// <param name="buffer">The buffer containing input data.</param>
141
        /// <param name="offset">The offset of the first byte of data.</param>
142
        /// <param name="count">The number of bytes of data to use as input.</param>
143
        public void SetInput(byte[] buffer, int offset, int count)
144
        {
145
            if ( buffer == null ) 
146
            {
147
                throw new ArgumentNullException("buffer");
148
            }
149

    
150
            if ( offset < 0 ) 
151
            {
152
                throw new ArgumentOutOfRangeException("offset");
153
            }
154

    
155
            if ( count < 0 ) 
156
            {
157
                throw new ArgumentOutOfRangeException("count");
158
            }
159

    
160
            if (inputOff < inputEnd) 
161
            {
162
                throw new InvalidOperationException("Old input was not completely processed");
163
            }
164
			
165
            int end = offset + count;
166
			
167
            /* We want to throw an ArrayIndexOutOfBoundsException early.  The
168
			* check is very tricky: it also handles integer wrap around.
169
			*/
170
            if ((offset > end) || (end > buffer.Length) ) 
171
            {
172
                throw new ArgumentOutOfRangeException("count");
173
            }
174
			
175
            inputBuf = buffer;
176
            inputOff = offset;
177
            inputEnd = end;
178
        }
179

    
180
        /// <summary>
181
        /// Determines if more <see cref="SetInput">input</see> is needed.
182
        /// </summary>		
183
        /// <returns>Return true if input is needed via <see cref="SetInput">SetInput</see></returns>
184
        public bool NeedsInput()
185
        {
186
            return (inputEnd == inputOff);
187
        }
188

    
189
        /// <summary>
190
        /// Set compression dictionary
191
        /// </summary>
192
        /// <param name="buffer">The buffer containing the dictionary data</param>
193
        /// <param name="offset">The offset in the buffer for the first byte of data</param>
194
        /// <param name="length">The length of the dictionary data.</param>
195
        public void SetDictionary(byte[] buffer, int offset, int length) 
196
        {
197
            adler.Update(buffer, offset, length);
198
            if (length < MIN_MATCH) 
199
            {
200
                return;
201
            }
202

    
203
            if (length > MAX_DIST) 
204
            {
205
                offset += length - MAX_DIST;
206
                length = MAX_DIST;
207
            }
208
			
209
            Array.Copy(buffer, offset, window, strstart, length);
210
			
211
            UpdateHash();
212
            --length;
213
            while (--length > 0) 
214
            {
215
                InsertString();
216
                strstart++;
217
            }
218
            strstart += 2;
219
            blockStart = strstart;
220
        }
221
		
222
        /// <summary>
223
        /// Reset internal state
224
        /// </summary>		
225
        public void Reset()
226
        {
227
            huffman.Reset();
228
            adler.Reset();
229
            blockStart = strstart = 1;
230
            lookahead = 0;
231
            totalIn   = 0;
232
            prevAvailable = false;
233
            matchLen = MIN_MATCH - 1;
234
			
235
            for (int i = 0; i < HASH_SIZE; i++) {
236
                head[i] = 0;
237
            }
238
			
239
            for (int i = 0; i < WSIZE; i++) {
240
                prev[i] = 0;
241
            }
242
        }
243

    
244
        /// <summary>
245
        /// Reset Adler checksum
246
        /// </summary>		
247
        public void ResetAdler()
248
        {
249
            adler.Reset();
250
        }
251

    
252
        /// <summary>
253
        /// Get current value of Adler checksum
254
        /// </summary>		
255
        public int Adler {
256
            get {
257
                return unchecked((int)adler.Value);
258
            }
259
        }
260

    
261
        /// <summary>
262
        /// Total data processed
263
        /// </summary>		
264
        public int TotalIn {
265
            get {
266
                return totalIn;
267
            }
268
        }
269

    
270
        /// <summary>
271
        /// Get/set the <see cref="DeflateStrategy">deflate strategy</see>
272
        /// </summary>		
273
        public DeflateStrategy Strategy {
274
            get {
275
                return strategy;
276
            }
277
            set {
278
                strategy = value;
279
            }
280
        }
281
		
282
        /// <summary>
283
        /// Set the deflate level (0-9)
284
        /// </summary>
285
        /// <param name="level">The value to set the level to.</param>
286
        public void SetLevel(int level)
287
        {
288
            if ( (level < 0) || (level > 9) )
289
            {
290
                throw new ArgumentOutOfRangeException("level");
291
            }
292

    
293
            goodLength = GOOD_LENGTH[level];
294
            max_lazy   = MAX_LAZY[level];
295
            niceLength = NICE_LENGTH[level];
296
            max_chain  = MAX_CHAIN[level];
297

    
298
            if (COMPR_FUNC[level] == compressionFunction)
299
            {
300
                return;
301
            }
302

    
303
            switch (compressionFunction) {
304
                case DEFLATE_STORED:
305
                    if (strstart > blockStart) {
306
                        huffman.FlushStoredBlock(window, blockStart,
307
                                                 strstart - blockStart, false);
308
                        blockStart = strstart;
309
                    }
310
                    UpdateHash();
311
                    break;
312

    
313
                case DEFLATE_FAST:
314
                    if (strstart > blockStart) {
315
                        huffman.FlushBlock(window, blockStart, strstart - blockStart,
316
                                           false);
317
                        blockStart = strstart;
318
                    }
319
                    break;
320

    
321
                case DEFLATE_SLOW:
322
                    if (prevAvailable) {
323
                        huffman.TallyLit(window[strstart-1] & 0xff);
324
                    }
325
                    if (strstart > blockStart) {
326
                        huffman.FlushBlock(window, blockStart, strstart - blockStart, false);
327
                        blockStart = strstart;
328
                    }
329
                    prevAvailable = false;
330
                    matchLen = MIN_MATCH - 1;
331
                    break;
332
            }
333
            compressionFunction = COMPR_FUNC[level];
334
        }
335
		
336
        /// <summary>
337
        /// Fill the window
338
        /// </summary>
339
        public void FillWindow()
340
        {
341
            /* If the window is almost full and there is insufficient lookahead,
342
			 * move the upper half to the lower one to make room in the upper half.
343
			 */
344
            if (strstart >= WSIZE + MAX_DIST) 
345
            {
346
                SlideWindow();
347
            }
348
			
349
            /* If there is not enough lookahead, but still some input left,
350
			 * read in the input
351
			 */
352
            while (lookahead < MIN_LOOKAHEAD && inputOff < inputEnd) 
353
            {
354
                int more = 2 * WSIZE - lookahead - strstart;
355
				
356
                if (more > inputEnd - inputOff) 
357
                {
358
                    more = inputEnd - inputOff;
359
                }
360
				
361
                Array.Copy(inputBuf, inputOff, window, strstart + lookahead, more);
362
                adler.Update(inputBuf, inputOff, more);
363
				
364
                inputOff += more;
365
                totalIn += more;
366
                lookahead += more;
367
            }
368
			
369
            if (lookahead >= MIN_MATCH) 
370
            {
371
                UpdateHash();
372
            }
373
        }
374
		
375
        void UpdateHash() 
376
        {
377
/*
378
			if (DEBUGGING) {
379
				Console.WriteLine("updateHash: "+strstart);
380
			}
381
*/
382
            ins_h = (window[strstart] << HASH_SHIFT) ^ window[strstart + 1];
383
        }
384
		
385
        /// <summary>
386
        /// Inserts the current string in the head hash and returns the previous
387
        /// value for this hash.
388
        /// </summary>
389
        /// <returns>The previous hash value</returns>
390
        int InsertString() 
391
        {
392
            short match;
393
            var hash = ((ins_h << HASH_SHIFT) ^ window[strstart + (MIN_MATCH -1)]) & HASH_MASK;
394
            prev[strstart & WMASK] = match = head[hash];
395
            head[hash] = unchecked((short)strstart);
396
            ins_h = hash;
397
            return match & 0xffff;
398
        }
399
		
400
        void SlideWindow()
401
        {
402
            Array.Copy(window, WSIZE, window, 0, WSIZE);
403
            matchStart -= WSIZE;
404
            strstart   -= WSIZE;
405
            blockStart -= WSIZE;
406
			
407
            // Slide the hash table (could be avoided with 32 bit values
408
            // at the expense of memory usage).
409
            for (int i = 0; i < HASH_SIZE; ++i) {
410
                int m = head[i] & 0xffff;
411
                head[i] = (short)(m >= WSIZE ? (m - WSIZE) : 0);
412
            }
413
			
414
            // Slide the prev table.
415
            for (int i = 0; i < WSIZE; i++) {
416
                int m = prev[i] & 0xffff;
417
                prev[i] = (short)(m >= WSIZE ? (m - WSIZE) : 0);
418
            }
419
        }
420
		
421
        /// <summary>
422
        /// Find the best (longest) string in the window matching the 
423
        /// string starting at strstart.
424
        ///
425
        /// Preconditions:
426
        /// <code>
427
        /// strstart + MAX_MATCH &lt;= window.length.</code>
428
        /// </summary>
429
        /// <param name="curMatch"></param>
430
        /// <returns>True if a match greater than the minimum length is found</returns>
431
        bool FindLongestMatch(int curMatch) 
432
        {
433
            var chainLength = max_chain;
434
            var niceLength  = this.niceLength;
435
            var prev    = this.prev;
436
            var scan        = strstart;
437
            var best_end = strstart + matchLen;
438
            var best_len = Math.Max(matchLen, MIN_MATCH - 1);
439
			
440
            int limit = Math.Max(strstart - MAX_DIST, 0);
441
			
442
            int strend = strstart + MAX_MATCH - 1;
443
            byte scan_end1 = window[best_end - 1];
444
            byte scan_end  = window[best_end];
445
			
446
            // Do not waste too much time if we already have a good match:
447
            if (best_len >= goodLength) {
448
                chainLength >>= 2;
449
            }
450
			
451
            /* Do not look for matches beyond the end of the input. This is necessary
452
			* to make deflate deterministic.
453
			*/
454
            if (niceLength > lookahead) {
455
                niceLength = lookahead;
456
            }
457
	
458
            do { 
459
                if (window[curMatch + best_len] != scan_end      || 
460
                    window[curMatch + best_len - 1] != scan_end1 || 
461
                    window[curMatch] != window[scan]             || 
462
                    window[curMatch + 1] != window[scan + 1]) {
463
                        continue;
464
                    }
465
				
466
                int match = curMatch + 2;
467
                scan += 2;
468
				
469
                /* We check for insufficient lookahead only every 8th comparison;
470
				* the 256th check will be made at strstart + 258.
471
				*/
472
                while (
473
                    window[++scan] == window[++match] && 
474
                    window[++scan] == window[++match] && 
475
                    window[++scan] == window[++match] && 
476
                    window[++scan] == window[++match] && 
477
                    window[++scan] == window[++match] && 
478
                    window[++scan] == window[++match] && 
479
                    window[++scan] == window[++match] && 
480
                    window[++scan] == window[++match] &&
481
                    (scan < strend))
482
                {
483
                    // Do nothing
484
                }
485
				
486
                if (scan > best_end) {
487
                    matchStart = curMatch;
488
                    best_end = scan;
489
                    best_len = scan - strstart;
490
					
491
                    if (best_len >= niceLength) {
492
                        break;
493
                    }
494
					
495
                    scan_end1  = window[best_end - 1];
496
                    scan_end   = window[best_end];
497
                }
498
                scan = strstart;
499
            } while ((curMatch = (prev[curMatch & WMASK] & 0xffff)) > limit && --chainLength != 0);
500
			
501
            matchLen = Math.Min(best_len, lookahead);
502
            return matchLen >= MIN_MATCH;
503
        }
504
		
505
        bool DeflateStored(bool flush, bool finish)
506
        {
507
            if (!flush && (lookahead == 0)) {
508
                return false;
509
            }
510
			
511
            strstart += lookahead;
512
            lookahead = 0;
513
			
514
            int storedLength = strstart - blockStart;
515
			
516
            if ((storedLength >= MAX_BLOCK_SIZE) || // Block is full
517
                (blockStart < WSIZE && storedLength >= MAX_DIST) ||   // Block may move out of window
518
                flush) {
519
                    bool lastBlock = finish;
520
                    if (storedLength > MAX_BLOCK_SIZE) {
521
                        storedLength = MAX_BLOCK_SIZE;
522
                        lastBlock = false;
523
                    }
524

    
525
                    huffman.FlushStoredBlock(window, blockStart, storedLength, lastBlock);
526
                    blockStart += storedLength;
527
                    return !lastBlock;
528
                }
529
            return true;
530
        }
531
		
532
        bool DeflateFast(bool flush, bool finish)
533
        {
534
            if (lookahead < MIN_LOOKAHEAD && !flush) {
535
                return false;
536
            }
537
			
538
            while (lookahead >= MIN_LOOKAHEAD || flush) {
539
                if (lookahead == 0) {
540
                    // We are flushing everything
541
                    huffman.FlushBlock(window, blockStart, strstart - blockStart, finish);
542
                    blockStart = strstart;
543
                    return false;
544
                }
545
				
546
                if (strstart > 2 * WSIZE - MIN_LOOKAHEAD) {
547
                    /* slide window, as FindLongestMatch needs this.
548
					 * This should only happen when flushing and the window
549
					 * is almost full.
550
					 */
551
                    SlideWindow();
552
                }
553
				
554
                int hashHead;
555
                if (lookahead >= MIN_MATCH && 
556
                    (hashHead = InsertString()) != 0 && 
557
                    strategy != DeflateStrategy.HuffmanOnly &&
558
                    strstart - hashHead <= MAX_DIST && 
559
                    FindLongestMatch(hashHead)) {
560
                        // longestMatch sets matchStart and matchLen
561
                        var full = huffman.TallyDist(strstart - matchStart, matchLen);
562

    
563
                        lookahead -= matchLen;
564
                        if (matchLen <= max_lazy && lookahead >= MIN_MATCH) {
565
                            while (--matchLen > 0) {
566
                                ++strstart;
567
                                InsertString();
568
                            }
569
                            ++strstart;
570
                        } else {
571
                            strstart += matchLen;
572
                            if (lookahead >= MIN_MATCH - 1) {
573
                                UpdateHash();
574
                            }
575
                        }
576
                        matchLen = MIN_MATCH - 1;
577
                        if (!full) {
578
                            continue;
579
                        }
580
                    } else {
581
                        // No match found
582
                        huffman.TallyLit(window[strstart] & 0xff);
583
                        ++strstart;
584
                        --lookahead;
585
                    }
586
				
587
                if (huffman.IsFull()) {
588
                    bool lastBlock = finish && (lookahead == 0);
589
                    huffman.FlushBlock(window, blockStart, strstart - blockStart, lastBlock);
590
                    blockStart = strstart;
591
                    return !lastBlock;
592
                }
593
            }
594
            return true;
595
        }
596
		
597
        bool DeflateSlow(bool flush, bool finish)
598
        {
599
            if (lookahead < MIN_LOOKAHEAD && !flush) {
600
                return false;
601
            }
602
			
603
            while (lookahead >= MIN_LOOKAHEAD || flush) {
604
                if (lookahead == 0) {
605
                    if (prevAvailable) {
606
                        huffman.TallyLit(window[strstart-1] & 0xff);
607
                    }
608
                    prevAvailable = false;
609
					
610
                    // We are flushing everything           
611
                    huffman.FlushBlock(window, blockStart, strstart - blockStart,
612
                                       finish);
613
                    blockStart = strstart;
614
                    return false;
615
                }
616
				
617
                if (strstart >= 2 * WSIZE - MIN_LOOKAHEAD) {
618
                    /* slide window, as FindLongestMatch needs this.
619
					 * This should only happen when flushing and the window
620
					 * is almost full.
621
					 */
622
                    SlideWindow();
623
                }
624
				
625
                int prevMatch = matchStart;
626
                int prevLen = matchLen;
627
                if (lookahead >= MIN_MATCH) {
628

    
629
                    int hashHead = InsertString();
630

    
631
                    if (strategy != DeflateStrategy.HuffmanOnly &&
632
                        hashHead != 0 &&
633
                        strstart - hashHead <= MAX_DIST &&
634
                        FindLongestMatch(hashHead)) {
635
						
636
                            // longestMatch sets matchStart and matchLen
637
							
638
                            // Discard match if too small and too far away
639
                            if (matchLen <= 5 && (strategy == DeflateStrategy.Filtered || (matchLen == MIN_MATCH && strstart - matchStart > TooFar))) {
640
                                matchLen = MIN_MATCH - 1;
641
                            }
642
                        }
643
                }
644
				
645
                // previous match was better
646
                if ((prevLen >= MIN_MATCH) && (matchLen <= prevLen) ) {
647
                    huffman.TallyDist(strstart - 1 - prevMatch, prevLen);
648
                    prevLen -= 2;
649
                    do {
650
                        strstart++;
651
                        lookahead--;
652
                        if (lookahead >= MIN_MATCH) {
653
                            InsertString();
654
                        }
655
                    } while (--prevLen > 0);
656

    
657
                    strstart ++;
658
                    lookahead--;
659
                    prevAvailable = false;
660
                    matchLen = MIN_MATCH - 1;
661
                } else {
662
                    if (prevAvailable) {
663
                        huffman.TallyLit(window[strstart-1] & 0xff);
664
                    }
665
                    prevAvailable = true;
666
                    strstart++;
667
                    lookahead--;
668
                }
669
				
670
                if (huffman.IsFull()) {
671
                    int len = strstart - blockStart;
672
                    if (prevAvailable) {
673
                        len--;
674
                    }
675
                    bool lastBlock = (finish && (lookahead == 0) && !prevAvailable);
676
                    huffman.FlushBlock(window, blockStart, len, lastBlock);
677
                    blockStart += len;
678
                    return !lastBlock;
679
                }
680
            }
681
            return true;
682
        }
683
		
684
        #region Instance Fields
685

    
686
        // Hash index of string to be inserted
687
        int ins_h;
688

    
689
        /// <summary>
690
        /// Hashtable, hashing three characters to an index for window, so
691
        /// that window[index]..window[index+2] have this hash code.  
692
        /// Note that the array should really be unsigned short, so you need
693
        /// to and the values with 0xffff.
694
        /// </summary>
695
        readonly short[] head;
696

    
697
        /// <summary>
698
        /// <code>prev[index &amp; WMASK]</code> points to the previous index that has the
699
        /// same hash code as the string starting at index.  This way 
700
        /// entries with the same hash code are in a linked list.
701
        /// Note that the array should really be unsigned short, so you need
702
        /// to and the values with 0xffff.
703
        /// </summary>
704
        readonly short[] prev;
705
		
706
        int    matchStart;
707
        // Length of best match
708
        int    matchLen;
709
        // Set if previous match exists
710
        bool   prevAvailable;
711
        int    blockStart;
712

    
713
        /// <summary>
714
        /// Points to the current character in the window.
715
        /// </summary>
716
        int    strstart;
717

    
718
        /// <summary>
719
        /// lookahead is the number of characters starting at strstart in
720
        /// window that are valid.
721
        /// So window[strstart] until window[strstart+lookahead-1] are valid
722
        /// characters.
723
        /// </summary>
724
        int    lookahead;
725

    
726
        /// <summary>
727
        /// This array contains the part of the uncompressed stream that 
728
        /// is of relevance.  The current character is indexed by strstart.
729
        /// </summary>
730
        readonly byte[] window;
731
		
732
        DeflateStrategy strategy;
733
        int max_chain, max_lazy, niceLength, goodLength;
734
		
735
        /// <summary>
736
        /// The current compression function.
737
        /// </summary>
738
        int compressionFunction;
739
		
740
        /// <summary>
741
        /// The input data for compression.
742
        /// </summary>
743
        byte[] inputBuf;
744
		
745
        /// <summary>
746
        /// The total bytes of input read.
747
        /// </summary>
748
        int totalIn;
749
		
750
        /// <summary>
751
        /// The offset into inputBuf, where input data starts.
752
        /// </summary>
753
        int inputOff;
754
		
755
        /// <summary>
756
        /// The end offset of the input data.
757
        /// </summary>
758
        int inputEnd;
759

    
760
        readonly DeflaterPending pending;
761
        readonly DeflaterHuffman huffman;
762
		
763
        /// <summary>
764
        /// The adler checksum
765
        /// </summary>
766
        readonly Adler32 adler;
767
        #endregion
768
    }
769
}