1 // Copyright Joyent, Inc. and other Node contributors.
3 // Permission is hereby granted, free of charge, to any person obtaining a
4 // copy of this software and associated documentation files (the
5 // "Software"), to deal in the Software without restriction, including
6 // without limitation the rights to use, copy, modify, merge, publish,
7 // distribute, sublicense, and/or sell copies of the Software, and to permit
8 // persons to whom the Software is furnished to do so, subject to the
9 // following conditions:
11 // The above copyright notice and this permission notice shall be included
12 // in all copies or substantial portions of the Software.
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17 // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18 // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19 // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20 // USE OR OTHER DEALINGS IN THE SOFTWARE.
27 #include <sys/types.h>
31 #include <node_buffer.h>
34 #include <node_vars.h>
35 // We do the following to minimize the detal between v0.6 branch. We want to
36 // use the variables as they were being used before.
37 #define callback_sym NODE_VAR(callback_sym)
43 // write() returns one of these, and then calls the cb() when it's done.
44 typedef ReqWrap<uv_work_t> WorkReqWrap;
56 template <node_zlib_mode mode> class ZCtx;
59 void InitZlib(v8::Handle<v8::Object> target);
65 template <node_zlib_mode mode> class ZCtx : public ObjectWrap {
68 ZCtx() : ObjectWrap() {
73 if (mode == DEFLATE || mode == GZIP || mode == DEFLATERAW) {
74 (void)deflateEnd(&strm_);
75 } else if (mode == INFLATE || mode == GUNZIP || mode == INFLATERAW) {
76 (void)inflateEnd(&strm_);
79 if (dictionary_ != NULL) delete[] dictionary_;
82 // write(flush, in, in_off, in_len, out, out_off, out_len)
84 Write(const Arguments& args) {
86 assert(args.Length() == 7);
88 ZCtx<mode> *ctx = ObjectWrap::Unwrap< ZCtx<mode> >(args.This());
89 assert(ctx->init_done_ && "write before init");
91 unsigned int flush = args[0]->Uint32Value();
94 size_t in_off, in_len, out_off, out_len;
96 if (args[1]->IsNull()) {
98 Bytef nada[1] = { 0 };
103 assert(Buffer::HasInstance(args[1]));
104 Local<Object> in_buf;
105 in_buf = args[1]->ToObject();
106 in_off = (size_t)args[2]->Uint32Value();
107 in_len = (size_t)args[3]->Uint32Value();
109 assert(in_off + in_len <= Buffer::Length(in_buf));
110 in = reinterpret_cast<Bytef *>(Buffer::Data(in_buf) + in_off);
113 assert(Buffer::HasInstance(args[4]));
114 Local<Object> out_buf = args[4]->ToObject();
115 out_off = (size_t)args[5]->Uint32Value();
116 out_len = (size_t)args[6]->Uint32Value();
117 assert(out_off + out_len <= Buffer::Length(out_buf));
118 out = reinterpret_cast<Bytef *>(Buffer::Data(out_buf) + out_off);
120 WorkReqWrap *req_wrap = new WorkReqWrap();
122 req_wrap->data_ = ctx;
123 ctx->strm_.avail_in = in_len;
124 ctx->strm_.next_in = &(*in);
125 ctx->strm_.avail_out = out_len;
126 ctx->strm_.next_out = out;
129 // set this so that later on, I can easily tell how much was written.
130 ctx->chunk_size_ = out_len;
132 // build up the work request
133 uv_work_t* work_req = new uv_work_t();
134 work_req->data = req_wrap;
136 uv_queue_work(uv_default_loop(),
141 req_wrap->Dispatched();
143 return req_wrap->object_;
148 // This function may be called multiple times on the uv_work pool
149 // for a single write() call, until all of the input bytes have
152 Process(uv_work_t* work_req) {
153 WorkReqWrap *req_wrap = reinterpret_cast<WorkReqWrap *>(work_req->data);
154 ZCtx<mode> *ctx = (ZCtx<mode> *)req_wrap->data_;
156 // If the avail_out is left at 0, then it means that it ran out
157 // of room. If there was avail_out left over, then it means
158 // that all of the input was consumed.
164 err = deflate(&(ctx->strm_), ctx->flush_);
170 err = inflate(&(ctx->strm_), ctx->flush_);
172 // If data was encoded with dictionary
173 if (err == Z_NEED_DICT) {
174 assert(ctx->dictionary_ != NULL && "Stream has no dictionary");
177 err = inflateSetDictionary(
182 assert(err == Z_OK && "Failed to set dictionary");
184 // And try to decode again
185 err = inflate(&(ctx->strm_), ctx->flush_);
191 assert(err != Z_STREAM_ERROR);
193 // now After will emit the output, and
194 // either schedule another call to Process,
195 // or shift the queue and call Process.
200 After(uv_work_t* work_req) {
202 WorkReqWrap *req_wrap = reinterpret_cast<WorkReqWrap *>(work_req->data);
203 ZCtx<mode> *ctx = (ZCtx<mode> *)req_wrap->data_;
204 Local<Integer> avail_out = Integer::New(ctx->strm_.avail_out);
205 Local<Integer> avail_in = Integer::New(ctx->strm_.avail_in);
207 // call the write() cb
208 assert(req_wrap->object_->Get(callback_sym)->IsFunction() &&
210 Local<Value> args[2] = { avail_in, avail_out };
211 MakeCallback(req_wrap->object_, "callback", 2, args);
213 // delete the ReqWrap
218 New(const Arguments& args) {
220 ZCtx<mode> *ctx = new ZCtx<mode>();
221 ctx->Wrap(args.This());
225 // just pull the ints out of the args and call the other Init
227 Init(const Arguments& args) {
230 assert((args.Length() == 4 || args.Length() == 5) &&
231 "init(windowBits, level, memLevel, strategy, [dictionary])");
233 ZCtx<mode> *ctx = ObjectWrap::Unwrap< ZCtx<mode> >(args.This());
235 int windowBits = args[0]->Uint32Value();
236 assert((windowBits >= 8 && windowBits <= 15) && "invalid windowBits");
238 int level = args[1]->Uint32Value();
239 assert((level >= -1 && level <= 9) && "invalid compression level");
241 int memLevel = args[2]->Uint32Value();
242 assert((memLevel >= 1 && memLevel <= 9) && "invalid memlevel");
244 int strategy = args[3]->Uint32Value();
245 assert((strategy == Z_FILTERED ||
246 strategy == Z_HUFFMAN_ONLY ||
248 strategy == Z_FIXED ||
249 strategy == Z_DEFAULT_STRATEGY) && "invalid strategy");
251 char* dictionary = NULL;
252 size_t dictionary_len = 0;
253 if (args.Length() >= 5 && Buffer::HasInstance(args[4])) {
254 Local<Object> dictionary_ = args[4]->ToObject();
256 dictionary_len = Buffer::Length(dictionary_);
257 dictionary = new char[dictionary_len];
259 memcpy(dictionary, Buffer::Data(dictionary_), dictionary_len);
262 Init(ctx, level, windowBits, memLevel, strategy,
263 dictionary, dictionary_len);
274 size_t dictionary_len) {
276 ctx->windowBits_ = windowBits;
277 ctx->memLevel_ = memLevel;
278 ctx->strategy_ = strategy;
280 ctx->strm_.zalloc = Z_NULL;
281 ctx->strm_.zfree = Z_NULL;
282 ctx->strm_.opaque = Z_NULL;
284 ctx->flush_ = Z_NO_FLUSH;
286 if (mode == GZIP || mode == GUNZIP) {
287 ctx->windowBits_ += 16;
291 ctx->windowBits_ += 32;
294 if (mode == DEFLATERAW || mode == INFLATERAW) {
295 ctx->windowBits_ *= -1;
303 err = deflateInit2(&(ctx->strm_),
314 err = inflateInit2(&(ctx->strm_), ctx->windowBits_);
322 ctx->dictionary_ = reinterpret_cast<Bytef *>(dictionary);
323 ctx->dictionary_len_ = dictionary_len;
325 if (dictionary != NULL) {
329 err = deflateSetDictionary(
339 assert(err == Z_OK && "Failed to set dictionary");
342 ctx->init_done_ = true;
356 size_t dictionary_len_;
364 #define NODE_ZLIB_CLASS(mode, name) \
366 Local<FunctionTemplate> z = FunctionTemplate::New(ZCtx<mode>::New); \
367 z->InstanceTemplate()->SetInternalFieldCount(1); \
368 NODE_SET_PROTOTYPE_METHOD(z, "write", ZCtx<mode>::Write); \
369 NODE_SET_PROTOTYPE_METHOD(z, "init", ZCtx<mode>::Init); \
370 z->SetClassName(String::NewSymbol(name)); \
371 target->Set(String::NewSymbol(name), z->GetFunction()); \
374 void InitZlib(Handle<Object> target) {
377 NODE_ZLIB_CLASS(INFLATE, "Inflate")
378 NODE_ZLIB_CLASS(DEFLATE, "Deflate")
379 NODE_ZLIB_CLASS(INFLATERAW, "InflateRaw")
380 NODE_ZLIB_CLASS(DEFLATERAW, "DeflateRaw")
381 NODE_ZLIB_CLASS(GZIP, "Gzip")
382 NODE_ZLIB_CLASS(GUNZIP, "Gunzip")
383 NODE_ZLIB_CLASS(UNZIP, "Unzip")
385 callback_sym = NODE_PSYMBOL("callback");
387 NODE_DEFINE_CONSTANT(target, Z_NO_FLUSH);
388 NODE_DEFINE_CONSTANT(target, Z_PARTIAL_FLUSH);
389 NODE_DEFINE_CONSTANT(target, Z_SYNC_FLUSH);
390 NODE_DEFINE_CONSTANT(target, Z_FULL_FLUSH);
391 NODE_DEFINE_CONSTANT(target, Z_FINISH);
392 NODE_DEFINE_CONSTANT(target, Z_BLOCK);
393 NODE_DEFINE_CONSTANT(target, Z_OK);
394 NODE_DEFINE_CONSTANT(target, Z_STREAM_END);
395 NODE_DEFINE_CONSTANT(target, Z_NEED_DICT);
396 NODE_DEFINE_CONSTANT(target, Z_ERRNO);
397 NODE_DEFINE_CONSTANT(target, Z_STREAM_ERROR);
398 NODE_DEFINE_CONSTANT(target, Z_DATA_ERROR);
399 NODE_DEFINE_CONSTANT(target, Z_MEM_ERROR);
400 NODE_DEFINE_CONSTANT(target, Z_BUF_ERROR);
401 NODE_DEFINE_CONSTANT(target, Z_VERSION_ERROR);
402 NODE_DEFINE_CONSTANT(target, Z_NO_COMPRESSION);
403 NODE_DEFINE_CONSTANT(target, Z_BEST_SPEED);
404 NODE_DEFINE_CONSTANT(target, Z_BEST_COMPRESSION);
405 NODE_DEFINE_CONSTANT(target, Z_DEFAULT_COMPRESSION);
406 NODE_DEFINE_CONSTANT(target, Z_FILTERED);
407 NODE_DEFINE_CONSTANT(target, Z_HUFFMAN_ONLY);
408 NODE_DEFINE_CONSTANT(target, Z_RLE);
409 NODE_DEFINE_CONSTANT(target, Z_FIXED);
410 NODE_DEFINE_CONSTANT(target, Z_DEFAULT_STRATEGY);
411 NODE_DEFINE_CONSTANT(target, ZLIB_VERNUM);
413 target->Set(String::NewSymbol("ZLIB_VERSION"), String::New(ZLIB_VERSION));
418 NODE_MODULE(node_zlib, node::InitZlib)