GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: node_zlib.cc Lines: 634 699 90.7 %
Date: 2021-09-27 04:13:02 Branches: 254 368 69.0 %

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 "node_external_reference.h"
29
#include "threadpoolwork-inl.h"
30
#include "util-inl.h"
31
32
#include "v8.h"
33
34
#include "brotli/encode.h"
35
#include "brotli/decode.h"
36
#include "zlib.h"
37
38
#include <sys/types.h>
39
40
#include <cerrno>
41
#include <cstdlib>
42
#include <cstring>
43
#include <atomic>
44
45
namespace node {
46
47
using v8::ArrayBuffer;
48
using v8::Context;
49
using v8::Function;
50
using v8::FunctionCallbackInfo;
51
using v8::FunctionTemplate;
52
using v8::Global;
53
using v8::HandleScope;
54
using v8::Int32;
55
using v8::Integer;
56
using v8::Local;
57
using v8::Object;
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
#define Z_MIN_WINDOWBITS 8
76
#define Z_MAX_WINDOWBITS 15
77
#define Z_DEFAULT_WINDOWBITS 15
78
79
#define ZLIB_ERROR_CODES(V)      \
80
  V(Z_OK)                        \
81
  V(Z_STREAM_END)                \
82
  V(Z_NEED_DICT)                 \
83
  V(Z_ERRNO)                     \
84
  V(Z_STREAM_ERROR)              \
85
  V(Z_DATA_ERROR)                \
86
  V(Z_MEM_ERROR)                 \
87
  V(Z_BUF_ERROR)                 \
88
  V(Z_VERSION_ERROR)             \
89
90
22
inline const char* ZlibStrerror(int err) {
91
#define V(code) if (err == code) return #code;
92




22
  ZLIB_ERROR_CODES(V)
93
#undef V
94
  return "Z_UNKNOWN_ERROR";
95
}
96
97
enum node_zlib_mode {
98
  NONE,
99
  DEFLATE,
100
  INFLATE,
101
  GZIP,
102
  GUNZIP,
103
  DEFLATERAW,
104
  INFLATERAW,
105
  UNZIP,
106
  BROTLI_DECODE,
107
  BROTLI_ENCODE
108
};
109
110
#define GZIP_HEADER_ID1 0x1f
111
#define GZIP_HEADER_ID2 0x8b
112
113
struct CompressionError {
114
24
  CompressionError(const char* message, const char* code, int err)
115
24
      : message(message),
116
        code(code),
117
24
        err(err) {
118
24
    CHECK_NOT_NULL(message);
119
24
  }
120
121
9992
  CompressionError() = default;
122
123
  const char* message = nullptr;
124
  const char* code = nullptr;
125
  int err = 0;
126
127
9028
  inline bool IsError() const { return code != nullptr; }
128
};
129
130
class ZlibContext : public MemoryRetainer {
131
 public:
132
1120
  ZlibContext() = default;
133
134
  // Streaming-related, should be available for all compression libraries:
135
  void Close();
136
  void DoThreadPoolWork();
137
  void SetBuffers(char* in, uint32_t in_len, char* out, uint32_t out_len);
138
  void SetFlush(int flush);
139
  void GetAfterWriteOffsets(uint32_t* avail_in, uint32_t* avail_out) const;
140
  CompressionError GetErrorInfo() const;
141
1120
  inline void SetMode(node_zlib_mode mode) { mode_ = mode; }
142
  CompressionError ResetStream();
143
144
  // Zlib-specific:
145
  void Init(int level, int window_bits, int mem_level, int strategy,
146
            std::vector<unsigned char>&& dictionary);
147
  void SetAllocationFunctions(alloc_func alloc, free_func free, void* opaque);
148
  CompressionError SetParams(int level, int strategy);
149
150
  SET_MEMORY_INFO_NAME(ZlibContext)
151
  SET_SELF_SIZE(ZlibContext)
152
153
  void MemoryInfo(MemoryTracker* tracker) const override {
154
    tracker->TrackField("dictionary", dictionary_);
155
  }
156
157
  ZlibContext(const ZlibContext&) = delete;
158
  ZlibContext& operator=(const ZlibContext&) = delete;
159
160
 private:
161
  CompressionError ErrorForMessage(const char* message) const;
162
  CompressionError SetDictionary();
163
  bool InitZlib();
164
165
  Mutex mutex_;  // Protects zlib_init_done_.
166
  bool zlib_init_done_ = false;
167
  int err_ = 0;
168
  int flush_ = 0;
169
  int level_ = 0;
170
  int mem_level_ = 0;
171
  node_zlib_mode mode_ = NONE;
172
  int strategy_ = 0;
173
  int window_bits_ = 0;
174
  unsigned int gzip_id_bytes_read_ = 0;
175
  std::vector<unsigned char> dictionary_;
176
177
  z_stream strm_;
178
};
179
180
// Brotli has different data types for compression and decompression streams,
181
// so some of the specifics are implemented in more specific subclasses
182
class BrotliContext : public MemoryRetainer {
183
 public:
184
207
  BrotliContext() = default;
185
186
  void SetBuffers(char* in, uint32_t in_len, char* out, uint32_t out_len);
187
  void SetFlush(int flush);
188
  void GetAfterWriteOffsets(uint32_t* avail_in, uint32_t* avail_out) const;
189
207
  inline void SetMode(node_zlib_mode mode) { mode_ = mode; }
190
191
  BrotliContext(const BrotliContext&) = delete;
192
  BrotliContext& operator=(const BrotliContext&) = delete;
193
194
 protected:
195
  node_zlib_mode mode_ = NONE;
196
  uint8_t* next_in_ = nullptr;
197
  uint8_t* next_out_ = nullptr;
198
  size_t avail_in_ = 0;
199
  size_t avail_out_ = 0;
200
  BrotliEncoderOperation flush_ = BROTLI_OPERATION_PROCESS;
201
  // TODO(addaleax): These should not need to be stored here.
202
  // This is currently only done this way to make implementing ResetStream()
203
  // easier.
204
  brotli_alloc_func alloc_ = nullptr;
205
  brotli_free_func free_ = nullptr;
206
  void* alloc_opaque_ = nullptr;
207
};
208
209
class BrotliEncoderContext final : public BrotliContext {
210
 public:
211
  void Close();
212
  void DoThreadPoolWork();
213
  CompressionError Init(brotli_alloc_func alloc,
214
                        brotli_free_func free,
215
                        void* opaque);
216
  CompressionError ResetStream();
217
  CompressionError SetParams(int key, uint32_t value);
218
  CompressionError GetErrorInfo() const;
219
220
  SET_MEMORY_INFO_NAME(BrotliEncoderContext)
221
  SET_SELF_SIZE(BrotliEncoderContext)
222
  SET_NO_MEMORY_INFO()  // state_ is covered through allocation tracking.
223
224
 private:
225
  bool last_result_ = false;
226
  DeleteFnPtr<BrotliEncoderState, BrotliEncoderDestroyInstance> state_;
227
};
228
229
class BrotliDecoderContext final : public BrotliContext {
230
 public:
231
  void Close();
232
  void DoThreadPoolWork();
233
  CompressionError Init(brotli_alloc_func alloc,
234
                        brotli_free_func free,
235
                        void* opaque);
236
  CompressionError ResetStream();
237
  CompressionError SetParams(int key, uint32_t value);
238
  CompressionError GetErrorInfo() const;
239
240
  SET_MEMORY_INFO_NAME(BrotliDecoderContext)
241
  SET_SELF_SIZE(BrotliDecoderContext)
242
  SET_NO_MEMORY_INFO()  // state_ is covered through allocation tracking.
243
244
 private:
245
  BrotliDecoderResult last_result_ = BROTLI_DECODER_RESULT_SUCCESS;
246
  BrotliDecoderErrorCode error_ = BROTLI_DECODER_NO_ERROR;
247
  std::string error_string_;
248
  DeleteFnPtr<BrotliDecoderState, BrotliDecoderDestroyInstance> state_;
249
};
250
251
template <typename CompressionContext>
252
class CompressionStream : public AsyncWrap, public ThreadPoolWork {
253
 public:
254
2654
  CompressionStream(Environment* env, Local<Object> wrap)
255
      : AsyncWrap(env, wrap, AsyncWrap::PROVIDER_ZLIB),
256
        ThreadPoolWork(env),
257
2654
        write_result_(nullptr) {
258
2654
    MakeWeak();
259
2654
  }
260
261
2652
  ~CompressionStream() override {
262
    CHECK_EQ(false, write_in_progress_ && "write in progress");
263
2652
    Close();
264
2652
    CHECK_EQ(zlib_memory_, 0);
265
2652
    CHECK_EQ(unreported_allocations_, 0);
266
7956
  }
267
268
4788
  void Close() {
269
4788
    if (write_in_progress_) {
270
60
      pending_close_ = true;
271
60
      return;
272
    }
273
274
4728
    pending_close_ = false;
275
4728
    closed_ = true;
276
4728
    CHECK(init_done_ && "close before init");
277
278
9456
    AllocScope alloc_scope(this);
279
4728
    ctx_.Close();
280
  }
281
282
283
2076
  static void Close(const FunctionCallbackInfo<Value>& args) {
284
    CompressionStream* ctx;
285
2076
    ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
286
2076
    ctx->Close();
287
  }
288
289
290
  // write(flush, in, in_off, in_len, out, out_off, out_len)
291
  template <bool async>
292
17582
  static void Write(const FunctionCallbackInfo<Value>& args) {
293
17582
    Environment* env = Environment::GetCurrent(args);
294
17582
    Local<Context> context = env->context();
295
17582
    CHECK_EQ(args.Length(), 7);
296
297
    uint32_t in_off, in_len, out_off, out_len, flush;
298
    char* in;
299
    char* out;
300
301

35164
    CHECK_EQ(false, args[0]->IsUndefined() && "must provide flush value");
302
35164
    if (!args[0]->Uint32Value(context).To(&flush)) return;
303
304
17582
    if (flush != Z_NO_FLUSH &&
305
8184
        flush != Z_PARTIAL_FLUSH &&
306
7228
        flush != Z_SYNC_FLUSH &&
307
6792
        flush != Z_FULL_FLUSH &&
308
1926
        flush != Z_FINISH &&
309
        flush != Z_BLOCK) {
310
      CHECK(0 && "Invalid flush value");
311
    }
312
313
35164
    if (args[1]->IsNull()) {
314
      // just a flush
315
      in = nullptr;
316
      in_len = 0;
317
      in_off = 0;
318
    } else {
319
17582
      CHECK(Buffer::HasInstance(args[1]));
320
35164
      Local<Object> in_buf = args[1].As<Object>();
321
35164
      if (!args[2]->Uint32Value(context).To(&in_off)) return;
322
35164
      if (!args[3]->Uint32Value(context).To(&in_len)) return;
323
324
17582
      CHECK(Buffer::IsWithinBounds(in_off, in_len, Buffer::Length(in_buf)));
325
17582
      in = Buffer::Data(in_buf) + in_off;
326
    }
327
328
17582
    CHECK(Buffer::HasInstance(args[4]));
329
35164
    Local<Object> out_buf = args[4].As<Object>();
330
35164
    if (!args[5]->Uint32Value(context).To(&out_off)) return;
331
35164
    if (!args[6]->Uint32Value(context).To(&out_len)) return;
332
17582
    CHECK(Buffer::IsWithinBounds(out_off, out_len, Buffer::Length(out_buf)));
333
17582
    out = Buffer::Data(out_buf) + out_off;
334
335
    CompressionStream* ctx;
336
17582
    ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
337
338
17582
    ctx->Write<async>(flush, in, in_len, out, out_len);
339
  }
340
341
  template <bool async>
342
17582
  void Write(uint32_t flush,
343
             char* in, uint32_t in_len,
344
             char* out, uint32_t out_len) {
345
17582
    AllocScope alloc_scope(this);
346
347
17582
    CHECK(init_done_ && "write before init");
348
17582
    CHECK(!closed_ && "already finalized");
349
350
17582
    CHECK_EQ(false, write_in_progress_);
351
17582
    CHECK_EQ(false, pending_close_);
352
17582
    write_in_progress_ = true;
353
17582
    Ref();
354
355
17582
    ctx_.SetBuffers(in, in_len, out, out_len);
356
17582
    ctx_.SetFlush(flush);
357
358
    if (!async) {
359
      // sync version
360
2402
      AsyncWrap::env()->PrintSyncTrace();
361
2402
      DoThreadPoolWork();
362
2402
      if (CheckError()) {
363
2390
        UpdateWriteResult();
364
2390
        write_in_progress_ = false;
365
      }
366
2402
      Unref();
367
2402
      return;
368
    }
369
370
    // async version
371
15180
    ScheduleWork();
372
  }
373
374
17536
  void UpdateWriteResult() {
375
17536
    ctx_.GetAfterWriteOffsets(&write_result_[1], &write_result_[0]);
376
17536
  }
377
378
  // thread pool!
379
  // This function may be called multiple times on the uv_work pool
380
  // for a single write() call, until all of the input bytes have
381
  // been consumed.
382
17582
  void DoThreadPoolWork() override {
383
17582
    ctx_.DoThreadPoolWork();
384
17582
  }
385
386
387
17582
  bool CheckError() {
388
17582
    const CompressionError err = ctx_.GetErrorInfo();
389
17582
    if (!err.IsError()) return true;
390
46
    EmitError(err);
391
46
    return false;
392
  }
393
394
395
  // v8 land!
396
15180
  void AfterThreadPoolWork(int status) override {
397
15180
    AllocScope alloc_scope(this);
398
22770
    auto on_scope_leave = OnScopeLeave([&]() { Unref(); });
399
400
15180
    write_in_progress_ = false;
401
402
15180
    if (status == UV_ECANCELED) {
403
      Close();
404
      return;
405
    }
406
407
15180
    CHECK_EQ(status, 0);
408
409
15180
    Environment* env = AsyncWrap::env();
410
15180
    HandleScope handle_scope(env->isolate());
411
15180
    Context::Scope context_scope(env->context());
412
413
15180
    if (!CheckError())
414
34
      return;
415
416
15146
    UpdateWriteResult();
417
418
    // call the write() cb
419
15146
    Local<Function> cb = PersistentToLocal::Default(env->isolate(),
420
                                                    write_js_callback_);
421
15146
    MakeCallback(cb, 0, nullptr);
422
423
15146
    if (pending_close_)
424
46
      Close();
425
  }
426
427
  // TODO(addaleax): Switch to modern error system (node_errors.h).
428
48
  void EmitError(const CompressionError& err) {
429
48
    Environment* env = AsyncWrap::env();
430
    // If you hit this assertion, you forgot to enter the v8::Context first.
431
96
    CHECK_EQ(env->context(), env->isolate()->GetCurrentContext());
432
433
96
    HandleScope scope(env->isolate());
434
144
    Local<Value> args[3] = {
435
48
      OneByteString(env->isolate(), err.message),
436
48
      Integer::New(env->isolate(), err.err),
437
48
      OneByteString(env->isolate(), err.code)
438
    };
439
48
    MakeCallback(env->onerror_string(), arraysize(args), args);
440
441
    // no hope of rescue.
442
48
    write_in_progress_ = false;
443
48
    if (pending_close_)
444
14
      Close();
445
48
  }
446
447
28
  static void Reset(const FunctionCallbackInfo<Value> &args) {
448
    CompressionStream* wrap;
449
28
    ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
450
451
56
    AllocScope alloc_scope(wrap);
452
28
    const CompressionError err = wrap->context()->ResetStream();
453
28
    if (err.IsError())
454
      wrap->EmitError(err);
455
  }
456
457
  void MemoryInfo(MemoryTracker* tracker) const override {
458
    tracker->TrackField("compression context", ctx_);
459
    tracker->TrackFieldWithSize("zlib_memory",
460
                                zlib_memory_ + unreported_allocations_);
461
  }
462
463
 protected:
464
7608
  CompressionContext* context() { return &ctx_; }
465
466
2654
  void InitStream(uint32_t* write_result, Local<Function> write_js_callback) {
467
2654
    write_result_ = write_result;
468
2654
    write_js_callback_.Reset(AsyncWrap::env()->isolate(), write_js_callback);
469
2654
    init_done_ = true;
470
2654
  }
471
472
  // Allocation functions provided to zlib itself. We store the real size of
473
  // the allocated memory chunk just before the "payload" memory we return
474
  // to zlib.
475
  // Because we use zlib off the thread pool, we can not report memory directly
476
  // to V8; rather, we first store it as "unreported" memory in a separate
477
  // field and later report it back from the main thread.
478
2764
  static void* AllocForZlib(void* data, uInt items, uInt size) {
479
    size_t real_size =
480
2764
        MultiplyWithOverflowCheck(static_cast<size_t>(items),
481
                                  static_cast<size_t>(size));
482
2764
    return AllocForBrotli(data, real_size);
483
  }
484
485
15820
  static void* AllocForBrotli(void* data, size_t size) {
486
15820
    size += sizeof(size_t);
487
15820
    CompressionStream* ctx = static_cast<CompressionStream*>(data);
488
15820
    char* memory = UncheckedMalloc(size);
489
15820
    if (UNLIKELY(memory == nullptr)) return nullptr;
490
15820
    *reinterpret_cast<size_t*>(memory) = size;
491
15820
    ctx->unreported_allocations_.fetch_add(size,
492
                                           std::memory_order_relaxed);
493
15820
    return memory + sizeof(size_t);
494
  }
495
496
20424
  static void FreeForZlib(void* data, void* pointer) {
497
20424
    if (UNLIKELY(pointer == nullptr)) return;
498
15816
    CompressionStream* ctx = static_cast<CompressionStream*>(data);
499
15816
    char* real_pointer = static_cast<char*>(pointer) - sizeof(size_t);
500
15816
    size_t real_size = *reinterpret_cast<size_t*>(real_pointer);
501
15816
    ctx->unreported_allocations_.fetch_sub(real_size,
502
                                           std::memory_order_relaxed);
503
15816
    free(real_pointer);
504
  }
505
506
  // This is called on the main thread after zlib may have allocated something
507
  // in order to report it back to V8.
508
40178
  void AdjustAmountOfExternalAllocatedMemory() {
509
    ssize_t report =
510
40178
        unreported_allocations_.exchange(0, std::memory_order_relaxed);
511
40178
    if (report == 0) return;
512

5170
    CHECK_IMPLIES(report < 0, zlib_memory_ >= static_cast<size_t>(-report));
513
5170
    zlib_memory_ += report;
514
5170
    AsyncWrap::env()->isolate()->AdjustAmountOfExternalAllocatedMemory(report);
515
  }
516
517
  struct AllocScope {
518
40178
    explicit AllocScope(CompressionStream* stream) : stream(stream) {}
519
20089
    ~AllocScope() { stream->AdjustAmountOfExternalAllocatedMemory(); }
520
    CompressionStream* stream;
521
  };
522
523
 private:
524
17582
  void Ref() {
525
17582
    if (++refs_ == 1) {
526
3702
      ClearWeak();
527
    }
528
17582
  }
529
530
17582
  void Unref() {
531
17582
    CHECK_GT(refs_, 0);
532
17582
    if (--refs_ == 0) {
533
3702
      MakeWeak();
534
    }
535
17582
  }
536
537
  bool init_done_ = false;
538
  bool write_in_progress_ = false;
539
  bool pending_close_ = false;
540
  bool closed_ = false;
541
  unsigned int refs_ = 0;
542
  uint32_t* write_result_ = nullptr;
543
  Global<Function> write_js_callback_;
544
  std::atomic<ssize_t> unreported_allocations_{0};
545
  size_t zlib_memory_ = 0;
546
547
  CompressionContext ctx_;
548
};
549
550
class ZlibStream : public CompressionStream<ZlibContext> {
551
 public:
552
1120
  ZlibStream(Environment* env, Local<Object> wrap, node_zlib_mode mode)
553
1120
    : CompressionStream(env, wrap) {
554
1120
    context()->SetMode(mode);
555
1120
  }
556
557
1120
  static void New(const FunctionCallbackInfo<Value>& args) {
558
1120
    Environment* env = Environment::GetCurrent(args);
559
1120
    CHECK(args[0]->IsInt32());
560
    node_zlib_mode mode =
561
2240
        static_cast<node_zlib_mode>(args[0].As<Int32>()->Value());
562
1120
    new ZlibStream(env, args.This(), mode);
563
1120
  }
564
565
  // just pull the ints out of the args and call the other Init
566
1120
  static void Init(const FunctionCallbackInfo<Value>& args) {
567
    // Refs: https://github.com/nodejs/node/issues/16649
568
    // Refs: https://github.com/nodejs/node/issues/14161
569
1120
    if (args.Length() == 5) {
570
      fprintf(stderr,
571
          "WARNING: You are likely using a version of node-tar or npm that "
572
          "is incompatible with this version of Node.js.\nPlease use "
573
          "either the version of npm that is bundled with Node.js, or "
574
          "a version of npm (> 5.5.1 or < 5.4.0) or node-tar (> 4.0.1) "
575
          "that is compatible with Node.js 9 and above.\n");
576
    }
577

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

3
    CHECK(args.Length() == 2 && "params(level, strategy)");
630
    ZlibStream* wrap;
631
3
    ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
632
3
    Local<Context> context = args.GetIsolate()->GetCurrentContext();
633
    int level;
634
6
    if (!args[0]->Int32Value(context).To(&level)) return;
635
    int strategy;
636
6
    if (!args[1]->Int32Value(context).To(&strategy)) return;
637
638
6
    AllocScope alloc_scope(wrap);
639
3
    const CompressionError err = wrap->context()->SetParams(level, strategy);
640
3
    if (err.IsError())
641
      wrap->EmitError(err);
642
  }
643
644
  SET_MEMORY_INFO_NAME(ZlibStream)
645
  SET_SELF_SIZE(ZlibStream)
646
};
647
648
template <typename CompressionContext>
649
class BrotliCompressionStream : public CompressionStream<CompressionContext> {
650
 public:
651
414
  BrotliCompressionStream(Environment* env,
652
                          Local<Object> wrap,
653
                          node_zlib_mode mode)
654
414
    : CompressionStream<CompressionContext>(env, wrap) {
655
414
    context()->SetMode(mode);
656
414
  }
657
658
854
  inline CompressionContext* context() {
659
854
    return this->CompressionStream<CompressionContext>::context();
660
  }
661
  typedef typename CompressionStream<CompressionContext>::AllocScope AllocScope;
662
663
414
  static void New(const FunctionCallbackInfo<Value>& args) {
664
414
    Environment* env = Environment::GetCurrent(args);
665
414
    CHECK(args[0]->IsInt32());
666
414
    node_zlib_mode mode =
667
828
        static_cast<node_zlib_mode>(args[0].As<Int32>()->Value());
668
414
    new BrotliCompressionStream(env, args.This(), mode);
669
414
  }
670
671
414
  static void Init(const FunctionCallbackInfo<Value>& args) {
672
    BrotliCompressionStream* wrap;
673
416
    ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
674

414
    CHECK(args.Length() == 3 && "init(params, writeResult, writeCallback)");
675
676
414
    CHECK(args[1]->IsUint32Array());
677
414
    uint32_t* write_result = reinterpret_cast<uint32_t*>(Buffer::Data(args[1]));
678
679
414
    CHECK(args[2]->IsFunction());
680
414
    Local<Function> write_js_callback = args[2].As<Function>();
681
414
    wrap->InitStream(write_result, write_js_callback);
682
683
414
    AllocScope alloc_scope(wrap);
684
414
    CompressionError err =
685
        wrap->context()->Init(
686
          CompressionStream<CompressionContext>::AllocForBrotli,
687
          CompressionStream<CompressionContext>::FreeForZlib,
688
          static_cast<CompressionStream<CompressionContext>*>(wrap));
689
414
    if (err.IsError()) {
690
      wrap->EmitError(err);
691
      args.GetReturnValue().Set(false);
692
      return;
693
    }
694
695
414
    CHECK(args[0]->IsUint32Array());
696
414
    const uint32_t* data = reinterpret_cast<uint32_t*>(Buffer::Data(args[0]));
697
828
    size_t len = args[0].As<Uint32Array>()->Length();
698
699
4130
    for (int i = 0; static_cast<size_t>(i) < len; i++) {
700
3718
      if (data[i] == static_cast<uint32_t>(-1))
701
3692
        continue;
702
26
      err = wrap->context()->SetParams(i, data[i]);
703
26
      if (err.IsError()) {
704
2
        wrap->EmitError(err);
705
2
        args.GetReturnValue().Set(false);
706
2
        return;
707
      }
708
    }
709
710
824
    args.GetReturnValue().Set(true);
711
  }
712
713
  static void Params(const FunctionCallbackInfo<Value>& args) {
714
    // Currently a no-op, and not accessed from JS land.
715
    // At some point Brotli may support changing parameters on the fly,
716
    // in which case we can implement this and a JS equivalent similar to
717
    // the zlib Params() function.
718
  }
719
720
  SET_MEMORY_INFO_NAME(BrotliCompressionStream)
721
  SET_SELF_SIZE(BrotliCompressionStream)
722
};
723
724
using BrotliEncoderStream = BrotliCompressionStream<BrotliEncoderContext>;
725
using BrotliDecoderStream = BrotliCompressionStream<BrotliDecoderContext>;
726
727
1956
void ZlibContext::Close() {
728
  {
729
1956
    Mutex::ScopedLock lock(mutex_);
730
1956
    if (!zlib_init_done_) {
731
154
      dictionary_.clear();
732
154
      mode_ = NONE;
733
154
      return;
734
    }
735
  }
736
737
1802
  CHECK_LE(mode_, UNZIP);
738
739
1802
  int status = Z_OK;
740

1802
  if (mode_ == DEFLATE || mode_ == GZIP || mode_ == DEFLATERAW) {
741
405
    status = deflateEnd(&strm_);
742

1397
  } else if (mode_ == INFLATE || mode_ == GUNZIP || mode_ == INFLATERAW ||
743
835
             mode_ == UNZIP) {
744
562
    status = inflateEnd(&strm_);
745
  }
746
747

1802
  CHECK(status == Z_OK || status == Z_DATA_ERROR);
748
1802
  mode_ = NONE;
749
750
1802
  dictionary_.clear();
751
}
752
753
754
7451
void ZlibContext::DoThreadPoolWork() {
755
7451
  bool first_init_call = InitZlib();
756

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

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

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

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

7451
  switch (err_) {
892
6102
  case Z_OK:
893
  case Z_BUF_ERROR:
894

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

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

764
    CHECK(
961
        (window_bits >= Z_MIN_WINDOWBITS && window_bits <= Z_MAX_WINDOWBITS) &&
962
        "invalid windowBits");
963
  }
964
965

1120
  CHECK((level >= Z_MIN_LEVEL && level <= Z_MAX_LEVEL) &&
966
    "invalid compression level");
967
968

1120
  CHECK((mem_level >= Z_MIN_MEMLEVEL && mem_level <= Z_MAX_MEMLEVEL) &&
969
        "invalid memlevel");
970
971




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

1120
  if (mode_ == GZIP || mode_ == GUNZIP) {
986
432
    window_bits_ += 16;
987
  }
988
989
1120
  if (mode_ == UNZIP) {
990
215
    window_bits_ += 32;
991
  }
992
993

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

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

3
  if (err_ != Z_OK && err_ != Z_BUF_ERROR) {
1089
    return ErrorForMessage("Failed to set parameters");
1090
  }
1091
1092
3
  return CompressionError {};
1093
}
1094
1095
1096
1340
void BrotliContext::SetBuffers(char* in, uint32_t in_len,
1097
                               char* out, uint32_t out_len) {
1098
1340
  next_in_ = reinterpret_cast<uint8_t*>(in);
1099
1340
  next_out_ = reinterpret_cast<uint8_t*>(out);
1100
1340
  avail_in_ = in_len;
1101
1340
  avail_out_ = out_len;
1102
1340
}
1103
1104
1105
1340
void BrotliContext::SetFlush(int flush) {
1106
1340
  flush_ = static_cast<BrotliEncoderOperation>(flush);
1107
1340
}
1108
1109
1110
1339
void BrotliContext::GetAfterWriteOffsets(uint32_t* avail_in,
1111
                                         uint32_t* avail_out) const {
1112
1339
  *avail_in = avail_in_;
1113
1339
  *avail_out = avail_out_;
1114
1339
}
1115
1116
1117
332
void BrotliEncoderContext::DoThreadPoolWork() {
1118
332
  CHECK_EQ(mode_, BROTLI_ENCODE);
1119
332
  CHECK(state_);
1120
332
  const uint8_t* next_in = next_in_;
1121
332
  last_result_ = BrotliEncoderCompressStream(state_.get(),
1122
                                             flush_,
1123
                                             &avail_in_,
1124
                                             &next_in,
1125
                                             &avail_out_,
1126
                                             &next_out_,
1127
332
                                             nullptr);
1128
332
  next_in_ += next_in - next_in_;
1129
332
}
1130
1131
1132
206
void BrotliEncoderContext::Close() {
1133
206
  state_.reset();
1134
206
  mode_ = NONE;
1135
206
}
1136
1137
105
CompressionError BrotliEncoderContext::Init(brotli_alloc_func alloc,
1138
                                            brotli_free_func free,
1139
                                            void* opaque) {
1140
105
  alloc_ = alloc;
1141
105
  free_ = free;
1142
105
  alloc_opaque_ = opaque;
1143
105
  state_.reset(BrotliEncoderCreateInstance(alloc, free, opaque));
1144
105
  if (!state_) {
1145
    return CompressionError("Could not initialize Brotli instance",
1146
                            "ERR_ZLIB_INITIALIZATION_FAILED",
1147
                            -1);
1148
  } else {
1149
105
    return CompressionError {};
1150
  }
1151
}
1152
1153
CompressionError BrotliEncoderContext::ResetStream() {
1154
  return Init(alloc_, free_, alloc_opaque_);
1155
}
1156
1157
13
CompressionError BrotliEncoderContext::SetParams(int key, uint32_t value) {
1158
13
  if (!BrotliEncoderSetParameter(state_.get(),
1159
                                 static_cast<BrotliEncoderParameter>(key),
1160
                                 value)) {
1161
    return CompressionError("Setting parameter failed",
1162
                            "ERR_BROTLI_PARAM_SET_FAILED",
1163
1
                            -1);
1164
  } else {
1165
12
    return CompressionError {};
1166
  }
1167
}
1168
1169
332
CompressionError BrotliEncoderContext::GetErrorInfo() const {
1170
332
  if (!last_result_) {
1171
    return CompressionError("Compression failed",
1172
                            "ERR_BROTLI_COMPRESSION_FAILED",
1173
                            -1);
1174
  } else {
1175
332
    return CompressionError {};
1176
  }
1177
}
1178
1179
1180
202
void BrotliDecoderContext::Close() {
1181
202
  state_.reset();
1182
202
  mode_ = NONE;
1183
202
}
1184
1185
1008
void BrotliDecoderContext::DoThreadPoolWork() {
1186
1008
  CHECK_EQ(mode_, BROTLI_DECODE);
1187
1008
  CHECK(state_);
1188
1008
  const uint8_t* next_in = next_in_;
1189
1008
  last_result_ = BrotliDecoderDecompressStream(state_.get(),
1190
                                               &avail_in_,
1191
                                               &next_in,
1192
                                               &avail_out_,
1193
                                               &next_out_,
1194
                                               nullptr);
1195
1008
  next_in_ += next_in - next_in_;
1196
1008
  if (last_result_ == BROTLI_DECODER_RESULT_ERROR) {
1197
1
    error_ = BrotliDecoderGetErrorCode(state_.get());
1198
1
    error_string_ = std::string("ERR_") + BrotliDecoderErrorString(error_);
1199
  }
1200
1008
}
1201
1202
102
CompressionError BrotliDecoderContext::Init(brotli_alloc_func alloc,
1203
                                            brotli_free_func free,
1204
                                            void* opaque) {
1205
102
  alloc_ = alloc;
1206
102
  free_ = free;
1207
102
  alloc_opaque_ = opaque;
1208
102
  state_.reset(BrotliDecoderCreateInstance(alloc, free, opaque));
1209
102
  if (!state_) {
1210
    return CompressionError("Could not initialize Brotli instance",
1211
                            "ERR_ZLIB_INITIALIZATION_FAILED",
1212
                            -1);
1213
  } else {
1214
102
    return CompressionError {};
1215
  }
1216
}
1217
1218
CompressionError BrotliDecoderContext::ResetStream() {
1219
  return Init(alloc_, free_, alloc_opaque_);
1220
}
1221
1222
CompressionError BrotliDecoderContext::SetParams(int key, uint32_t value) {
1223
  if (!BrotliDecoderSetParameter(state_.get(),
1224
                                 static_cast<BrotliDecoderParameter>(key),
1225
                                 value)) {
1226
    return CompressionError("Setting parameter failed",
1227
                            "ERR_BROTLI_PARAM_SET_FAILED",
1228
                            -1);
1229
  } else {
1230
    return CompressionError {};
1231
  }
1232
}
1233
1234
1008
CompressionError BrotliDecoderContext::GetErrorInfo() const {
1235
1008
  if (error_ != BROTLI_DECODER_NO_ERROR) {
1236
    return CompressionError("Decompression failed",
1237
                            error_string_.c_str(),
1238
1
                            static_cast<int>(error_));
1239
1007
  } else if (flush_ == BROTLI_OPERATION_FINISH &&
1240
98
             last_result_ == BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT) {
1241
    // Match zlib's behaviour, as brotli doesn't have its own code for this.
1242
    return CompressionError("unexpected end of file",
1243
                            "Z_BUF_ERROR",
1244
                            Z_BUF_ERROR);
1245
  } else {
1246
1007
    return CompressionError {};
1247
  }
1248
}
1249
1250
1251
template <typename Stream>
1252
struct MakeClass {
1253
366
  static void Make(Environment* env, Local<Object> target, const char* name) {
1254
366
    Local<FunctionTemplate> z = env->NewFunctionTemplate(Stream::New);
1255
1256
732
    z->InstanceTemplate()->SetInternalFieldCount(
1257
        Stream::kInternalFieldCount);
1258
366
    z->Inherit(AsyncWrap::GetConstructorTemplate(env));
1259
1260
366
    env->SetProtoMethod(z, "write", Stream::template Write<true>);
1261
366
    env->SetProtoMethod(z, "writeSync", Stream::template Write<false>);
1262
366
    env->SetProtoMethod(z, "close", Stream::Close);
1263
1264
366
    env->SetProtoMethod(z, "init", Stream::Init);
1265
366
    env->SetProtoMethod(z, "params", Stream::Params);
1266
366
    env->SetProtoMethod(z, "reset", Stream::Reset);
1267
1268
366
    env->SetConstructorFunction(target, name, z);
1269
366
  }
1270
1271
28764
  static void Make(ExternalReferenceRegistry* registry) {
1272
28764
    registry->Register(Stream::New);
1273
28764
    registry->Register(Stream::template Write<true>);
1274
28764
    registry->Register(Stream::template Write<false>);
1275
28764
    registry->Register(Stream::Close);
1276
28764
    registry->Register(Stream::Init);
1277
28764
    registry->Register(Stream::Params);
1278
28764
    registry->Register(Stream::Reset);
1279
28764
  }
1280
};
1281
1282
61
void Initialize(Local<Object> target,
1283
                Local<Value> unused,
1284
                Local<Context> context,
1285
                void* priv) {
1286
61
  Environment* env = Environment::GetCurrent(context);
1287
1288
61
  MakeClass<ZlibStream>::Make(env, target, "Zlib");
1289
61
  MakeClass<BrotliEncoderStream>::Make(env, target, "BrotliEncoder");
1290
61
  MakeClass<BrotliDecoderStream>::Make(env, target, "BrotliDecoder");
1291
1292
61
  target->Set(env->context(),
1293
              FIXED_ONE_BYTE_STRING(env->isolate(), "ZLIB_VERSION"),
1294
183
              FIXED_ONE_BYTE_STRING(env->isolate(), ZLIB_VERSION)).Check();
1295
61
}
1296
1297
4794
void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
1298
4794
  MakeClass<ZlibStream>::Make(registry);
1299
4794
  MakeClass<BrotliEncoderStream>::Make(registry);
1300
4794
  MakeClass<BrotliDecoderStream>::Make(registry);
1301
4794
}
1302
1303
}  // anonymous namespace
1304
1305
611
void DefineZlibConstants(Local<Object> target) {
1306
1833
  NODE_DEFINE_CONSTANT(target, Z_NO_FLUSH);
1307
1833
  NODE_DEFINE_CONSTANT(target, Z_PARTIAL_FLUSH);
1308
1833
  NODE_DEFINE_CONSTANT(target, Z_SYNC_FLUSH);
1309
1833
  NODE_DEFINE_CONSTANT(target, Z_FULL_FLUSH);
1310
1833
  NODE_DEFINE_CONSTANT(target, Z_FINISH);
1311
1833
  NODE_DEFINE_CONSTANT(target, Z_BLOCK);
1312
1313
  // return/error codes
1314
1833
  NODE_DEFINE_CONSTANT(target, Z_OK);
1315
1833
  NODE_DEFINE_CONSTANT(target, Z_STREAM_END);
1316
1833
  NODE_DEFINE_CONSTANT(target, Z_NEED_DICT);
1317
1833
  NODE_DEFINE_CONSTANT(target, Z_ERRNO);
1318
1833
  NODE_DEFINE_CONSTANT(target, Z_STREAM_ERROR);
1319
1833
  NODE_DEFINE_CONSTANT(target, Z_DATA_ERROR);
1320
1833
  NODE_DEFINE_CONSTANT(target, Z_MEM_ERROR);
1321
1833
  NODE_DEFINE_CONSTANT(target, Z_BUF_ERROR);
1322
1833
  NODE_DEFINE_CONSTANT(target, Z_VERSION_ERROR);
1323
1324
1833
  NODE_DEFINE_CONSTANT(target, Z_NO_COMPRESSION);
1325
1833
  NODE_DEFINE_CONSTANT(target, Z_BEST_SPEED);
1326
1833
  NODE_DEFINE_CONSTANT(target, Z_BEST_COMPRESSION);
1327
1833
  NODE_DEFINE_CONSTANT(target, Z_DEFAULT_COMPRESSION);
1328
1833
  NODE_DEFINE_CONSTANT(target, Z_FILTERED);
1329
1833
  NODE_DEFINE_CONSTANT(target, Z_HUFFMAN_ONLY);
1330
1833
  NODE_DEFINE_CONSTANT(target, Z_RLE);
1331
1833
  NODE_DEFINE_CONSTANT(target, Z_FIXED);
1332
1833
  NODE_DEFINE_CONSTANT(target, Z_DEFAULT_STRATEGY);
1333
1833
  NODE_DEFINE_CONSTANT(target, ZLIB_VERNUM);
1334
1335
1833
  NODE_DEFINE_CONSTANT(target, DEFLATE);
1336
1833
  NODE_DEFINE_CONSTANT(target, INFLATE);
1337
1833
  NODE_DEFINE_CONSTANT(target, GZIP);
1338
1833
  NODE_DEFINE_CONSTANT(target, GUNZIP);
1339
1833
  NODE_DEFINE_CONSTANT(target, DEFLATERAW);
1340
1833
  NODE_DEFINE_CONSTANT(target, INFLATERAW);
1341
1833
  NODE_DEFINE_CONSTANT(target, UNZIP);
1342
1833
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODE);
1343
1833
  NODE_DEFINE_CONSTANT(target, BROTLI_ENCODE);
