GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: node_zlib.cc Lines: 635 700 90.7 %
Date: 2022-08-02 04:16:51 Branches: 254 368 69.0 %

Line Branch Exec Source
1
// Copyright Joyent, Inc. and other Node contributors.
2
//
3
// Permission is hereby granted, free of charge, to any person obtaining a
4
// copy of this software and associated documentation files (the
5
// "Software"), to deal in the Software without restriction, including
6
// without limitation the rights to use, copy, modify, merge, publish,
7
// distribute, sublicense, and/or sell copies of the Software, and to permit
8
// persons to whom the Software is furnished to do so, subject to the
9
// following conditions:
10
//
11
// The above copyright notice and this permission notice shall be included
12
// in all copies or substantial portions of the Software.
13
//
14
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20
// USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22
#include "memory_tracker-inl.h"
23
#include "node.h"
24
#include "node_buffer.h"
25
26
#include "async_wrap-inl.h"
27
#include "env-inl.h"
28
#include "node_external_reference.h"
29
#include "threadpoolwork-inl.h"
30
#include "util-inl.h"
31
32
#include "v8.h"
33
34
#include "brotli/encode.h"
35
#include "brotli/decode.h"
36
#include "zlib.h"
37
38
#include <sys/types.h>
39
40
#include <cerrno>
41
#include <cstdlib>
42
#include <cstring>
43
#include <atomic>
44
45
namespace node {
46
47
using v8::ArrayBuffer;
48
using v8::Context;
49
using v8::Function;
50
using v8::FunctionCallbackInfo;
51
using v8::FunctionTemplate;
52
using v8::HandleScope;
53
using v8::Int32;
54
using v8::Integer;
55
using v8::Isolate;
56
using v8::Local;
57
using v8::Object;
58
using v8::Uint32Array;
59
using v8::Value;
60
61
namespace {
62
63
// Fewer than 64 bytes per chunk is not recommended.
64
// Technically it could work with as few as 8, but even 64 bytes
65
// is low.  Usually a MB or more is best.
66
#define Z_MIN_CHUNK 64
67
#define Z_MAX_CHUNK std::numeric_limits<double>::infinity()
68
#define Z_DEFAULT_CHUNK (16 * 1024)
69
#define Z_MIN_MEMLEVEL 1
70
#define Z_MAX_MEMLEVEL 9
71
#define Z_DEFAULT_MEMLEVEL 8
72
#define Z_MIN_LEVEL -1
73
#define Z_MAX_LEVEL 9
74
#define Z_DEFAULT_LEVEL Z_DEFAULT_COMPRESSION
75
#define Z_MIN_WINDOWBITS 8
76
#define Z_MAX_WINDOWBITS 15
77
#define Z_DEFAULT_WINDOWBITS 15
78
79
#define ZLIB_ERROR_CODES(V)      \
80
  V(Z_OK)                        \
81
  V(Z_STREAM_END)                \
82
  V(Z_NEED_DICT)                 \
83
  V(Z_ERRNO)                     \
84
  V(Z_STREAM_ERROR)              \
85
  V(Z_DATA_ERROR)                \
86
  V(Z_MEM_ERROR)                 \
87
  V(Z_BUF_ERROR)                 \
88
  V(Z_VERSION_ERROR)             \
89
90
22
inline const char* ZlibStrerror(int err) {
91
#define V(code) if (err == code) return #code;
92




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

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

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

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

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

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

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

1451
  } else if (mode_ == INFLATE || mode_ == GUNZIP || mode_ == INFLATERAW ||
749
931
             mode_ == UNZIP) {
750
520
    status = inflateEnd(&strm_);
751
  }
752
753

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

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

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

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

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

7653
  switch (err_) {
898
6177
  case Z_OK:
899
  case Z_BUF_ERROR:
900

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

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

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

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

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




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

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

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

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

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