From 667690630336883b196b73937bae5c3726fb696c Mon Sep 17 00:00:00 2001 From: nik Date: Tue, 11 Feb 2014 16:31:57 -0200 Subject: [PATCH] implement deflate store + high level deflate implementation + lint fixes --- .jshintignore | 1 - .jshintrc | 2 +- .../implementations/deflate-pako/index.js | 9 + lib/deflate.js | 87 +- lib/zlib/adler32.js | 44 +- lib/zlib/constants.js | 4 +- lib/zlib/deflate.js | 954 +++++++++++++----- lib/zlib/inflate.js | 86 +- lib/zlib/messages.js | 13 + lib/zlib/trees.js | 179 ++++ lib/zlib/utils.js | 8 +- lib/zlib/zstream.js | 6 +- test/deflate.js | 22 +- 13 files changed, 1074 insertions(+), 341 deletions(-) create mode 100644 benchmark/implementations/deflate-pako/index.js create mode 100644 lib/zlib/messages.js create mode 100644 lib/zlib/trees.js diff --git a/.jshintignore b/.jshintignore index ed1a17c..6264b72 100644 --- a/.jshintignore +++ b/.jshintignore @@ -1,4 +1,3 @@ .git/ node_modules/ benchmark/implementations -lib/zlib diff --git a/.jshintrc b/.jshintrc index b610e0e..367f4f5 100644 --- a/.jshintrc +++ b/.jshintrc @@ -1,7 +1,7 @@ { // Enforcing Options ///////////////////////////////////////////////////////// - "bitwise" : true, // Prohibit bitwise operators (&, |, ^, etc.). + "bitwise" : false, // Prohibit bitwise operators (&, |, ^, etc.). "camelcase" : false, // true: Identifiers must be in camelCase "curly" : true, // Require {} for every new block or scope. "eqeqeq" : true, // Require triple equals i.e. `===`. diff --git a/benchmark/implementations/deflate-pako/index.js b/benchmark/implementations/deflate-pako/index.js new file mode 100644 index 0000000..d2a0186 --- /dev/null +++ b/benchmark/implementations/deflate-pako/index.js @@ -0,0 +1,9 @@ +'use strict' + +var pako = require('../../../index.js'); + +exports.run = function(data) { + return pako.deflate(data, { + level: 0 + }); +} diff --git a/lib/deflate.js b/lib/deflate.js index 36ff744..4a84152 100644 --- a/lib/deflate.js +++ b/lib/deflate.js @@ -1,8 +1,11 @@ 'use strict'; -//var zlib_deflate = require('./zlib/deflate.js'); +var zlib_deflate = require('./zlib/deflate.js'); var utils = require('./zlib/utils'); +var c = require('./zlib/constants'); +var msg = require('./zlib/messages'); +var zstream = require('./zlib/zstream'); /** @@ -11,25 +14,76 @@ var utils = require('./zlib/utils'); * @param {Object} [options] zlib options * @constructor */ -var Deflate = function(/*options*/) { +var Deflate = function(options) { + options = utils.assign({ + level: 6, + method: c.Z_DEFLATED, + chunkSize: 16384, + windowBits: 15, + memLevel: 8, + strategy: c.Z_DEFAULT_STRATEGY + },options || {}); + this.options = options; + this.strm = new zstream(); + this.strm.next_out = utils.arrayCreate(this.options.chunkSize); + + var ret = zlib_deflate.deflateInit2(this.strm, options.level, options.method, options.windowBits, options.memLevel, options.strategy); + if (ret !== c.Z_OK) { + throw new Error(msg[ret]); + } }; - /** * Compresses the input data and fills output buffer with compressed data. - * @return {Array|Uint8Array} compressed data */ -Deflate.prototype.push = function(/*data_in*/) { +Deflate.prototype.push = function(data_in) { + var strm = this.strm; + strm.next_in = data_in; + strm.next_in_index = 0; + strm.avail_in = strm.next_in.length; + + /* run deflate() on input until output buffer not full, finish + compression if all of source has been read in */ + do { + strm.avail_out = this.options.chunkSize; + strm.next_out_index = 0; + zlib_deflate.deflate(strm, c.Z_NO_FLUSH); + //var ret = zlib_deflate.deflate(strm, c.Z_NO_FLUSH); /* no bad return value */ + //if (ret !== c.Z_STREAM_END && ret !== c.Z_OK) { + // this.onEnd(ret); + //} + if(strm.next_out_index) { + var out = utils.arrayCreate(strm.next_out_index); + utils.arraySet(out, strm.next_out, 0, strm.next_out_index, 0); + this.onData(out); + } + } while (strm.avail_in > 0 || strm.avail_out === 0); }; Deflate.prototype.flush = function() { + var strm = this.strm; + do { + strm.avail_out = this.options.chunkSize; + strm.next_out_index = 0; + var ret = zlib_deflate.deflate(strm, c.Z_FINISH); /* no bad return value */ + if (ret !== c.Z_STREAM_END && ret !== c.Z_OK) { + this.onEnd(ret); + } + if(strm.next_out_index) { + var out = utils.arrayCreate(strm.next_out_index); + utils.arraySet(out, strm.next_out, 0, strm.next_out_index, 0); + this.onData(out); + } + } while (strm.avail_out === 0); }; Deflate.prototype.finish = function() { - + this.flush(); + zlib_deflate.deflateEnd(this.strm); + this.onEnd(c.Z_OK); }; Deflate.prototype.onData = function(/*data_out*/) { @@ -52,37 +106,38 @@ exports.Deflate = Deflate; */ function deflate(input, options) { var result; - var chains = []; + var chunks = []; var deflator = new Deflate(options); deflator.onData = function(data_out) { - chains.push(data_out); + chunks.push(data_out); }; deflator.onEnd = function(error) { - var i, l, len, pos, chain; + var i, l, len, pos, chunk; if (error) { throw error; } // calculate data length len = 0; - for (i=0, l=chains.length; i> 16) & 0xffff; adler &= 0xffff; /* in case user likes doing a byte at a time, keep it fast */ - if (len == 1) { + if (len === 1) { adler += buf[0]; - if (adler >= BASE) + if (adler >= BASE) { adler -= BASE; + } sum2 += adler; - if (sum2 >= BASE) + if (sum2 >= BASE) { sum2 -= BASE; + } return (adler | (sum2 << 16)) >>> 0; } @@ -27,30 +29,18 @@ function adler32(adler, buf, len) adler += buf[i]; sum2 += adler; } - if (adler >= BASE) + if (adler >= BASE) { adler -= BASE; + } sum2 %= BASE; /* only added so many BASE's */ return (adler | (sum2 << 16)) >>> 0; } - var cursor = 0; - /* do length NMAX blocks -- requires just one modulo operation */ - while (len >= NMAX) { - len -= NMAX; - var next_cursor = cursor + NMAX; - for (i=cursor;i0) { + var cursor = len > NMAX ? NMAX : len; + len -= cursor; + for(var j=0;j 4 ? 9 : 0); +} + +/* ========================================================================= + * Flush as much pending output as possible. All deflate() output goes + * through this function so some applications may wish to modify it + * to avoid allocating a large strm->next_out buffer and copying into it. + * (See also read_buf()). + */ +function flush_pending(strm) { + var s = strm.state; + + //_tr_flush_bits(s); + var len = s.pending; + if (len > strm.avail_out) { + len = strm.avail_out; + } + if (len === 0) { return;} + + utils.arraySet(strm.next_out, s.pending_buf, s.pending_out, len, strm.next_out_index); + strm.next_out_index += len; + s.pending_out += len; + strm.total_out += len; + strm.avail_out -= len; + s.pending -= len; + if (s.pending === 0) { + s.pending_out = 0; + } +} + +function flush_block_only (s, last) { + trees._tr_flush_block(s, (s.block_start >= 0 ? s.block_start : Z_NULL), s.strstart - s.block_start, last); + s.block_start = s.strstart; + flush_pending(s.strm); +} + +function update_hash (s, h, c) { + return (((h) << s.hash_shift) ^ (c)) & s.hash_mask; +} + +/* ========================================================================= + * Put a short in the pending buffer. The 16-bit value is put in MSB order. + * IN assertion: the stream state is correct and there is enough room in + * pending_buf. + */ +function putShortMSB(s, b) { +// put_byte(s, (Byte)(b >> 8)); +// put_byte(s, (Byte)(b & 0xff)); + s.pending_buf[s.pending++] = (b >>> 8) & 0xff; + s.pending_buf[s.pending++] = b & 0xff; +} + +/* =========================================================================== + * Read a new buffer from the current input stream, update the adler32 + * and total number of bytes read. All deflate() input goes through + * this function so some applications may wish to modify it to avoid + * allocating a large strm->next_in buffer and copying from it. + * (See also flush_pending()). + */ +function read_buf(strm, buf, start, size) { + var len = strm.avail_in; + + if (len > size) { len = size;} + if (len === 0) { return 0;} + + strm.avail_in -= len; + + utils.arraySet(buf, strm.next_in, strm.next_in_index, len, start); + if (strm.state.wrap === 1) { + strm.adler = adler32(strm.adler, buf, len, start); + } + strm.next_in_index += len; + strm.total_in += len; + + return len; +} + +/* =========================================================================== + * Set match_start to the longest match starting at the given string and + * return its length. Matches shorter or equal to prev_length are discarded, + * in which case the result is equal to prev_length and match_start is + * garbage. + * IN assertions: cur_match is the head of the hash chain for the current + * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 + * OUT assertion: the match length is not greater than s->lookahead. + */ +//function longest_match(s, cur_match) { +// +//} + +/* =========================================================================== + * Fill the window when the lookahead becomes insufficient. + * Updates strstart and lookahead. + * + * IN assertion: lookahead < MIN_LOOKAHEAD + * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD + * At least one byte has been read, or avail_in == 0; reads are + * performed for at least two bytes (required for the zip translate_eol + * option -- not supported here). + */ +function fill_window(s) { + var wsize = s.w_size; + var p = 0, n = 0, m = 0; + + //Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead"); + + do { + var more = s.window_size - s.lookahead - s.strstart; + + if (more === 0 && s.strstart === 0 && s.lookahead === 0) { + more = wsize; + + } else if (more === -1) { + /* Very unlikely, but possible on 16 bit machine if + * strstart == 0 && lookahead == 1 (input done a byte at time) + */ + more--; + } + + + /* If the window is almost full and there is insufficient lookahead, + * move the upper half to the lower one to make room in the upper half. + */ + if (s.strstart >= wsize + (wsize - MIN_LOOKAHEAD)) { + + utils.arraySet(s.window, s.window, wsize, wsize, 0); + s.match_start -= wsize; + s.strstart -= wsize; + /* we now have strstart >= MAX_DIST */ + s.block_start -= wsize; + + /* Slide the hash table (could be avoided with 32 bit values + at the expense of memory usage). We slide even when level == 0 + to keep the hash table consistent if we switch back to level > 0 + later. (Using level 0 permanently is not an optimal usage of + zlib, so we don't care about this pathological case.) + */ + n = s.hash_size; + p = s.head[n]; + do { + m = s.head[--p]; + s.head[p] = m >= wsize ? m - wsize : 0; + } while (--n); + + n = wsize; + if (FASTEST) { + p = s.prev[n]; + do { + m = s.head[--p]; + s.head[p] = m >= wsize ? m - wsize : 0; + /* If n is not on any hash chain, prev[n] is garbage but + * its value will never be used. + */ + } while (--n); + } + more += wsize; + } + if (s.strm.avail_in === 0) { + break; + } + + /* If there was no sliding: + * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && + * more == window_size - lookahead - strstart + * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) + * => more >= window_size - 2*WSIZE + 2 + * In the BIG_MEM or MMAP case (not yet supported), + * window_size == input_size + MIN_LOOKAHEAD && + * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. + * Otherwise, window_size == 2*WSIZE so more >= 2. + * If there was sliding, more >= WSIZE. So in all cases, more >= 2. + */ + //Assert(more >= 2, "more < 2"); + n = read_buf(s.strm, s.window, s.strstart + s.lookahead, more); + s.lookahead += n; + + /* Initialize the hash value now that we have some input: */ + if (s.lookahead + s.insert >= MIN_MATCH) { + var str = s.strstart - s.insert; + s.ins_h = s.window[str]; + s.ins_h = update_hash(s, s.ins_h, s.window[str + 1]); +//#if MIN_MATCH != 3 +// Call update_hash() MIN_MATCH-3 more times +//#endif + while (s.insert) { + s.ins_h = update_hash(s, s.ins_h, s.window[str + MIN_MATCH - 1]); + if (FASTEST) { + s.prev[str & s.w_mask] = s.head[s.ins_h]; + } + s.head[s.ins_h] = str; + str++; + s.insert--; + if (s.lookahead + s.insert < MIN_MATCH) { + break; + } + } + } + /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, + * but this is not important since only literal bytes will be emitted. + */ + + } while (s.lookahead < MIN_LOOKAHEAD && s.strm.avail_in !== 0); + + /* If the WIN_INIT bytes after the end of the current data have never been + * written, then zero those bytes in order to avoid memory check reports of + * the use of uninitialized (or uninitialised as Julian writes) bytes by + * the longest match routines. Update the high water mark for the next + * time through here. WIN_INIT is set to MAX_MATCH since the longest match + * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead. + */ +// if (s.high_water < s.window_size) { +// var curr = s.strstart + s.lookahead; +// var init = 0; +// +// if (s.high_water < curr) { +// /* Previous high water mark below current data -- zero WIN_INIT +// * bytes or up to end of window, whichever is less. +// */ +// init = s.window_size - curr; +// if (init > WIN_INIT) +// init = WIN_INIT; +// zmemzero(s->window + curr, (unsigned)init); +// s->high_water = curr + init; +// } +// else if (s->high_water < (ulg)curr + WIN_INIT) { +// /* High water mark at or above current data, but below current data +// * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up +// * to end of window, whichever is less. +// */ +// init = (ulg)curr + WIN_INIT - s->high_water; +// if (init > s->window_size - s->high_water) +// init = s->window_size - s->high_water; +// zmemzero(s->window + s->high_water, (unsigned)init); +// s->high_water += init; +// } +// } +// +// Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD, +// "not enough room for search"); +} + +/* =========================================================================== + * Copy without compression as much as possible from the input stream, return + * the current block state. + * This function does not insert new strings in the dictionary since + * uncompressible data is probably not useful. This function is used + * only for the level=0 compression option. + * NOTE: this function should be optimized to avoid extra copying from + * window to pending_buf. + */ +function deflate_stored(s, flush) { + /* Stored blocks are limited to 0xffff bytes, pending_buf is limited + * to pending_buf_size, and each stored block has a 5 byte header: + */ + var max_block_size = 0xffff; + + if (max_block_size > s.pending_buf_size - 5) { + max_block_size = s.pending_buf_size - 5; + } + + /* Copy as much as possible from input to output: */ + for (; ;) { + /* Fill the window as much as possible: */ + if (s.lookahead <= 1) { + + //Assert(s->strstart < s->w_size+MAX_DIST(s) || + // s->block_start >= (long)s->w_size, "slide too late"); +// if (!(s.strstart < s.w_size + (s.w_size - MIN_LOOKAHEAD) || +// s.block_start >= s.w_size)) { +// throw new Error("slide too late"); +// } + + fill_window(s); + if (s.lookahead === 0 && flush === c.Z_NO_FLUSH) { + return BS_NEED_MORE; + } + + if (s.lookahead === 0) { + break; + } + /* flush the current block */ + } + //Assert(s->block_start >= 0L, "block gone"); +// if (s.block_start < 0) throw new Error("block gone"); + + s.strstart += s.lookahead; + s.lookahead = 0; + + /* Emit a stored block if pending_buf will be full: */ + var max_start = s.block_start + max_block_size; + + if (s.strstart === 0 || s.strstart >= max_start) { + /* strstart == 0 is possible when wraparound on 16-bit machine */ + s.lookahead = s.strstart - max_start; + s.strstart = max_start; + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + + + } + /* Flush if we may have to slide, otherwise block_start may become + * negative and the data will be gone: + */ + if (s.strstart - s.block_start >= (s.w_size - MIN_LOOKAHEAD)) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + } + + s.insert = 0; + + if (flush === c.Z_FINISH) { + /*** FLUSH_BLOCK(s, 1); ***/ + flush_block_only(s, true); + if (s.strm.avail_out === 0) { + return BS_FINISH_STARTED; + } + /***/ + return BS_FINISH_STARTED; + } + + if (s.strstart > s.block_start) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + + return BS_NEED_MORE; +} + +/* =========================================================================== + * Compress as much as possible from the input stream, return the current + * block state. + * This function does not perform lazy evaluation of matches and inserts + * new strings in the dictionary only for unmatched strings or for short + * matches. It is used only for the fast compression options. + */ +function deflate_fast(/*s, flush*/) { + +} + +/* =========================================================================== + * Same as above, but achieves better compression. We use a lazy + * evaluation for matches: a match is finally adopted only if there is + * no better match at the next window position. + */ +function deflate_slow(/*s, flush*/) { + +} + +/* =========================================================================== + * For Z_RLE, simply look for runs of bytes, generate matches only of distance + * one. Do not maintain a hash table. (It will be regenerated if this run of + * deflate switches away from Z_RLE.) + */ +function deflate_rle(/*s, flush*/) { + +} + +/* =========================================================================== + * For Z_HUFFMAN_ONLY, do not look for matches. Do not maintain a hash table. + * (It will be regenerated if this run of deflate switches away from Huffman.) + */ +function deflate_huff(/*s, flush*/) { + +} + +var Config = function (good_length, max_lazy, nice_length, max_chain, func) { this.good_length = good_length; this.max_lazy = max_lazy; this.nice_length = nice_length; this.max_chain = max_chain; this.func = func; -} +}; var configuration_table; if (FASTEST) { configuration_table = [ -/* good lazy nice chain */ -/* 0 */ new config(0, 0, 0, 0, deflate_stored), /* store only */ -/* 1 */ new config(4, 4, 8, 4, deflate_fast) /* max speed, no lazy matches */ - ] + /* good lazy nice chain */ + new Config(0, 0, 0, 0, deflate_stored), /* 0 store only */ + new Config(4, 4, 8, 4, deflate_fast) /* 1 max speed, no lazy matches */ + ]; } else { configuration_table = [ - /* good lazy nice chain */ - /* 0 */ new config(0, 0, 0, 0, deflate_stored), /* store only */ - /* 1 */ new config(4, 4, 8, 4, deflate_fast), /* max speed, no lazy matches */ - /* 2 */ new config(4, 5, 16, 8, deflate_fast), - /* 3 */ new config(4, 6, 32, 32, deflate_fast), + /* good lazy nice chain */ + new Config(0, 0, 0, 0, deflate_stored), /* 0 store only */ + new Config(4, 4, 8, 4, deflate_fast), /* 1 max speed, no lazy matches */ + new Config(4, 5, 16, 8, deflate_fast), /* 2 */ + new Config(4, 6, 32, 32, deflate_fast), /* 3 */ - /* 4 */ new config(4, 4, 16, 16, deflate_slow), /* lazy matches */ - /* 5 */ new config(8, 16, 32, 32, deflate_slow), - /* 6 */ new config(8, 16, 128, 128, deflate_slow), - /* 7 */ new config(8, 32, 128, 256, deflate_slow), - /* 8 */ new config(32, 128, 258, 1024, deflate_slow), - /* 9 */ new config(32, 258, 258, 4096, deflate_slow) /* max compression */ - ] + new Config(4, 4, 16, 16, deflate_slow), /* 4 lazy matches */ + new Config(8, 16, 32, 32, deflate_slow), /* 5 */ + new Config(8, 16, 128, 128, deflate_slow), /* 6 */ + new Config(8, 32, 128, 256, deflate_slow), /* 7 */ + new Config(32, 128, 258, 1024, deflate_slow), /* 8 */ + new Config(32, 258, 258, 4096, deflate_slow) /* 9 max compression */ + ]; } -function deflate_state() { - this.status = 0; /* as the name implies */ - this.pending_buf = Z_NULL; /* output still pending */ - this.pending_buf_size = 0; /* size of pending_buf */ - this.pending_out = Z_NULL; /* next pending byte to output to the stream */ - this.pending = 0; /* nb of bytes in the pending buffer */ - this.last_flush = Z_NULL; /* value of flush param for previous deflate call */ +/* =========================================================================== + * Initialize the "longest match" routines for a new zlib stream + */ +function lm_init(s) { + s.window_size = 2 * s.w_size; - this.w_size = 0; /* LZ77 window size (32K by default) */ - this.w_bits = 0; /* log2(w_size) (8..16) */ - this.w_mask = 0; /* w_size - 1 */ + /* Set the default configuration parameters: + */ + s.max_lazy_match = configuration_table[s.level].max_lazy; + s.good_match = configuration_table[s.level].good_length; + s.nice_match = configuration_table[s.level].nice_length; + s.max_chain_length = configuration_table[s.level].max_chain; - this.window = Z_NULL; + s.strstart = 0; + s.block_start = 0; + s.lookahead = 0; + s.insert = 0; + s.match_length = s.prev_length = MIN_MATCH - 1; + s.match_available = 0; + s.ins_h = 0; +} + +function DeflateState() { + this.status = 0; + /* as the name implies */ + //this.pending_buf = Z_NULL; /* output still pending */ + this.pending_buf_size = 0; + /* size of pending_buf */ + this.pending_out = 0; + /* next pending byte to output to the stream */ + this.pending = 0; + /* nb of bytes in the pending buffer */ + this.last_flush = Z_NULL; + /* value of flush param for previous deflate call */ + + this.w_size = 0; + /* LZ77 window size (32K by default) */ + this.w_bits = 0; + /* log2(w_size) (8..16) */ + this.w_mask = 0; + /* w_size - 1 */ + + //this.window = Z_NULL; /* Sliding window. Input bytes are read into the second half of the window, * and move to the first half later to keep a dictionary of at least wSize * bytes. With this organization, matches are limited to a distance of @@ -84,12 +505,17 @@ function deflate_state() { * An index in this array is thus a window index modulo 32K. */ - this.head = Z_NULL; /* Heads of the hash chains or NIL. */ + this.head = Z_NULL; + /* Heads of the hash chains or NIL. */ - this.ins_h = 0; /* hash index of string to be inserted */ - this.hash_size = 0; /* number of elements in hash table */ - this.hash_bits = 0; /* log2(hash_size) */ - this.hash_mask = 0; /* hash_size-1 */ + this.ins_h = 0; + /* hash index of string to be inserted */ + this.hash_size = 0; + /* number of elements in hash table */ + this.hash_bits = 0; + /* log2(hash_size) */ + this.hash_mask = 0; + /* hash_size-1 */ this.hash_shift = 0; /* Number of bits by which ins_h must be shifted at each input @@ -103,14 +529,20 @@ function deflate_state() { * negative when the window is moved backwards. */ - this.match_length = 0; /* length of best match */ - this.prev_match = 0; /* previous match */ - this.match_available = 1; /* set if previous match exists */ - this.strstart = 0; /* start of string to insert */ - this.match_start = 0; /* start of matching string */ - this.lookahead = 0; /* number of valid bytes ahead in window */ + this.match_length = 0; + /* length of best match */ + this.prev_match = 0; + /* previous match */ + this.match_available = 1; + /* set if previous match exists */ + this.strstart = 0; + /* start of string to insert */ + this.match_start = 0; + /* start of matching string */ + this.lookahead = 0; + /* number of valid bytes ahead in window */ - this.prev_length = 0; + this.prev_length = 0; /* Length of the best match at previous step. Matches not greater than this * are discarded. This is used in the lazy match evaluation. */ @@ -132,26 +564,59 @@ function deflate_state() { * max_insert_length is used only for compression levels <= 3. */ - this.level = 0; /* compression level (1..9) */ - this.strategy = 0; /* favor or force Huffman coding*/ + this.level = 0; + /* compression level (1..9) */ + this.strategy = 0; + /* favor or force Huffman coding*/ this.good_match = 0; /* Use a faster search when the previous match is longer than this */ - this.nice_match = 0; /* Stop searching when current match exceeds this */ + this.nice_match = 0; + /* Stop searching when current match exceeds this */ } -function deflateInit (strm, level) { - return deflateInit2(strm, level, c.Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL,c.Z_DEFAULT_STRATEGY); +function deflateResetKeep(strm) { + strm.total_in = strm.total_out = 0; + strm.data_type = c.Z_UNKNOWN; + + var s = strm.state; + s.pending = 0; + s.pending_out = 0; + + if (s.wrap < 0) { + s.wrap = -s.wrap; + /* was made negative by deflate(..., Z_FINISH); */ + } + s.status = s.wrap ? INIT_STATE : BUSY_STATE; + strm.adler = 1; // adler32(0, Z_NULL, 0); + s.last_flush = c.Z_NO_FLUSH; + trees._tr_init(s); + return c.Z_OK; } -function deflateInit2 (strm, level, method, windowBits, memLevel, strategy) { - if (strm == Z_NULL) return c.Z_STREAM_ERROR; +function deflateReset(strm) { + var ret = deflateResetKeep(strm); + if (ret === c.Z_OK) { + lm_init(strm.state); + } + return ret; +} - if(FASTEST) { - if (level != 0) level = 1; +function deflateInit2(strm, level, method, windowBits, memLevel, strategy) { + if (strm === Z_NULL) { + return c.Z_STREAM_ERROR; + } + var wrap = 1; + + if (FASTEST) { + if (level !== 0) { + level = 1; + } } else { - if (level == c.Z_DEFAULT_COMPRESSION) level = 6; + if (level === c.Z_DEFAULT_COMPRESSION) { + level = 6; + } } if (windowBits < 0) { /* suppress zlib wrapper */ @@ -159,9 +624,12 @@ function deflateInit2 (strm, level, method, windowBits, memLevel, strategy) { windowBits = -windowBits; } - if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */ + if (windowBits === 8) { + windowBits = 9; + } + /* until 256-byte window bug fixed */ - var s = new deflate_state(); + var s = new DeflateState(); strm.state = s; s.strm = strm; @@ -172,13 +640,20 @@ function deflateInit2 (strm, level, method, windowBits, memLevel, strategy) { s.w_size = 1 << s.w_bits; s.w_mask = s.w_size - 1; + s.window = utils.arrayCreate(s.w_size * 2); + s.hash_bits = memLevel + 7; s.hash_size = 1 << s.hash_bits; s.hash_mask = s.hash_size - 1; - s.hash_shift = ((s.hash_bits+MIN_MATCH-1)/MIN_MATCH); + s.hash_shift = (s.hash_bits + MIN_MATCH - 1) / MIN_MATCH; - s.high_water = 0; /* nothing written to s->window yet */ - s.lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ + s.high_water = 0; + /* nothing written to s->window yet */ + s.lit_bufsize = 1 << (memLevel + 6); + /* 16K elements by default */ + + s.pending_buf_size = s.lit_bufsize * 4; + s.pending_buf = utils.arrayCreate(s.pending_buf_size); s.level = level; s.strategy = strategy; @@ -187,194 +662,201 @@ function deflateInit2 (strm, level, method, windowBits, memLevel, strategy) { return deflateReset(strm); } -function deflateSetDictionary (strm, dictionary, dictLength) { +function deflateInit(strm, level) { + return deflateInit2(strm, level, c.Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, c.Z_DEFAULT_STRATEGY); +} + +function deflateSetDictionary(/*strm, dictionary, dictLength*/) { } -function deflateResetKeep (strm) { - strm.total_in = strm.total_out = 0; - strm.data_type = c.Z_UNKNOWN; +function deflateParams(/*strm, level, strategy*/) { +} + +function deflateSetHeader(/*strm, head*/) { + +} + +function deflateBound(/*strm, sourceLen*/) { + +} + +function deflatePending(/*strm, pending, bits*/) { + +} + +function deflate(strm, flush) { var s = strm.state; - s.pending = 0; - s.pending_out = s.pending_buf; - if (s.wrap < 0) { - s.wrap = -s.wrap; /* was made negative by deflate(..., Z_FINISH); */ +// if (strm.next_out == Z_NULL || +// (strm.next_in == Z_NULL && strm.avail_in !== 0) || +// (s.status == FINISH_STATE && flush != c.Z_FINISH)) { +// return c.Z_STREAM_ERROR; +// } + if (strm.avail_out === 0) { + return c.Z_BUF_ERROR; } - s.status = s.wrap ? INIT_STATE : BUSY_STATE; - strm.adler = adler32(0, Z_NULL, 0); - s.last_flush = c.Z_NO_FLUSH; - //_tr_init(s); - return c.Z_OK; + + s.strm = strm; + /* just in case */ + var old_flush = s.last_flush; + /* value of flush param for previous deflate call */ + s.last_flush = flush; + + /* Write the header */ + if (s.status === INIT_STATE) { + + var header = (c.Z_DEFLATED + ((s.w_bits - 8) << 4)) << 8; + var level_flags = -1; + + if (s.strategy >= c.Z_HUFFMAN_ONLY || s.level < 2) { + level_flags = 0; + } else if (s.level < 6) { + level_flags = 1; + } else if (s.level === 6) { + level_flags = 2; + } else { + level_flags = 3; + } + header |= (level_flags << 6); + if (s.strstart !== 0) { header |= PRESET_DICT;} + header += 31 - (header % 31); + + s.status = BUSY_STATE; + putShortMSB(s, header); + + /* Save the adler32 of the preset dictionary: */ + if (s.strstart !== 0) { + putShortMSB(s, strm.adler >>> 16); + putShortMSB(s, strm.adler & 0xffff); + } + strm.adler = 1;//adler32(0L, Z_NULL, 0); + } + + /* Flush as much pending output as possible */ + if (s.pending !== 0) { + flush_pending(strm); + if (strm.avail_out === 0) { + /* Since avail_out is 0, deflate will be called again with + * more output space, but possibly with both pending and + * avail_in equal to zero. There won't be anything to do, + * but this is not an error situation so make sure we + * return OK instead of BUF_ERROR at next call of deflate: + */ + s.last_flush = -1; + return c.Z_OK; + } + + /* Make sure there is something to do and avoid duplicate consecutive + * flushes. For repeated and useless calls with Z_FINISH, we keep + * returning Z_STREAM_END instead of Z_BUF_ERROR. + */ + } else if (strm.avail_in === 0 && rank(flush) <= rank(old_flush) && + flush !== c.Z_FINISH) { + return c.Z_BUF_ERROR; + } + + /* User must not provide more input after the first FINISH: */ + if (s.status === FINISH_STATE && strm.avail_in !== 0) { + return c.Z_BUF_ERROR; + } + + /* Start a new block or continue the current one. + */ + if (strm.avail_in !== 0 || s.lookahead !== 0 || + (flush !== c.Z_NO_FLUSH && s.status !== FINISH_STATE)) { + var bstate = s.strategy === c.Z_HUFFMAN_ONLY ? deflate_huff(s, flush) : + (s.strategy === c.Z_RLE ? deflate_rle(s, flush) : + configuration_table[s.level].func(s, flush)); + + if (bstate === BS_FINISH_STARTED || bstate === BS_FINISH_DONE) { + s.status = FINISH_STATE; + } + if (bstate === BS_NEED_MORE || bstate === BS_FINISH_STARTED) { + if (strm.avail_out === 0) { + s.last_flush = -1; + /* avoid BUF_ERROR next call, see above */ + } + return c.Z_OK; + /* If flush != Z_NO_FLUSH && avail_out == 0, the next call + * of deflate should use the same flush parameter to make sure + * that the flush is complete. So we don't have to output an + * empty block here, this will be done at next call. This also + * ensures that for a very small output buffer, we emit at most + * one empty block. + */ + } + if (bstate === BS_BLOCK_DONE) { + /*if (flush === c.Z_PARTIAL_FLUSH) { + //todo:_tr_align(s); + } else*/ + if (flush !== c.Z_BLOCK) { /* FULL_FLUSH or SYNC_FLUSH */ + trees._tr_stored_block(s, 0, 0, 0); + /* For a full flush, this empty block will be recognized + * as a special marker by inflate_sync(). + */ + if (flush === c.Z_FULL_FLUSH) { + //CLEAR_HASH(s); /* forget history */ + s.head[s.hash_size - 1] = -1; + + if (s.lookahead === 0) { + s.strstart = 0; + s.block_start = 0; + s.insert = 0; + } + } + } + flush_pending(strm); + if (strm.avail_out === 0) { + s.last_flush = -1; + /* avoid BUF_ERROR at next call, see above */ + return c.Z_OK; + } + } + } + //Assert(strm->avail_out > 0, "bug2"); + //if (strm.avail_out <= 0) { throw new Error("bug2");} + + if (flush !== c.Z_FINISH) { return c.Z_OK; } + if (s.wrap <= 0) { return c.Z_STREAM_END; } + + putShortMSB(s, strm.adler >>> 16); + putShortMSB(s, strm.adler & 0xffff); + + flush_pending(strm); + /* If avail_out is zero, the application will call deflate again + * to flush the rest. + */ + if (s.wrap > 0) { s.wrap = -s.wrap; } + /* write the trailer only once! */ + return s.pending !== 0 ? c.Z_OK : c.Z_STREAM_END; } -function deflateReset (strm) { - var ret = deflateResetKeep(strm); - if (ret == c.Z_OK) - lm_init(strm.state); - return ret; -} +function deflateEnd(strm) { + var status = strm.state.status; + if (status !== INIT_STATE && + status !== EXTRA_STATE && + status !== NAME_STATE && + status !== COMMENT_STATE && + status !== HCRC_STATE && + status !== BUSY_STATE && + status !== FINISH_STATE + ) { + return c.Z_STREAM_ERROR; + } -function deflateParams (strm,level,strategy) { - -} - -function deflateSetHeader (strm, head) { - -} - -function deflateBound(strm, sourceLen) { - -} - -function deflatePending (strm, pending, bits) { - -} - -/* ========================================================================= - * Put a short in the pending buffer. The 16-bit value is put in MSB order. - * IN assertion: the stream state is correct and there is enough room in - * pending_buf. - */ -function putShortMSB (s, b) { - -} - -/* ========================================================================= - * Flush as much pending output as possible. All deflate() output goes - * through this function so some applications may wish to modify it - * to avoid allocating a large strm->next_out buffer and copying into it. - * (See also read_buf()). - */ -function flush_pending(strm) { - -} - -function deflate (strm, flush) { - -} - -function deflateEnd (strm) { + strm.state = Z_NULL; + return status === BUSY_STATE ? c.Z_DATA_ERROR : c.Z_OK; } /* ========================================================================= * Copy the source state to the destination state */ -function deflateCopy (dest, source) { - -} - -/* =========================================================================== - * Read a new buffer from the current input stream, update the adler32 - * and total number of bytes read. All deflate() input goes through - * this function so some applications may wish to modify it to avoid - * allocating a large strm->next_in buffer and copying from it. - * (See also flush_pending()). - */ -function read_buf(strm, buf, size) { - -} - -/* =========================================================================== - * Initialize the "longest match" routines for a new zlib stream - */ -function lm_init (s) { - s.window_size = 2* s.w_size; - - /* Set the default configuration parameters: - */ - s.max_lazy_match = configuration_table[s.level].max_lazy; - s.good_match = configuration_table[s.level].good_length; - s.nice_match = configuration_table[s.level].nice_length; - s.max_chain_length = configuration_table[s.level].max_chain; - - s.strstart = 0; - s.block_start = 0; - s.lookahead = 0; - s.insert = 0; - s.match_length = s.prev_length = MIN_MATCH-1; - s.match_available = 0; - s.ins_h = 0; -} - -/* =========================================================================== - * Set match_start to the longest match starting at the given string and - * return its length. Matches shorter or equal to prev_length are discarded, - * in which case the result is equal to prev_length and match_start is - * garbage. - * IN assertions: cur_match is the head of the hash chain for the current - * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 - * OUT assertion: the match length is not greater than s->lookahead. - */ -function longest_match(s, cur_match) { - -} - -/* =========================================================================== - * Fill the window when the lookahead becomes insufficient. - * Updates strstart and lookahead. - * - * IN assertion: lookahead < MIN_LOOKAHEAD - * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD - * At least one byte has been read, or avail_in == 0; reads are - * performed for at least two bytes (required for the zip translate_eol - * option -- not supported here). - */ -function fill_window(s) { - -} - -/* =========================================================================== - * Copy without compression as much as possible from the input stream, return - * the current block state. - * This function does not insert new strings in the dictionary since - * uncompressible data is probably not useful. This function is used - * only for the level=0 compression option. - * NOTE: this function should be optimized to avoid extra copying from - * window to pending_buf. - */ -function deflate_stored(s, flush) { - -} - -/* =========================================================================== - * Compress as much as possible from the input stream, return the current - * block state. - * This function does not perform lazy evaluation of matches and inserts - * new strings in the dictionary only for unmatched strings or for short - * matches. It is used only for the fast compression options. - */ -function deflate_fast(s, flush) { - -} - -/* =========================================================================== - * Same as above, but achieves better compression. We use a lazy - * evaluation for matches: a match is finally adopted only if there is - * no better match at the next window position. - */ -function deflate_slow(s, flush) { - -} - -/* =========================================================================== - * For Z_RLE, simply look for runs of bytes, generate matches only of distance - * one. Do not maintain a hash table. (It will be regenerated if this run of - * deflate switches away from Z_RLE.) - */ -function deflate_rle(s, flush) { - -} - -/* =========================================================================== - * For Z_HUFFMAN_ONLY, do not look for matches. Do not maintain a hash table. - * (It will be regenerated if this run of deflate switches away from Huffman.) - */ -function deflate_huff(s, flush) { - -} +//function deflateCopy(dest, source) { +// +//} exports.deflateInit = deflateInit; diff --git a/lib/zlib/inflate.js b/lib/zlib/inflate.js index 70e983e..96892c8 100644 --- a/lib/zlib/inflate.js +++ b/lib/zlib/inflate.js @@ -1,16 +1,18 @@ -var utils = require('utils'); +'use strict'; + +//var utils = require('utils'); var ENOUGH_LENS = 852; var ENOUGH_DISTS = 592; var ENOUGH = (ENOUGH_LENS+ENOUGH_DISTS); -function code() { - this.op = 0; /* operation, extra bits, table bits */ - this.bits = 0; /* bits in this part of the code */ - this.val = 0; /* offset in table or code value */ -}; +//function Code() { +// this.op = 0; /* operation, extra bits, table bits */ +// this.bits = 0; /* bits in this part of the code */ +// this.val = 0; /* offset in table or code value */ +//} -function inflate_state() { +function InflateState() { this.mode = -1; /* current inflate mode */ this.last = 0; /* true if processing last block */ this.wrap = 0; /* bit 0 true for zlib, bit 1 true for gzip */ @@ -55,29 +57,29 @@ function inflate_state() { this.sane = 0; /* if false, allow invalid distance too far */ this.back = 0; /* bits back of last unprocessed length/lit */ this.was = 0; /* initial length of match */ -}; +} -function inflateResetKeep(strm) { +function inflateResetKeep(/*strm*/) { } -function inflateReset(strm) { +function inflateReset(/*strm*/) { } -function inflateReset2(strm, windowBits) { +function inflateReset2(/*strm, windowBits*/) { } -function inflateInit2(strm, windowBits, version, stream_size) { +function inflateInit2(strm/*, windowBits, version, stream_size*/) { + strm.state = new InflateState(); +} + +function inflateInit(/*strm, version, stream_size*/) { } -function inflateInit(strm, version, stream_size) { - -} - -function inflatePrime(strm, bits, value) { +function inflatePrime(/*strm, bits, value*/) { } @@ -91,9 +93,9 @@ function inflatePrime(strm, bits, value) { used for threaded applications, since the rewriting of the tables and virgin may not be thread-safe. */ -function fixedtables(state) { - -} +//function fixedtables(state) { +// +//} /* Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also @@ -113,9 +115,9 @@ function fixedtables(state) { a.out > inffixed.h */ -function makefixed() { - -} +//function makefixed() { +// +//} /* Update the window with the last wsize (normally 32K) bytes written before @@ -131,27 +133,27 @@ function makefixed() { output will fall in the output data, making match copies simpler and faster. The advantage may be dependent on the size of the processor's data caches. */ -function updatewindow(strm, end, copy) { +//function updatewindow(strm, end, copy) { +// +//} + +function inflate(/*strm, flush*/) { } -function inflate(strm, flush) { +function inflateEnd(/*strm*/) { } -function inflateEnd(strm) { +function inflateGetDictionary(/*strm, dictionary, dictLength*/) { } -function inflateGetDictionary(strm, dictionary, dictLength) { +function inflateSetDictionary(/*strm, dictionary, dictLength*/) { } -function inflateSetDictionary(strm, dictionary, dictLength) { - -} - -function inflateGetHeader(strm, head) { +function inflateGetHeader(/*strm, head*/) { } @@ -166,27 +168,27 @@ function inflateGetHeader(strm, head) { called again with more data and the *have state. *have is initialized to zero for the first call. */ -function syncsearch(have, buf, len) { +//function syncsearch(/*have, buf, len*/) { +// +//} + +function inflateSync(/*strm*/) { } -function inflateSync(strm) { +function inflateSyncPoint(/*strm*/) { } -function inflateSyncPoint(strm) { +function inflateCopy(/*dest, source*/) { } -function inflateCopy(dest, source) { +function inflateUndermine(/*strm, subvert*/) { } -function inflateUndermine(strm, subvert) { - -} - -function inflateMark(strm) { +function inflateMark(/*strm*/) { } @@ -210,6 +212,8 @@ exports.inflateGetDictionary = inflateGetDictionary; exports.inflateGetHeader = inflateGetHeader; +exports.inflateSetDictionary = inflateSetDictionary; + exports.inflateSync = inflateSync; exports.inflateSyncPoint = inflateSyncPoint; diff --git a/lib/zlib/messages.js b/lib/zlib/messages.js new file mode 100644 index 0000000..4c171da --- /dev/null +++ b/lib/zlib/messages.js @@ -0,0 +1,13 @@ +'use strict'; + +module.exports = { + '2': 'need dictionary', /* Z_NEED_DICT 2 */ + '1': 'stream end', /* Z_STREAM_END 1 */ + '0': '', /* Z_OK 0 */ + '-1': 'file error', /* Z_ERRNO (-1) */ + '-2': 'stream error', /* Z_STREAM_ERROR (-2) */ + '-3': 'data error', /* Z_DATA_ERROR (-3) */ + '-4': 'insufficient memory', /* Z_MEM_ERROR (-4) */ + '-5': 'buffer error', /* Z_BUF_ERROR (-5) */ + '-6': 'incompatible version' /* Z_VERSION_ERROR (-6) */ +}; \ No newline at end of file diff --git a/lib/zlib/trees.js b/lib/zlib/trees.js new file mode 100644 index 0000000..1eb57e9 --- /dev/null +++ b/lib/zlib/trees.js @@ -0,0 +1,179 @@ +'use strict'; + +var utils = require('./utils'); + +var STORED_BLOCK = 0; +var Buf_size = 16; + +/* =========================================================================== + * Output a short LSB first on the stream. + * IN assertion: there is enough room in pendingBuf. + */ +function put_short (s, w) { +// put_byte(s, (uch)((w) & 0xff)); +// put_byte(s, (uch)((ush)(w) >> 8)); + s.pending_buf[s.pending++] = (w) & 0xff; + s.pending_buf[s.pending++] = (w >>> 8) & 0xff; +} + +/* =========================================================================== + * Send a value on a given number of bits. + * IN assertion: length <= 16 and value fits in length bits. + */ +function send_bits (s, value, length) +{ + var len = length, val = value; + if (s.bi_valid > Buf_size - len) { + s.bi_buf |= (val << s.bi_valid) & 0xffff; + put_short(s, s.bi_buf); + s.bi_buf = val >>> (Buf_size - s.bi_valid); + s.bi_valid += len - Buf_size; + } else { + s.bi_buf |= ((value) << s.bi_valid) & 0xffff; + s.bi_valid += len; + } +} + +/* =========================================================================== + * Flush the bit buffer and align the output on a byte boundary + */ +function bi_windup (s) +{ + if (s.bi_valid > 8) { + put_short(s, s.bi_buf); + } else if (s.bi_valid > 0) { + //put_byte(s, (Byte)s->bi_buf); + s.pending_buf[s.pending++] = s.bi_buf; + } + s.bi_buf = 0; + s.bi_valid = 0; +} + +/* =========================================================================== + * Copy a stored block, storing first the length and its + * one's complement if requested. + */ +function copy_block (s, buf, len, header) +//DeflateState *s; +//charf *buf; /* the input data */ +//unsigned len; /* its length */ +//int header; /* true if block header must be written */ +{ + bi_windup(s); /* align on byte boundary */ + + if (header) { + put_short(s, len); + put_short(s, ~len); + } +// while (len--) { +// put_byte(s, *buf++); +// } + utils.arraySet(s.pending_buf, s.window, buf, len, s.pending); + s.pending += len; +} + + +/* =========================================================================== + * Initialize the tree data structures for a new zlib stream. + */ +function _tr_init(s) +{ +// todo: tr_static_init(); +// +// s.l_desc.dyn_tree = s.dyn_ltree; +// s.l_desc.stat_desc = static_l_desc; +// +// s.d_desc.dyn_tree = s.dyn_dtree; +// s.d_desc.stat_desc = static_d_desc; +// +// s.bl_desc.dyn_tree = s.bl_tree; +// s.bl_desc.stat_desc = static_bl_desc; +// + s.bi_buf = 0; + s.bi_valid = 0; +// +// /* Initialize the first block of the first file: */ +// todo:init_block(s); +} + +/* =========================================================================== + * Send a stored block + */ +function _tr_stored_block(s, buf, stored_len, last) +//DeflateState *s; +//charf *buf; /* input block */ +//ulg stored_len; /* length of input block */ +//int last; /* one if this is the last block for a file */ +{ + send_bits(s, (STORED_BLOCK<<1)+(last ? 1 : 0), 3); /* send block type */ + copy_block(s, buf, stored_len, 1); /* with header */ +} + +/* =========================================================================== + * Determine the best encoding for the current block: dynamic trees, static + * trees or store, and output the encoded block to the zip file. + */ +function _tr_flush_block(s, buf, stored_len, last) +//DeflateState *s; +//charf *buf; /* input block, or NULL if too old */ +//ulg stored_len; /* length of input block */ +//int last; /* one if this is the last block for a file */ +{ + var opt_lenb = 0, static_lenb = 0; /* opt_len and static_len in bytes */ +// var max_blindex = 0; /* index of last bit length code of non zero freq */ + + /* Build the Huffman trees unless a stored block is forced */ + if (s.level > 0) { + /* Construct the literal and distance trees */ + //todo: build_tree(s, s.l_desc); + //todo: build_tree(s, s->d_desc); + + /* At this point, opt_len and static_len are the total bit lengths of + * the compressed block data, excluding the tree representations. + */ + + /* Build the bit length tree for the above two trees, and get the index + * in bl_order of the last bit length code to send. + */ + //todo: max_blindex = build_bl_tree(s); + + /* Determine the best encoding. Compute the block lengths in bytes. */ + opt_lenb = (s.opt_len + 3 + 7) >>> 3; + static_lenb = (s.static_len + 3 + 7) >>> 3; + + if (static_lenb <= opt_lenb) { opt_lenb = static_lenb; } + + } else { + opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ + } + + if ((stored_len+4 <= opt_lenb) && (buf !== -1)) { + /* 4: two words for the lengths */ + + /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. + * Otherwise we can't have processed more than WSIZE input bytes since + * the last block flush, because compression would have been + * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to + * transform a block into a stored block. + */ + _tr_stored_block(s, buf, stored_len, last); + } +// else { +// //send_bits(s, (DYN_TREES<<1)+(last ? 1 : 0), 3); +// //todo: send_all_trees(s, s.l_desc.max_code+1, s.d_desc.max_code+1,max_blindex+1); +// //todo: compress_block(s, s->dyn_ltree,s->dyn_dtree); +// } + + /* The above check is made mod 2^32, for files larger than 512 MB + * and uLong implemented on 32 bits. + */ + //todo: init_block(s); + + if (last) { + bi_windup(s); + } +} + +exports._tr_init = _tr_init; +exports._tr_stored_block = _tr_stored_block; +exports._tr_flush_block = _tr_flush_block; \ No newline at end of file diff --git a/lib/zlib/utils.js b/lib/zlib/utils.js index 6ea97d7..45516bb 100644 --- a/lib/zlib/utils.js +++ b/lib/zlib/utils.js @@ -1,11 +1,10 @@ 'use strict'; - exports.assign = function(obj /*from1, from2, from3, ...*/) { var sources = Array.prototype.slice.call(arguments, 1); while (sources.length) { var source = sources.shift(); - if (!source) { continue } + if (!source) { continue; } if (typeof(source) !== 'object') { throw new TypeError(source + 'must be non-object'); @@ -26,8 +25,9 @@ exports.arraySet = function(dest, src, src_offs, len, dest_offs) { for(var i=0; i