171 lines
5.0 KiB
Factor
171 lines
5.0 KiB
Factor
! Copyright (C) 2009 Marc Fauconneau.
|
|
! See http://factorcode.org/license.txt for BSD license.
|
|
USING: accessors arrays assocs byte-vectors combinators
|
|
combinators.smart compression.huffman fry hashtables io.binary
|
|
kernel literals locals math math.bitwise math.order math.ranges
|
|
sequences sorting memoize combinators.short-circuit byte-arrays ;
|
|
QUALIFIED-WITH: bitstreams bs
|
|
IN: compression.inflate
|
|
|
|
<PRIVATE
|
|
|
|
ERROR: zlib-unimplemented ;
|
|
ERROR: bad-zlib-data ;
|
|
ERROR: bad-zlib-header ;
|
|
|
|
:: check-zlib-header ( data -- )
|
|
16 data bs:peek 2 >le be> 31 mod ! checksum
|
|
0 assert=
|
|
4 data bs:read 8 assert= ! compression method: deflate
|
|
4 data bs:read ! log2(max length)-8, 32K max
|
|
7 <= [ bad-zlib-header ] unless
|
|
5 data bs:seek ! drop check bits
|
|
1 data bs:read 0 assert= ! dictionary - not allowed in png
|
|
2 data bs:seek ! compression level; ignore
|
|
;
|
|
|
|
CONSTANT: clen-shuffle { 16 17 18 0 8 7 9 6 10 5 11 4 12 3 13 2 14 1 15 }
|
|
|
|
: get-table ( values size -- table )
|
|
16 f <array> <enum>
|
|
[ '[ _ push-at ] 2each ] keep
|
|
seq>> rest-slice [ natural-sort ] map ; inline
|
|
|
|
:: decode-huffman-tables ( bitstream -- tables )
|
|
5 bitstream bs:read 257 +
|
|
5 bitstream bs:read 1 +
|
|
4 bitstream bs:read 4 + clen-shuffle swap head
|
|
|
|
dup length [ 3 bitstream bs:read ] replicate
|
|
get-table
|
|
bitstream swap <huffman-decoder>
|
|
[ 2dup + ] dip swap :> k!
|
|
'[
|
|
_ read1-huff2 {
|
|
{ [ dup 16 = ] [ 2 bitstream bs:read 3 + 2array ] }
|
|
{ [ dup 17 = ] [ 3 bitstream bs:read 3 + 2array ] }
|
|
{ [ dup 18 = ] [ 7 bitstream bs:read 11 + 2array ] }
|
|
[ ]
|
|
} cond
|
|
dup array? [ dup second ] [ 1 ] if
|
|
k swap - dup k! 0 >
|
|
] [ ] produce swap suffix
|
|
{ } [
|
|
dup { [ array? ] [ first 16 = ] } 1&& [
|
|
[ unclip-last-slice ]
|
|
[ second 1 + swap <repetition> append ] bi*
|
|
] [
|
|
suffix
|
|
] if
|
|
] reduce
|
|
[ dup array? [ second 0 <repetition> ] [ 1array ] if ] map concat
|
|
nip swap cut 2array
|
|
[ [ length>> iota ] [ ] bi get-table ] map ;
|
|
|
|
MEMO: static-huffman-tables ( -- obj )
|
|
[
|
|
0 143 [a,b] length [ 8 ] replicate
|
|
144 255 [a,b] length [ 9 ] replicate append
|
|
256 279 [a,b] length [ 7 ] replicate append
|
|
280 287 [a,b] length [ 8 ] replicate append
|
|
] append-outputs
|
|
0 31 [a,b] length [ 5 ] replicate 2array
|
|
[ [ length>> iota ] [ ] bi get-table ] map ;
|
|
|
|
CONSTANT: length-table
|
|
{
|
|
3 4 5 6 7 8 9 10 11 13 15 17 19 23 27 31
|
|
35 43 51 59 67 83 99 115 131 163 195 227 258
|
|
}
|
|
|
|
CONSTANT: dist-table
|
|
{
|
|
1 2 3 4 5 7 9 13 17 25 33 49
|
|
65 97 129 193 257 385 513 769 1025 1537 2049 3073
|
|
4097 6145 8193 12289 16385 24577
|
|
}
|
|
|
|
: nth* ( n seq -- elt )
|
|
[ length 1 - swap - ] [ nth ] bi ; inline
|
|
|
|
:: inflate-lz77 ( seq -- byte-array )
|
|
1000 <byte-vector> :> bytes
|
|
seq [
|
|
dup array?
|
|
[ first2 '[ _ 1 - bytes nth* bytes push ] times ]
|
|
[ bytes push ] if
|
|
] each
|
|
bytes >byte-array ;
|
|
|
|
:: inflate-huffman ( bitstream tables -- bytes )
|
|
bitstream tables [ <huffman-decoder> ] with map :> tables
|
|
[
|
|
tables first read1-huff2
|
|
dup 256 > [
|
|
dup 285 = [
|
|
dup 264 > [
|
|
dup 261 - 4 /i
|
|
dup 5 > [ bad-zlib-data ] when
|
|
bitstream bs:read 2array
|
|
] when
|
|
] unless
|
|
|
|
tables second read1-huff2
|
|
|
|
dup 3 > [
|
|
dup 2 - 2 /i dup 13 >
|
|
[ bad-zlib-data ] when
|
|
bitstream bs:read 2array
|
|
] when 2array
|
|
] when dup 256 = not
|
|
] [ ] produce nip
|
|
[
|
|
dup array? [
|
|
first2 [
|
|
dup array? [ first2 ] [ 0 ] if
|
|
[ 257 - length-table nth ] [ + ] bi*
|
|
] [
|
|
dup array? [ first2 ] [ 0 ] if
|
|
[ dist-table nth ] [ + ] bi*
|
|
] bi* 2array
|
|
] when
|
|
] map ;
|
|
|
|
:: inflate-raw ( bitstream -- bytes )
|
|
8 bitstream bs:align
|
|
16 bitstream bs:read :> len
|
|
16 bitstream bs:read :> nlen
|
|
|
|
! len + ~len = -1
|
|
len nlen + 16 >signed -1 assert=
|
|
|
|
bitstream byte-pos>>
|
|
bitstream byte-pos>> len +
|
|
bitstream bytes>> <slice>
|
|
len 8 * bitstream bs:seek ;
|
|
|
|
: inflate-dynamic ( bitstream -- array )
|
|
dup decode-huffman-tables inflate-huffman ;
|
|
|
|
: inflate-static ( bitstream -- array )
|
|
static-huffman-tables inflate-huffman ;
|
|
|
|
:: inflate-loop ( bitstream -- array )
|
|
[ 1 bitstream bs:read 0 = ] [
|
|
bitstream
|
|
2 bitstream bs:read
|
|
{
|
|
{ 0 [ inflate-raw ] }
|
|
{ 1 [ inflate-static ] }
|
|
{ 2 [ inflate-dynamic ] }
|
|
{ 3 [ bad-zlib-data f ] }
|
|
} case
|
|
] [ produce ] keep call suffix concat ;
|
|
|
|
PRIVATE>
|
|
|
|
: zlib-inflate ( bytes -- bytes )
|
|
bs:<lsb0-bit-reader>
|
|
[ check-zlib-header ] [ inflate-loop ] bi
|
|
inflate-lz77 ;
|