-
Notifications
You must be signed in to change notification settings - Fork 8
/
deflate.cs
executable file
·2298 lines (1974 loc) · 89.3 KB
/
deflate.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// deflate.cs -- internal compression state & compress data using the deflation algorithm
// Copyright (C) 1995-2010 Jean-loup Gailly.
// Copyright (C) 2007-2011 by the Authors
// For conditions of distribution and use, see copyright notice in License.txt
#region ALGORITHM , ACKNOWLEDGEMENTS & REFERENCES
// ALGORITHM
//
// The "deflation" process depends on being able to identify portions
// of the input text which are identical to earlier input (within a
// sliding window trailing behind the input currently being processed).
//
// The most straightforward technique turns out to be the fastest for
// most input files: try all possible matches and select the longest.
// The key feature of this algorithm is that insertions into the string
// dictionary are very simple and thus fast, and deletions are avoided
// completely. Insertions are performed at each input character, whereas
// string matches are performed only when the previous match ends. So it
// is preferable to spend more time in matches to allow very fast string
// insertions and avoid deletions. The matching algorithm for small
// strings is inspired from that of Rabin & Karp. A brute force approach
// is used to find longer strings when a small match has been found.
// A similar algorithm is used in comic (by Jan-Mark Wams) and freeze
// (by Leonid Broukhis).
// A previous version of this file used a more sophisticated algorithm
// (by Fiala and Greene) which is guaranteed to run in linear amortized
// time, but has a larger average cost, uses more memory and is patented.
// However the F&G algorithm may be faster for some highly redundant
// files if the parameter max_chain_length (described below) is too large.
//
// ACKNOWLEDGEMENTS
//
// The idea of lazy evaluation of matches is due to Jan-Mark Wams, and
// I found it in 'freeze' written by Leonid Broukhis.
// Thanks to many people for bug reports and testing.
//
// REFERENCES
//
// Deutsch, L.P.,"DEFLATE Compressed Data Format Specification".
// Available in http://www.ietf.org/rfc/rfc1951.txt
//
// A description of the Rabin and Karp algorithm is given in the book
// "Algorithms" by R. Sedgewick, Addison-Wesley, p252.
//
// Fiala,E.R., and Greene,D.H.
// Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595
#endregion
using System;
namespace Free.Ports.zLib
{
public static partial class zlib
{
#region deflate.h
// ===========================================================================
// Internal compression state.
// number of length codes, not counting the special END_BLOCK code
private const int LENGTH_CODES=29;
// number of literal bytes 0..255
private const int LITERALS=256;
// number of Literal or Length codes, including the END_BLOCK code
private const int L_CODES=LITERALS+1+LENGTH_CODES;
// number of distance codes
private const int D_CODES=30;
// number of codes used to transfer the bit lengths
private const int BL_CODES=19;
// maximum heap size
private const int HEAP_SIZE=2*L_CODES+1;
// All codes must not exceed MAX_BITS bits
private const int MAX_BITS=15;
// Stream status
private const int INIT_STATE=42;
private const int EXTRA_STATE=69;
private const int NAME_STATE=73;
private const int COMMENT_STATE=91;
private const int HCRC_STATE=103;
private const int BUSY_STATE=113;
private const int FINISH_STATE=666;
// Data structure describing a single value and its code string.
struct ct_data
{
ushort freq;
public ushort Freq { get { return freq; } set { freq=value; } } // frequency count
public ushort Code { get { return freq; } set { freq=value; } } // bit string
ushort dad;
public ushort Dad { get { return dad; } set { dad=value; } } // father node in Huffman tree
public ushort Len { get { return dad; } set { dad=value; } } // length of bit string
public ct_data(ushort freq, ushort dad)
{
this.freq=freq;
this.dad=dad;
}
public ct_data(ct_data data)
{
freq=data.freq;
dad=data.dad;
}
}
struct tree_desc
{
public ct_data[] dyn_tree; // the dynamic tree
public int max_code; // largest code with non zero frequency
public static_tree_desc stat_desc; // the corresponding static tree
public tree_desc(tree_desc desc)
{
dyn_tree=desc.dyn_tree;
max_code=desc.max_code;
stat_desc=desc.stat_desc;
}
}
class deflate_state //internal_state
{
public z_stream strm; // pointer back to this zlib stream
public int status; // as the name implies
public byte[] pending_buf; // output still pending
public uint pending_buf_size; // size of pending_buf
public int pending_out; // next pending byte to output to the stream
public uint pending; // nb of bytes in the pending buffer
public int wrap; // bit 0 true for zlib, bit 1 true for gzip
public gz_header gzhead; // gzip header information to write
public uint gzindex; // where in extra, name, or comment
public byte method; // STORED (for zip only) or DEFLATED
public int last_flush; // value of flush param for previous deflate call
// used by deflate.c:
public uint w_size; // LZ77 window size (32K by default)
public uint w_bits; // log2(w_size) (8..16)
public uint w_mask; // w_size - 1
// Sliding window. Input bytes are read into the second half of the window,
// and move to the first half later to keep a dictionary of at least wSize
// bytes. With this organization, matches are limited to a distance of
// wSize-MAX_MATCH bytes, but this ensures that IO is always
// performed with a length multiple of the block size. Also, it limits
// the window size to 64K, which is quite useful on MSDOS.
// To do: use the user input buffer as sliding window.
public byte[] window;
// Actual size of window: 2*wSize, except when the user input buffer
// is directly used as sliding window.
public uint window_size;
// Link to older string with same hash index. To limit the size of this
// array to 64K, this link is maintained only for the last 32K strings.
// An index in this array is thus a window index modulo 32K.
public ushort[] prev;
public ushort[] head; // Heads of the hash chains or NIL.
public uint ins_h; // hash index of string to be inserted
public uint hash_size; // number of elements in hash table
public uint hash_bits; // log2(hash_size)
public uint hash_mask; // hash_size-1
// Number of bits by which ins_h must be shifted at each input
// step. It must be such that after MIN_MATCH steps, the oldest
// byte no longer takes part in the hash key, that is:
// hash_shift * MIN_MATCH >= hash_bits
public uint hash_shift;
// Window position at the beginning of the current output block. Gets
// negative when the window is moved backwards.
public int block_start;
public uint match_length; // length of best match
public uint prev_match; // previous match
public int match_available; // set if previous match exists
public uint strstart; // start of string to insert
public uint match_start; // start of matching string
public uint lookahead; // number of valid bytes ahead in window
// Length of the best match at previous step. Matches not greater than this
// are discarded. This is used in the lazy match evaluation.
public uint prev_length;
// To speed up deflation, hash chains are never searched beyond this
// length. A higher limit improves compression ratio but degrades the speed.
public uint max_chain_length;
// Attempt to find a better match only when the current match is strictly
// smaller than this value. This mechanism is used only for compression
// levels >= 4.
public uint max_lazy_match;
// Insert new strings in the hash table only if the match length is not
// greater than this length. This saves time but degrades compression.
// max_insert_length is used only for compression levels <= 3.
//#define max_insert_length max_lazy_match
public int level; // compression level (1..9)
public int strategy; // favor or force Huffman coding
public uint good_match; // Use a faster search when the previous match is longer than this
public int nice_match; // Stop searching when current match exceeds this
// used by trees.c:
public ct_data[] dyn_ltree=new ct_data[HEAP_SIZE]; // literal and length tree
public ct_data[] dyn_dtree=new ct_data[2*D_CODES+1]; // distance tree
public ct_data[] bl_tree=new ct_data[2*BL_CODES+1]; // Huffman tree for bit lengths
public tree_desc l_desc=new tree_desc(); // desc. for literal tree
public tree_desc d_desc=new tree_desc(); // desc. for distance tree
public tree_desc bl_desc=new tree_desc(); // desc. for bit length tree
// number of codes at each bit length for an optimal tree
public ushort[] bl_count=new ushort[MAX_BITS+1];
// The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
// The same heap array is used to build all trees.
public int[] heap=new int[2*L_CODES+1]; // heap used to build the Huffman trees
public int heap_len; // number of elements in the heap
public int heap_max; // element of largest frequency
// Depth of each subtree used as tie breaker for trees of equal frequency
public byte[] depth=new byte[2*L_CODES+1];
public byte[] l_buf; // buffer for literals or lengths
// Size of match buffer for literals/lengths. There are 4 reasons for
// limiting lit_bufsize to 64K:
// - frequencies can be kept in 16 bit counters
// - if compression is not successful for the first block, all input
// data is still in the window so we can still emit a stored block even
// when input comes from standard input. (This can also be done for
// all blocks if lit_bufsize is not greater than 32K.)
// - if compression is not successful for a file smaller than 64K, we can
// even emit a stored file instead of a stored block (saving 5 bytes).
// This is applicable only for zip (not zlib).
// - creating new Huffman trees less frequently may not provide fast
// adaptation to changes in the input data statistics. (Take for
// example a binary file with poorly compressible code followed by
// a highly compressible string table.) Smaller buffer sizes give
// fast adaptation but have of course the overhead of transmitting
// trees more frequently.
// - I can't count above 4
public uint lit_bufsize;
public uint last_lit; // running index in l_buf
// Buffer for distances. To simplify the code, d_buf and l_buf have
// the same number of elements. To use different lengths, an extra flag
// array would be necessary.
public ushort[] d_buf;
public uint opt_len; // bit length of current block with optimal trees
public uint static_len; // bit length of current block with static trees
public uint matches; // number of string matches in current block
public int last_eob_len; // bit length of EOB code for last block
// Output buffer. bits are inserted starting at the bottom (least
// significant bits).
public ushort bi_buf;
// Number of valid bits in bi_buf. All bits above the last valid bit
// are always zero.
public int bi_valid;
// High water mark offset in window for initialized bytes -- bytes above
// this are set to zero in order to avoid memory check warnings when
// longest match routines access bytes past the input. This is then
// updated to the new high water mark.
public uint high_water;
public deflate_state Clone()
{
deflate_state ret=(deflate_state)MemberwiseClone();
ret.dyn_ltree=new ct_data[HEAP_SIZE];
for(int i=0; i<HEAP_SIZE; i++) ret.dyn_ltree[i]=new ct_data(dyn_ltree[i]);
ret.dyn_dtree=new ct_data[2*D_CODES+1];
for(int i=0; i<(2*D_CODES+1); i++) ret.dyn_dtree[i]=new ct_data(dyn_dtree[i]);
ret.bl_tree=new ct_data[2*BL_CODES+1];
for(int i=0; i<(2*BL_CODES+1); i++) ret.bl_tree[i]=new ct_data(bl_tree[i]);
ret.bl_count=new ushort[MAX_BITS+1]; bl_count.CopyTo(ret.bl_count, 0);
ret.heap=new int[2*L_CODES+1]; heap.CopyTo(ret.heap, 0);
ret.depth=new byte[2*L_CODES+1]; depth.CopyTo(ret.depth, 0);
ret.l_desc=new tree_desc(l_desc); // desc. for literal tree
ret.d_desc=new tree_desc(d_desc); // desc. for distance tree
ret.bl_desc=new tree_desc(bl_desc);
return ret;
}
}
// Output a byte on the stream.
// IN assertion: there is enough room in pending_buf.
//#define put_byte(s, c) {s.pending_buf[s.pending++] = (c);}
// Minimum amount of lookahead, except at the end of the input file.
// See deflate.c for comments about the MIN_MATCH+1.
private const int MIN_LOOKAHEAD=MAX_MATCH+MIN_MATCH+1;
// In order to simplify the code, particularly on 16 bit machines, match
// distances are limited to MAX_DIST instead of WSIZE.
//#define MAX_DIST(s) (s.w_size-MIN_LOOKAHEAD)
// Number of bytes after end of data in window to initialize in order to avoid
// memory checker errors from longest match routines
private const int WIN_INIT=MAX_MATCH;
// Mapping from a distance to a distance code. dist is the distance - 1 and
// must not have side effects. _dist_code[256] and _dist_code[257] are never
// used.
//#define d_code(dist) ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)])
#endregion
// If you use the zlib library in a product, an acknowledgment is welcome
// in the documentation of your product. If for some reason you cannot
// include such an acknowledgment, I would appreciate that you keep this
// copyright string in the executable of your product.
private const string deflate_copyright=" deflate 1.2.5 Copyright 1995-2010 Jean-loup Gailly ";
// ===========================================================================
// Function prototypes.
enum block_state
{
need_more, // block not completed, need more input or more output
block_done, // block flush performed
finish_started, // finish started, need only more output at next deflate
finish_done // finish done, accept no more input or output
}
// Compression function. Returns the block state after the call.
delegate block_state compress_func(deflate_state s, int flush);
// ===========================================================================
// Local data
// Tail of hash chains
private const int NIL=0;
// Matches of length 3 are discarded if their distance exceeds TOO_FAR
private const int TOO_FAR=4096;
// Values for max_lazy_match, good_match and max_chain_length, depending on
// the desired pack level (0..9). The values given below have been tuned to
// exclude worst case performance for pathological files. Better values may be
// found for specific files.
struct config
{
public ushort good_length; // reduce lazy search above this match length
public ushort max_lazy; // do not perform lazy search above this match length
public ushort nice_length; // quit search above this match length
public ushort max_chain;
public compress_func func;
public config(ushort good_length, ushort max_lazy, ushort nice_length, ushort max_chain, compress_func func)
{
this.good_length=good_length;
this.max_lazy=max_lazy;
this.nice_length=nice_length;
this.max_chain=max_chain;
this.func=func;
}
}
static readonly config[] configuration_table=new config[]
{ // good lazy nice chain
new config( 0, 0, 0, 0, deflate_stored), // store only
new config( 4, 4, 8, 4, deflate_fast), // max speed, no lazy matches
new config( 4, 5, 16, 8, deflate_fast),
new config( 4, 6, 32, 32, deflate_fast),
new config( 4, 4, 16, 16, deflate_slow), // lazy matches
new config( 8, 16, 32, 32, deflate_slow),
new config( 8, 16, 128, 128, deflate_slow),
new config( 8, 32, 128, 256, deflate_slow),
new config(32, 128, 258, 1024, deflate_slow),
new config(32, 258, 258, 4096, deflate_slow) // max compression
};
// Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4
// For deflate_fast() (levels <= 3) good is ignored and lazy has a different
// meaning.
// ===========================================================================
// Update a hash value with the given input byte
// IN assertion: all calls to to UPDATE_HASH are made with consecutive
// input characters, so that a running hash key can be computed from the
// previous key instead of complete recalculation each time.
//#define UPDATE_HASH(s,h,c) h = ((h<<s.hash_shift) ^ c) & s.hash_mask
// ===========================================================================
// Insert string str in the dictionary and set match_head to the previous head
// of the hash chain (the most recent string with same hash key). Return
// the previous length of the hash chain.
// If this file is compiled with -DFASTEST, the compression level is forced
// to 1, and no hash chains are maintained.
// IN assertion: all calls to to INSERT_STRING are made with consecutive
// input characters and the first MIN_MATCH bytes of str are valid
// (except for the last MIN_MATCH-1 bytes of the input file).
//#define INSERT_STRING(s, str, match_head) \
// s.ins_h = ((s.ins_h<<(int)s.hash_shift) ^ s.window[(str) + (MIN_MATCH-1)]) & s.hash_mask; \
// match_head = s.prev[(str) & s.w_mask] = s.head[s.ins_h]; \
// s.head[s.ins_h] = (unsigned short)str
// ===========================================================================
// Initialize the hash table (avoiding 64K overflow for 16 bit systems).
// prev[] will be initialized on the fly.
// =========================================================================
// Initializes the internal stream state for compression. The fields
// zalloc, zfree and opaque must be initialized before by the caller.
// If zalloc and zfree are set to Z_NULL, deflateInit updates them to
// use default allocation functions.
// The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
// 1 gives best speed, 9 gives best compression, 0 gives no compression at
// all (the input data is simply copied a block at a time).
// Z_DEFAULT_COMPRESSION requests a default compromise between speed and
// compression (currently equivalent to level 6).
// deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
// enough memory, Z_STREAM_ERROR if level is not a valid compression level,
// Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
// with the version assumed by the caller (ZLIB_VERSION).
// msg is set to null if there is no error message. deflateInit does not
// perform any compression: this will be done by deflate().
public static int deflateInit(z_stream strm, int level)
{
return deflateInit2(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
// Todo: ignore strm.next_in if we use it as window
}
// =========================================================================
// This is another version of deflateInit with more compression options. The
// fields next_in, zalloc, zfree and opaque must be initialized before by
// the caller.
// The method parameter is the compression method. It must be Z_DEFLATED in
// this version of the library.
// The windowBits parameter is the base two logarithm of the window size
// (the size of the history buffer). It should be in the range 8..15 for this
// version of the library. Larger values of this parameter result in better
// compression at the expense of memory usage. The default value is 15 if
// deflateInit is used instead.
// windowBits can also be -8..-15 for raw deflate. In this case, -windowBits
// determines the window size. deflate() will then generate raw deflate data
// with no zlib header or trailer, and will not compute an adler32 check value.
// windowBits can also be greater than 15 for optional gzip encoding. Add
// 16 to windowBits to write a simple gzip header and trailer around the
// compressed data instead of a zlib wrapper. The gzip header will have no
// file name, no extra data, no comment, no modification time (set to zero),
// no header crc, and the operating system will be set to 255 (unknown). If a
// gzip stream is being written, strm.adler is a crc32 instead of an adler32.
// The memLevel parameter specifies how much memory should be allocated
// for the internal compression state. memLevel=1 uses minimum memory but
// is slow and reduces compression ratio; memLevel=9 uses maximum memory
// for optimal speed. The default value is 8. See zconf.h for total memory
// usage as a function of windowBits and memLevel.
// The strategy parameter is used to tune the compression algorithm. Use the
// value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
// filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no
// string match), or Z_RLE to limit match distances to one (run-length
// encoding). Filtered data consists mostly of small values with a somewhat
// random distribution. In this case, the compression algorithm is tuned to
// compress them better. The effect of Z_FILTERED is to force more Huffman
// coding and less string matching; it is somewhat intermediate between
// Z_DEFAULT and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as
// Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy
// parameter only affects the compression ratio but not the correctness of the
// compressed output even if it is not set appropriately. Z_FIXED prevents the
// use of dynamic Huffman codes, allowing for a simpler decoder for special
// applications.
// deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
// memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid
// method). msg is set to null if there is no error message. deflateInit2 does
// not perform any compression: this will be done by deflate().
public static int deflateInit2(z_stream strm, int level, int method, int windowBits, int memLevel, int strategy)
{
if(strm==null) return Z_STREAM_ERROR;
strm.msg=null;
if(level==Z_DEFAULT_COMPRESSION) level=6;
int wrap=1;
if(windowBits<0)
{ // suppress zlib wrapper
wrap=0;
windowBits=-windowBits;
}
else if(windowBits>15)
{
wrap=2; // write gzip wrapper instead
windowBits-=16;
}
if(memLevel<1||memLevel>MAX_MEM_LEVEL||method!=Z_DEFLATED||windowBits<8||windowBits>15||level<0||level>9||
strategy<0||strategy>Z_FIXED) return Z_STREAM_ERROR;
if(windowBits==8) windowBits=9; // until 256-byte window bug fixed
deflate_state s;
try
{
s=new deflate_state();
}
catch(Exception)
{
return Z_MEM_ERROR;
}
strm.state=s;
s.strm=strm;
s.wrap=wrap;
s.w_bits=(uint)windowBits;
s.w_size=1U<<(int)s.w_bits;
s.w_mask=s.w_size-1;
s.hash_bits=(uint)memLevel+7;
s.hash_size=1U<<(int)s.hash_bits;
s.hash_mask=s.hash_size-1;
s.hash_shift=(s.hash_bits+MIN_MATCH-1)/MIN_MATCH;
try
{
s.window=new byte[s.w_size*2];
s.prev=new ushort[s.w_size];
s.head=new ushort[s.hash_size];
s.high_water=0; // nothing written to s->window yet
s.lit_bufsize=1U<<(memLevel+6); // 16K elements by default
s.pending_buf=new byte[s.lit_bufsize*4];
s.pending_buf_size=s.lit_bufsize*4;
s.d_buf=new ushort[s.lit_bufsize];
s.l_buf=new byte[s.lit_bufsize];
}
catch(Exception)
{
s.status=FINISH_STATE;
strm.msg=zError(Z_MEM_ERROR);
deflateEnd(strm);
return Z_MEM_ERROR;
}
s.level=level;
s.strategy=strategy;
s.method=(byte)method;
return deflateReset(strm);
}
// =========================================================================
// Initializes the compression dictionary from the given byte sequence
// without producing any compressed output. This function must be called
// immediately after deflateInit, deflateInit2 or deflateReset, before any
// call of deflate. The compressor and decompressor must use exactly the same
// dictionary (see inflateSetDictionary).
// The dictionary should consist of strings (byte sequences) that are likely
// to be encountered later in the data to be compressed, with the most commonly
// used strings preferably put towards the end of the dictionary. Using a
// dictionary is most useful when the data to be compressed is short and can be
// predicted with good accuracy; the data can then be compressed better than
// with the default empty dictionary.
// Depending on the size of the compression data structures selected by
// deflateInit or deflateInit2, a part of the dictionary may in effect be
// discarded, for example if the dictionary is larger than the window size in
// deflate or deflate2. Thus the strings most likely to be useful should be
// put at the end of the dictionary, not at the front. In addition, the
// current implementation of deflate will use at most the window size minus
// 262 bytes of the provided dictionary.
// Upon return of this function, strm.adler is set to the adler32 value
// of the dictionary; the decompressor may later use this value to determine
// which dictionary has been used by the compressor. (The adler32 value
// applies to the whole dictionary even if only a subset of the dictionary is
// actually used by the compressor.) If a raw deflate was requested, then the
// adler32 value is not computed and strm.adler is not set.
// deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
// parameter is invalid (such as NULL dictionary) or the stream state is
// inconsistent (for example if deflate has already been called for this stream
// or if the compression method is bsort). deflateSetDictionary does not
// perform any compression: this will be done by deflate().
public static int deflateSetDictionary(z_stream strm, byte[] dictionary, uint dictLength)
{
uint length=dictLength;
uint n;
uint hash_head=0;
if(strm==null||strm.state==null||dictionary==null) return Z_STREAM_ERROR;
deflate_state s=strm.state as deflate_state;
if(s==null||s.wrap==2||(s.wrap==1&&s.status!=INIT_STATE))
return Z_STREAM_ERROR;
if(s.wrap!=0) strm.adler=adler32(strm.adler, dictionary, dictLength);
if(length<MIN_MATCH) return Z_OK;
int dictionary_ind=0;
if(length>s.w_size)
{
length=s.w_size;
dictionary_ind=(int)(dictLength-length); // use the tail of the dictionary
}
//was memcpy(s.window, dictionary+dictionary_ind, length);
Array.Copy(dictionary, dictionary_ind, s.window, 0, length);
s.strstart=length;
s.block_start=(int)length;
// Insert all strings in the hash table (except for the last two bytes).
// s.lookahead stays null, so s.ins_h will be recomputed at the next
// call of fill_window.
s.ins_h=s.window[0];
//was UPDATE_HASH(s, s.ins_h, s.window[1]);
s.ins_h=((s.ins_h<<(int)s.hash_shift)^s.window[1])&s.hash_mask;
for(n=0; n<=length-MIN_MATCH; n++)
{
//was INSERT_STRING(s, n, hash_head);
s.ins_h=((s.ins_h<<(int)s.hash_shift)^s.window[n+(MIN_MATCH-1)])&s.hash_mask;
hash_head=s.prev[n&s.w_mask]=s.head[s.ins_h];
s.head[s.ins_h]=(ushort)n;
}
if(hash_head!=0) hash_head=0; // to make compiler happy
return Z_OK;
}
// =========================================================================
// This function is equivalent to deflateEnd followed by deflateInit,
// but does not free and reallocate all the internal compression state.
// The stream will keep the same compression level and any other attributes
// that may have been set by deflateInit2.
// deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
// stream state was inconsistent (such as zalloc or state being NULL).
public static int deflateReset(z_stream strm)
{
if(strm==null||strm.state==null) return Z_STREAM_ERROR;
strm.total_in=strm.total_out=0;
strm.msg=null;
deflate_state s=(deflate_state)strm.state;
s.pending=0;
s.pending_out=0;
if(s.wrap<0) s.wrap=-s.wrap; // was made negative by deflate(..., Z_FINISH);
s.status=s.wrap!=0?INIT_STATE:BUSY_STATE;
strm.adler=s.wrap==2?crc32(0, null, 0):adler32(0, null, 0);
s.last_flush=Z_NO_FLUSH;
_tr_init(s);
lm_init(s);
return Z_OK;
}
// =========================================================================
// deflateSetHeader() provides gzip header information for when a gzip
// stream is requested by deflateInit2(). deflateSetHeader() may be called
// after deflateInit2() or deflateReset() and before the first call of
// deflate(). The text, time, os, extra field, name, and comment information
// in the provided gz_header structure are written to the gzip header (xflag is
// ignored -- the extra flags are set according to the compression level). The
// caller must assure that, if not Z_NULL, name and comment are terminated with
// a zero byte, and that if extra is not Z_NULL, that extra_len bytes are
// available there. If hcrc is true, a gzip header crc is included. Note that
// the current versions of the command-line version of gzip (up through version
// 1.3.x) do not support header crc's, and will report that it is a "multi-part
// gzip file" and give up.
// If deflateSetHeader is not used, the default gzip header has text false,
// the time set to zero, and os set to 255, with no extra, name, or comment
// fields. The gzip header is returned to the default state by deflateReset().
// deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
// stream state was inconsistent.
public static int deflateSetHeader(z_stream strm, gz_header head)
{
if(strm==null||strm.state==null) return Z_STREAM_ERROR;
deflate_state s=(deflate_state)strm.state;
if(s.wrap!=2) return Z_STREAM_ERROR;
s.gzhead=head;
return Z_OK;
}
// =========================================================================
// deflatePrime() inserts bits in the deflate output stream. The intent
// is that this function is used to start off the deflate output with the
// bits leftover from a previous deflate stream when appending to it. As such,
// this function can only be used for raw deflate, and must be used before the
// first deflate() call after a deflateInit2() or deflateReset(). bits must be
// less than or equal to 16, and that many of the least significant bits of
// value will be inserted in the output.
// deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source
// stream state was inconsistent.
public static int deflatePrime(z_stream strm, int bits, int value)
{
if(strm==null||strm.state==null) return Z_STREAM_ERROR;
deflate_state s=(deflate_state)strm.state;
s.bi_valid=bits;
s.bi_buf=(ushort)(value&((1<<bits)-1));
return Z_OK;
}
// =========================================================================
// Dynamically update the compression level and compression strategy. The
// interpretation of level and strategy is as in deflateInit2. This can be
// used to switch between compression and straight copy of the input data, or
// to switch to a different kind of input data requiring a different
// strategy. If the compression level is changed, the input available so far
// is compressed with the old level (and may be flushed); the new level will
// take effect only at the next call of deflate().
// Before the call of deflateParams, the stream state must be set as for
// a call of deflate(), since the currently available input may have to
// be compressed and flushed. In particular, strm.avail_out must be non-zero.
// deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
// stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR
// if strm.avail_out was zero.
public static int deflateParams(z_stream strm, int level, int strategy)
{
if(strm==null||strm.state==null) return Z_STREAM_ERROR;
deflate_state s=(deflate_state)strm.state;
if(level==Z_DEFAULT_COMPRESSION) level=6;
if(level<0||level>9||strategy<0||strategy>Z_FIXED) return Z_STREAM_ERROR;
compress_func func=configuration_table[s.level].func;
int err=Z_OK;
if((strategy!=s.strategy||func!=configuration_table[level].func)&&strm.total_in!=0) // Flush the last buffer:
err=deflate(strm, Z_BLOCK);
if(s.level!=level)
{
s.level=level;
s.max_lazy_match=configuration_table[level].max_lazy;
s.good_match=configuration_table[level].good_length;
s.nice_match=configuration_table[level].nice_length;
s.max_chain_length=configuration_table[level].max_chain;
}
s.strategy=strategy;
return err;
}
// =========================================================================
// Fine tune deflate's internal compression parameters. This should only be
// used by someone who understands the algorithm used by zlib's deflate for
// searching for the best matching string, and even then only by the most
// fanatic optimizer trying to squeeze out the last compressed bit for their
// specific input data. Read the deflate.cs source code for the meaning of the
// max_lazy, good_length, nice_length, and max_chain parameters.
// deflateTune() can be called after deflateInit() or deflateInit2(), and
// returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream.
public static int deflateTune(z_stream strm, uint good_length, uint max_lazy, int nice_length, uint max_chain)
{
if(strm==null||strm.state==null) return Z_STREAM_ERROR;
deflate_state s=(deflate_state)strm.state;
s.good_match=good_length;
s.max_lazy_match=max_lazy;
s.nice_match=nice_length;
s.max_chain_length=max_chain;
return Z_OK;
}
// =========================================================================
// For the default windowBits of 15 and memLevel of 8, this function returns
// a close to exact, as well as small, upper bound on the compressed size.
// They are coded as constants here for a reason--if the #define's are
// changed, then this function needs to be changed as well. The return
// value for 15 and 8 only works for those exact settings.
//
// For any setting other than those defaults for windowBits and memLevel,
// the value returned is a conservative worst case for the maximum expansion
// resulting from using fixed blocks instead of stored blocks, which deflate
// can emit on compressed data for some combinations of the parameters.
//
// This function could be more sophisticated to provide closer upper bounds for
// every combination of windowBits and memLevel. But even the conservative
// upper bound of about 14% expansion does not seem onerous for output buffer
// allocation.
// deflateBound() returns an upper bound on the compressed size after
// deflation of sourceLen bytes. It must be called after deflateInit()
// or deflateInit2(). This would be used to allocate an output buffer
// for deflation in a single pass, and so would be called before deflate().
public static uint deflateBound(z_stream strm, uint sourceLen)
{
// conservative upper bound for compressed data
uint complen=sourceLen+((sourceLen+7)>>3)+((sourceLen+63)>>6)+5;
// if can't get parameters, return conservative bound plus zlib wrapper
if(strm==null||strm.state==null) return complen+6;
// compute wrapper length
deflate_state s=(deflate_state)strm.state;
uint wraplen;
byte[] str;
switch(s.wrap)
{
case 0: // raw deflate
wraplen=0;
break;
case 1: // zlib wrapper
wraplen=(uint)(6+(s.strstart!=0?4:0));
break;
case 2: // gzip wrapper
wraplen=18;
if(s.gzhead!=null) // user-supplied gzip header
{
if(s.gzhead.extra!=null) wraplen+=2+s.gzhead.extra_len;
str=s.gzhead.name;
int str_ind=0;
if(str!=null)
{
do
{
wraplen++;
} while(str[str_ind++]!=0);
}
str=s.gzhead.comment;
if(str!=null)
{
do
{
wraplen++;
} while(str[str_ind++]!=0);
}
if(s.gzhead.hcrc!=0) wraplen+=2;
}
break;
default: wraplen=6; break; // for compiler happiness
}
// if not default parameters, return conservative bound
if(s.w_bits!=15||s.hash_bits!=8+7) return complen+wraplen;
// default settings: return tight bound for that case
return sourceLen+(sourceLen>>12)+(sourceLen>>14)+(sourceLen>>25)+13-6+wraplen;
}
// =========================================================================
// Put a short in the pending buffer. The 16-bit value is put in MSB order.
// IN assertion: the stream state is correct and there is enough room in
// pending_buf.
static void putShortMSB(deflate_state s, uint b)
{
//was put_byte(s, (byte)(b >> 8));
s.pending_buf[s.pending++]=(byte)(b >> 8);
//was put_byte(s, (byte)(b & 0xff));
s.pending_buf[s.pending++]=(byte)(b & 0xff);
}
// =========================================================================
// Flush as much pending output as possible. All deflate() output goes
// through this function so some applications may wish to modify it
// to avoid allocating a large strm.next_out buffer and copying into it.
// (See also read_buf()).
static void flush_pending(z_stream strm)
{
deflate_state s=(deflate_state)strm.state;
uint len=s.pending;
if(len>strm.avail_out) len=strm.avail_out;
if(len==0) return;
//was memcpy(strm.next_out, s.pending_out, len);
Array.Copy(s.pending_buf, s.pending_out, strm.out_buf, strm.next_out, len);
strm.next_out+=(int)len;
s.pending_out+=(int)len;
strm.total_out+=len;
strm.avail_out-=len;
s.pending-=len;
if(s.pending==0) s.pending_out=0;
}
const int PRESET_DICT=0x20; // preset dictionary flag in zlib header
#region deflate
// =========================================================================
// deflate compresses as much data as possible, and stops when the input
// buffer becomes empty or the output buffer becomes full. It may introduce some
// output latency (reading input without producing any output) except when
// forced to flush.
// The detailed semantics are as follows. deflate performs one or both of the
// following actions:
// - Compress more input starting at next_in and update next_in and avail_in
// accordingly. If not all input can be processed (because there is not
// enough room in the output buffer), next_in and avail_in are updated and
// processing will resume at this point for the next call of deflate().
// - Provide more output starting at next_out and update next_out and avail_out
// accordingly. This action is forced if the parameter flush is non zero.
// Forcing flush frequently degrades the compression ratio, so this parameter
// should be set only when necessary (in interactive applications).
// Some output may be provided even if flush is not set.
// Before the call of deflate(), the application should ensure that at least
// one of the actions is possible, by providing more input and/or consuming
// more output, and updating avail_in or avail_out accordingly; avail_out
// should never be zero before the call. The application can consume the
// compressed output when it wants, for example when the output buffer is full
// (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK
// and with zero avail_out, it must be called again after making room in the
// output buffer because there might be more output pending.
// Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to
// decide how much data to accumualte before producing output, in order to
// maximize compression.
// If the parameter flush is set to Z_SYNC_FLUSH, all pending output is
// flushed to the output buffer and the output is aligned on a byte boundary, so
// that the decompressor can get all input data available so far. (In particular
// avail_in is zero after the call if enough output space has been provided
// before the call.) Flushing may degrade compression for some compression
// algorithms and so it should be used only when necessary.
// If flush is set to Z_FULL_FLUSH, all output is flushed as with
// Z_SYNC_FLUSH, and the compression state is reset so that decompression can
// restart from this point if previous compressed data has been damaged or if
// random access is desired. Using Z_FULL_FLUSH too often can seriously degrade
// compression.
// If deflate returns with avail_out == 0, this function must be called again
// with the same value of the flush parameter and more output space (updated
// avail_out), until the flush is complete (deflate returns with non-zero
// avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that
// avail_out is greater than six to avoid repeated flush markers due to
// avail_out == 0 on return.
// If the parameter flush is set to Z_FINISH, pending input is processed,
// pending output is flushed and deflate returns with Z_STREAM_END if there
// was enough output space; if deflate returns with Z_OK, this function must be
// called again with Z_FINISH and more output space (updated avail_out) but no
// more input data, until it returns with Z_STREAM_END or an error. After
// deflate has returned Z_STREAM_END, the only possible operations on the
// stream are deflateReset or deflateEnd.
// Z_FINISH can be used immediately after deflateInit if all the compression
// is to be done in a single step. In this case, avail_out must be at least
// the value returned by deflateBound (see below). If deflate does not return
// Z_STREAM_END, then it must be called again as described above.
// deflate() sets strm.adler to the adler32 checksum of all input read
// so far (that is, total_in bytes).
// deflate() returns Z_OK if some progress has been made (more input
// processed or more output produced), Z_STREAM_END if all input has been
// consumed and all output has been produced (only when flush is set to
// Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
// if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible
// (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not
// fatal, and deflate() can be called again with more input and more output