1 ! Copyright (C) 2009 Doug Coleman.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: accessors alien.accessors byte-arrays combinators
4 constructors destructors fry io io.binary kernel locals macros
5 math math.ranges multiline sequences sequences.private ;
8 QUALIFIED-WITH: bitstreams bs
10 CONSTANT: clear-code 256
11 CONSTANT: end-of-information 257
13 TUPLE: lzw input output end-of-input? table count k omega omega-k #bits
18 ERROR: index-too-big n ;
20 : lzw-bit-width ( n -- n' )
22 { [ dup 510 <= ] [ drop 9 ] }
23 { [ dup 1022 <= ] [ drop 10 ] }
24 { [ dup 2046 <= ] [ drop 11 ] }
25 { [ dup 4094 <= ] [ drop 12 ] }
29 : lzw-bit-width-compress ( lzw -- n )
30 count>> lzw-bit-width ;
32 : lzw-bit-width-uncompress ( lzw -- n )
33 table>> length lzw-bit-width ;
35 : initial-compress-table ( -- assoc )
36 258 iota [ [ 1vector ] keep ] H{ } map>assoc ;
38 : initial-uncompress-table ( -- seq )
39 258 iota [ 1vector ] V{ } map-as ;
41 : reset-lzw ( lzw -- lzw )
47 : reset-lzw-compress ( lzw -- lzw )
49 initial-compress-table >>table reset-lzw ;
51 : reset-lzw-uncompress ( lzw -- lzw )
52 initial-uncompress-table >>table reset-lzw ;
54 : <lzw-compress> ( input -- obj )
57 ! binary <byte-writer> <bitstream-writer> >>output
58 V{ } clone >>output ! TODO
61 : <lzw-uncompress> ( input -- obj )
65 reset-lzw-uncompress ;
67 : push-k ( lzw -- lzw )
70 [ omega>> clone [ push ] keep ] tri >>omega-k ;
72 : omega-k-in-table? ( lzw -- ? )
73 [ omega-k>> ] [ table>> ] bi key? ;
75 ERROR: not-in-table value ;
77 : write-output ( lzw -- )
79 [ omega>> ] [ table>> ] bi ?at [ not-in-table ] unless
81 [ lzw-bit-width-compress ]
82 [ output>> bs:poke ] bi
85 : omega-k>omega ( lzw -- lzw )
86 dup omega-k>> clone >>omega ;
88 : k>omega ( lzw -- lzw )
89 dup k>> 1vector >>omega ;
91 : add-omega-k ( lzw -- )
92 [ [ 1+ ] change-count count>> ]
94 [ table>> ] tri set-at ;
96 : lzw-compress-char ( lzw k -- )
97 >>k push-k dup omega-k-in-table? [
105 : (lzw-compress-chars) ( lzw -- )
106 dup lzw-bit-width-compress table-full = [
109 dup input>> stream-read1
110 [ [ lzw-compress-char ] [ drop (lzw-compress-chars) ] 2bi ]
111 [ t >>end-of-input? drop ] if*
114 : lzw-compress-chars ( lzw -- )
116 ! [ [ clear-code lzw-compress-char ] [ drop ] bi ] ! reset-lzw-compress drop ] bi ]
119 [ lzw-bit-width-compress ]
120 [ output>> bs:poke ] bi
122 [ (lzw-compress-chars) ]
125 [ lzw-bit-width-compress ]
126 [ output>> bs:poke ] tri
129 [ end-of-information ] dip
130 [ lzw-bit-width-compress ]
131 [ output>> bs:poke ] bi
134 } cleave dup end-of-input?>> [ drop ] [ lzw-compress-chars ] if ;
136 : lzw-compress ( byte-array -- seq )
137 binary <byte-reader> <lzw-compress>
138 [ lzw-compress-chars ] [ output>> stream>> ] bi ;
140 : lookup-old-code ( lzw -- vector )
141 [ old-code>> ] [ table>> ] bi nth ;
143 : lookup-code ( lzw -- vector )
144 [ code>> ] [ table>> ] bi nth ;
146 : code-in-table? ( lzw -- ? )
147 [ code>> ] [ table>> length ] bi < ;
149 : code>old-code ( lzw -- lzw )
150 dup code>> >>old-code ;
152 : write-code ( lzw -- )
153 [ lookup-code ] [ output>> ] bi push-all ;
155 : add-to-table ( seq lzw -- ) table>> push ;
157 : lzw-read ( lzw -- lzw n )
158 [ ] [ lzw-bit-width-uncompress ] [ input>> ] tri bs:peek ;
160 DEFER: lzw-uncompress-char
161 : handle-clear-code ( lzw -- )
163 lzw-read dup end-of-information = [
172 : handle-uncompress-code ( lzw -- lzw )
178 [ lookup-code first ] bi suffix
179 ] [ add-to-table ] bi
180 ] [ code>old-code ] tri
183 [ lookup-old-code dup first suffix ] keep
184 [ output>> push-all ] [ add-to-table ] 2bi
185 ] [ code>old-code ] bi
188 : lzw-uncompress-char ( lzw -- )
191 dup code>> end-of-information = [
194 dup code>> clear-code = [
197 handle-uncompress-code
205 : lzw-uncompress ( seq -- byte-array )
207 ! binary <byte-reader> ! <bitstream-reader>
208 <lzw-uncompress> [ lzw-uncompress-char ] [ output>> ] bi ;