GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage-daily/nodes/benchmark/out/../src/node_zlib.cc Lines: 615 675 91.1 %
Date: 2020-08-17 22:13:26 Branches: 458 754 60.7 %

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 "memory_tracker-inl.h"
23
#include "node.h"
24
#include "node_buffer.h"
25
26
#include "async_wrap-inl.h"
27
#include "env-inl.h"
28
#include "threadpoolwork-inl.h"
29
#include "util-inl.h"
30
31
#include "v8.h"
32
33
#include "brotli/encode.h"
34
#include "brotli/decode.h"
35
#include "zlib.h"
36
37
#include <sys/types.h>
38
39
#include <cerrno>
40
#include <cstdlib>
41
#include <cstring>
42
#include <atomic>
43
44
namespace node {
45
46
using v8::ArrayBuffer;
47
using v8::Context;
48
using v8::Function;
49
using v8::FunctionCallbackInfo;
50
using v8::FunctionTemplate;
51
using v8::Global;
52
using v8::HandleScope;
53
using v8::Int32;
54
using v8::Integer;
55
using v8::Local;
56
using v8::Object;
57
using v8::String;
58
using v8::Uint32Array;
59
using v8::Value;
60
61
namespace {
62
63
// Fewer than 64 bytes per chunk is not recommended.
64
// Technically it could work with as few as 8, but even 64 bytes
65
// is low.  Usually a MB or more is best.
66
#define Z_MIN_CHUNK 64
67
#define Z_MAX_CHUNK std::numeric_limits<double>::infinity()
68
#define Z_DEFAULT_CHUNK (16 * 1024)
69
#define Z_MIN_MEMLEVEL 1
70
#define Z_MAX_MEMLEVEL 9
71
#define Z_DEFAULT_MEMLEVEL 8
72
#define Z_MIN_LEVEL -1
73
#define Z_MAX_LEVEL 9
74
#define Z_DEFAULT_LEVEL Z_DEFAULT_COMPRESSION
75
76
#define ZLIB_ERROR_CODES(V)      \
77
  V(Z_OK)                        \
78
  V(Z_STREAM_END)                \
79
  V(Z_NEED_DICT)                 \
80
  V(Z_ERRNO)                     \
81
  V(Z_STREAM_ERROR)              \
82
  V(Z_DATA_ERROR)                \
83
  V(Z_MEM_ERROR)                 \
84
  V(Z_BUF_ERROR)                 \
85
  V(Z_VERSION_ERROR)             \
86
87
22
inline const char* ZlibStrerror(int err) {
88
#define V(code) if (err == code) return #code;
89




22
  ZLIB_ERROR_CODES(V)
90
#undef V
91
  return "Z_UNKNOWN_ERROR";
92
}
93
94
enum node_zlib_mode {
95
  NONE,
96
  DEFLATE,
97
  INFLATE,
98
  GZIP,
99
  GUNZIP,
100
  DEFLATERAW,
101
  INFLATERAW,
102
  UNZIP,
103
  BROTLI_DECODE,
104
  BROTLI_ENCODE
105
};
106
107
#define GZIP_HEADER_ID1 0x1f
108
#define GZIP_HEADER_ID2 0x8b
109
110
struct CompressionError {
111
24
  CompressionError(const char* message, const char* code, int err)
112
24
      : message(message),
113
        code(code),
114
24
        err(err) {
115
24
    CHECK_NOT_NULL(message);
116
24
  }
117
118
10047
  CompressionError() = default;
119
120
  const char* message = nullptr;
121
  const char* code = nullptr;
122
  int err = 0;
123
124
9030
  inline bool IsError() const { return code != nullptr; }
125
};
126
127
999
class ZlibContext : public MemoryRetainer {
128
 public:
129
1173
  ZlibContext() = default;
130
131
  // Streaming-related, should be available for all compression libraries:
132
  void Close();
133
  void DoThreadPoolWork();
134
  void SetBuffers(char* in, uint32_t in_len, char* out, uint32_t out_len);
135
  void SetFlush(int flush);
136
  void GetAfterWriteOffsets(uint32_t* avail_in, uint32_t* avail_out) const;
137
  CompressionError GetErrorInfo() const;
138
1173
  inline void SetMode(node_zlib_mode mode) { mode_ = mode; }
139
  CompressionError ResetStream();
140
141
  // Zlib-specific:
142
  void Init(int level, int window_bits, int mem_level, int strategy,
143
            std::vector<unsigned char>&& dictionary);
144
  void SetAllocationFunctions(alloc_func alloc, free_func free, void* opaque);
145
  CompressionError SetParams(int level, int strategy);
146
147
  SET_MEMORY_INFO_NAME(ZlibContext)
148
  SET_SELF_SIZE(ZlibContext)
149
150
  void MemoryInfo(MemoryTracker* tracker) const override {
151
    tracker->TrackField("dictionary", dictionary_);
152
  }
153
154
  ZlibContext(const ZlibContext&) = delete;
155
  ZlibContext& operator=(const ZlibContext&) = delete;
156
157
 private:
158
  CompressionError ErrorForMessage(const char* message) const;
159
  CompressionError SetDictionary();
160
  bool InitZlib();
161
162
  Mutex mutex_;  // Protects zlib_init_done_.
163
  bool zlib_init_done_ = false;
164
  int err_ = 0;
165
  int flush_ = 0;
166
  int level_ = 0;
167
  int mem_level_ = 0;
168
  node_zlib_mode mode_ = NONE;
169
  int strategy_ = 0;
170
  int window_bits_ = 0;
171
  unsigned int gzip_id_bytes_read_ = 0;
172
  std::vector<unsigned char> dictionary_;
173
174
  z_stream strm_;
175
};
176
177
// Brotli has different data types for compression and decompression streams,
178
// so some of the specifics are implemented in more specific subclasses
179
205
class BrotliContext : public MemoryRetainer {
180
 public:
181
205
  BrotliContext() = default;
182
183
  void SetBuffers(char* in, uint32_t in_len, char* out, uint32_t out_len);
184
  void SetFlush(int flush);
185
  void GetAfterWriteOffsets(uint32_t* avail_in, uint32_t* avail_out) const;
186
205
  inline void SetMode(node_zlib_mode mode) { mode_ = mode; }
187
188
  BrotliContext(const BrotliContext&) = delete;
189
  BrotliContext& operator=(const BrotliContext&) = delete;
190
191
 protected:
192
  node_zlib_mode mode_ = NONE;
193
  uint8_t* next_in_ = nullptr;
194
  uint8_t* next_out_ = nullptr;
195
  size_t avail_in_ = 0;
196
  size_t avail_out_ = 0;
197
  BrotliEncoderOperation flush_ = BROTLI_OPERATION_PROCESS;
198
  // TODO(addaleax): These should not need to be stored here.
199
  // This is currently only done this way to make implementing ResetStream()
200
  // easier.
201
  brotli_alloc_func alloc_ = nullptr;
202
  brotli_free_func free_ = nullptr;
203
  void* alloc_opaque_ = nullptr;
204
};
205
206
206
class BrotliEncoderContext final : public BrotliContext {
207
 public:
208
  void Close();
209
  void DoThreadPoolWork();
210
  CompressionError Init(brotli_alloc_func alloc,
211
                        brotli_free_func free,
212
                        void* opaque);
213
  CompressionError ResetStream();
214
  CompressionError SetParams(int key, uint32_t value);
215
  CompressionError GetErrorInfo() const;
216
217
  SET_MEMORY_INFO_NAME(BrotliEncoderContext)
218
  SET_SELF_SIZE(BrotliEncoderContext)
219
  SET_NO_MEMORY_INFO()  // state_ is covered through allocation tracking.
220
221
 private:
222
  bool last_result_ = false;
223
  DeleteFnPtr<BrotliEncoderState, BrotliEncoderDestroyInstance> state_;
224
};
225
226
204
class BrotliDecoderContext final : public BrotliContext {
227
 public:
228
  void Close();
229
  void DoThreadPoolWork();
230
  CompressionError Init(brotli_alloc_func alloc,
231
                        brotli_free_func free,
232
                        void* opaque);
233
  CompressionError ResetStream();
234
  CompressionError SetParams(int key, uint32_t value);
235
  CompressionError GetErrorInfo() const;
236
237
  SET_MEMORY_INFO_NAME(BrotliDecoderContext)
238
  SET_SELF_SIZE(BrotliDecoderContext)
239
  SET_NO_MEMORY_INFO()  // state_ is covered through allocation tracking.
240
241
 private:
242
  BrotliDecoderResult last_result_ = BROTLI_DECODER_RESULT_SUCCESS;
243
  BrotliDecoderErrorCode error_ = BROTLI_DECODER_NO_ERROR;
244
  std::string error_string_;
245
  DeleteFnPtr<BrotliDecoderState, BrotliDecoderDestroyInstance> state_;
246
};
247
248
template <typename CompressionContext>
249
class CompressionStream : public AsyncWrap, public ThreadPoolWork {
250
 public:
251
1378
  CompressionStream(Environment* env, Local<Object> wrap)
252
      : AsyncWrap(env, wrap, AsyncWrap::PROVIDER_ZLIB),
253
        ThreadPoolWork(env),
254
2756
        write_result_(nullptr) {
255
1378
    MakeWeak();
256
1378
  }
257
258
1204
  ~CompressionStream() override {
259

1204
    CHECK_EQ(false, write_in_progress_ && "write in progress");
260
1204
    Close();
261

1204
    CHECK_EQ(zlib_memory_, 0);
262

1204
    CHECK_EQ(unreported_allocations_, 0);
263
3612
  }
264
265
2271
  void Close() {
266

2271
    if (write_in_progress_) {
267
30
      pending_close_ = true;
268
30
      return;
269
    }
270
271
2241
    pending_close_ = false;
272
2241
    closed_ = true;
273

2241
    CHECK(init_done_ && "close before init");
274
275
4482
    AllocScope alloc_scope(this);
276
2241
    ctx_.Close();
277
  }
278
279
280
1037
  static void Close(const FunctionCallbackInfo<Value>& args) {
281
    CompressionStream* ctx;
282

1037
    ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
283
1037
    ctx->Close();
284
  }
285
286
287
  // write(flush, in, in_off, in_len, out, out_off, out_len)
288
  template <bool async>
289
8795
  static void Write(const FunctionCallbackInfo<Value>& args) {
290
8795
    Environment* env = Environment::GetCurrent(args);
291
8795
    Local<Context> context = env->context();
292



8795
    CHECK_EQ(args.Length(), 7);
293
294
    uint32_t in_off, in_len, out_off, out_len, flush;
295
    char* in;
296
    char* out;
297
298






26385
    CHECK_EQ(false, args[0]->IsUndefined() && "must provide flush value");
299



26385
    if (!args[0]->Uint32Value(context).To(&flush)) return;
300
301






12941
    if (flush != Z_NO_FLUSH &&
302



7814
        flush != Z_PARTIAL_FLUSH &&
303



7116
        flush != Z_SYNC_FLUSH &&
304



4463
        flush != Z_FULL_FLUSH &&
305



1015
        flush != Z_FINISH &&
306
        flush != Z_BLOCK) {
307
      CHECK(0 && "Invalid flush value");
308
    }
309
310



26385
    if (args[1]->IsNull()) {
311
      // just a flush
312
      in = nullptr;
313
      in_len = 0;
314
      in_off = 0;
315
    } else {
316



8795
      CHECK(Buffer::HasInstance(args[1]));
317
17590
      Local<Object> in_buf = args[1].As<Object>();
318



26385
      if (!args[2]->Uint32Value(context).To(&in_off)) return;
319



26385
      if (!args[3]->Uint32Value(context).To(&in_len)) return;
320
321



8795
      CHECK(Buffer::IsWithinBounds(in_off, in_len, Buffer::Length(in_buf)));
322
8795
      in = Buffer::Data(in_buf) + in_off;
323
    }
324
325



8795
    CHECK(Buffer::HasInstance(args[4]));
326
17590
    Local<Object> out_buf = args[4].As<Object>();
327



26385
    if (!args[5]->Uint32Value(context).To(&out_off)) return;
328



26385
    if (!args[6]->Uint32Value(context).To(&out_len)) return;
329



8795
    CHECK(Buffer::IsWithinBounds(out_off, out_len, Buffer::Length(out_buf)));
330
8795
    out = Buffer::Data(out_buf) + out_off;
331
332
    CompressionStream* ctx;
333



8795
    ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
334
335
8795
    ctx->Write<async>(flush, in, in_len, out, out_len);
336
  }
337
338
  template <bool async>
339
8795
  void Write(uint32_t flush,
340
             char* in, uint32_t in_len,
341
             char* out, uint32_t out_len) {
342
16383
    AllocScope alloc_scope(this);
343
344



8795
    CHECK(init_done_ && "write before init");
345



8795
    CHECK(!closed_ && "already finalized");
346
347



8795
    CHECK_EQ(false, write_in_progress_);
348



8795
    CHECK_EQ(false, pending_close_);
349
8795
    write_in_progress_ = true;
350
8795
    Ref();
351
352
8795
    ctx_.SetBuffers(in, in_len, out, out_len);
353
8795
    ctx_.SetFlush(flush);
354
355
    if (!async) {
356
      // sync version
357
1207
      AsyncWrap::env()->PrintSyncTrace();
358
1207
      DoThreadPoolWork();
359

1207
      if (CheckError()) {
360
1201
        UpdateWriteResult();
361
1201
        write_in_progress_ = false;
362
      }
363
1207
      Unref();
364

1207
      return;
365
    }
366
367
    // async version
368

7588
    ScheduleWork();
369
  }
370
371
8772
  void UpdateWriteResult() {
372
8772
    ctx_.GetAfterWriteOffsets(&write_result_[1], &write_result_[0]);
373
8772
  }
374
375
  // thread pool!
376
  // This function may be called multiple times on the uv_work pool
377
  // for a single write() call, until all of the input bytes have
378
  // been consumed.
379
8795
  void DoThreadPoolWork() override {
380
8795
    ctx_.DoThreadPoolWork();
381
8795
  }
382
383
384
8795
  bool CheckError() {
385
8795
    const CompressionError err = ctx_.GetErrorInfo();
386

8795
    if (!err.IsError()) return true;
387
23
    EmitError(err);
388
23
    return false;
389
  }
390
391
392
  // v8 land!
393
7588
  void AfterThreadPoolWork(int status) override {
394
15159
    AllocScope alloc_scope(this);
395

22747
    auto on_scope_leave = OnScopeLeave([&]() { Unref(); });
396
397
7588
    write_in_progress_ = false;
398
399

7588
    if (status == UV_ECANCELED) {
400
      Close();
401
      return;
402
    }
403
404

7588
    CHECK_EQ(status, 0);
405
406
7588
    Environment* env = AsyncWrap::env();
407

15159
    HandleScope handle_scope(env->isolate());
408

15159
    Context::Scope context_scope(env->context());
409
410

7588
    if (!CheckError())
411
17
      return;
412
413
7571
    UpdateWriteResult();
414
415
    // call the write() cb
416
7571
    Local<Function> cb = PersistentToLocal::Default(env->isolate(),
417
7571
                                                    write_js_callback_);
418
7571
    MakeCallback(cb, 0, nullptr);
419
420

7571
    if (pending_close_)
421
23
      Close();
422
  }
423
424
  // TODO(addaleax): Switch to modern error system (node_errors.h).
425
24
  void EmitError(const CompressionError& err) {
426
24
    Environment* env = AsyncWrap::env();
427
    // If you hit this assertion, you forgot to enter the v8::Context first.
428

48
    CHECK_EQ(env->context(), env->isolate()->GetCurrentContext());
429
430
48
    HandleScope scope(env->isolate());
431
    Local<Value> args[3] = {
432
24
      OneByteString(env->isolate(), err.message),
433
24
      Integer::New(env->isolate(), err.err),
434
24
      OneByteString(env->isolate(), err.code)
435
168
    };
436
24
    MakeCallback(env->onerror_string(), arraysize(args), args);
437
438
    // no hope of rescue.
439
24
    write_in_progress_ = false;
440

24
    if (pending_close_)
441
7
      Close();
442
24
  }
443
444
14
  static void Reset(const FunctionCallbackInfo<Value> &args) {
445
    CompressionStream* wrap;
446

14
    ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
447
448
28
    AllocScope alloc_scope(wrap);
449
14
    const CompressionError err = wrap->context()->ResetStream();
450

14
    if (err.IsError())
451
      wrap->EmitError(err);
452
  }
453
454
  void MemoryInfo(MemoryTracker* tracker) const override {
455
    tracker->TrackField("compression context", ctx_);
456
    tracker->TrackFieldWithSize("zlib_memory",
457
                                zlib_memory_ + unreported_allocations_);
458
  }
459
460
 protected:
461
3959
  CompressionContext* context() { return &ctx_; }
462
463
1378
  void InitStream(uint32_t* write_result, Local<Function> write_js_callback) {
464
1378
    write_result_ = write_result;
465
1378
    write_js_callback_.Reset(AsyncWrap::env()->isolate(), write_js_callback);
466
1378
    init_done_ = true;
467
1378
  }
468
469
  // Allocation functions provided to zlib itself. We store the real size of
470
  // the allocated memory chunk just before the "payload" memory we return
471
  // to zlib.
472
  // Because we use zlib off the thread pool, we can not report memory directly
473
  // to V8; rather, we first store it as "unreported" memory in a separate
474
  // field and later report it back from the main thread.
475
2804
  static void* AllocForZlib(void* data, uInt items, uInt size) {
476
    size_t real_size =
477
2804
        MultiplyWithOverflowCheck(static_cast<size_t>(items),
478
2804
                                  static_cast<size_t>(size));
479
2804
    return AllocForBrotli(data, real_size);
480
  }
481
482
7949
  static void* AllocForBrotli(void* data, size_t size) {
483
7949
    size += sizeof(size_t);
484
7949
    CompressionStream* ctx = static_cast<CompressionStream*>(data);
485
7949
    char* memory = UncheckedMalloc(size);
486

7950
    if (UNLIKELY(memory == nullptr)) return nullptr;
487
7950
    *reinterpret_cast<size_t*>(memory) = size;
488
7950
    ctx->unreported_allocations_.fetch_add(size,
489
                                           std::memory_order_relaxed);
490
7950
    return memory + sizeof(size_t);
491
  }
492
493
10004
  static void FreeForZlib(void* data, void* pointer) {
494

10004
    if (UNLIKELY(pointer == nullptr)) return;
495
7712
    CompressionStream* ctx = static_cast<CompressionStream*>(data);
496
7712
    char* real_pointer = static_cast<char*>(pointer) - sizeof(size_t);
497
7712
    size_t real_size = *reinterpret_cast<size_t*>(real_pointer);
498
7712
    ctx->unreported_allocations_.fetch_sub(real_size,
499
                                           std::memory_order_relaxed);
500
7712
    free(real_pointer);
501
  }
502
503
  // This is called on the main thread after zlib may have allocated something
504
  // in order to report it back to V8.
505
20019
  void AdjustAmountOfExternalAllocatedMemory() {
506
    ssize_t report =
507
40038
        unreported_allocations_.exchange(0, std::memory_order_relaxed);
508

20019
    if (report == 0) return;
509



2532
    CHECK_IMPLIES(report < 0, zlib_memory_ >= static_cast<size_t>(-report));
510
2532
    zlib_memory_ += report;
511
2532
    AsyncWrap::env()->isolate()->AdjustAmountOfExternalAllocatedMemory(report);
512
  }
513
514
  struct AllocScope {
515
20019
    explicit AllocScope(CompressionStream* stream) : stream(stream) {}
516
20019
    ~AllocScope() { stream->AdjustAmountOfExternalAllocatedMemory(); }
517
    CompressionStream* stream;
518
  };
519
520
 private:
521
8795
  void Ref() {
522

8795
    if (++refs_ == 1) {
523
1855
      ClearWeak();
524
    }
525
8795
  }
526
527
8795
  void Unref() {
528

8795
    CHECK_GT(refs_, 0);
529

8795
    if (--refs_ == 0) {
530
1855
      MakeWeak();
531
    }
532
8795
  }
533
534
  bool init_done_ = false;
535
  bool write_in_progress_ = false;
536
  bool pending_close_ = false;
537
  bool closed_ = false;
538
  unsigned int refs_ = 0;
539
  uint32_t* write_result_ = nullptr;
540
  Global<Function> write_js_callback_;
541
  std::atomic<ssize_t> unreported_allocations_{0};
542
  size_t zlib_memory_ = 0;
543
544
  CompressionContext ctx_;
545
};
546
547
1998
class ZlibStream : public CompressionStream<ZlibContext> {
548
 public:
549
1173
  ZlibStream(Environment* env, Local<Object> wrap, node_zlib_mode mode)
550
1173
    : CompressionStream(env, wrap) {
551
1173
    context()->SetMode(mode);
552
1173
  }
553
554
1173
  static void New(const FunctionCallbackInfo<Value>& args) {
555
1173
    Environment* env = Environment::GetCurrent(args);
556
2346
    CHECK(args[0]->IsInt32());
557
    node_zlib_mode mode =
558
3519
        static_cast<node_zlib_mode>(args[0].As<Int32>()->Value());
559
1173
    new ZlibStream(env, args.This(), mode);
560
1173
  }
561
562
  // just pull the ints out of the args and call the other Init
563
1173
  static void Init(const FunctionCallbackInfo<Value>& args) {
564
    // Refs: https://github.com/nodejs/node/issues/16649
565
    // Refs: https://github.com/nodejs/node/issues/14161
566
1173
    if (args.Length() == 5) {
567
      fprintf(stderr,
568
          "WARNING: You are likely using a version of node-tar or npm that "
569
          "is incompatible with this version of Node.js.\nPlease use "
570
          "either the version of npm that is bundled with Node.js, or "
571
          "a version of npm (> 5.5.1 or < 5.4.0) or node-tar (> 4.0.1) "
572
          "that is compatible with Node.js 9 and above.\n");
573
    }
574

1173
    CHECK(args.Length() == 7 &&
575
      "init(windowBits, level, memLevel, strategy, writeResult, writeCallback,"
576
      " dictionary)");
577
578
    ZlibStream* wrap;
579
1173
    ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
580
581
1173
    Local<Context> context = args.GetIsolate()->GetCurrentContext();
582
583
    // windowBits is special. On the compression side, 0 is an invalid value.
584
    // But on the decompression side, a value of 0 for windowBits tells zlib
585
    // to use the window size in the zlib header of the compressed stream.
586
    uint32_t window_bits;
587
3519
    if (!args[0]->Uint32Value(context).To(&window_bits)) return;
588
589
    int32_t level;
590
3519
    if (!args[1]->Int32Value(context).To(&level)) return;
591
592
    uint32_t mem_level;
593
3519
    if (!args[2]->Uint32Value(context).To(&mem_level)) return;
594
595
    uint32_t strategy;
596
3519
    if (!args[3]->Uint32Value(context).To(&strategy)) return;
597
598
2346
    CHECK(args[4]->IsUint32Array());
599
2346
    Local<Uint32Array> array = args[4].As<Uint32Array>();
600
1173
    Local<ArrayBuffer> ab = array->Buffer();
601
    uint32_t* write_result = static_cast<uint32_t*>(
602
1173
        ab->GetBackingStore()->Data());
603
604
2346
    CHECK(args[5]->IsFunction());
605
2346
    Local<Function> write_js_callback = args[5].As<Function>();
606
607
2346
    std::vector<unsigned char> dictionary;
608
1173
    if (Buffer::HasInstance(args[6])) {
609
      unsigned char* data =
610
51
          reinterpret_cast<unsigned char*>(Buffer::Data(args[6]));
611
153
      dictionary = std::vector<unsigned char>(
612
          data,
613
102
          data + Buffer::Length(args[6]));
614
    }
615
616
1173
    wrap->InitStream(write_result, write_js_callback);
617
618
2346
    AllocScope alloc_scope(wrap);
619
1173
    wrap->context()->SetAllocationFunctions(
620
1173
        AllocForZlib, FreeForZlib, static_cast<CompressionStream*>(wrap));
621
2346
    wrap->context()->Init(level, window_bits, mem_level, strategy,
622
3519
                          std::move(dictionary));
623
  }
624
625
3
  static void Params(const FunctionCallbackInfo<Value>& args) {
626

3
    CHECK(args.Length() == 2 && "params(level, strategy)");
627
    ZlibStream* wrap;
628
3
    ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
629
3
    Local<Context> context = args.GetIsolate()->GetCurrentContext();
630
    int level;
631
9
    if (!args[0]->Int32Value(context).To(&level)) return;
632
    int strategy;
633
9
    if (!args[1]->Int32Value(context).To(&strategy)) return;
634
635
6
    AllocScope alloc_scope(wrap);
636
3
    const CompressionError err = wrap->context()->SetParams(level, strategy);
637
3
    if (err.IsError())
638
      wrap->EmitError(err);
639
  }
640
641
  SET_MEMORY_INFO_NAME(ZlibStream)
642
  SET_SELF_SIZE(ZlibStream)
643
};
644
645
template <typename CompressionContext>
646
410
class BrotliCompressionStream : public CompressionStream<CompressionContext> {
647
 public:
648
205
  BrotliCompressionStream(Environment* env,
649
                          Local<Object> wrap,
650
                          node_zlib_mode mode)
651
205
    : CompressionStream<CompressionContext>(env, wrap) {
652
205
    context()->SetMode(mode);
653
205
  }
654
655
423
  inline CompressionContext* context() {
656
423
    return this->CompressionStream<CompressionContext>::context();
657
  }
658
  typedef typename CompressionStream<CompressionContext>::AllocScope AllocScope;
659
660
205
  static void New(const FunctionCallbackInfo<Value>& args) {
661
205
    Environment* env = Environment::GetCurrent(args);
662

410
    CHECK(args[0]->IsInt32());
663
    node_zlib_mode mode =
664
615
        static_cast<node_zlib_mode>(args[0].As<Int32>()->Value());
665
205
    new BrotliCompressionStream(env, args.This(), mode);
666
205
  }
667
668
205
  static void Init(const FunctionCallbackInfo<Value>& args) {
669
    BrotliCompressionStream* wrap;
670

206
    ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
671


205
    CHECK(args.Length() == 3 && "init(params, writeResult, writeCallback)");
672
673

410
    CHECK(args[1]->IsUint32Array());
674
205
    uint32_t* write_result = reinterpret_cast<uint32_t*>(Buffer::Data(args[1]));
675
676

410
    CHECK(args[2]->IsFunction());
677
410
    Local<Function> write_js_callback = args[2].As<Function>();
678
205
    wrap->InitStream(write_result, write_js_callback);
679
680
409
    AllocScope alloc_scope(wrap);
681
    CompressionError err =
682
        wrap->context()->Init(
683
          CompressionStream<CompressionContext>::AllocForBrotli,
684
          CompressionStream<CompressionContext>::FreeForZlib,
685
205
          static_cast<CompressionStream<CompressionContext>*>(wrap));
686

205
    if (err.IsError()) {
687
      wrap->EmitError(err);
688
      args.GetReturnValue().Set(false);
689
      return;
690
    }
691
692

410
    CHECK(args[0]->IsUint32Array());
693
205
    const uint32_t* data = reinterpret_cast<uint32_t*>(Buffer::Data(args[0]));
694
615
    size_t len = args[0].As<Uint32Array>()->Length();
695
696

2045
    for (int i = 0; static_cast<size_t>(i) < len; i++) {
697

1841
      if (data[i] == static_cast<uint32_t>(-1))
698
1828
        continue;
699
13
      err = wrap->context()->SetParams(i, data[i]);
700

13
      if (err.IsError()) {
701
1
        wrap->EmitError(err);
702
2
        args.GetReturnValue().Set(false);
703
1
        return;
704
      }
705
    }
706
707

408
    args.GetReturnValue().Set(true);
708
  }
709
710
  static void Params(const FunctionCallbackInfo<Value>& args) {
711
    // Currently a no-op, and not accessed from JS land.
712
    // At some point Brotli may support changing parameters on the fly,
713
    // in which case we can implement this and a JS equivalent similar to
714
    // the zlib Params() function.
715
  }
716
717
  SET_MEMORY_INFO_NAME(BrotliCompressionStream)
718
  SET_SELF_SIZE(BrotliCompressionStream)
719
};
720
721
using BrotliEncoderStream = BrotliCompressionStream<BrotliEncoderContext>;
722
using BrotliDecoderStream = BrotliCompressionStream<BrotliDecoderContext>;
723
724
1835
void ZlibContext::Close() {
725
  {
726
3516
    Mutex::ScopedLock lock(mutex_);
727
1835
    if (!zlib_init_done_) {
728
154
      dictionary_.clear();
729
154
      mode_ = NONE;
730
154
      return;
731
    }
732
  }
733
734
1681
  CHECK_LE(mode_, UNZIP);
735
736
1681
  int status = Z_OK;
737

1681
  if (mode_ == DEFLATE || mode_ == GZIP || mode_ == DEFLATERAW) {
738
403
    status = deflateEnd(&strm_);
739


2111
  } else if (mode_ == INFLATE || mode_ == GUNZIP || mode_ == INFLATERAW ||
740
833
             mode_ == UNZIP) {
741
445
    status = inflateEnd(&strm_);
742
  }
743
744

1681
  CHECK(status == Z_OK || status == Z_DATA_ERROR);
745
1681
  mode_ = NONE;
746
747
1681
  dictionary_.clear();
748
}
749
750
751
7456
void ZlibContext::DoThreadPoolWork() {
752
7456
  bool first_init_call = InitZlib();
753

7455
  if (first_init_call && err_ != Z_OK) {
754
    return;
755
  }
756
757
7455
  const Bytef* next_expected_header_byte = nullptr;
758
759
  // If the avail_out is left at 0, then it means that it ran out
760
  // of room.  If there was avail_out left over, then it means
761
  // that all of the input was consumed.
762

7455
  switch (mode_) {
763
    case DEFLATE:
764
    case GZIP:
765
    case DEFLATERAW:
766
1448
      err_ = deflate(&strm_, flush_);
767
1447
      break;
768
    case UNZIP:
769
273
      if (strm_.avail_in > 0) {
770
272
        next_expected_header_byte = strm_.next_in;
771
      }
772
773
273
      switch (gzip_id_bytes_read_) {
774
        case 0:
775
270
          if (next_expected_header_byte == nullptr) {
776
            break;
777
          }
778
779
270
          if (*next_expected_header_byte == GZIP_HEADER_ID1) {
780
264
            gzip_id_bytes_read_ = 1;
781
264
            next_expected_header_byte++;
782
783
264
            if (strm_.avail_in == 1) {
784
              // The only available byte was already read.
785
2
              break;
786
            }
787
          } else {
788
6
            mode_ = INFLATE;
789
6
            break;
790
          }
791
792
          // fallthrough
793
        case 1:
794
265
          if (next_expected_header_byte == nullptr) {
795
1
            break;
796
          }
797
798
264
          if (*next_expected_header_byte == GZIP_HEADER_ID2) {
799
264
            gzip_id_bytes_read_ = 2;
800
264
            mode_ = GUNZIP;
801
          } else {
802
            // There is no actual difference between INFLATE and INFLATERAW
803
            // (after initialization).
804
            mode_ = INFLATE;
805
          }
806
807
264
          break;
808
        default:
809
          CHECK(0 && "invalid number of gzip magic number bytes read");
810
      }
811
812
      // fallthrough
813
    case INFLATE:
814
    case GUNZIP:
815
    case INFLATERAW:
816
6007
      err_ = inflate(&strm_, flush_);
817
818
      // If data was encoded with dictionary (INFLATERAW will have it set in
819
      // SetDictionary, don't repeat that here)
820

16381
      if (mode_ != INFLATERAW &&
821

6021
          err_ == Z_NEED_DICT &&
822
14
          !dictionary_.empty()) {
823
        // Load it
824
26
        err_ = inflateSetDictionary(&strm_,
825
13
                                    dictionary_.data(),
826
13
                                    dictionary_.size());
827
13
        if (err_ == Z_OK) {
828
          // And try to decode again
829
12
          err_ = inflate(&strm_, flush_);
830
1
        } else if (err_ == Z_DATA_ERROR) {
831
          // Both inflateSetDictionary() and inflate() return Z_DATA_ERROR.
832
          // Make it possible for After() to tell a bad dictionary from bad
833
          // input.
834
1
          err_ = Z_NEED_DICT;
835
        }
836
      }
837
838
6526
      while (strm_.avail_in > 0 &&
839
914
             mode_ == GUNZIP &&
840

6484
             err_ == Z_STREAM_END &&
841
22
             strm_.next_in[0] != 0x00) {
842
        // Bytes remain in input buffer. Perhaps this is another compressed
843
        // member in the same archive, or just trailing garbage.
844
        // Trailing zero bytes are okay, though, since they are frequently
845
        // used for padding.
846
847
20
        ResetStream();
848
20
        err_ = inflate(&strm_, flush_);
849
      }
850
6007
      break;
851
    default:
852
      UNREACHABLE();
853
  }
854
}
855
856
857
7456
void ZlibContext::SetBuffers(char* in, uint32_t in_len,
858
                             char* out, uint32_t out_len) {
859
7456
  strm_.avail_in = in_len;
860
7456
  strm_.next_in = reinterpret_cast<Bytef*>(in);
861
7456
  strm_.avail_out = out_len;
862
7456
  strm_.next_out = reinterpret_cast<Bytef*>(out);
863
7456
}
864
865
866
7456
void ZlibContext::SetFlush(int flush) {
867
7456
  flush_ = flush;
868
7456
}
869
870
871
7434
void ZlibContext::GetAfterWriteOffsets(uint32_t* avail_in,
872
                                       uint32_t* avail_out) const {
873
7434
  *avail_in = strm_.avail_in;
874
7434
  *avail_out = strm_.avail_out;
875
7434
}
876
877
878
22
CompressionError ZlibContext::ErrorForMessage(const char* message) const {
879
22
  if (strm_.msg != nullptr)
880
12
    message = strm_.msg;
881
882
22
  return CompressionError { message, ZlibStrerror(err_), err_ };
883
}
884
885
886
7456
CompressionError ZlibContext::GetErrorInfo() const {
887
  // Acceptable error states depend on the type of zlib stream.
888

7456
  switch (err_) {
889
  case Z_OK:
890
  case Z_BUF_ERROR:
891

6003
    if (strm_.avail_out != 0 && flush_ == Z_FINISH) {
892
8
      return ErrorForMessage("unexpected end of file");
893
    }
894
  case Z_STREAM_END:
895
    // normal statuses, not fatal
896
7434
    break;
897
  case Z_NEED_DICT:
898
2
    if (dictionary_.empty())
899
1
      return ErrorForMessage("Missing dictionary");
900
    else
901
1
      return ErrorForMessage("Bad dictionary");
902
  default:
903
    // something else.
904
12
    return ErrorForMessage("Zlib error");
905
  }
906
907
7434
  return CompressionError {};
908
}
909
910
911
34
CompressionError ZlibContext::ResetStream() {
912
34
  bool first_init_call = InitZlib();
913

34
  if (first_init_call && err_ != Z_OK) {
914
    return ErrorForMessage("Failed to init stream before reset");
915
  }
916
917
34
  err_ = Z_OK;
918
919
34
  switch (mode_) {
920
    case DEFLATE:
921
    case DEFLATERAW:
922
    case GZIP:
923
13
      err_ = deflateReset(&strm_);
924
13
      break;
925
    case INFLATE:
926
    case INFLATERAW:
927
    case GUNZIP:
928
21
      err_ = inflateReset(&strm_);
929
21
      break;
930
    default:
931
      break;
932
  }
933
934
34
  if (err_ != Z_OK)
935
    return ErrorForMessage("Failed to reset stream");
936
937
34
  return SetDictionary();
938
}
939
940
941
1173
void ZlibContext::SetAllocationFunctions(alloc_func alloc,
942
                                         free_func free,
943
                                         void* opaque) {
944
1173
  strm_.zalloc = alloc;
945
1173
  strm_.zfree = free;
946
1173
  strm_.opaque = opaque;
947
1173
}
948
949
950
1173
void ZlibContext::Init(
951
    int level, int window_bits, int mem_level, int strategy,
952
    std::vector<unsigned char>&& dictionary) {
953

1586
  if (!((window_bits == 0) &&
954
742
        (mode_ == INFLATE ||
955
576
         mode_ == GUNZIP ||
956
247
         mode_ == UNZIP))) {
957

760
    CHECK(
958
        (window_bits >= Z_MIN_WINDOWBITS && window_bits <= Z_MAX_WINDOWBITS) &&
959
        "invalid windowBits");
960
  }
961
962

1173
  CHECK((level >= Z_MIN_LEVEL && level <= Z_MAX_LEVEL) &&
963
    "invalid compression level");
964
965

1173
  CHECK((mem_level >= Z_MIN_MEMLEVEL && mem_level <= Z_MAX_MEMLEVEL) &&
966
        "invalid memlevel");
967
968




1173
  CHECK((strategy == Z_FILTERED || strategy == Z_HUFFMAN_ONLY ||
969
         strategy == Z_RLE || strategy == Z_FIXED ||
970
         strategy == Z_DEFAULT_STRATEGY) &&
971
        "invalid strategy");
972
973
1173
  level_ = level;
974
1173
  window_bits_ = window_bits;
975
1173
  mem_level_ = mem_level;
976
1173
  strategy_ = strategy;
977
978
1173
  flush_ = Z_NO_FLUSH;
979
980
1173
  err_ = Z_OK;
981
982

1173
  if (mode_ == GZIP || mode_ == GUNZIP) {
983
431
    window_bits_ += 16;
984
  }
985
986
1173
  if (mode_ == UNZIP) {
987
271
    window_bits_ += 32;
988
  }
989
990

1173
  if (mode_ == DEFLATERAW || mode_ == INFLATERAW) {
991
219
    window_bits_ *= -1;
992
  }
993
994
1173
  dictionary_ = std::move(dictionary);
995
1173
}
996
997
7493
bool ZlibContext::InitZlib() {
998
14986
  Mutex::ScopedLock lock(mutex_);
999
7493
  if (zlib_init_done_) {
1000
6472
    return false;
1001
  }
1002
1003
1021
  switch (mode_) {
1004
    case DEFLATE:
1005
    case GZIP:
1006
    case DEFLATERAW:
1007
403
      err_ = deflateInit2(&strm_,
1008
                          level_,
1009
                          Z_DEFLATED,
1010
                          window_bits_,
1011
                          mem_level_,
1012
                          strategy_);
1013
402
      break;
1014
    case INFLATE:
1015
    case GUNZIP:
1016
    case INFLATERAW:
1017
    case UNZIP:
1018
618
      err_ = inflateInit2(&strm_, window_bits_);
1019
618
      break;
1020
    default:
1021
      UNREACHABLE();
1022
  }
1023
1024
1020
  if (err_ != Z_OK) {
1025
    dictionary_.clear();
1026
    mode_ = NONE;
1027
    return true;
1028
  }
1029
1030
1020
  SetDictionary();
1031
1021
  zlib_init_done_ = true;
1032
1021
  return true;
1033
}
1034
1035
1036
1054
CompressionError ZlibContext::SetDictionary() {
1037
1054
  if (dictionary_.empty())
1038
993
    return CompressionError {};
1039
1040
62
  err_ = Z_OK;
1041
1042
62
  switch (mode_) {
1043
    case DEFLATE:
1044
    case DEFLATERAW:
1045
72
      err_ = deflateSetDictionary(&strm_,
1046
36
                                  dictionary_.data(),
1047
36
                                  dictionary_.size());
1048
36
      break;
1049
    case INFLATERAW:
1050
      // The other inflate cases will have the dictionary set when inflate()
1051
      // returns Z_NEED_DICT in Process()
1052
26
      err_ = inflateSetDictionary(&strm_,
1053
13
                                  dictionary_.data(),
1054
13
                                  dictionary_.size());
1055
13
      break;
1056
    default:
1057
13
      break;
1058
  }
1059
1060
62
  if (err_ != Z_OK) {
1061
    return ErrorForMessage("Failed to set dictionary");
1062
  }
1063
1064
62
  return CompressionError {};
1065
}
1066
1067
1068
3
CompressionError ZlibContext::SetParams(int level, int strategy) {
1069
3
  bool first_init_call = InitZlib();
1070

3
  if (first_init_call && err_ != Z_OK) {
1071
    return ErrorForMessage("Failed to init stream before set parameters");
1072
  }
1073
1074
3
  err_ = Z_OK;
1075
1076
3
  switch (mode_) {
1077
    case DEFLATE:
1078
    case DEFLATERAW:
1079
2
      err_ = deflateParams(&strm_, level, strategy);
1080
2
      break;
1081
    default:
1082
1
      break;
1083
  }
1084
1085

3
  if (err_ != Z_OK && err_ != Z_BUF_ERROR) {
1086
    return ErrorForMessage("Failed to set parameters");
1087
  }
1088
1089
3
  return CompressionError {};
1090
}
1091
1092
1093
1339
void BrotliContext::SetBuffers(char* in, uint32_t in_len,
1094
                               char* out, uint32_t out_len) {
1095
1339
  next_in_ = reinterpret_cast<uint8_t*>(in);
1096
1339
  next_out_ = reinterpret_cast<uint8_t*>(out);
1097
1339
  avail_in_ = in_len;
1098
1339
  avail_out_ = out_len;
1099
1339
}
1100
1101
1102
1339
void BrotliContext::SetFlush(int flush) {
1103
1339
  flush_ = static_cast<BrotliEncoderOperation>(flush);
1104
1339
}
1105
1106
1107
1338
void BrotliContext::GetAfterWriteOffsets(uint32_t* avail_in,
1108
                                         uint32_t* avail_out) const {
1109
1338
  *avail_in = avail_in_;
1110
1338
  *avail_out = avail_out_;
1111
1338
}
1112
1113
1114
331
void BrotliEncoderContext::DoThreadPoolWork() {
1115
331
  CHECK_EQ(mode_, BROTLI_ENCODE);
1116
331
  CHECK(state_);
1117
331
  const uint8_t* next_in = next_in_;
1118
662
  last_result_ = BrotliEncoderCompressStream(state_.get(),
1119
                                             flush_,
1120
                                             &avail_in_,
1121
                                             &next_in,
1122
                                             &avail_out_,
1123
                                             &next_out_,
1124
331
                                             nullptr);
1125
331
  next_in_ += next_in - next_in_;
1126
331
}
1127
1128
1129
204
void BrotliEncoderContext::Close() {
1130
204
  state_.reset();
1131
204
  mode_ = NONE;
1132
204
}
1133
1134
103
CompressionError BrotliEncoderContext::Init(brotli_alloc_func alloc,
1135
                                            brotli_free_func free,
1136
                                            void* opaque) {
1137
103
  alloc_ = alloc;
1138
103
  free_ = free;
1139
103
  alloc_opaque_ = opaque;
1140
103
  state_.reset(BrotliEncoderCreateInstance(alloc, free, opaque));
1141
103
  if (!state_) {
1142
    return CompressionError("Could not initialize Brotli instance",
1143
                            "ERR_ZLIB_INITIALIZATION_FAILED",
1144
                            -1);
1145
  } else {
1146
103
    return CompressionError {};
1147
  }
1148
}
1149
1150
CompressionError BrotliEncoderContext::ResetStream() {
1151
  return Init(alloc_, free_, alloc_opaque_);
1152
}
1153
1154
13
CompressionError BrotliEncoderContext::SetParams(int key, uint32_t value) {
1155
13
  if (!BrotliEncoderSetParameter(state_.get(),
1156
                                 static_cast<BrotliEncoderParameter>(key),
1157
                                 value)) {
1158
    return CompressionError("Setting parameter failed",
1159
                            "ERR_BROTLI_PARAM_SET_FAILED",
1160
1
                            -1);
1161
  } else {
1162
12
    return CompressionError {};
1163
  }
1164
}
1165
1166
331
CompressionError BrotliEncoderContext::GetErrorInfo() const {
1167
331
  if (!last_result_) {
1168
    return CompressionError("Compression failed",
1169
                            "ERR_BROTLI_COMPRESSION_FAILED",
1170
                            -1);
1171
  } else {
1172
331
    return CompressionError {};
1173
  }
1174
}
1175
1176
1177
202
void BrotliDecoderContext::Close() {
1178
202
  state_.reset();
1179
202
  mode_ = NONE;
1180
202
}
1181
1182
1008
void BrotliDecoderContext::DoThreadPoolWork() {
1183
1008
  CHECK_EQ(mode_, BROTLI_DECODE);
1184
1008
  CHECK(state_);
1185
1008
  const uint8_t* next_in = next_in_;
1186
1008
  last_result_ = BrotliDecoderDecompressStream(state_.get(),
1187
                                               &avail_in_,
1188
                                               &next_in,
1189
                                               &avail_out_,
1190
                                               &next_out_,
1191
                                               nullptr);
1192
1008
  next_in_ += next_in - next_in_;
1193
1008
  if (last_result_ == BROTLI_DECODER_RESULT_ERROR) {
1194
1
    error_ = BrotliDecoderGetErrorCode(state_.get());
1195
1
    error_string_ = std::string("ERR_") + BrotliDecoderErrorString(error_);
1196
  }
1197
1008
}
1198
1199
102
CompressionError BrotliDecoderContext::Init(brotli_alloc_func alloc,
1200
                                            brotli_free_func free,
1201
                                            void* opaque) {
1202
102
  alloc_ = alloc;
1203
102
  free_ = free;
1204
102
  alloc_opaque_ = opaque;
1205
102
  state_.reset(BrotliDecoderCreateInstance(alloc, free, opaque));
1206
102
  if (!state_) {
1207
    return CompressionError("Could not initialize Brotli instance",
1208
                            "ERR_ZLIB_INITIALIZATION_FAILED",
1209
                            -1);
1210
  } else {
1211
102
    return CompressionError {};
1212
  }
1213
}
1214
1215
CompressionError BrotliDecoderContext::ResetStream() {
1216
  return Init(alloc_, free_, alloc_opaque_);
1217
}
1218
1219
CompressionError BrotliDecoderContext::SetParams(int key, uint32_t value) {
1220
  if (!BrotliDecoderSetParameter(state_.get(),
1221
                                 static_cast<BrotliDecoderParameter>(key),
1222
                                 value)) {
1223
    return CompressionError("Setting parameter failed",
1224
                            "ERR_BROTLI_PARAM_SET_FAILED",
1225
                            -1);
1226
  } else {
1227
    return CompressionError {};
1228
  }
1229
}
1230
1231
1008
CompressionError BrotliDecoderContext::GetErrorInfo() const {
1232
1008
  if (error_ != BROTLI_DECODER_NO_ERROR) {
1233
    return CompressionError("Decompression failed",
1234
                            error_string_.c_str(),
1235
1
                            static_cast<int>(error_));
1236

1105
  } else if (flush_ == BROTLI_OPERATION_FINISH &&
1237
98
             last_result_ == BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT) {
1238
    // Match zlib's behaviour, as brotli doesn't have its own code for this.
1239
    return CompressionError("unexpected end of file",
1240
                            "Z_BUF_ERROR",
1241
                            Z_BUF_ERROR);
1242
  } else {
1243
1007
    return CompressionError {};
1244
  }
1245
}
1246
1247
1248
template <typename Stream>
1249
struct MakeClass {
1250
177
  static void Make(Environment* env, Local<Object> target, const char* name) {
1251
177
    Local<FunctionTemplate> z = env->NewFunctionTemplate(Stream::New);
1252
1253
354
    z->InstanceTemplate()->SetInternalFieldCount(
1254
        Stream::kInternalFieldCount);
1255
354
    z->Inherit(AsyncWrap::GetConstructorTemplate(env));
1256
1257
177
    env->SetProtoMethod(z, "write", Stream::template Write<true>);
1258
177
    env->SetProtoMethod(z, "writeSync", Stream::template Write<false>);
1259
177
    env->SetProtoMethod(z, "close", Stream::Close);
1260
1261
177
    env->SetProtoMethod(z, "init", Stream::Init);
1262
177
    env->SetProtoMethod(z, "params", Stream::Params);
1263
177
    env->SetProtoMethod(z, "reset", Stream::Reset);
1264
1265
177
    Local<String> zlibString = OneByteString(env->isolate(), name);
1266
177
    z->SetClassName(zlibString);
1267
531
    target->Set(env->context(),
1268
                zlibString,
1269
531
                z->GetFunction(env->context()).ToLocalChecked()).Check();
1270
177
  }
1271
};
1272
1273
59
void Initialize(Local<Object> target,
1274
                Local<Value> unused,
1275
                Local<Context> context,
1276
                void* priv) {
1277
59
  Environment* env = Environment::GetCurrent(context);
1278
1279
59
  MakeClass<ZlibStream>::Make(env, target, "Zlib");
1280
59
  MakeClass<BrotliEncoderStream>::Make(env, target, "BrotliEncoder");
1281
59
  MakeClass<BrotliDecoderStream>::Make(env, target, "BrotliDecoder");
1282
1283
118
  target->Set(env->context(),
1284
              FIXED_ONE_BYTE_STRING(env->isolate(), "ZLIB_VERSION"),
1285
295
              FIXED_ONE_BYTE_STRING(env->isolate(), ZLIB_VERSION)).Check();
1286
59
}
1287
1288
}  // anonymous namespace
1289
1290
387
void DefineZlibConstants(Local<Object> target) {
1291
1548
  NODE_DEFINE_CONSTANT(target, Z_NO_FLUSH);
1292
1548
  NODE_DEFINE_CONSTANT(target, Z_PARTIAL_FLUSH);
1293
1548
  NODE_DEFINE_CONSTANT(target, Z_SYNC_FLUSH);
1294
1548
  NODE_DEFINE_CONSTANT(target, Z_FULL_FLUSH);
1295
1548
  NODE_DEFINE_CONSTANT(target, Z_FINISH);
1296
1548
  NODE_DEFINE_CONSTANT(target, Z_BLOCK);
1297
1298
  // return/error codes
1299
1548
  NODE_DEFINE_CONSTANT(target, Z_OK);
1300
1548
  NODE_DEFINE_CONSTANT(target, Z_STREAM_END);
1301
1548
  NODE_DEFINE_CONSTANT(target, Z_NEED_DICT);
1302
1548
  NODE_DEFINE_CONSTANT(target, Z_ERRNO);
1303
1548
  NODE_DEFINE_CONSTANT(target, Z_STREAM_ERROR);
1304
1548
  NODE_DEFINE_CONSTANT(target, Z_DATA_ERROR);
1305
1548
  NODE_DEFINE_CONSTANT(target, Z_MEM_ERROR);
1306
1548
  NODE_DEFINE_CONSTANT(target, Z_BUF_ERROR);
1307
1548
  NODE_DEFINE_CONSTANT(target, Z_VERSION_ERROR);
1308
1309
1548
  NODE_DEFINE_CONSTANT(target, Z_NO_COMPRESSION);
1310
1548
  NODE_DEFINE_CONSTANT(target, Z_BEST_SPEED);
1311
1548
  NODE_DEFINE_CONSTANT(target, Z_BEST_COMPRESSION);
1312
1548
  NODE_DEFINE_CONSTANT(target, Z_DEFAULT_COMPRESSION);
1313
1548
  NODE_DEFINE_CONSTANT(target, Z_FILTERED);
1314
1548
  NODE_DEFINE_CONSTANT(target, Z_HUFFMAN_ONLY);
1315
1548
  NODE_DEFINE_CONSTANT(target, Z_RLE);
1316
1548
  NODE_DEFINE_CONSTANT(target, Z_FIXED);
1317
1548
  NODE_DEFINE_CONSTANT(target, Z_DEFAULT_STRATEGY);
1318
1548
  NODE_DEFINE_CONSTANT(target, ZLIB_VERNUM);
1319
1320
1548
  NODE_DEFINE_CONSTANT(target, DEFLATE);
1321
1548
  NODE_DEFINE_CONSTANT(target, INFLATE);
1322
1548
  NODE_DEFINE_CONSTANT(target, GZIP);
1323
1548
  NODE_DEFINE_CONSTANT(target, GUNZIP);
1324
1548
  NODE_DEFINE_CONSTANT(target, DEFLATERAW);
1325
1548
  NODE_DEFINE_CONSTANT(target, INFLATERAW);
1326
1548
  NODE_DEFINE_CONSTANT(target, UNZIP);
1327
1548
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODE);
1328
1548
  NODE_DEFINE_CONSTANT(target, BROTLI_ENCODE);
1329
1330
1548
  NODE_DEFINE_CONSTANT(target, Z_MIN_WINDOWBITS);
1331
1548
  NODE_DEFINE_CONSTANT(target, Z_MAX_WINDOWBITS);
1332
1548
  NODE_DEFINE_CONSTANT(target, Z_DEFAULT_WINDOWBITS);
1333
1548
  NODE_DEFINE_CONSTANT(target, Z_MIN_CHUNK);
1334
1548
  NODE_DEFINE_CONSTANT(target, Z_MAX_CHUNK);
1335
1548
  NODE_DEFINE_CONSTANT(target, Z_DEFAULT_CHUNK);
1336
1548
  NODE_DEFINE_CONSTANT(target, Z_MIN_MEMLEVEL);
1337
1548
  NODE_DEFINE_CONSTANT(target, Z_MAX_MEMLEVEL);
1338
1548
  NODE_DEFINE_CONSTANT(target, Z_DEFAULT_MEMLEVEL);
1339
1548
  NODE_DEFINE_CONSTANT(target, Z_MIN_LEVEL);
1340
1548
  NODE_DEFINE_CONSTANT(target, Z_MAX_LEVEL);
1341
1548
  NODE_DEFINE_CONSTANT(target, Z_DEFAULT_LEVEL);
1342
1343
  // Brotli constants
1344
1548
  NODE_DEFINE_CONSTANT(target, BROTLI_OPERATION_PROCESS);
1345
1548
  NODE_DEFINE_CONSTANT(target, BROTLI_OPERATION_FLUSH);
1346
1548
  NODE_DEFINE_CONSTANT(target, BROTLI_OPERATION_FINISH);
1347
1548
  NODE_DEFINE_CONSTANT(target, BROTLI_OPERATION_EMIT_METADATA);
1348
1548
  NODE_DEFINE_CONSTANT(target, BROTLI_PARAM_MODE);
1349
1548
  NODE_DEFINE_CONSTANT(target, BROTLI_MODE_GENERIC);
1350
1548
  NODE_DEFINE_CONSTANT(target, BROTLI_MODE_TEXT);
1351
1548
  NODE_DEFINE_CONSTANT(target, BROTLI_MODE_FONT);
1352
1548
  NODE_DEFINE_CONSTANT(target, BROTLI_DEFAULT_MODE);
1353
1548
  NODE_DEFINE_CONSTANT(target, BROTLI_PARAM_QUALITY);
1354
1548
  NODE_DEFINE_CONSTANT(target, BROTLI_MIN_QUALITY);
1355
1548
  NODE_DEFINE_CONSTANT(target, BROTLI_MAX_QUALITY);
1356
1548
  NODE_DEFINE_CONSTANT(target, BROTLI_DEFAULT_QUALITY);
1357
1548
  NODE_DEFINE_CONSTANT(target, BROTLI_PARAM_LGWIN);
1358
1548
  NODE_DEFINE_CONSTANT(target, BROTLI_MIN_WINDOW_BITS);
1359
1548
  NODE_DEFINE_CONSTANT(target, BROTLI_MAX_WINDOW_BITS);
1360
1548
  NODE_DEFINE_CONSTANT(target, BROTLI_LARGE_MAX_WINDOW_BITS);
1361
1548
  NODE_DEFINE_CONSTANT(target, BROTLI_DEFAULT_WINDOW);
1362
1548
  NODE_DEFINE_CONSTANT(target, BROTLI_PARAM_LGBLOCK);
1363
1548
  NODE_DEFINE_CONSTANT(target, BROTLI_MIN_INPUT_BLOCK_BITS);
1364
1548
  NODE_DEFINE_CONSTANT(target, BROTLI_MAX_INPUT_BLOCK_BITS);
1365
1548
  NODE_DEFINE_CONSTANT(target, BROTLI_PARAM_DISABLE_LITERAL_CONTEXT_MODELING);
1366
1548
  NODE_DEFINE_CONSTANT(target, BROTLI_PARAM_SIZE_HINT);
1367
1548
  NODE_DEFINE_CONSTANT(target, BROTLI_PARAM_LARGE_WINDOW);
1368
1548
  NODE_DEFINE_CONSTANT(target, BROTLI_PARAM_NPOSTFIX);
1369
1548
  NODE_DEFINE_CONSTANT(target, BROTLI_PARAM_NDIRECT);
1370
1548
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_RESULT_ERROR);
1371
1548
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_RESULT_SUCCESS);
1372
1548
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT);
1373
1548
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT);
1374
1548
  NODE_DEFINE_CONSTANT(target,
1375
      BROTLI_DECODER_PARAM_DISABLE_RING_BUFFER_REALLOCATION);
