mirror of
https://github.com/0x5eal/rbxts-pako.git
synced 2025-05-04 10:33:48 +01:00
Deflate: added custom gzip headers support
This commit is contained in:
parent
e4593facbb
commit
b165c9c945
3 changed files with 207 additions and 13 deletions
|
@ -86,6 +86,14 @@ var Z_DEFLATED = 8;
|
||||||
* - `gzip` (Boolean) - create gzip wrapper
|
* - `gzip` (Boolean) - create gzip wrapper
|
||||||
* - `to` (String) - if equal to 'string', then result will be "binary string"
|
* - `to` (String) - if equal to 'string', then result will be "binary string"
|
||||||
* (each char code [0..255])
|
* (each char code [0..255])
|
||||||
|
* - `header` (Object) - custom header for gzip
|
||||||
|
* - `text` (Boolean) - true if compressed data believed to be text
|
||||||
|
* - `time` (Number) - modification time, unix timestamp
|
||||||
|
* - `os` (Number) - operation system code
|
||||||
|
* - `extra` (Array) - array of bytes with extra data (max 65536)
|
||||||
|
* - `name` (String) - file name (binary string)
|
||||||
|
* - `comment` (String) - comment (binary string)
|
||||||
|
* - `hcrc` (Boolean) - true if header crc should be added
|
||||||
*
|
*
|
||||||
* ##### Example:
|
* ##### Example:
|
||||||
*
|
*
|
||||||
|
@ -146,6 +154,10 @@ var Deflate = function(options) {
|
||||||
if (status !== Z_OK) {
|
if (status !== Z_OK) {
|
||||||
throw new Error(msg[status]);
|
throw new Error(msg[status]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (opt.header) {
|
||||||
|
zlib_deflate.deflateSetHeader(this.strm, opt.header);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1179,13 +1179,6 @@ function DeflateState() {
|
||||||
zero(this.dyn_dtree);
|
zero(this.dyn_dtree);
|
||||||
zero(this.bl_tree);
|
zero(this.bl_tree);
|
||||||
|
|
||||||
// struct tree_desc_s l_desc; /* desc. for literal tree */
|
|
||||||
// struct tree_desc_s d_desc; /* desc. for distance tree */
|
|
||||||
// struct tree_desc_s bl_desc; /* desc. for bit length tree */
|
|
||||||
|
|
||||||
// Seems to init better from `tree` with direct structures,
|
|
||||||
// (?) with separate constructor for bl_desc or not?
|
|
||||||
// Make sure objects have the same hidden class if needed
|
|
||||||
this.l_desc = null; /* desc. for literal tree */
|
this.l_desc = null; /* desc. for literal tree */
|
||||||
this.d_desc = null; /* desc. for distance tree */
|
this.d_desc = null; /* desc. for distance tree */
|
||||||
this.bl_desc = null; /* desc. for bit length tree */
|
this.bl_desc = null; /* desc. for bit length tree */
|
||||||
|
@ -1264,6 +1257,7 @@ function DeflateState() {
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function deflateResetKeep(strm) {
|
function deflateResetKeep(strm) {
|
||||||
var s;
|
var s;
|
||||||
|
|
||||||
|
@ -1292,6 +1286,7 @@ function deflateResetKeep(strm) {
|
||||||
return Z_OK;
|
return Z_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function deflateReset(strm) {
|
function deflateReset(strm) {
|
||||||
var ret = deflateResetKeep(strm);
|
var ret = deflateResetKeep(strm);
|
||||||
if (ret === Z_OK) {
|
if (ret === Z_OK) {
|
||||||
|
@ -1300,6 +1295,15 @@ function deflateReset(strm) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function deflateSetHeader(strm, head) {
|
||||||
|
if (!strm || !strm.state) { return Z_STREAM_ERROR; }
|
||||||
|
if (strm.state.wrap !== 2) { return Z_STREAM_ERROR; }
|
||||||
|
strm.state.gzhead = head;
|
||||||
|
return Z_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function deflateInit2(strm, level, method, windowBits, memLevel, strategy) {
|
function deflateInit2(strm, level, method, windowBits, memLevel, strategy) {
|
||||||
if (!strm) { // === Z_NULL
|
if (!strm) { // === Z_NULL
|
||||||
return err(strm, Z_STREAM_ERROR);
|
return err(strm, Z_STREAM_ERROR);
|
||||||
|
@ -1378,6 +1382,7 @@ function deflateInit(strm, level) {
|
||||||
|
|
||||||
function deflate(strm, flush) {
|
function deflate(strm, flush) {
|
||||||
var old_flush, s;
|
var old_flush, s;
|
||||||
|
var beg, val; // for gzip header write only
|
||||||
|
|
||||||
if (!strm || !strm.state ||
|
if (!strm || !strm.state ||
|
||||||
flush > Z_BLOCK || flush < 0) {
|
flush > Z_BLOCK || flush < 0) {
|
||||||
|
@ -1417,7 +1422,29 @@ function deflate(strm, flush) {
|
||||||
s.status = BUSY_STATE;
|
s.status = BUSY_STATE;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throw new Error('Custom GZIP headers not supported');
|
put_byte(s, (s.gzhead.text ? 1 : 0) +
|
||||||
|
(s.gzhead.hcrc ? 2 : 0) +
|
||||||
|
(!s.gzhead.extra ? 0 : 4) +
|
||||||
|
(!s.gzhead.name ? 0 : 8) +
|
||||||
|
(!s.gzhead.comment ? 0 : 16)
|
||||||
|
);
|
||||||
|
put_byte(s, s.gzhead.time & 0xff);
|
||||||
|
put_byte(s, (s.gzhead.time >> 8) & 0xff);
|
||||||
|
put_byte(s, (s.gzhead.time >> 16) & 0xff);
|
||||||
|
put_byte(s, (s.gzhead.time >> 24) & 0xff);
|
||||||
|
put_byte(s, s.level === 9 ? 2 :
|
||||||
|
(s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ?
|
||||||
|
4 : 0));
|
||||||
|
put_byte(s, s.gzhead.os & 0xff);
|
||||||
|
if (s.gzhead.extra && s.gzhead.extra.length) {
|
||||||
|
put_byte(s, s.gzhead.extra.length & 0xff);
|
||||||
|
put_byte(s, (s.gzhead.extra.length >> 8) & 0xff);
|
||||||
|
}
|
||||||
|
if (s.gzhead.hcrc) {
|
||||||
|
strm.adler = crc32(strm.adler, s.pending_buf, s.pending, 0);
|
||||||
|
}
|
||||||
|
s.gzindex = 0;
|
||||||
|
s.status = EXTRA_STATE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else // DEFLATE header
|
else // DEFLATE header
|
||||||
|
@ -1450,6 +1477,130 @@ function deflate(strm, flush) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//#ifdef GZIP
|
||||||
|
if (s.status === EXTRA_STATE) {
|
||||||
|
if (s.gzhead.extra/* != Z_NULL*/) {
|
||||||
|
beg = s.pending; /* start of bytes to update crc */
|
||||||
|
|
||||||
|
while (s.gzindex < (s.gzhead.extra.length & 0xffff)) {
|
||||||
|
if (s.pending === s.pending_buf_size) {
|
||||||
|
if (s.gzhead.hcrc && s.pending > beg) {
|
||||||
|
strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);
|
||||||
|
}
|
||||||
|
flush_pending(strm);
|
||||||
|
beg = s.pending;
|
||||||
|
if (s.pending === s.pending_buf_size) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
put_byte(s, s.gzhead.extra[s.gzindex] & 0xff);
|
||||||
|
s.gzindex++;
|
||||||
|
}
|
||||||
|
if (s.gzhead.hcrc && s.pending > beg) {
|
||||||
|
strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);
|
||||||
|
}
|
||||||
|
if (s.gzindex === s.gzhead.extra.length) {
|
||||||
|
s.gzindex = 0;
|
||||||
|
s.status = NAME_STATE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
s.status = NAME_STATE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (s.status === NAME_STATE) {
|
||||||
|
if (s.gzhead.name/* != Z_NULL*/) {
|
||||||
|
beg = s.pending; /* start of bytes to update crc */
|
||||||
|
//int val;
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (s.pending === s.pending_buf_size) {
|
||||||
|
if (s.gzhead.hcrc && s.pending > beg) {
|
||||||
|
strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);
|
||||||
|
}
|
||||||
|
flush_pending(strm);
|
||||||
|
beg = s.pending;
|
||||||
|
if (s.pending === s.pending_buf_size) {
|
||||||
|
val = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// JS specific: little magic to add zero terminator to end of string
|
||||||
|
if (s.gzindex < s.gzhead.name.length) {
|
||||||
|
val = s.gzhead.name.charCodeAt(s.gzindex++) & 0xff;
|
||||||
|
} else {
|
||||||
|
val = 0;
|
||||||
|
}
|
||||||
|
put_byte(s, val);
|
||||||
|
} while (val !== 0);
|
||||||
|
|
||||||
|
if (s.gzhead.hcrc && s.pending > beg){
|
||||||
|
strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);
|
||||||
|
}
|
||||||
|
if (val === 0) {
|
||||||
|
s.gzindex = 0;
|
||||||
|
s.status = COMMENT_STATE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
s.status = COMMENT_STATE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (s.status === COMMENT_STATE) {
|
||||||
|
if (s.gzhead.comment/* != Z_NULL*/) {
|
||||||
|
beg = s.pending; /* start of bytes to update crc */
|
||||||
|
//int val;
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (s.pending === s.pending_buf_size) {
|
||||||
|
if (s.gzhead.hcrc && s.pending > beg) {
|
||||||
|
strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);
|
||||||
|
}
|
||||||
|
flush_pending(strm);
|
||||||
|
beg = s.pending;
|
||||||
|
if (s.pending === s.pending_buf_size) {
|
||||||
|
val = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// JS specific: little magic to add zero terminator to end of string
|
||||||
|
if (s.gzindex < s.gzhead.comment.length) {
|
||||||
|
val = s.gzhead.comment.charCodeAt(s.gzindex++) & 0xff;
|
||||||
|
} else {
|
||||||
|
val = 0;
|
||||||
|
}
|
||||||
|
put_byte(s, val);
|
||||||
|
} while (val !== 0);
|
||||||
|
|
||||||
|
if (s.gzhead.hcrc && s.pending > beg) {
|
||||||
|
strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);
|
||||||
|
}
|
||||||
|
if (val === 0) {
|
||||||
|
s.status = HCRC_STATE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
s.status = HCRC_STATE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (s.status === HCRC_STATE) {
|
||||||
|
if (s.gzhead.hcrc) {
|
||||||
|
if (s.pending + 2 > s.pending_buf_size) {
|
||||||
|
flush_pending(strm);
|
||||||
|
}
|
||||||
|
if (s.pending + 2 <= s.pending_buf_size) {
|
||||||
|
put_byte(s, strm.adler & 0xff);
|
||||||
|
put_byte(s, (strm.adler >> 8) & 0xff);
|
||||||
|
strm.adler = 0; //crc32(0L, Z_NULL, 0);
|
||||||
|
s.status = BUSY_STATE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
s.status = BUSY_STATE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//#endif
|
||||||
|
|
||||||
/* Flush as much pending output as possible */
|
/* Flush as much pending output as possible */
|
||||||
if (s.pending !== 0) {
|
if (s.pending !== 0) {
|
||||||
flush_pending(strm);
|
flush_pending(strm);
|
||||||
|
@ -1597,6 +1748,7 @@ function deflateEnd(strm) {
|
||||||
exports.deflateInit = deflateInit;
|
exports.deflateInit = deflateInit;
|
||||||
exports.deflateInit2 = deflateInit2;
|
exports.deflateInit2 = deflateInit2;
|
||||||
exports.deflateReset = deflateReset;
|
exports.deflateReset = deflateReset;
|
||||||
|
exports.deflateSetHeader = deflateSetHeader;
|
||||||
exports.deflate = deflate;
|
exports.deflate = deflate;
|
||||||
exports.deflateEnd = deflateEnd;
|
exports.deflateEnd = deflateEnd;
|
||||||
exports.deflateInfo = 'pako deflate (from Nodeca project)';
|
exports.deflateInfo = 'pako deflate (from Nodeca project)';
|
||||||
|
@ -1604,7 +1756,6 @@ exports.deflateInfo = 'pako deflate (from Nodeca project)';
|
||||||
/* Not implemented
|
/* Not implemented
|
||||||
exports.deflateSetDictionary = deflateSetDictionary;
|
exports.deflateSetDictionary = deflateSetDictionary;
|
||||||
exports.deflateParams = deflateParams;
|
exports.deflateParams = deflateParams;
|
||||||
exports.deflateSetHeader = deflateSetHeader;
|
|
||||||
exports.deflateBound = deflateBound;
|
exports.deflateBound = deflateBound;
|
||||||
exports.deflatePending = deflatePending;
|
exports.deflatePending = deflatePending;
|
||||||
*/
|
*/
|
|
@ -4,12 +4,13 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
var assert = require('assert');
|
var assert = require('assert');
|
||||||
|
|
||||||
var pako_utils = require('../lib/utils/common');
|
var pako_utils = require('../lib/utils/common');
|
||||||
var pako = require('../index');
|
var pako = require('../index');
|
||||||
|
var cmp = require('./helpers').cmpBuf;
|
||||||
|
|
||||||
|
|
||||||
function a2s(array) {
|
function a2s(array) {
|
||||||
|
@ -29,6 +30,36 @@ describe('Gzip special cases', function() {
|
||||||
assert.equal(a2s(inflator.header.extra), 'test extra');
|
assert.equal(a2s(inflator.header.extra), 'test extra');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Write custom headers', function() {
|
||||||
|
var data = ' ';
|
||||||
|
|
||||||
|
var deflator = new pako.Deflate({
|
||||||
|
gzip: true,
|
||||||
|
header: {
|
||||||
|
hcrc: true,
|
||||||
|
time: 1234567,
|
||||||
|
os: 15,
|
||||||
|
name: 'test name',
|
||||||
|
comment: 'test comment',
|
||||||
|
extra: [4,5,6]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
deflator.push(data, true);
|
||||||
|
|
||||||
|
var inflator = new pako.Inflate({ to: 'string' });
|
||||||
|
inflator.push(deflator.result, true);
|
||||||
|
|
||||||
|
assert.equal(inflator.err, 0);
|
||||||
|
assert.equal(inflator.result, data);
|
||||||
|
|
||||||
|
var header = inflator.header;
|
||||||
|
assert.equal(header.time, 1234567);
|
||||||
|
assert.equal(header.os, 15);
|
||||||
|
assert.equal(header.name, 'test name');
|
||||||
|
assert.equal(header.comment, 'test comment');
|
||||||
|
assert(cmp(header.extra, [4,5,6]));
|
||||||
|
});
|
||||||
|
|
||||||
it('Read stream with SYNC marks', function() {
|
it('Read stream with SYNC marks', function() {
|
||||||
var inflator, strm, _in, len, pos = 0, i = 0;
|
var inflator, strm, _in, len, pos = 0, i = 0;
|
||||||
var data = fs.readFileSync(path.join(__dirname, 'fixtures/gzip-joined.gz'));
|
var data = fs.readFileSync(path.join(__dirname, 'fixtures/gzip-joined.gz'));
|
||||||
|
|
Loading…
Add table
Reference in a new issue