GCC Code Coverage Report
Directory: ../src/ Exec Total Coverage
File: /home/node-core-coverage/node-core-coverage/workdir/node/out/../src/node_zlib.cc Lines: 269 279 96.4 %
Date: 2017-01-02 Branches: 156 230 67.8 %

Line Branch 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::Value;
31
32
enum node_zlib_mode {
33
  NONE,
34
  DEFLATE,
35
  INFLATE,
36
  GZIP,
37
  GUNZIP,
38
  DEFLATERAW,
39
  INFLATERAW,
40
  UNZIP
41
};
42
43
#define GZIP_HEADER_ID1 0x1f
44
#define GZIP_HEADER_ID2 0x8b
45
46
void InitZlib(v8::Local<v8::Object> target);
47
48
49
/**
50
 * Deflate/Inflate
51
 */
52
class ZCtx : public AsyncWrap {
53
 public:
54
193
  ZCtx(Environment* env, Local<Object> wrap, node_zlib_mode mode)
55
      : AsyncWrap(env, wrap, AsyncWrap::PROVIDER_ZLIB),
56
        dictionary_(nullptr),
57
        dictionary_len_(0),
58
        err_(0),
59
        flush_(0),
60
        init_done_(false),
61
        level_(0),
62
        memLevel_(0),
63
        mode_(mode),
64
        strategy_(0),
65
        windowBits_(0),
66
        write_in_progress_(false),
67
        pending_close_(false),
68
        refs_(0),
69
193
        gzip_id_bytes_read_(0) {
70
193
    MakeWeak<ZCtx>(this);
71
193
  }
72
73
74
465
  ~ZCtx() override {
75
155
    CHECK_EQ(false, write_in_progress_ && "write in progress");
76
155
    Close();
77
310
  }
78
79
344
  void Close() {
80
344
    if (write_in_progress_) {
81
25
      pending_close_ = true;
82
25
      return;
83
    }
84
85
319
    pending_close_ = false;
86
319
    CHECK(init_done_ && "close before init");
87
319
    CHECK_LE(mode_, UNZIP);
88
89

319
    if (mode_ == DEFLATE || mode_ == GZIP || mode_ == DEFLATERAW) {
90
60
      (void)deflateEnd(&strm_);
91
60
      int64_t change_in_bytes = -static_cast<int64_t>(kDeflateContextSize);
92
60
      env()->isolate()->AdjustAmountOfExternalAllocatedMemory(change_in_bytes);
93


259
    } else if (mode_ == INFLATE || mode_ == GUNZIP || mode_ == INFLATERAW ||
94
               mode_ == UNZIP) {
95
104
      (void)inflateEnd(&strm_);
96
104
      int64_t change_in_bytes = -static_cast<int64_t>(kInflateContextSize);
97
104
      env()->isolate()->AdjustAmountOfExternalAllocatedMemory(change_in_bytes);
98
    }
99
319
    mode_ = NONE;
100
101
319
    if (dictionary_ != nullptr) {
102
10
      delete[] dictionary_;
103
10
      dictionary_ = nullptr;
104
    }
105
  }
106
107
108
164
  static void Close(const FunctionCallbackInfo<Value>& args) {
109
    ZCtx* ctx;
110
164
    ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
111
164
    ctx->Close();
112
  }
113
114
115
  // write(flush, in, in_off, in_len, out, out_off, out_len)
116
  template <bool async>
117
772
  static void Write(const FunctionCallbackInfo<Value>& args) {
118

772
    CHECK_EQ(args.Length(), 7);
119
120
    ZCtx* ctx;
121

828
    ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
122

772
    CHECK(ctx->init_done_ && "write before init");
123

772
    CHECK(ctx->mode_ != NONE && "already finalized");
124
125

772
    CHECK_EQ(false, ctx->write_in_progress_ && "write already in progress");
126

772
    CHECK_EQ(false, ctx->pending_close_ && "close is pending");
127
772
    ctx->write_in_progress_ = true;
128
1544
    ctx->Ref();
129
130


2316
    CHECK_EQ(false, args[0]->IsUndefined() && "must provide flush value");
131
132
772
    unsigned int flush = args[0]->Uint32Value();
133
134

772
    if (flush != Z_NO_FLUSH &&
135
        flush != Z_PARTIAL_FLUSH &&
136
        flush != Z_SYNC_FLUSH &&
137
        flush != Z_FULL_FLUSH &&
138
        flush != Z_FINISH &&
139
        flush != Z_BLOCK) {
140
      CHECK(0 && "Invalid flush value");
141
    }
142
143
    Bytef *in;
144
    Bytef *out;
145
    size_t in_off, in_len, out_off, out_len;
146
772
    Environment* env = ctx->env();
147
148

1544
    if (args[1]->IsNull()) {
149
      // just a flush
150
      in = nullptr;
151
      in_len = 0;
152
      in_off = 0;
153
    } else {
154

772
      CHECK(Buffer::HasInstance(args[1]));
155
772
      Local<Object> in_buf;
156
1544
      in_buf = args[1]->ToObject(env->isolate());
157
772
      in_off = args[2]->Uint32Value();
158
772
      in_len = args[3]->Uint32Value();
159
160

1544
      CHECK(Buffer::IsWithinBounds(in_off, in_len, Buffer::Length(in_buf)));
161
772
      in = reinterpret_cast<Bytef *>(Buffer::Data(in_buf) + in_off);
162
    }
163
164

772
    CHECK(Buffer::HasInstance(args[4]));
165
1544
    Local<Object> out_buf = args[4]->ToObject(env->isolate());
166
772
    out_off = args[5]->Uint32Value();
167
772
    out_len = args[6]->Uint32Value();
168

1544
    CHECK(Buffer::IsWithinBounds(out_off, out_len, Buffer::Length(out_buf)));
169
772
    out = reinterpret_cast<Bytef *>(Buffer::Data(out_buf) + out_off);
170
171
    // build up the work request
172
772
    uv_work_t* work_req = &(ctx->work_req_);
173
174
772
    ctx->strm_.avail_in = in_len;
175
772
    ctx->strm_.next_in = in;
176
772
    ctx->strm_.avail_out = out_len;
177
772
    ctx->strm_.next_out = out;
178
772
    ctx->flush_ = flush;
179
180
    if (!async) {
181
      // sync version
182
56
      ctx->env()->PrintSyncTrace();
183
56
      Process(work_req);
184
56
      if (CheckError(ctx))
185
50
        AfterSync(ctx, args);
186
      return;
187
    }
188
189
    // async version
190
716
    uv_queue_work(ctx->env()->event_loop(),
191
                  work_req,
192
                  ZCtx::Process,
193
                  ZCtx::After);
194
195
2864
    args.GetReturnValue().Set(ctx->object());
196
  }
197
198
199
50
  static void AfterSync(ZCtx* ctx, const FunctionCallbackInfo<Value>& args) {
200
50
    Environment* env = ctx->env();
201
    Local<Integer> avail_out = Integer::New(env->isolate(),
202
50
                                            ctx->strm_.avail_out);
203
    Local<Integer> avail_in = Integer::New(env->isolate(),
204
50
                                           ctx->strm_.avail_in);
205
206
50
    ctx->write_in_progress_ = false;
207
208
50
    Local<Array> result = Array::New(env->isolate(), 2);
209
50
    result->Set(0, avail_in);
210
50
    result->Set(1, avail_out);
211
100
    args.GetReturnValue().Set(result);
212
213
50
    ctx->Unref();
214
50
  }
215
216
217
  // thread pool!
218
  // This function may be called multiple times on the uv_work pool
219
  // for a single write() call, until all of the input bytes have
220
  // been consumed.
221
772
  static void Process(uv_work_t* work_req) {
222
772
    ZCtx *ctx = ContainerOf(&ZCtx::work_req_, work_req);
223
224
772
    const Bytef* next_expected_header_byte = nullptr;
225
226
    // If the avail_out is left at 0, then it means that it ran out
227
    // of room.  If there was avail_out left over, then it means
228
    // that all of the input was consumed.
229


772
    switch (ctx->mode_) {
230
      case DEFLATE:
231
      case GZIP:
232
      case DEFLATERAW:
233
495
        ctx->err_ = deflate(&ctx->strm_, ctx->flush_);
234
495
        break;
235
      case UNZIP:
236
25
        if (ctx->strm_.avail_in > 0) {
237
25
          next_expected_header_byte = ctx->strm_.next_in;
238
        }
239
240
25
        switch (ctx->gzip_id_bytes_read_) {
241
          case 0:
242
24
            if (next_expected_header_byte == nullptr) {
243
              break;
244
            }
245
246
24
            if (*next_expected_header_byte == GZIP_HEADER_ID1) {
247
18
              ctx->gzip_id_bytes_read_ = 1;
248
18
              next_expected_header_byte++;
249
250
18
              if (ctx->strm_.avail_in == 1) {
251
                // The only available byte was already read.
252
                break;
253
              }
254
            } else {
255
6
              ctx->mode_ = INFLATE;
256
6
              break;
257
            }
258
259
            // fallthrough
260
          case 1:
261
18
            if (next_expected_header_byte == nullptr) {
262
              break;
263
            }
264
265
18
            if (*next_expected_header_byte == GZIP_HEADER_ID2) {
266
18
              ctx->gzip_id_bytes_read_ = 2;
267
18
              ctx->mode_ = GUNZIP;
268
            } else {
269
              // There is no actual difference between INFLATE and INFLATERAW
270
              // (after initialization).
271
              ctx->mode_ = INFLATE;
272
            }
273
274
            break;
275
          default:
276
            CHECK(0 && "invalid number of gzip magic number bytes read");
277
        }
278
279
        // fallthrough
280
      case INFLATE:
281
      case GUNZIP:
282
      case INFLATERAW:
283
277
        ctx->err_ = inflate(&ctx->strm_, ctx->flush_);
284
285
        // If data was encoded with dictionary (INFLATERAW will have it set in
286
        // SetDictionary, don't repeat that here)
287

277
        if (ctx->mode_ != INFLATERAW &&
288
4
            ctx->err_ == Z_NEED_DICT &&
289
4
            ctx->dictionary_ != nullptr) {
290
          // Load it
291
3
          ctx->err_ = inflateSetDictionary(&ctx->strm_,
292
                                           ctx->dictionary_,
293
6
                                           ctx->dictionary_len_);
294
3
          if (ctx->err_ == Z_OK) {
295
            // And try to decode again
296
2
            ctx->err_ = inflate(&ctx->strm_, ctx->flush_);
297
1
          } else if (ctx->err_ == Z_DATA_ERROR) {
298
            // Both inflateSetDictionary() and inflate() return Z_DATA_ERROR.
299
            // Make it possible for After() to tell a bad dictionary from bad
300
            // input.
301
1
            ctx->err_ = Z_NEED_DICT;
302
          }
303
        }
304
305
379
        while (ctx->strm_.avail_in > 0 &&
306
103
               ctx->mode_ == GUNZIP &&
307

360
               ctx->err_ == Z_STREAM_END &&
308
22
               ctx->strm_.next_in[0] != 0x00) {
309
          // Bytes remain in input buffer. Perhaps this is another compressed
310
          // member in the same archive, or just trailing garbage.
311
          // Trailing zero bytes are okay, though, since they are frequently
312
          // used for padding.
313
314
20
          Reset(ctx);
315
20
          ctx->err_ = inflate(&ctx->strm_, ctx->flush_);
316
        }
317
        break;
318
      default:
319
        CHECK(0 && "wtf?");
320
    }
321
322
    // pass any errors back to the main thread to deal with.
323
324
    // now After will emit the output, and
325
    // either schedule another call to Process,
326
    // or shift the queue and call Process.
327
772
  }
328
329
330
772
  static bool CheckError(ZCtx* ctx) {
331
    // Acceptable error states depend on the type of zlib stream.
332

772
    switch (ctx->err_) {
333
    case Z_OK:
334
    case Z_BUF_ERROR:
335

560
      if (ctx->strm_.avail_out != 0 && ctx->flush_ == Z_FINISH) {
336
12
        ZCtx::Error(ctx, "unexpected end of file");
337
12
        return false;
338
      }
339
    case Z_STREAM_END:
340
      // normal statuses, not fatal
341
      break;
342
    case Z_NEED_DICT:
343
2
      if (ctx->dictionary_ == nullptr)
344
1
        ZCtx::Error(ctx, "Missing dictionary");
345
      else
346
1
        ZCtx::Error(ctx, "Bad dictionary");
347
      return false;
348
    default:
349
      // something else.
350
10
      ZCtx::Error(ctx, "Zlib error");
351
10
      return false;
352
    }
353
354
    return true;
355
  }
356
357
358
  // v8 land!
359
716
  static void After(uv_work_t* work_req, int status) {
360
716
    CHECK_EQ(status, 0);
361
362
716
    ZCtx* ctx = ContainerOf(&ZCtx::work_req_, work_req);
363
716
    Environment* env = ctx->env();
364
365
1414
    HandleScope handle_scope(env->isolate());
366
2130
    Context::Scope context_scope(env->context());
367
368
716
    if (!CheckError(ctx))
369
18
      return;
370
371
    Local<Integer> avail_out = Integer::New(env->isolate(),
372
698
                                            ctx->strm_.avail_out);
373
    Local<Integer> avail_in = Integer::New(env->isolate(),
374
698
                                           ctx->strm_.avail_in);
375
376
698
    ctx->write_in_progress_ = false;
377
378
    // call the write() cb
379
2094
    Local<Value> args[2] = { avail_in, avail_out };
380
1396
    ctx->MakeCallback(env->callback_string(), arraysize(args), args);
381
382
698
    ctx->Unref();
383
698
    if (ctx->pending_close_)
384
1
      ctx->Close();
385
  }
386
387
24
  static void Error(ZCtx* ctx, const char* message) {
388
24
    Environment* env = ctx->env();
389
390
    // If you hit this assertion, you forgot to enter the v8::Context first.
391
72
    CHECK_EQ(env->context(), env->isolate()->GetCurrentContext());
392
393
24
    if (ctx->strm_.msg != nullptr) {
394
10
      message = ctx->strm_.msg;
395
    }
396
397
48
    HandleScope scope(env->isolate());
398
    Local<Value> args[2] = {
399
      OneByteString(env->isolate(), message),
400
24
      Number::New(env->isolate(), ctx->err_)
401
96
    };
402
48
    ctx->MakeCallback(env->onerror_string(), arraysize(args), args);
403
404
    // no hope of rescue.
405
24
    if (ctx->write_in_progress_)
406
24
      ctx->Unref();
407
24
    ctx->write_in_progress_ = false;
408
24
    if (ctx->pending_close_)
409
24
      ctx->Close();
410
24
  }
411
412
193
  static void New(const FunctionCallbackInfo<Value>& args) {
413
193
    Environment* env = Environment::GetCurrent(args);
414
415

579
    if (args.Length() < 1 || !args[0]->IsInt32()) {
416
      return env->ThrowTypeError("Bad argument");
417
    }
418
193
    node_zlib_mode mode = static_cast<node_zlib_mode>(args[0]->Int32Value());
419
420
193
    if (mode < DEFLATE || mode > UNZIP) {
421
      return env->ThrowTypeError("Bad argument");
422
    }
423
424
193
    new ZCtx(env, args.This(), mode);
425
  }
426
427
  // just pull the ints out of the args and call the other Init
428
193
  static void Init(const FunctionCallbackInfo<Value>& args) {
429


193
    CHECK((args.Length() == 4 || args.Length() == 5) &&
430
           "init(windowBits, level, memLevel, strategy, [dictionary])");
431
432
    ZCtx* ctx;
433
193
    ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
434
435
193
    int windowBits = args[0]->Uint32Value();
436
193
    CHECK((windowBits >= 8 && windowBits <= 15) && "invalid windowBits");
437
438
193
    int level = args[1]->Int32Value();
439
193
    CHECK((level >= -1 && level <= 9) && "invalid compression level");
440
441
193
    int memLevel = args[2]->Uint32Value();
442
193
    CHECK((memLevel >= 1 && memLevel <= 9) && "invalid memlevel");
443
444
193
    int strategy = args[3]->Uint32Value();
445
193
    CHECK((strategy == Z_FILTERED ||
446
            strategy == Z_HUFFMAN_ONLY ||
447
            strategy == Z_RLE ||
448
            strategy == Z_FIXED ||
449
            strategy == Z_DEFAULT_STRATEGY) && "invalid strategy");
450
451
193
    char* dictionary = nullptr;
452
193
    size_t dictionary_len = 0;
453

386
    if (args.Length() >= 5 && Buffer::HasInstance(args[4])) {
454
20
      Local<Object> dictionary_ = args[4]->ToObject(args.GetIsolate());
455
456
10
      dictionary_len = Buffer::Length(dictionary_);
457
10
      dictionary = new char[dictionary_len];
458
459
20
      memcpy(dictionary, Buffer::Data(dictionary_), dictionary_len);
460
    }
461
462
    Init(ctx, level, windowBits, memLevel, strategy,
463
193
         dictionary, dictionary_len);
464
193
    SetDictionary(ctx);
465
  }
466
467
1
  static void Params(const FunctionCallbackInfo<Value>& args) {
468
1
    CHECK(args.Length() == 2 && "params(level, strategy)");
469
    ZCtx* ctx;
470
1
    ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
471
2
    Params(ctx, args[0]->Int32Value(), args[1]->Int32Value());
472
  }
473
474
2
  static void Reset(const FunctionCallbackInfo<Value> &args) {
475
    ZCtx* ctx;
476
2
    ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
477
2
    Reset(ctx);
478
2
    SetDictionary(ctx);
479
  }
480
481
193
  static void Init(ZCtx *ctx, int level, int windowBits, int memLevel,
482
                   int strategy, char* dictionary, size_t dictionary_len) {
483
193
    ctx->level_ = level;
484
193
    ctx->windowBits_ = windowBits;
485
193
    ctx->memLevel_ = memLevel;
486
193
    ctx->strategy_ = strategy;
487
488
193
    ctx->strm_.zalloc = Z_NULL;
489
193
    ctx->strm_.zfree = Z_NULL;
490
193
    ctx->strm_.opaque = Z_NULL;
491
492
193
    ctx->flush_ = Z_NO_FLUSH;
493
494
193
    ctx->err_ = Z_OK;
495
496
193
    if (ctx->mode_ == GZIP || ctx->mode_ == GUNZIP) {
497
81
      ctx->windowBits_ += 16;
498
    }
499
500
193
    if (ctx->mode_ == UNZIP) {
501
24
      ctx->windowBits_ += 32;
502
    }
503
504
193
    if (ctx->mode_ == DEFLATERAW || ctx->mode_ == INFLATERAW) {
505

32
      ctx->windowBits_ *= -1;
506
    }
507
508
    switch (ctx->mode_) {
509
      case DEFLATE:
510
      case GZIP:
511
      case DEFLATERAW:
512
88
        ctx->err_ = deflateInit2(&ctx->strm_,
513
                                 ctx->level_,
514
                                 Z_DEFLATED,
515
                                 ctx->windowBits_,
516
                                 ctx->memLevel_,
517
88
                                 ctx->strategy_);
518
        ctx->env()->isolate()
519
88
            ->AdjustAmountOfExternalAllocatedMemory(kDeflateContextSize);
520
        break;
521
      case INFLATE:
522
      case GUNZIP:
523
      case INFLATERAW:
524
      case UNZIP:
525
105
        ctx->err_ = inflateInit2(&ctx->strm_, ctx->windowBits_);
526
        ctx->env()->isolate()
527
105
            ->AdjustAmountOfExternalAllocatedMemory(kInflateContextSize);
528
        break;
529
      default:
530
        CHECK(0 && "wtf?");
531
    }
532
533
193
    if (ctx->err_ != Z_OK) {
534
      ZCtx::Error(ctx, "Init error");
535
    }
536
537
538
193
    ctx->dictionary_ = reinterpret_cast<Bytef *>(dictionary);
539
193
    ctx->dictionary_len_ = dictionary_len;
540
541
193
    ctx->write_in_progress_ = false;
542
193
    ctx->init_done_ = true;
543
193
  }
544
545
195
  static void SetDictionary(ZCtx* ctx) {
546
195
    if (ctx->dictionary_ == nullptr)
547
      return;
548
549
12
    ctx->err_ = Z_OK;
550
551
12
    switch (ctx->mode_) {
552
      case DEFLATE:
553
      case DEFLATERAW:
554
6
        ctx->err_ = deflateSetDictionary(&ctx->strm_,
555
                                         ctx->dictionary_,
556
12
                                         ctx->dictionary_len_);
557
6
        break;
558
      case INFLATERAW:
559
        // The other inflate cases will have the dictionary set when inflate()
560
        // returns Z_NEED_DICT in Process()
561
3
        ctx->err_ = inflateSetDictionary(&ctx->strm_,
562
                                         ctx->dictionary_,
563
6
                                         ctx->dictionary_len_);
564
3
        break;
565
      default:
566
        break;
567
    }
568
569
12
    if (ctx->err_ != Z_OK) {
570
      ZCtx::Error(ctx, "Failed to set dictionary");
571
    }
572
  }
573
574
1
  static void Params(ZCtx* ctx, int level, int strategy) {
575
1
    ctx->err_ = Z_OK;
576
577
1
    switch (ctx->mode_) {
578
      case DEFLATE:
579
      case DEFLATERAW:
580
1
        ctx->err_ = deflateParams(&ctx->strm_, level, strategy);
581
1
        break;
582
      default:
583
        break;
584
    }
585
586
1
    if (ctx->err_ != Z_OK && ctx->err_ != Z_BUF_ERROR) {
587
      ZCtx::Error(ctx, "Failed to set parameters");
588
    }
589
1
  }
590
591
22
  static void Reset(ZCtx* ctx) {
592
22
    ctx->err_ = Z_OK;
593
594

22
    switch (ctx->mode_) {
595
      case DEFLATE:
596
      case DEFLATERAW:
597
      case GZIP:
598
2
        ctx->err_ = deflateReset(&ctx->strm_);
599
2
        break;
600
      case INFLATE:
601
      case INFLATERAW:
602
      case GUNZIP:
603
20
        ctx->err_ = inflateReset(&ctx->strm_);
604
20
        break;
605
      default:
606
        break;
607
    }
608
609
22
    if (ctx->err_ != Z_OK) {
610
      ZCtx::Error(ctx, "Failed to reset stream");
611
    }
612
22
  }
613
614
  size_t self_size() const override { return sizeof(*this); }
615
616
 private:
617
  void Ref() {
618

772
    if (++refs_ == 1) {
619
208
      ClearWeak();
620
    }
621
  }
622
623
772
  void Unref() {
624
772
    CHECK_GT(refs_, 0);
625
772
    if (--refs_ == 0) {
626
208
      MakeWeak<ZCtx>(this);
627
    }
628
772
  }
629
630
  static const int kDeflateContextSize = 16384;  // approximate
631
  static const int kInflateContextSize = 10240;  // approximate
632
633
  Bytef* dictionary_;
634
  size_t dictionary_len_;
635
  int err_;
636
  int flush_;
637
  bool init_done_;
638
  int level_;
639
  int memLevel_;
640
  node_zlib_mode mode_;
641
  int strategy_;
642
  z_stream strm_;
643
  int windowBits_;
644
  uv_work_t work_req_;
645
  bool write_in_progress_;
646
  bool pending_close_;
647
  unsigned int refs_;
648
  unsigned int gzip_id_bytes_read_;
649
};
650
651
652
31
void InitZlib(Local<Object> target,
653
              Local<Value> unused,
654
              Local<Context> context,
655
              void* priv) {
656
31
  Environment* env = Environment::GetCurrent(context);
657
62
  Local<FunctionTemplate> z = env->NewFunctionTemplate(ZCtx::New);
658
659
62
  z->InstanceTemplate()->SetInternalFieldCount(1);
660
661
31
  env->SetProtoMethod(z, "write", ZCtx::Write<true>);
662
31
  env->SetProtoMethod(z, "writeSync", ZCtx::Write<false>);
663
31
  env->SetProtoMethod(z, "init", ZCtx::Init);
664
31
  env->SetProtoMethod(z, "close", ZCtx::Close);
665
31
  env->SetProtoMethod(z, "params", ZCtx::Params);
666
31
  env->SetProtoMethod(z, "reset", ZCtx::Reset);
667
668
31
  z->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "Zlib"));
669
93
  target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "Zlib"), z->GetFunction());
670
671
124
  target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "ZLIB_VERSION"),
672
31
              FIXED_ONE_BYTE_STRING(env->isolate(), ZLIB_VERSION));
673
31
}
674
675
}  // namespace node
676
677
1757
NODE_MODULE_CONTEXT_AWARE_BUILTIN(zlib, node::InitZlib)