! Copyright (C) 2009 Doug Coleman. ! See http://factorcode.org/license.txt for BSD license. USING: accessors combinators io kernel math namespaces prettyprint sequences vectors ; QUALIFIED-WITH: bitstreams bs IN: compression.lzw TUPLE: lzw input output table code old-code initial-code-size code-size clear-code end-of-information-code ; TUPLE: tiff-lzw < lzw ; TUPLE: gif-lzw < lzw ; : initial-uncompress-table ( size -- seq ) iota [ 1vector ] V{ } map-as ; : reset-lzw-uncompress ( lzw -- lzw ) dup end-of-information-code>> 1 + initial-uncompress-table >>table dup initial-code-size>> >>code-size ; : ( input code-size class -- obj ) new swap >>code-size dup code-size>> >>initial-code-size dup code-size>> 1 - 2^ >>clear-code dup clear-code>> 1 + >>end-of-information-code swap >>input BV{ } clone >>output reset-lzw-uncompress ; ERROR: not-in-table value ; : lookup-old-code ( lzw -- vector ) [ old-code>> ] [ table>> ] bi nth ; : lookup-code ( lzw -- vector ) [ code>> ] [ table>> ] bi nth ; : code-in-table? ( lzw -- ? ) [ code>> ] [ table>> length ] bi < ; : code>old-code ( lzw -- lzw ) dup code>> >>old-code ; : write-code ( lzw -- ) [ lookup-code ] [ output>> ] bi push-all ; GENERIC: code-space-full? ( lzw -- ? ) M: tiff-lzw code-space-full? [ table>> length ] [ code-size>> 2^ 1 - ] bi = ; M: gif-lzw code-space-full? [ table>> length ] [ code-size>> 2^ ] bi = ; : maybe-increment-code-size ( lzw -- lzw ) dup code-space-full? [ [ 1 + ] change-code-size ] when ; : add-to-table ( seq lzw -- ) [ table>> push ] [ maybe-increment-code-size 2drop ] 2bi ; : lzw-read ( lzw -- lzw n ) [ ] [ code-size>> ] [ input>> ] tri bs:read ; : end-of-information? ( lzw code -- ? ) swap end-of-information-code>> = ; : clear-code? ( lzw code -- ? ) swap clear-code>> = ; DEFER: handle-clear-code : lzw-process-next-code ( lzw quot: ( lzw code -- ) -- ) [ lzw-read ] dip { { [ 3dup drop end-of-information? ] [ 3drop ] } { [ 3dup drop clear-code? ] [ 2drop handle-clear-code ] } [ call( lzw code -- ) ] } cond ; inline DEFER: lzw-uncompress-char : handle-clear-code ( lzw -- ) reset-lzw-uncompress [ >>code [ write-code ] [ code>old-code ] bi lzw-uncompress-char ] lzw-process-next-code ; : handle-uncompress-code ( lzw -- lzw ) dup code-in-table? [ [ write-code ] [ [ [ lookup-old-code ] [ lookup-code first ] bi suffix ] [ add-to-table ] bi ] [ code>old-code ] tri ] [ [ [ lookup-old-code dup first suffix ] keep [ output>> push-all ] [ add-to-table ] 2bi ] [ code>old-code ] bi ] if ; : lzw-uncompress-char ( lzw -- ) [ >>code handle-uncompress-code lzw-uncompress-char ] lzw-process-next-code ; : lzw-uncompress ( bitstream code-size class -- byte-array ) [ lzw-uncompress-char ] [ output>> ] bi ; : tiff-lzw-uncompress ( seq -- byte-array ) bs: 9 tiff-lzw lzw-uncompress ; : gif-lzw-uncompress ( seq code-size -- byte-array ) [ bs: ] dip gif-lzw lzw-uncompress ;