forked from JoshDullen/zlib.net
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathinflate.cs
executable file
·2055 lines (1816 loc) · 68.9 KB
/
inflate.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
// inflate.cs -- internal inflate state definition & zlib decompression
// Copyright (C) 1995-2009 Mark Adler
// Copyright (C) 2007-2011 by the Authors
// For conditions of distribution and use, see copyright notice in License.txt
using System;
namespace Free.Ports.zLib
{
public static partial class zlib
{
// Possible inflate modes between inflate() calls
enum inflate_mode
{
HEAD, // i: waiting for magic header
FLAGS, // i: waiting for method and flags (gzip)
TIME, // i: waiting for modification time (gzip)
OS, // i: waiting for extra flags and operating system (gzip)
EXLEN, // i: waiting for extra length (gzip)
EXTRA, // i: waiting for extra bytes (gzip)
NAME, // i: waiting for end of file name (gzip)
COMMENT, // i: waiting for end of comment (gzip)
HCRC, // i: waiting for header crc (gzip)
DICTID, // i: waiting for dictionary check value
DICT, // waiting for inflateSetDictionary() call
TYPE, // i: waiting for type bits, including last-flag bit
TYPEDO, // i: same, but skip check to exit inflate on new block
STORED, // i: waiting for stored size (length and complement)
COPY_, // i/o: same as COPY below, but only first time in
COPY, // i/o: waiting for input or output to copy stored block
TABLE, // i: waiting for dynamic block table lengths
LENLENS, // i: waiting for code length code lengths
CODELENS, // i: waiting for length/lit and distance code lengths
LEN_, // i: same as LEN below, but only first time in
LEN, // i: waiting for length/lit/eob code
LENEXT, // i: waiting for length extra bits
DIST, // i: waiting for distance code
DISTEXT, // i: waiting for distance extra bits
MATCH, // o: waiting for output space to copy string
LIT, // o: waiting for output space to write literal
CHECK, // i: waiting for 32-bit check value
LENGTH, // i: waiting for 32-bit length (gzip)
DONE, // finished check, done -- remain here until reset
BAD, // got a data error -- remain here until reset
MEM, // got an inflate() memory error -- remain here until reset
SYNC // looking for synchronization bytes to restart inflate()
};
// State transitions between above modes -
//
// (most modes can go to BAD or MEM on error -- not shown for clarity)
//
// Process header:
// HEAD -> (gzip) or (zlib) or (raw)
// (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME -> COMMENT ->
// HCRC -> TYPE
// (zlib) -> DICTID or TYPE
// DICTID -> DICT -> TYPE
// (raw) -> TYPEDO
// Read deflate blocks:
// TYPE -> TYPEDO -> STORED or TABLE or LEN_ or CHECK
// STORED -> COPY_ -> COPY -> TYPE
// TABLE -> LENLENS -> CODELENS -> LEN_
// LEN_ -> LEN
// Read deflate codes in fixed or dynamic block:
// LEN -> LENEXT or LIT or TYPE
// LENEXT -> DIST -> DISTEXT -> MATCH -> LEN
// LIT -> LEN
// Process trailer:
// CHECK -> LENGTH -> DONE
// state maintained between inflate() calls. Approximately 10K bytes.
class inflate_state
{
public inflate_mode mode; // current inflate mode
public int last; // true if processing last block
public int wrap; // bit 0 true for zlib, bit 1 true for gzip
public int havedict; // true if dictionary provided
public int flags; // gzip header method and flags (0 if zlib)
public uint dmax; // zlib header max distance
public uint check; // protected copy of check value
public uint total; // protected copy of output count
public gz_header head; // where to save gzip header information
// sliding window
public uint wbits; // log base 2 of requested window size
public uint wsize; // window size or zero if not using window
public uint whave; // valid bytes in the window
public uint wnext; // window write index
public byte[] window; // allocated sliding window, if needed
// bit accumulator
public uint hold; // input bit accumulator
public uint bits; // number of bits in "in"
// for string and stored block copying
public uint length; // literal or length of data to copy
public uint offset; // distance back to copy string from
// for table and code decoding
public uint extra; // extra bits needed
// fixed and dynamic code tables
public code[] lencode; // starting table for length/literal codes
public code[] distcode; // starting table for distance codes
public int distcode_ind;// index of the start in distcode
public uint lenbits; // index bits for lencode
public uint distbits; // index bits for distcode
// dynamic table building
public uint ncode; // number of code length code lengths
public uint nlen; // number of length code lengths
public uint ndist; // number of distance code lengths
public uint have; // number of code lengths in lens[]
public int next; // next available space in codes[]
public ushort[] lens=new ushort[320]; // temporary storage for code lengths
public ushort[] work=new ushort[288]; // work area for code table building
public code[] codes=new code[ENOUGH]; // space for code tables
public bool sane; // if false, allow invalid distance too far
public int back; // bits back of last unprocessed length/lit
public uint was; // initial length of match
public inflate_state GetCopy()
{
inflate_state ret=(inflate_state)MemberwiseClone();
ret.lens=new ushort[320];
lens.CopyTo(ret.lens, 0);
ret.work=new ushort[288];
work.CopyTo(ret.work, 0);
ret.codes=new code[codes.Length];
for(int i=0; i<codes.Length; i++) ret.codes[i]=codes[i].Clone();
if(lencode==codes) ret.lencode=ret.distcode=ret.codes;
if(window!=null)
{
uint wsize=1U<<(int)wbits;
ret.window=new byte[wsize];
Array.Copy(window, ret.window, wsize);
}
return ret;
}
};
// This function is equivalent to inflateEnd followed by inflateInit,
// but does not free and reallocate all the internal decompression state.
// The stream will keep attributes that may have been set by inflateInit2.
// inflateReset 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 inflateReset(z_stream strm)
{
if(strm==null||strm.state==null) return Z_STREAM_ERROR;
inflate_state state=(inflate_state)strm.state;
strm.total_in=strm.total_out=state.total=0;
strm.msg=null;
strm.adler=1; // to support ill-conceived Java test suite
state.mode=inflate_mode.HEAD;
state.last=0;
state.havedict=0;
state.dmax=32768;
state.head=null;
state.wsize=0;
state.whave=0;
state.wnext=0;
state.hold=0;
state.bits=0;
state.lencode=state.distcode=state.codes;
state.distcode_ind=0;
state.next=0;
state.sane=true;
state.back=-1;
//Tracev((stderr, "inflate: reset\n"));
return Z_OK;
}
public static int inflateReset2(z_stream strm, int windowBits)
{
// get the state
if(strm==null||strm.state==null) return Z_STREAM_ERROR;
inflate_state state=(inflate_state)strm.state;
int wrap;
// extract wrap request from windowBits parameter
if(windowBits<0)
{
wrap=0;
windowBits=-windowBits;
}
else
{
wrap=(windowBits>>4)+1;
if(windowBits<48) windowBits&=15;
}
// set number of window bits, free window if different
if(windowBits!=0&&(windowBits<8||windowBits>15)) return Z_STREAM_ERROR;
if(state.window!=null&&state.wbits!=(uint)windowBits)
state.window=null;
// update state and reset the rest of it
state.wrap=wrap;
state.wbits=(uint)windowBits;
return inflateReset(strm);
}
// This is another version of inflateInit with an extra parameter. The
// fields next_in, avail_in, zalloc, zfree and opaque must be initialized
// before by the caller.
// The windowBits parameter is the base two logarithm of the maximum window
// size (the size of the history buffer). It should be in the range 8..15 for
// this version of the library. The default value is 15 if inflateInit is used
// instead. windowBits must be greater than or equal to the windowBits value
// provided to deflateInit2() while compressing, or it must be equal to 15 if
// deflateInit2() was not used. If a compressed stream with a larger window
// size is given as input, inflate() will return with the error code
// Z_DATA_ERROR instead of trying to allocate a larger window.
// windowBits can also be -8..-15 for raw inflate. In this case, -windowBits
// determines the window size. inflate() will then process raw deflate data,
// not looking for a zlib or gzip header, not generating a check value, and not
// looking for any check values for comparison at the end of the stream. This
// is for use with other formats that use the deflate compressed data format
// such as zip. Those formats provide their own check values. If a custom
// format is developed using the raw deflate format for compressed data, it is
// recommended that a check value such as an adler32 or a crc32 be applied to
// the uncompressed data as is done in the zlib, gzip, and zip formats. For
// most applications, the zlib format should be used as is. Note that comments
// above on the use in deflateInit2() applies to the magnitude of windowBits.
// windowBits can also be greater than 15 for optional gzip decoding. Add
// 32 to windowBits to enable zlib and gzip decoding with automatic header
// detection, or add 16 to decode only the gzip format (the zlib format will
// return a Z_DATA_ERROR). If a gzip stream is being decoded, strm.adler is
// a crc32 instead of an adler32.
// inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
// memory, Z_STREAM_ERROR if a parameter is invalid (such as a null strm). msg
// is set to null if there is no error message. inflateInit2 does not perform
// any decompression apart from reading the zlib header if present: this will
// be done by inflate(). (So next_in and avail_in may be modified, but next_out
// and avail_out are unchanged.)
public static int inflateInit2(z_stream strm, int windowBits)
{
if(strm==null) return Z_STREAM_ERROR;
strm.msg=null; // in case we return an error
inflate_state state;
try
{
state=new inflate_state();
}
catch(Exception)
{
return Z_MEM_ERROR;
}
//Tracev((stderr, "inflate: allocated\n"));
strm.state=state;
state.window=null;
int ret=inflateReset2(strm, windowBits);
if(ret!=Z_OK) strm.state=null;
return ret;
}
// Initializes the internal stream state for decompression. The fields
// next_in, avail_in, zalloc, zfree and opaque must be initialized before by
// the caller. If next_in is not Z_NULL and avail_in is large enough (the exact
// value depends on the compression method), inflateInit determines the
// compression method from the zlib header and allocates all data structures
// accordingly; otherwise the allocation will be deferred to the first call of
// inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to
// use default allocation functions.
// inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
// memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
// version assumed by the caller. msg is set to null if there is no error
// message. inflateInit does not perform any decompression apart from reading
// the zlib header if present: this will be done by inflate(). (So next_in and
// avail_in may be modified, but next_out and avail_out are unchanged.)
public static int inflateInit(z_stream strm)
{
return inflateInit2(strm, DEF_WBITS);
}
// This function inserts bits in the inflate input stream. The intent is
// that this function is used to start inflating at a bit position in the
// middle of a byte. The provided bits will be used before any bytes are used
// from next_in. This function should only be used with raw inflate, and
// should be used before the first inflate() call after inflateInit2() or
// inflateReset(). bits must be less than or equal to 16, and that many of the
// least significant bits of value will be inserted in the input.
// inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source
// stream state was inconsistent.
public static int inflatePrime(z_stream strm, int bits, int value)
{
if(strm==null||strm.state==null) return Z_STREAM_ERROR;
inflate_state state=(inflate_state)strm.state;
if(bits<0)
{
state.hold=0;
state.bits=0;
return Z_OK;
}
if(bits>16||state.bits+bits>32) return Z_STREAM_ERROR;
value&=(1<<(int)bits)-1;
state.hold+=(uint)(value<<(int)state.bits);
state.bits+=(uint)bits;
return Z_OK;
}
// Return state with length and distance decoding tables and index sizes set to
// fixed code decoding.
static void fixedtables(inflate_state state)
{
state.lencode=lenfix;
state.lenbits=9;
state.distcode=distfix;
state.distcode_ind=0;
state.distbits=5;
}
// Update the window with the last wsize (normally 32K) bytes written before
// returning. If window does not exist yet, create it. This is only called
// when a window is already in use, or when output has been written during this
// inflate call, but the end of the deflate stream has not been reached yet.
// It is also called to create a window for dictionary data when a dictionary
// is loaded.
//
// Providing output buffers larger than 32K to inflate() should provide a speed
// advantage, since only the last 32K of output is copied to the sliding window
// upon return from inflate(), and since all distances after the first 32K of
// output will fall in the output data, making match copies simpler and faster.
// The advantage may be dependent on the size of the processor's data caches.
static int updatewindow(z_stream strm, uint _out)
{
inflate_state state;
uint copy, dist;
state=(inflate_state)strm.state;
// if it hasn't been done already, allocate space for the window
if(state.window==null)
{
try
{
state.window=new byte[1<<(int)state.wbits];
}
catch(Exception)
{
return 1;
}
}
// if window not in use yet, initialize
if(state.wsize==0)
{
state.wsize=1U<<(int)state.wbits;
state.wnext=0;
state.whave=0;
}
// copy state.wsize or less output bytes into the circular window
copy=_out-strm.avail_out;
if(copy>=state.wsize)
{
//memcpy(state.window, strm.next_out-state.wsize, state.wsize);
Array.Copy(strm.out_buf, strm.next_out-state.wsize, state.window, 0, state.wsize);
state.wnext=0;
state.whave=state.wsize;
}
else
{
dist=state.wsize-state.wnext;
if(dist>copy) dist=copy;
//memcpy(state.window+state.write, strm.next_out-copy, dist);
Array.Copy(strm.out_buf, strm.next_out-copy, state.window, state.wnext, dist);
copy-=dist;
if(copy!=0)
{
//memcpy(state.window, strm.next_out-copy, copy);
Array.Copy(strm.out_buf, strm.next_out-copy, state.window, 0, copy);
state.wnext=copy;
state.whave=state.wsize;
}
else
{
state.wnext+=dist;
if(state.wnext==state.wsize) state.wnext=0;
if(state.whave<state.wsize) state.whave+=dist;
}
}
return 0;
}
// Macros for inflate():
// check function to use adler32() for zlib or crc32() for gzip
//#define UPDATE(check, buf, len) (state.flags ? crc32(check, buf, len) : adler32(check, buf, len))
// check macros for header crc
//#define CRC2(check, word) \
// hbuf[0] = (byte)word; \
// hbuf[1] = (byte)(word >> 8); \
// check = crc32(check, hbuf, 2); \
//#define CRC4(check, word) \
// hbuf[0] = (byte)word; \
// hbuf[1] = (byte)(word >> 8); \
// hbuf[2] = (byte)(word >> 16); \
// hbuf[3] = (byte)(word >> 24); \
// check = crc32(check, hbuf, 4); \
// Load registers with state in inflate() for speed
//#define LOAD() \
// put = strm.next_out; \
// left = strm.avail_out; \
// next = strm.next_in; \
// have = strm.avail_in; \
// hold = state.hold; \
// bits = state.bits;
// Restore state from registers in inflate()
//#define RESTORE() \
// strm.next_out = put; \
// strm.avail_out = left; \
// strm.next_in = next; \
// strm.avail_in = have; \
// state.hold = hold; \
// state.bits = bits;
// Clear the input bit accumulator
//#define INITBITS() hold = bits = 0;
// Get a byte of input into the bit accumulator, or return from inflate()
// if there is no input available.
//#define PULLBYTE() \
// if (have == 0) goto inf_leave; \
// have--; \
// hold += (uint)in_buf[next++] << (int)bits; \
// bits += 8;
// Assure that there are at least n bits in the bit accumulator. If there is
// not enough available input to do that, then return from inflate().
//#define NEEDBITS(n) while (bits < (unsigned int)(n)) { PULLBYTE(); }
// Return the low n bits of the bit accumulator (n < 16)
//#define BITS(n) ((uint)hold & ((1U << (n)) - 1))
// Remove n bits from the bit accumulator
//#define DROPBITS(n) \
// hold >>= (n); \
// bits -= (unsigned int)(n);
// Remove zero to seven bits as needed to go to a byte boundary
//#define BYTEBITS() \
// hold >>= bits & 7; \
// bits -= bits & 7;
// Reverse the bytes in a 32-bit value
//#define REVERSE(q) ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + (((q) & 0xff00) << 8) + (((q) & 0xff) << 24))
// inflate() uses a state machine to process as much input data and generate as
// much output data as possible before returning. The state machine is
// structured roughly as follows:
//
// for (;;) switch (state) {
// ...
// case STATEn:
// if (not enough input data or output space to make progress)
// return;
// ... make progress ...
// state = STATEm;
// break;
// ...
// }
//
// so when inflate() is called again, the same case is attempted again, and
// if the appropriate resources are provided, the machine proceeds to the
// next state. The NEEDBITS() macro is usually the way the state evaluates
// whether it can proceed or should return. NEEDBITS() does the return if
// the requested bits are not available. The typical use of the BITS macros
// is:
//
// NEEDBITS(n);
// ... do something with BITS(n) ...
// DROPBITS(n);
//
// where NEEDBITS(n) either returns from inflate() if there isn't enough
// input left to load n bits into the accumulator, or it continues. BITS(n)
// gives the low n bits in the accumulator. When done, DROPBITS(n) drops
// the low n bits off the accumulator. INITBITS() clears the accumulator
// and sets the number of available bits to zero. BYTEBITS() discards just
// enough bits to put the accumulator on a byte boundary. After BYTEBITS()
// and a NEEDBITS(8), then BITS(8) would return the next byte in the stream.
//
// NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return
// if there is no input available. The decoding of variable length codes uses
// PULLBYTE() directly in order to pull just enough bytes to decode the next
// code, and no more.
//
// Some states loop until they get enough input, making sure that enough
// state information is maintained to continue the loop where it left off
// if NEEDBITS() returns in the loop. For example, want, need, and keep
// would all have to actually be part of the saved state in case NEEDBITS()
// returns:
//
// case STATEw:
// while (want < need) {
// NEEDBITS(n);
// keep[want++] = BITS(n);
// DROPBITS(n);
// }
// state = STATEx;
// case STATEx:
//
// As shown above, if the next state is also the next case, then the break
// is omitted.
//
// A state may also return if there is not enough output space available to
// complete that state. Those states are copying stored data, writing a
// literal byte, and copying a matching string.
//
// When returning, a "goto inf_leave" is used to update the total counters,
// update the check value, and determine whether any progress has been made
// during that inflate() call in order to return the proper return code.
// Progress is defined as a change in either strm.avail_in or strm.avail_out.
// When there is a window, goto inf_leave will update the window with the last
// output written. If a goto inf_leave occurs in the middle of decompression
// and there is no window currently, goto inf_leave will create one and copy
// output to the window for the next call of inflate().
//
// In this implementation, the flush parameter of inflate() only affects the
// return code (per zlib.h). inflate() always writes as much as possible to
// strm.next_out, given the space available and the provided input--the effect
// documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers
// the allocation of and copying into a sliding window until necessary, which
// provides the effect documented in zlib.h for Z_FINISH when the entire input
// stream available. So the only thing the flush parameter actually does is:
// when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it
// will return Z_BUF_ERROR if it has not reached the end of the stream.
// permutation of code lengths
static readonly ushort[] order=new ushort[19] { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
// inflate decompresses 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. inflate performs one or both of the
// following actions:
// - Decompress 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 is updated and processing
// will resume at this point for the next call of inflate().
// - Provide more output starting at next_out and update next_out and avail_out
// accordingly. inflate() provides as much output as possible, until there
// is no more input data or no more space in the output buffer (see below
// about the flush parameter).
// Before the call of inflate(), the application should ensure that at least
// one of the actions is possible, by providing more input and/or consuming
// more output, and updating the next_* and avail_* values accordingly.
// The application can consume the uncompressed output when it wants, for
// example when the output buffer is full (avail_out == 0), or after each
// call of inflate(). If inflate 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.
// The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH,
// Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much
// output as possible to the output buffer. Z_BLOCK requests that inflate() stop
// if and when it gets to the next deflate block boundary. When decoding the
// zlib or gzip format, this will cause inflate() to return immediately after
// the header and before the first block. When doing a raw inflate, inflate()
// will go ahead and process the first block, and will return when it gets to
// the end of that block, or when it runs out of data.
// The Z_BLOCK option assists in appending to or combining deflate streams.
// Also to assist in this, on return inflate() will set strm.data_type to the
// number of unused bits in the last byte taken from strm.next_in, plus 64
// if inflate() is currently decoding the last block in the deflate stream,
// plus 128 if inflate() returned immediately after decoding an end-of-block
// code or decoding the complete header up to just before the first byte of the
// deflate stream. The end-of-block will not be indicated until all of the
// uncompressed data from that block has been written to strm.next_out. The
// number of unused bits may in general be greater than seven, except when
// bit 7 of data_type is set, in which case the number of unused bits will be
// less than eight.
// inflate() should normally be called until it returns Z_STREAM_END or an
// error. However if all decompression is to be performed in a single step
// (a single call of inflate), the parameter flush should be set to
// Z_FINISH. In this case all pending input is processed and all pending
// output is flushed; avail_out must be large enough to hold all the
// uncompressed data. (The size of the uncompressed data may have been saved
// by the compressor for this purpose.) The next operation on this stream must
// be inflateEnd to deallocate the decompression state. The use of Z_FINISH
// is never required, but can be used to inform inflate that a faster approach
// may be used for the single inflate() call.
// In this implementation, inflate() always flushes as much output as
// possible to the output buffer, and always uses the faster approach on the
// first call. So the only effect of the flush parameter in this implementation
// is on the return value of inflate(), as noted below, or when it returns early
// because Z_BLOCK is used.
// If a preset dictionary is needed after this call (see inflateSetDictionary
// below), inflate sets strm.adler to the adler32 checksum of the dictionary
// chosen by the compressor and returns Z_NEED_DICT; otherwise it sets
// strm.adler to the adler32 checksum of all output produced so far (that is,
// total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described
// below. At the end of the stream, inflate() checks that its computed adler32
// checksum is equal to that saved by the compressor and returns Z_STREAM_END
// only if the checksum is correct.
// inflate() will decompress and check either zlib-wrapped or gzip-wrapped
// deflate data. The header type is detected automatically. Any information
// contained in the gzip header is not retained, so applications that need that
// information should instead use raw inflate, see inflateInit2() below, or
// inflateBack() and perform their own processing of the gzip header and
// trailer.
// inflate() returns Z_OK if some progress has been made (more input processed
// or more output produced), Z_STREAM_END if the end of the compressed data has
// been reached and all uncompressed output has been produced, Z_NEED_DICT if a
// preset dictionary is needed at this point, Z_DATA_ERROR if the input data was
// corrupted (input stream not conforming to the zlib format or incorrect check
// value), Z_STREAM_ERROR if the stream structure was inconsistent (for example
// if next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory,
// Z_BUF_ERROR if no progress is possible or if there was not enough room in the
// output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and
// inflate() can be called again with more input and more output space to
// continue decompressing. If Z_DATA_ERROR is returned, the application may then
// call inflateSync() to look for a good compression block if a partial recovery
// of the data is desired.
public static int inflate(z_stream strm, int flush)
{
inflate_state state;
uint next; // next input
int put; // next output
uint have, left; // available input and output
uint hold; // bit buffer
uint bits; // bits in bit buffer
uint _in, _out; // save starting available input and output
uint copy; // number of stored or match bytes to copy
byte[] from; // where to copy match bytes from
int from_ind; // where to copy match bytes from
code here; // current decoding table entry
code last; // parent table entry
uint len; // length to copy for repeats, bits to drop
int ret; // return code
byte[] hbuf=new byte[4];// buffer for gzip header crc calculation
if(strm==null||strm.state==null||strm.out_buf==null||(strm.in_buf==null&&strm.avail_in!=0))
return Z_STREAM_ERROR;
byte[] in_buf=strm.in_buf;
byte[] out_buf=strm.out_buf;
state=(inflate_state)strm.state;
if(state.mode==inflate_mode.TYPE) state.mode=inflate_mode.TYPEDO; // skip check
//was LOAD();
put=strm.next_out;
left=strm.avail_out;
next=strm.next_in;
have=strm.avail_in;
hold=state.hold;
bits=state.bits;
_in=have;
_out=left;
ret=Z_OK;
for(; ; )
{
switch(state.mode)
{
case inflate_mode.HEAD:
if(state.wrap==0)
{
state.mode=inflate_mode.TYPEDO;
break;
}
//was NEEDBITS(16);
while(bits<16)
{
//was PULLBYTE();
if(have==0) goto inf_leave;
have--;
hold+=(uint)in_buf[next++]<<(int)bits;
bits+=8;
}
if((state.wrap&2)!=0&&hold==0x8b1f)
{ // gzip header
state.check=crc32(0, null, 0);
//was CRC2(state.check, hold);
hbuf[0]=(byte)hold;
hbuf[1]=(byte)(hold>>8);
state.check=crc32(state.check, hbuf, 2);
//was INITBITS();
hold=bits=0;
state.mode=inflate_mode.FLAGS;
break;
}
state.flags=0; // expect zlib header
if(state.head!=null) state.head.done=-1;
//was if(!(state.wrap & 1) || // check if zlib header allowed
// ((BITS(8)<<8)+(hold>>8))%31)
if((state.wrap&1)==0|| // check if zlib header allowed
((((hold&0xFF)<<8)+(hold>>8))%31)!=0)
{
strm.msg="incorrect header check";
state.mode=inflate_mode.BAD;
break;
}
//was if(BITS(4)!=Z_DEFLATED)
if((hold&0x0F)!=Z_DEFLATED)
{
strm.msg="unknown compression method";
state.mode=inflate_mode.BAD;
break;
}
//was DROPBITS(4);
hold>>=4;
bits-=4;
//was len=BITS(4)+8;
len=(hold&0x0F)+8;
if(state.wbits==0)
state.wbits=len;
else if(len>state.wbits)
{
strm.msg="invalid window size";
state.mode=inflate_mode.BAD;
break;
}
state.dmax=1U<<(int)len;
//Tracev((stderr, "inflate: zlib header ok\n"));
strm.adler=state.check=adler32(0, null, 0);
state.mode=(hold&0x200)!=0?inflate_mode.DICTID:inflate_mode.TYPE;
//was INITBITS();
hold=bits=0;
break;
case inflate_mode.FLAGS:
//was NEEDBITS(16);
while(bits<16)
{
//was PULLBYTE();
if(have==0) goto inf_leave;
have--;
hold+=(uint)in_buf[next++]<<(int)bits;
bits+=8;
}
state.flags=(int)hold;
if((state.flags&0xff)!=Z_DEFLATED)
{
strm.msg="unknown compression method";
state.mode=inflate_mode.BAD;
break;
}
if((state.flags&0xe000)!=0)
{
strm.msg="unknown header flags set";
state.mode=inflate_mode.BAD;
break;
}
if(state.head!=null) state.head.text=(int)((hold>>8)&1);
if((state.flags&0x0200)!=0)
{
//was CRC2(state.check, hold);
hbuf[0]=(byte)hold;
hbuf[1]=(byte)(hold>>8);
state.check=crc32(state.check, hbuf, 2);
}
//was INITBITS();
hold=bits=0;
state.mode=inflate_mode.TIME;
break; // no fall through
case inflate_mode.TIME:
//was NEEDBITS(32);
while(bits<32)
{
//was PULLBYTE();
if(have==0) goto inf_leave;
have--;
hold+=(uint)in_buf[next++]<<(int)bits;
bits+=8;
}
if(state.head!=null) state.head.time=hold;
if((state.flags&0x0200)!=0)
{
//was CRC4(state.check, hold);
hbuf[0]=(byte)hold;
hbuf[1]=(byte)(hold>>8);
hbuf[2]=(byte)(hold>>16);
hbuf[3]=(byte)(hold>>24);
state.check=crc32(state.check, hbuf, 4);
}
//was INITBITS();
hold=bits=0;
state.mode=inflate_mode.OS;
break; // no fall through
case inflate_mode.OS:
//was NEEDBITS(16);
while(bits<16)
{
//was PULLBYTE();
if(have==0) goto inf_leave;
have--;
hold+=(uint)in_buf[next++]<<(int)bits;
bits+=8;
}
if(state.head!=null)
{
state.head.xflags=(int)(hold&0xff);
state.head.os=(int)(hold>>8);
}
if((state.flags&0x0200)!=0)
{
//was CRC2(state.check, hold);
hbuf[0]=(byte)hold;
hbuf[1]=(byte)(hold>>8);
state.check=crc32(state.check, hbuf, 2);
}
//was INITBITS();
hold=bits=0;
state.mode=inflate_mode.EXLEN;
break; // no fall through
case inflate_mode.EXLEN:
if((state.flags&0x0400)!=0)
{
//was NEEDBITS(16);
while(bits<16)
{
//was PULLBYTE();
if(have==0) goto inf_leave;
have--;
hold+=(uint)in_buf[next++]<<(int)bits;
bits+=8;
}
state.length=hold;
if(state.head!=null) state.head.extra_len=hold;
if((state.flags&0x0200)!=0)
{
//was CRC2(state.check, hold);
hbuf[0]=(byte)hold;
hbuf[1]=(byte)(hold>>8);
state.check=crc32(state.check, hbuf, 2);
}
//was INITBITS();
hold=bits=0;
}
else if(state.head!=null) state.head.extra=null;
state.mode=inflate_mode.EXTRA;
break; // no fall through
case inflate_mode.EXTRA:
if((state.flags&0x0400)!=0)
{
copy=state.length;
if(copy>have) copy=have;
if(copy!=0)
{
if(state.head!=null&&state.head.extra!=null)
{
len=state.head.extra_len-state.length; // should be always zero!!!
//was zmemcpy(state.head.extra+len, next, (len+copy>state.head.extra_max)?state.head.extra_max-len:copy);
Array.Copy(in_buf, next, state.head.extra, len, (len+copy>state.head.extra_max)?state.head.extra_max-len:copy);
}
if((state.flags&0x0200)!=0) state.check=crc32(state.check, in_buf, (uint)next, copy);
have-=copy;
next+=copy;
state.length-=copy;
}
if(state.length!=0) goto inf_leave;
}
state.length=0;
state.mode=inflate_mode.NAME;
break; // no fall through
case inflate_mode.NAME:
if((state.flags&0x0800)!=0)
{
if(have==0) goto inf_leave;
copy=0;
do
{
//was len=next[copy++];
len=in_buf[next+copy++];
if(state.head!=null&&state.head.name!=null&&state.length<state.head.name_max)
state.head.name[state.length++]=(byte)len;
} while(len!=0&©<have);
if((state.flags&0x0200)!=0) state.check=crc32(state.check, in_buf, (uint)next, copy);
have-=copy;
next+=copy;
if(len!=0) goto inf_leave;
}
else if(state.head!=null) state.head.name=null;
state.length=0;
state.mode=inflate_mode.COMMENT;
break; // no fall through
case inflate_mode.COMMENT:
if((state.flags&0x1000)!=0)
{
if(have==0) goto inf_leave;
copy=0;
do
{
//was len=next[copy++];
len=in_buf[next+copy++];
if(state.head!=null&&state.head.comment!=null&&state.length<state.head.comm_max)
state.head.comment[state.length++]=(byte)len;
} while(len!=0&©<have);
if((state.flags&0x0200)!=0) state.check=crc32(state.check, in_buf, (uint)next, copy);
have-=copy;
next+=copy;
if(len!=0) goto inf_leave;
}
else if(state.head!=null) state.head.comment=null;
state.mode=inflate_mode.HCRC;
break; // no fall through
case inflate_mode.HCRC:
if((state.flags&0x0200)!=0)
{
//was NEEDBITS(16);
while(bits<16)
{
//was PULLBYTE();
if(have==0) goto inf_leave;
have--;
hold+=(uint)in_buf[next++]<<(int)bits;
bits+=8;
}
if(hold!=(state.check&0xffff))
{
strm.msg="header crc mismatch";
state.mode=inflate_mode.BAD;
break;
}
//was INITBITS();
hold=bits=0;
}
if(state.head!=null)
{
state.head.hcrc=(int)((state.flags>>9)&1);
state.head.done=1;
}
strm.adler=state.check=crc32(0, null, 0);
state.mode=inflate_mode.TYPE;
break;
case inflate_mode.DICTID:
//was NEEDBITS(32);
while(bits<32)
{
//was PULLBYTE();