mirror of
https://github.com/nodejs/node.git
synced 2024-11-21 10:59:27 +00:00
[zlib] added dictionary support
This commit is contained in:
parent
21d081fd7f
commit
e609195202
@ -215,6 +215,7 @@ relevant when compressing, and are ignored by the decompression classes.
|
||||
* level (compression only)
|
||||
* memLevel (compression only)
|
||||
* strategy (compression only)
|
||||
* dictionary (deflate/inflate only, empty dictionary by default)
|
||||
|
||||
See the description of `deflateInit2` and `inflateInit2` at
|
||||
<http://zlib.net/manual.html#Advanced> for more information on these.
|
||||
|
@ -259,11 +259,18 @@ function Zlib(opts, Binding) {
|
||||
}
|
||||
}
|
||||
|
||||
if (opts.dictionary) {
|
||||
if (!Buffer.isBuffer(opts.dictionary)) {
|
||||
throw new Error('Invalid dictionary: it should be a Buffer instance');
|
||||
}
|
||||
}
|
||||
|
||||
this._binding = new Binding();
|
||||
this._binding.init(opts.windowBits || exports.Z_DEFAULT_WINDOWBITS,
|
||||
opts.level || exports.Z_DEFAULT_COMPRESSION,
|
||||
opts.memLevel || exports.Z_DEFAULT_MEMLEVEL,
|
||||
opts.strategy || exports.Z_DEFAULT_STRATEGY);
|
||||
opts.strategy || exports.Z_DEFAULT_STRATEGY,
|
||||
opts.dictionary);
|
||||
|
||||
this._chunkSize = opts.chunkSize || exports.Z_DEFAULT_CHUNK;
|
||||
this._buffer = new Buffer(this._chunkSize);
|
||||
|
@ -64,6 +64,7 @@ template <node_zlib_mode mode> class ZCtx : public ObjectWrap {
|
||||
public:
|
||||
|
||||
ZCtx() : ObjectWrap() {
|
||||
dictionary_ = NULL;
|
||||
}
|
||||
|
||||
~ZCtx() {
|
||||
@ -72,6 +73,8 @@ template <node_zlib_mode mode> class ZCtx : public ObjectWrap {
|
||||
} else if (mode == INFLATE || mode == GUNZIP || mode == INFLATERAW) {
|
||||
(void)inflateEnd(&strm_);
|
||||
}
|
||||
|
||||
if (dictionary_ != NULL) delete[] dictionary_;
|
||||
}
|
||||
|
||||
// write(flush, in, in_off, in_len, out, out_off, out_len)
|
||||
@ -163,6 +166,22 @@ template <node_zlib_mode mode> class ZCtx : public ObjectWrap {
|
||||
case GUNZIP:
|
||||
case INFLATERAW:
|
||||
err = inflate(&(ctx->strm_), ctx->flush_);
|
||||
|
||||
// If data was encoded with dictionary
|
||||
if (err == Z_NEED_DICT) {
|
||||
assert(ctx->dictionary_ != NULL && "Stream has no dictionary");
|
||||
|
||||
// Load it
|
||||
err = inflateSetDictionary(
|
||||
&(ctx->strm_),
|
||||
ctx->dictionary_,
|
||||
ctx->dictionary_len_
|
||||
);
|
||||
assert(err == Z_OK && "Failed to set dictionary");
|
||||
|
||||
// And try to decode again
|
||||
err = inflate(&(ctx->strm_), ctx->flush_);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
assert(0 && "wtf?");
|
||||
@ -206,8 +225,8 @@ template <node_zlib_mode mode> class ZCtx : public ObjectWrap {
|
||||
Init(const Arguments& args) {
|
||||
HandleScope scope;
|
||||
|
||||
assert(args.Length() == 4 &&
|
||||
"init(windowBits, level, memLevel, strategy)");
|
||||
assert((args.Length() == 4 || args.Length() == 5) &&
|
||||
"init(windowBits, level, memLevel, strategy, [dictionary])");
|
||||
|
||||
ZCtx<mode> *ctx = ObjectWrap::Unwrap< ZCtx<mode> >(args.This());
|
||||
|
||||
@ -227,7 +246,19 @@ template <node_zlib_mode mode> class ZCtx : public ObjectWrap {
|
||||
strategy == Z_FIXED ||
|
||||
strategy == Z_DEFAULT_STRATEGY) && "invalid strategy");
|
||||
|
||||
Init(ctx, level, windowBits, memLevel, strategy);
|
||||
char* dictionary = NULL;
|
||||
size_t dictionary_len = 0;
|
||||
if (args.Length() >= 5 && Buffer::HasInstance(args[4])) {
|
||||
Local<Object> dictionary_ = args[4]->ToObject();
|
||||
|
||||
dictionary_len = Buffer::Length(dictionary_);
|
||||
dictionary = new char[dictionary_len];
|
||||
|
||||
memcpy(dictionary, Buffer::Data(dictionary_), dictionary_len);
|
||||
}
|
||||
|
||||
Init(ctx, level, windowBits, memLevel, strategy,
|
||||
dictionary, dictionary_len);
|
||||
return Undefined();
|
||||
}
|
||||
|
||||
@ -236,7 +267,9 @@ template <node_zlib_mode mode> class ZCtx : public ObjectWrap {
|
||||
int level,
|
||||
int windowBits,
|
||||
int memLevel,
|
||||
int strategy) {
|
||||
int strategy,
|
||||
char* dictionary,
|
||||
size_t dictionary_len) {
|
||||
ctx->level_ = level;
|
||||
ctx->windowBits_ = windowBits;
|
||||
ctx->memLevel_ = memLevel;
|
||||
@ -282,8 +315,29 @@ template <node_zlib_mode mode> class ZCtx : public ObjectWrap {
|
||||
assert(0 && "wtf?");
|
||||
}
|
||||
|
||||
ctx->init_done_ = true;
|
||||
assert(err == Z_OK);
|
||||
|
||||
ctx->dictionary_ = reinterpret_cast<Bytef *>(dictionary);
|
||||
ctx->dictionary_len_ = dictionary_len;
|
||||
|
||||
if (dictionary != NULL) {
|
||||
switch (mode) {
|
||||
case DEFLATE:
|
||||
case DEFLATERAW:
|
||||
err = deflateSetDictionary(
|
||||
&(ctx->strm_),
|
||||
ctx->dictionary_,
|
||||
dictionary_len
|
||||
);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
assert(err == Z_OK && "Failed to set dictionary");
|
||||
}
|
||||
|
||||
ctx->init_done_ = true;
|
||||
}
|
||||
|
||||
private:
|
||||
@ -296,6 +350,9 @@ template <node_zlib_mode mode> class ZCtx : public ObjectWrap {
|
||||
int memLevel_;
|
||||
int strategy_;
|
||||
|
||||
Bytef* dictionary_;
|
||||
size_t dictionary_len_;
|
||||
|
||||
int flush_;
|
||||
|
||||
int chunk_size_;
|
||||
|
73
test/simple/test-zlib-dictionary.js
Normal file
73
test/simple/test-zlib-dictionary.js
Normal file
@ -0,0 +1,73 @@
|
||||
// Copyright Joyent, Inc. and other Node contributors.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
||||
// persons to whom the Software is furnished to do so, subject to the
|
||||
// following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
// test compression/decompresion with dictionary
|
||||
|
||||
var common = require('../common.js');
|
||||
var assert = require('assert');
|
||||
var zlib = require('zlib');
|
||||
var path = require('path');
|
||||
|
||||
var spdyDict = new Buffer([
|
||||
'optionsgetheadpostputdeletetraceacceptaccept-charsetaccept-encodingaccept-',
|
||||
'languageauthorizationexpectfromhostif-modified-sinceif-matchif-none-matchi',
|
||||
'f-rangeif-unmodifiedsincemax-forwardsproxy-authorizationrangerefererteuser',
|
||||
'-agent10010120020120220320420520630030130230330430530630740040140240340440',
|
||||
'5406407408409410411412413414415416417500501502503504505accept-rangesageeta',
|
||||
'glocationproxy-authenticatepublicretry-afterservervarywarningwww-authentic',
|
||||
'ateallowcontent-basecontent-encodingcache-controlconnectiondatetrailertran',
|
||||
'sfer-encodingupgradeviawarningcontent-languagecontent-lengthcontent-locati',
|
||||
'oncontent-md5content-rangecontent-typeetagexpireslast-modifiedset-cookieMo',
|
||||
'ndayTuesdayWednesdayThursdayFridaySaturdaySundayJanFebMarAprMayJunJulAugSe',
|
||||
'pOctNovDecchunkedtext/htmlimage/pngimage/jpgimage/gifapplication/xmlapplic',
|
||||
'ation/xhtmltext/plainpublicmax-agecharset=iso-8859-1utf-8gzipdeflateHTTP/1',
|
||||
'.1statusversionurl\0'
|
||||
].join(''));
|
||||
|
||||
var deflate = zlib.createDeflate({ dictionary: spdyDict });
|
||||
var inflate = zlib.createInflate({ dictionary: spdyDict });
|
||||
|
||||
var input = [
|
||||
'HTTP/1.1 200 Ok',
|
||||
'Server: node.js',
|
||||
'Content-Length: 0',
|
||||
''
|
||||
].join('\r\n');
|
||||
|
||||
// Put data into deflate stream
|
||||
deflate.on('data', function(chunk) {
|
||||
inflate.write(chunk);
|
||||
});
|
||||
deflate.on('end', function() {
|
||||
inflate.end();
|
||||
});
|
||||
|
||||
// Get data from inflate stream
|
||||
var output = [];
|
||||
inflate.on('data', function(chunk) {
|
||||
output.push(chunk);
|
||||
});
|
||||
inflate.on('end', function() {
|
||||
assert.equal(output.join(''), input);
|
||||
});
|
||||
|
||||
deflate.write(input);
|
||||
deflate.end();
|
Loading…
Reference in New Issue
Block a user