diff --git a/.gitignore b/.gitignore index 0058b67..73b6cf5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ build -.lock-wscript \ No newline at end of file +lib/*.node +.lock-wscript diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..73b6cf5 --- /dev/null +++ b/.npmignore @@ -0,0 +1,3 @@ +build +lib/*.node +.lock-wscript diff --git a/package.json b/package.json index 97b7df5..b290e0c 100644 --- a/package.json +++ b/package.json @@ -1,18 +1,28 @@ { - "name": "zlib", - "description": "Simple, synchronous deflate/inflate for buffers", - "version": "1.0.3", - "homepage": "https://github.com/kkaefer/node-zlib", - "author": "Konstantin Käfer ", - "repository": { - "type": "git", - "url": "git://github.com/kkaefer/node-zlib.git" - }, - "engines": { - "node": ">=0.2.0" - }, - "licenses": [ - { "type": "BSD" } - ], - "main": "./lib/zlib" -} + "name": "zlibcontext", + "description": "Simple, synchronous deflate/inflate for buffers (ZLibContext modification)", + "version": "1.0.9", + "homepage": "https://github.com/kkaefer/node-zlib", + "author": "Fedor Indutny ", + "contributors": [ + "Konstantin Käfer " + ], + "repository": { + "type": "git", + "url": "git://github.com/kkaefer/node-zlib.git" + }, + "engines": { + "node": ">=0.6.0" + }, + "licenses": [ + { + "type": "BSD" + } + ], + "scripts": { + "install": "./configure && make" + }, + "main": "./lib/zlib", + "dependencies": {}, + "devDependencies": {} +} \ No newline at end of file diff --git a/src/node-zlib.cc b/src/node-zlib.cc deleted file mode 100644 index b2c7e14..0000000 --- a/src/node-zlib.cc +++ /dev/null @@ -1,95 +0,0 @@ -#include -#include -#include -#include - -#include -#include -#include - -using namespace v8; -using namespace node; - -// node v0.2.x compatibility -#if NODE_VERSION_AT_LEAST(0,3,0) - #define Buffer_Data Buffer::Data - #define Buffer_Length Buffer::Length - #define Buffer_New Buffer::New -#else - inline char* Buffer_Data(Handle obj) { - return (ObjectWrap::Unwrap(obj))->data(); - } - inline size_t Buffer_Length(Handle obj) { - return (ObjectWrap::Unwrap(obj))->length(); - } - inline Buffer* Buffer_New(char* data, size_t length) { - Buffer* buffer = Buffer::New(length); - memcpy(buffer->data(), data, length); - return buffer; - } -#endif - - -z_stream deflate_s; -z_stream inflate_s; - -inline Handle ZLib_error(const char* msg = NULL) { - return ThrowException(Exception::Error( - String::New(msg ? msg : "Unknown Error"))); -} - -#define ZLib_Xflate(x, factor) \ -Handle ZLib_##x##flate(const Arguments& args) { \ - HandleScope scope; \ - \ - if (args.Length() < 1 || !Buffer::HasInstance(args[0])) { \ - return ZLib_error("Expected Buffer as first argument"); \ - } \ - \ - if ((x##flateReset(&x##flate_s)) != Z_OK) { \ - assert((false, "ZLib stream is beyond repair")); \ - } \ - \ - Local input = args[0]->ToObject(); \ - x##flate_s.next_in = (Bytef*)Buffer_Data(input); \ - int length = x##flate_s.avail_in = Buffer_Length(input); \ - \ - int ret; \ - char* result = NULL; \ - \ - int compressed = 0; \ - do { \ - result = (char*)realloc(result, compressed + factor * length); \ - if (!result) return ZLib_error("Could not allocate memory"); \ - \ - x##flate_s.avail_out = factor * length; \ - x##flate_s.next_out = (Bytef*)result + compressed; \ - \ - ret = x##flate(&x##flate_s, Z_FINISH); \ - if (ret != Z_STREAM_END && ret != Z_OK && ret != Z_BUF_ERROR) { \ - free(result); \ - return ZLib_error(x##flate_s.msg); \ - } \ - \ - compressed += (factor * length - x##flate_s.avail_out); \ - } while (x##flate_s.avail_out == 0); \ - \ - Buffer* output = Buffer_New(result, compressed); \ - free(result); \ - return scope.Close(Local::New(output->handle_)); \ -} - -ZLib_Xflate(de, 1); -ZLib_Xflate(in, 2); - -extern "C" void init (Handle target) { - deflate_s.zalloc = inflate_s.zalloc = Z_NULL; - deflate_s.zfree = inflate_s.zfree = Z_NULL; - deflate_s.opaque = inflate_s.opaque = Z_NULL; - - deflateInit(&deflate_s, Z_DEFAULT_COMPRESSION); - inflateInit(&inflate_s); - - NODE_SET_METHOD(target, "deflate", ZLib_deflate); - NODE_SET_METHOD(target, "inflate", ZLib_inflate); -} diff --git a/src/node_zlib.cc b/src/node_zlib.cc new file mode 100644 index 0000000..c66070f --- /dev/null +++ b/src/node_zlib.cc @@ -0,0 +1,146 @@ +#include +#include +#include + +#include +#include +#include + +#include "node_zlib.h" + +using namespace v8; +using namespace node; + +Persistent ZLibContext::constructor_template; + +void ZLibContext::Initialize(Handle target) { + Local t = FunctionTemplate::New(ZLibContext::New); + constructor_template = Persistent::New(t); + constructor_template->InstanceTemplate()->SetInternalFieldCount(1); + constructor_template->SetClassName(String::NewSymbol("ZLibContext")); + + // Instance methods + NODE_SET_PROTOTYPE_METHOD(constructor_template, "deflate", + ZLibContext::Deflate); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "inflate", + ZLibContext::Inflate); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "resetDeflate", + ZLibContext::ResetDeflate); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "resetInflate", + ZLibContext::ResetInflate); + + target->Set(String::NewSymbol("ZLibContext"), constructor_template->GetFunction()); +}; + +Handle ZLibContext::New(const Arguments &args) { + if (!args.IsConstructCall()) { + return FromConstructorTemplate(constructor_template, args); + } + + HandleScope scope; + + ZLibContext *z = new ZLibContext(); + z->Wrap(args.This()); + + // First argument can be initial dictionary + if (args.Length() >= 1 && Buffer::HasInstance(args[0])) { + Local dict = args[0]->ToObject(); + z->pdict = Persistent::New(dict); + z->bdict = (Bytef*)Buffer::Data(dict); + z->dictLen = Buffer::Length(dict); + z->hasDict = true; + } + + return args.This(); +}; + +inline Handle ZLib_error(const char* msg = NULL) { + return ThrowException(Exception::Error( + String::New(msg ? msg : "Unknown Error"))); +}; + +#define ZLib_Xreset(Method, method) \ +Handle ZLibContext::Reset##Method(const Arguments& args) { \ + HandleScope scope; \ + ZLibContext *z = ObjectWrap::Unwrap(args.This()); \ + \ + if (method##Reset(&(z->method##_s)) != Z_OK) { \ + return ZLib_error("ZLib stream is beyond repair"); \ + } \ + \ + z->dictSet = false; \ + return scope.Close(Boolean::New(true)); \ +} + +#define ZLib_Xflate(Method, method, factor) \ +Handle ZLibContext::Method(const Arguments& args) { \ + HandleScope scope; \ + \ + if (args.Length() < 1 || !Buffer::HasInstance(args[0])) { \ + return ZLib_error("Expected Buffer as first argument"); \ + } \ + \ + Local input = args[0]->ToObject(); \ + \ + ZLibContext *z = ObjectWrap::Unwrap(args.This()); \ + \ + int ret; \ + if (factor == 1 && z->hasDict && !z->dictSet) { \ + ret = method##SetDictionary(&(z->method##_s), z->bdict, z->dictLen); \ + \ + if (ret != Z_OK) { \ + return ZLib_error("Failed to set dictionary!"); \ + } \ + \ + z->dictSet = true; \ + } \ + \ + z->method##_s.next_in = (Bytef*)Buffer::Data(input); \ + int length = z->method##_s.avail_in = Buffer::Length(input); \ + \ + char* result = NULL; \ + \ + int compressed = 0; \ + do { \ + result = (char*)realloc(result, compressed + factor * length); \ + if (!result) return ZLib_error("Could not allocate memory"); \ + \ + z->method##_s.avail_out = factor * length; \ + z->method##_s.next_out = (Bytef*)result + compressed; \ + \ + ret = method(&(z->method##_s), Z_SYNC_FLUSH); \ + \ + if (ret == Z_NEED_DICT) { \ + if (!z->hasDict) { \ + free(result); \ + return ZLib_error("Dictionary is required"); \ + } \ + ret = method##SetDictionary(&(z->method##_s), z->bdict, \ + z->dictLen); \ + \ + if (ret != Z_OK) { \ + return ZLib_error("Failed to set dictionary"); \ + } \ + \ + ret = method(&(z->method##_s), Z_SYNC_FLUSH); \ + } \ + \ + if (ret != Z_STREAM_END && ret != Z_OK && ret != Z_BUF_ERROR) { \ + free(result); \ + return ZLib_error(z->method##_s.msg); \ + } \ + \ + compressed += (factor * length - z->method##_s.avail_out); \ + } while (z->method##_s.avail_out == 0); \ + \ + Buffer* output = Buffer::New(result, compressed); \ + free(result); \ + return scope.Close(Local::New(output->handle_)); \ +} + +ZLib_Xflate(Deflate, deflate, 1); +ZLib_Xflate(Inflate, inflate, 2); +ZLib_Xreset(Deflate, deflate); +ZLib_Xreset(Inflate, inflate); + +NODE_MODULE(zlib_bindings, ZLibContext::Initialize); diff --git a/src/node_zlib.h b/src/node_zlib.h new file mode 100644 index 0000000..4195c63 --- /dev/null +++ b/src/node_zlib.h @@ -0,0 +1,58 @@ +/** + * ZLib binding for node.js + */ +#ifndef NODE_ZLIB_H +#define NODE_ZLIB_H + +#include +#include +#include + +#include + +using namespace node; +using namespace v8; + +class ZLibContext : public ObjectWrap { + public: + + static void Initialize(Handle target); + + static Persistent constructor_template; + + protected: + ZLibContext() : ObjectWrap(), deflate_s(), inflate_s() { + deflate_s.zalloc = inflate_s.zalloc = Z_NULL; + deflate_s.zfree = inflate_s.zfree = Z_NULL; + deflate_s.opaque = inflate_s.opaque = Z_NULL; + + deflateInit(&deflate_s, Z_DEFAULT_COMPRESSION); + inflateInit(&inflate_s); + + dictSet = hasDict = false; + dictLen = 0; + } + + ~ZLibContext() { } + + + static Handle New(const Arguments &args); + + static Handle Deflate(const Arguments &args); + static Handle Inflate(const Arguments &args); + + static Handle ResetDeflate(const Arguments &args); + static Handle ResetInflate(const Arguments &args); + + z_stream deflate_s; + z_stream inflate_s; + + bool hasDict; + bool dictSet; + int dictLen; + Bytef* bdict; + Persistent pdict; + +}; + +#endif // NODE_ZLIB_H diff --git a/test/deflate.test.js b/test/deflate.test.js index c27b7ec..61c4b18 100644 --- a/test/deflate.test.js +++ b/test/deflate.test.js @@ -1,6 +1,6 @@ var assert = require('assert'); var Buffer = require('buffer').Buffer; -var zlib = require('../lib/zlib'); +var zlib = require('../lib/zlib').ZLibContext(); exports['test deflate/inflate buffer'] = function(beforeExit) { var input = new Buffer('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.'); diff --git a/test/inflate.test.js b/test/inflate.test.js index c35b3f5..96e1770 100644 --- a/test/inflate.test.js +++ b/test/inflate.test.js @@ -1,6 +1,6 @@ var assert = require('assert'); var Buffer = require('buffer').Buffer; -var zlib = require('../lib/zlib'); +var zlib = require('../lib/zlib').ZLibContext(); exports['test inflate fail'] = function(beforeExit) { var compressed = new Buffer('\x78\x80\x9c\xab\x56\x4a\x93\xaf\x46\x00\x1b\xa9\x02\x77\x92\x0f', 'binary'); diff --git a/wscript b/wscript index a07dbcb..81cea21 100644 --- a/wscript +++ b/wscript @@ -4,7 +4,7 @@ from shutil import copy2 as copy TARGET = 'zlib_bindings' TARGET_FILE = '%s.node' % TARGET -built = 'build/default/%s' % TARGET_FILE +built = 'build/Release/%s' % TARGET_FILE dest = 'lib/%s' % TARGET_FILE def set_options(opt): @@ -18,9 +18,10 @@ def configure(conf): def build(bld): obj = bld.new_task_gen("cxx", "shlib", "node_addon") - obj.cxxflags = ["-g", "-D_FILE_OFFSET_BITS=64", "-D_LARGEFILE_SOURCE", "-Wall"] + obj.cxxflags = ["-g", "-D_LARGEFILE_SOURCE", "-Wall"] obj.target = TARGET - obj.source = "src/node-zlib.cc" + obj.source = "src/node_zlib.cc" + obj.includes = "src/" obj.uselib = "ZLIB" def shutdown(): @@ -29,4 +30,4 @@ def shutdown(): unlink(TARGET_FILE) else: if exists(built): - copy(built, dest) \ No newline at end of file + copy(built, dest)