1344
1345
1833
  NODE_DEFINE_CONSTANT(target, Z_MIN_WINDOWBITS);
1346
1833
  NODE_DEFINE_CONSTANT(target, Z_MAX_WINDOWBITS);
1347
1833
  NODE_DEFINE_CONSTANT(target, Z_DEFAULT_WINDOWBITS);
1348
1833
  NODE_DEFINE_CONSTANT(target, Z_MIN_CHUNK);
1349
1833
  NODE_DEFINE_CONSTANT(target, Z_MAX_CHUNK);
1350
1833
  NODE_DEFINE_CONSTANT(target, Z_DEFAULT_CHUNK);
1351
1833
  NODE_DEFINE_CONSTANT(target, Z_MIN_MEMLEVEL);
1352
1833
  NODE_DEFINE_CONSTANT(target, Z_MAX_MEMLEVEL);
1353
1833
  NODE_DEFINE_CONSTANT(target, Z_DEFAULT_MEMLEVEL);
1354
1833
  NODE_DEFINE_CONSTANT(target, Z_MIN_LEVEL);
1355
1833
  NODE_DEFINE_CONSTANT(target, Z_MAX_LEVEL);
1356
1833
  NODE_DEFINE_CONSTANT(target, Z_DEFAULT_LEVEL);
