GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage/nodes/benchmark/out/../src/node_zlib.cc Lines: 285 306 93.1 %
Date: 2017-12-18 Branches: 188 278 67.6 %

Line Branch Exec Source
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
#include "node.h"
23
#include "node_buffer.h"
24
25
#include "async_wrap-inl.h"
26
#include "env-inl.h"
27
#include "util-inl.h"
28
29
#include "v8.h"
30
#include "zlib.h"
31
32
#include <errno.h>
33
#include <stdlib.h>
34
#include <string.h>
35
#include <sys/types.h>
36
37
namespace node {
38
39
using v8::Array;
40
using v8::ArrayBuffer;
41
using v8::Context;
42
using v8::Function;
43
using v8::FunctionCallbackInfo;
44
using v8::FunctionTemplate;
45
using v8::HandleScope;
46
using v8::Local;
47
using v8::Number;
48
using v8::Object;
49
using v8::Persistent;
50
using v8::String;
51
using v8::Uint32Array;
52
using v8::Value;
53
54
namespace {
55
56
enum node_zlib_mode {
57
  NONE,
58
  DEFLATE,
59
  INFLATE,
60
  GZIP,
61
  GUNZIP,
62
  DEFLATERAW,
63
  INFLATERAW,
64
  UNZIP
65
};
66
67
#define GZIP_HEADER_ID1 0x1f
68
#define GZIP_HEADER_ID2 0x8b
69
70
/**
71
 * Deflate/Inflate
72
 */
73
class ZCtx : public AsyncWrap {
74
 public:
75
933
  ZCtx(Environment* env, Local<Object> wrap, node_zlib_mode mode)
76
      : AsyncWrap(env, wrap, AsyncWrap::PROVIDER_ZLIB),
77
        dictionary_(nullptr),
78
        dictionary_len_(0),
79
        err_(0),
80
        flush_(0),
81
        init_done_(false),
82
        level_(0),
83
        memLevel_(0),
84
        mode_(mode),
85
        strategy_(0),
86
        windowBits_(0),
87
        write_in_progress_(false),
88
        pending_close_(false),
89
        refs_(0),
90
        gzip_id_bytes_read_(0),
91
933
        write_result_(nullptr) {
92
933
    MakeWeak<ZCtx>(this);
93
933
    Wrap(wrap, this);
94
933
  }
95
96
97
2205
  ~ZCtx() override {
98
735
    CHECK_EQ(false, write_in_progress_ && "write in progress");
99
735
    Close();
100
1470
  }
101
102
1649
  void Close() {
103
1649
    if (write_in_progress_) {
104
27
      pending_close_ = true;
105
1676
      return;
106
    }
107
108
1622
    pending_close_ = false;
109
1622
    CHECK(init_done_ && "close before init");
110
1622
    CHECK_LE(mode_, UNZIP);
111
112
1622
    int status = Z_OK;
113

1622
    if (mode_ == DEFLATE || mode_ == GZIP || mode_ == DEFLATERAW) {
114
391
      status = deflateEnd(&strm_);
115
391
      int64_t change_in_bytes = -static_cast<int64_t>(kDeflateContextSize);
116
782
      env()->isolate()->AdjustAmountOfExternalAllocatedMemory(change_in_bytes);
117


1964
    } else if (mode_ == INFLATE || mode_ == GUNZIP || mode_ == INFLATERAW ||
118
733
               mode_ == UNZIP) {
119
498
      status = inflateEnd(&strm_);
120
498
      int64_t change_in_bytes = -static_cast<int64_t>(kInflateContextSize);
121
498
      env()->isolate()->AdjustAmountOfExternalAllocatedMemory(change_in_bytes);
122
    }
123

1622
    CHECK(status == Z_OK || status == Z_DATA_ERROR);
124
1622
    mode_ = NONE;
125
126
1622
    if (dictionary_ != nullptr) {
127
50
      delete[] dictionary_;
128
50
      dictionary_ = nullptr;
129
    }
130
  }
131
132
133
887
  static void Close(const FunctionCallbackInfo<Value>& args) {
134
    ZCtx* ctx;
135
1774
    ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
136
887
    ctx->Close();
137
  }
138
139
140
  // write(flush, in, in_off, in_len, out, out_off, out_len)
141
  template <bool async>
142
19332
  static void Write(const FunctionCallbackInfo<Value>& args) {
143

19332
    CHECK_EQ(args.Length(), 7);
144
145
    ZCtx* ctx;
146

21772
    ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
147

19332
    CHECK(ctx->init_done_ && "write before init");
148

19332
    CHECK(ctx->mode_ != NONE && "already finalized");
149
150

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

19332
    CHECK_EQ(false, ctx->pending_close_ && "close is pending");
152
19332
    ctx->write_in_progress_ = true;
153
19332
    ctx->Ref();
154
155



77328
    CHECK_EQ(false, args[0]->IsUndefined() && "must provide flush value");
156
157
38664
    unsigned int flush = args[0]->Uint32Value();
158
159






19332
    if (flush != Z_NO_FLUSH &&
160
        flush != Z_PARTIAL_FLUSH &&
161
        flush != Z_SYNC_FLUSH &&
162
        flush != Z_FULL_FLUSH &&
163
        flush != Z_FINISH &&
164
        flush != Z_BLOCK) {
165
      CHECK(0 && "Invalid flush value");
166
    }
167
168
    Bytef *in;
169
    Bytef *out;
170
    size_t in_off, in_len, out_off, out_len;
171
19332
    Environment* env = ctx->env();
172
173

57996
    if (args[1]->IsNull()) {
174
      // just a flush
175
      in = nullptr;
176
      in_len = 0;
177
      in_off = 0;
178
    } else {
179

19332
      CHECK(Buffer::HasInstance(args[1]));
180
      Local<Object> in_buf;
181
77328
      in_buf = args[1]->ToObject(env->context()).ToLocalChecked();
182
38664
      in_off = args[2]->Uint32Value();
183
38664
      in_len = args[3]->Uint32Value();
184
185

19332
      CHECK(Buffer::IsWithinBounds(in_off, in_len, Buffer::Length(in_buf)));
186
19332
      in = reinterpret_cast<Bytef *>(Buffer::Data(in_buf) + in_off);
187
    }
188
189

19332
    CHECK(Buffer::HasInstance(args[4]));
190
77328
    Local<Object> out_buf = args[4]->ToObject(env->context()).ToLocalChecked();
191
38664
    out_off = args[5]->Uint32Value();
192
38664
    out_len = args[6]->Uint32Value();
193

19332
    CHECK(Buffer::IsWithinBounds(out_off, out_len, Buffer::Length(out_buf)));
194
19332
    out = reinterpret_cast<Bytef *>(Buffer::Data(out_buf) + out_off);
195
196
    // build up the work request
197
19332
    uv_work_t* work_req = &(ctx->work_req_);
198
199
19332
    ctx->strm_.avail_in = in_len;
200
19332
    ctx->strm_.next_in = in;
201
19332
    ctx->strm_.avail_out = out_len;
202
19332
    ctx->strm_.next_out = out;
203
19332
    ctx->flush_ = flush;
204
205
    if (!async) {
206
      // sync version
207
2440
      env->PrintSyncTrace();
208
2440
      Process(work_req);
209
2440
      if (CheckError(ctx)) {
210
2434
        ctx->write_result_[0] = ctx->strm_.avail_out;
211
2434
        ctx->write_result_[1] = ctx->strm_.avail_in;
212
2434
        ctx->write_in_progress_ = false;
213
2434
        ctx->Unref();
214
      }
215
2440
      return;
216
    }
217
218
    // async version
219
16892
    uv_queue_work(env->event_loop(), work_req, ZCtx::Process, ZCtx::After);
220
  }
221
222
223
  // thread pool!
224
  // This function may be called multiple times on the uv_work pool
225
  // for a single write() call, until all of the input bytes have
226
  // been consumed.
227
19328
  static void Process(uv_work_t* work_req) {
228
19328
    ZCtx *ctx = ContainerOf(&ZCtx::work_req_, work_req);
229
230
19328
    const Bytef* next_expected_header_byte = nullptr;
231
232
    // If the avail_out is left at 0, then it means that it ran out
233
    // of room.  If there was avail_out left over, then it means
234
    // that all of the input was consumed.
235

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

20494
        if (ctx->mode_ != INFLATERAW &&
294
5704
            ctx->err_ == Z_NEED_DICT &&
295
14
            ctx->dictionary_ != nullptr) {
296
          // Load it
297
          ctx->err_ = inflateSetDictionary(&ctx->strm_,
298
                                           ctx->dictionary_,
299
13
                                           ctx->dictionary_len_);
300
13
          if (ctx->err_ == Z_OK) {
301
            // And try to decode again
302
12
            ctx->err_ = inflate(&ctx->strm_, ctx->flush_);
303
1
          } else if (ctx->err_ == Z_DATA_ERROR) {
304
            // Both inflateSetDictionary() and inflate() return Z_DATA_ERROR.
305
            // Make it possible for After() to tell a bad dictionary from bad
306
            // input.
307
1
            ctx->err_ = Z_NEED_DICT;
308
          }
309
        }
310
311

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

19332
    switch (ctx->err_) {
339
    case Z_OK:
340
    case Z_BUF_ERROR:
341

18132
      if (ctx->strm_.avail_out != 0 && ctx->flush_ == Z_FINISH) {
342
12
        ZCtx::Error(ctx, "unexpected end of file");
343
12
        return false;
344
      }
345
    case Z_STREAM_END:
346
      // normal statuses, not fatal
347
19308
      break;
348
    case Z_NEED_DICT:
349
2
      if (ctx->dictionary_ == nullptr)
350
1
        ZCtx::Error(ctx, "Missing dictionary");
351
      else
352
1
        ZCtx::Error(ctx, "Bad dictionary");
353
2
      return false;
354
    default:
355
      // something else.
356
10
      ZCtx::Error(ctx, "Zlib error");
357
10
      return false;
358
    }
359
360
19308
    return true;
361
  }
362
363
364
  // v8 land!
365
16892
  static void After(uv_work_t* work_req, int status) {
366
16892
    CHECK_EQ(status, 0);
367
368
16892
    ZCtx* ctx = ContainerOf(&ZCtx::work_req_, work_req);
369
16892
    Environment* env = ctx->env();
370
371
16892
    HandleScope handle_scope(env->isolate());
372
33766
    Context::Scope context_scope(env->context());
373
374
16892
    if (!CheckError(ctx))
375
16910
      return;
376
377
16874
    ctx->write_result_[0] = ctx->strm_.avail_out;
378
16874
    ctx->write_result_[1] = ctx->strm_.avail_in;
379
16874
    ctx->write_in_progress_ = false;
380
381
    // call the write() cb
382
    Local<Function> cb = PersistentToLocal(env->isolate(),
383
16874
                                           ctx->write_js_callback_);
384
16874
    ctx->MakeCallback(cb, 0, nullptr);
385
386
16874
    ctx->Unref();
387
16874
    if (ctx->pending_close_)
388
16877
      ctx->Close();
389
  }
390
391
24
  static void Error(ZCtx* ctx, const char* message) {
392
24
    Environment* env = ctx->env();
393
394
    // If you hit this assertion, you forgot to enter the v8::Context first.
395
48
    CHECK_EQ(env->context(), env->isolate()->GetCurrentContext());
396
397
24
    if (ctx->strm_.msg != nullptr) {
398
10
      message = ctx->strm_.msg;
399
    }
400
401
24
    HandleScope scope(env->isolate());
402
    Local<Value> args[2] = {
403
      OneByteString(env->isolate(), message),
404
      Number::New(env->isolate(), ctx->err_)
405
72
    };
406
24
    ctx->MakeCallback(env->onerror_string(), arraysize(args), args);
407
408
    // no hope of rescue.
409
24
    if (ctx->write_in_progress_)
410
24
      ctx->Unref();
411
24
    ctx->write_in_progress_ = false;
412
24
    if (ctx->pending_close_)
413
24
      ctx->Close();
414
24
  }
415
416
933
  static void New(const FunctionCallbackInfo<Value>& args) {
417
933
    Environment* env = Environment::GetCurrent(args);
418
1866
    CHECK(args[0]->IsInt32());
419
1866
    node_zlib_mode mode = static_cast<node_zlib_mode>(args[0]->Int32Value());
420
933
    new ZCtx(env, args.This(), mode);
421
933
  }
422
423
  // just pull the ints out of the args and call the other Init
424
933
  static void Init(const FunctionCallbackInfo<Value>& args) {
425
    // Refs: https://github.com/nodejs/node/issues/16649
426
    // Refs: https://github.com/nodejs/node/issues/14161
427
933
    if (args.Length() == 5) {
428
      fprintf(stderr,
429
          "WARNING: You are likely using a version of node-tar or npm that "
430
          "is incompatible with this version of Node.js.\nPlease use "
431
          "either the version of npm that is bundled with Node.js, or "
432
          "a version of npm (> 5.5.1 or < 5.4.0) or node-tar (> 4.0.1) "
433
          "that is compatible with Node.js 9 and above.\n");
434
    }
435

933
    CHECK(args.Length() == 7 &&
436
      "init(windowBits, level, memLevel, strategy, writeResult, writeCallback,"
437
      " dictionary)");
438
439
    ZCtx* ctx;
440
933
    ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
441
442
1866
    int windowBits = args[0]->Uint32Value();
443

933
    CHECK((windowBits >= Z_MIN_WINDOWBITS && windowBits <= Z_MAX_WINDOWBITS) &&
444
      "invalid windowBits");
445
446
1866
    int level = args[1]->Int32Value();
447

933
    CHECK((level >= Z_MIN_LEVEL && level <= Z_MAX_LEVEL) &&
448
      "invalid compression level");
449
450
1866
    int memLevel = args[2]->Uint32Value();
451

933
    CHECK((memLevel >= Z_MIN_MEMLEVEL && memLevel <= Z_MAX_MEMLEVEL) &&
452
      "invalid memlevel");
453
454
1866
    int strategy = args[3]->Uint32Value();
455



933
    CHECK((strategy == Z_FILTERED ||
456
           strategy == Z_HUFFMAN_ONLY ||
457
           strategy == Z_RLE ||
458
           strategy == Z_FIXED ||
459
           strategy == Z_DEFAULT_STRATEGY) && "invalid strategy");
460
461
1866
    CHECK(args[4]->IsUint32Array());
462
1866
    Local<Uint32Array> array = args[4].As<Uint32Array>();
463
933
    Local<ArrayBuffer> ab = array->Buffer();
464
933
    uint32_t* write_result = static_cast<uint32_t*>(ab->GetContents().Data());
465
466
1866
    Local<Function> write_js_callback = args[5].As<Function>();
467
468
933
    char* dictionary = nullptr;
469
933
    size_t dictionary_len = 0;
470
933
    if (Buffer::HasInstance(args[6])) {
471
52
      const char* dictionary_ = Buffer::Data(args[6]);
472
52
      dictionary_len = Buffer::Length(args[6]);
473
474
52
      dictionary = new char[dictionary_len];
475
52
      memcpy(dictionary, dictionary_, dictionary_len);
476
    }
477
478
    bool ret = Init(ctx, level, windowBits, memLevel, strategy, write_result,
479
933
                    write_js_callback, dictionary, dictionary_len);
480
933
    if (!ret) goto end;
481
482
933
    SetDictionary(ctx);
483
484
   end:
485
2799
    return args.GetReturnValue().Set(ret);
486
  }
487
488
1
  static void Params(const FunctionCallbackInfo<Value>& args) {
489

1
    CHECK(args.Length() == 2 && "params(level, strategy)");
490
    ZCtx* ctx;
491
2
    ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
492
4
    Params(ctx, args[0]->Int32Value(), args[1]->Int32Value());
493
  }
494
495
12
  static void Reset(const FunctionCallbackInfo<Value> &args) {
496
    ZCtx* ctx;
497
24
    ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
498
12
    Reset(ctx);
499
12
    SetDictionary(ctx);
500
  }
501
502
933
  static bool Init(ZCtx *ctx, int level, int windowBits, int memLevel,
503
                   int strategy, uint32_t* write_result,
504
                   Local<Function> write_js_callback, char* dictionary,
505
                   size_t dictionary_len) {
506
933
    ctx->level_ = level;
507
933
    ctx->windowBits_ = windowBits;
508
933
    ctx->memLevel_ = memLevel;
509
933
    ctx->strategy_ = strategy;
510
511
933
    ctx->strm_.zalloc = Z_NULL;
512
933
    ctx->strm_.zfree = Z_NULL;
513
933
    ctx->strm_.opaque = Z_NULL;
514
515
933
    ctx->flush_ = Z_NO_FLUSH;
516
517
933
    ctx->err_ = Z_OK;
518
519

933
    if (ctx->mode_ == GZIP || ctx->mode_ == GUNZIP) {
520
324
      ctx->windowBits_ += 16;
521
    }
522
523
933
    if (ctx->mode_ == UNZIP) {
524
163
      ctx->windowBits_ += 32;
525
    }
526
527

933
    if (ctx->mode_ == DEFLATERAW || ctx->mode_ == INFLATERAW) {
528
211
      ctx->windowBits_ *= -1;
529
    }
530
531
933
    switch (ctx->mode_) {
532
      case DEFLATE:
533
      case GZIP:
534
      case DEFLATERAW:
535
432
        ctx->err_ = deflateInit2(&ctx->strm_,
536
                                 ctx->level_,
537
                                 Z_DEFLATED,
538
                                 ctx->windowBits_,
539
                                 ctx->memLevel_,
540
432
                                 ctx->strategy_);
541
        ctx->env()->isolate()
542
432
            ->AdjustAmountOfExternalAllocatedMemory(kDeflateContextSize);
543
432
        break;
544
      case INFLATE:
545
      case GUNZIP:
546
      case INFLATERAW:
547
      case UNZIP:
548
501
        ctx->err_ = inflateInit2(&ctx->strm_, ctx->windowBits_);
549
        ctx->env()->isolate()
550
501
            ->AdjustAmountOfExternalAllocatedMemory(kInflateContextSize);
551
501
        break;
552
      default:
553
        UNREACHABLE();
554
    }
555
556
933
    ctx->dictionary_ = reinterpret_cast<Bytef *>(dictionary);
557
933
    ctx->dictionary_len_ = dictionary_len;
558
559
933
    ctx->write_in_progress_ = false;
560
933
    ctx->init_done_ = true;
561
562
933
    if (ctx->err_ != Z_OK) {
563
      if (dictionary != nullptr) {
564
        delete[] dictionary;
565
        ctx->dictionary_ = nullptr;
566
      }
567
      ctx->mode_ = NONE;
568
      return false;
569
    }
570
571
933
    ctx->write_result_ = write_result;
572
933
    ctx->write_js_callback_.Reset(ctx->env()->isolate(), write_js_callback);
573
933
    return true;
574
  }
575
576
945
  static void SetDictionary(ZCtx* ctx) {
577
945
    if (ctx->dictionary_ == nullptr)
578
1826
      return;
579
580
64
    ctx->err_ = Z_OK;
581
582
64
    switch (ctx->mode_) {
583
      case DEFLATE:
584
      case DEFLATERAW:
585
        ctx->err_ = deflateSetDictionary(&ctx->strm_,
586
                                         ctx->dictionary_,
587
38
                                         ctx->dictionary_len_);
588
38
        break;
589
      case INFLATERAW:
590
        // The other inflate cases will have the dictionary set when inflate()
591
        // returns Z_NEED_DICT in Process()
592
        ctx->err_ = inflateSetDictionary(&ctx->strm_,
593
                                         ctx->dictionary_,
594
13
                                         ctx->dictionary_len_);
595
13
        break;
596
      default:
597
13
        break;
598
    }
599
600
64
    if (ctx->err_ != Z_OK) {
601
      ZCtx::Error(ctx, "Failed to set dictionary");
602
    }
603
  }
604
605
1
  static void Params(ZCtx* ctx, int level, int strategy) {
606
1
    ctx->err_ = Z_OK;
607
608
1
    switch (ctx->mode_) {
609
      case DEFLATE:
610
      case DEFLATERAW:
611
1
        ctx->err_ = deflateParams(&ctx->strm_, level, strategy);
612
1
        break;
613
      default:
614
        break;
615
    }
616
617

1
    if (ctx->err_ != Z_OK && ctx->err_ != Z_BUF_ERROR) {
618
      ZCtx::Error(ctx, "Failed to set parameters");
619
    }
620
1
  }
621
622
32
  static void Reset(ZCtx* ctx) {
623
32
    ctx->err_ = Z_OK;
624
625
32
    switch (ctx->mode_) {
626
      case DEFLATE:
627
      case DEFLATERAW:
628
      case GZIP:
629
12
        ctx->err_ = deflateReset(&ctx->strm_);
630
12
        break;
631
      case INFLATE:
632
      case INFLATERAW:
633
      case GUNZIP:
634
20
        ctx->err_ = inflateReset(&ctx->strm_);
635
20
        break;
636
      default:
637
        break;
638
    }
639
640
32
    if (ctx->err_ != Z_OK) {
641
      ZCtx::Error(ctx, "Failed to reset stream");
642
    }
643
32
  }
644
645
  size_t self_size() const override { return sizeof(*this); }
646
647
 private:
648
19332
  void Ref() {
649
19332
    if (++refs_ == 1) {
650
5831
      ClearWeak();
651
    }
652
19332
  }
653
654
19332
  void Unref() {
655
19332
    CHECK_GT(refs_, 0);
656
19332
    if (--refs_ == 0) {
657
5831
      MakeWeak<ZCtx>(this);
658
    }
659
19332
  }
660
661
  static const int kDeflateContextSize = 16384;  // approximate
662
  static const int kInflateContextSize = 10240;  // approximate
663
664
  Bytef* dictionary_;
665
  size_t dictionary_len_;
666
  int err_;
667
  int flush_;
668
  bool init_done_;
669
  int level_;
670
  int memLevel_;
671
  node_zlib_mode mode_;
672
  int strategy_;
673
  z_stream strm_;
674
  int windowBits_;
675
  uv_work_t work_req_;
676
  bool write_in_progress_;
677
  bool pending_close_;
678
  unsigned int refs_;
679
  unsigned int gzip_id_bytes_read_;
680
  uint32_t* write_result_;
681
  Persistent<Function> write_js_callback_;
682
};
683
684
685
48
void InitZlib(Local<Object> target,
686
              Local<Value> unused,
687
              Local<Context> context,
688
              void* priv) {
689
48
  Environment* env = Environment::GetCurrent(context);
690
48
  Local<FunctionTemplate> z = env->NewFunctionTemplate(ZCtx::New);
691
692
96
  z->InstanceTemplate()->SetInternalFieldCount(1);
693
694
48
  AsyncWrap::AddWrapMethods(env, z);
695
48
  env->SetProtoMethod(z, "write", ZCtx::Write<true>);
696
48
  env->SetProtoMethod(z, "writeSync", ZCtx::Write<false>);
697
48
  env->SetProtoMethod(z, "init", ZCtx::Init);
698
48
  env->SetProtoMethod(z, "close", ZCtx::Close);
699
48
  env->SetProtoMethod(z, "params", ZCtx::Params);
700
48
  env->SetProtoMethod(z, "reset", ZCtx::Reset);
701
702
48
  Local<String> zlibString = FIXED_ONE_BYTE_STRING(env->isolate(), "Zlib");
703
48
  z->SetClassName(zlibString);
704
96
  target->Set(zlibString, z->GetFunction());
705
706
  target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "ZLIB_VERSION"),
707
144
              FIXED_ONE_BYTE_STRING(env->isolate(), ZLIB_VERSION));
708
48
}
709
710
}  // anonymous namespace
711
}  // namespace node
712
713
3391
NODE_BUILTIN_MODULE_CONTEXT_AWARE(zlib, node::InitZlib)