Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

first commit

  • Loading branch information...
commit 9fcd7432d6b13accc4b9ed777e57ab4388af790c 0 parents
@waveto waveto authored
Showing with 544 additions and 0 deletions.
  1. +18 −0 LICENSE
  2. +37 −0 README
  3. +377 −0 compress.cc
  4. +41 −0 filetest.js
  5. +38 −0 test.js
  6. +33 −0 wscript
18 LICENSE
@@ -0,0 +1,18 @@
+// Copyright 2009, Acknack Ltd. All rights reserved.
+// 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.
37 README
@@ -0,0 +1,37 @@
+node-compress
+=============
+
+A streaming compression / gzip module for node.js
+
+To install, ensure that you have openssl installed, and run:
+
+node-waf configure
+node-waf build
+
+This will put the compress.node binary module in build/default.
+
+
+Quick example
+-------------
+
+var compress=require("./compress");
+var sys=require("sys");
+var posix=require("posix");
+
+// Create gzip stream
+var gzip=new compress.Gzip;
+gzip.init();
+
+// Pump data to be compressed
+var gzdata1 = gzip.deflate("My data that needs ", "binary");
+sys.puts("Compressed size : "+gzdata1.length);
+
+var gzdata2 = gzip.deflate("to be compressed. 01234567890.", "binary");
+sys.puts("Compressed size : "+gzdata2.length);
+
+var gzdata3 = gzip.end();
+sys.puts("Last bit : "+gzdata3.length);
+
+// Normally stream this out as its generated, but just print here
+var gzdata = gzdata1+gzdata2+gzdata3;
+sys.puts("Total compressed size : "+gzdata.length);
377 compress.cc
@@ -0,0 +1,377 @@
+#include <node.h>
+#include <node_events.h>
+#include <assert.h>
+#include <string.h>
+#include <zlib.h>
+
+#define CHUNK 16384
+
+using namespace v8;
+using namespace node;
+
+
+class Gzip : public EventEmitter {
+ public:
+ static void
+ Initialize (v8::Handle<v8::Object> target)
+ {
+ HandleScope scope;
+
+ Local<FunctionTemplate> t = FunctionTemplate::New(New);
+
+ t->Inherit(EventEmitter::constructor_template);
+ t->InstanceTemplate()->SetInternalFieldCount(1);
+
+ NODE_SET_PROTOTYPE_METHOD(t, "init", GzipInit);
+ NODE_SET_PROTOTYPE_METHOD(t, "deflate", GzipDeflate);
+ NODE_SET_PROTOTYPE_METHOD(t, "end", GzipEnd);
+
+ target->Set(String::NewSymbol("Gzip"), t->GetFunction());
+ }
+
+ int GzipInit(int level) {
+ int ret;
+ /* allocate deflate state */
+ strm.zalloc = Z_NULL;
+ strm.zfree = Z_NULL;
+ strm.opaque = Z_NULL;
+ ret = deflateInit2(&strm, level, Z_DEFLATED, 16+MAX_WBITS, 8, Z_DEFAULT_STRATEGY);
+ return ret;
+ }
+
+ int GzipDeflate(char* data, int data_len, char** out, int* out_len) {
+ int ret;
+ char* temp;
+ int i=1;
+
+ if (data_len == 0)
+ return 0;
+
+ *out = NULL;
+ *out_len = 0;
+ ret = 0;
+
+ while(data_len>0) {
+ if (data_len>CHUNK) {
+ strm.avail_in = CHUNK;
+ } else {
+ strm.avail_in = data_len;
+ }
+
+ strm.next_in = (Bytef*)data;
+ do {
+ temp = (char *)realloc(*out, CHUNK*i +1);
+ if (temp == NULL) {
+ return Z_MEM_ERROR;
+ }
+ *out = temp;
+ strm.avail_out = CHUNK;
+ strm.next_out = (Bytef*)*out + *out_len;
+ ret = deflate(&strm, Z_NO_FLUSH);
+ assert(ret != Z_STREAM_ERROR); /* state not clobbered */
+ *out_len += (CHUNK - strm.avail_out);
+ i++;
+ } while (strm.avail_out == 0);
+
+ data += CHUNK;
+ data_len -= CHUNK;
+ }
+ return ret;
+ }
+
+
+ int GzipEnd(char** out, int*out_len) {
+ int ret;
+ char* temp;
+ int i = 1;
+
+ *out = NULL;
+ *out_len = 0;
+ strm.avail_in = 0;
+ strm.next_in = NULL;
+
+ do {
+ temp = (char *)realloc(*out, CHUNK*i);
+ if (temp == NULL) {
+ return Z_MEM_ERROR;
+ }
+ *out = temp;
+ strm.avail_out = CHUNK;
+ strm.next_out = (Bytef*)*out + *out_len;
+ ret = deflate(&strm, Z_FINISH);
+ assert(ret != Z_STREAM_ERROR); /* state not clobbered */
+ *out_len += (CHUNK - strm.avail_out);
+ i++;
+ } while (strm.avail_out == 0);
+
+
+ deflateEnd(&strm);
+ return ret;
+ }
+
+
+ protected:
+
+ static Handle<Value>
+ New (const Arguments& args)
+ {
+ HandleScope scope;
+
+ Gzip *gzip = new Gzip();
+ gzip->Wrap(args.This());
+
+ return args.This();
+ }
+
+ static Handle<Value>
+ GzipInit (const Arguments& args)
+ {
+ Gzip *gzip = ObjectWrap::Unwrap<Gzip>(args.This());
+
+ HandleScope scope;
+
+ int level=Z_DEFAULT_COMPRESSION;
+
+ int r = gzip->GzipInit(level);
+
+ return scope.Close(Integer::New(r));
+ }
+
+ static Handle<Value>
+ GzipDeflate(const Arguments& args) {
+ Gzip *gzip = ObjectWrap::Unwrap<Gzip>(args.This());
+
+ HandleScope scope;
+
+ enum encoding enc = ParseEncoding(args[1]);
+ ssize_t len = DecodeBytes(args[0], enc);
+
+ if (len < 0) {
+ Local<Value> exception = Exception::TypeError(String::New("Bad argument"));
+ return ThrowException(exception);
+ }
+ char* buf = new char[len];
+ ssize_t written = DecodeWrite(buf, len, args[0], enc);
+ assert(written == len);
+
+ char* out;
+ int out_size;
+ int r = gzip->GzipDeflate(buf, len, &out, &out_size);
+
+ if (out_size==0) {
+ return scope.Close(String::New(""));
+ }
+
+ Local<Value> outString = Encode(out, out_size, BINARY);
+ free(out);
+ return scope.Close(outString);
+ }
+
+ static Handle<Value>
+ GzipEnd(const Arguments& args) {
+ Gzip *gzip = ObjectWrap::Unwrap<Gzip>(args.This());
+
+ HandleScope scope;
+
+ char* out;
+ int out_size;
+ bool hex_format = false;
+
+ if (args.Length() > 0 && args[0]->IsString()) {
+ String::Utf8Value format_type(args[1]->ToString());
+ }
+
+
+ int r = gzip->GzipEnd( &out, &out_size);
+
+ if (out_size==0) {
+ return String::New("");
+ }
+ Local<Value> outString = Encode(out, out_size, BINARY);
+ free(out);
+ return scope.Close(outString);
+
+ }
+
+
+ Gzip () : EventEmitter ()
+ {
+ }
+
+ ~Gzip ()
+ {
+ }
+
+ private:
+
+ z_stream strm;
+};
+
+
+class Gunzip : public EventEmitter {
+ public:
+ static void
+ Initialize (v8::Handle<v8::Object> target)
+ {
+ HandleScope scope;
+
+ Local<FunctionTemplate> t = FunctionTemplate::New(New);
+
+ t->Inherit(EventEmitter::constructor_template);
+ t->InstanceTemplate()->SetInternalFieldCount(1);
+
+ NODE_SET_PROTOTYPE_METHOD(t, "init", GunzipInit);
+ NODE_SET_PROTOTYPE_METHOD(t, "inflate", GunzipInflate);
+ NODE_SET_PROTOTYPE_METHOD(t, "end", GunzipEnd);
+
+ target->Set(String::NewSymbol("Gunzip"), t->GetFunction());
+ }
+
+ int GunzipInit() {
+ /* allocate inflate state */
+ strm.zalloc = Z_NULL;
+ strm.zfree = Z_NULL;
+ strm.opaque = Z_NULL;
+ strm.avail_in = 0;
+ strm.next_in = Z_NULL;
+ int ret = inflateInit2(&strm, 16+MAX_WBITS);
+ return ret;
+ }
+
+ int GunzipInflate(const char* data, int data_len, char** out, int* out_len) {
+ int ret;
+ char* temp;
+ int i=1;
+
+ if (data_len == 0)
+ return 0;
+
+ *out = NULL;
+ *out_len = 0;
+
+
+ while(data_len>0) {
+ if (data_len>CHUNK) {
+ strm.avail_in = CHUNK;
+ } else {
+ strm.avail_in = data_len;
+ }
+
+ strm.next_in = (Bytef*)data;
+
+ do {
+ temp = (char *)realloc(*out, CHUNK*i);
+ if (temp == NULL) {
+ return Z_MEM_ERROR;
+ }
+ *out = temp;
+ strm.avail_out = CHUNK;
+ strm.next_out = (Bytef*)*out + *out_len;
+ ret = inflate(&strm, Z_NO_FLUSH);
+ assert(ret != Z_STREAM_ERROR); /* state not clobbered */
+ switch (ret) {
+ case Z_NEED_DICT:
+ ret = Z_DATA_ERROR; /* and fall through */
+ case Z_DATA_ERROR:
+ case Z_MEM_ERROR:
+ (void)inflateEnd(&strm);
+ return ret;
+ }
+ *out_len += (CHUNK - strm.avail_out);
+ i++;
+ } while (strm.avail_out == 0);
+ data += CHUNK;
+ data_len -= CHUNK;
+ }
+ return ret;
+
+ }
+
+
+ void GunzipEnd() {
+ inflateEnd(&strm);
+ }
+
+ protected:
+
+ static Handle<Value>
+ New(const Arguments& args) {
+ HandleScope scope;
+
+ Gunzip *gunzip = new Gunzip();
+ gunzip->Wrap(args.This());
+
+ return args.This();
+ }
+
+ static Handle<Value>
+ GunzipInit(const Arguments& args) {
+ Gunzip *gunzip = ObjectWrap::Unwrap<Gunzip>(args.This());
+
+ HandleScope scope;
+
+ int r = gunzip->GunzipInit();
+
+ return scope.Close(Integer::New(r));
+ }
+
+
+ static Handle<Value>
+ GunzipInflate(const Arguments& args) {
+ Gunzip *gunzip = ObjectWrap::Unwrap<Gunzip>(args.This());
+
+ HandleScope scope;
+
+ enum encoding enc = ParseEncoding(args[1]);
+ ssize_t len = DecodeBytes(args[0], enc);
+
+ if (len < 0) {
+ Local<Value> exception = Exception::TypeError(String::New("Bad argument"));
+ return ThrowException(exception);
+ }
+
+ char* buf = new char[len];
+ ssize_t written = DecodeWrite(buf, len, args[0], BINARY);
+ assert(written == len);
+
+ char* out;
+ int out_size;
+ int r = gunzip->GunzipInflate(buf, len, &out, &out_size);
+
+ Local<Value> outString = Encode(out, out_size, enc);
+ free(out);
+ return scope.Close(outString);
+ }
+
+ static Handle<Value>
+ GunzipEnd(const Arguments& args) {
+ Gunzip *gunzip = ObjectWrap::Unwrap<Gunzip>(args.This());
+
+ HandleScope scope;
+
+ gunzip->GunzipEnd();
+
+ return scope.Close(String::New(""));
+ }
+
+ Gunzip () : EventEmitter ()
+ {
+ }
+
+ ~Gunzip ()
+ {
+ }
+
+ private:
+
+ z_stream strm;
+
+};
+
+extern "C" void
+init (Handle<Object> target)
+{
+ HandleScope scope;
+ Gzip::Initialize(target);
+ Gunzip::Initialize(target);
+}
41 filetest.js
@@ -0,0 +1,41 @@
+var compress=require("./compress");
+var sys=require("sys");
+var posix=require("posix");
+
+// Read in our test file
+var data=posix.cat("filetest.js", encoding="binary").wait();
+sys.puts("Got : "+data.length);
+
+// Set output file
+var fd = posix.open("filetest.js.gz", process.O_WRONLY | process.O_TRUNC | process.O_CREAT, 0644).wait();
+sys.puts("Openned file");
+
+// Create gzip stream
+var gzip=new compress.Gzip;
+gzip.init();
+
+// Pump data to be compressed
+gzdata=gzip.deflate(data, "binary"); // Do this as many times as required
+sys.puts("Compressed size : "+gzdata.length);
+posix.write(fd, gzdata, encoding="binary").wait();
+
+// Get the last bit
+gzlast=gzip.end();
+sys.puts("Last bit : "+gzlast.length);
+posix.write(fd, gzlast, encoding="binary").wait();
+posix.close(fd).wait();
+sys.puts("File closed");
+
+// See if we can uncompress it ok
+var gunzip=new compress.Gunzip;
+gunzip.init();
+var testdata = posix.cat("filetest.js.gz", encoding="binary").wait();
+sys.puts("Test opened : "+testdata.length);
+sys.puts(gunzip.inflate(testdata, "binary").length);
+gunzip.end();
+
+
+
+
+
+
38 test.js
@@ -0,0 +1,38 @@
+var compress=require("./compress");
+var sys=require("sys");
+var posix=require("posix");
+
+// Create gzip stream
+var gzip=new compress.Gzip;
+gzip.init();
+
+// Pump data to be compressed
+var gzdata1 = gzip.deflate("My data that needs ", "binary");
+sys.puts("Compressed size : "+gzdata1.length);
+
+var gzdata2 = gzip.deflate("to be compressed. 01234567890.", "binary");
+sys.puts("Compressed size : "+gzdata2.length);
+
+var gzdata3=gzip.end();
+sys.puts("Last bit : "+gzdata3.length);
+
+// Take the output stream, and chop it up into two
+var gzdata = gzdata1+gzdata2+gzdata3;
+sys.puts("Total compressed size : "+gzdata.length);
+var d1 = gzdata.substr(0, 25);
+var d2 = gzdata.substr(25);
+
+// Create gunzip stream to decode these
+var gunzip = new compress.Gunzip;
+gunzip.init();
+var data1 = gunzip.inflate(d1, "binary");
+var data2 = gunzip.inflate(d2, "binary");
+var data3 = gunzip.end();
+
+sys.puts(data1+data2+data3);
+
+
+
+
+
+
33 wscript
@@ -0,0 +1,33 @@
+import Options
+from os import unlink, symlink, popen
+from os.path import exists
+
+srcdir = "."
+blddir = "build"
+VERSION = "0.0.1"
+
+def set_options(opt):
+ opt.tool_options("compiler_cxx")
+ opt.tool_options("compiler_cc")
+
+def configure(conf):
+ conf.check_tool("compiler_cxx")
+ conf.check_tool("compiler_cc")
+ conf.check_tool("node_addon")
+
+ conf.check(lib='z', libpath=['/usr/lib', '/usr/local/lib'], uselib_store='ZLIB')
+
+def build(bld):
+ obj = bld.new_task_gen("cxx", "shlib", "node_addon")
+ obj.target = "compress"
+ obj.source = "compress.cc"
+ obj.uselib = "ZLIB"
+
+def shutdown():
+ # HACK to get compress.node out of build directory.
+ # better way to do this?
+ if Options.commands['clean']:
+ if exists('compress.node'): unlink('compress.node')
+ else:
+ if exists('build/default/compress.node') and not exists('compress.node'):
+ symlink('build/default/compress.node', 'compress.node')
Please sign in to comment.
Something went wrong with that request. Please try again.