factor/basis/compression/inflate/inflate.factor

181 lines
5.0 KiB
Factor
Raw Normal View History

! Copyright (C) 2009 Marc Fauconneau.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors arrays assocs byte-vectors combinators
2009-10-05 23:34:43 -04:00
combinators.smart compression.huffman fry hashtables io.binary
kernel literals locals math math.bitwise math.order math.ranges
2009-10-06 00:19:42 -04:00
sequences sorting memoize combinators.short-circuit ;
QUALIFIED-WITH: bitstreams bs
IN: compression.inflate
<PRIVATE
ERROR: zlib-unimplemented ;
ERROR: bad-zlib-data ;
ERROR: bad-zlib-header ;
2009-10-06 00:19:42 -04:00
:: check-zlib-header ( data -- )
16 data bs:peek 2 >le be> 31 mod ! checksum
2009-10-06 00:19:42 -04:00
0 assert=
4 data bs:read 8 assert= ! compression method: deflate
4 data bs:read ! log2(max length)-8, 32K max
2009-10-06 00:19:42 -04:00
7 <= [ bad-zlib-header ] unless
5 data bs:seek ! drop check bits
1 data bs:read 0 assert= ! dictionnary - 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 }
2009-10-06 00:19:42 -04:00
: get-table ( values size -- table )
16 f <array> clone <enum>
[ '[ _ push-at ] 2each ] keep seq>> 1 tail [ natural-sort ] map ;
:: 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 [ drop 3 bitstream bs:read ] map
get-table
2009-10-06 00:19:42 -04:00
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 >
2009-10-05 23:34:43 -04:00
]
2009-10-06 00:19:42 -04:00
[ ] produce swap suffix
{ } [
dup { [ array? ] [ first 16 = ] } 1&& [
[ unclip-last ]
[ second 1 + swap <repetition> append ] bi*
] [
suffix
] if
] reduce
[
dup array? [ second 0 <repetition> ] [ 1array ] if
] map concat
nip swap cut 2array [
[ length>> [0,b) ] [ ] bi get-table
] map ;
MEMO: static-huffman-tables ( -- obj )
[
0 143 [a,b] [ 8 ] replicate
144 255 [a,b] [ 9 ] replicate append
256 279 [a,b] [ 7 ] replicate append
280 287 [a,b] [ 8 ] replicate append
] append-outputs
0 31 [a,b] [ 5 ] replicate 2array
[ [ length>> [0,b) ] [ ] bi get-table ] map ;
2009-10-05 23:12:59 -04:00
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
{
2009-10-06 00:19:42 -04:00
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 )
2009-10-06 00:19:42 -04:00
[ length 1 - swap - ] [ nth ] bi ; inline
:: inflate-lz77 ( seq -- bytes )
1000 <byte-vector> :> bytes
2009-10-06 00:19:42 -04:00
seq [
dup array?
[ first2 '[ _ 1 - bytes nth* bytes push ] times ]
[ bytes push ] if
2009-10-06 00:19:42 -04:00
] each
bytes ;
2009-10-05 23:12:59 -04:00
:: inflate-huffman ( bitstream tables -- bytes )
tables bitstream '[ _ swap <huffman-decoder> ] map :> tables
[
tables first read1-huff2
2009-10-06 00:19:42 -04:00
dup 256 > [
dup 285 = [
dup 264 > [
dup 261 - 4 /i dup 5 >
[ bad-zlib-data ] when
bitstream bs:read 2array
] when
] unless
! 5 bitstream read-bits ! distance
tables second read1-huff2
2009-10-06 00:19:42 -04:00
dup 3 > [
dup 2 - 2 /i dup 13 >
[ bad-zlib-data ] when
bitstream bs:read 2array
2009-10-06 00:19:42 -04:00
] when 2array
] when
dup 256 = not
2009-10-06 00:19:42 -04:00
] [ ] produce nip
[
dup array? [
2009-10-06 00:19:42 -04:00
first2 [
dup array? [ first2 ] [ 0 ] if
[ 257 - length-table nth ] [ + ] bi*
2009-10-06 00:19:42 -04:00
] [
dup array? [ first2 ] [ 0 ] if
[ dist-table nth ] [ + ] bi*
2009-10-06 00:19:42 -04:00
] bi* 2array
] when
] map ;
2009-10-06 00:19:42 -04:00
:: inflate-raw ( bitstream -- bytes )
8 bitstream bs:align
16 bitstream bs:read :> len
16 bitstream bs:read :> nlen
len nlen + 16 >signed -1 assert= ! len + ~len = -1
bitstream byte-pos>>
bitstream byte-pos>> len +
bitstream bytes>> <slice>
len 8 * bitstream bs:seek ;
2009-10-06 00:19:42 -04:00
: inflate-dynamic ( bitstream -- bytes )
2009-10-05 23:12:59 -04:00
dup decode-huffman-tables inflate-huffman ;
2009-10-06 00:19:42 -04:00
: inflate-static ( bitstream -- bytes )
2009-10-05 23:12:59 -04:00
static-huffman-tables inflate-huffman ;
:: inflate-loop ( bitstream -- bytes )
2009-10-06 00:19:42 -04:00
[ 1 bitstream bs:read 0 = ] [
bitstream
2 bitstream bs:read
2009-10-06 00:19:42 -04:00
{
{ 0 [ inflate-raw ] }
{ 1 [ inflate-static ] }
{ 2 [ inflate-dynamic ] }
{ 3 [ bad-zlib-data f ] }
2009-10-05 23:34:43 -04:00
} case
] [ produce ] keep call suffix concat ;
PRIVATE>
: zlib-inflate ( bytes -- bytes )
bs:<lsb0-bit-reader>
[ check-zlib-header ] [ inflate-loop ] bi
inflate-lz77 ;