1376
1548
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_PARAM_LARGE_WINDOW);
1377
1548
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_NO_ERROR);
1378
1548
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_SUCCESS);
1379
1548
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_NEEDS_MORE_INPUT);
1380
1548
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_NEEDS_MORE_OUTPUT);
1381
1548
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_NIBBLE);
1382
1548
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_RESERVED);
1383
1548
  NODE_DEFINE_CONSTANT(target,
1384
      BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_META_NIBBLE);
1385
1548
  NODE_DEFINE_CONSTANT(target,
1386
      BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_ALPHABET);
1387
1548
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_SAME);
1388
1548
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_CL_SPACE);
1389
1548
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_HUFFMAN_SPACE);
1390
1548
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_CONTEXT_MAP_REPEAT);
1391
1548
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_1);
1392
1548
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_2);
1393
1548
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_TRANSFORM);
1394
1548
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_DICTIONARY);
1395
1548
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_WINDOW_BITS);
1396
1548
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_PADDING_1);
1397
1548
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_PADDING_2);
1398
1548
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_DISTANCE);
1399
1548
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_DICTIONARY_NOT_SET);
1400
1548
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_INVALID_ARGUMENTS);
1401
1548
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MODES);
1402
1548
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_ALLOC_TREE_GROUPS);
1403
1548
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MAP);
1404
1548
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_1);
1405
1548
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_2);
1406
1548
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_ALLOC_BLOCK_TYPE_TREES);
1407
1548
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_UNREACHABLE);
1408
387
}
1409
1410
}  // namespace node
1411
1412

17839
NODE_MODULE_CONTEXT_AWARE_INTERNAL(zlib, node::Initialize)