]> gitweb.factorcode.org Git - factor.git/blob - basis/compression/inflate/inflate.factor
move the png filtering code to images.png
[factor.git] / basis / compression / inflate / inflate.factor
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
8
9 QUALIFIED-WITH: bitstreams bs
10
11 <PRIVATE
12
13 : enum>seq ( assoc -- seq )
14     dup keys [ ] [ max ] map-reduce 1 + f <array>
15     [ '[ swap _ set-nth ] assoc-each ] keep ;
16
17 ERROR: zlib-unimplemented ;
18 ERROR: bad-zlib-data ;
19 ERROR: bad-zlib-header ;
20     
21 :: check-zlib-header ( data -- )
22     16 data bs:peek 2 >le be> 31 mod    ! checksum
23     0 assert=                           
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
30     ;
31
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 ;
38
39 CONSTANT: clen-shuffle { 16 17 18 0 8 7 9 6 10 5 11 4 12 3 13 2 14 1 15 }
40
41 : get-table ( values size -- table ) 
42     16 f <array> clone <enum> 
43     [ '[ _ push-at ] 2each ] keep seq>> 1 tail [ natural-sort ] map ;
44
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
51     get-table
52     bitstream swap <huffman-decoder> 
53     [ 2dup + ] dip swap :> k!
54     '[
55         _ read1-huff2
56         {
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 ] }
60             [ ]
61         } cond
62         dup array? [ dup second ] [ 1 ] if
63         k swap - dup k! 0 >
64     ] 
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 ;
69     
70 CONSTANT: length-table
71     {
72         3 4 5 6 7 8 9 10
73         11 13 15 17
74         19 23 27 31
75         35 43 51 59
76         67 83 99 115
77         131 163 195 227 258
78     }
79
80 CONSTANT: dist-table
81     {
82         1 2 3 4 
83         5 7 9 13 
84         17 25 33 49
85         65 97 129 193
86         257 385 513 769
87         1025 1537 2049 3073
88         4097 6145 8193 12289
89         16385 24577
90     }
91
92 : nth* ( n seq -- elt )
93     [ length 1 - swap - ] [ nth ] bi ;
94
95 :: inflate-lz77 ( seq -- bytes )
96     1000 <byte-vector> :> bytes
97     seq
98     [
99         dup array?
100         [ first2 '[ _ 1 - bytes nth* bytes push ] times ]
101         [ bytes push ] if
102     ] each 
103     bytes ;
104
105 :: inflate-dynamic ( bitstream -- bytes )
106     bitstream decode-huffman-tables
107     bitstream '[ _ swap <huffman-decoder> ] map :> tables
108     [
109         tables first read1-huff2
110         dup 256 >
111         [
112             dup 285 = 
113             [ ]
114             [ 
115                 dup 264 > 
116                 [ 
117                     dup 261 - 4 /i dup 5 > 
118                     [ bad-zlib-data ] when 
119                     bitstream bs:read 2array 
120                 ]
121                 when 
122             ] if
123             ! 5 bitstream read-bits ! distance
124             tables second read1-huff2
125             dup 3 > 
126             [ 
127                 dup 2 - 2 /i dup 13 >
128                 [ bad-zlib-data ] when
129                 bitstream bs:read 2array
130             ] 
131             when
132             2array
133         ]
134         when
135         dup 256 = not
136     ]
137     [ ] produce nip
138     [
139         dup array? [
140             first2
141             [  
142                 dup array? [ first2 ] [ 0 ] if
143                 [ 257 - length-table nth ] [ + ] bi*
144             ] 
145             [
146                 dup array? [ first2 ] [ 0 ] if
147                 [ dist-table nth ] [ + ] bi*
148             ] bi*
149             2array
150         ] when
151     ] map ;
152     
153 :: inflate-raw ( bitstream -- bytes ) 
154     8 bitstream bs:align 
155     16 bitstream bs:read :> len
156     16 bitstream bs:read :> nlen
157     len nlen + 16 >signed -1 assert= ! len + ~len = -1
158     bitstream byte-pos>>
159     bitstream byte-pos>> len +
160     bitstream bytes>> <slice>
161     len 8 * bitstream bs:seek ;
162
163 : inflate-static ( bitstream -- bytes ) zlib-unimplemented ;
164
165 :: inflate-loop ( bitstream -- bytes )
166     [ 1 bitstream bs:read 0 = ]
167     [
168         bitstream
169         2 bitstream bs:read
170         { 
171             { 0 [ inflate-raw ] }
172             { 1 [ inflate-static ] }
173             { 2 [ inflate-dynamic ] }
174             { 3 [ bad-zlib-data f ] }
175         }
176         case
177     ]
178     [ produce ] keep call suffix concat ;
179
180 PRIVATE>
181
182 : zlib-inflate ( bytes -- bytes )
183     bs:<lsb0-bit-reader>
184     [ check-zlib-header ] [ inflate-loop ] bi
185     inflate-lz77 ;