Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

initial commit

  • Loading branch information...
commit 1188cb22341788db903cf021221cea2009c6e8c3 1 parent d39af71
authored August 30, 2011
4  .gitignore
... ...
@@ -0,0 +1,4 @@
  1
+build/
  2
+test/temp*
  3
+*.node
  4
+.lock-wscript
34  README.md
Source Rendered
@@ -23,12 +23,6 @@ You'll need to start with:
23 23
 
24 24
     var deflate = require('deflate');
25 25
 
26  
-### String
27  
-
28  
-Deflate a `String`, returning a `Buffer`:
29  
-
30  
-	var gzip = deflate.deflate('some text which needs to be compressed');
31  
-
32 26
 ### Buffer
33 27
 
34 28
 Deflate a `Buffer` which contains all data to be compressed:
@@ -64,22 +58,26 @@ the low-level API. All low-level functions are synchronous.
64 58
 ## Options
65 59
 
66 60
 ### deflate(level=6)
67  
-Use `gzip` format. `level` sets the compression level from `0` (uncompressed) to `9` (highly compressed), 
  61
+Deflates a gzip formatted `Buffer`. `level` sets the compression level from `0` (uncompressed) to `9` (highly compressed), 
68 62
 a smaller number is faster.
69 63
 
70 64
 ### deflate(format='gzip', level=6)
71  
-`format` specifies the format and can be `gzip`, `zlib`, or `deflate`.
  65
+Deflates a buffer.
  66
+
  67
+`format` can be `gzip`, `zlib`, or `deflate`.
72 68
 
73 69
 `level` sets the compression level from `0` (uncompressed) to `9` (highly compressed), 
74 70
 a smaller number is faster.
75 71
 
76  
----
  72
+### createDeflateStream(readStream, level=6)
  73
+Creates a `Stream` which wraps `readStream` to deflates gzip content.
  74
+
  75
+`level` sets the compression level from `0` (uncompressed) to `9`, a smaller number is faster.
77 76
 
78  
-### createDeflateStream(level=6)
79  
-Use `gzip` format. `level` sets the compression level from `0` (uncompressed) to `9`, a smaller number is faster.
  77
+### createDeflateStream(readStream, format='gzip', level=6, bufferSize=131072)
  78
+Creates a `Stream` which wraps `readStream` to deflate its content.
80 79
 
81  
-### createDeflateStream(format='gzip', level=6, bufferSize=131072)
82  
-`format` specifies the format and can be `gzip`, `zlib`, or `deflate`.
  80
+`format` can be `gzip`, `zlib`, or `deflate`.
83 81
 
84 82
 `level` sets the compression level from `0` (uncompressed) to `9` (highly compressed), 
85 83
 a smaller number is faster.
@@ -87,6 +85,16 @@ a smaller number is faster.
87 85
 `bufferSize` is the size of the output buffer in bytes. Output data is buffered until it reaches
88 86
 this size, with the exception of the final chunk. The default is 128K.
89 87
 
  88
+### inflate(buffer, format='gzip')
  89
+Inflates a `Buffer`.
  90
+
  91
+`format` can be `gzip`, `zlib`, or `deflate`.
  92
+
  93
+### createInflateStream(readStream, format='gzip')
  94
+Creates a `Stream` which wraps `readStream` to inflate its content.
  95
+
  96
+`format` can be `gzip`, `zlib`, or `deflate`.
  97
+
90 98
 ## Tests
