GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: node_zlib.cc Lines: 635 700 90.7 %
Date: 2022-09-11 04:22:34 Branches: 253 366 69.1 %

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::HandleScope;
53
using v8::Int32;
54
using v8::Integer;
55
using v8::Isolate;
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
constexpr uint8_t GZIP_HEADER_ID1 = 0x1f;
111
constexpr uint8_t 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
10355
  CompressionError() = default;
122
123
  const char* message = nullptr;
124
  const char* code = nullptr;
125
  int err = 0;
126
127
9291
  inline bool IsError() const { return code != nullptr; }
128
};
129
130
class ZlibContext final : public MemoryRetainer {
131
 public:
132
1220
  ZlibContext() = default;
133
134
  // Streaming-related, should be available for all compression libraries:
135
  void Close();
136
  void DoThreadPoolWork();
137
  void SetBuffers(const 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
1220
  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
231
  BrotliContext() = default;
185
186
  void SetBuffers(const 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
231
  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
  const 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
  enum InternalFields {
255
    kCompressionStreamBaseField = AsyncWrap::kInternalFieldCount,
256
    kWriteJSCallback,
257
    kInternalFieldCount
258
  };
259
260
2902
  CompressionStream(Environment* env, Local<Object> wrap)
261
      : AsyncWrap(env, wrap, AsyncWrap::PROVIDER_ZLIB),
262
        ThreadPoolWork(env),
263
2902
        write_result_(nullptr) {
264
2902
    MakeWeak();
265
2902
  }
266
267
2660
  ~CompressionStream() override {
268
    CHECK(!write_in_progress_);
269
2660
    Close();
270
2660
    CHECK_EQ(zlib_memory_, 0);
271
2660
    CHECK_EQ(unreported_allocations_, 0);
272
5320
  }
273
274
5038
  void Close() {
275
5038
    if (write_in_progress_) {
276
60
      pending_close_ = true;
277
60
      return;
278
    }
279
280
4978
    pending_close_ = false;
281
4978
    closed_ = true;
282
4978
    CHECK(init_done_ && "close before init");
283
284
9956
    AllocScope alloc_scope(this);
285
4978
    ctx_.Close();
286
  }
287
288
289
2318
  static void Close(const FunctionCallbackInfo<Value>& args) {
290
    CompressionStream* ctx;
291
2318
    ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
292
2318
    ctx->Close();
293
  }
294
295
296
  // write(flush, in, in_off, in_len, out, out_off, out_len)
297
  template <bool async>
298
18060
  static void Write(const FunctionCallbackInfo<Value>& args) {
299
18060
    Environment* env = Environment::GetCurrent(args);
300
18060
    Local<Context> context = env->context();
301
18060
    CHECK_EQ(args.Length(), 7);
302
303
    uint32_t in_off, in_len, out_off, out_len, flush;
304
    const char* in;
305
    char* out;
306
307

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

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

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

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

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

1879
  if (mode_ == DEFLATE || mode_ == GZIP || mode_ == DEFLATERAW) {
746
453
    status = deflateEnd(&strm_);
747

1426
  } else if (mode_ == INFLATE || mode_ == GUNZIP || mode_ == INFLATERAW ||
748
932
             mode_ == UNZIP) {
749
494
    status = inflateEnd(&strm_);
750
  }
751
752

1879
  CHECK(status == Z_OK || status == Z_DATA_ERROR);
753
1879
  mode_ = NONE;
754
755
1879
  dictionary_.clear();
756
}
757
758
759
7655
void ZlibContext::DoThreadPoolWork() {
760
7655
  bool first_init_call = InitZlib();
761

7655
  if (first_init_call && err_ != Z_OK) {
762
    return;
763
  }
764
765
7655
  const Bytef* next_expected_header_byte = nullptr;
766
767
  // If the avail_out is left at 0, then it means that it ran out
768
  // of room.  If there was avail_out left over, then it means
769
  // that all of the input was consumed.
770

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

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

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

7655
  switch (err_) {
897
6177
  case Z_OK:
898
  case Z_BUF_ERROR:
899

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

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

830
    CHECK(
966
        (window_bits >= Z_MIN_WINDOWBITS && window_bits <= Z_MAX_WINDOWBITS) &&
967
        "invalid windowBits");
968
  }
969
970

1220
  CHECK((level >= Z_MIN_LEVEL && level <= Z_MAX_LEVEL) &&
971
    "invalid compression level");
972
973

1220
  CHECK((mem_level >= Z_MIN_MEMLEVEL && mem_level <= Z_MAX_MEMLEVEL) &&
974
        "invalid memlevel");
975
976




1220
  CHECK((strategy == Z_FILTERED || strategy == Z_HUFFMAN_ONLY ||
977
         strategy == Z_RLE || strategy == Z_FIXED ||
978
         strategy == Z_DEFAULT_STRATEGY) &&
979
        "invalid strategy");
980
981
1220
  level_ = level;
982
1220
  window_bits_ = window_bits;
983
1220
  mem_level_ = mem_level;
984
1220
  strategy_ = strategy;
985
986
1220
  flush_ = Z_NO_FLUSH;
987
988
1220
  err_ = Z_OK;
989
990

1220
  if (mode_ == GZIP || mode_ == GUNZIP) {
991
468
    window_bits_ += 16;
992
  }
993
994
1220
  if (mode_ == UNZIP) {
995
230
    window_bits_ += 32;
996
  }
997
998

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

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

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