GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: node_zlib.cc Lines: 619 684 90.5 %
Date: 2021-08-24 04:12:49 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 "threadpoolwork-inl.h"
29
#include "util-inl.h"
30
31
#include "v8.h"
32
33
#include "brotli/encode.h"
34
#include "brotli/decode.h"
35
#include "zlib.h"
36
37
#include <sys/types.h>
38
39
#include <cerrno>
40
#include <cstdlib>
41
#include <cstring>
42
#include <atomic>
43
44
namespace node {
45
46
using v8::ArrayBuffer;
47
using v8::Context;
48
using v8::Function;
49
using v8::FunctionCallbackInfo;
50
using v8::FunctionTemplate;
51
using v8::Global;
52
using v8::HandleScope;
53
using v8::Int32;
54
using v8::Integer;
55
using v8::Local;
56
using v8::Object;
57
using v8::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
#define GZIP_HEADER_ID1 0x1f
110
#define 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
9989
  CompressionError() = default;
121
122
  const char* message = nullptr;
123
  const char* code = nullptr;
124
  int err = 0;
125
126
9037
  inline bool IsError() const { return code != nullptr; }
127
};
128
129
class ZlibContext : public MemoryRetainer {
130
 public:
131
1108
  ZlibContext() = default;
132
133
  // Streaming-related, should be available for all compression libraries:
134
  void Close();
135
  void DoThreadPoolWork();
136
  void SetBuffers(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
1108
  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(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
  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
2630
  CompressionStream(Environment* env, Local<Object> wrap)
254
      : AsyncWrap(env, wrap, AsyncWrap::PROVIDER_ZLIB),
255
        ThreadPoolWork(env),
256
2630
        write_result_(nullptr) {
257
2630
    MakeWeak();
258
2630
  }
259
260
2628
  ~CompressionStream() override {
261
    CHECK_EQ(false, write_in_progress_ && "write in progress");
262
2628
    Close();
263
2628
    CHECK_EQ(zlib_memory_, 0);
264
2628
    CHECK_EQ(unreported_allocations_, 0);
265
7884
  }
266
267
4764
  void Close() {
268
4764
    if (write_in_progress_) {
269
60
      pending_close_ = true;
270
60
      return;
271
    }
272
273
4704
    pending_close_ = false;
274
4704
    closed_ = true;
275
4704
    CHECK(init_done_ && "close before init");
276
277
9408
    AllocScope alloc_scope(this);
278
4704
    ctx_.Close();
279
  }
280
281
282
2076
  static void Close(const FunctionCallbackInfo<Value>& args) {
283
    CompressionStream* ctx;
284
2076
    ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
285
2076
    ctx->Close();
286
  }
287
288
289
  // write(flush, in, in_off, in_len, out, out_off, out_len)
290
  template <bool async>
291
17600
  static void Write(const FunctionCallbackInfo<Value>& args) {
292
17600
    Environment* env = Environment::GetCurrent(args);
293
17600
    Local<Context> context = env->context();
294
17600
    CHECK_EQ(args.Length(), 7);
295
296
    uint32_t in_off, in_len, out_off, out_len, flush;
297
    char* in;
298
    char* out;
299
300

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

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

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

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

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

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

1385
  } else if (mode_ == INFLATE || mode_ == GUNZIP || mode_ == INFLATERAW ||
742
835
             mode_ == UNZIP) {
743
550
    status = inflateEnd(&strm_);
744
  }
745
746

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

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

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

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

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

7461
  switch (err_) {
891
6137
  case Z_OK:
892
  case Z_BUF_ERROR:
893

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

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

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

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

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




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

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

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

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

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