1357
1358
  // Brotli constants
1359
1833
  NODE_DEFINE_CONSTANT(target, BROTLI_OPERATION_PROCESS);
1360
1833
  NODE_DEFINE_CONSTANT(target, BROTLI_OPERATION_FLUSH);
1361
1833
  NODE_DEFINE_CONSTANT(target, BROTLI_OPERATION_FINISH);
1362
1833
  NODE_DEFINE_CONSTANT(target, BROTLI_OPERATION_EMIT_METADATA);
1363
1833
  NODE_DEFINE_CONSTANT(target, BROTLI_PARAM_MODE);
1364
1833
  NODE_DEFINE_CONSTANT(target, BROTLI_MODE_GENERIC);
1365
1833
  NODE_DEFINE_CONSTANT(target, BROTLI_MODE_TEXT);
1366
1833
  NODE_DEFINE_CONSTANT(target, BROTLI_MODE_FONT);
1367
1833
  NODE_DEFINE_CONSTANT(target, BROTLI_DEFAULT_MODE);
1368
1833
  NODE_DEFINE_CONSTANT(target, BROTLI_PARAM_QUALITY);
1369
1833
  NODE_DEFINE_CONSTANT(target, BROTLI_MIN_QUALITY);
1370
1833
  NODE_DEFINE_CONSTANT(target, BROTLI_MAX_QUALITY);
