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