2 * tinf - tiny inflate library (inflate, gzip, zlib)
5 * Copyright (c) 2003 by Joergen Ibsen / Jibz
8 * http://www.ibsensoftware.com/
10 * This software is provided 'as-is', without any express
11 * or implied warranty. In no event will the authors be
12 * held liable for any damages arising from the use of
15 * Permission is granted to anyone to use this software
16 * for any purpose, including commercial applications,
17 * and to alter it and redistribute it freely, subject to
18 * the following restrictions:
20 * 1. The origin of this software must not be
21 * misrepresented; you must not claim that you
22 * wrote the original software. If you use this
23 * software in a product, an acknowledgment in
24 * the product documentation would be appreciated
25 * but is not required.
27 * 2. Altered source versions must be plainly marked
28 * as such, and must not be misrepresented as
29 * being the original software.
31 * 3. This notice may not be removed or altered from
32 * any source distribution.
35 * This D port was made by Ketmar // Invisible Vector
36 * ketmar@ketmar.no-ip.org
37 * the original code was heavily changed ang uglified (sorry!)
39 module iv
.vfs
.inflate
/*is aliced*/;
43 ////////////////////////////////////////////////////////////////////////////////
45 * Adler-32 algorithm taken from the zlib source, which is
46 * Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler
48 /// Adler-32 checksum computer
52 enum { BASE
= 65521, NMAX
= 5552 }
53 enum normS1S2
= `s1 %= BASE; s2 %= BASE;`;
55 template genByteProcessors(int count
) {
57 enum genByteProcessors
= `s1 += *dta++;s2 += s1;`~genByteProcessors
!(count
-1);
59 enum genByteProcessors
= "";
67 * Computes the Adler-32 checksum. We can do `Adler32(buf)`.
75 static uint opCall(T
) (T
[] data
) {
87 /// get current Adler-32 sum
88 @property uint result () const pure { return ((s2
<<16)|s1
); }
91 void doBuffer(T
) (T
[] data
) @trusted {
92 if (data
.length
== 0) return;
93 usize len
= data
.length
*data
[0].sizeof
; // length in bytes
94 const(ubyte)* dta
= cast(const(ubyte)*)data
.ptr
;
95 foreach (immutable _
; 0..len
/NMAX
) {
96 foreach (immutable _
; 0..NMAX
/16) { mixin(genByteProcessors
!(16)); }
101 foreach (immutable _
; 0..len
) { mixin(genByteProcessors
!(1)); }
107 void doByte(T
) (T
bt)
109 if (is(T
== char) ||
is(T
== byte) ||
is(T
== ubyte) ||
110 is(T
== const char) ||
is(T
== const byte) ||
is(T
== const ubyte) ||
111 is(T
== immutable char) ||
is(T
== immutable byte) ||
is(T
== immutable ubyte))
121 * Computes the Adler-32 checksum.
129 alias adler32
= Adler32
;
132 // -----------------------------------------------------------------------------
133 // internal data structures
135 private struct Tree
{
136 ushort[16] table
; // table of code length counts
137 ushort[288] trans
; // code -> symbol translation table
139 @disable this (this); // disable copying
141 // given an array of code lengths, build a tree
142 void buildTree (const(ubyte)[] lengths
) @trusted {
143 if (lengths
.length
< 1) throw new Exception("invalid lengths");
144 ushort[16] offs
= void;
146 // clear code length count table
148 // scan symbol lengths, and sum code length counts
149 foreach (immutable l
; lengths
) {
150 if (l
>= 16) throw new Exception("invalid lengths");
154 // compute offset table for distribution sort
155 foreach (immutable i
, immutable n
; table
) {
159 // create code->symbol translation table (symbols sorted by code)
160 foreach (ushort i
, immutable l
; lengths
) {
162 auto n
= offs
.ptr
[l
]++;
163 if (n
>= 288) throw new Exception("invalid lengths");
171 // -----------------------------------------------------------------------------
172 // stream of unpacked data
176 alias ReadBufDg
= int delegate (ubyte[] buf
);
179 // return number of bytes read, -1 on error, 0 on eof; can read less than requested
180 //ReadBufDg readBuf = null;
183 uint bytesLeft
= void; // bytes to copy both for compressed and for uncompressed blocks
184 uint matchOfs
= void; // match offset for inflated block
185 const(Tree
)* lt
= void; // dynamic length/symbol tree
186 const(Tree
)* dt = void; // dynamic distance tree
187 bool doingFinalBlock
= false; // stop on next processBlockHeader()
191 ExpectZLibHeader
, // expecting ZLib header
192 ExpectBlock
, // expecting new block
193 RawBlock
, // uncompressed block
195 EOF
, // readOneByte() returns false before block header
196 Dead
, // some error occured, throw exception on any read
198 State state
= State
.ExpectZLibHeader
;
199 Mode mode
= Mode
.ZLib
;
206 Tree ltree
; // dynamic length/symbol tree
207 Tree dtree
; // dynamic distance tree
211 uint nmaxLeft
= Adler32
.NMAX
;
215 ubyte[65536] dict
= void;
216 uint dictEnd
; // current dict free byte
218 ubyte[65536] rdbuf
= void;
223 enum DictPutByteMixin
= q
{{
224 if (dictEnd
== dict
.length
) {
225 import core
.stdc
.string
: memmove
;
227 memmove(dict
.ptr
, dict
.ptr
+dictEnd
-32768, 32768);
230 dict
.ptr
[dictEnd
++] = bt;
231 if (mode
== Mode
.ZLib
) {
234 if (--nmaxLeft
== 0) {
235 nmaxLeft
= Adler32
.NMAX
;
236 a32s1
%= Adler32
.BASE
;
237 a32s2
%= Adler32
.BASE
;
242 uint finishAdler32 () nothrow @safe @nogc {
243 pragma(inline
, true);
244 a32s1
%= Adler32
.BASE
;
245 a32s2
%= Adler32
.BASE
;
246 return (a32s2
<<16)|a32s1
;
249 static template StrOr(string v
, string def
) {
250 static if (v
.length
== 0) enum StrOr
= def
; else enum StrOr
= v
;
253 enum ReadOneByteMixin(string dvar
, string oneof
="") = "{
254 //if (readBuf is null) rbeof = true;
256 "~StrOr
!(oneof
, `throw new Exception("out of data for inflate");`)~"
258 if (rbpos >= rbused) {
260 if ((rbused = readBuf(rdbuf[])) <= 0) {
262 if (rbused < 0) throw new Exception(`inflate read error`);
263 "~StrOr
!(oneof
, `throw new Exception("out of data for inflate");`)~"
266 //assert(rbpos < rbused);
267 "~dvar
~" = rdbuf.ptr[rbpos++];
271 void setErrorState () nothrow @safe @nogc {
273 lt
= dt = null; // just in case
274 doingFinalBlock
= false; // just in case too
277 void processZLibHeader (scope ReadBufDg readBuf
) @trusted {
278 scope(failure
) setErrorState();
281 // compression parameters
282 //if (!readOneByte(readBuf, cmf)) throw new Exception("out of input data");
283 mixin(ReadOneByteMixin
!"cmf");
285 //if (!readOneByte(readBuf, flg)) throw new Exception("out of input data");
286 mixin(ReadOneByteMixin
!"flg");
289 if ((256*cmf
+flg
)%31) throw new Exception("invalid zlib checksum");
290 // check method (only deflate allowed)
291 if ((cmf
&0x0f) != 8) throw new Exception("invalid compression method");
293 if ((cmf
>>4) > 7) throw new Exception("invalid window size");
294 // there must be no preset dictionary
295 if (flg
&0x20) throw new Exception("preset dictionaries are not supported");
296 // FYI: flg>>6 will give you compression level:
297 // 0 - compressor used fastest algorithm
298 // 1 - compressor used fast algorithm
299 // 2 - compressor used default algorithm
300 // 3 - compressor used maximum compression, slowest algorithm
301 // not that you can make any sane use of that info though...
302 // note that last 4 bytes is Adler32 checksum in big-endian format
303 // init Adler32 counters
306 nmaxLeft
= Adler32
.NMAX
;
308 state
= State
.ExpectBlock
;
311 void finishZLibData (scope ReadBufDg readBuf
) {
313 scope(failure
) setErrorState();
314 uint a32
; // autoinit
316 foreach_reverse (immutable n
; 0..4) {
317 //if (!readOneByte(readBuf, bt)) throw new Exception("out of input data");
318 mixin(ReadOneByteMixin
!"bt");
319 a32 |
= (cast(uint)bt)<<(n
*8);
321 if (a32
!= finishAdler32()) throw new Exception("invalid checksum");
324 // get one bit from source stream to `ubyte onebit`
325 enum GetBitMixin
= q
{{
327 scope(failure
) setErrorState();
328 //if (!readOneByte(readBuf, onebit)) throw new Exception("out of input data");
329 mixin(ReadOneByteMixin
!"onebit");
337 // read a num bit value from a stream and add base
338 enum ReadBitsMixin(string dvar
, string num
, string base
) = "{
342 immutable uint limit = 1<<"~num
~";
343 for (uint mask = 1; mask < limit; mask <<= 1) {
344 //if (getBit(readBuf)) val += mask;
346 if (onebit) val += mask;
349 "~dvar
~" = cast(typeof("~dvar
~"))(val+"~base
~");
352 // given a data stream and a tree, decode a symbol
353 uint decodeSymbol (scope ReadBufDg readBuf
, const(Tree
*) t
) {
354 scope(failure
) setErrorState();
355 int cur
, sum
, len
; // autoinit
357 // get more bits while code value is above sum
359 //cur = 2*cur+getBit(readBuf);
363 if (len
>= 16) throw new Exception("invalid symbol");
364 ushort sl
= t
.table
.ptr
[len
];
369 if (sum
< 0 || sum
>= 288) throw new Exception("invalid symbol");
370 return t
.trans
.ptr
[sum
];
373 // given a data stream, decode dynamic trees from it
374 void decodeTrees (scope ReadBufDg readBuf
) {
375 scope(failure
) setErrorState();
376 // special ordering of code length codes
377 static immutable ubyte[19] clcidx
= [16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15];
379 ubyte[288+32] lengths
;
380 uint hlit
, hdist
, hclen
;
382 // get 5 bits HLIT (257-286)
383 //hlit = readBits(readBuf, 5, 257);
384 mixin(ReadBitsMixin
!("hlit", "5", "257"));
385 // get 5 bits HDIST (1-32)
386 //hdist = readBits(readBuf, 5, 1);
387 mixin(ReadBitsMixin
!("hdist", "5", "1"));
388 if (hlit
+hdist
> 288+32) throw new Exception("invalid tree");
389 // get 4 bits HCLEN (4-19)
390 //hclen = readBits(readBuf, 4, 4);
391 mixin(ReadBitsMixin
!("hclen", "4", "4"));
392 if (hclen
> 19) throw new Exception("invalid tree");
393 lengths
.ptr
[0..19] = 0;
394 // read code lengths for code length alphabet
395 foreach (immutable i
; 0..hclen
) {
396 //lengths[clcidx[i]] = cast(ubyte)readBits(readBuf, 3, 0); // get 3 bits code length (0-7)
397 mixin(ReadBitsMixin
!("lengths.ptr[clcidx.ptr[i]]", "3", "0")); // get 3 bits code length (0-7)
399 // build code length tree
400 codeTree
.buildTree(lengths
.ptr
[0..19]);
401 // decode code lengths for the dynamic trees
402 for (num
= 0; num
< hlit
+hdist
; ) {
404 uint sym
= decodeSymbol(readBuf
, &codeTree
);
406 case 16: // copy previous code length 3-6 times (read 2 bits)
407 if (num
== 0) throw new Exception("invalid tree");
408 bt = lengths
.ptr
[num
-1];
409 //length = readBits(readBuf, 2, 3);
410 mixin(ReadBitsMixin
!("length", "2", "3"));
412 case 17: // repeat code length 0 for 3-10 times (read 3 bits)
414 //length = readBits(readBuf, 3, 3);
415 mixin(ReadBitsMixin
!("length", "3", "3"));
417 case 18: // repeat code length 0 for 11-138 times (read 7 bits)
419 //length = readBits(readBuf, 7, 11);
420 mixin(ReadBitsMixin
!("length", "7", "11"));
422 default: // values 0-15 represent the actual code lengths
423 if (sym
>= 19) throw new Exception("invalid tree symbol");
429 if (num
+length
> 288+32) throw new Exception("invalid tree");
430 while (length
-- > 0) lengths
.ptr
[num
++] = bt;
432 // build dynamic trees
433 ltree
.buildTree(lengths
.ptr
[0..hlit
]);
434 dtree
.buildTree(lengths
.ptr
[hlit
..hlit
+hdist
]);
437 // can return zero-length slice (on state switch, for example)
438 ubyte[] processInflatedBlock (scope ReadBufDg readBuf
, ubyte[] btdest
) {
439 auto btleft
= btdest
.length
;
440 ubyte* dest
= btdest
.ptr
;
443 // copying match; all checks already done
445 ubyte bt = dict
.ptr
[dictEnd
-matchOfs
];
446 mixin(DictPutByteMixin
);
451 uint sym
= decodeSymbol(readBuf
, lt
);
453 // end of block, fix state
454 state
= State
.ExpectBlock
;
460 ubyte bt = cast(ubyte)sym
;
461 mixin(DictPutByteMixin
);
465 scope(failure
) setErrorState();
467 uint dist
, length
, offs
;
469 // possibly get more bits from length code
470 if (sym
>= 30) throw new Exception("invalid symbol");
471 //length = readBits(readBuf, lengthBits[sym], lengthBase[sym]);
472 mixin(ReadBitsMixin
!("length", "lengthBits[sym]", "lengthBase[sym]"));
473 dist
= decodeSymbol(readBuf
, dt);
474 if (dist
>= 30) throw new Exception("invalid distance");
475 // possibly get more bits from distance code
476 //offs = readBits(readBuf, distBits[dist], distBase[dist]);
477 mixin(ReadBitsMixin
!("offs", "distBits[dist]", "distBase[dist]"));
478 if (offs
> dictEnd
) throw new Exception("invalid distance");
482 //return false; // no byte read yet
486 return btdest
[0..$-btleft
];
489 // can return zero-length slice (on state switch, for example)
490 ubyte[] processUncompressedBlock (scope ReadBufDg readBuf
, ubyte[] btdest
) {
491 auto btleft
= btdest
.length
;
492 ubyte* dest
= btdest
.ptr
;
493 while (btleft
> 0 && bytesLeft
> 0) {
495 scope(failure
) setErrorState();
496 //if (!readOneByte(readBuf, *dest)) throw new Exception("out of input data");
497 mixin(ReadOneByteMixin
!"*dest");
499 mixin(DictPutByteMixin
);
503 if (bytesLeft
== 0) {
504 // end of block, fix state
505 state
= State
.ExpectBlock
;
507 return btdest
[0..$-btleft
];
510 ushort readU16 (scope ReadBufDg readBuf
) {
511 scope(failure
) setErrorState();
512 ubyte b0
= void, b1
= void;
513 //if (!readOneByte(readBuf, b0)) throw new Exception("out of input data");
514 mixin(ReadOneByteMixin
!"b0");
515 //if (!readOneByte(readBuf, b1)) throw new Exception("out of input data");
516 mixin(ReadOneByteMixin
!"b1");
517 return cast(ushort)(b0|
(b1
<<8));
520 void processRawHeader (scope ReadBufDg readBuf
) {
521 ushort length
= readU16(readBuf
);
522 ushort invlength
= readU16(readBuf
); // one's complement of length
524 if (length
!= cast(ushort)(~(invlength
))) { setErrorState(); throw new Exception("invalid uncompressed block length"); }
525 bitcount
= 0; // make sure we start next block on a byte boundary
527 state
= State
.RawBlock
;
530 void processFixedHeader (scope ReadBufDg readBuf
) nothrow @safe @nogc {
533 bytesLeft
= 0; // force reading of symbol (just in case)
534 state
= State
.CompressedBlock
;
537 void processDynamicHeader (scope ReadBufDg readBuf
) {
538 // decode trees from stream
539 decodeTrees(readBuf
);
542 bytesLeft
= 0; // force reading of symbol (just in case)
543 state
= State
.CompressedBlock
;
546 // set state to State.EOF on correct EOF
547 void processBlockHeader (scope ReadBufDg readBuf
) {
548 if (doingFinalBlock
) {
549 if (mode
== Mode
.ZLib
) finishZLibData(readBuf
);
550 doingFinalBlock
= false;
554 //doingFinalBlock = (getBit(readBuf) != 0); // final block flag
558 doingFinalBlock
= (onebit
!= 0);
560 // read block type (2 bits) and fix state
562 mixin(ReadBitsMixin
!("btype", "2", "0"));
563 switch (/*readBits(readBuf, 2, 0)*/btype
) {
564 case 0: processRawHeader(readBuf
); break; // uncompressed block
565 case 1: processFixedHeader(readBuf
); break; // block with fixed huffman trees
566 case 2: processDynamicHeader(readBuf
); break; // block with dynamic huffman trees
567 default: setErrorState(); throw new Exception("invalid input block type");
573 enum Mode
{ ZLib
, Deflate
}
576 @disable this (this);
579 * Initialize decompression stream.
583 * must either set bt to next byte and return true or return false on EOF;
584 * note that it will not be called anymore after EOF or error;
586 * amode = stream format; either headerless 'deflate' stream or 'zlib' stream
591 this (Mode amode
/*=Mode.ZLib*/) {
596 void reinit (Mode amode
=Mode
.ZLib
) {
603 state
= (amode
== Mode
.ZLib ? State
.ExpectZLibHeader
: State
.ExpectBlock
);
604 doingFinalBlock
= false;
608 * Check stream header. Can be called after this() or reinit().
616 void checkStreamHeader (scope ReadBufDg readBuf
) {
617 if (mode
== Mode
.ZLib
&& state
== State
.ExpectZLibHeader
) processZLibHeader(readBuf
);
621 * Get bytes from stream.
624 * slice of `btdest`; can be zero-length
629 ubyte[] getBytes (scope ReadBufDg readBuf
, ubyte[] btdest
) {
631 mainloop
: while (btpos
< btdest
.length
) {
632 //{ import core.stdc.stdio; printf("btpos=%u; btlen=%u; state=%u\n", cast(uint)btpos, cast(uint)btdest.length, cast(uint)state); }
633 final switch (state
) {
634 case State
.ExpectZLibHeader
:
635 processZLibHeader(readBuf
);
637 case State
.ExpectBlock
:
638 processBlockHeader(readBuf
);
641 auto rd
= processUncompressedBlock(readBuf
, btdest
[btpos
..$]);
644 case State
.CompressedBlock
:
645 auto rd
= processInflatedBlock(readBuf
, btdest
[btpos
..$]);
648 case State
.EOF
: break mainloop
;
649 case State
.Dead
: setErrorState(); throw new Exception("dead stream"); break;
652 //DONE: MOVE THIS TO READERS!
654 return btdest
[0..btpos
];
658 * Get another byte from stream.
661 * one decompressed byte
664 * Exception on EOF/error
666 ubyte getByte (scope ReadBufDg readBuf
) {
668 auto rd
= getBytes(readBuf
, (&res
)[0..1]);
669 if (rd
.length
== 0) throw new Exception("no more data");
674 * Read bytes from stream. Almost similar to File.rawRead().
677 * buf = destination buffer
680 * destination buffer or slice of destination buffer if EOF encountered
685 T
[] rawRead(T
) (scope ReadBufDg readBuf
, T
[] buf
) {
686 auto len
= buf
.length
*T
.sizeof
;
687 if (len
== 0) return buf
;
688 auto dst
= cast(ubyte*)buf
.ptr
;
689 auto rd
= getBytes(readBuf
, dst
[0..len
]);
690 // check if the last 'dest' item is fully decompressed
691 static if (T
.sizeof
> 1) { if (rd
.length
%T
.sizeof
) { setErrorState(); throw new Exception("partial data"); } }
692 return buf
[0..rd
.length
/T
.sizeof
];
695 @property const pure nothrow @safe @nogc {
696 bool eof () { return (state
== State
.EOF
); }
697 bool invalid () { return (state
== State
.Dead
); }
702 // -----------------------------------------------------------------------------
704 // private global data
705 // build it using CTFE
707 // fixed length/symbol tree
708 static immutable Tree sltree
= (){
713 foreach (immutable i
; 0..24) sl
.trans
[i
] = cast(ushort)(256+i
);
714 foreach (immutable ushort i
; 0..144) sl
.trans
[24+i
] = i
;
715 foreach (immutable i
; 0..8) sl
.trans
[24+144+i
] = cast(ushort)(280+i
);
716 foreach (immutable i
; 0..112) sl
.trans
[24+144+8+i
] = cast(ushort)(144+i
);
720 // fixed distance tree
721 static immutable Tree sdtree
= (){
724 foreach (immutable ushort i
; 0..32) sd
.trans
[i
] = i
;
728 void fillBits (ubyte[] bits
, uint delta
) @safe nothrow {
730 foreach (immutable i
; 0..30-delta
) bits
[i
+delta
] = cast(ubyte)(i
/delta
);
733 void fillBase (ushort[] base
, immutable(ubyte[30]) bits
, ushort first
) @safe nothrow {
735 foreach (immutable i
; 0..30) {
741 // extra bits and base tables for length codes
742 static immutable ubyte[30] lengthBits
= (){
745 bits
[28] = 0; // fix a special case
749 static immutable ushort[30] lengthBase
= (){
753 fillBase(base
, bits
, 3);
754 base
[28] = 258; // fix a special case
758 // extra bits and base tables for distance codes
759 static immutable ubyte[30] distBits
= (){
765 static immutable ushort[30] distBase
= (){
766 enum bits
= distBits
;
768 fillBase(base
, bits
, 1);