GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage-daily/nodes/benchmark/out/../src/node_zlib.cc Lines: 625 685 91.2 %
Date: 2021-06-02 04:11:51 Branches: 458 754 60.7 %

Line Branch Exec Source
1
// Copyright Joyent, Inc. and other Node contributors.
2
//
3
// Permission is hereby granted, free of charge, to any person obtaining a
4
// copy of this software and associated documentation files (the
5
// "Software"), to deal in the Software without restriction, including
6
// without limitation the rights to use, copy, modify, merge, publish,
7
// distribute, sublicense, and/or sell copies of the Software, and to permit
8
// persons to whom the Software is furnished to do so, subject to the
9
// following conditions:
10
//
11
// The above copyright notice and this permission notice shall be included
12
// in all copies or substantial portions of the Software.
13
//
14
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20
// USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22
#include "memory_tracker-inl.h"
23
#include "node.h"
24
#include "node_buffer.h"
25
26
#include "async_wrap-inl.h"
27
#include "env-inl.h"
28
#include "threadpoolwork-inl.h"
29
#include "util-inl.h"
30
31
#include "v8.h"
32
33
#include "brotli/encode.h"
34
#include "brotli/decode.h"
35
#include "zlib.h"
36
37
#include <sys/types.h>
38
39
#include <cerrno>
40
#include <cstdlib>
41
#include <cstring>
42
#include <atomic>
43
44
namespace node {
45
46
using v8::ArrayBuffer;
47
using v8::Context;
48
using v8::Function;
49
using v8::FunctionCallbackInfo;
50
using v8::FunctionTemplate;
51
using v8::Global;
52
using v8::HandleScope;
53
using v8::Int32;
54
using v8::Integer;
55
using v8::Local;
56
using v8::Object;
57
using v8::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
75
#define ZLIB_ERROR_CODES(V)      \
76
  V(Z_OK)                        \
77
  V(Z_STREAM_END)                \
78
  V(Z_NEED_DICT)                 \
79
  V(Z_ERRNO)                     \
80
  V(Z_STREAM_ERROR)              \
81
  V(Z_DATA_ERROR)                \
82
  V(Z_MEM_ERROR)                 \
83
  V(Z_BUF_ERROR)                 \
84
  V(Z_VERSION_ERROR)             \
85
86
22
inline const char* ZlibStrerror(int err) {
87
#define V(code) if (err == code) return #code;
88




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

1234
    CHECK_EQ(false, write_in_progress_ && "write in progress");
259
1234
    Close();
260

1234
    CHECK_EQ(zlib_memory_, 0);
261

1234
    CHECK_EQ(unreported_allocations_, 0);
262
3702
  }
263
264
2298
  void Close() {
265

2298
    if (write_in_progress_) {
266
30
      pending_close_ = true;
267
30
      return;
268
    }
269
270
2268
    pending_close_ = false;
271
2268
    closed_ = true;
272

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

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



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






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



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






12889
    if (flush != Z_NO_FLUSH &&
301



7766
        flush != Z_PARTIAL_FLUSH &&
302



7068
        flush != Z_SYNC_FLUSH &&
303



4415
        flush != Z_FULL_FLUSH &&
304



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



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



8767
      CHECK(Buffer::HasInstance(args[1]));
316
17534
      Local<Object> in_buf = args[1].As<Object>();
317



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



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



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



8767
    CHECK(Buffer::HasInstance(args[4]));
325
17534
    Local<Object> out_buf = args[4].As<Object>();
326



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



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



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



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



8767
    CHECK(init_done_ && "write before init");
344



8767
    CHECK(!closed_ && "already finalized");
345
346



8767
    CHECK_EQ(false, write_in_progress_);
347



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

1187
      if (CheckError()) {
359
1181
        UpdateWriteResult();
360
1181
        write_in_progress_ = false;
361
      }
362
1187
      Unref();
363

1187
      return;
364
    }
365
366
    // async version
367

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

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

22723
    auto on_scope_leave = OnScopeLeave([&]() { Unref(); });
395
396
7580
    write_in_progress_ = false;
397
398

7580
    if (status == UV_ECANCELED) {
399
      Close();
400
      return;
401
    }
402
403

7580
    CHECK_EQ(status, 0);
404
405
7580
    Environment* env = AsyncWrap::env();
406

15143
    HandleScope handle_scope(env->isolate());
407

15143
    Context::Scope context_scope(env->context());
408
409

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

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

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

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

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

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

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

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

19988
    if (report == 0) return;
508



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

8767
    if (++refs_ == 1) {
522
1831
      ClearWeak();
523
    }
524
8767
  }
525
526
8767
  void Unref() {
527

8767
    CHECK_GT(refs_, 0);
528

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

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

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

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

208
    ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
670


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

414
    CHECK(args[1]->IsUint32Array());
673
207
    uint32_t* write_result = reinterpret_cast<uint32_t*>(Buffer::Data(args[1]));
674
675

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

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

414
    CHECK(args[0]->IsUint32Array());
692
207
    const uint32_t* data = reinterpret_cast<uint32_t*>(Buffer::Data(args[0]));
693
621
    size_t len = args[0].As<Uint32Array>()->Length();
694
695

2065
    for (int i = 0; static_cast<size_t>(i) < len; i++) {
696

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

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

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

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


2134
  } else if (mode_ == INFLATE || mode_ == GUNZIP || mode_ == INFLATERAW ||
739
831
             mode_ == UNZIP) {
740
472
    status = inflateEnd(&strm_);
741
  }
742
743

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

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

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

16297
      if (mode_ != INFLATERAW &&
820

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

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

7428
  switch (err_) {
888
  case Z_OK:
889
  case Z_BUF_ERROR:
890

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

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

1537
  if (!((window_bits == 0) &&
953
692
        (mode_ == INFLATE ||
954
526
         mode_ == GUNZIP ||
955
222
         mode_ == UNZIP))) {
956

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

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

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




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

1149
  if (mode_ == GZIP || mode_ == GUNZIP) {
982
432
    window_bits_ += 16;
983
  }
984
985
1149
  if (mode_ == UNZIP) {
986
246
    window_bits_ += 32;
987
  }
988
989

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

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

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

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

19352
NODE_MODULE_CONTEXT_AWARE_INTERNAL(zlib, node::Initialize)