GCC Code Coverage Report
Directory: ../src/ Exec Total Coverage
File: /home/node-core-coverage/node-core-coverage/workdir/node/src/node_zlib.cc Lines: 265 275 96.4 %
Date: 2016-07-23 Branches: 153 227 67.4 %

Line Exec Source
1
#include "node.h"
2
#include "node_buffer.h"
3
4
#include "async-wrap.h"
5
#include "async-wrap-inl.h"
6
#include "env.h"
7
#include "env-inl.h"
8
#include "util.h"
9
#include "util-inl.h"
10
11
#include "v8.h"
12
#include "zlib.h"
13
14
#include <errno.h>
15
#include <stdlib.h>
16
#include <string.h>
17
#include <sys/types.h>
18
19
namespace node {
20
21
using v8::Array;
22
using v8::Context;
23
using v8::FunctionCallbackInfo;
24
using v8::FunctionTemplate;
25
using v8::HandleScope;
26
using v8::Integer;
27
using v8::Local;
28
using v8::Number;
29
using v8::Object;
30
using v8::String;
31
using v8::Value;
32
33
enum node_zlib_mode {
34
  NONE,
35
  DEFLATE,
36
  INFLATE,
37
  GZIP,
38
  GUNZIP,
39
  DEFLATERAW,
40
  INFLATERAW,
41
  UNZIP
42
};
43
44
#define GZIP_HEADER_ID1 0x1f
45
#define GZIP_HEADER_ID2 0x8b
46
47
void InitZlib(v8::Local<v8::Object> target);
48
49
50
/**
51
 * Deflate/Inflate
52
 */
53
class ZCtx : public AsyncWrap {
54
 public:
55
165
  ZCtx(Environment* env, Local<Object> wrap, node_zlib_mode mode)
56
      : AsyncWrap(env, wrap, AsyncWrap::PROVIDER_ZLIB),
57
        chunk_size_(0),
58
        dictionary_(nullptr),
59
        dictionary_len_(0),
60
        err_(0),
61
        flush_(0),
62
        init_done_(false),
63
        level_(0),
64
        memLevel_(0),
65
        mode_(mode),
66
        strategy_(0),
67
        windowBits_(0),
68
        write_in_progress_(false),
69
        pending_close_(false),
70
        refs_(0),
71
165
        gzip_id_bytes_read_(0) {
72
165
    MakeWeak<ZCtx>(this);
73
165
  }
74
75
76
456
  ~ZCtx() override {
77
152
    CHECK_EQ(false, write_in_progress_ && "write in progress");
78
152
    Close();
79
304
  }
80
81
334
  void Close() {
82
334
    if (write_in_progress_) {
83
24
      pending_close_ = true;
84
24
      return;
85
    }
86
87
310
    pending_close_ = false;
88
310
    CHECK(init_done_ && "close before init");
89
310
    CHECK_LE(mode_, UNZIP);
90
91
310
    if (mode_ == DEFLATE || mode_ == GZIP || mode_ == DEFLATERAW) {
92
58
      (void)deflateEnd(&strm_);
93
58
      int64_t change_in_bytes = -static_cast<int64_t>(kDeflateContextSize);
94
58
      env()->isolate()->AdjustAmountOfExternalAllocatedMemory(change_in_bytes);
95
252
    } else if (mode_ == INFLATE || mode_ == GUNZIP || mode_ == INFLATERAW ||
96
               mode_ == UNZIP) {
97
100
      (void)inflateEnd(&strm_);
98
100
      int64_t change_in_bytes = -static_cast<int64_t>(kInflateContextSize);
99
100
      env()->isolate()->AdjustAmountOfExternalAllocatedMemory(change_in_bytes);
100
    }
101
310
    mode_ = NONE;
102
103
310
    if (dictionary_ != nullptr) {
104
5
      delete[] dictionary_;
105
5
      dictionary_ = nullptr;
106
    }
107
  }
108
109
110
158
  static void Close(const FunctionCallbackInfo<Value>& args) {
111
    ZCtx* ctx;
112
158
    ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
113
158
    ctx->Close();
114
  }
115
116
117
  // write(flush, in, in_off, in_len, out, out_off, out_len)
118
  template <bool async>
119
759
  static void Write(const FunctionCallbackInfo<Value>& args) {
120
759
    CHECK_EQ(args.Length(), 7);
121
122
    ZCtx* ctx;
123
814
    ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
124
759
    CHECK(ctx->init_done_ && "write before init");
125
759
    CHECK(ctx->mode_ != NONE && "already finalized");
126
127
759
    CHECK_EQ(false, ctx->write_in_progress_ && "write already in progress");
128
759
    CHECK_EQ(false, ctx->pending_close_ && "close is pending");
129
759
    ctx->write_in_progress_ = true;
130
1518
    ctx->Ref();
131
132
2277
    CHECK_EQ(false, args[0]->IsUndefined() && "must provide flush value");
133
134
759
    unsigned int flush = args[0]->Uint32Value();
135
136
759
    if (flush != Z_NO_FLUSH &&
137
        flush != Z_PARTIAL_FLUSH &&
138
        flush != Z_SYNC_FLUSH &&
139
        flush != Z_FULL_FLUSH &&
140
        flush != Z_FINISH &&
141
        flush != Z_BLOCK) {
142
      CHECK(0 && "Invalid flush value");
143
    }
144
145
    Bytef *in;
146
    Bytef *out;
147
    size_t in_off, in_len, out_off, out_len;
148
759
    Environment* env = ctx->env();
149
150
1518
    if (args[1]->IsNull()) {
151
      // just a flush
152
      in = nullptr;
153
      in_len = 0;
154
      in_off = 0;
155
    } else {
156
759
      CHECK(Buffer::HasInstance(args[1]));
157
759
      Local<Object> in_buf;
158
1518
      in_buf = args[1]->ToObject(env->isolate());
159
759
      in_off = args[2]->Uint32Value();
160
759
      in_len = args[3]->Uint32Value();
161
162
1518
      CHECK(Buffer::IsWithinBounds(in_off, in_len, Buffer::Length(in_buf)));
163
759
      in = reinterpret_cast<Bytef *>(Buffer::Data(in_buf) + in_off);
164
    }
165
166
759
    CHECK(Buffer::HasInstance(args[4]));
167
1518
    Local<Object> out_buf = args[4]->ToObject(env->isolate());
168
759
    out_off = args[5]->Uint32Value();
169
759
    out_len = args[6]->Uint32Value();
170
1518
    CHECK(Buffer::IsWithinBounds(out_off, out_len, Buffer::Length(out_buf)));
171
759
    out = reinterpret_cast<Bytef *>(Buffer::Data(out_buf) + out_off);
172
173
    // build up the work request
174
759
    uv_work_t* work_req = &(ctx->work_req_);
175
176
759
    ctx->strm_.avail_in = in_len;
177
759
    ctx->strm_.next_in = in;
178
759
    ctx->strm_.avail_out = out_len;
179
759
    ctx->strm_.next_out = out;
180
759
    ctx->flush_ = flush;
181
182
    // set this so that later on, I can easily tell how much was written.
183
759
    ctx->chunk_size_ = out_len;
184
185
    if (!async) {
186
      // sync version
187
55
      ctx->env()->PrintSyncTrace();
188
55
      Process(work_req);
189
55
      if (CheckError(ctx))
190
49
        AfterSync(ctx, args);
191
      return;
192
    }
193
194
    // async version
195
704
    uv_queue_work(ctx->env()->event_loop(),
196
                  work_req,
197
                  ZCtx::Process,
198
                  ZCtx::After);
199
200
2816
    args.GetReturnValue().Set(ctx->object());
201
  }
202
203
204
49
  static void AfterSync(ZCtx* ctx, const FunctionCallbackInfo<Value>& args) {
205
49
    Environment* env = ctx->env();
206
    Local<Integer> avail_out = Integer::New(env->isolate(),
207
49
                                            ctx->strm_.avail_out);
208
    Local<Integer> avail_in = Integer::New(env->isolate(),
209
49
                                           ctx->strm_.avail_in);
210
211
49
    ctx->write_in_progress_ = false;
212
213
49
    Local<Array> result = Array::New(env->isolate(), 2);
214
49
    result->Set(0, avail_in);
215
49
    result->Set(1, avail_out);
216
98
    args.GetReturnValue().Set(result);
217
218
49
    ctx->Unref();
219
49
  }
220
221
222
  // thread pool!
223
  // This function may be called multiple times on the uv_work pool
224
  // for a single write() call, until all of the input bytes have
225
  // been consumed.
226
759
  static void Process(uv_work_t* work_req) {
227
759
    ZCtx *ctx = ContainerOf(&ZCtx::work_req_, work_req);
228
229
759
    const Bytef* next_expected_header_byte = nullptr;
230
231
    // If the avail_out is left at 0, then it means that it ran out
232
    // of room.  If there was avail_out left over, then it means
233
    // that all of the input was consumed.
234
759
    switch (ctx->mode_) {
235
      case DEFLATE:
236
      case GZIP:
237
      case DEFLATERAW:
238
488
        ctx->err_ = deflate(&ctx->strm_, ctx->flush_);
239
488
        break;
240
      case UNZIP:
241
25
        if (ctx->strm_.avail_in > 0) {
242
25
          next_expected_header_byte = ctx->strm_.next_in;
243
        }
244
245
25
        switch (ctx->gzip_id_bytes_read_) {
246
          case 0:
247
24
            if (next_expected_header_byte == nullptr) {
248
              break;
249
            }
250
251
24
            if (*next_expected_header_byte == GZIP_HEADER_ID1) {
252
18
              ctx->gzip_id_bytes_read_ = 1;
253
18
              next_expected_header_byte++;
254
255
18
              if (ctx->strm_.avail_in == 1) {
256
                // The only available byte was already read.
257
                break;
258
              }
259
            } else {
260
6
              ctx->mode_ = INFLATE;
261
6
              break;
262
            }
263
264
            // fallthrough
265
          case 1:
266
18
            if (next_expected_header_byte == nullptr) {
267
              break;
268
            }
269
270
18
            if (*next_expected_header_byte == GZIP_HEADER_ID2) {
271
18
              ctx->gzip_id_bytes_read_ = 2;
272
18
              ctx->mode_ = GUNZIP;
273
            } else {
274
              // There is no actual difference between INFLATE and INFLATERAW
275
              // (after initialization).
276
              ctx->mode_ = INFLATE;
277
            }
278
279
            break;
280
          default:
281
            CHECK(0 && "invalid number of gzip magic number bytes read");
282
        }
283
284
        // fallthrough
285
      case INFLATE:
286
      case GUNZIP:
287
      case INFLATERAW:
288
271
        ctx->err_ = inflate(&ctx->strm_, ctx->flush_);
289
290
        // If data was encoded with dictionary
291
271
        if (ctx->err_ == Z_NEED_DICT && ctx->dictionary_ != nullptr) {
292
          // Load it
293
3
          ctx->err_ = inflateSetDictionary(&ctx->strm_,
294
                                           ctx->dictionary_,
295
6
                                           ctx->dictionary_len_);
296
3
          if (ctx->err_ == Z_OK) {
297
            // And try to decode again
298
2
            ctx->err_ = inflate(&ctx->strm_, ctx->flush_);
299
1
          } else if (ctx->err_ == Z_DATA_ERROR) {
300
            // Both inflateSetDictionary() and inflate() return Z_DATA_ERROR.
301
            // Make it possible for After() to tell a bad dictionary from bad
302
            // input.
303
1
            ctx->err_ = Z_NEED_DICT;
304
          }
305
        }
306
307
372
        while (ctx->strm_.avail_in > 0 &&
308
102
               ctx->mode_ == GUNZIP &&
309
354
               ctx->err_ == Z_STREAM_END &&
310
22
               ctx->strm_.next_in[0] != 0x00) {
311
          // Bytes remain in input buffer. Perhaps this is another compressed
312
          // member in the same archive, or just trailing garbage.
313
          // Trailing zero bytes are okay, though, since they are frequently
314
          // used for padding.
315
316
20
          Reset(ctx);
317
20
          ctx->err_ = inflate(&ctx->strm_, ctx->flush_);
318
        }
319
        break;
320
      default:
321
        CHECK(0 && "wtf?");
322
    }
323
324
    // pass any errors back to the main thread to deal with.
325
326
    // now After will emit the output, and
327
    // either schedule another call to Process,
328
    // or shift the queue and call Process.
329
759
  }
330
331
332
759
  static bool CheckError(ZCtx* ctx) {
333
    // Acceptable error states depend on the type of zlib stream.
334
759
    switch (ctx->err_) {
335
    case Z_OK:
336
    case Z_BUF_ERROR:
337
555
      if (ctx->strm_.avail_out != 0 && ctx->flush_ == Z_FINISH) {
338
12
        ZCtx::Error(ctx, "unexpected end of file");
339
12
        return false;
340
      }
341
    case Z_STREAM_END:
342
      // normal statuses, not fatal
343
      break;
344
    case Z_NEED_DICT:
345
2
      if (ctx->dictionary_ == nullptr)
346
1
        ZCtx::Error(ctx, "Missing dictionary");
347
      else
348
1
        ZCtx::Error(ctx, "Bad dictionary");
349
      return false;
350
    default:
351
      // something else.
352
9
      ZCtx::Error(ctx, "Zlib error");
353
9
      return false;
354
    }
355
356
    return true;
357
  }
358
359
360
  // v8 land!
361
704
  static void After(uv_work_t* work_req, int status) {
362
704
    CHECK_EQ(status, 0);
363
364
704
    ZCtx* ctx = ContainerOf(&ZCtx::work_req_, work_req);
365
704
    Environment* env = ctx->env();
366
367
1391
    HandleScope handle_scope(env->isolate());
368
2095
    Context::Scope context_scope(env->context());
369
370
704
    if (!CheckError(ctx))
371
17
      return;
372
373
    Local<Integer> avail_out = Integer::New(env->isolate(),
374
687
                                            ctx->strm_.avail_out);
375
    Local<Integer> avail_in = Integer::New(env->isolate(),
376
687
                                           ctx->strm_.avail_in);
377
378
687
    ctx->write_in_progress_ = false;
379
380
    // call the write() cb
381
2061
    Local<Value> args[2] = { avail_in, avail_out };
382
1374
    ctx->MakeCallback(env->callback_string(), arraysize(args), args);
383
384
687
    ctx->Unref();
385
687
    if (ctx->pending_close_)
386
1
      ctx->Close();
387
  }
388
389
23
  static void Error(ZCtx* ctx, const char* message) {
390
23
    Environment* env = ctx->env();
391
392
    // If you hit this assertion, you forgot to enter the v8::Context first.
393
69
    CHECK_EQ(env->context(), env->isolate()->GetCurrentContext());
394
395
23
    if (ctx->strm_.msg != nullptr) {
396
9
      message = ctx->strm_.msg;
397
    }
398
399
46
    HandleScope scope(env->isolate());
400
    Local<Value> args[2] = {
401
      OneByteString(env->isolate(), message),
402
23
      Number::New(env->isolate(), ctx->err_)
403
92
    };
404
46
    ctx->MakeCallback(env->onerror_string(), arraysize(args), args);
405
406
    // no hope of rescue.
407
23
    if (ctx->write_in_progress_)
408
23
      ctx->Unref();
409
23
    ctx->write_in_progress_ = false;
410
23
    if (ctx->pending_close_)
411
23
      ctx->Close();
412
23
  }
413
414
165
  static void New(const FunctionCallbackInfo<Value>& args) {
415
165
    Environment* env = Environment::GetCurrent(args);
416
417
495
    if (args.Length() < 1 || !args[0]->IsInt32()) {
418
      return env->ThrowTypeError("Bad argument");
419
    }
420
165
    node_zlib_mode mode = static_cast<node_zlib_mode>(args[0]->Int32Value());
421
422
165
    if (mode < DEFLATE || mode > UNZIP) {
423
      return env->ThrowTypeError("Bad argument");
424
    }
425
426
165
    new ZCtx(env, args.This(), mode);
427
  }
428
429
  // just pull the ints out of the args and call the other Init
430
165
  static void Init(const FunctionCallbackInfo<Value>& args) {
431
165
    CHECK((args.Length() == 4 || args.Length() == 5) &&
432
           "init(windowBits, level, memLevel, strategy, [dictionary])");
433
434
    ZCtx* ctx;
435
165
    ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
436
437
165
    int windowBits = args[0]->Uint32Value();
438
165
    CHECK((windowBits >= 8 && windowBits <= 15) && "invalid windowBits");
439
440
165
    int level = args[1]->Int32Value();
441
165
    CHECK((level >= -1 && level <= 9) && "invalid compression level");
442
443
165
    int memLevel = args[2]->Uint32Value();
444
165
    CHECK((memLevel >= 1 && memLevel <= 9) && "invalid memlevel");
445
446
165
    int strategy = args[3]->Uint32Value();
447
165
    CHECK((strategy == Z_FILTERED ||
448
            strategy == Z_HUFFMAN_ONLY ||
449
            strategy == Z_RLE ||
450
            strategy == Z_FIXED ||
451
            strategy == Z_DEFAULT_STRATEGY) && "invalid strategy");
452
453
165
    char* dictionary = nullptr;
454
165
    size_t dictionary_len = 0;
455
330
    if (args.Length() >= 5 && Buffer::HasInstance(args[4])) {
456
10
      Local<Object> dictionary_ = args[4]->ToObject(args.GetIsolate());
457
458
5
      dictionary_len = Buffer::Length(dictionary_);
459
5
      dictionary = new char[dictionary_len];
460
461
10
      memcpy(dictionary, Buffer::Data(dictionary_), dictionary_len);
462
    }
463
464
    Init(ctx, level, windowBits, memLevel, strategy,
465
165
         dictionary, dictionary_len);
466
165
    SetDictionary(ctx);
467
  }
468
469
1
  static void Params(const FunctionCallbackInfo<Value>& args) {
470
1
    CHECK(args.Length() == 2 && "params(level, strategy)");
471
    ZCtx* ctx;
472
1
    ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
473
2
    Params(ctx, args[0]->Int32Value(), args[1]->Int32Value());
474
  }
475
476
1
  static void Reset(const FunctionCallbackInfo<Value> &args) {
477
    ZCtx* ctx;
478
1
    ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
479
1
    Reset(ctx);
480
1
    SetDictionary(ctx);
481
  }
482
483
165
  static void Init(ZCtx *ctx, int level, int windowBits, int memLevel,
484
                   int strategy, char* dictionary, size_t dictionary_len) {
485
165
    ctx->level_ = level;
486
165
    ctx->windowBits_ = windowBits;
487
165
    ctx->memLevel_ = memLevel;
488
165
    ctx->strategy_ = strategy;
489
490
165
    ctx->strm_.zalloc = Z_NULL;
491
165
    ctx->strm_.zfree = Z_NULL;
492
165
    ctx->strm_.opaque = Z_NULL;
493
494
165
    ctx->flush_ = Z_NO_FLUSH;
495
496
165
    ctx->err_ = Z_OK;
497
498
165
    if (ctx->mode_ == GZIP || ctx->mode_ == GUNZIP) {
499
81
      ctx->windowBits_ += 16;
500
    }
501
502
165
    if (ctx->mode_ == UNZIP) {
503
24
      ctx->windowBits_ += 32;
504
    }
505
506
165
    if (ctx->mode_ == DEFLATERAW || ctx->mode_ == INFLATERAW) {
507
22
      ctx->windowBits_ *= -1;
508
    }
509
510
    switch (ctx->mode_) {
511
      case DEFLATE:
512
      case GZIP:
513
      case DEFLATERAW:
514
65
        ctx->err_ = deflateInit2(&ctx->strm_,
515
                                 ctx->level_,
516
                                 Z_DEFLATED,
517
                                 ctx->windowBits_,
518
                                 ctx->memLevel_,
519
65
                                 ctx->strategy_);
520
        ctx->env()->isolate()
521
65
            ->AdjustAmountOfExternalAllocatedMemory(kDeflateContextSize);
522
        break;
523
      case INFLATE:
524
      case GUNZIP:
525
      case INFLATERAW:
526
      case UNZIP:
527
100
        ctx->err_ = inflateInit2(&ctx->strm_, ctx->windowBits_);
528
        ctx->env()->isolate()
529
100
            ->AdjustAmountOfExternalAllocatedMemory(kInflateContextSize);
530
        break;
531
      default:
532
        CHECK(0 && "wtf?");
533
    }
534
535
165
    if (ctx->err_ != Z_OK) {
536
      ZCtx::Error(ctx, "Init error");
537
    }
538
539
540
165
    ctx->dictionary_ = reinterpret_cast<Bytef *>(dictionary);
541
165
    ctx->dictionary_len_ = dictionary_len;
542
543
165
    ctx->write_in_progress_ = false;
544
165
    ctx->init_done_ = true;
545
165
  }
546
547
166
  static void SetDictionary(ZCtx* ctx) {
548
166
    if (ctx->dictionary_ == nullptr)
549
      return;
550
551
6
    ctx->err_ = Z_OK;
552
553
6
    switch (ctx->mode_) {
554
      case DEFLATE:
555
      case DEFLATERAW:
556
3
        ctx->err_ = deflateSetDictionary(&ctx->strm_,
557
                                         ctx->dictionary_,
558
6
                                         ctx->dictionary_len_);
559
3
        break;
560
      default:
561
        break;
562
    }
563
564
6
    if (ctx->err_ != Z_OK) {
565
      ZCtx::Error(ctx, "Failed to set dictionary");
566
    }
567
  }
568
569
1
  static void Params(ZCtx* ctx, int level, int strategy) {
570
1
    ctx->err_ = Z_OK;
571
572
1
    switch (ctx->mode_) {
573
      case DEFLATE:
574
      case DEFLATERAW:
575
1
        ctx->err_ = deflateParams(&ctx->strm_, level, strategy);
576
1
        break;
577
      default:
578
        break;
579
    }
580
581
1
    if (ctx->err_ != Z_OK && ctx->err_ != Z_BUF_ERROR) {
582
      ZCtx::Error(ctx, "Failed to set parameters");
583
    }
584
1
  }
585
586
21
  static void Reset(ZCtx* ctx) {
587
21
    ctx->err_ = Z_OK;
588
589
21
    switch (ctx->mode_) {
590
      case DEFLATE:
591
      case DEFLATERAW:
592
      case GZIP:
593
1
        ctx->err_ = deflateReset(&ctx->strm_);
594
1
        break;
595
      case INFLATE:
596
      case INFLATERAW:
597
      case GUNZIP:
598
20
        ctx->err_ = inflateReset(&ctx->strm_);
599
20
        break;
600
      default:
601
        break;
602
    }
603
604
21
    if (ctx->err_ != Z_OK) {
605
      ZCtx::Error(ctx, "Failed to reset stream");
606
    }
607
21
  }
608
609
  size_t self_size() const override { return sizeof(*this); }
610
611
 private:
612
  void Ref() {
613
759
    if (++refs_ == 1) {
614
202
      ClearWeak();
615
    }
616
  }
617
618
759
  void Unref() {
619
759
    CHECK_GT(refs_, 0);
620
759
    if (--refs_ == 0) {
621
202
      MakeWeak<ZCtx>(this);
622
    }
623
759
  }
624
625
  static const int kDeflateContextSize = 16384;  // approximate
626
  static const int kInflateContextSize = 10240;  // approximate
627
628
  int chunk_size_;
629
  Bytef* dictionary_;
630
  size_t dictionary_len_;
631
  int err_;
632
  int flush_;
633
  bool init_done_;
634
  int level_;
635
  int memLevel_;
636
  node_zlib_mode mode_;
637
  int strategy_;
638
  z_stream strm_;
639
  int windowBits_;
640
  uv_work_t work_req_;
641
  bool write_in_progress_;
642
  bool pending_close_;
643
  unsigned int refs_;
644
  unsigned int gzip_id_bytes_read_;
645
};
646
647
648
27
void InitZlib(Local<Object> target,
649
              Local<Value> unused,
650
              Local<Context> context,
651
              void* priv) {
652
27
  Environment* env = Environment::GetCurrent(context);
653
54
  Local<FunctionTemplate> z = env->NewFunctionTemplate(ZCtx::New);
654
655
54
  z->InstanceTemplate()->SetInternalFieldCount(1);
656
657
27
  env->SetProtoMethod(z, "write", ZCtx::Write<true>);
658
27
  env->SetProtoMethod(z, "writeSync", ZCtx::Write<false>);
659
27
  env->SetProtoMethod(z, "init", ZCtx::Init);
660
27
  env->SetProtoMethod(z, "close", ZCtx::Close);
661
27
  env->SetProtoMethod(z, "params", ZCtx::Params);
662
27
  env->SetProtoMethod(z, "reset", ZCtx::Reset);
663
664
27
  z->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "Zlib"));
665
81
  target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "Zlib"), z->GetFunction());
666
667
108
  target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "ZLIB_VERSION"),
668
27
              FIXED_ONE_BYTE_STRING(env->isolate(), ZLIB_VERSION));
669
27
}
670
671
}  // namespace node
672
673
1569
NODE_MODULE_CONTEXT_AWARE_BUILTIN(zlib, node::InitZlib)