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