GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
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 |
10355 |
CompressionError() = default; |
|
122 |
|||
123 |
const char* message = nullptr; |
||
124 |
const char* code = nullptr; |
||
125 |
int err = 0; |
||
126 |
|||
127 |
9291 |
inline bool IsError() const { return code != nullptr; } |
|
128 |
}; |
||
129 |
|||
130 |
class ZlibContext final : public MemoryRetainer { |
||
131 |
public: |
||
132 |
1220 |
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 |
1220 |
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 |
2902 |
CompressionStream(Environment* env, Local<Object> wrap) |
|
261 |
: AsyncWrap(env, wrap, AsyncWrap::PROVIDER_ZLIB), |
||
262 |
ThreadPoolWork(env), |
||
263 |
2902 |
write_result_(nullptr) { |
|
264 |
2902 |
MakeWeak(); |
|
265 |
2902 |
} |
|
266 |
|||
267 |
2660 |
~CompressionStream() override { |
|
268 |
CHECK(!write_in_progress_); |
||
269 |
2660 |
Close(); |
|
270 |
✗✓ | 2660 |
CHECK_EQ(zlib_memory_, 0); |
271 |
✗✓ | 2660 |
CHECK_EQ(unreported_allocations_, 0); |
272 |
✗✓ | 5320 |
} |
273 |
|||
274 |
5038 |
void Close() { |
|
275 |
✓✓ | 5038 |
if (write_in_progress_) { |
276 |
60 |
pending_close_ = true; |
|
277 |
60 |
return; |
|
278 |
} |
||
279 |
|||
280 |
4978 |
pending_close_ = false; |
|
281 |
4978 |
closed_ = true; |
|
282 |
✗✓ | 4978 |
CHECK(init_done_ && "close before init"); |
283 |
|||
284 |
9956 |
AllocScope alloc_scope(this); |
|
285 |
4978 |
ctx_.Close(); |
|
286 |
} |
||
287 |
|||
288 |
|||
289 |
2318 |
static void Close(const FunctionCallbackInfo<Value>& args) { |
|
290 |
CompressionStream* ctx; |
||
291 |
✗✓ | 2318 |
ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder()); |
292 |
2318 |
ctx->Close(); |
|
293 |
} |
||
294 |
|||
295 |
|||
296 |
// write(flush, in, in_off, in_len, out, out_off, out_len) |
||
297 |
template <bool async> |
||
298 |
18060 |
static void Write(const FunctionCallbackInfo<Value>& args) { |
|
299 |
18060 |
Environment* env = Environment::GetCurrent(args); |
|
300 |
18060 |
Local<Context> context = env->context(); |
|
301 |
✗✓ | 18060 |
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 |
✗✓✗✓ |
36120 |
CHECK_EQ(false, args[0]->IsUndefined() && "must provide flush value"); |
308 |
✗✓ | 36120 |
if (!args[0]->Uint32Value(context).To(&flush)) return; |
309 |
|||
310 |
✓✓ | 18060 |
if (flush != Z_NO_FLUSH && |
311 |
✓✓ | 8436 |
flush != Z_PARTIAL_FLUSH && |
312 |
✓✓ | 7480 |
flush != Z_SYNC_FLUSH && |
313 |
✓✓ | 6996 |
flush != Z_FULL_FLUSH && |
314 |
✗✓ | 2130 |
flush != Z_FINISH && |
315 |
flush != Z_BLOCK) { |
||
316 |
CHECK(0 && "Invalid flush value"); |
||
317 |
} |
||
318 |
|||
319 |
✗✓ | 36120 |
if (args[1]->IsNull()) { |
320 |
// just a flush |
||
321 |
in = nullptr; |
||
322 |
in_len = 0; |
||
323 |
in_off = 0; |
||
324 |
} else { |
||
325 |
✗✓ | 18060 |
CHECK(Buffer::HasInstance(args[1])); |
326 |
✓✗ | 36120 |
Local<Object> in_buf = args[1].As<Object>(); |
327 |
✗✓ | 36120 |
if (!args[2]->Uint32Value(context).To(&in_off)) return; |
328 |
✗✓ | 36120 |
if (!args[3]->Uint32Value(context).To(&in_len)) return; |
329 |
|||
330 |
✗✓ | 18060 |
CHECK(Buffer::IsWithinBounds(in_off, in_len, Buffer::Length(in_buf))); |
331 |
18060 |
in = Buffer::Data(in_buf) + in_off; |
|
332 |
} |
||
333 |
|||
334 |
✗✓ | 18060 |
CHECK(Buffer::HasInstance(args[4])); |
335 |
✓✗ | 36120 |
Local<Object> out_buf = args[4].As<Object>(); |
336 |
✗✓ | 36120 |
if (!args[5]->Uint32Value(context).To(&out_off)) return; |
337 |
✗✓ | 36120 |
if (!args[6]->Uint32Value(context).To(&out_len)) return; |
338 |
✗✓ | 18060 |
CHECK(Buffer::IsWithinBounds(out_off, out_len, Buffer::Length(out_buf))); |
339 |
18060 |
out = Buffer::Data(out_buf) + out_off; |
|
340 |
|||
341 |
CompressionStream* ctx; |
||
342 |
✗✓ | 18060 |
ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder()); |
343 |
|||
344 |
18060 |
ctx->Write<async>(flush, in, in_len, out, out_len); |
|
345 |
} |
||
346 |
|||
347 |
template <bool async> |
||
348 |
18060 |
void Write(uint32_t flush, |
|
349 |
const char* in, uint32_t in_len, |
||
350 |
char* out, uint32_t out_len) { |
||
351 |
33482 |
AllocScope alloc_scope(this); |
|
352 |
|||
353 |
✗✓ | 18060 |
CHECK(init_done_ && "write before init"); |
354 |
✗✓ | 18060 |
CHECK(!closed_ && "already finalized"); |
355 |
|||
356 |
✗✓ | 18060 |
CHECK_EQ(false, write_in_progress_); |
357 |
✗✓ | 18060 |
CHECK_EQ(false, pending_close_); |
358 |
18060 |
write_in_progress_ = true; |
|
359 |
18060 |
Ref(); |
|
360 |
|||
361 |
18060 |
ctx_.SetBuffers(in, in_len, out, out_len); |
|
362 |
18060 |
ctx_.SetFlush(flush); |
|
363 |
|||
364 |
if constexpr (!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 |
15422 |
ScheduleWork(); |
|
378 |
} |
||
379 |
|||
380 |
18014 |
void UpdateWriteResult() { |
|
381 |
18014 |
ctx_.GetAfterWriteOffsets(&write_result_[1], &write_result_[0]); |
|
382 |
18014 |
} |
|
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 |
18060 |
void DoThreadPoolWork() override { |
|
389 |
18060 |
ctx_.DoThreadPoolWork(); |
|
390 |
18060 |
} |
|
391 |
|||
392 |
|||
393 |
18060 |
bool CheckError() { |
|
394 |
18060 |
const CompressionError err = ctx_.GetErrorInfo(); |
|
395 |
✓✓ | 18060 |
if (!err.IsError()) return true; |
396 |
46 |
EmitError(err); |
|
397 |
46 |
return false; |
|
398 |
} |
||
399 |
|||
400 |
|||
401 |
// v8 land! |
||
402 |
15422 |
void AfterThreadPoolWork(int status) override { |
|
403 |
DCHECK(init_done_); |
||
404 |
15422 |
AllocScope alloc_scope(this); |
|
405 |
23133 |
auto on_scope_leave = OnScopeLeave([&]() { Unref(); }); |
|
406 |
|||
407 |
15422 |
write_in_progress_ = false; |
|
408 |
|||
409 |
✗✓ | 15422 |
if (status == UV_ECANCELED) { |
410 |
Close(); |
||
411 |
return; |
||
412 |
} |
||
413 |
|||
414 |
✗✓ | 15422 |
CHECK_EQ(status, 0); |
415 |
|||
416 |
15422 |
Environment* env = AsyncWrap::env(); |
|
417 |
15422 |
HandleScope handle_scope(env->isolate()); |
|
418 |
15422 |
Context::Scope context_scope(env->context()); |
|
419 |
|||
420 |
✓✓ | 15422 |
if (!CheckError()) |
421 |
34 |
return; |
|
422 |
|||
423 |
15388 |
UpdateWriteResult(); |
|
424 |
|||
425 |
// call the write() cb |
||
426 |
30776 |
Local<Value> cb = object()->GetInternalField(kWriteJSCallback); |
|
427 |
30776 |
MakeCallback(cb.As<Function>(), 0, nullptr); |
|
428 |
|||
429 |
✓✓ | 15388 |
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 |
8304 |
CompressionContext* context() { return &ctx_; } |
|
471 |
|||
472 |
2902 |
void InitStream(uint32_t* write_result, Local<Function> write_js_callback) { |
|
473 |
2902 |
write_result_ = write_result; |
|
474 |
5804 |
object()->SetInternalField(kWriteJSCallback, write_js_callback); |
|
475 |
2902 |
init_done_ = true; |
|
476 |
2902 |
} |
|
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 |
3071 |
static void* AllocForZlib(void* data, uInt items, uInt size) { |
|
485 |
size_t real_size = |
||
486 |
3071 |
MultiplyWithOverflowCheck(static_cast<size_t>(items), |
|
487 |
static_cast<size_t>(size)); |
||
488 |
3071 |
return AllocForBrotli(data, real_size); |
|
489 |
} |
||
490 |
|||
491 |
17686 |
static void* AllocForBrotli(void* data, size_t size) { |
|
492 |
17686 |
size += sizeof(size_t); |
|
493 |
17686 |
CompressionStream* ctx = static_cast<CompressionStream*>(data); |
|
494 |
17686 |
char* memory = UncheckedMalloc(size); |
|
495 |
✗✓ | 17686 |
if (UNLIKELY(memory == nullptr)) return nullptr; |
496 |
17686 |
*reinterpret_cast<size_t*>(memory) = size; |
|
497 |
17686 |
ctx->unreported_allocations_.fetch_add(size, |
|
498 |
std::memory_order_relaxed); |
||
499 |
17686 |
return memory + sizeof(size_t); |
|
500 |
} |
||
501 |
|||
502 |
22286 |
static void FreeForZlib(void* data, void* pointer) { |
|
503 |
✓✓ | 22286 |
if (UNLIKELY(pointer == nullptr)) return; |
504 |
17294 |
CompressionStream* ctx = static_cast<CompressionStream*>(data); |
|
505 |
17294 |
char* real_pointer = static_cast<char*>(pointer) - sizeof(size_t); |
|
506 |
17294 |
size_t real_size = *reinterpret_cast<size_t*>(real_pointer); |
|
507 |
17294 |
ctx->unreported_allocations_.fetch_sub(real_size, |
|
508 |
std::memory_order_relaxed); |
||
509 |
17294 |
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 |
41396 |
void AdjustAmountOfExternalAllocatedMemory() { |
|
515 |
ssize_t report = |
||
516 |
41396 |
unreported_allocations_.exchange(0, std::memory_order_relaxed); |
|
517 |
✓✓ | 41396 |
if (report == 0) return; |
518 |
✓✓✗✓ |
5512 |
CHECK_IMPLIES(report < 0, zlib_memory_ >= static_cast<size_t>(-report)); |
519 |
5512 |
zlib_memory_ += report; |
|
520 |
5512 |
AsyncWrap::env()->isolate()->AdjustAmountOfExternalAllocatedMemory(report); |
|
521 |
} |
||
522 |
|||
523 |
struct AllocScope { |
||
524 |
41396 |
explicit AllocScope(CompressionStream* stream) : stream(stream) {} |
|
525 |
20698 |
~AllocScope() { stream->AdjustAmountOfExternalAllocatedMemory(); } |
|
526 |
CompressionStream* stream; |
||
527 |
}; |
||
528 |
|||
529 |
private: |
||
530 |
18060 |
void Ref() { |
|
531 |
✓✓ | 18060 |
if (++refs_ == 1) { |
532 |
4056 |
ClearWeak(); |
|
533 |
} |
||
534 |
18060 |
} |
|
535 |
|||
536 |
18060 |
void Unref() { |
|
537 |
✗✓ | 18060 |
CHECK_GT(refs_, 0); |
538 |
✓✓ | 18060 |
if (--refs_ == 0) { |
539 |
4056 |
MakeWeak(); |
|
540 |
} |
||
541 |
18060 |
} |
|
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 |
1220 |
ZlibStream(Environment* env, Local<Object> wrap, node_zlib_mode mode) |
|
558 |
1220 |
: CompressionStream(env, wrap) { |
|
559 |
1220 |
context()->SetMode(mode); |
|
560 |
1220 |
} |
|
561 |
|||
562 |
1220 |
static void New(const FunctionCallbackInfo<Value>& args) { |
|
563 |
1220 |
Environment* env = Environment::GetCurrent(args); |
|
564 |
✗✓ | 1220 |
CHECK(args[0]->IsInt32()); |
565 |
node_zlib_mode mode = |
||
566 |
2440 |
static_cast<node_zlib_mode>(args[0].As<Int32>()->Value()); |
|
567 |
1220 |
new ZlibStream(env, args.This(), mode); |
|
568 |
1220 |
} |
|
569 |
|||
570 |
// just pull the ints out of the args and call the other Init |
||
571 |
1220 |
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 |
✗✓ | 1220 |
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 |
✗✓✗✓ |
1220 |
CHECK(args.Length() == 7 && |
583 |
"init(windowBits, level, memLevel, strategy, writeResult, writeCallback," |
||
584 |
" dictionary)"); |
||
585 |
|||
586 |
ZlibStream* wrap; |
||
587 |
✗✓ | 1220 |
ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder()); |
588 |
|||
589 |
1220 |
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 |
✗✓ | 2440 |
if (!args[0]->Uint32Value(context).To(&window_bits)) return; |
596 |
|||
597 |
int32_t level; |
||
598 |
✗✓ | 2440 |
if (!args[1]->Int32Value(context).To(&level)) return; |
599 |
|||
600 |
uint32_t mem_level; |
||
601 |
✗✓ | 2440 |
if (!args[2]->Uint32Value(context).To(&mem_level)) return; |
602 |
|||
603 |
uint32_t strategy; |
||
604 |
✗✓ | 2440 |
if (!args[3]->Uint32Value(context).To(&strategy)) return; |
605 |
|||
606 |
✗✓ | 1220 |
CHECK(args[4]->IsUint32Array()); |
607 |
2440 |
Local<Uint32Array> array = args[4].As<Uint32Array>(); |
|
608 |
1220 |
Local<ArrayBuffer> ab = array->Buffer(); |
|
609 |
1220 |
uint32_t* write_result = static_cast<uint32_t*>(ab->Data()); |
|
610 |
|||
611 |
✗✓ | 1220 |
CHECK(args[5]->IsFunction()); |
612 |
1220 |
Local<Function> write_js_callback = args[5].As<Function>(); |
|
613 |
|||
614 |
2440 |
std::vector<unsigned char> dictionary; |
|
615 |
✓✓ | 1220 |
if (Buffer::HasInstance(args[6])) { |
616 |
unsigned char* data = |
||
617 |
51 |
reinterpret_cast<unsigned char*>(Buffer::Data(args[6])); |
|
618 |
153 |
dictionary = std::vector<unsigned char>( |
|
619 |
data, |
||
620 |
102 |
data + Buffer::Length(args[6])); |
|
621 |
} |
||
622 |
|||
623 |
1220 |
wrap->InitStream(write_result, write_js_callback); |
|
624 |
|||
625 |
2440 |
AllocScope alloc_scope(wrap); |
|
626 |
1220 |
wrap->context()->SetAllocationFunctions( |
|
627 |
AllocForZlib, FreeForZlib, static_cast<CompressionStream*>(wrap)); |
||
628 |
2440 |
wrap->context()->Init(level, window_bits, mem_level, strategy, |
|
629 |
1220 |
std::move(dictionary)); |
|
630 |
} |
||
631 |
|||
632 |
3 |
static void Params(const FunctionCallbackInfo<Value>& args) { |
|
633 |
✗✓✗✓ |
3 |
CHECK(args.Length() == 2 && "params(level, strategy)"); |
634 |
ZlibStream* wrap; |
||
635 |
✗✓ | 3 |
ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder()); |
636 |
3 |
Local<Context> context = args.GetIsolate()->GetCurrentContext(); |
|
637 |
int level; |
||
638 |
✗✓ | 6 |
if (!args[0]->Int32Value(context).To(&level)) return; |
639 |
int strategy; |
||
640 |
✗✓ | 6 |
if (!args[1]->Int32Value(context).To(&strategy)) return; |
641 |
|||
642 |
6 |
AllocScope alloc_scope(wrap); |
|
643 |
3 |
const CompressionError err = wrap->context()->SetParams(level, strategy); |
|
644 |
✗✓ | 3 |
if (err.IsError()) |
645 |
wrap->EmitError(err); |
||
646 |
} |
||
647 |
|||
648 |
SET_MEMORY_INFO_NAME(ZlibStream) |
||
649 |
SET_SELF_SIZE(ZlibStream) |
||
650 |
}; |
||
651 |
|||
652 |
template <typename CompressionContext> |
||
653 |
class BrotliCompressionStream final : |
||
654 |
public CompressionStream<CompressionContext> { |
||
655 |
public: |
||
656 |
462 |
BrotliCompressionStream(Environment* env, |
|
657 |
Local<Object> wrap, |
||
658 |
node_zlib_mode mode) |
||
659 |
462 |
: CompressionStream<CompressionContext>(env, wrap) { |
|
660 |
462 |
context()->SetMode(mode); |
|
661 |
462 |
} |
|
662 |
|||
663 |
950 |
inline CompressionContext* context() { |
|
664 |
950 |
return this->CompressionStream<CompressionContext>::context(); |
|
665 |
} |
||
666 |
typedef typename CompressionStream<CompressionContext>::AllocScope AllocScope; |
||
667 |
|||
668 |
462 |
static void New(const FunctionCallbackInfo<Value>& args) { |
|
669 |
462 |
Environment* env = Environment::GetCurrent(args); |
|
670 |
✗✓ | 462 |
CHECK(args[0]->IsInt32()); |
671 |
462 |
node_zlib_mode mode = |
|
672 |
924 |
static_cast<node_zlib_mode>(args[0].As<Int32>()->Value()); |
|
673 |
462 |
new BrotliCompressionStream(env, args.This(), mode); |
|
674 |
462 |
} |
|
675 |
|||
676 |
462 |
static void Init(const FunctionCallbackInfo<Value>& args) { |
|
677 |
BrotliCompressionStream* wrap; |
||
678 |
✗✓ | 464 |
ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder()); |
679 |
✗✓✗✓ |
462 |
CHECK(args.Length() == 3 && "init(params, writeResult, writeCallback)"); |
680 |
|||
681 |
✗✓ | 462 |
CHECK(args[1]->IsUint32Array()); |
682 |
462 |
uint32_t* write_result = reinterpret_cast<uint32_t*>(Buffer::Data(args[1])); |
|
683 |
|||
684 |
✗✓ | 462 |
CHECK(args[2]->IsFunction()); |
685 |
462 |
Local<Function> write_js_callback = args[2].As<Function>(); |
|
686 |
462 |
wrap->InitStream(write_result, write_js_callback); |
|
687 |
|||
688 |
462 |
AllocScope alloc_scope(wrap); |
|
689 |
462 |
CompressionError err = |
|
690 |
wrap->context()->Init( |
||
691 |
CompressionStream<CompressionContext>::AllocForBrotli, |
||
692 |
CompressionStream<CompressionContext>::FreeForZlib, |
||
693 |
static_cast<CompressionStream<CompressionContext>*>(wrap)); |
||
694 |
✗✓ | 462 |
if (err.IsError()) { |
695 |
wrap->EmitError(err); |
||
696 |
args.GetReturnValue().Set(false); |
||
697 |
return; |
||
698 |
} |
||
699 |
|||
700 |
✗✓ | 462 |
CHECK(args[0]->IsUint32Array()); |
701 |
462 |
const uint32_t* data = reinterpret_cast<uint32_t*>(Buffer::Data(args[0])); |
|
702 |
924 |
size_t len = args[0].As<Uint32Array>()->Length(); |
|
703 |
|||
704 |
✓✓ | 4610 |
for (int i = 0; static_cast<size_t>(i) < len; i++) { |
705 |
✓✓ | 4150 |
if (data[i] == static_cast<uint32_t>(-1)) |
706 |
4124 |
continue; |
|
707 |
26 |
err = wrap->context()->SetParams(i, data[i]); |
|
708 |
✓✓ | 26 |
if (err.IsError()) { |
709 |
2 |
wrap->EmitError(err); |
|
710 |
✗✓ | 2 |
args.GetReturnValue().Set(false); |
711 |
2 |
return; |
|
712 |
} |
||
713 |
} |
||
714 |
|||
715 |
✓✗ | 920 |
args.GetReturnValue().Set(true); |
716 |
} |
||
717 |
|||
718 |
static void Params(const FunctionCallbackInfo<Value>& args) { |
||
719 |
// Currently a no-op, and not accessed from JS land. |
||
720 |
// At some point Brotli may support changing parameters on the fly, |
||
721 |
// in which case we can implement this and a JS equivalent similar to |
||
722 |
// the zlib Params() function. |
||
723 |
} |
||
724 |
|||
725 |
SET_MEMORY_INFO_NAME(BrotliCompressionStream) |
||
726 |
SET_SELF_SIZE(BrotliCompressionStream) |
||
727 |
}; |
||
728 |
|||
729 |
using BrotliEncoderStream = BrotliCompressionStream<BrotliEncoderContext>; |
||
730 |
using BrotliDecoderStream = BrotliCompressionStream<BrotliDecoderContext>; |
||
731 |
|||
732 |
2033 |
void ZlibContext::Close() { |
|
733 |
{ |
||
734 |
2033 |
Mutex::ScopedLock lock(mutex_); |
|
735 |
✓✓ | 2033 |
if (!zlib_init_done_) { |
736 |
154 |
dictionary_.clear(); |
|
737 |
154 |
mode_ = NONE; |
|
738 |
154 |
return; |
|
739 |
} |
||
740 |
} |
||
741 |
|||
742 |
✗✓ | 1879 |
CHECK_LE(mode_, UNZIP); |
743 |
|||
744 |
1879 |
int status = Z_OK; |
|
745 |
✓✓✓✓ ✓✓ |
1879 |
if (mode_ == DEFLATE || mode_ == GZIP || mode_ == DEFLATERAW) { |
746 |
453 |
status = deflateEnd(&strm_); |
|
747 |
✓✓✓✓ ✓✓ |
1426 |
} else if (mode_ == INFLATE || mode_ == GUNZIP || mode_ == INFLATERAW || |
748 |
✗✓ | 932 |
mode_ == UNZIP) { |
749 |
494 |
status = inflateEnd(&strm_); |
|
750 |
} |
||
751 |
|||
752 |
✓✓✗✓ |
1879 |
CHECK(status == Z_OK || status == Z_DATA_ERROR); |
753 |
1879 |
mode_ = NONE; |
|
754 |
|||
755 |
1879 |
dictionary_.clear(); |
|
756 |
} |
||
757 |
|||
758 |
|||
759 |
7655 |
void ZlibContext::DoThreadPoolWork() { |
|
760 |
7655 |
bool first_init_call = InitZlib(); |
|
761 |
✓✓✗✓ |
7655 |
if (first_init_call && err_ != Z_OK) { |
762 |
return; |
||
763 |
} |
||
764 |
|||
765 |
7655 |
const Bytef* next_expected_header_byte = nullptr; |
|
766 |
|||
767 |
// If the avail_out is left at 0, then it means that it ran out |
||
768 |
// of room. If there was avail_out left over, then it means |
||
769 |
// that all of the input was consumed. |
||
770 |
✓✓✓✗ |
7655 |
switch (mode_) { |
771 |
1522 |
case DEFLATE: |
|
772 |
case GZIP: |
||
773 |
case DEFLATERAW: |
||
774 |
1522 |
err_ = deflate(&strm_, flush_); |
|
775 |
1522 |
break; |
|
776 |
232 |
case UNZIP: |
|
777 |
✓✓ | 232 |
if (strm_.avail_in > 0) { |
778 |
231 |
next_expected_header_byte = strm_.next_in; |
|
779 |
} |
||
780 |
|||
781 |
✓✓✗ | 232 |
switch (gzip_id_bytes_read_) { |
782 |
229 |
case 0: |
|
783 |
✗✓ | 229 |
if (next_expected_header_byte == nullptr) { |
784 |
break; |
||
785 |
} |
||
786 |
|||
787 |
✓✓ | 229 |
if (*next_expected_header_byte == GZIP_HEADER_ID1) { |
788 |
223 |
gzip_id_bytes_read_ = 1; |
|
789 |
223 |
next_expected_header_byte++; |
|
790 |
|||
791 |
✓✓ | 223 |
if (strm_.avail_in == 1) { |
792 |
// The only available byte was already read. |
||
793 |
2 |
break; |
|
794 |
} |
||
795 |
} else { |
||
796 |
6 |
mode_ = INFLATE; |
|
797 |
6 |
break; |
|
798 |
} |
||
799 |
|||
800 |
// fallthrough |
||
801 |
case 1: |
||
802 |
✓✓ | 224 |
if (next_expected_header_byte == nullptr) { |
803 |
1 |
break; |
|
804 |
} |
||
805 |
|||
806 |
✓✗ | 223 |
if (*next_expected_header_byte == GZIP_HEADER_ID2) { |
807 |
223 |
gzip_id_bytes_read_ = 2; |
|
808 |
223 |
mode_ = GUNZIP; |
|
809 |
} else { |
||
810 |
// There is no actual difference between INFLATE and INFLATERAW |
||
811 |
// (after initialization). |
||
812 |
mode_ = INFLATE; |
||
813 |
} |
||
814 |
|||
815 |
223 |
break; |
|
816 |
default: |
||
817 |
CHECK(0 && "invalid number of gzip magic number bytes read"); |
||
818 |
6133 |
} |
|
819 |
|||
820 |
// fallthrough |
||
821 |
case INFLATE: |
||
822 |
case GUNZIP: |
||
823 |
case INFLATERAW: |
||
824 |
6133 |
err_ = inflate(&strm_, flush_); |
|
825 |
|||
826 |
// If data was encoded with dictionary (INFLATERAW will have it set in |
||
827 |
// SetDictionary, don't repeat that here) |
||
828 |
16741 |
if (mode_ != INFLATERAW && |
|
829 |
✓✓✓✓ ✓✓ |
6147 |
err_ == Z_NEED_DICT && |
830 |
✓✓ | 14 |
!dictionary_.empty()) { |
831 |
// Load it |
||
832 |
13 |
err_ = inflateSetDictionary(&strm_, |
|
833 |
13 |
dictionary_.data(), |
|
834 |
13 |
dictionary_.size()); |
|
835 |
✓✓ | 13 |
if (err_ == Z_OK) { |
836 |
// And try to decode again |
||
837 |
12 |
err_ = inflate(&strm_, flush_); |
|
838 |
✓✗ | 1 |
} else if (err_ == Z_DATA_ERROR) { |
839 |
// Both inflateSetDictionary() and inflate() return Z_DATA_ERROR. |
||
840 |
// Make it possible for After() to tell a bad dictionary from bad |
||
841 |
// input. |
||
842 |
1 |
err_ = Z_NEED_DICT; |
|
843 |
} |
||
844 |
} |
||
845 |
|||
846 |
6811 |
while (strm_.avail_in > 0 && |
|
847 |
✓✓ | 638 |
mode_ == GUNZIP && |
848 |
✓✓✓✓ |
6747 |
err_ == Z_STREAM_END && |
849 |
✓✓ | 22 |
strm_.next_in[0] != 0x00) { |
850 |
// Bytes remain in input buffer. Perhaps this is another compressed |
||
851 |
// member in the same archive, or just trailing garbage. |
||
852 |
// Trailing zero bytes are okay, though, since they are frequently |
||
853 |
// used for padding. |
||
854 |
|||
855 |
20 |
ResetStream(); |
|
856 |
20 |
err_ = inflate(&strm_, flush_); |
|
857 |
} |
||
858 |
6133 |
break; |
|
859 |
default: |
||
860 |
UNREACHABLE(); |
||
861 |
} |
||
862 |
} |
||
863 |
|||
864 |
|||
865 |
7655 |
void ZlibContext::SetBuffers(const char* in, uint32_t in_len, |
|
866 |
char* out, uint32_t out_len) { |
||
867 |
7655 |
strm_.avail_in = in_len; |
|
868 |
7655 |
strm_.next_in = const_cast<Bytef*>(reinterpret_cast<const Bytef*>(in)); |
|
869 |
7655 |
strm_.avail_out = out_len; |
|
870 |
7655 |
strm_.next_out = reinterpret_cast<Bytef*>(out); |
|
871 |
7655 |
} |
|
872 |
|||
873 |
|||
874 |
7655 |
void ZlibContext::SetFlush(int flush) { |
|
875 |
7655 |
flush_ = flush; |
|
876 |
7655 |
} |
|
877 |
|||
878 |
|||
879 |
7633 |
void ZlibContext::GetAfterWriteOffsets(uint32_t* avail_in, |
|
880 |
uint32_t* avail_out) const { |
||
881 |
7633 |
*avail_in = strm_.avail_in; |
|
882 |
7633 |
*avail_out = strm_.avail_out; |
|
883 |
7633 |
} |
|
884 |
|||
885 |
|||
886 |
22 |
CompressionError ZlibContext::ErrorForMessage(const char* message) const { |
|
887 |
✓✓ | 22 |
if (strm_.msg != nullptr) |
888 |
12 |
message = strm_.msg; |
|
889 |
|||
890 |
22 |
return CompressionError { message, ZlibStrerror(err_), err_ }; |
|
891 |
} |
||
892 |
|||
893 |
|||
894 |
7655 |
CompressionError ZlibContext::GetErrorInfo() const { |
|
895 |
// Acceptable error states depend on the type of zlib stream. |
||
896 |
✓✓✓✓ |
7655 |
switch (err_) { |
897 |
6177 |
case Z_OK: |
|
898 |
case Z_BUF_ERROR: |
||
899 |
✓✓✓✓ |
6177 |
if (strm_.avail_out != 0 && flush_ == Z_FINISH) { |
900 |
8 |
return ErrorForMessage("unexpected end of file"); |
|
901 |
} |
||
902 |
case Z_STREAM_END: |
||
903 |
// normal statuses, not fatal |
||
904 |
7633 |
break; |
|
905 |
2 |
case Z_NEED_DICT: |
|
906 |
✓✓ | 2 |
if (dictionary_.empty()) |
907 |
1 |
return ErrorForMessage("Missing dictionary"); |
|
908 |
else |
||
909 |
1 |
return ErrorForMessage("Bad dictionary"); |
|
910 |
12 |
default: |
|
911 |
// something else. |
||
912 |
12 |
return ErrorForMessage("Zlib error"); |
|
913 |
} |
||
914 |
|||
915 |
7633 |
return CompressionError {}; |
|
916 |
} |
||
917 |
|||
918 |
|||
919 |
34 |
CompressionError ZlibContext::ResetStream() { |
|
920 |
34 |
bool first_init_call = InitZlib(); |
|
921 |
✓✓✗✓ |
34 |
if (first_init_call && err_ != Z_OK) { |
922 |
return ErrorForMessage("Failed to init stream before reset"); |
||
923 |
} |
||
924 |
|||
925 |
34 |
err_ = Z_OK; |
|
926 |
|||
927 |
✓✓✗ | 34 |
switch (mode_) { |
928 |
13 |
case DEFLATE: |
|
929 |
case DEFLATERAW: |
||
930 |
case GZIP: |
||
931 |
13 |
err_ = deflateReset(&strm_); |
|
932 |
13 |
break; |
|
933 |
21 |
case INFLATE: |
|
934 |
case INFLATERAW: |
||
935 |
case GUNZIP: |
||
936 |
21 |
err_ = inflateReset(&strm_); |
|
937 |
21 |
break; |
|
938 |
default: |
||
939 |
break; |
||
940 |
} |
||
941 |
|||
942 |
✗✓ | 34 |
if (err_ != Z_OK) |
943 |
return ErrorForMessage("Failed to reset stream"); |
||
944 |
|||
945 |
34 |
return SetDictionary(); |
|
946 |
} |
||
947 |
|||
948 |
|||
949 |
1220 |
void ZlibContext::SetAllocationFunctions(alloc_func alloc, |
|
950 |
free_func free, |
||
951 |
void* opaque) { |
||
952 |
1220 |
strm_.zalloc = alloc; |
|
953 |
1220 |
strm_.zfree = free; |
|
954 |
1220 |
strm_.opaque = opaque; |
|
955 |
1220 |
} |
|
956 |
|||
957 |
|||
958 |
1220 |
void ZlibContext::Init( |
|
959 |
int level, int window_bits, int mem_level, int strategy, |
||
960 |
std::vector<unsigned char>&& dictionary) { |
||
961 |
✓✓ | 1220 |
if (!((window_bits == 0) && |
962 |
✓✓ | 390 |
(mode_ == INFLATE || |
963 |
✓✓ | 295 |
mode_ == GUNZIP || |
964 |
✗✓ | 204 |
mode_ == UNZIP))) { |
965 |
✓✗✗✓ |
830 |
CHECK( |
966 |
(window_bits >= Z_MIN_WINDOWBITS && window_bits <= Z_MAX_WINDOWBITS) && |
||
967 |
"invalid windowBits"); |
||
968 |
} |
||
969 |
|||
970 |
✓✗✗✓ |
1220 |
CHECK((level >= Z_MIN_LEVEL && level <= Z_MAX_LEVEL) && |
971 |
"invalid compression level"); |
||
972 |
|||
973 |
✓✗✗✓ |
1220 |
CHECK((mem_level >= Z_MIN_MEMLEVEL && mem_level <= Z_MAX_MEMLEVEL) && |
974 |
"invalid memlevel"); |
||
975 |
|||
976 |
✓✓✓✓ ✓✓✓✓ ✓✓✓✓ ✓✓✗✓ |
1220 |
CHECK((strategy == Z_FILTERED || strategy == Z_HUFFMAN_ONLY || |
977 |
strategy == Z_RLE || strategy == Z_FIXED || |
||
978 |
strategy == Z_DEFAULT_STRATEGY) && |
||
979 |
"invalid strategy"); |
||
980 |
|||
981 |
1220 |
level_ = level; |
|
982 |
1220 |
window_bits_ = window_bits; |
|
983 |
1220 |
mem_level_ = mem_level; |
|
984 |
1220 |
strategy_ = strategy; |
|
985 |
|||
986 |
1220 |
flush_ = Z_NO_FLUSH; |
|
987 |
|||
988 |
1220 |
err_ = Z_OK; |
|
989 |
|||
990 |
✓✓✓✓ |
1220 |
if (mode_ == GZIP || mode_ == GUNZIP) { |
991 |
468 |
window_bits_ += 16; |
|
992 |
} |
||
993 |
|||
994 |
✓✓ | 1220 |
if (mode_ == UNZIP) { |
995 |
230 |
window_bits_ += 32; |
|
996 |
} |
||
997 |
|||
998 |
✓✓✓✓ |
1220 |
if (mode_ == DEFLATERAW || mode_ == INFLATERAW) { |
999 |
243 |
window_bits_ *= -1; |
|
1000 |
} |
||
1001 |
|||
1002 |
1220 |
dictionary_ = std::move(dictionary); |
|
1003 |
1220 |
} |
|
1004 |
|||
1005 |
7692 |
bool ZlibContext::InitZlib() { |
|
1006 |
15384 |
Mutex::ScopedLock lock(mutex_); |
|
1007 |
✓✓ | 7692 |
if (zlib_init_done_) { |
1008 |
6624 |
return false; |
|
1009 |
} |
||
1010 |
|||
1011 |
✓✓✗ | 1068 |
switch (mode_) { |
1012 |
453 |
case DEFLATE: |
|
1013 |
case GZIP: |
||
1014 |
case DEFLATERAW: |
||
1015 |
453 |
err_ = deflateInit2(&strm_, |
|
1016 |
level_, |
||
1017 |
Z_DEFLATED, |
||
1018 |
window_bits_, |
||
1019 |
mem_level_, |
||
1020 |
strategy_); |
||
1021 |
453 |
break; |
|
1022 |
615 |
case INFLATE: |
|
1023 |
case GUNZIP: |
||
1024 |
case INFLATERAW: |
||
1025 |
case UNZIP: |
||
1026 |
615 |
err_ = inflateInit2(&strm_, window_bits_); |
|
1027 |
615 |
break; |
|
1028 |
default: |
||
1029 |
UNREACHABLE(); |
||
1030 |
} |
||
1031 |
|||
1032 |
✗✓ | 1068 |
if (err_ != Z_OK) { |
1033 |
dictionary_.clear(); |
||
1034 |
mode_ = NONE; |
||
1035 |
return true; |
||
1036 |
} |
||
1037 |
|||
1038 |
1068 |
SetDictionary(); |
|
1039 |
1068 |
zlib_init_done_ = true; |
|
1040 |
1068 |
return true; |
|
1041 |
} |
||
1042 |
|||
1043 |
|||
1044 |
1102 |
CompressionError ZlibContext::SetDictionary() { |
|
1045 |
✓✓ | 1102 |
if (dictionary_.empty()) |
1046 |
1040 |
return CompressionError {}; |
|
1047 |
|||
1048 |
62 |
err_ = Z_OK; |
|
1049 |
|||
1050 |
✓✓✓ | 62 |
switch (mode_) { |
1051 |
36 |
case DEFLATE: |
|
1052 |
case DEFLATERAW: |
||
1053 |
36 |
err_ = deflateSetDictionary(&strm_, |
|
1054 |
36 |
dictionary_.data(), |
|
1055 |
36 |
dictionary_.size()); |
|
1056 |
36 |
break; |
|
1057 |
13 |
case INFLATERAW: |
|
1058 |
// The other inflate cases will have the dictionary set when inflate() |
||
1059 |
// returns Z_NEED_DICT in Process() |
||
1060 |
13 |
err_ = inflateSetDictionary(&strm_, |
|
1061 |
13 |
dictionary_.data(), |
|
1062 |
13 |
dictionary_.size()); |
|
1063 |
13 |
break; |
|
1064 |
13 |
default: |
|
1065 |
13 |
break; |
|
1066 |
} |
||
1067 |
|||
1068 |
✗✓ | 62 |
if (err_ != Z_OK) { |
1069 |
return ErrorForMessage("Failed to set dictionary"); |
||
1070 |
} |
||
1071 |
|||
1072 |
62 |
return CompressionError {}; |
|
1073 |
} |
||
1074 |
|||
1075 |
|||
1076 |
3 |
CompressionError ZlibContext::SetParams(int level, int strategy) { |
|
1077 |
3 |
bool first_init_call = InitZlib(); |
|
1078 |
✗✓✗✗ |
3 |
if (first_init_call && err_ != Z_OK) { |
1079 |
return ErrorForMessage("Failed to init stream before set parameters"); |
||
1080 |
} |
||
1081 |
|||
1082 |
3 |
err_ = Z_OK; |
|
1083 |
|||
1084 |
✓✓ | 3 |
switch (mode_) { |
1085 |
2 |
case DEFLATE: |
|
1086 |
case DEFLATERAW: |
||
1087 |
2 |
err_ = deflateParams(&strm_, level, strategy); |
|
1088 |
2 |
break; |
|
1089 |
1 |
default: |
|
1090 |
1 |
break; |
|
1091 |
} |
||
1092 |
|||
1093 |
✗✓✗✗ |
3 |
if (err_ != Z_OK && err_ != Z_BUF_ERROR) { |
1094 |
return ErrorForMessage("Failed to set parameters"); |
||
1095 |
} |
||
1096 |
|||
1097 |
3 |
return CompressionError {}; |
|
1098 |
} |
||
1099 |
|||
1100 |
|||
1101 |
1375 |
void BrotliContext::SetBuffers(const char* in, uint32_t in_len, |
|
1102 |
char* out, uint32_t out_len) { |
||
1103 |
1375 |
next_in_ = reinterpret_cast<const uint8_t*>(in); |
|
1104 |
1375 |
next_out_ = reinterpret_cast<uint8_t*>(out); |
|
1105 |
1375 |
avail_in_ = in_len; |
|
1106 |
1375 |
avail_out_ = out_len; |
|
1107 |
1375 |
} |
|
1108 |
|||
1109 |
|||
1110 |
1375 |
void BrotliContext::SetFlush(int flush) { |
|
1111 |
1375 |
flush_ = static_cast<BrotliEncoderOperation>(flush); |
|
1112 |
1375 |
} |
|
1113 |
|||
1114 |
|||
1115 |
1374 |
void BrotliContext::GetAfterWriteOffsets(uint32_t* avail_in, |
|
1116 |
uint32_t* avail_out) const { |
||
1117 |
1374 |
*avail_in = avail_in_; |
|
1118 |
1374 |
*avail_out = avail_out_; |
|
1119 |
1374 |
} |
|
1120 |
|||
1121 |
|||
1122 |
349 |
void BrotliEncoderContext::DoThreadPoolWork() { |
|
1123 |
✗✓ | 349 |
CHECK_EQ(mode_, BROTLI_ENCODE); |
1124 |
✗✓ | 349 |
CHECK(state_); |
1125 |
349 |
const uint8_t* next_in = next_in_; |
|
1126 |
349 |
last_result_ = BrotliEncoderCompressStream(state_.get(), |
|
1127 |
flush_, |
||
1128 |
&avail_in_, |
||
1129 |
&next_in, |
||
1130 |
&avail_out_, |
||
1131 |
&next_out_, |
||
1132 |
349 |
nullptr); |
|
1133 |
349 |
next_in_ += next_in - next_in_; |
|
1134 |
349 |
} |
|
1135 |
|||
1136 |
|||
1137 |
230 |
void BrotliEncoderContext::Close() { |
|
1138 |
230 |
state_.reset(); |
|
1139 |
230 |
mode_ = NONE; |
|
1140 |
230 |
} |
|
1141 |
|||
1142 |
117 |
CompressionError BrotliEncoderContext::Init(brotli_alloc_func alloc, |
|
1143 |
brotli_free_func free, |
||
1144 |
void* opaque) { |
||
1145 |
117 |
alloc_ = alloc; |
|
1146 |
117 |
free_ = free; |
|
1147 |
117 |
alloc_opaque_ = opaque; |
|
1148 |
117 |
state_.reset(BrotliEncoderCreateInstance(alloc, free, opaque)); |
|
1149 |
✗✓ | 117 |
if (!state_) { |
1150 |
return CompressionError("Could not initialize Brotli instance", |
||
1151 |
"ERR_ZLIB_INITIALIZATION_FAILED", |
||
1152 |
-1); |
||
1153 |
} else { |
||
1154 |
117 |
return CompressionError {}; |
|
1155 |
} |
||
1156 |
} |
||
1157 |
|||
1158 |
CompressionError BrotliEncoderContext::ResetStream() { |
||
1159 |
return Init(alloc_, free_, alloc_opaque_); |
||
1160 |
} |
||
1161 |
|||
1162 |
13 |
CompressionError BrotliEncoderContext::SetParams(int key, uint32_t value) { |
|
1163 |
✓✓ | 13 |
if (!BrotliEncoderSetParameter(state_.get(), |
1164 |
static_cast<BrotliEncoderParameter>(key), |
||
1165 |
value)) { |
||
1166 |
return CompressionError("Setting parameter failed", |
||
1167 |
"ERR_BROTLI_PARAM_SET_FAILED", |
||
1168 |
1 |
-1); |
|
1169 |
} else { |
||
1170 |
12 |
return CompressionError {}; |
|
1171 |
} |
||
1172 |
} |
||
1173 |
|||
1174 |
349 |
CompressionError BrotliEncoderContext::GetErrorInfo() const { |
|
1175 |
✗✓ | 349 |
if (!last_result_) { |
1176 |
return CompressionError("Compression failed", |
||
1177 |
"ERR_BROTLI_COMPRESSION_FAILED", |
||
1178 |
-1); |
||
1179 |
} else { |
||
1180 |
349 |
return CompressionError {}; |
|
1181 |
} |
||
1182 |
} |
||
1183 |
|||
1184 |
|||
1185 |
226 |
void BrotliDecoderContext::Close() { |
|
1186 |
226 |
state_.reset(); |
|
1187 |
226 |
mode_ = NONE; |
|
1188 |
226 |
} |
|
1189 |
|||
1190 |
1026 |
void BrotliDecoderContext::DoThreadPoolWork() { |
|
1191 |
✗✓ | 1026 |
CHECK_EQ(mode_, BROTLI_DECODE); |
1192 |
✗✓ | 1026 |
CHECK(state_); |
1193 |
1026 |
const uint8_t* next_in = next_in_; |
|
1194 |
1026 |
last_result_ = BrotliDecoderDecompressStream(state_.get(), |
|
1195 |
&avail_in_, |
||
1196 |
&next_in, |
||
1197 |
&avail_out_, |
||
1198 |
&next_out_, |
||
1199 |
nullptr); |
||
1200 |
1026 |
next_in_ += next_in - next_in_; |
|
1201 |
✓✓ | 1026 |
if (last_result_ == BROTLI_DECODER_RESULT_ERROR) { |
1202 |
1 |
error_ = BrotliDecoderGetErrorCode(state_.get()); |
|
1203 |
1 |
error_string_ = std::string("ERR_") + BrotliDecoderErrorString(error_); |
|
1204 |
} |
||
1205 |
1026 |
} |
|
1206 |
|||
1207 |
114 |
CompressionError BrotliDecoderContext::Init(brotli_alloc_func alloc, |
|
1208 |
brotli_free_func free, |
||
1209 |
void* opaque) { |
||
1210 |
114 |
alloc_ = alloc; |
|
1211 |
114 |
free_ = free; |
|
1212 |
114 |
alloc_opaque_ = opaque; |
|
1213 |
114 |
state_.reset(BrotliDecoderCreateInstance(alloc, free, opaque)); |
|
1214 |
✗✓ | 114 |
if (!state_) { |
1215 |
return CompressionError("Could not initialize Brotli instance", |
||
1216 |
"ERR_ZLIB_INITIALIZATION_FAILED", |
||
1217 |
-1); |
||
1218 |
} else { |
||
1219 |
114 |
return CompressionError {}; |
|
1220 |
} |
||
1221 |
} |
||
1222 |
|||
1223 |
CompressionError BrotliDecoderContext::ResetStream() { |
||
1224 |
return Init(alloc_, free_, alloc_opaque_); |
||
1225 |
} |
||
1226 |
|||
1227 |
CompressionError BrotliDecoderContext::SetParams(int key, uint32_t value) { |
||
1228 |
if (!BrotliDecoderSetParameter(state_.get(), |
||
1229 |
static_cast<BrotliDecoderParameter>(key), |
||
1230 |
value)) { |
||
1231 |
return CompressionError("Setting parameter failed", |
||
1232 |
"ERR_BROTLI_PARAM_SET_FAILED", |
||
1233 |
-1); |
||
1234 |
} else { |
||
1235 |
return CompressionError {}; |
||
1236 |
} |
||
1237 |
} |
||
1238 |
|||
1239 |
1026 |
CompressionError BrotliDecoderContext::GetErrorInfo() const { |
|
1240 |
✓✓ | 1026 |
if (error_ != BROTLI_DECODER_NO_ERROR) { |
1241 |
return CompressionError("Decompression failed", |
||
1242 |
error_string_.c_str(), |
||
1243 |
1 |
static_cast<int>(error_)); |
|
1244 |
✓✓ | 1025 |
} else if (flush_ == BROTLI_OPERATION_FINISH && |
1245 |
✗✓ | 110 |
last_result_ == BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT) { |
1246 |
// Match zlib's behaviour, as brotli doesn't have its own code for this. |
||
1247 |
return CompressionError("unexpected end of file", |
||
1248 |
"Z_BUF_ERROR", |
||
1249 |
Z_BUF_ERROR); |
||
1250 |
} else { |
||
1251 |
1025 |
return CompressionError {}; |
|
1252 |
} |
||
1253 |
} |
||
1254 |
|||
1255 |
|||
1256 |
template <typename Stream> |
||
1257 |
struct MakeClass { |
||
1258 |
432 |
static void Make(Environment* env, Local<Object> target, const char* name) { |
|
1259 |
432 |
Isolate* isolate = env->isolate(); |
|
1260 |
432 |
Local<FunctionTemplate> z = NewFunctionTemplate(isolate, Stream::New); |
|
1261 |
|||
1262 |
864 |
z->InstanceTemplate()->SetInternalFieldCount( |
|
1263 |
Stream::kInternalFieldCount); |
||
1264 |
432 |
z->Inherit(AsyncWrap::GetConstructorTemplate(env)); |
|
1265 |
|||
1266 |
432 |
SetProtoMethod(isolate, z, "write", Stream::template Write<true>); |
|
1267 |
432 |
SetProtoMethod(isolate, z, "writeSync", Stream::template Write<false>); |
|
1268 |
432 |
SetProtoMethod(isolate, z, "close", Stream::Close); |
|
1269 |
|||
1270 |
432 |
SetProtoMethod(isolate, z, "init", Stream::Init); |
|
1271 |
432 |
SetProtoMethod(isolate, z, "params", Stream::Params); |
|
1272 |
432 |
SetProtoMethod(isolate, z, "reset", Stream::Reset); |
|
1273 |
|||
1274 |
432 |
SetConstructorFunction(env->context(), target, name, z); |
|
1275 |
432 |
} |
|
1276 |
|||
1277 |
33084 |
static void Make(ExternalReferenceRegistry* registry) { |
|
1278 |
33084 |
registry->Register(Stream::New); |
|
1279 |
33084 |
registry->Register(Stream::template Write<true>); |
|
1280 |
33084 |
registry->Register(Stream::template Write<false>); |
|
1281 |
33084 |
registry->Register(Stream::Close); |
|
1282 |
33084 |
registry->Register(Stream::Init); |
|
1283 |
33084 |
registry->Register(Stream::Params); |
|
1284 |
33084 |
registry->Register(Stream::Reset); |
|
1285 |
33084 |
} |
|
1286 |
}; |
||
1287 |
|||
1288 |
72 |
void Initialize(Local<Object> target, |
|
1289 |
Local<Value> unused, |
||
1290 |
Local<Context> context, |
||
1291 |
void* priv) { |
||
1292 |
72 |
Environment* env = Environment::GetCurrent(context); |
|
1293 |
|||
1294 |
72 |
MakeClass<ZlibStream>::Make(env, target, "Zlib"); |
|
1295 |
72 |
MakeClass<BrotliEncoderStream>::Make(env, target, "BrotliEncoder"); |
|
1296 |
72 |
MakeClass<BrotliDecoderStream>::Make(env, target, "BrotliDecoder"); |
|
1297 |
|||
1298 |
72 |
target->Set(env->context(), |
|
1299 |
FIXED_ONE_BYTE_STRING(env->isolate(), "ZLIB_VERSION"), |
||
1300 |
216 |
FIXED_ONE_BYTE_STRING(env->isolate(), ZLIB_VERSION)).Check(); |
|
1301 |
72 |
} |
|
1302 |
|||
1303 |
5514 |
void RegisterExternalReferences(ExternalReferenceRegistry* registry) { |
|
1304 |
5514 |
MakeClass<ZlibStream>::Make(registry); |
|
1305 |
5514 |
MakeClass<BrotliEncoderStream>::Make(registry); |
|
1306 |
5514 |
MakeClass<BrotliDecoderStream>::Make(registry); |
|
1307 |
5514 |
} |
|
1308 |
|||
1309 |
} // anonymous namespace |
||
1310 |
|||
1311 |
785 |
void DefineZlibConstants(Local<Object> target) { |
|
1312 |
2355 |
NODE_DEFINE_CONSTANT(target, Z_NO_FLUSH); |
|
1313 |
2355 |
NODE_DEFINE_CONSTANT(target, Z_PARTIAL_FLUSH); |
|
1314 |
2355 |
NODE_DEFINE_CONSTANT(target, Z_SYNC_FLUSH); |
|
1315 |
2355 |
NODE_DEFINE_CONSTANT(target, Z_FULL_FLUSH); |
|
1316 |
2355 |
NODE_DEFINE_CONSTANT(target, Z_FINISH); |
|
1317 |
2355 |
NODE_DEFINE_CONSTANT(target, Z_BLOCK); |
|
1318 |
|||
1319 |
// return/error codes |
||
1320 |
2355 |
NODE_DEFINE_CONSTANT(target, Z_OK); |
|
1321 |
2355 |
NODE_DEFINE_CONSTANT(target, Z_STREAM_END); |
|
1322 |
2355 |
NODE_DEFINE_CONSTANT(target, Z_NEED_DICT); |
|
1323 |
2355 |
NODE_DEFINE_CONSTANT(target, Z_ERRNO); |
|
1324 |
2355 |
NODE_DEFINE_CONSTANT(target, Z_STREAM_ERROR); |
|
1325 |
2355 |
NODE_DEFINE_CONSTANT(target, Z_DATA_ERROR); |
|
1326 |
2355 |
NODE_DEFINE_CONSTANT(target, Z_MEM_ERROR); |
|
1327 |
2355 |
NODE_DEFINE_CONSTANT(target, Z_BUF_ERROR); |
|
1328 |
2355 |
NODE_DEFINE_CONSTANT(target, Z_VERSION_ERROR); |
|
1329 |
|||
1330 |
2355 |
NODE_DEFINE_CONSTANT(target, Z_NO_COMPRESSION); |
|
1331 |
2355 |
NODE_DEFINE_CONSTANT(target, Z_BEST_SPEED); |
|
1332 |
2355 |
NODE_DEFINE_CONSTANT(target, Z_BEST_COMPRESSION); |
|
1333 |
2355 |
NODE_DEFINE_CONSTANT(target, Z_DEFAULT_COMPRESSION); |
|
1334 |
2355 |
NODE_DEFINE_CONSTANT(target, Z_FILTERED); |
|
1335 |
2355 |
NODE_DEFINE_CONSTANT(target, Z_HUFFMAN_ONLY); |
|
1336 |
2355 |
NODE_DEFINE_CONSTANT(target, Z_RLE); |
|
1337 |
2355 |
NODE_DEFINE_CONSTANT(target, Z_FIXED); |
|
1338 |
2355 |
NODE_DEFINE_CONSTANT(target, Z_DEFAULT_STRATEGY); |
|
1339 |
2355 |
NODE_DEFINE_CONSTANT(target, ZLIB_VERNUM); |
|
1340 |
|||
1341 |
2355 |
NODE_DEFINE_CONSTANT(target, DEFLATE); |
|
1342 |
2355 |
NODE_DEFINE_CONSTANT(target, INFLATE); |
|
1343 |
2355 |
NODE_DEFINE_CONSTANT(target, GZIP); |
|
1344 |
2355 |
NODE_DEFINE_CONSTANT(target, GUNZIP); |
|
1345 |
2355 |
NODE_DEFINE_CONSTANT(target, DEFLATERAW); |
|
1346 |
2355 |
NODE_DEFINE_CONSTANT(target, INFLATERAW); |
|
1347 |
2355 |
NODE_DEFINE_CONSTANT(target, UNZIP); |
|
1348 |
2355 |
NODE_DEFINE_CONSTANT(target, BROTLI_DECODE); |
|
1349 |
2355 |
NODE_DEFINE_CONSTANT(target, BROTLI_ENCODE); |
|
1350 |
|||
1351 |
2355 |
NODE_DEFINE_CONSTANT(target, Z_MIN_WINDOWBITS); |
|
1352 |
2355 |
NODE_DEFINE_CONSTANT(target, Z_MAX_WINDOWBITS); |
|
1353 |
2355 |
NODE_DEFINE_CONSTANT(target, Z_DEFAULT_WINDOWBITS); |
|
1354 |
2355 |
NODE_DEFINE_CONSTANT(target, Z_MIN_CHUNK); |
|
1355 |
2355 |
NODE_DEFINE_CONSTANT(target, Z_MAX_CHUNK); |
|
1356 |
2355 |
NODE_DEFINE_CONSTANT(target, Z_DEFAULT_CHUNK); |
|
1357 |
2355 |
NODE_DEFINE_CONSTANT(target, Z_MIN_MEMLEVEL); |
|
1358 |
2355 |
NODE_DEFINE_CONSTANT(target, Z_MAX_MEMLEVEL); |
|
1359 |
2355 |
NODE_DEFINE_CONSTANT(target, Z_DEFAULT_MEMLEVEL); |
|
1360 |
2355 |
NODE_DEFINE_CONSTANT(target, Z_MIN_LEVEL); |
|
1361 |
2355 |
NODE_DEFINE_CONSTANT(target, Z_MAX_LEVEL); |
|
1362 |
2355 |
NODE_DEFINE_CONSTANT(target, Z_DEFAULT_LEVEL); |
|
1363 |
|||
1364 |
// Brotli constants |
||
1365 |
2355 |
NODE_DEFINE_CONSTANT(target, BROTLI_OPERATION_PROCESS); |
|
1366 |
2355 |
NODE_DEFINE_CONSTANT(target, BROTLI_OPERATION_FLUSH); |
|
1367 |
2355 |
NODE_DEFINE_CONSTANT(target, BROTLI_OPERATION_FINISH); |
|
1368 |
2355 |
NODE_DEFINE_CONSTANT(target, BROTLI_OPERATION_EMIT_METADATA); |
|
1369 |
2355 |
NODE_DEFINE_CONSTANT(target, BROTLI_PARAM_MODE); |
|
1370 |
2355 |
NODE_DEFINE_CONSTANT(target, BROTLI_MODE_GENERIC); |
|
1371 |
2355 |
NODE_DEFINE_CONSTANT(target, BROTLI_MODE_TEXT); |
|
1372 |
2355 |
NODE_DEFINE_CONSTANT(target, BROTLI_MODE_FONT); |
|
1373 |
2355 |
NODE_DEFINE_CONSTANT(target, BROTLI_DEFAULT_MODE); |
|
1374 |
2355 |
NODE_DEFINE_CONSTANT(target, BROTLI_PARAM_QUALITY); |
|
1375 |
2355 |
NODE_DEFINE_CONSTANT(target, BROTLI_MIN_QUALITY); |
|
1376 |
2355 |
NODE_DEFINE_CONSTANT(target, BROTLI_MAX_QUALITY); |
|
1377 |
2355 |
NODE_DEFINE_CONSTANT(target, BROTLI_DEFAULT_QUALITY); |
|
1378 |
2355 |
NODE_DEFINE_CONSTANT(target, BROTLI_PARAM_LGWIN); |
|
1379 |
2355 |
NODE_DEFINE_CONSTANT(target, BROTLI_MIN_WINDOW_BITS); |
|
1380 |
2355 |
NODE_DEFINE_CONSTANT(target, BROTLI_MAX_WINDOW_BITS); |
|
1381 |
2355 |
NODE_DEFINE_CONSTANT(target, BROTLI_LARGE_MAX_WINDOW_BITS); |
|
1382 |
2355 |
NODE_DEFINE_CONSTANT(target, BROTLI_DEFAULT_WINDOW); |
|
1383 |
2355 |
NODE_DEFINE_CONSTANT(target, BROTLI_PARAM_LGBLOCK); |
|
1384 |
2355 |
NODE_DEFINE_CONSTANT(target, BROTLI_MIN_INPUT_BLOCK_BITS); |
|
1385 |
2355 |
NODE_DEFINE_CONSTANT(target, BROTLI_MAX_INPUT_BLOCK_BITS); |
|
1386 |
2355 |
NODE_DEFINE_CONSTANT(target, BROTLI_PARAM_DISABLE_LITERAL_CONTEXT_MODELING); |
|
1387 |
2355 |
NODE_DEFINE_CONSTANT(target, BROTLI_PARAM_SIZE_HINT); |
|
1388 |
2355 |
NODE_DEFINE_CONSTANT(target, BROTLI_PARAM_LARGE_WINDOW); |
|
1389 |
2355 |
NODE_DEFINE_CONSTANT(target, BROTLI_PARAM_NPOSTFIX); |
|
1390 |
2355 |
NODE_DEFINE_CONSTANT(target, BROTLI_PARAM_NDIRECT); |
|
1391 |
2355 |
NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_RESULT_ERROR); |
|
1392 |
2355 |
NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_RESULT_SUCCESS); |
|
1393 |
2355 |
NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT); |
|
1394 |
2355 |
NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT); |
|
1395 |
2355 |
NODE_DEFINE_CONSTANT(target, |
|
1396 |
BROTLI_DECODER_PARAM_DISABLE_RING_BUFFER_REALLOCATION); |
||
1397 |
2355 |
NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_PARAM_LARGE_WINDOW); |
|
1398 |
2355 |
NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_NO_ERROR); |
|
1399 |
2355 |
NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_SUCCESS); |
|
1400 |
2355 |
NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_NEEDS_MORE_INPUT); |
|
1401 |
2355 |
NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_NEEDS_MORE_OUTPUT); |
|
1402 |
2355 |
NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_NIBBLE); |
|
1403 |
2355 |
NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_RESERVED); |
|
1404 |
2355 |
NODE_DEFINE_CONSTANT(target, |
|
1405 |
BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_META_NIBBLE); |
||
1406 |
2355 |
NODE_DEFINE_CONSTANT(target, |
|
1407 |
BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_ALPHABET); |
||
1408 |
2355 |
NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_SAME); |
|
1409 |
2355 |
NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_CL_SPACE); |
|
1410 |
2355 |
NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_HUFFMAN_SPACE); |
|
1411 |
2355 |
NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_CONTEXT_MAP_REPEAT); |
|
1412 |
2355 |
NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_1); |
|
1413 |
2355 |
NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_2); |
|
1414 |
2355 |
NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_TRANSFORM); |
|
1415 |
2355 |
NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_DICTIONARY); |
|
1416 |
2355 |
NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_WINDOW_BITS); |
|
1417 |
2355 |
NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_PADDING_1); |
|
1418 |
2355 |
NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_PADDING_2); |
|
1419 |
2355 |
NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_DISTANCE); |
|
1420 |
2355 |
NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_DICTIONARY_NOT_SET); |
|
1421 |
2355 |
NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_INVALID_ARGUMENTS); |
|
1422 |
2355 |
NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MODES); |
|
1423 |
2355 |
NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_ALLOC_TREE_GROUPS); |
|
1424 |
2355 |
NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MAP); |
|
1425 |
2355 |
NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_1); |
|
1426 |
2355 |
NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_2); |
|
1427 |
2355 |
NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_ALLOC_BLOCK_TYPE_TREES); |
|
1428 |
1570 |
NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_UNREACHABLE); |
|
1429 |
785 |
} |
|
1430 |
|||
1431 |
} // namespace node |
||
1432 |
|||
1433 |
5584 |
NODE_MODULE_CONTEXT_AWARE_INTERNAL(zlib, node::Initialize) |
|
1434 |
5514 |
NODE_MODULE_EXTERNAL_REFERENCE(zlib, node::RegisterExternalReferences) |
Generated by: GCOVR (Version 4.2) |