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