1 ! Copyright (C) 2009 Marc Fauconneau.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: accessors arrays assocs byte-vectors combinators
4 compression.huffman fry hashtables io.binary kernel locals math
5 math.bitwise math.order math.ranges sequences sorting ;
6 QUALIFIED-WITH: bitstreams bs
7 IN: compression.inflate
9 QUALIFIED-WITH: bitstreams bs
13 : enum>seq ( assoc -- seq )
14 dup keys [ ] [ max ] map-reduce 1 + f <array>
15 [ '[ swap _ set-nth ] assoc-each ] keep ;
17 ERROR: zlib-unimplemented ;
18 ERROR: bad-zlib-data ;
19 ERROR: bad-zlib-header ;
21 :: check-zlib-header ( data -- )
22 16 data bs:peek 2 >le be> 31 mod ! checksum
24 4 data bs:read 8 assert= ! compression method: deflate
25 4 data bs:read ! log2(max length)-8, 32K max
26 7 <= [ bad-zlib-header ] unless
27 5 data bs:seek ! drop check bits
28 1 data bs:read 0 assert= ! dictionnary - not allowed in png
29 2 data bs:seek ! compression level; ignore
32 :: default-table ( -- table )
33 0 <hashtable> :> table
34 0 143 [a,b] 280 287 [a,b] append 8 table set-at
35 144 255 [a,b] >array 9 table set-at
36 256 279 [a,b] >array 7 table set-at
37 table enum>seq 1 tail ;
39 CONSTANT: clen-shuffle { 16 17 18 0 8 7 9 6 10 5 11 4 12 3 13 2 14 1 15 }
41 : get-table ( values size -- table )
42 16 f <array> clone <enum>
43 [ '[ _ push-at ] 2each ] keep seq>> 1 tail [ natural-sort ] map ;
45 :: decode-huffman-tables ( bitstream -- tables )
46 5 bitstream bs:read 257 +
47 5 bitstream bs:read 1 +
48 4 bitstream bs:read 4 +
49 clen-shuffle swap head
50 dup [ drop 3 bitstream bs:read ] map
52 bitstream swap <huffman-decoder>
53 [ 2dup + ] dip swap :> k!
57 { [ dup 16 = ] [ 2 bitstream bs:read 3 + 2array ] }
58 { [ dup 17 = ] [ 3 bitstream bs:read 3 + 2array ] }
59 { [ dup 18 = ] [ 7 bitstream bs:read 11 + 2array ] }
62 dup array? [ dup second ] [ 1 ] if
65 [ ] produce swap suffix
66 { } [ dup array? [ dup first 16 = ] [ f ] if [ [ unclip-last ] [ second 1 + swap <repetition> append ] bi* ] [ suffix ] if ] reduce
67 [ dup array? [ second 0 <repetition> ] [ 1array ] if ] map concat
68 nip swap cut 2array [ [ length>> [0,b) ] [ ] bi get-table ] map ;
70 CONSTANT: length-table
92 : nth* ( n seq -- elt )
93 [ length 1 - swap - ] [ nth ] bi ;
95 :: inflate-lz77 ( seq -- bytes )
96 1000 <byte-vector> :> bytes
100 [ first2 '[ _ 1 - bytes nth* bytes push ] times ]
105 :: inflate-dynamic ( bitstream -- bytes )
106 bitstream decode-huffman-tables
107 bitstream '[ _ swap <huffman-decoder> ] map :> tables
109 tables first read1-huff2
117 dup 261 - 4 /i dup 5 >
118 [ bad-zlib-data ] when
119 bitstream bs:read 2array
123 ! 5 bitstream read-bits ! distance
124 tables second read1-huff2
127 dup 2 - 2 /i dup 13 >
128 [ bad-zlib-data ] when
129 bitstream bs:read 2array
142 dup array? [ first2 ] [ 0 ] if
143 [ 257 - length-table nth ] [ + ] bi*
146 dup array? [ first2 ] [ 0 ] if
147 [ dist-table nth ] [ + ] bi*
153 :: inflate-raw ( bitstream -- bytes )
155 16 bitstream bs:read :> len
156 16 bitstream bs:read :> nlen
157 len nlen + 16 >signed -1 assert= ! len + ~len = -1
159 bitstream byte-pos>> len +
160 bitstream bytes>> <slice>
161 len 8 * bitstream bs:seek ;
163 : inflate-static ( bitstream -- bytes ) zlib-unimplemented ;
165 :: inflate-loop ( bitstream -- bytes )
166 [ 1 bitstream bs:read 0 = ]
171 { 0 [ inflate-raw ] }
172 { 1 [ inflate-static ] }
173 { 2 [ inflate-dynamic ] }
174 { 3 [ bad-zlib-data f ] }
178 [ produce ] keep call suffix concat ;
182 : zlib-inflate ( bytes -- bytes )
184 [ check-zlib-header ] [ inflate-loop ] bi