@ -5,23 +5,20 @@ const TINF_DATA_ERROR = -3;
class Tree {
table = new Uint16Array ( 16 ) ; /* table of code length counts */
trans = new Uint16Array ( 288 ) ; /* code -> symbol translation table */
}
type HCtree = [ number | HCtree , ( number | HCtree ) ? ] ;
let log = ( x , . . . n ) = > {
//console.log('t2', x, ...n);
}
// these two functions are a big bottleneck because im not clever enough to figure out how to encode
// something directly by using the sorted code length/value tables, haha
le t pathMap = new Map < HCtree , Map < number , {
const pathMap = new Map < HCtree , Map < number , {
length : number ,
val : number
} >> ( ) ;
le t getPathTo = ( tree : HCtree , value : number ) : string | undefined = > {
cons t getPathTo = ( tree : HCtree , value : number ) : string | undefined = > {
if ( tree [ 0 ] === value )
return '0' ;
if ( tree [ 1 ] === value )
@ -43,6 +40,7 @@ let getPathTo = (tree: HCtree, value: number): string | undefined => {
// from jpeg-js, in turns this means that jpeg-js decoding could be faster
// if they decoded directly from the symbol tables instead of building a tree
function buildHuffmanTable ( codeLengths : ArrayLike < number > , values : ArrayLike < number > ) {
// eslint-disable-next-line prefer-const
let k = 0 , code : any = [ ] , i , j , length = 16 ;
while ( length > 0 && ! codeLengths [ length - 1 ] )
length -- ;
@ -84,16 +82,18 @@ class Data {
}
ltree : Tree ;
dtree : Tree ;
rltree ! : HCtree ;
rdtree ! : HCtree ;
adists ! : Set < number > ;
dest : number [ ] = [ ] ;
constructor ( public source : BitstreamReader , public dests : BitstreamWriter , public to_hide : BitstreamReader | BitstreamWriter , public hidden : BitstreamWriter ) {
constructor ( public source : BitstreamReader , public dests : BitstreamWriter | null , public to_hide? : BitstreamReader | BitstreamWriter , public hidden? : BitstreamWriter ) {
this . ltree = new Tree ( ) ; /* dynamic length/symbol tree */
this . dtree = new Tree ( ) ; /* dynamic distance tree */
}
@ -103,31 +103,36 @@ class Data {
* -- uninitialized global data ( static structures ) -- *
* -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - * /
le t sltree = new Tree ( ) ;
le t sdtree = new Tree ( ) ;
cons t sltree = new Tree ( ) ;
cons t sdtree = new Tree ( ) ;
// eslint-disable-next-line prefer-const
let rltree : HCtree ;
// eslint-disable-next-line prefer-const
let rdtree : HCtree ;
// eslint-disable-next-line prefer-const
let sadist : Set < number > ;
/* extra bits and base tables for length codes */
le t length_bits = new Uint8Array ( 30 ) ;
le t length_base = new Uint16Array ( 30 ) ;
cons t length_bits = new Uint8Array ( 30 ) ;
cons t length_base = new Uint16Array ( 30 ) ;
/* extra bits and base tables for distance codes */
le t dist_bits = new Uint8Array ( 30 ) ;
le t dist_base = new Uint16Array ( 30 ) ;
cons t dist_bits = new Uint8Array ( 30 ) ;
cons t dist_base = new Uint16Array ( 30 ) ;
/* special ordering of code length codes */
le t clcidx = new Uint8Array ( [
cons t clcidx = new Uint8Array ( [
16 , 17 , 18 , 0 , 8 , 7 , 9 , 6 ,
10 , 5 , 11 , 4 , 12 , 3 , 13 , 2 ,
14 , 1 , 15
] ) ;
/* used by tinf_decode_trees, avoids allocations every call */
le t code_tree = new Tree ( ) ;
le t lengths = new Uint8Array ( 288 + 32 ) ;
cons t code_tree = new Tree ( ) ;
cons t lengths = new Uint8Array ( 288 + 32 ) ;
/ * - - - - - - - - - - - - - - - - - - - - - - - *
* -- utility functions -- *
@ -173,7 +178,7 @@ function tinf_build_fixed_trees(lt: Tree, dt: Tree) {
}
/* given an array of code lengths, build a tree */
le t offs = new Uint16Array ( 16 ) ;
cons t offs = new Uint16Array ( 16 ) ;
function tinf_build_tree ( t : Tree , lengths : Uint8Array , off : number , num : number ) {
let i , sum ;
@ -204,19 +209,18 @@ function tinf_build_tree(t: Tree, lengths: Uint8Array, off: number, num: number)
/* get one bit from source stream */
function tinf_getbit ( d : Data ) {
let v = d . source . readSync ( 1 ) ;
log ( v , 'getbit' ) ;
const v = d . source . readSync ( 1 ) ;
return v ;
}
let loff = 0 ;
le t loffs : number [ ] = [ ] ;
cons t loffs : number [ ] = [ ] ;
/* read a num bit value from a stream and add base */
function tinf_read_bits ( d : Data , num : number , base : number ) {
if ( ! num )
return base ;
le t v = d . source . readSync ( num ) + base ;
cons t v = d . source . readSync ( num ) + base ;
loff = v ;
//console.log(v);
loffs . push ( v ) ;
@ -233,8 +237,8 @@ function tinf_decode_symbol(d: Data, t: Tree, copy = true, ext: any = {}) {
/* get more bits while code value is above sum */
let s = 0 ;
do {
le t b = d . source . readSync ( 1 ) ;
copy && d . hidden . write ( 1 , b ) ;
cons t b = d . source . readSync ( 1 ) ;
copy && d . hidden ? . write ( 1 , b ) ;
s = ( s << 1 ) | b ;
cur = 2 * cur + b ;
++ len ;
@ -252,7 +256,7 @@ function tinf_decode_symbol2(d: Data, t: Tree) {
/* get more bits while code value is above sum */
do {
le t b = d . source . readSync ( 1 ) ;
cons t b = d . source . readSync ( 1 ) ;
//d.hidden.write(1, b);
cur = 2 * cur + b ;
++ len ;
@ -268,15 +272,15 @@ function tinf_decode_trees(d: Data, lt: Tree, dt: Tree, copy = true) {
let i , num , length ;
/* get 5 bits HLIT (257-286) */
le t hlit = tinf_read_bits ( d , 5 , 257 ) ;
cons t hlit = tinf_read_bits ( d , 5 , 257 ) ;
copy && d . hidden ? . write ( 5 , hlit - 257 ) ;
/* get 5 bits HDIST (1-32) */
le t hdist = tinf_read_bits ( d , 5 , 1 ) ;
cons t hdist = tinf_read_bits ( d , 5 , 1 ) ;
copy && d . hidden ? . write ( 5 , hdist - 1 ) ;
/* get 4 bits HCLEN (4-19) */
le t hclen = tinf_read_bits ( d , 4 , 4 ) ;
cons t hclen = tinf_read_bits ( d , 4 , 4 ) ;
copy && d . hidden ? . write ( 4 , hclen - 4 ) ;
for ( i = 0 ; i < 19 ; ++ i ) lengths [ i ] = 0 ;
@ -284,7 +288,7 @@ function tinf_decode_trees(d: Data, lt: Tree, dt: Tree, copy = true) {
/* read code lengths for code length alphabet */
for ( i = 0 ; i < hclen ; ++ i ) {
/* get 3 bits code length (0-7) */
le t clen = tinf_read_bits ( d , 3 , 0 ) ;
cons t clen = tinf_read_bits ( d , 3 , 0 ) ;
copy && d . hidden ? . write ( 3 , clen ) ;
lengths [ clcidx [ i ] ] = clen ;
@ -295,12 +299,13 @@ function tinf_decode_trees(d: Data, lt: Tree, dt: Tree, copy = true) {
/* decode code lengths for the dynamic trees */
for ( num = 0 ; num < hlit + hdist ; ) {
let sym = tinf_decode_symbol ( d , code_tree , copy ) ;
const sym = tinf_decode_symbol ( d , code_tree , copy ) ;
let prev : number ;
switch ( sym ) {
case 16 :
/* copy previous code length 3-6 times (read 2 bits) */
let prev = lengths [ num - 1 ] ;
prev = lengths [ num - 1 ] ;
length = tinf_read_bits ( d , 2 , 3 ) ;
copy && d . hidden ? . write ( 2 , length - 3 ) ;
for ( ; length ; -- length ) {
@ -335,23 +340,22 @@ function tinf_decode_trees(d: Data, lt: Tree, dt: Tree, copy = true) {
tinf_build_tree ( dt , lengths , hlit , hdist ) ;
}
const get_symbol = ( value : number , bits_table : Uint8Array , base_table : Uint16Array ) : [ number , number , number ] = > {
let i = 0 ;
for ( i = 0 ; i < base_table . length ; ++ i ) {
if ( base_table [ i ] > value ) {
i -- ;
return [ i , bits_table [ i ] , value - base_table [ i ] ]
return [ i , bits_table [ i ] , value - base_table [ i ] ] ;
}
}
i -- ;
return [ i , bits_table [ i ] , value - base_table [ i ] ]
return [ i , bits_table [ i ] , value - base_table [ i ] ] ;
} ;
const encode_symbol = ( sym : number , tree : HCtree ) = > {
let m : Map < number , { length : number , val : number } > | undefined ;
let m : Map < number , { length : number , val : number } > | undefined ;
if ( ( m = pathMap . get ( tree ) ) ) {
le t v = m . get ( sym ) ;
cons t v = m . get ( sym ) ;
if ( v ) return v ;
} else {
m = new Map ;
@ -360,7 +364,7 @@ const encode_symbol = (sym: number, tree: HCtree) => {
const code = getPathTo ( tree , sym ) ! ;
le t v = {
cons t v = {
length : code?.length ,
val : parseInt ( code , 2 )
} ;
@ -374,6 +378,7 @@ const encode_symbol = (sym: number, tree: HCtree) => {
/* given a stream and two trees, inflate a block of data */
export let capacity = 0 ;
function tinf_inflate_block_data ( d : Data , lt : Tree , dt : Tree ) {
// eslint-disable-next-line no-constant-condition
while ( 1 ) {
let sym = tinf_decode_symbol ( d , lt ) ; // copy
@ -386,30 +391,28 @@ function tinf_inflate_block_data(d: Data, lt: Tree, dt: Tree) {
d . dest . push ( sym ) ;
// same
} else {
let length , dist , offs ;
sym -= 257 ;
/* possibly get more bits from length code */
length = tinf_read_bits ( d , length_bits [ sym ] , length_base [ sym ] ) ;
const length = tinf_read_bits ( d , length_bits [ sym ] , length_base [ sym ] ) ;
//d.hidden.write(length_bits[sym], length - length_base[sym]);
// length is unchanged, so copy as is
if ( length_bits [ sym ] )
d . hidden . write ( length_bits [ sym ] , length - length_base [ sym ] ) ;
d . hidden ? . write ( length_bits [ sym ] , length - length_base [ sym ] ) ;
le t ext = { length : 0 , sym : 0 } ;
dist = tinf_decode_symbol ( d , dt , false , ext ) ; // don't copy immediately, we may change the code
cons t ext = { length : 0 , sym : 0 } ;
const dist = tinf_decode_symbol ( d , dt , false , ext ) ; // don't copy immediately, we may change the code
//ext.sym = revbyte(ext.sym, ext.length);
//d.hidden.write(ext.length, ext.sym);
/* possibly get more bits from distance code */
let backoffset = tinf_read_bits ( d , dist_bits [ dist ] , dist_base [ dist ] ) ;
offs = d . dest . length - backoffset ;
const offs = d . dest . length - backoffset ;
let match : Buffer ;
// don't consider matches that could be in the lookahead buffer
le t skip = d . to_hide instanceof BitstreamReader && d . to_hide . available == 0 ;
cons t skip = d . to_hide && d . to_hide instanceof BitstreamReader && d . to_hide . available == 0 ;
if ( ! skip && ( match = Buffer . from ( d . dest . slice ( offs , offs + length ) ) ) . length == length ) {
let begin = d . dest . length - 32768 ;
if ( begin < 0 )
@ -418,7 +421,7 @@ function tinf_inflate_block_data(d: Data, lt: Tree, dt: Tree) {
let o = 0 ;
const slic = Buffer . from ( d . dest . slice ( begin + o , d . dest . length ) ) ;
while ( begin + o < d . dest . length ) {
le t r = slic . slice ( o , d . dest . length ) . indexOf ( match ) ;
cons t r = slic . slice ( o , d . dest . length ) . indexOf ( match ) ;
if ( r >= 0 ) {
matches . push ( r + begin + o ) ;
o += r ;
@ -432,7 +435,7 @@ function tinf_inflate_block_data(d: Data, lt: Tree, dt: Tree) {
matches = matches . map ( e = > - ( e - d . dest . length ) ) . filter ( e = > {
const [ dsym ] = get_symbol ( e , dist_bits , dist_base ) ;
return d . adists . has ( dsym ) ;
} )
} ) ;
matches . reverse ( ) ;
const v = Math . floor ( Math . log2 ( matches . length ) ) ;
capacity += v ;
@ -447,7 +450,7 @@ function tinf_inflate_block_data(d: Data, lt: Tree, dt: Tree) {
// extract hidden bit
else {
const idx = matches . indexOf ( backoffset ) ;
d . to_hide . write ( v , idx ) ;
d . to_hide ! . write ( v , idx ) ;
}
}
}
@ -456,11 +459,10 @@ function tinf_inflate_block_data(d: Data, lt: Tree, dt: Tree) {
//let enclen = encode_symbol(lsym, d.rltree);
//d.hidden.write(enclen.length, enclen.val);
//d.hidden.write(llen, loff);
let [ dsym , dlen , doff ] = get_symbol ( backoffset , dist_bits , dist_base ) ;
let encdist = encode_symbol ( dsym , d . rdtree ) ;
d . hidden . write ( encdist . length , revbyte ( encdist . val , encdist . length ) ) ;
d . hidden . write ( dlen , doff ) ;
const [ dsym , dlen , doff ] = get_symbol ( backoffset , dist_bits , dist_base ) ;
const encdist = encode_symbol ( dsym , d . rdtree ) ;
d . hidden ? . write ( encdist . length , revbyte ( encdist . val , encdist . length ) ) ;
d . hidden ? . write ( dlen , doff ) ;
/* copy match */
for ( let i = offs ; i < offs + length ; ++ i ) {
@ -474,15 +476,15 @@ function tinf_inflate_block_data(d: Data, lt: Tree, dt: Tree) {
function tinf_inflate_uncompressed_block ( d : Data ) {
if ( d . source . offset & 7 )
d . source . readSync ( 8 - d . source . offset & 7 ) ;
if ( d . hidden . offset & 7 )
d . hidden . write ( 8 - d . hidden . offset & 7 , 0 ) ;
if ( d . hidden && d . hidden . offset & 7 )
d . hidden ? . write ( 8 - d . hidden . offset & 7 , 0 ) ;
le t length = d . source . readSync ( 16 ) ;
d . hidden . write ( 16 , length ) ;
cons t length = d . source . readSync ( 16 ) ;
d . hidden ? . write ( 16 , length ) ;
/* get one's complement of length */
le t invlength = d . source . readSync ( 16 ) ;
d . hidden . write ( 16 , invlength ) ;
cons t invlength = d . source . readSync ( 16 ) ;
d . hidden ? . write ( 16 , invlength ) ;
/* check length */
if ( length !== ( ~ invlength & 0x0000ffff ) ) {
//console.log(length, invlength, loff)
@ -492,12 +494,13 @@ function tinf_inflate_uncompressed_block(d: Data) {
for ( let i = length ; i ; -- i ) {
const v = d . source . readSync ( 8 ) ;
d . dest . push ( v ) ;
d . hidden . write ( 8 , v ) ;
d . hidden ? . write ( 8 , v ) ;
}
return TINF_OK ;
}
function copy_block_data ( d : Data , lt : Tree , dt : Tree ) {
// eslint-disable-next-line no-constant-condition
while ( 1 ) {
let sym = tinf_decode_symbol ( d , lt , false ) ; // copy
@ -510,11 +513,9 @@ function copy_block_data(d: Data, lt: Tree, dt: Tree) {
//d.dest.push(sym);
// same
} else {
let length , dist , offs ;
sym -= 257 ;
length = tinf_read_bits ( d , length_bits [ sym ] , length_base [ sym ] ) ;
dist = tinf_decode_symbol2 ( d , dt ) ;
const length = tinf_read_bits ( d , length_bits [ sym ] , length_base [ sym ] ) ;
const dist = tinf_decode_symbol2 ( d , dt ) ;
tinf_read_bits ( d , dist_bits [ dist ] , dist_base [ dist ] ) ;
}
}
@ -524,17 +525,17 @@ function copy_uncompressed_block(d: Data) {
// align
if ( d . source . offset & 7 )
d . source . readSync ( 8 - d . source . offset & 7 ) ;
if ( d . hidden . offset & 7 )
if ( d . hidden && d . hidden . offset & 7 )
d . hidden . write ( 8 - d . hidden . offset & 7 , 0 ) ;
le t length : number ;
d . hidden . write ( 16 , length = d . source . readSync ( 16 ) ) ;
d . hidden . write ( 16 , d . source . readSync ( 16 ) ) ;
cons t length : number = d . source . readSync ( 16 ) ;
d . hidden ? . write ( 16 , length ) ;
d . hidden ? . write ( 16 , d . source . readSync ( 16 ) ) ;
let total = length * 8 ;
while ( total ) {
const r = Math . min ( 32 , total ) ;
d . hidden . write ( r , d . source . readSync ( r ) ) ;
d . hidden ? . write ( r , d . source . readSync ( r ) ) ;
total -= r ;
}
return TINF_OK ;
@ -543,16 +544,16 @@ function copy_uncompressed_block(d: Data) {
/* inflate stream from source to dest */
export function tinf_uncompress ( source : BitstreamReader ,
// normal decompressed data
decompressed : ( chunk : Uint8Array ) = > void ,
decompressed ? : ( chunk : Uint8Array ) = > void ,
// stream of data to hide
to_hide : BitstreamReader | BitstreamWriter ,
to_hide? : BitstreamReader | BitstreamWriter ,
// compressed stream containing hidden data
hidden : ( chunk : Uint8Array ) = > void , opt = 0 ) {
hidden ? : ( chunk : Uint8Array ) = > void , opt = 0 ) {
let decomp = new BitstreamWriter ( { write : ( decompressed || ( ( ) = > { } ) ) } ) ;
let hid = new BitstreamWriter ( { write : ( hidden || ( ( ) = > { } ) ) } , 4 ) ;
const decomp = decompressed ? new BitstreamWriter ( { write : decompressed } ) : null ;
const hid = hidden && new BitstreamWriter ( { write : hidden } , 4 ) ;
le t d = new Data ( source , decomp , to_hide , hid ) ;
cons t d = new Data ( source , decomp , to_hide , hid ) ;
let res : number | undefined | true ;
let bfinal : number , btype : number ;
@ -561,7 +562,7 @@ export function tinf_uncompress(source: BitstreamReader,
/* read final block flag */
bfinal = tinf_getbit ( d ) ;
d . hidden . write ( 1 , bfinal ) ;
d . hidden ? . write ( 1 , bfinal ) ;
/* read block type (2 bits) */
btype = tinf_read_bits ( d , 2 , 0 ) ;
@ -596,9 +597,8 @@ export function tinf_uncompress(source: BitstreamReader,
} while ( ! bfinal ) ;
decomp . end ( ) ;
hid . end ( )
decomp ? . end ( ) ;
hid ? . end ( ) ;
//if (d.dest.byteOffset < d.dest.length) {
// if (typeof d.dest.slice === 'function')