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: 599 658 91.0 %
Date: 2020-05-27 22:15:15 Branches: 444 734 60.5 %

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::Array;
47
using v8::ArrayBuffer;
48
using v8::Context;
49
using v8::Function;
50
using v8::FunctionCallbackInfo;
51
using v8::FunctionTemplate;
52
using v8::Global;
53
using v8::HandleScope;
54
using v8::Int32;
55
using v8::Integer;
56
using v8::Local;
57
using v8::Object;
58
using v8::String;
59
using v8::Uint32;
60
using v8::Uint32Array;
61
using v8::Value;
62
63
namespace {
64
65
// Fewer than 64 bytes per chunk is not recommended.
66
// Technically it could work with as few as 8, but even 64 bytes
67
// is low.  Usually a MB or more is best.
68
#define Z_MIN_CHUNK 64
69
#define Z_MAX_CHUNK std::numeric_limits<double>::infinity()
70
#define Z_DEFAULT_CHUNK (16 * 1024)
71
#define Z_MIN_MEMLEVEL 1
72
#define Z_MAX_MEMLEVEL 9
73
#define Z_DEFAULT_MEMLEVEL 8
74
#define Z_MIN_LEVEL -1
75
#define Z_MAX_LEVEL 9
76
#define Z_DEFAULT_LEVEL Z_DEFAULT_COMPRESSION
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
10059
  CompressionError() = default;
121
122
  const char* message = nullptr;
123
  const char* code = nullptr;
124
  int err = 0;
125
126
11231
  inline bool IsError() const { return code != nullptr; }
127
};
128
129
994
class ZlibContext : public MemoryRetainer {
130
 public:
131
1168
  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
1168
  inline void SetMode(node_zlib_mode mode) { mode_ = mode; }
141
  CompressionError ResetStream();
142
143
  // Zlib-specific:
144
  CompressionError 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
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
201
class BrotliContext : public MemoryRetainer {
179
 public:
180
201
  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
201
  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
206
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
196
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
1369
  CompressionStream(Environment* env, Local<Object> wrap)
251
      : AsyncWrap(env, wrap, AsyncWrap::PROVIDER_ZLIB),
252
        ThreadPoolWork(env),
253
2738
        write_result_(nullptr) {
254
1369
    MakeWeak();
255
1369
  }
256
257
1195
  ~CompressionStream() override {
258

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

1195
    CHECK_EQ(zlib_memory_, 0);
261

1195
    CHECK_EQ(unreported_allocations_, 0);
262
3585
  }
263
264
2254
  void Close() {
265

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

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

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



8668
    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






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



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






12805
    if (flush != Z_NO_FLUSH &&
301



7796
        flush != Z_PARTIAL_FLUSH &&
302



7102
        flush != Z_SYNC_FLUSH &&
303



4453
        flush != Z_FULL_FLUSH &&
304



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



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



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



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



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



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



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



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



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



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



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



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



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



8668
    CHECK_EQ(false, write_in_progress_);
347



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

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

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

7574
    ScheduleWork();
368
  }
369
370
8645
  void UpdateWriteResult() {
371
8645
    ctx_.GetAfterWriteOffsets(&write_result_[1], &write_result_[0]);
372
8645
  }
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
8668
  void DoThreadPoolWork() override {
379
8668
    ctx_.DoThreadPoolWork();
380
8667
  }
381
382
383
8668
  bool CheckError() {
384
8668
    const CompressionError err = ctx_.GetErrorInfo();
385

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

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

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

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

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

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

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

7557
    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
12
  static void Reset(const FunctionCallbackInfo<Value> &args) {
444
    CompressionStream* wrap;
445

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

12
    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
3932
  CompressionContext* context() { return &ctx_; }
461
462
1369
  void InitStream(uint32_t* write_result, Local<Function> write_js_callback) {
463
1369
    write_result_ = write_result;
464
1369
    write_js_callback_.Reset(AsyncWrap::env()->isolate(), write_js_callback);
465
1369
    init_done_ = true;
466
1369
  }
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
3511
  static void* AllocForZlib(void* data, uInt items, uInt size) {
475
    size_t real_size =
476
3511
        MultiplyWithOverflowCheck(static_cast<size_t>(items),
477
3511
                                  static_cast<size_t>(size));
478
3511
    return AllocForBrotli(data, real_size);
479
  }
480
481
8617
  static void* AllocForBrotli(void* data, size_t size) {
482
8617
    size += sizeof(size_t);
483
8617
    CompressionStream* ctx = static_cast<CompressionStream*>(data);
484
8617
    char* memory = UncheckedMalloc(size);
485

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

10651
    if (UNLIKELY(pointer == nullptr)) return;
494
8383
    CompressionStream* ctx = static_cast<CompressionStream*>(data);
495
8383
    char* real_pointer = static_cast<char*>(pointer) - sizeof(size_t);
496
8383
    size_t real_size = *reinterpret_cast<size_t*>(real_pointer);
497
8383
    ctx->unreported_allocations_.fetch_sub(real_size,
498
                                           std::memory_order_relaxed);
499
8383
    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
19848
  void AdjustAmountOfExternalAllocatedMemory() {
505
    ssize_t report =
506
39696
        unreported_allocations_.exchange(0, std::memory_order_relaxed);
507

19848
    if (report == 0) return;
508



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

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

8668
    CHECK_GT(refs_, 0);
528

8668
    if (--refs_ == 0) {
529
1736
      MakeWeak();
530
    }
531
8668
  }
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
1988
class ZlibStream : public CompressionStream<ZlibContext> {
547
 public:
548
1168
  ZlibStream(Environment* env, Local<Object> wrap, node_zlib_mode mode)
549
1168
    : CompressionStream(env, wrap) {
550
1168
    context()->SetMode(mode);
551
1168
  }
552
553
1168
  static void New(const FunctionCallbackInfo<Value>& args) {
554
1168
    Environment* env = Environment::GetCurrent(args);
555
2336
    CHECK(args[0]->IsInt32());
556
    node_zlib_mode mode =
557
3504
        static_cast<node_zlib_mode>(args[0].As<Int32>()->Value());
558
1168
    new ZlibStream(env, args.This(), mode);
559
1168
  }
560
561
  // just pull the ints out of the args and call the other Init
562
1168
  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
1168
    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

1168
    CHECK(args.Length() == 7 &&
574
      "init(windowBits, level, memLevel, strategy, writeResult, writeCallback,"
575
      " dictionary)");
576
577
    ZlibStream* wrap;
578
1168
    ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
579
580
1168
    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
3504
    if (!args[0]->Uint32Value(context).To(&window_bits)) return;
587
588
    int32_t level;
589
3504
    if (!args[1]->Int32Value(context).To(&level)) return;
590
591
    uint32_t mem_level;
592
3504
    if (!args[2]->Uint32Value(context).To(&mem_level)) return;
593
594
    uint32_t strategy;
595
3504
    if (!args[3]->Uint32Value(context).To(&strategy)) return;
596
597
2336
    CHECK(args[4]->IsUint32Array());
598
2336
    Local<Uint32Array> array = args[4].As<Uint32Array>();
599
1168
    Local<ArrayBuffer> ab = array->Buffer();
600
    uint32_t* write_result = static_cast<uint32_t*>(
601
1168
        ab->GetBackingStore()->Data());
602
603
2336
    CHECK(args[5]->IsFunction());
604
2336
    Local<Function> write_js_callback = args[5].As<Function>();
605
606
2336
    std::vector<unsigned char> dictionary;
607
1168
    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
1168
    wrap->InitStream(write_result, write_js_callback);
616
617
2336
    AllocScope alloc_scope(wrap);
618
1168
    wrap->context()->SetAllocationFunctions(
619
1168
        AllocForZlib, FreeForZlib, static_cast<CompressionStream*>(wrap));
620
    const CompressionError err =
621
        wrap->context()->Init(level, window_bits, mem_level, strategy,
622
1168
                              std::move(dictionary));
623
1168
    if (err.IsError())
624
      wrap->EmitError(err);
625
626
3504
    return args.GetReturnValue().Set(!err.IsError());
627
  }
628
629
1
  static void Params(const FunctionCallbackInfo<Value>& args) {
630

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

402
    CHECK(args[0]->IsInt32());
667
    node_zlib_mode mode =
668
603
        static_cast<node_zlib_mode>(args[0].As<Int32>()->Value());
669
201
    new BrotliCompressionStream(env, args.This(), mode);
670
201
  }
671
672
201
  static void Init(const FunctionCallbackInfo<Value>& args) {
673
    BrotliCompressionStream* wrap;
674

202
    ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
675


201
    CHECK(args.Length() == 3 && "init(params, writeResult, writeCallback)");
676
677

402
    CHECK(args[1]->IsUint32Array());
678
201
    uint32_t* write_result = reinterpret_cast<uint32_t*>(Buffer::Data(args[1]));
679
680

402
    CHECK(args[2]->IsFunction());
681
402
    Local<Function> write_js_callback = args[2].As<Function>();
682
201
    wrap->InitStream(write_result, write_js_callback);
683
684
401
    AllocScope alloc_scope(wrap);
685
    CompressionError err =
686
        wrap->context()->Init(
687
          CompressionStream<CompressionContext>::AllocForBrotli,
688
          CompressionStream<CompressionContext>::FreeForZlib,
689
201
          static_cast<CompressionStream<CompressionContext>*>(wrap));
690

201
    if (err.IsError()) {
691
      wrap->EmitError(err);
692
      args.GetReturnValue().Set(false);
693
      return;
694
    }
695
696

402
    CHECK(args[0]->IsUint32Array());
697
201
    const uint32_t* data = reinterpret_cast<uint32_t*>(Buffer::Data(args[0]));
698
603
    size_t len = args[0].As<Uint32Array>()->Length();
699
700

2005
    for (int i = 0; static_cast<size_t>(i) < len; i++) {
701

1805
      if (data[i] == static_cast<uint32_t>(-1))
702
1792
        continue;
703
13
      err = wrap->context()->SetParams(i, data[i]);
704

13
      if (err.IsError()) {
705
1
        wrap->EmitError(err);
706
2
        args.GetReturnValue().Set(false);
707
1
        return;
708
      }
709
    }
710
711

400
    args.GetReturnValue().Set(true);
712
  }
713
714
  static void Params(const FunctionCallbackInfo<Value>& args) {
715
    // Currently a no-op, and not accessed from JS land.
716
    // At some point Brotli may support changing parameters on the fly,
717
    // in which case we can implement this and a JS equivalent similar to
718
    // the zlib Params() function.
719
  }
720
721
  SET_MEMORY_INFO_NAME(BrotliCompressionStream)
722
  SET_SELF_SIZE(BrotliCompressionStream)
723
};
724
725
using BrotliEncoderStream = BrotliCompressionStream<BrotliEncoderContext>;
726
using BrotliDecoderStream = BrotliCompressionStream<BrotliDecoderContext>;
727
728
1826
void ZlibContext::Close() {
729
1826
  CHECK_LE(mode_, UNZIP);
730
731
1826
  int status = Z_OK;
732

1826
  if (mode_ == DEFLATE || mode_ == GZIP || mode_ == DEFLATERAW) {
733
543
    status = deflateEnd(&strm_);
734


2114
  } else if (mode_ == INFLATE || mode_ == GUNZIP || mode_ == INFLATERAW ||
735
831
             mode_ == UNZIP) {
736
453
    status = inflateEnd(&strm_);
737
  }
738
739

1826
  CHECK(status == Z_OK || status == Z_DATA_ERROR);
740
1826
  mode_ = NONE;
741
742
1826
  dictionary_.clear();
743
1826
}
744
745
746
7333
void ZlibContext::DoThreadPoolWork() {
747
7333
  const Bytef* next_expected_header_byte = nullptr;
748
749
  // If the avail_out is left at 0, then it means that it ran out
750
  // of room.  If there was avail_out left over, then it means
751
  // that all of the input was consumed.
752

7333
  switch (mode_) {
753
    case DEFLATE:
754
    case GZIP:
755
    case DEFLATERAW:
756
1442
      err_ = deflate(&strm_, flush_);
757
1441
      break;
758
    case UNZIP:
759
272
      if (strm_.avail_in > 0) {
760
271
        next_expected_header_byte = strm_.next_in;
761
      }
762
763
272
      switch (gzip_id_bytes_read_) {
764
        case 0:
765
269
          if (next_expected_header_byte == nullptr) {
766
            break;
767
          }
768
769
269
          if (*next_expected_header_byte == GZIP_HEADER_ID1) {
770
263
            gzip_id_bytes_read_ = 1;
771
263
            next_expected_header_byte++;
772
773
263
            if (strm_.avail_in == 1) {
774
              // The only available byte was already read.
775
2
              break;
776
            }
777
          } else {
778
6
            mode_ = INFLATE;
779
6
            break;
780
          }
781
782
          // fallthrough
783
        case 1:
784
264
          if (next_expected_header_byte == nullptr) {
785
1
            break;
786
          }
787
788
263
          if (*next_expected_header_byte == GZIP_HEADER_ID2) {
789
263
            gzip_id_bytes_read_ = 2;
790
263
            mode_ = GUNZIP;
791
          } else {
792
            // There is no actual difference between INFLATE and INFLATERAW
793
            // (after initialization).
794
            mode_ = INFLATE;
795
          }
796
797
263
          break;
798
        default:
799
          CHECK(0 && "invalid number of gzip magic number bytes read");
800
      }
801
802
      // fallthrough
803
    case INFLATE:
804
    case GUNZIP:
805
    case INFLATERAW:
806
5891
      err_ = inflate(&strm_, flush_);
807
808
      // If data was encoded with dictionary (INFLATERAW will have it set in
809
      // SetDictionary, don't repeat that here)
810

16033
      if (mode_ != INFLATERAW &&
811

5905
          err_ == Z_NEED_DICT &&
812
14
          !dictionary_.empty()) {
813
        // Load it
814
26
        err_ = inflateSetDictionary(&strm_,
815
13
                                    dictionary_.data(),
816
13
                                    dictionary_.size());
817
13
        if (err_ == Z_OK) {
818
          // And try to decode again
819
12
          err_ = inflate(&strm_, flush_);
820
1
        } else if (err_ == Z_DATA_ERROR) {
821
          // Both inflateSetDictionary() and inflate() return Z_DATA_ERROR.
822
          // Make it possible for After() to tell a bad dictionary from bad
823
          // input.
824
1
          err_ = Z_NEED_DICT;
825
        }
826
      }
827
828
6300
      while (strm_.avail_in > 0 &&
829
694
             mode_ == GUNZIP &&
830

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

7333
  switch (err_) {
879
  case Z_OK:
880
  case Z_BUF_ERROR:
881

5887
    if (strm_.avail_out != 0 && flush_ == Z_FINISH) {
882
8
      return ErrorForMessage("unexpected end of file");
883
    }
884
  case Z_STREAM_END:
885
    // normal statuses, not fatal
886
7311
    break;
887
  case Z_NEED_DICT:
888
2
    if (dictionary_.empty())
889
1
      return ErrorForMessage("Missing dictionary");
890
    else
891
1
      return ErrorForMessage("Bad dictionary");
892
  default:
893
    // something else.
894
12
    return ErrorForMessage("Zlib error");
895
  }
896
897
7311
  return CompressionError {};
898
}
899
900
901
32
CompressionError ZlibContext::ResetStream() {
902
32
  err_ = Z_OK;
903
904
32
  switch (mode_) {
905
    case DEFLATE:
906
    case DEFLATERAW:
907
    case GZIP:
908
12
      err_ = deflateReset(&strm_);
909
12
      break;
910
    case INFLATE:
911
    case INFLATERAW:
912
    case GUNZIP:
913
20
      err_ = inflateReset(&strm_);
914
20
      break;
915
    default:
916
      break;
917
  }
918
919
32
  if (err_ != Z_OK)
920
    return ErrorForMessage("Failed to reset stream");
921
922
32
  return SetDictionary();
923
}
924
925
926
1168
void ZlibContext::SetAllocationFunctions(alloc_func alloc,
927
                                         free_func free,
928
                                         void* opaque) {
929
1168
  strm_.zalloc = alloc;
930
1168
  strm_.zfree = free;
931
1168
  strm_.opaque = opaque;
932
1168
}
933
934
935
1168
CompressionError ZlibContext::Init(
936
    int level, int window_bits, int mem_level, int strategy,
937
    std::vector<unsigned char>&& dictionary) {
938

1580
  if (!((window_bits == 0) &&
939
740
        (mode_ == INFLATE ||
940
574
         mode_ == GUNZIP ||
941
246
         mode_ == UNZIP))) {
942

756
    CHECK(
943
        (window_bits >= Z_MIN_WINDOWBITS && window_bits <= Z_MAX_WINDOWBITS) &&
944
        "invalid windowBits");
945
  }
946
947

1168
  CHECK((level >= Z_MIN_LEVEL && level <= Z_MAX_LEVEL) &&
948
    "invalid compression level");
949
950

1168
  CHECK((mem_level >= Z_MIN_MEMLEVEL && mem_level <= Z_MAX_MEMLEVEL) &&
951
        "invalid memlevel");
952
953




1168
  CHECK((strategy == Z_FILTERED || strategy == Z_HUFFMAN_ONLY ||
954
         strategy == Z_RLE || strategy == Z_FIXED ||
955
         strategy == Z_DEFAULT_STRATEGY) &&
956
        "invalid strategy");
957
958
1168
  level_ = level;
959
1168
  window_bits_ = window_bits;
960
1168
  mem_level_ = mem_level;
961
1168
  strategy_ = strategy;
962
963
1168
  flush_ = Z_NO_FLUSH;
964
965
1168
  err_ = Z_OK;
966
967

1168
  if (mode_ == GZIP || mode_ == GUNZIP) {
968
431
    window_bits_ += 16;
969
  }
970
971
1168
  if (mode_ == UNZIP) {
972
270
    window_bits_ += 32;
973
  }
974
975

1168
  if (mode_ == DEFLATERAW || mode_ == INFLATERAW) {
976
219
    window_bits_ *= -1;
977
  }
978
979
1168
  switch (mode_) {
980
    case DEFLATE:
981
    case GZIP:
982
    case DEFLATERAW:
983
543
      err_ = deflateInit2(&strm_,
984
                          level_,
985
                          Z_DEFLATED,
986
                          window_bits_,
987
                          mem_level_,
988
                          strategy_);
989
543
      break;
990
    case INFLATE:
991
    case GUNZIP:
992
    case INFLATERAW:
993
    case UNZIP:
994
625
      err_ = inflateInit2(&strm_, window_bits_);
995
625
      break;
996
    default:
997
      UNREACHABLE();
998
  }
999
1000
1168
  dictionary_ = std::move(dictionary);
1001
1002
1168
  if (err_ != Z_OK) {
1003
    dictionary_.clear();
1004
    mode_ = NONE;
1005
    return ErrorForMessage("zlib error");
1006
  }
1007
1008
1168
  return SetDictionary();
1009
}
1010
1011
1012
1200
CompressionError ZlibContext::SetDictionary() {
1013
1200
  if (dictionary_.empty())
1014
1138
    return CompressionError {};
1015
1016
62
  err_ = Z_OK;
1017
1018
62
  switch (mode_) {
1019
    case DEFLATE:
1020
    case DEFLATERAW:
1021
72
      err_ = deflateSetDictionary(&strm_,
1022
36
                                  dictionary_.data(),
1023
36
                                  dictionary_.size());
1024
36
      break;
1025
    case INFLATERAW:
1026
      // The other inflate cases will have the dictionary set when inflate()
1027
      // returns Z_NEED_DICT in Process()
1028
26
      err_ = inflateSetDictionary(&strm_,
1029
13
                                  dictionary_.data(),
1030
13
                                  dictionary_.size());
1031
13
      break;
1032
    default:
1033
13
      break;
1034
  }
1035
1036
62
  if (err_ != Z_OK) {
1037
    return ErrorForMessage("Failed to set dictionary");
1038
  }
1039
1040
62
  return CompressionError {};
1041
}
1042
1043
1044
1
CompressionError ZlibContext::SetParams(int level, int strategy) {
1045
1
  err_ = Z_OK;
1046
1047
1
  switch (mode_) {
1048
    case DEFLATE:
1049
    case DEFLATERAW:
1050
1
      err_ = deflateParams(&strm_, level, strategy);
1051
1
      break;
1052
    default:
1053
      break;
1054
  }
1055
1056

1
  if (err_ != Z_OK && err_ != Z_BUF_ERROR) {
1057
    return ErrorForMessage("Failed to set parameters");
1058
  }
1059
1060
1
  return CompressionError {};
1061
}
1062
1063
1064
1335
void BrotliContext::SetBuffers(char* in, uint32_t in_len,
1065
                               char* out, uint32_t out_len) {
1066
1335
  next_in_ = reinterpret_cast<uint8_t*>(in);
1067
1335
  next_out_ = reinterpret_cast<uint8_t*>(out);
1068
1335
  avail_in_ = in_len;
1069
1335
  avail_out_ = out_len;
1070
1335
}
1071
1072
1073
1335
void BrotliContext::SetFlush(int flush) {
1074
1335
  flush_ = static_cast<BrotliEncoderOperation>(flush);
1075
1335
}
1076
1077
1078
1334
void BrotliContext::GetAfterWriteOffsets(uint32_t* avail_in,
1079
                                         uint32_t* avail_out) const {
1080
1334
  *avail_in = avail_in_;
1081
1334
  *avail_out = avail_out_;
1082
1334
}
1083
1084
1085
331
void BrotliEncoderContext::DoThreadPoolWork() {
1086
331
  CHECK_EQ(mode_, BROTLI_ENCODE);
1087
331
  CHECK(state_);
1088
331
  const uint8_t* next_in = next_in_;
1089
662
  last_result_ = BrotliEncoderCompressStream(state_.get(),
1090
                                             flush_,
1091
                                             &avail_in_,
1092
                                             &next_in,
1093
                                             &avail_out_,
1094
                                             &next_out_,
1095
331
                                             nullptr);
1096
331
  next_in_ += next_in - next_in_;
1097
331
}
1098
1099
1100
204
void BrotliEncoderContext::Close() {
1101
204
  state_.reset();
1102
204
  mode_ = NONE;
1103
204
}
1104
1105
103
CompressionError BrotliEncoderContext::Init(brotli_alloc_func alloc,
1106
                                            brotli_free_func free,
1107
                                            void* opaque) {
1108
103
  alloc_ = alloc;
1109
103
  free_ = free;
1110
103
  alloc_opaque_ = opaque;
1111
103
  state_.reset(BrotliEncoderCreateInstance(alloc, free, opaque));
1112
103
  if (!state_) {
1113
    return CompressionError("Could not initialize Brotli instance",
1114
                            "ERR_ZLIB_INITIALIZATION_FAILED",
1115
                            -1);
1116
  } else {
1117
103
    return CompressionError {};
1118
  }
1119
}
1120
1121
CompressionError BrotliEncoderContext::ResetStream() {
1122
  return Init(alloc_, free_, alloc_opaque_);
1123
}
1124
1125
13
CompressionError BrotliEncoderContext::SetParams(int key, uint32_t value) {
1126
13
  if (!BrotliEncoderSetParameter(state_.get(),
1127
                                 static_cast<BrotliEncoderParameter>(key),
1128
                                 value)) {
1129
    return CompressionError("Setting parameter failed",
1130
                            "ERR_BROTLI_PARAM_SET_FAILED",
1131
1
                            -1);
1132
  } else {
1133
12
    return CompressionError {};
1134
  }
1135
}
1136
1137
331
CompressionError BrotliEncoderContext::GetErrorInfo() const {
1138
331
  if (!last_result_) {
1139
    return CompressionError("Compression failed",
1140
                            "ERR_BROTLI_COMPRESSION_FAILED",
1141
                            -1);
1142
  } else {
1143
331
    return CompressionError {};
1144
  }
1145
}
1146
1147
1148
194
void BrotliDecoderContext::Close() {
1149
194
  state_.reset();
1150
194
  mode_ = NONE;
1151
194
}
1152
1153
1004
void BrotliDecoderContext::DoThreadPoolWork() {
1154
1004
  CHECK_EQ(mode_, BROTLI_DECODE);
1155
1004
  CHECK(state_);
1156
1004
  const uint8_t* next_in = next_in_;
1157
1004
  last_result_ = BrotliDecoderDecompressStream(state_.get(),
1158
                                               &avail_in_,
1159
                                               &next_in,
1160
                                               &avail_out_,
1161
                                               &next_out_,
1162
                                               nullptr);
1163
1004
  next_in_ += next_in - next_in_;
1164
1004
  if (last_result_ == BROTLI_DECODER_RESULT_ERROR) {
1165
1
    error_ = BrotliDecoderGetErrorCode(state_.get());
1166
1
    error_string_ = std::string("ERR_") + BrotliDecoderErrorString(error_);
1167
  }
1168
1004
}
1169
1170
98
CompressionError BrotliDecoderContext::Init(brotli_alloc_func alloc,
1171
                                            brotli_free_func free,
1172
                                            void* opaque) {
1173
98
  alloc_ = alloc;
1174
98
  free_ = free;
1175
98
  alloc_opaque_ = opaque;
1176
98
  state_.reset(BrotliDecoderCreateInstance(alloc, free, opaque));
1177
98
  if (!state_) {
1178
    return CompressionError("Could not initialize Brotli instance",
1179
                            "ERR_ZLIB_INITIALIZATION_FAILED",
1180
                            -1);
1181
  } else {
1182
98
    return CompressionError {};
1183
  }
1184
}
1185
1186
CompressionError BrotliDecoderContext::ResetStream() {
1187
  return Init(alloc_, free_, alloc_opaque_);
1188
}
1189
1190
CompressionError BrotliDecoderContext::SetParams(int key, uint32_t value) {
1191
  if (!BrotliDecoderSetParameter(state_.get(),
1192
                                 static_cast<BrotliDecoderParameter>(key),
1193
                                 value)) {
1194
    return CompressionError("Setting parameter failed",
1195
                            "ERR_BROTLI_PARAM_SET_FAILED",
1196
                            -1);
1197
  } else {
1198
    return CompressionError {};
1199
  }
1200
}
1201
1202
1004
CompressionError BrotliDecoderContext::GetErrorInfo() const {
1203
1004
  if (error_ != BROTLI_DECODER_NO_ERROR) {
1204
    return CompressionError("Decompression failed",
1205
                            error_string_.c_str(),
1206
1
                            static_cast<int>(error_));
1207

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