GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: node_zlib.cc Lines: 634 699 90.7 %
Date: 2022-05-21 04:15:56 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::HandleScope;
53
using v8::Int32;
54
using v8::Integer;
55
using v8::Local;
56
using v8::Object;
57
using v8::Uint32Array;
58
using v8::Value;
59
60
namespace {
61
62
// Fewer than 64 bytes per chunk is not recommended.
63
// Technically it could work with as few as 8, but even 64 bytes
64
// is low.  Usually a MB or more is best.
65
#define Z_MIN_CHUNK 64
66
#define Z_MAX_CHUNK std::numeric_limits<double>::infinity()
67
#define Z_DEFAULT_CHUNK (16 * 1024)
68
#define Z_MIN_MEMLEVEL 1
69
#define Z_MAX_MEMLEVEL 9
70
#define Z_DEFAULT_MEMLEVEL 8
71
#define Z_MIN_LEVEL -1
72
#define Z_MAX_LEVEL 9
73
#define Z_DEFAULT_LEVEL Z_DEFAULT_COMPRESSION
74
#define Z_MIN_WINDOWBITS 8
75
#define Z_MAX_WINDOWBITS 15
76
#define Z_DEFAULT_WINDOWBITS 15
77
78
#define ZLIB_ERROR_CODES(V)      \
79
  V(Z_OK)                        \
80
  V(Z_STREAM_END)                \
81
  V(Z_NEED_DICT)                 \
82
  V(Z_ERRNO)                     \
83
  V(Z_STREAM_ERROR)              \
84
  V(Z_DATA_ERROR)                \
85
  V(Z_MEM_ERROR)                 \
86
  V(Z_BUF_ERROR)                 \
87
  V(Z_VERSION_ERROR)             \
88
89
22
inline const char* ZlibStrerror(int err) {
90
#define V(code) if (err == code) return #code;
91




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

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

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

1124
    CHECK(args.Length() == 7 &&
582
      "init(windowBits, level, memLevel, strategy, writeResult, writeCallback,"
583
      " dictionary)");
584
585
    ZlibStream* wrap;
586
1124
    ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
587
588
1124
    Local<Context> context = args.GetIsolate()->GetCurrentContext();
589
590
    // windowBits is special. On the compression side, 0 is an invalid value.
591
    // But on the decompression side, a value of 0 for windowBits tells zlib
592
    // to use the window size in the zlib header of the compressed stream.
593
    uint32_t window_bits;
594
2248
    if (!args[0]->Uint32Value(context).To(&window_bits)) return;
595
596
    int32_t level;
597
2248
    if (!args[1]->Int32Value(context).To(&level)) return;
598
599
    uint32_t mem_level;
600
2248
    if (!args[2]->Uint32Value(context).To(&mem_level)) return;
601
602
    uint32_t strategy;
603
2248
    if (!args[3]->Uint32Value(context).To(&strategy)) return;
604
605
1124
    CHECK(args[4]->IsUint32Array());
606
2248
    Local<Uint32Array> array = args[4].As<Uint32Array>();
607
1124
    Local<ArrayBuffer> ab = array->Buffer();
608
    uint32_t* write_result = static_cast<uint32_t*>(
609
1124
        ab->GetBackingStore()->Data());
610
611
1124
    CHECK(args[5]->IsFunction());
612
1124
    Local<Function> write_js_callback = args[5].As<Function>();
613
614
2248
    std::vector<unsigned char> dictionary;
615
1124
    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
1124
    wrap->InitStream(write_result, write_js_callback);
624
625
2248
    AllocScope alloc_scope(wrap);
626
1124
    wrap->context()->SetAllocationFunctions(
627
        AllocForZlib, FreeForZlib, static_cast<CompressionStream*>(wrap));
628
2248
    wrap->context()->Init(level, window_bits, mem_level, strategy,
629
1124
                          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
414
  BrotliCompressionStream(Environment* env,
657
                          Local<Object> wrap,
658
                          node_zlib_mode mode)
659
414
    : CompressionStream<CompressionContext>(env, wrap) {
660
414
    context()->SetMode(mode);
661
414
  }
662
663
854
  inline CompressionContext* context() {
664
854
    return this->CompressionStream<CompressionContext>::context();
665
  }
666
  typedef typename CompressionStream<CompressionContext>::AllocScope AllocScope;
667
668
414
  static void New(const FunctionCallbackInfo<Value>& args) {
669
414
    Environment* env = Environment::GetCurrent(args);
670
414
    CHECK(args[0]->IsInt32());
671
414
    node_zlib_mode mode =
672
828
        static_cast<node_zlib_mode>(args[0].As<Int32>()->Value());
673
414
    new BrotliCompressionStream(env, args.This(), mode);
674
414
  }
675
676
414
  static void Init(const FunctionCallbackInfo<Value>& args) {
677
    BrotliCompressionStream* wrap;
678
416
    ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
679

414
    CHECK(args.Length() == 3 && "init(params, writeResult, writeCallback)");
680
681
414
    CHECK(args[1]->IsUint32Array());
682
414
    uint32_t* write_result = reinterpret_cast<uint32_t*>(Buffer::Data(args[1]));
683
684
414
    CHECK(args[2]->IsFunction());
685
414
    Local<Function> write_js_callback = args[2].As<Function>();
686
414
    wrap->InitStream(write_result, write_js_callback);
687
688
414
    AllocScope alloc_scope(wrap);
689
414
    CompressionError err =
690
        wrap->context()->Init(
691
          CompressionStream<CompressionContext>::AllocForBrotli,
692
          CompressionStream<CompressionContext>::FreeForZlib,
693
          static_cast<CompressionStream<CompressionContext>*>(wrap));
694
414
    if (err.IsError()) {
695
      wrap->EmitError(err);
696
      args.GetReturnValue().Set(false);
697
      return;
698
    }
699
700
414
    CHECK(args[0]->IsUint32Array());
701
414
    const uint32_t* data = reinterpret_cast<uint32_t*>(Buffer::Data(args[0]));
702
828
    size_t len = args[0].As<Uint32Array>()->Length();
703
704
4130
    for (int i = 0; static_cast<size_t>(i) < len; i++) {
705
3718
      if (data[i] == static_cast<uint32_t>(-1))
706
3692
        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
824
    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
1846
void ZlibContext::Close() {
733
  {
734
1846
    Mutex::ScopedLock lock(mutex_);
735
1846
    if (!zlib_init_done_) {
736
154
      dictionary_.clear();
737
154
      mode_ = NONE;
738
154
      return;
739
    }
740
  }
741
742
1692
  CHECK_LE(mode_, UNZIP);
743
744
1692
  int status = Z_OK;
745

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

1287
  } else if (mode_ == INFLATE || mode_ == GUNZIP || mode_ == INFLATERAW ||
748
835
             mode_ == UNZIP) {
749
452
    status = inflateEnd(&strm_);
750
  }
751
752

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

7505
  if (first_init_call && err_ != Z_OK) {
762
    return;
763
  }
764
765
7505
  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

7505
  switch (mode_) {
771
1450
    case DEFLATE:
772
    case GZIP:
773
    case DEFLATERAW:
774
1450
      err_ = deflate(&strm_, flush_);
775
1450
      break;
776
221
    case UNZIP:
777
221
      if (strm_.avail_in > 0) {
778
220
        next_expected_header_byte = strm_.next_in;
779
      }
780
781
221
      switch (gzip_id_bytes_read_) {
782
218
        case 0:
783
218
          if (next_expected_header_byte == nullptr) {
784
            break;
785
          }
786
787
218
          if (*next_expected_header_byte == GZIP_HEADER_ID1) {
788
212
            gzip_id_bytes_read_ = 1;
789
212
            next_expected_header_byte++;
790
791
212
            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
213
          if (next_expected_header_byte == nullptr) {
803
1
            break;
804
          }
805
806
212
          if (*next_expected_header_byte == GZIP_HEADER_ID2) {
807
212
            gzip_id_bytes_read_ = 2;
808
212
            mode_ = GUNZIP;
809
          } else {
810
            // There is no actual difference between INFLATE and INFLATERAW
811
            // (after initialization).
812
            mode_ = INFLATE;
813
          }
814
815
212
          break;
816
        default:
817
          CHECK(0 && "invalid number of gzip magic number bytes read");
818
6055
      }
819
820
      // fallthrough
821
    case INFLATE:
822
    case GUNZIP:
823
    case INFLATERAW:
824
6055
      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
16525
      if (mode_ != INFLATERAW &&
829

6069
          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
6728
      while (strm_.avail_in > 0 &&
847
633
             mode_ == GUNZIP &&
848

6664
             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
6055
      break;
859
    default:
860
      UNREACHABLE();
861
  }
862
}
863
864
865
7505
void ZlibContext::SetBuffers(const char* in, uint32_t in_len,
866
                             char* out, uint32_t out_len) {
867
7505
  strm_.avail_in = in_len;
868
7505
  strm_.next_in = const_cast<Bytef*>(reinterpret_cast<const Bytef*>(in));
869
7505
  strm_.avail_out = out_len;
870
7505
  strm_.next_out = reinterpret_cast<Bytef*>(out);
871
7505
}
872
873
874
7505
void ZlibContext::SetFlush(int flush) {
875
7505
  flush_ = flush;
876
7505
}
877
878
879
7483
void ZlibContext::GetAfterWriteOffsets(uint32_t* avail_in,
880
                                       uint32_t* avail_out) const {
881
7483
  *avail_in = strm_.avail_in;
882
7483
  *avail_out = strm_.avail_out;
883
7483
}
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
7505
CompressionError ZlibContext::GetErrorInfo() const {
895
  // Acceptable error states depend on the type of zlib stream.
896

7505
  switch (err_) {
897
6148
  case Z_OK:
898
  case Z_BUF_ERROR:
899

6148
    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
7483
    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
7483
  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
1124
void ZlibContext::SetAllocationFunctions(alloc_func alloc,
950
                                         free_func free,
951
                                         void* opaque) {
952
1124
  strm_.zalloc = alloc;
953
1124
  strm_.zfree = free;
954
1124
  strm_.opaque = opaque;
955
1124
}
956
957
958
1124
void ZlibContext::Init(
959
    int level, int window_bits, int mem_level, int strategy,
960
    std::vector<unsigned char>&& dictionary) {
961
1124
  if (!((window_bits == 0) &&
962
360
        (mode_ == INFLATE ||
963
276
         mode_ == GUNZIP ||
964
195
         mode_ == UNZIP))) {
965

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

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

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




1124
  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
1124
  level_ = level;
982
1124
  window_bits_ = window_bits;
983
1124
  mem_level_ = mem_level;
984
1124
  strategy_ = strategy;
985
986
1124
  flush_ = Z_NO_FLUSH;
987
988
1124
  err_ = Z_OK;
989
990

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

1124
  if (mode_ == DEFLATERAW || mode_ == INFLATERAW) {
999
219
    window_bits_ *= -1;
1000
  }
1001
1002
1124
  dictionary_ = std::move(dictionary);
1003
1124
}
1004
1005
7542
bool ZlibContext::InitZlib() {
1006
15084
  Mutex::ScopedLock lock(mutex_);
1007
7542
  if (zlib_init_done_) {
1008
6570
    return false;
1009
  }
1010
1011
972
  switch (mode_) {
1012
405
    case DEFLATE:
1013
    case GZIP:
1014
    case DEFLATERAW:
1015
405
      err_ = deflateInit2(&strm_,
1016
                          level_,
1017
                          Z_DEFLATED,
1018
                          window_bits_,
1019
                          mem_level_,
1020
                          strategy_);
1021
405
      break;
1022
567
    case INFLATE:
1023
    case GUNZIP:
1024
    case INFLATERAW:
1025
    case UNZIP:
1026
567
      err_ = inflateInit2(&strm_, window_bits_);
1027
567
      break;
1028
    default:
1029
      UNREACHABLE();
1030
  }
1031
1032
972
  if (err_ != Z_OK) {
1033
    dictionary_.clear();
1034
    mode_ = NONE;
1035
    return true;
1036
  }
1037
1038
972
  SetDictionary();
1039
972
  zlib_init_done_ = true;
1040
972
  return true;
1041
}
1042
1043
1044
1006
CompressionError ZlibContext::SetDictionary() {
1045
1006
  if (dictionary_.empty())
1046
944
    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
1339
void BrotliContext::SetBuffers(const char* in, uint32_t in_len,
1102
                               char* out, uint32_t out_len) {
1103
1339
  next_in_ = reinterpret_cast<const uint8_t*>(in);
1104
1339
  next_out_ = reinterpret_cast<uint8_t*>(out);
1105
1339
  avail_in_ = in_len;
1106
1339
  avail_out_ = out_len;
1107
1339
}
1108
1109
1110
1339
void BrotliContext::SetFlush(int flush) {
1111
1339
  flush_ = static_cast<BrotliEncoderOperation>(flush);
1112
1339
}
1113
1114
1115
1338
void BrotliContext::GetAfterWriteOffsets(uint32_t* avail_in,
1116
                                         uint32_t* avail_out) const {
1117
1338
  *avail_in = avail_in_;
1118
1338
  *avail_out = avail_out_;
1119
1338
}
1120
1121
1122
331
void BrotliEncoderContext::DoThreadPoolWork() {
1123
331
  CHECK_EQ(mode_, BROTLI_ENCODE);
1124
331
  CHECK(state_);
1125
331
  const uint8_t* next_in = next_in_;
1126
331
  last_result_ = BrotliEncoderCompressStream(state_.get(),
1127
                                             flush_,
1128
                                             &avail_in_,
1129
                                             &next_in,
1130
                                             &avail_out_,
1131
                                             &next_out_,
1132
331
                                             nullptr);
1133
331
  next_in_ += next_in - next_in_;
1134
331
}
1135
1136
1137
206
void BrotliEncoderContext::Close() {
1138
206
  state_.reset();
1139
206
  mode_ = NONE;
1140
206
}
1141
1142
105
CompressionError BrotliEncoderContext::Init(brotli_alloc_func alloc,
1143
                                            brotli_free_func free,
1144
                                            void* opaque) {
1145
105
  alloc_ = alloc;
1146
105
  free_ = free;
1147
105
  alloc_opaque_ = opaque;
1148
105
  state_.reset(BrotliEncoderCreateInstance(alloc, free, opaque));
1149
105
  if (!state_) {
1150
    return CompressionError("Could not initialize Brotli instance",
1151
                            "ERR_ZLIB_INITIALIZATION_FAILED",
1152
                            -1);
1153
  } else {
1154
105
    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
331
CompressionError BrotliEncoderContext::GetErrorInfo() const {
1175
331
  if (!last_result_) {
1176
    return CompressionError("Compression failed",
1177
                            "ERR_BROTLI_COMPRESSION_FAILED",
1178
                            -1);
1179
  } else {
1180
331
    return CompressionError {};
1181
  }
1182
}
1183
1184
1185
202
void BrotliDecoderContext::Close() {
1186
202
  state_.reset();
1187
202
  mode_ = NONE;
1188
202
}
1189
1190
1008
void BrotliDecoderContext::DoThreadPoolWork() {
1191
1008
  CHECK_EQ(mode_, BROTLI_DECODE);
1192
1008
  CHECK(state_);
1193
1008
  const uint8_t* next_in = next_in_;
1194
1008
  last_result_ = BrotliDecoderDecompressStream(state_.get(),
1195
                                               &avail_in_,
1196
                                               &next_in,
1197
                                               &avail_out_,
1198
                                               &next_out_,
1199
                                               nullptr);
1200
1008
  next_in_ += next_in - next_in_;
1201
1008
  if (last_result_ == BROTLI_DECODER_RESULT_ERROR) {
1202
1
    error_ = BrotliDecoderGetErrorCode(state_.get());
1203
1
    error_string_ = std::string("ERR_") + BrotliDecoderErrorString(error_);
1204
  }
1205
1008
}
1206
1207
102
CompressionError BrotliDecoderContext::Init(brotli_alloc_func alloc,
1208
                                            brotli_free_func free,
1209
                                            void* opaque) {
1210
102
  alloc_ = alloc;
1211
102
  free_ = free;
1212
102
  alloc_opaque_ = opaque;
1213
102
  state_.reset(BrotliDecoderCreateInstance(alloc, free, opaque));
1214
102
  if (!state_) {
1215
    return CompressionError("Could not initialize Brotli instance",
1216
                            "ERR_ZLIB_INITIALIZATION_FAILED",
1217
                            -1);
1218
  } else {
1219
102
    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
1008
CompressionError BrotliDecoderContext::GetErrorInfo() const {
1240
1008
  if (error_ != BROTLI_DECODER_NO_ERROR) {
1241
    return CompressionError("Decompression failed",
1242
                            error_string_.c_str(),
1243
1
                            static_cast<int>(error_));
1244
1007
  } else if (flush_ == BROTLI_OPERATION_FINISH &&
1245
98
             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
1007
    return CompressionError {};
1252
  }
1253
}
1254
1255
1256
template <typename Stream>
1257
struct MakeClass {
1258
438
  static void Make(Environment* env, Local<Object> target, const char* name) {
1259
438
    Local<FunctionTemplate> z = env->NewFunctionTemplate(Stream::New);
1260
1261
876
    z->InstanceTemplate()->SetInternalFieldCount(
1262
        Stream::kInternalFieldCount);
1263
438
    z->Inherit(AsyncWrap::GetConstructorTemplate(env));
1264
1265
438
    env->SetProtoMethod(z, "write", Stream::template Write<true>);
1266
438
    env->SetProtoMethod(z, "writeSync", Stream::template Write<false>);
1267
438
    env->SetProtoMethod(z, "close", Stream::Close);
1268
1269
438
    env->SetProtoMethod(z, "init", Stream::Init);
1270
438
    env->SetProtoMethod(z, "params", Stream::Params);
1271
438
    env->SetProtoMethod(z, "reset", Stream::Reset);
1272
1273
438
    env->SetConstructorFunction(target, name, z);
1274
438
  }
1275
1276
31104
  static void Make(ExternalReferenceRegistry* registry) {
1277
31104
    registry->Register(Stream::New);
1278
31104
    registry->Register(Stream::template Write<true>);
1279
31104
    registry->Register(Stream::template Write<false>);
1280
31104
    registry->Register(Stream::Close);
1281
31104
    registry->Register(Stream::Init);
1282
31104
    registry->Register(Stream::Params);
1283
31104
    registry->Register(Stream::Reset);
1284
31104
  }
1285
};
1286
1287
73
void Initialize(Local<Object> target,
1288
                Local<Value> unused,
1289
                Local<Context> context,
1290
                void* priv) {
1291
73
  Environment* env = Environment::GetCurrent(context);
1292
1293
73
  MakeClass<ZlibStream>::Make(env, target, "Zlib");
1294
73
  MakeClass<BrotliEncoderStream>::Make(env, target, "BrotliEncoder");
1295
73
  MakeClass<BrotliDecoderStream>::Make(env, target, "BrotliDecoder");
1296
1297
73
  target->Set(env->context(),
1298
              FIXED_ONE_BYTE_STRING(env->isolate(), "ZLIB_VERSION"),
1299
219
              FIXED_ONE_BYTE_STRING(env->isolate(), ZLIB_VERSION)).Check();
1300
73
}
1301
1302
5184
void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
1303
5184
  MakeClass<ZlibStream>::Make(registry);
1304
5184
  MakeClass<BrotliEncoderStream>::Make(registry);
1305
5184
  MakeClass<BrotliDecoderStream>::Make(registry);
1306
5184
}
1307
1308
}  // anonymous namespace
1309
1310
856
void DefineZlibConstants(Local<Object> target) {
1311
2568
  NODE_DEFINE_CONSTANT(target, Z_NO_FLUSH);
1312
2568
  NODE_DEFINE_CONSTANT(target, Z_PARTIAL_FLUSH);
1313
2568
  NODE_DEFINE_CONSTANT(target, Z_SYNC_FLUSH);
1314
2568
  NODE_DEFINE_CONSTANT(target, Z_FULL_FLUSH);
1315
2568
  NODE_DEFINE_CONSTANT(target, Z_FINISH);
1316
2568
  NODE_DEFINE_CONSTANT(target, Z_BLOCK);
1317
1318
  // return/error codes
1319
2568
  NODE_DEFINE_CONSTANT(target, Z_OK);
1320
2568
  NODE_DEFINE_CONSTANT(target, Z_STREAM_END);
1321
2568
  NODE_DEFINE_CONSTANT(target, Z_NEED_DICT);
1322
2568
  NODE_DEFINE_CONSTANT(target, Z_ERRNO);
1323
2568
  NODE_DEFINE_CONSTANT(target, Z_STREAM_ERROR);
1324
2568
  NODE_DEFINE_CONSTANT(target, Z_DATA_ERROR);
1325
2568
  NODE_DEFINE_CONSTANT(target, Z_MEM_ERROR);
1326
2568
  NODE_DEFINE_CONSTANT(target, Z_BUF_ERROR);
1327
2568
  NODE_DEFINE_CONSTANT(target, Z_VERSION_ERROR);
1328
1329
2568
  NODE_DEFINE_CONSTANT(target, Z_NO_COMPRESSION);
1330
2568
  NODE_DEFINE_CONSTANT(target, Z_BEST_SPEED);
1331
2568
  NODE_DEFINE_CONSTANT(target, Z_BEST_COMPRESSION);
1332
2568
  NODE_DEFINE_CONSTANT(target, Z_DEFAULT_COMPRESSION);
1333
2568
  NODE_DEFINE_CONSTANT(target, Z_FILTERED);
1334
2568
  NODE_DEFINE_CONSTANT(target, Z_HUFFMAN_ONLY);
1335
2568
  NODE_DEFINE_CONSTANT(target, Z_RLE);
1336
2568
  NODE_DEFINE_CONSTANT(target, Z_FIXED);
1337
2568
  NODE_DEFINE_CONSTANT(target, Z_DEFAULT_STRATEGY);
1338
2568
  NODE_DEFINE_CONSTANT(target, ZLIB_VERNUM);
1339
1340
2568
  NODE_DEFINE_CONSTANT(target, DEFLATE);
1341
2568
  NODE_DEFINE_CONSTANT(target, INFLATE);
1342
2568
  NODE_DEFINE_CONSTANT(target, GZIP);
1343
2568
  NODE_DEFINE_CONSTANT(target, GUNZIP);
1344
2568
  NODE_DEFINE_CONSTANT(target, DEFLATERAW);
1345
2568
  NODE_DEFINE_CONSTANT(target, INFLATERAW);
1346
2568
  NODE_DEFINE_CONSTANT(target, UNZIP);
1347
2568
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODE);
1348
2568
  NODE_DEFINE_CONSTANT(target, BROTLI_ENCODE);
1349
1350
2568
  NODE_DEFINE_CONSTANT(target, Z_MIN_WINDOWBITS);
1351
2568
  NODE_DEFINE_CONSTANT(target, Z_MAX_WINDOWBITS);
1352
2568
  NODE_DEFINE_CONSTANT(target, Z_DEFAULT_WINDOWBITS);
1353
2568
  NODE_DEFINE_CONSTANT(target, Z_MIN_CHUNK);
1354
2568
  NODE_DEFINE_CONSTANT(target, Z_MAX_CHUNK);
1355
2568
  NODE_DEFINE_CONSTANT(target, Z_DEFAULT_CHUNK);
1356
2568
  NODE_DEFINE_CONSTANT(target, Z_MIN_MEMLEVEL);
1357
2568
  NODE_DEFINE_CONSTANT(target, Z_MAX_MEMLEVEL);
1358
2568
  NODE_DEFINE_CONSTANT(target, Z_DEFAULT_MEMLEVEL);
1359
2568
  NODE_DEFINE_CONSTANT(target, Z_MIN_LEVEL);
1360
2568
  NODE_DEFINE_CONSTANT(target, Z_MAX_LEVEL);
1361
2568
  NODE_DEFINE_CONSTANT(target, Z_DEFAULT_LEVEL);
1362
1363
  // Brotli constants
1364
2568
  NODE_DEFINE_CONSTANT(target, BROTLI_OPERATION_PROCESS);
1365
2568
  NODE_DEFINE_CONSTANT(target, BROTLI_OPERATION_FLUSH);
1366
2568
  NODE_DEFINE_CONSTANT(target, BROTLI_OPERATION_FINISH);
1367
2568
  NODE_DEFINE_CONSTANT(target, BROTLI_OPERATION_EMIT_METADATA);
1368
2568
  NODE_DEFINE_CONSTANT(target, BROTLI_PARAM_MODE);
1369
2568
  NODE_DEFINE_CONSTANT(target, BROTLI_MODE_GENERIC);
1370
2568
  NODE_DEFINE_CONSTANT(target, BROTLI_MODE_TEXT);
1371
2568
  NODE_DEFINE_CONSTANT(target, BROTLI_MODE_FONT);
1372
2568
  NODE_DEFINE_CONSTANT(target, BROTLI_DEFAULT_MODE);
1373
2568
  NODE_DEFINE_CONSTANT(target, BROTLI_PARAM_QUALITY);
1374
2568
  NODE_DEFINE_CONSTANT(target, BROTLI_MIN_QUALITY);
1375
2568
  NODE_DEFINE_CONSTANT(target, BROTLI_MAX_QUALITY);
1376
2568
  NODE_DEFINE_CONSTANT(target, BROTLI_DEFAULT_QUALITY);
1377
2568
  NODE_DEFINE_CONSTANT(target, BROTLI_PARAM_LGWIN);
1378
2568
  NODE_DEFINE_CONSTANT(target, BROTLI_MIN_WINDOW_BITS);
1379
2568
  NODE_DEFINE_CONSTANT(target, BROTLI_MAX_WINDOW_BITS);
1380
2568
  NODE_DEFINE_CONSTANT(target, BROTLI_LARGE_MAX_WINDOW_BITS);
1381
2568
  NODE_DEFINE_CONSTANT(target, BROTLI_DEFAULT_WINDOW);
1382
2568
  NODE_DEFINE_CONSTANT(target, BROTLI_PARAM_LGBLOCK);
1383
2568
  NODE_DEFINE_CONSTANT(target, BROTLI_MIN_INPUT_BLOCK_BITS);
1384
2568
  NODE_DEFINE_CONSTANT(target, BROTLI_MAX_INPUT_BLOCK_BITS);
1385
2568
  NODE_DEFINE_CONSTANT(target, BROTLI_PARAM_DISABLE_LITERAL_CONTEXT_MODELING);
1386
2568
  NODE_DEFINE_CONSTANT(target, BROTLI_PARAM_SIZE_HINT);
1387
2568
  NODE_DEFINE_CONSTANT(target, BROTLI_PARAM_LARGE_WINDOW);
1388
2568
  NODE_DEFINE_CONSTANT(target, BROTLI_PARAM_NPOSTFIX);
1389
2568
  NODE_DEFINE_CONSTANT(target, BROTLI_PARAM_NDIRECT);
1390
2568
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_RESULT_ERROR);
1391
2568
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_RESULT_SUCCESS);
1392
2568
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT);
1393
2568
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT);
1394
2568
  NODE_DEFINE_CONSTANT(target,
1395
      BROTLI_DECODER_PARAM_DISABLE_RING_BUFFER_REALLOCATION);
1396
2568
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_PARAM_LARGE_WINDOW);
1397
2568
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_NO_ERROR);
1398
2568
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_SUCCESS);
1399
2568
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_NEEDS_MORE_INPUT);
1400
2568
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_NEEDS_MORE_OUTPUT);
1401
2568
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_NIBBLE);
1402
2568
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_RESERVED);
1403
2568
  NODE_DEFINE_CONSTANT(target,
1404
      BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_META_NIBBLE);
1405
2568
  NODE_DEFINE_CONSTANT(target,
1406
      BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_ALPHABET);
1407
2568
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_SAME);
1408
2568
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_CL_SPACE);
1409
2568
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_HUFFMAN_SPACE);
1410
2568
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_CONTEXT_MAP_REPEAT);
1411
2568
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_1);
1412
2568
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_2);
1413
2568
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_TRANSFORM);
1414
2568
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_DICTIONARY);
1415
2568
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_WINDOW_BITS);
1416
2568
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_PADDING_1);
1417
2568
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_PADDING_2);
1418
2568
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_DISTANCE);
1419
2568
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_DICTIONARY_NOT_SET);
1420
2568
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_INVALID_ARGUMENTS);
1421
2568
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MODES);
1422
2568
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_ALLOC_TREE_GROUPS);
1423
2568
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MAP);
1424
2568
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_1);
1425
2568
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_2);
1426
2568
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_ALLOC_BLOCK_TYPE_TREES);
1427
1712
  NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_UNREACHABLE);
1428
856
}
1429
1430
}  // namespace node
1431
1432
5252
NODE_MODULE_CONTEXT_AWARE_INTERNAL(zlib, node::Initialize)
1433
5184
NODE_MODULE_EXTERNAL_REFERENCE(zlib, node::RegisterExternalReferences)