1371
1833
  NODE_DEFINE_CONSTANT(target, BROTLI_DEFAULT_QUALITY);
1372
1833
  NODE_DEFINE_CONSTANT(target, BROTLI_PARAM_LGWIN);
1373
1833
  NODE_DEFINE_CONSTANT(target, BROTLI_MIN_WINDOW_BITS);
1374
1833
  NODE_DEFINE_CONSTANT(target, BROTLI_MAX_WINDOW_BITS);
1375
1833
  NODE_DEFINE_CONSTANT(target, BROTLI_LARGE_MAX_WINDOW_BITS);
1376
1833
  NODE_DEFINE_CONSTANT(target, BROTLI_DEFAULT_WINDOW);
1377
1833
  NODE_DEFINE_CONSTANT(target, BROTLI_PARAM_LGBLOCK);
1378
1833
  NODE_DEFINE_CONSTANT(target, BROTLI_MIN_INPUT_BLOCK_BITS);
1379
1833
  NODE_DEFINE_CONSTANT(target, BROTLI_MAX_INPUT_BLOCK_BITS);
1380
1833
  NODE_DEFINE_CONSTANT(target, BROTLI_PARAM_DISABLE_LITERAL_CONTEXT_MODELING);
1381
1833
  NODE_DEFINE_CONSTANT(target, BROTLI_PARAM_SIZE_HINT);