91 99
 Tests require [nodeunit](https://github.com/caolan/nodeunit), you can run them all with:
92 100
 	
3  build.sh
... ...
@@ -0,0 +1,3 @@
  1
+#!/bin/bash
  2
+node-waf configure $*
  3
+node-waf build
2  lib/deflate/.gitignore
... ...
@@ -0,0 +1,2 @@
  1
+build/
  2
+
102  lib/deflate/index.js
... ...
@@ -0,0 +1,102 @@
  1
+var deflate = require('./deflate-bindings'),
  2
+    Stream = require('stream').Stream,
  3
+     util = require('util');
  4
+
  5
+module.exports = deflate;
  6
+
  7
+//////////////////////////////////////////////////////////
  8
+// TODO: REFACTOR THIS TO MATCH MY LineReader STREAM ????
  9
+//////////////////////////////////////////////////////////
  10
+
  11
+module.exports.createDeflateStream = function(readStream, format, level, bufferSize) {
  12
+  if (!readStream) {
  13
+    throw new Error('expected ReadableStream');
  14
+  }
  15
+  return new DeflateStream(readStream, format, level, bufferSize);
  16
+};
  17
+
  18
+function DeflateStream(readStream, format, level, bufferSize) {
  19
+  this.writable = true;
  20
+  this.readable = true;
  21
+  this.deflater = new deflate.Deflater(format, level, bufferSize);
  22
+  this.readStream = readStream;
  23
+  
  24
+  if (readStream) {
  25
+    if (!readStream.readable) {
  26
+      throw new Error('expected ReadableStream');
  27
+    }
  28
+  }
  29
+}
  30
+util.inherits(DeflateStream, Stream);
  31
+
  32
+DeflateStream.prototype.write = function(data) {
  33
+  this.deflater.write(data);
  34
+  while (this.deflater.deflate()) {
  35
+    this.emit('data', this.deflater.read());
  36
+  }
  37
+};
  38
+
  39
+DeflateStream.prototype.end = function() {
  40
+  while (this.deflater.flush()) {
  41
+    this.emit('data', this.deflater.read());
  42
+  }
  43
+  this.emit('end');
  44
+};
  45
+
  46
+DeflateStream.prototype.destroy = function() {
  47
+  this.emit('close');
  48
+};
  49
+
  50
+DeflateStream.prototype.pipe = function(src) {
  51
+  Stream.prototype.pipe.call(this, src);
  52
+  if (this.readStream) {
  53
+    this.readStream.pipe(this);
  54
+  }
  55
+};
  56
+
  57
+//////////////////////////////////////////////////////////
  58
+
  59
+module.exports.createInflateStream = function(readStream, format, level, bufferSize) {
  60
+  if (!readStream) {
  61
+    throw new Error('expected ReadableStream');
  62
+  }
  63
+  return new InflateStream(readStream, format, level, bufferSize);
  64
+};
  65
+
  66
+function InflateStream(readStream, format, level, bufferSize) {
  67
+  this.writable = true;
  68
+  this.readable = true;
  69
+  this.inflater = new deflate.Inflater(format, level, bufferSize);
  70
+  this.readStream = readStream;
  71
+  
  72
+  if (readStream) {
  73
+    if (!readStream.readable) {
  74
+      throw new Error('expected ReadableStream');
  75
+    }
  76
+  }
  77
+}
  78
+util.inherits(InflateStream, Stream);
  79
+
  80
+InflateStream.prototype.write = function(data) {
  81
+  this.inflater.write(data);
  82
+  while (this.inflater.inflate()) {
  83
+    this.emit('data', this.inflater.read());
  84
+  }
  85
+};
  86
+
  87
+InflateStream.prototype.end = function() {
  88
+  this.emit('end');
  89
+};
  90
+
  91
+InflateStream.prototype.destroy = function() {
  92
+  this.emit('close');
  93
+};
  94
+
  95
+InflateStream.prototype.pipe = function(src) {
  96
+  Stream.prototype.pipe.call(this, src);
  97
+  if (this.readStream) {
  98
+    this.readStream.pipe(this);
  99
+  }
  100
+};
  101
+
  102
+//////////////////////////////////////////////////////////
17  package.json
... ...
@@ -0,0 +1,17 @@
  1
+{
  2
+  "name": "deflate",
  3
+  "description": "super-simple streaming gzip, wrapping native zlib (deflate/inflate)",
  4
+	"homepage" : "https://github.com/jahewson/node-deflate",
  5
+	"bugs" : { "web" : "https://github.com/jahewson/node-deflate/issues" },
  6
+  "version": "0.0.1",
  7
+  "author": "John Hewson",
  8
+  "repository": {
  9
+    "type": "git",
  10
+    "url": "https://github.com/jahewson/node-deflate"
  11
+  },
  12
+  "engine": [ "node >=0.4.0" ],
  13
+	"main" : "./lib",
  14
+  "scripts": {
  15
+    "install": "./build.sh"
  16
+  }
  17
+}
785  src/deflate.cc
... ...
@@ -0,0 +1,785 @@
  1
+// Copyright (C) 2011 John Hewson
  2
+//
  3
+// Permission is hereby granted, free of charge, to any person obtaining a copy
  4
+// of this software and associated documentation files (the "Software"), to
  5
+// deal in the Software without restriction, including without limitation the
  6
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  7
+// sell copies of the Software, and to permit persons to whom the Software is
  8
+// furnished to do so, subject to the following conditions:
  9
+// 
  10
+// The above copyright notice and this permission notice shall be included in
  11
+// all copies or substantial portions of the Software.
  12
+// 
  13
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  18
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  19
+// IN THE SOFTWARE.
  20
+
  21
+#include <node.h>
  22
+#include <node_buffer.h>
  23
+#include <zlib.h>
  24
+#include <string.h>
  25
+
  26
+#include <stdio.h>
  27
+
  28
+using namespace v8;
  29
+using namespace node;
  30
+
  31
+////////////////////////////////////////////////////////////////////////////////////////////////////////
  32
+
  33
+static Handle<Value> GetZError(int ret) {
  34
+ const char* msg;
  35
+
  36
+ switch (ret) {
  37
+ case Z_ERRNO:
  38
+   msg = "Z_ERRNO";
  39
+   break;
  40
+ case Z_STREAM_ERROR:
  41
+   msg = "Z_STREAM_ERROR";
  42
+   break;
  43
+ case Z_DATA_ERROR:
  44
+   msg = "Z_DATA_ERROR";
  45
+   break;
  46
+ case Z_MEM_ERROR:
  47
+   msg = "Z_MEM_ERROR";
  48
+   break;
  49
+ case Z_BUF_ERROR:
  50
+   msg = "Z_BUF_ERROR";
  51
+   break;
  52
+ case Z_VERSION_ERROR:
  53
+   msg = "Z_VERSION_ERROR";
  54
+   break;
  55
+ default:
  56
+   msg = "Unknown ZLIB Error";
  57
+ }
  58
+ 
  59
+ return ThrowException(Exception::Error(String::New(msg)));
  60
+}
  61
+
  62
+////////////////////////////////////////////////////////////////////////////////////////////////////////
  63
+
  64
+class Deflater : ObjectWrap {
  65
+
  66
+  private:
  67
+   z_stream strm;
  68
+   char* input;
  69
+   char* output;
  70
+   int output_length;
  71
+   int status;
  72
+   bool finished;
  73
+   int output_chunk_size;
  74
+   
  75
+  public:
  76
+
  77
+   Deflater() {
  78
+      input = NULL;
  79
+      output_length = 0;
  80
+      output = NULL;
  81
+      finished = false;
  82
+   }
  83
+
  84
+   int Init(int level, int windowBits, int memLevel, int strategy, int chunk_size) {
  85
+      strm.zalloc = Z_NULL;
  86
+      strm.zfree = Z_NULL;
  87
+      strm.opaque = Z_NULL;
  88
+      output_chunk_size = chunk_size;
  89
+      return deflateInit2(&strm, level, Z_DEFLATED, windowBits, memLevel, strategy);
  90
+   }
  91
+   
  92
+   int SetInput(int in_length) {
  93
+      strm.avail_in = in_length;
  94
+      strm.next_in = (Bytef*) input;
  95
+      
  96
+      if (output == NULL || output_length == output_chunk_size) {
  97
+         strm.avail_out = output_chunk_size;
  98
+         output = (char*) malloc(output_chunk_size);
  99
+         
  100
+         if (output == NULL) {
  101
+            return Z_MEM_ERROR;
  102
+         }
  103
+         
  104
+         strm.next_out = (Bytef*) output;
  105
+      }
  106
+      
  107
+      return Z_OK;
  108
+   }
  109
+   
  110
+   void ResetOutput() {
  111
+      strm.avail_out = output_chunk_size;
  112
+      strm.next_out = (Bytef*) output;
  113
+   }
  114
+   
  115
+   int Deflate() {
  116
+      int ret = deflate(&strm, Z_NO_FLUSH);
  117
+      status = ret;
  118
+      output_length = output_chunk_size - strm.avail_out;
  119
+      return ret;
  120
+   }
  121
+   
  122
+   int Finish() {
  123
+      strm.avail_in = 0;
  124
+      strm.next_in = NULL;
  125
+
  126
+      int ret = deflate(&strm, Z_FINISH);
  127
+      status = ret;
  128
+      
  129
+      output_length = output_chunk_size - strm.avail_out;
  130
+      
  131
+      if (ret == Z_STREAM_END) {
  132
+         deflateEnd(&strm);
  133
+         finished = true;
  134
+      }
  135
+      
  136
+      return ret;
  137
+   }
  138
+   
  139
+   bool IsOutputBufferFull() {
  140
+      return output_length == output_chunk_size;
  141
+   }
  142
+   
  143
+   bool HasFinished() {
  144
+      return finished;
  145
+   }
  146
+   
  147
+   int GetOutputLength() {
  148
+      return output_length;
  149
+   }
  150
+   
  151
+   char* GetOutput() {
  152
+      return output;
  153
+   }
  154
+   
  155
+   // node.js wrapper //
  156
+       
  157
+   static void Init(v8::Handle<v8::Object> target) {
  158
+      Local<FunctionTemplate> t = FunctionTemplate::New(New);
  159
+
  160
+      t->InstanceTemplate()->SetInternalFieldCount(1);
  161
+      t->SetClassName(String::NewSymbol("Deflater"));
  162
+
  163
+      NODE_SET_PROTOTYPE_METHOD(t, "write", SetInput);
  164
+      NODE_SET_PROTOTYPE_METHOD(t, "deflate", Deflate);
  165
+      NODE_SET_PROTOTYPE_METHOD(t, "read", GetOutput);
  166
+      NODE_SET_PROTOTYPE_METHOD(t, "flush", Finish);
  167
+      
  168
+      target->Set(String::NewSymbol("Deflater"), t->GetFunction());
  169
+   }
  170
+    
  171
+   static Handle<Value> New (const Arguments& args) {
  172
+      HandleScope scope;
  173
+      
  174
+      int level = Z_DEFAULT_COMPRESSION;
  175
+      int windowBits = 16 + MAX_WBITS; // gzip
  176
+      int memLevel = 8;
  177
+      int strategy = Z_DEFAULT_STRATEGY;
  178
+      int output_chunk_size = 131072; // 128K
  179
+      
  180
+      int idx = 0;
  181
+
  182
+      if (args.Length() > 0) {
  183
+         if(args[idx+0]->IsNumber()) {
  184
+            level = args[idx+0]->Int32Value();        
  185
+            if (level < 0 || level > 9) {
  186
+               Local<Value> exception = Exception::Error(String::New("level must be between 0 and 9"));
  187
+               return ThrowException(exception);
  188
+            }
  189
+         }
  190
+         else if (args[idx+0]->IsString()) {
  191
+            char* strLevel = *String::AsciiValue(args[idx+0]->ToString());
  192
+
  193
+            if (strcmp(strLevel, "gzip") == 0) {
  194
+               windowBits = 16 + MAX_WBITS;
  195
+            }
  196
+            else if (strcmp(strLevel, "zlib") == 0) {
  197
+               windowBits = MAX_WBITS;
  198
+            }
  199
+            else if (strcmp(strLevel, "deflate") == 0) {
  200
+               windowBits = -MAX_WBITS;
  201
+            }
  202
+            else {
  203
+               Local<Value> exception = Exception::TypeError(String::New("bad deflate kind"));
  204
+               return ThrowException(exception);
  205
+            }
  206
+         }
  207
+         else if (args[idx+0]->IsUndefined()) {
  208
+         }
  209
+         else {
  210
+            Local<Value> exception = Exception::TypeError(String::New("expected a Number or String"));
  211
+            return ThrowException(exception);
  212
+         }
  213
+
  214
+         if (args.Length() > 1) {
  215
+            if(args[idx+1]->IsNumber()) {
  216
+               level = args[idx+1]->Int32Value();        
  217
+               if (level < 0 || level > 9) {
  218
+                  Local<Value> exception = Exception::Error(String::New("level must be between 0 and 9"));
  219
+                  return ThrowException(exception);
  220
+               }
  221
+            }
  222
+            else if (args[idx+1]->IsUndefined()) {
  223
+            }
  224
+            else {
  225
+               Local<Value> exception = Exception::TypeError(String::New("expected a Number"));
  226
+               return ThrowException(exception);
  227
+            }
  228
+         }
  229
+
  230
+         if (args.Length() > 2) {
  231
+            if(args[idx+2]->IsNumber()) {
  232
+               output_chunk_size = args[idx+2]->Int32Value();        
  233
+               if (output_chunk_size < 0) {
  234
+                  Local<Value> exception = Exception::Error(String::New("invalid buffer size"));
  235
+                  return ThrowException(exception);
  236
+               }
  237
+            }
  238
+            else if (args[idx+2]->IsUndefined()) {
  239
+            }
  240
+            else {
  241
+               Local<Value> exception = Exception::TypeError(String::New("buffer size must be a Number"));
  242
+               return ThrowException(exception);
  243
+            }
  244
+         }
  245
+      }
  246
+      
  247
+      Deflater *deflater = new Deflater();
  248
+      deflater->Wrap(args.This());
  249
+
  250
+      int r = deflater->Init(level, windowBits, memLevel, strategy, output_chunk_size);
  251
+      
  252
+      if (r < 0) {
  253
+         return GetZError(r);
  254
+      }
  255
+      
  256
+      return args.This();
  257
+   }
  258
+   
  259
+   static Handle<Value> SetInput(const Arguments& args) {
  260
+      Deflater *deflater = ObjectWrap::Unwrap<Deflater>(args.This());
  261
+      HandleScope scope;
  262
+      
  263
+      Local<Object> in = args[0]->ToObject();
  264
+      ssize_t length = Buffer::Length(in);
  265
+
  266
+      // copy the input buffer, because it can be kept for several deflate() calls
  267
+      deflater->input = (char*)realloc(deflater->input, length);
  268
+      
  269
+      if (deflater->input == NULL) {
  270
+          return GetZError(Z_MEM_ERROR);
  271
+      }
  272
+      
  273
+      memcpy(deflater->input, Buffer::Data(in), length);
  274
+
  275
+      int r = deflater->SetInput(length);
  276
+      
  277
+      if (r < 0) {
  278
+         return GetZError(r);
  279
+      }
  280
+      
  281
+      return scope.Close(Undefined());
  282
+   }
  283
+   
  284
+   static Handle<Value> Deflate(const Arguments& args) {
  285
+      Deflater *deflater = ObjectWrap::Unwrap<Deflater>(args.This());
  286
+      HandleScope scope;
  287
+
  288
+      int r = deflater->Deflate();
  289
+      
  290
+      if (r < 0) {
  291
+         return GetZError(r);
  292
+      }
  293
+      
  294
+      return scope.Close(Boolean::New(deflater->IsOutputBufferFull()));
  295
+   }
  296
+   
  297
+   static Handle<Value> Finish(const Arguments& args) {
  298
+      Deflater *deflater = ObjectWrap::Unwrap<Deflater>(args.This());
  299
+      HandleScope scope;
  300
+      
  301
+      if (deflater->HasFinished()) {
  302
+         return scope.Close(False());
  303
+      }
  304
+      
  305
+      int r = deflater->Finish();
  306
+      
  307
+      if (r < 0) {
  308
+         return GetZError(r);
  309
+      }
  310
+      
  311
+      return scope.Close(True());
  312
+   }
  313
+   
  314
+   static Handle<Value> GetOutput(const Arguments& args) {
  315
+      Deflater *deflater = ObjectWrap::Unwrap<Deflater>(args.This());
  316
+      HandleScope scope;
  317
+      
  318
+      Buffer* slowBuffer = Buffer::New(deflater->GetOutput(), deflater->GetOutputLength());
  319
+      deflater->ResetOutput();
  320
+      
  321
+      if (deflater->HasFinished()) {
  322
+         free(deflater->GetOutput());
  323
+      }
  324
+      
  325
+      Local<Object> globalObj = Context::GetCurrent()->Global();
  326
+      Local<Function> bufferConstructor = Local<Function>::Cast(globalObj->Get(String::New("Buffer")));
  327
+      Handle<Value> constructorArgs[3] = { slowBuffer->handle_, Integer::New(deflater->GetOutputLength()), Integer::New(0) };
  328
+      Local<Object> jsBuffer = bufferConstructor->NewInstance(3, constructorArgs);
  329
+      
  330
+      return scope.Close(jsBuffer);
  331
+   }
  332
+};
  333
+
  334
+////////////////////////////////////////////////////////////////////////////////////////////////////////
  335
+
  336
+class Inflater : ObjectWrap {
  337
+
  338
+  private:
  339
+   z_stream strm;
  340
+   char* input;
  341
+   char* output;
  342
+   int output_length;
  343
+   int status;
  344
+   bool finished;
  345
+   int output_chunk_size;
  346
+   
  347
+  public:
  348
+
  349
+   Inflater() {
  350
+      input = NULL;
  351
+      output_length = 0;
  352
+      output = NULL;
  353
+      finished = false;
  354
+   }
  355
+
  356
+   int Init(int windowBits, int chunk_size) {
  357
+      strm.zalloc = Z_NULL;
  358
+      strm.zfree = Z_NULL;
  359
+      strm.opaque = Z_NULL;
  360
+      strm.avail_in = 0;
  361
+      strm.next_in = Z_NULL;
  362
+      output_chunk_size = chunk_size;
  363
+      return inflateInit2(&strm, windowBits);
  364
+   }
  365
+   
  366
+   int SetInput(int in_length) {
  367
+      strm.avail_in = in_length;
  368
+      strm.next_in = (Bytef*) input;
  369
+      
  370
+      if (output == NULL || output_length == output_chunk_size) {
  371
+         strm.avail_out = output_chunk_size;
  372
+         output = (char*) malloc(output_chunk_size);
  373
+         
  374
+         if (output == NULL) {
  375
+            return Z_MEM_ERROR;
  376
+         }
  377
+         
  378
+         strm.next_out = (Bytef*) output;
  379
+      }
  380
+      
  381
+      return Z_OK;
  382
+   }
  383
+   
  384
+   void ResetOutput() {
  385
+      strm.avail_out = output_chunk_size;
  386
+      strm.next_out = (Bytef*) output;
  387
+   }
  388
+   
  389
+   int Inflate() {
  390
+      int ret = inflate(&strm, Z_NO_FLUSH);
  391
+      status = ret;
  392
+      output_length = output_chunk_size - strm.avail_out;
  393
+
  394
+      if (ret == Z_STREAM_END) {
  395
+         inflateEnd(&strm);
  396
+         finished = true;
  397
+      }
  398
+
  399
+      return ret;
  400
+   }
  401
+   
  402
+   bool IsOutputBufferFull() {
  403
+      return output_length == output_chunk_size;
  404
+   }
  405
+   
  406
+   bool HasFinished() {
  407
+      return finished;
  408
+   }
  409
+   
  410
+   int GetOutputLength() {
  411
+      return output_length;
  412
+   }
  413
+   
  414
+   char* GetOutput() {
  415
+      return output;
  416
+   }
  417
+   
  418
+   // node.js wrapper //
  419
+       
  420
+   static void Init(v8::Handle<v8::Object> target) {
  421
+      Local<FunctionTemplate> t = FunctionTemplate::New(New);
  422
+
  423
+      t->InstanceTemplate()->SetInternalFieldCount(1);
  424
+      t->SetClassName(String::NewSymbol("Inflater"));
  425
+
  426
+      NODE_SET_PROTOTYPE_METHOD(t, "write", SetInput);
  427
+      NODE_SET_PROTOTYPE_METHOD(t, "inflate", Inflate);
  428
+      NODE_SET_PROTOTYPE_METHOD(t, "read", GetOutput);
  429
+      
  430
+      target->Set(String::NewSymbol("Inflater"), t->GetFunction());
  431
+   }
  432
+    
  433
+   static Handle<Value> New (const Arguments& args) {
  434
+      HandleScope scope;
  435
+      
  436
+      int windowBits = 16 + MAX_WBITS; // gzip
  437
+      int output_chunk_size = 65545; // <--- TODO: should have optional output buffer size
  438
+      
  439
+      if (args.Length() > 0) {
  440
+         if (args[0]->IsString()) {
  441
+            char* strLevel = *String::AsciiValue(args[0]->ToString());
  442
+
  443
+            if (strcmp(strLevel, "gzip") == 0) {
  444
+               windowBits = 16 + MAX_WBITS;
  445
+            }
  446
+            else if (strcmp(strLevel, "zlib") == 0) {
  447
+               windowBits = MAX_WBITS;
  448
+            }
  449
+            else if (strcmp(strLevel, "deflate") == 0) {
  450
+               windowBits = -MAX_WBITS;
  451
+            }
  452
+            else {
  453
+               Local<Value> exception = Exception::TypeError(String::New("bad deflate kind"));
  454
+               return ThrowException(exception);
  455
+            }
  456
+         }
  457
+         else if (args[0]->IsUndefined()) {
  458
+         }
  459
+         else {
  460
+            Local<Value> exception = Exception::TypeError(String::New("expected a Number or String"));
  461
+            return ThrowException(exception);
  462
+         }
  463
+      }
  464
+      
  465
+      Inflater *inflater = new Inflater();
  466
+      inflater->Wrap(args.This());
  467
+
  468
+      int r = inflater->Init(windowBits, output_chunk_size);
  469
+      
  470
+      if (r < 0) {
  471
+         return GetZError(r);
  472
+      }
  473
+      
  474
+      return args.This();
  475
+   }
  476
+   
  477
+   static Handle<Value> SetInput(const Arguments& args) {
  478
+      Inflater *inflater = ObjectWrap::Unwrap<Inflater>(args.This());
  479
+      HandleScope scope;
  480
+      
  481
+      Local<Object> in = args[0]->ToObject();
  482
+      ssize_t length = Buffer::Length(in);
  483
+
  484
+      // copy the input buffer, because it can be kept for several deflate() calls
  485
+      inflater->input = (char*)realloc(inflater->input, length);
  486
+      
  487
+      if (inflater->input == NULL) {
  488
+          return GetZError(Z_MEM_ERROR);
  489
+      }
  490
+      
  491
+      memcpy(inflater->input, Buffer::Data(in), length);
  492
+
  493
+      int r = inflater->SetInput(length);
  494
+      
  495
+      if (r < 0) {
  496
+         return GetZError(r);
  497
+      }
  498
+      
  499
+      return scope.Close(Undefined());
  500
+   }
  501
+   
  502
+   static Handle<Value> Inflate(const Arguments& args) {
  503
+      Inflater *inflater = ObjectWrap::Unwrap<Inflater>(args.This());
  504
+      HandleScope scope;
  505
+
  506
+      if (inflater->HasFinished()) {
  507
+         return scope.Close(False());
  508
+      }
  509
+
  510
+      int r = inflater->Inflate();
  511
+      
  512
+      if (r < 0) {
  513
+         return GetZError(r);
  514
+      }
  515
+      
  516
+      if (inflater->HasFinished()) {
  517
+         return scope.Close(True());
  518
+      }
  519
+      else {
  520
+         return scope.Close(Boolean::New(inflater->IsOutputBufferFull()));
  521
+      }
  522
+   }
  523
+   
  524
+   static Handle<Value> GetOutput(const Arguments& args) {
  525
+      Inflater *inflater = ObjectWrap::Unwrap<Inflater>(args.This());
  526
+      HandleScope scope;
  527
+      
  528
+      Buffer* slowBuffer = Buffer::New(inflater->GetOutput(), inflater->GetOutputLength());
  529
+      inflater->ResetOutput();
  530
+      
  531
+      if (inflater->HasFinished()) {
  532
+         free(inflater->GetOutput());
  533
+      }
  534
+      
  535
+      Local<Object> globalObj = Context::GetCurrent()->Global();
  536
+      Local<Function> bufferConstructor = Local<Function>::Cast(globalObj->Get(String::New("Buffer")));
  537
+      Handle<Value> constructorArgs[3] = { slowBuffer->handle_, Integer::New(inflater->GetOutputLength()), Integer::New(0) };
  538
+      Local<Object> jsBuffer = bufferConstructor->NewInstance(3, constructorArgs);
  539
+      
  540
+      return scope.Close(jsBuffer);
  541
+   }
  542
+};
  543
+
  544
+////////////////////////////////////////////////////////////////////////////////////////////////////////
  545
+
  546
+static Handle<Value> GetVersion(const Arguments &args) {
  547
+   const char* version = zlibVersion();
  548
+   return String::New(version);
  549
+}
  550
+
  551
+////////////////////////////////////////////////////////////////////////////////////////////////////////
  552
+
  553
+static Handle<Value> OnePassDeflate(const Arguments& args) {
  554
+   HandleScope scope;
  555
+   
  556
+   int level = Z_DEFAULT_COMPRESSION;
  557
+   int windowBits = 16 + MAX_WBITS; // gzip
  558
+   int memLevel = 8;
  559
+   int strategy = Z_DEFAULT_STRATEGY;
  560
+   
  561
+   int idx = 1;
  562
+   
  563
+   if (args.Length() > 0) {
  564
+      if(args[idx+0]->IsNumber()) {
  565
+         level = args[idx+0]->Int32Value();        
  566
+         if (level < 0 || level > 9) {
  567
+            Local<Value> exception = Exception::Error(String::New("level must be between 0 and 9"));
  568
+            return ThrowException(exception);
  569
+         }
  570
+      }
  571
+      else if (args[idx+0]->IsString()) {
  572
+         char* strLevel = *String::AsciiValue(args[idx+0]->ToString());
  573
+         
  574
+         if (strcmp(strLevel, "gzip") == 0) {
  575
+            windowBits = 16 + MAX_WBITS;
  576
+         }
  577
+         else if (strcmp(strLevel, "zlib") == 0) {
  578
+            windowBits = MAX_WBITS;
  579
+         }
  580
+         else if (strcmp(strLevel, "deflate") == 0) {
  581
+            windowBits = -MAX_WBITS;
  582
+         }
  583
+         else {
  584
+            Local<Value> exception = Exception::TypeError(String::New("bad deflate kind"));
  585
+            return ThrowException(exception);
  586
+         }
  587
+      }
  588
+      else if (args[idx+0]->IsUndefined()) {
  589
+      }
  590
+      else {
  591
+         Local<Value> exception = Exception::TypeError(String::New("expected a Number or String"));
  592
+         return ThrowException(exception);
  593
+      }
  594
+      
  595
+      if (args.Length() > 1) {
  596
+         if(args[idx+1]->IsNumber()) {
  597
+            level = args[idx+1]->Int32Value();        
  598
+            if (level < 0 || level > 9) {
  599
+               Local<Value> exception = Exception::Error(String::New("level must be between 0 and 9"));
  600
+               return ThrowException(exception);
  601
+            }
  602
+         }
  603
+         else if (args[idx+1]->IsUndefined()) {
  604
+         }
  605
+         else {
  606
+            Local<Value> exception = Exception::TypeError(String::New("expected a Number"));
  607
+            return ThrowException(exception);
  608
+         }
  609
+      }
  610
+   }
  611
+   
  612
+   Local<Object> inBuff = args[0]->ToObject();
  613
+   char* in = Buffer::Data(inBuff);
  614
+   size_t in_length = Buffer::Length(inBuff);
  615
+
  616
+   z_stream strm;
  617
+   strm.zalloc = Z_NULL;
  618
+   strm.zfree = Z_NULL;
  619
+   strm.opaque = Z_NULL;
  620
+   int r =  deflateInit2(&strm, level, Z_DEFLATED, windowBits, memLevel, strategy);
  621
+      
  622
+   if (r < 0) {
  623
+      return GetZError(r);
  624
+   }
  625
+   
  626
+   // deflate
  627
+   strm.avail_in = in_length;
  628
+   strm.next_in = (Bytef*) in;
  629
+   
  630
+   uLong bound = deflateBound(&strm, strm.avail_in);
  631
+   
  632
+   char* out = (char*) malloc(bound);
  633
+   
  634
+   if (out == NULL) {
  635
+      return GetZError(Z_MEM_ERROR);
  636
+   }
  637
+   
  638
+   strm.avail_out = bound;
  639
+   strm.next_out = (Bytef*) out;
  640
+          
  641
+   r = deflate(&strm, Z_FINISH);
  642
+   
  643
+   int out_length = bound - strm.avail_out;
  644
+   
  645
+   deflateEnd(&strm);
  646
+
  647
+   if (r < 0) {
  648
+      return GetZError(r);
  649
+   }
  650
+   
  651
+   // output
  652
+   Buffer* slowBuffer = Buffer::New(out, out_length);
  653
+   free(out);
  654
+
  655
+   Local<Object> globalObj = Context::GetCurrent()->Global();
  656
+   Local<Function> bufferConstructor = Local<Function>::Cast(globalObj->Get(String::New("Buffer")));
  657
+   Handle<Value> constructorArgs[3] = { slowBuffer->handle_, Integer::New(out_length), Integer::New(0) };
  658
+   Local<Object> jsBuffer = bufferConstructor->NewInstance(3, constructorArgs);
  659
+
  660
+   return scope.Close(jsBuffer);
  661
+}
  662
+   
  663
+static Handle<Value> OnePassInflate(const Arguments& args) {
  664
+   HandleScope scope;
  665
+   
  666
+   int windowBits = 16 + MAX_WBITS; // gzip
  667
+   
  668
+   int idx = 1;
  669
+   
  670
+   if (args.Length() > 0) {
  671
+      if (args[idx+0]->IsString()) {
  672
+         char* strLevel = *String::AsciiValue(args[idx+0]->ToString());
  673
+         
  674
+         if (strcmp(strLevel, "gzip") == 0) {
  675
+            windowBits = 16 + MAX_WBITS;
  676
+         }
  677
+         else if (strcmp(strLevel, "zlib") == 0) {
  678
+            windowBits = MAX_WBITS;
  679
+         }
  680
+         else if (strcmp(strLevel, "deflate") == 0) {
  681
+            windowBits = -MAX_WBITS;
  682
+         }
  683
+         else {
  684
+            Local<Value> exception = Exception::TypeError(String::New("bad deflate kind"));
  685
+            return ThrowException(exception);
  686
+         }
  687
+      }
  688
+      else if (args[idx+0]->IsUndefined()) {
  689
+      }
  690
+      else {
  691
+         Local<Value> exception = Exception::TypeError(String::New("expected a String"));
  692
+         return ThrowException(exception);
  693
+      }
  694
+   }
  695
+   
  696
+   Local<Object> inBuff = args[0]->ToObject();
  697
+   char* in = Buffer::Data(inBuff);
  698
+   size_t in_length = Buffer::Length(inBuff);
  699
+
  700
+   if (in_length == 0) {
  701
+      Local<Value> exception = Exception::TypeError(String::New("Buffer length must be greater than zero"));
  702
+      return ThrowException(exception);
  703
+   }
  704
+
  705
+   z_stream strm;
  706
+   strm.zalloc = Z_NULL;
  707
+   strm.zfree = Z_NULL;
  708
+   strm.opaque = Z_NULL;
  709
+   strm.avail_in = 0;
  710
+   strm.next_in = Z_NULL;
  711
+   int r = inflateInit2(&strm, windowBits);
  712
+      
  713
+   if (r < 0) {
  714
+      return GetZError(r);
  715
+   }
  716
+   
  717
+   // deflate
  718
+   strm.avail_in = in_length;
  719
+   strm.next_in = (Bytef*) in;
  720
+   
  721
+   // urgh, we don't know the buffer size (Q: is it in the gzip header?)
  722
+   uLong bound = 131072; // 128K
  723
+   
  724
+   char* out = (char*) malloc(bound);
  725
+   
  726
+   if (out == NULL) {
  727
+      return GetZError(Z_MEM_ERROR);
  728
+   }
  729
+   
  730
+   strm.avail_out = bound;
  731
+   strm.next_out = (Bytef*) out;
  732
+          
  733
+   r = inflate(&strm, Z_FINISH);
  734
+   
  735
+   while (r == Z_BUF_ERROR) {
  736
+      bound = bound * 2;
  737
+      size_t len = (char*)strm.next_out - out;
  738
+      
  739
+      out = (char*) realloc(out, bound);
  740
+
  741
+      if (out == NULL) {
  742
+         return GetZError(Z_MEM_ERROR);
  743
+      }
  744
+      
  745
+      strm.avail_out = bound - len;
  746
+      strm.next_out = (Bytef*) (out + len);
  747
+      
  748
+      r = inflate(&strm, Z_FINISH);
  749
+   }
  750
+   
  751
+   if (r < 0) {
  752
+      return GetZError(r);
  753
+   }
  754
+   
  755
+   int out_length = bound - strm.avail_out;
  756
+   
  757
+   inflateEnd(&strm);
  758
+   
  759
+   // output
  760
+   Buffer* slowBuffer = Buffer::New(out, out_length);
  761
+   free(out);
  762
+
  763
+   Local<Object> globalObj = Context::GetCurrent()->Global();
  764
+   Local<Function> bufferConstructor = Local<Function>::Cast(globalObj->Get(String::New("Buffer")));
  765
+   Handle<Value> constructorArgs[3] = { slowBuffer->handle_, Integer::New(out_length), Integer::New(0) };
  766
+   Local<Object> jsBuffer = bufferConstructor->NewInstance(3, constructorArgs);
  767
+
  768
+   return scope.Close(jsBuffer);
  769
+}
  770
+   
  771
+////////////////////////////////////////////////////////////////////////////////////////////////////////
  772
+
  773
+extern "C" {
  774
+   void init (Handle<Object> target) 
  775
+   {
  776
+     Deflater::Init(target);
  777
+     Inflater::Init(target);
  778
+     
  779
+     NODE_SET_METHOD(target, "version", GetVersion);
  780
+     NODE_SET_METHOD(target, "deflate", OnePassDeflate);
  781
+     NODE_SET_METHOD(target, "inflate", OnePassInflate);
  782
+   }
  783
+   
  784
+   NODE_MODULE(compress, init);
  785
+}
BIN  test/andromeda.bmp
Binary file not shown
BIN  test/andromeda.bmp.deflate
Binary file not shown
BIN  test/andromeda.bmp.gz
Binary file not shown
BIN  test/andromeda.bmp.z
Binary file not shown
144  test/node-deflate-test.js
... ...
@@ -0,0 +1,144 @@
  1
+var deflate = require('../lib/deflate'),
  2
+    fs = require('fs'),
  3
+    path = require('path');
  4
+
  5
+function testOnePassDeflate(format, extension, test) {
  6
+  test.expect(1);
  7
+  
  8
+  var inPath = path.join(__dirname, 'andromeda.bmp');
  9
+  var outPath = path.join(__dirname, 'temp.' + extension);
  10
+  
  11
+  fs.writeFileSync(outPath, deflate.deflate(fs.readFileSync(inPath), format));      // <-- todo: just use buffer!
  12
+  
  13
+  validateDeflate(test, extension);
  14
+  test.done();
  15
+}
  16
+
  17
+function testStreamingDeflate(format, extension, test) {
  18
+  test.expect(1);
  19
+
  20
+  var input = fs.createReadStream(path.join(__dirname, 'andromeda.bmp'));
  21
+  var output = fs.createWriteStream(path.join(__dirname, 'temp.' + extension)); // <-- TODO: write to MemoryStream ???
  22
+  
  23
+  var ds = deflate.createDeflateStream(input, format);
  24
+  ds.pipe(output);
  25
+
  26
+  input.on('close', function() {
  27
+    validateDeflate(test, extension);
  28
+    test.done();
  29
+  });
  30
+}
  31
+
  32
+function validateDeflate(test, extension, inflate) {
  33
+  var correct = fs.readFileSync(path.join(__dirname, 'andromeda.bmp.' + extension));
  34
+  var deflated = fs.readFileSync(path.join(__dirname, 'temp.' + extension));    // <-- TODO!
  35
+
  36
+  var failed = false;
  37
+
  38
+  for (var i = 0; i < correct.length; i++) {
  39
+    if (deflated[i] != correct[i]) {
  40
+      test.equal(deflated[i], correct[i], 'at offset: ' + i);
  41
+      failed = true;
  42
+      break;
  43
+    }
  44
+  }
  45
+
  46
+  if (!failed) {
  47
+    test.ok(true);  
  48
+  }
  49
+}
  50
+
  51
+function testOnePassInflate(format, extension, test) {
  52
+  test.expect(1);
  53
+  
  54
+  var inPath = path.join(__dirname, 'andromeda.bmp.' + extension);
  55
+  var outPath = path.join(__dirname, 'temp_' + extension + '.bmp');
  56
+  
  57
+  fs.writeFileSync(outPath, deflate.inflate(fs.readFileSync(inPath), format));      // <-- todo: just use buffer!
  58
+  
  59
+  validateInflate(test, extension);
  60
+  test.done();
  61
+}
  62
+
  63
+
  64
+function testStreamingInflate(format, extension, test) {
  65
+  test.expect(1);
  66
+  
  67
+  var input = fs.createReadStream(path.join(__dirname, 'andromeda.bmp.' + extension));
  68
+  var output = fs.createWriteStream(path.join(__dirname, 'temp_' + extension + '.bmp')); // <-- TODO: write to MemoryStream ???
  69
+  
  70
+  var ds = deflate.createInflateStream(input, format);
  71
+  ds.pipe(output);
  72
+
  73
+  input.on('close', function() {
  74
+    validateInflate(test, extension);
  75
+    test.done();
  76
+  });
  77
+}
  78
+
  79
+function validateInflate(test, extension, inflate) {
  80
+  var correct = fs.readFileSync(path.join(__dirname, 'andromeda.bmp'));
  81
+  var inflated = fs.readFileSync(path.join(__dirname, 'temp_' + extension + '.bmp'));    // <-- TODO!
  82
+
  83
+  var failed = false;
  84
+
  85
+  for (var i = 0; i < correct.length; i++) {
  86
+    if (inflated[i] != correct[i]) {
  87
+      test.equal(inflated[i], correct[i], 'at offset: ' + i);
  88
+      failed = true;
  89
+      break;
  90
+    }
  91
+  }
  92
+
  93
+  if (!failed) {
  94
+    test.ok(true);  
  95
+  }
  96
+}
  97
+
  98
+exports['GZIP deflate'] = function(test) {
  99
+    testOnePassDeflate('gzip', 'gz', test);
  100
+};
  101
+
  102
+exports['ZLIB deflate'] = function(test) {
  103
+    testOnePassDeflate('zlib', 'z', test);
  104
+};
  105
+
  106
+exports['DEFLATE deflate'] = function(test) {
  107
+    testOnePassDeflate('deflate', 'deflate', test);
  108
+};
  109
+
  110
+exports['streaming GZIP deflate'] = function(test) {
  111
+    testStreamingDeflate('gzip', 'gz', test);
  112
+};
  113
+
  114
+exports['streaming ZLIB deflate'] = function(test) {
  115
+    testStreamingDeflate('zlib', 'z', test);
  116
+};
  117
+
  118
+exports['streaming DEFLATE deflate'] = function(test) {
  119
+    testStreamingDeflate('deflate', 'deflate', test);
  120
+};
  121
+
  122
+exports['GZIP inflate'] = function(test) {
  123
+    testOnePassInflate('gzip', 'gz', test);
  124
+};
  125
+
  126
+exports['ZLIB inflate'] = function(test) {
  127
+    testOnePassInflate('zlib', 'z', test);
  128
+};
  129
+
  130
+exports['DEFLATE inflate'] = function(test) {
  131
+    testOnePassInflate('deflate', 'deflate', test);
  132
+};
  133
+
  134
+exports['streaming GZIP inflate'] = function(test) {
  135
+    testStreamingInflate('gzip', 'gz', test);
  136
+};
  137
+
  138
+exports['streaming ZLIB inflate'] = function(test) {
  139
+    testStreamingInflate('zlib', 'z', test);
  140
+};
  141
+
  142
+exports['streaming DEFLATE inflate'] = function(test) {
  143
+    testStreamingInflate('deflate', 'deflate', test);
  144
+};
45  wscript
... ...
@@ -0,0 +1,45 @@
  1
+import Options
  2
+from os import unlink, symlink, popen
  3
+from os.path import exists
  4
+from shutil import copy2 as copy
  5
+
  6
+TARGET = 'deflate-bindings'
  7
+TARGET_FILE = '%s.node' % TARGET
  8
+built = 'build/default/%s' % TARGET_FILE
  9
+dest = 'lib/deflate/%s' % TARGET_FILE
  10
+
  11
+def set_options(opt):
  12
+  opt.tool_options("compiler_cxx")
  13
+  opt.add_option('--debug', dest='debug', action='store_true', default=False)
  14
+   
  15
+def configure(conf):
  16
+  conf.check_tool("compiler_cxx")
  17
+  conf.check_tool("node_addon")
  18
+  conf.check(lib='z', libpath=['/usr/lib', '/usr/local/lib'], uselib_store='ZLIB', mandatory=True)
  19
+  
  20
+  conf.env.DEFINES = []
  21
+
  22
+  if Options.options.debug:
  23
+    conf.env.DEFINES += [ 'DEBUG' ]
  24
+    conf.env.CXXFLAGS = [ '-O0', '-g3' ]
  25
+  else:
  26
+    conf.env.CXXFLAGS = [ '-O3' ]
  27
+  
  28
+
  29
+def build(bld):
  30
+  obj = bld.new_task_gen("cxx", "shlib", "node_addon")
  31
+  #obj.cxxflags = ["-D_FILE_OFFSET_BITS=64", "-D_LARGEFILE_SOURCE", "-Wall"]
  32
+  obj.target = TARGET
  33
+  obj.source = "src/deflate.cc"
  34
+  obj.uselib = "ZLIB"
  35
+  obj.defines = bld.env.DEFINES
  36
+  
  37
+def shutdown():
  38
+ if Options.commands['clean']:
  39
+     if exists(TARGET_FILE):
  40
+       unlink(TARGET_FILE)
  41
+     if exists(dest):
  42
+       unlink(dest)
  43
+ else:
  44
+   if exists(built):
  45
+     copy(built, dest)

0 notes on commit 1188cb2

Please sign in to comment.
Something went wrong with that request. Please try again.