Skip to content
Browse files

Implemented zlib native addon for parsing packfiles

  • Loading branch information...
1 parent 542c2f1 commit ccb16c472500e2fabc4b295ae9baae61d455fbd9 @tarruda committed Jan 8, 2013
Showing with 212 additions and 3 deletions.
  1. +1 −0 .gitignore
  2. +33 −0 binding.gyp
  3. +3 −3 package.json
  4. +124 −0 src/cpp/zlib.cpp
  5. +51 −0 src/js/zlib.js
View
1 .gitignore
@@ -1,2 +1,3 @@
+/build
/node_modules
*.tgz
View
33 binding.gyp
@@ -0,0 +1,33 @@
+{
+ 'targets': [{
+ 'target_name': 'binding',
+ 'sources': [ 'src/cpp/zlib.cpp' ],
+ # Adapted from https://github.com/brianc/node-postgres/blob/master/binding.gyp
+ 'conditions' : [
+ ['OS=="mac"', {
+ 'include_dirs': ['<!@(pg_config --includedir)'],
+ 'libraries' : ['-lz -L<!@(pg_config --libdir)']
+ }],
+ ['OS=="linux"', {
+ 'include_dirs': ['<!@(pg_config --includedir)'],
+ 'libraries' : ['-lz -L<!@(pg_config --libdir)']
+ }],
+ ['OS=="solaris"', {
+ 'include_dirs': ['<!@(pg_config --includedir)'],
+ 'libraries' : ['-lz -L<!@(pg_config --libdir)']
+ }],
+ ['OS=="win"', {
+ 'include_dirs': ['<!@(pg_config --includedir)'],
+ 'libraries' : ['libz.lib'],
+ 'msvs_settings': {
+ 'VCLinkerTool' : {
+ 'AdditionalLibraryDirectories' : [
+ '<!@(pg_config --libdir)\\'
+ ]
+ },
+ }
+ }]
+ ]
+ }
+ ]
+}
View
6 package.json
@@ -1,8 +1,8 @@
{
- "name": "node-git-core",
+ "name": "git-core",
"version": "0.0.1",
- "description": "Library for working git core structures(blobs, trees, commits, tags and packs)",
- "main": "index.js",
+ "description": "Simple library for working git core structures(blobs, trees, commits, tags and packs) without a repository",
+ "main": "./src/js/index.js",
"scripts": {
"test": "make test"
},
View
124 src/cpp/zlib.cpp
@@ -0,0 +1,124 @@
+// helper zlib functions for easily inflating/deflating git packed objects
+#include <node.h>
+#include <node_buffer.h>
+#include <zlib.h>
+#include <stdlib.h>
+#include <iostream>
+
+using namespace v8;
+using namespace node;
+
+void freeBuffer(char* pointer, void* hint) {
+ free(pointer);
+}
+
+Handle<Value> wrapReturnCode(HandleScope* scope, int code) {
+ Local<Number> num = Number::New(code);
+ return scope->Close(num);
+}
+
+Handle<Value> deflate(const Arguments& args) {
+ HandleScope scope;
+ int rv;
+ Local<Object> inBuffer = args[0]->ToObject();
+ // get a pointer to the input buffer data
+ unsigned char* inData = (unsigned char*)Buffer::Data(inBuffer);
+ // length of the input buffer
+ size_t inLength = Buffer::Length(inBuffer);
+ // declare deflate structure
+ z_stream strm;
+ // set the default memory routines
+ strm.zalloc = Z_NULL;
+ strm.zfree = Z_NULL;
+ strm.opaque = Z_NULL;
+ // initialize the structure
+ rv = deflateInit(&strm, Z_DEFAULT_COMPRESSION);
+ if (rv != Z_OK)
+ return wrapReturnCode(&scope, rv);
+ // set the number of bytes to read, since we are compressing the buffer
+ // in a single step, this is just the buffer length
+ strm.avail_in = inLength;
+ // set the uncompressed data pointer
+ strm.next_in = inData;
+ // find the maximum number of bytes needed to hold the compressed
+ // data
+ size_t outMaxLength = deflateBound(&strm, inLength);
+ // allocate memory for compressed data
+ unsigned char* outData = (unsigned char*)malloc(outMaxLength);
+ if (outData == NULL)
+ return wrapReturnCode(&scope, Z_MEM_ERROR);
+ // set allocated memory info
+ strm.avail_out = outMaxLength;
+ strm.next_out = outData;
+ // compress everything in one step
+ rv = deflate(&strm, Z_FINISH);
+ if (rv != Z_STREAM_END)
+ return wrapReturnCode(&scope, rv);
+ size_t outLength = outMaxLength - strm.avail_out;
+ // free zlib allocated memory
+ deflateEnd(&strm);
+ // create the nodejs SlowBuffer to hold the compressed data
+ Buffer* outBuffer = Buffer::New((char*)outData, outLength, freeBuffer, NULL);
+ return scope.Close(outBuffer->handle_);
+}
+
+Handle<Value> inflate(const Arguments& args) {
+ HandleScope scope;
+ int rv;
+ Local<Object> inBuffer = args[0]->ToObject();
+ // length of the uncompressed data is available in the packfile
+ // before the deflated stream, and is used to allocate the output
+ // buffer
+ Local<Object> uncompressedLength = args[1]->ToObject();
+ unsigned char* inData = (unsigned char*)Buffer::Data(inBuffer);
+ size_t inLength = Buffer::Length(inBuffer);
+ z_stream strm;
+ strm.zalloc = Z_NULL;
+ strm.zfree = Z_NULL;
+ strm.opaque = Z_NULL;
+ // initialize avail_in/next_in so zlib can optimize
+ // initial memory allocation
+ strm.avail_in = inLength;
+ strm.next_in = inData;
+ rv = inflateInit(&strm);
+ if (rv != Z_OK)
+ return wrapReturnCode(&scope, rv);
+ size_t outLength = uncompressedLength->Uint32Value();
+ unsigned char* outData = (unsigned char*)malloc(outLength);
+ if (outData == NULL)
+ return wrapReturnCode(&scope, Z_MEM_ERROR);
+ strm.avail_out = outLength;
+ strm.next_out = outData;
+ rv = inflate(&strm, Z_FINISH);
+ if (rv != Z_STREAM_END)
+ return wrapReturnCode(&scope, rv);
+ // set the number of bytes read from the input buffer
+ size_t bytesRead = inLength - strm.avail_in;
+ deflateEnd(&strm);
+ // create the slowbuffer containing inflated data
+ Buffer* outBuffer = Buffer::New((char*)outData, (size_t)outLength, freeBuffer, NULL);
+ // create a javascript array to hold the number of bytes read and
+ // inflated data
+ Handle<Array> array = Array::New(2);
+ if (array.IsEmpty())
+ return wrapReturnCode(&scope, Z_MEM_ERROR);
+ array->Set(0, outBuffer->handle_);
+ array->Set(1, Integer::New(bytesRead));
+ return scope.Close(array);
+}
+
+void init(Handle<Object> target) {
+ NODE_SET_METHOD(target, "deflate", deflate);
+ NODE_SET_METHOD(target, "inflate", inflate);
+ NODE_DEFINE_CONSTANT(target, Z_OK);
+ NODE_DEFINE_CONSTANT(target, Z_STREAM_END);
+ NODE_DEFINE_CONSTANT(target, Z_NEED_DICT);
+ NODE_DEFINE_CONSTANT(target, Z_ERRNO);
+ NODE_DEFINE_CONSTANT(target, Z_STREAM_ERROR);
+ NODE_DEFINE_CONSTANT(target, Z_DATA_ERROR);
+ NODE_DEFINE_CONSTANT(target, Z_MEM_ERROR);
+ NODE_DEFINE_CONSTANT(target, Z_BUF_ERROR);
+ NODE_DEFINE_CONSTANT(target, Z_VERSION_ERROR);
+}
+
+NODE_MODULE(binding, init);
View
51 src/js/zlib.js
@@ -0,0 +1,51 @@
+var _zlib = require('../../build/Release/binding.node')
+ , returnCodes = {
+ Z_OK: binding.Z_OK,
+ Z_STREAM_END: binding.Z_STREAM_END,
+ Z_NEED_DICT: binding.Z_NEED_DICT,
+ Z_ERRNO: binding.Z_ERRNO,
+ Z_STREAM_ERROR: binding.Z_STREAM_ERROR,
+ Z_DATA_ERROR: binding.Z_DATA_ERROR,
+ Z_MEM_ERROR: binding.Z_MEM_ERROR,
+ Z_BUF_ERROR: binding.Z_BUF_ERROR,
+ Z_VERSION_ERROR: binding.Z_VERSION_ERROR
+};
+
+function checkBuffer(data) {
+ if (!(data instanceof Buffer))
+ throw new Error('expecting buffer');
+}
+
+function checkError(returnValue) {
+ if (typeof returnValue === 'number')
+ throw new Error(returnCodes[returnValue]);
+}
+
+function deflate(data) {
+ var rv;
+
+ checkBuffer(data);
+ rv = _zlib.deflate(data);
+ checkError(rv);
+
+ return new Buffer(rv, rv.length, 0);
+}
+
+function inflate(data, inflatedsize) {
+ var rv;
+
+ checkBuffer(data);
+ rv = _zlib.inflate(data, inflatedsize);
+ checkError(rv);
+ rv[0] = new Buffer(rv[0], rv[0].length, 0);
+
+ return rv;
+}
+
+
+Object.keys(returnCodes).forEach(function(k) {
+ returnCodes[returnCodes[k]] = k;
+});
+
+exports.deflate = deflate;
+exports.inflate = inflate;

0 comments on commit ccb16c4

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