move global vars for node_file.cc, node_zlib.cc, and node_crypto.cc
[platform/upstream/nodejs.git] / src / node_zlib.cc
1 // Copyright Joyent, Inc. and other Node contributors.
2 //
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:
10 //
11 // The above copyright notice and this permission notice shall be included
12 // in all copies or substantial portions of the Software.
13 //
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.
21
22
23 #include <v8.h>
24 #include <errno.h>
25 #include <string.h>
26 #include <stdlib.h>
27 #include <sys/types.h>
28 #include <zlib.h>
29
30 #include <node.h>
31 #include <node_buffer.h>
32 #include <req_wrap.h>
33
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)
38
39
40 namespace node {
41 using namespace v8;
42
43 // write() returns one of these, and then calls the cb() when it's done.
44 typedef ReqWrap<uv_work_t> WorkReqWrap;
45
46 enum node_zlib_mode {
47   DEFLATE = 1,
48   INFLATE,
49   GZIP,
50   GUNZIP,
51   DEFLATERAW,
52   INFLATERAW,
53   UNZIP
54 };
55
56 template <node_zlib_mode mode> class ZCtx;
57
58
59 void InitZlib(v8::Handle<v8::Object> target);
60
61
62 /**
63  * Deflate/Inflate
64  */
65 template <node_zlib_mode mode> class ZCtx : public ObjectWrap {
66  public:
67
68   ZCtx() : ObjectWrap() {
69     dictionary_ = NULL;
70   }
71
72   ~ZCtx() {
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_);
77     }
78
79     if (dictionary_ != NULL) delete[] dictionary_;
80   }
81
82   // write(flush, in, in_off, in_len, out, out_off, out_len)
83   static Handle<Value>
84   Write(const Arguments& args) {
85     HandleScope scope;
86     assert(args.Length() == 7);
87
88     ZCtx<mode> *ctx = ObjectWrap::Unwrap< ZCtx<mode> >(args.This());
89     assert(ctx->init_done_ && "write before init");
90
91     unsigned int flush = args[0]->Uint32Value();
92     Bytef *in;
93     Bytef *out;
94     size_t in_off, in_len, out_off, out_len;
95
96     if (args[1]->IsNull()) {
97       // just a flush
98       Bytef nada[1] = { 0 };
99       in = nada;
100       in_len = 0;
101       in_off = 0;
102     } else {
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();
108
109       assert(in_off + in_len <= Buffer::Length(in_buf));
110       in = reinterpret_cast<Bytef *>(Buffer::Data(in_buf) + in_off);
111     }
112
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);
119
120     WorkReqWrap *req_wrap = new WorkReqWrap();
121
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;
127     ctx->flush_ = flush;
128
129     // set this so that later on, I can easily tell how much was written.
130     ctx->chunk_size_ = out_len;
131
132     // build up the work request
133     uv_work_t* work_req = new uv_work_t();
134     work_req->data = req_wrap;
135
136     uv_queue_work(uv_default_loop(),
137                   work_req,
138                   ZCtx<mode>::Process,
139                   ZCtx<mode>::After);
140
141     req_wrap->Dispatched();
142
143     return req_wrap->object_;
144   }
145
146
147   // thread pool!
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
150   // been consumed.
151   static void
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_;
155
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.
159     int err;
160     switch (mode) {
161       case DEFLATE:
162       case GZIP:
163       case DEFLATERAW:
164         err = deflate(&(ctx->strm_), ctx->flush_);
165         break;
166       case UNZIP:
167       case INFLATE:
168       case GUNZIP:
169       case INFLATERAW:
170         err = inflate(&(ctx->strm_), ctx->flush_);
171
172         // If data was encoded with dictionary
173         if (err == Z_NEED_DICT) {
174           assert(ctx->dictionary_ != NULL && "Stream has no dictionary");
175
176           // Load it
177           err = inflateSetDictionary(
178               &(ctx->strm_),
179               ctx->dictionary_,
180               ctx->dictionary_len_
181           );
182           assert(err == Z_OK && "Failed to set dictionary");
183
184           // And try to decode again
185           err = inflate(&(ctx->strm_), ctx->flush_);
186         }
187         break;
188       default:
189         assert(0 && "wtf?");
190     }
191     assert(err != Z_STREAM_ERROR);
192
193     // now After will emit the output, and
194     // either schedule another call to Process,
195     // or shift the queue and call Process.
196   }
197
198   // v8 land!
199   static void
200   After(uv_work_t* work_req) {
201     HandleScope scope;
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);
206
207     // call the write() cb
208     assert(req_wrap->object_->Get(callback_sym)->IsFunction() &&
209            "Invalid callback");
210     Local<Value> args[2] = { avail_in, avail_out };
211     MakeCallback(req_wrap->object_, "callback", 2, args);
212
213     // delete the ReqWrap
214     delete req_wrap;
215   }
216
217   static Handle<Value>
218   New(const Arguments& args) {
219     HandleScope scope;
220     ZCtx<mode> *ctx = new ZCtx<mode>();
221     ctx->Wrap(args.This());
222     return args.This();
223   }
224
225   // just pull the ints out of the args and call the other Init
226   static Handle<Value>
227   Init(const Arguments& args) {
228     HandleScope scope;
229
230     assert((args.Length() == 4 || args.Length() == 5) &&
231            "init(windowBits, level, memLevel, strategy, [dictionary])");
232
233     ZCtx<mode> *ctx = ObjectWrap::Unwrap< ZCtx<mode> >(args.This());
234
235     int windowBits = args[0]->Uint32Value();
236     assert((windowBits >= 8 && windowBits <= 15) && "invalid windowBits");
237
238     int level = args[1]->Uint32Value();
239     assert((level >= -1 && level <= 9) && "invalid compression level");
240
241     int memLevel = args[2]->Uint32Value();
242     assert((memLevel >= 1 && memLevel <= 9) && "invalid memlevel");
243
244     int strategy = args[3]->Uint32Value();
245     assert((strategy == Z_FILTERED ||
246             strategy == Z_HUFFMAN_ONLY ||
247             strategy == Z_RLE ||
248             strategy == Z_FIXED ||
249             strategy == Z_DEFAULT_STRATEGY) && "invalid strategy");
250
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();
255
256       dictionary_len = Buffer::Length(dictionary_);
257       dictionary = new char[dictionary_len];
258
259       memcpy(dictionary, Buffer::Data(dictionary_), dictionary_len);
260     }
261
262     Init(ctx, level, windowBits, memLevel, strategy,
263          dictionary, dictionary_len);
264     return Undefined();
265   }
266
267   static void
268   Init(ZCtx *ctx,
269        int level,
270        int windowBits,
271        int memLevel,
272        int strategy,
273        char* dictionary,
274        size_t dictionary_len) {
275     ctx->level_ = level;
276     ctx->windowBits_ = windowBits;
277     ctx->memLevel_ = memLevel;
278     ctx->strategy_ = strategy;
279
280     ctx->strm_.zalloc = Z_NULL;
281     ctx->strm_.zfree = Z_NULL;
282     ctx->strm_.opaque = Z_NULL;
283
284     ctx->flush_ = Z_NO_FLUSH;
285
286     if (mode == GZIP || mode == GUNZIP) {
287       ctx->windowBits_ += 16;
288     }
289
290     if (mode == UNZIP) {
291       ctx->windowBits_ += 32;
292     }
293
294     if (mode == DEFLATERAW || mode == INFLATERAW) {
295       ctx->windowBits_ *= -1;
296     }
297
298     int err;
299     switch (mode) {
300       case DEFLATE:
301       case GZIP:
302       case DEFLATERAW:
303         err = deflateInit2(&(ctx->strm_),
304                            ctx->level_,
305                            Z_DEFLATED,
306                            ctx->windowBits_,
307                            ctx->memLevel_,
308                            ctx->strategy_);
309         break;
310       case INFLATE:
311       case GUNZIP:
312       case INFLATERAW:
313       case UNZIP:
314         err = inflateInit2(&(ctx->strm_), ctx->windowBits_);
315         break;
316       default:
317         assert(0 && "wtf?");
318     }
319
320     assert(err == Z_OK);
321
322     ctx->dictionary_ = reinterpret_cast<Bytef *>(dictionary);
323     ctx->dictionary_len_ = dictionary_len;
324
325     if (dictionary != NULL) {
326       switch (mode) {
327         case DEFLATE:
328         case DEFLATERAW:
329           err = deflateSetDictionary(
330               &(ctx->strm_),
331               ctx->dictionary_,
332               dictionary_len
333           );
334           break;
335         default:
336           break;
337       }
338
339       assert(err == Z_OK && "Failed to set dictionary");
340     }
341
342     ctx->init_done_ = true;
343   }
344
345  private:
346
347   bool init_done_;
348
349   z_stream strm_;
350   int level_;
351   int windowBits_;
352   int memLevel_;
353   int strategy_;
354
355   Bytef* dictionary_;
356   size_t dictionary_len_;
357
358   int flush_;
359
360   int chunk_size_;
361 };
362
363
364 #define NODE_ZLIB_CLASS(mode, name)   \
365   { \
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()); \
372   }
373
374 void InitZlib(Handle<Object> target) {
375   HandleScope scope;
376
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")
384
385   callback_sym = NODE_PSYMBOL("callback");
386
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);
412
413   target->Set(String::NewSymbol("ZLIB_VERSION"), String::New(ZLIB_VERSION));
414 }
415
416 }  // namespace node
417
418 NODE_MODULE(node_zlib, node::InitZlib)