1382
1833
  NODE_DEFINE_CONSTANT(target, BROTLI_PARAM_LARGE_WINDOW);
1383
1833
  NODE_DEFINE_CONSTANT(target, BROTLI_PARAM_NPOSTFIX);
1384
1833
  NODE_DEFINE_CONSTANT(target, BROTLI_PARAM_NDIRECT);
1385
1833
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_RESULT_ERROR);
1386
1833
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_RESULT_SUCCESS);
1387
1833
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT);
1388
1833
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT);
1389
1833
  NODE_DEFINE_CONSTANT(target,
1390
      BROTLI_DECODER_PARAM_DISABLE_RING_BUFFER_REALLOCATION);
1391
1833
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_PARAM_LARGE_WINDOW);
1392
1833
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_NO_ERROR);
1393
1833
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_SUCCESS);
1394
1833
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_NEEDS_MORE_INPUT);
1395
1833
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_NEEDS_MORE_OUTPUT);
1396
1833
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_NIBBLE);
1397
1833
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_RESERVED);
1398
1833
  NODE_DEFINE_CONSTANT(target,
1399
      BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_META_NIBBLE);
1400
1833
  NODE_DEFINE_CONSTANT(target,
1401
      BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_ALPHABET);
1402
1833
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_SAME);
1403
1833
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_CL_SPACE);
1404
1833
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_HUFFMAN_SPACE);
1405
1833
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_CONTEXT_MAP_REPEAT);
1406
1833
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_1);
1407
1833
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_2);
1408
1833
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_TRANSFORM);
1409
1833
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_DICTIONARY);
1410
1833
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_WINDOW_BITS);
1411
1833
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_PADDING_1);
1412
1833
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_PADDING_2);
1413
1833
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_DISTANCE);
1414
1833
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_DICTIONARY_NOT_SET);
1415
1833
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_INVALID_ARGUMENTS);
1416
1833
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MODES);
1417
1833
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_ALLOC_TREE_GROUPS);
1418
1833
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MAP);
1419
1833
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_1);
1420
1833
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_2);
1421
1833
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_ALLOC_BLOCK_TYPE_TREES);
1422
1222
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_UNREACHABLE);
1423
611
}
1424
1425
}  // namespace node
1426
1427
4863
NODE_MODULE_CONTEXT_AWARE_INTERNAL(zlib, node::Initialize)
1428
4794
NODE_MODULE_EXTERNAL_REFERENCE(zlib, node::RegisterExternalReferences)