MIRROR: javascript for 馃悳's, a tiny runtime with big ambitions
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at mir/inline-method 807 lines 28 kB view raw
1#include <compat.h> 2 3#include <stdlib.h> 4#include <string.h> 5#include <zlib.h> 6 7#include "ant.h" 8#include "ptr.h" 9#include "errors.h" 10#include "internal.h" 11 12#include "silver/engine.h" 13#include "streams/brotli.h" 14#include "modules/buffer.h" 15#include "modules/events.h" 16#include "modules/symbol.h" 17#include "modules/zlib.h" 18 19#define ZLIB_CHUNK 16384 20#define ZLIB_STREAM_TAG 0x5A4C4942u 21 22typedef enum { 23 ZLIB_KIND_GZIP, 24 ZLIB_KIND_GUNZIP, 25 ZLIB_KIND_DEFLATE, 26 ZLIB_KIND_INFLATE, 27 ZLIB_KIND_DEFLATE_RAW, 28 ZLIB_KIND_INFLATE_RAW, 29 ZLIB_KIND_UNZIP, 30 ZLIB_KIND_BROTLI_COMPRESS, 31 ZLIB_KIND_BROTLI_DECOMPRESS, 32} zlib_kind_t; 33 34typedef struct zlib_stream_s { 35 z_stream strm; 36 brotli_stream_state_t *brotli; 37 ant_value_t obj; 38 ant_t *js; 39 zlib_kind_t kind; 40 uint32_t bytes_written; 41 bool initialized; 42 bool ended; 43 bool destroyed; 44 struct zlib_stream_s *next_active; 45} zlib_stream_t; 46 47static ant_value_t g_transform_proto = 0; 48static zlib_stream_t *g_active_streams = NULL; 49 50static bool zlib_kind_is_compress(zlib_kind_t k) { 51 return 52 k == ZLIB_KIND_GZIP 53 || k == ZLIB_KIND_DEFLATE 54 || k == ZLIB_KIND_DEFLATE_RAW 55 || k == ZLIB_KIND_BROTLI_COMPRESS; 56} 57 58static int zlib_window_bits(zlib_kind_t k) { 59 switch (k) { 60 case ZLIB_KIND_GZIP: return 15 + 16; 61 case ZLIB_KIND_GUNZIP: return 15 + 32; 62 case ZLIB_KIND_UNZIP: return 15 + 32; 63 case ZLIB_KIND_DEFLATE: return 15; 64 case ZLIB_KIND_INFLATE: return 15; 65 case ZLIB_KIND_DEFLATE_RAW: return -15; 66 case ZLIB_KIND_INFLATE_RAW: return -15; 67 default: return 15; 68 } 69} 70 71static ant_value_t pick_callback(ant_value_t *args, int nargs) { 72 if (nargs > 2 && is_callable(args[2])) return args[2]; 73 if (nargs > 1 && is_callable(args[1])) return args[1]; 74 return js_mkundef(); 75} 76 77static zlib_stream_t *zlib_stream_ptr(ant_value_t obj) { 78 if (!js_check_native_tag(obj, ZLIB_STREAM_TAG)) return NULL; 79 return (zlib_stream_t *)js_get_native_ptr(obj); 80} 81 82static void zlib_add_active(zlib_stream_t *st) { 83 st->next_active = g_active_streams; 84 g_active_streams = st; 85} 86 87static void zlib_remove_active(zlib_stream_t *st) { 88 zlib_stream_t **it; 89 for (it = &g_active_streams; *it; it = &(*it)->next_active) { 90 if (*it == st) { 91 *it = st->next_active; 92 st->next_active = NULL; 93 return; 94 }} 95} 96 97static void zlib_stream_release(zlib_stream_t *st) { 98 if (!st) return; 99 if (st->brotli) { 100 brotli_stream_state_destroy(st->brotli); 101 st->brotli = NULL; 102 } else if (st->initialized) { 103 if (zlib_kind_is_compress(st->kind)) deflateEnd(&st->strm); 104 else inflateEnd(&st->strm); 105 st->initialized = false; 106 } 107} 108 109static ant_value_t zlib_make_buffer(ant_t *js, const uint8_t *data, size_t len) { 110 ArrayBufferData *ab = create_array_buffer_data(len); 111 if (!ab) return js_mkerr(js, "out of memory"); 112 if (data && len > 0) memcpy(ab->data, data, len); 113 return create_typed_array(js, TYPED_ARRAY_UINT8, ab, 0, len, "Buffer"); 114} 115 116static void zlib_emit_data(ant_t *js, ant_value_t obj, const uint8_t *data, size_t len) { 117 ant_value_t buf = zlib_make_buffer(js, data, len); 118 if (!is_err(buf)) eventemitter_emit_args(js, obj, "data", &buf, 1); 119} 120 121typedef struct { ant_t *js; ant_value_t obj; } brotli_emit_ctx_t; 122typedef struct { ant_t *js; ant_value_t arr; bool error; } brotli_collect_ctx_t; 123 124static int brotli_emit_cb(void *ctx, const uint8_t *chunk, size_t len) { 125 brotli_emit_ctx_t *ec = (brotli_emit_ctx_t *)ctx; 126 zlib_emit_data(ec->js, ec->obj, chunk, len); 127 return 0; 128} 129 130static int brotli_collect_cb(void *ctx, const uint8_t *chunk, size_t len) { 131 brotli_collect_ctx_t *ec = (brotli_collect_ctx_t *)ctx; 132 ant_value_t buf = zlib_make_buffer(ec->js, chunk, len); 133 if (is_err(buf)) { ec->error = true; return -1; } 134 js_arr_push(ec->js, ec->arr, buf); 135 return 0; 136} 137 138static ant_value_t zlib_do_process( 139 ant_t *js, zlib_stream_t *st, 140 const uint8_t *input, size_t input_len, 141 bool finish 142) { 143 if (st->destroyed || st->ended) return js_mkundef(); 144 145 if (st->brotli) { 146 brotli_emit_ctx_t ctx = { js, st->obj }; 147 int rc; 148 if (finish) { 149 rc = brotli_stream_finish(st->brotli, brotli_emit_cb, &ctx); 150 } else { 151 rc = brotli_stream_process(st->brotli, input, input_len, brotli_emit_cb, &ctx); 152 } 153 if (rc < 0) return js_mkerr(js, "brotli operation failed"); 154 return js_mkundef(); 155 } 156 157 bool compress = zlib_kind_is_compress(st->kind); 158 int flush = finish ? Z_FINISH : Z_NO_FLUSH; 159 uint8_t out[ZLIB_CHUNK]; 160 161 if (!finish) { 162 st->strm.next_in = (Bytef *)input; 163 st->strm.avail_in = (uInt)input_len; 164 } else { 165 st->strm.next_in = NULL; 166 st->strm.avail_in = 0; 167 } 168 169 int ret; 170 do { 171 st->strm.next_out = out; 172 st->strm.avail_out = ZLIB_CHUNK; 173 174 if (compress) { 175 ret = deflate(&st->strm, flush); 176 if (ret == Z_STREAM_ERROR) return js_mkerr(js, "zlib deflate error"); 177 } else { 178 ret = inflate(&st->strm, flush == Z_FINISH ? Z_SYNC_FLUSH : flush); 179 if (ret == Z_NEED_DICT || ret == Z_DATA_ERROR || ret == Z_MEM_ERROR) 180 return js_mkerr(js, "zlib inflate error"); 181 } 182 183 size_t have = ZLIB_CHUNK - st->strm.avail_out; 184 if (have > 0) zlib_emit_data(js, st->obj, out, have); 185 if (ret == Z_STREAM_END) break; 186 } while (st->strm.avail_out == 0); 187 188 return js_mkundef(); 189} 190 191static ant_value_t zlib_process_chunk_sync( 192 ant_t *js, zlib_stream_t *st, 193 const uint8_t *input, size_t input_len, 194 int flush_flag 195) { 196 ant_value_t arr = js_mkarr(js); 197 198 if (st->brotli) { 199 brotli_collect_ctx_t ctx = { js, arr, false }; 200 int rc = 0; 201 if (input && input_len > 0) 202 rc = brotli_stream_process(st->brotli, input, input_len, brotli_collect_cb, &ctx); 203 if (rc >= 0 && flush_flag == Z_FINISH) 204 rc = brotli_stream_finish(st->brotli, brotli_collect_cb, &ctx); 205 if (rc < 0 || ctx.error) return js_mkerr(js, "brotli operation failed"); 206 return arr; 207 } 208 209 bool compress = zlib_kind_is_compress(st->kind); 210 uint8_t out[ZLIB_CHUNK]; 211 212 st->strm.next_in = input ? (Bytef *)input : NULL; 213 st->strm.avail_in = input ? (uInt)input_len : 0; 214 215 int ret; 216 do { 217 st->strm.next_out = out; 218 st->strm.avail_out = ZLIB_CHUNK; 219 220 if (compress) { 221 ret = deflate(&st->strm, flush_flag); 222 if (ret == Z_STREAM_ERROR) return js_mkerr(js, "zlib deflate error"); 223 } else { 224 ret = inflate(&st->strm, flush_flag); 225 if (ret == Z_NEED_DICT || ret == Z_DATA_ERROR || ret == Z_MEM_ERROR) 226 return js_mkerr(js, "zlib inflate error"); 227 } 228 229 size_t have = ZLIB_CHUNK - st->strm.avail_out; 230 if (have > 0) { 231 ant_value_t buf = zlib_make_buffer(js, out, have); 232 if (is_err(buf)) return buf; 233 js_arr_push(js, arr, buf); 234 } 235 if (ret == Z_STREAM_END) break; 236 } while (st->strm.avail_out == 0); 237 238 return arr; 239} 240 241static ant_value_t js_zlib_process_chunk(ant_t *js, ant_value_t *args, int nargs) { 242 zlib_stream_t *st = zlib_stream_ptr(js_getthis(js)); 243 if (!st) return js_mkerr_typed(js, JS_ERR_TYPE, "Invalid zlib stream"); 244 if (st->destroyed || st->ended) return js_mkarr(js); 245 246 const uint8_t *input = NULL; 247 size_t input_len = 0; 248 if (nargs >= 1 && is_object_type(args[0])) 249 buffer_source_get_bytes(js, args[0], &input, &input_len); 250 251 int flush_flag = Z_NO_FLUSH; 252 if (nargs >= 2 && vtype(args[1]) == T_NUM) 253 flush_flag = (int)js_getnum(args[1]); 254 255 return zlib_process_chunk_sync(js, st, input, input_len, flush_flag); 256} 257 258static ant_value_t js_zlib_write(ant_t *js, ant_value_t *args, int nargs) { 259 zlib_stream_t *st = zlib_stream_ptr(js_getthis(js)); 260 if (!st) return js_mkerr_typed(js, JS_ERR_TYPE, "Invalid zlib stream"); 261 if (st->destroyed) return js_false; 262 if (st->ended) return js_false; 263 264 if (nargs < 1 || vtype(args[0]) == T_UNDEF || vtype(args[0]) == T_NULL) 265 return js_true; 266 267 const uint8_t *bytes = NULL; 268 size_t len = 0; 269 270 if (is_object_type(args[0])) { 271 buffer_source_get_bytes(js, args[0], &bytes, &len); 272 } 273 274 if (!bytes) { 275 size_t slen = 0; 276 char *s = js_getstr(js, args[0], &slen); 277 if (s) { bytes = (const uint8_t *)s; len = slen; } 278 } 279 280 if (!bytes || len == 0) return js_true; 281 st->bytes_written += (uint32_t)len; 282 283 ant_value_t r = zlib_do_process(js, st, bytes, len, false); 284 if (is_err(r)) { 285 eventemitter_emit_args(js, st->obj, "error", &r, 1); 286 return js_false; 287 } 288 289 ant_value_t cb = pick_callback(args, nargs); 290 if (is_callable(cb)) { 291 ant_value_t null_val = js_mknull(); 292 sv_vm_call(js->vm, js, cb, js_mkundef(), &null_val, 1, NULL, false); 293 } 294 295 return js_true; 296} 297 298static ant_value_t js_zlib_end(ant_t *js, ant_value_t *args, int nargs) { 299 zlib_stream_t *st = zlib_stream_ptr(js_getthis(js)); 300 ant_value_t self = js_getthis(js); 301 302 if (!st) return js_mkerr_typed(js, JS_ERR_TYPE, "Invalid zlib stream"); 303 if (st->destroyed || st->ended) return self; 304 305 if (nargs > 0 && vtype(args[0]) != T_UNDEF && vtype(args[0]) != T_NULL) { 306 ant_value_t write_args[1] = { args[0] }; 307 js_zlib_write(js, write_args, 1); 308 } 309 310 st->ended = true; 311 ant_value_t r = zlib_do_process(js, st, NULL, 0, true); 312 313 if (is_err(r)) { 314 eventemitter_emit_args(js, st->obj, "error", &r, 1); 315 return self; 316 } 317 318 eventemitter_emit_args(js, st->obj, "end", NULL, 0); 319 eventemitter_emit_args(js, st->obj, "finish", NULL, 0); 320 eventemitter_emit_args(js, st->obj, "close", NULL, 0); 321 322 ant_value_t cb = pick_callback(args, nargs); 323 if (is_callable(cb)) 324 sv_vm_call(js->vm, js, cb, js_mkundef(), NULL, 0, NULL, false); 325 326 return self; 327} 328 329static ant_value_t js_zlib_destroy(ant_t *js, ant_value_t *args, int nargs) { 330 zlib_stream_t *st = zlib_stream_ptr(js_getthis(js)); 331 ant_value_t self = js_getthis(js); 332 333 if (!st || st->destroyed) return self; 334 st->destroyed = true; 335 zlib_stream_release(st); 336 337 if (nargs > 0 && !js_truthy(js, args[0])) { 338 ant_value_t null_val = js_mknull(); 339 eventemitter_emit_args(js, st->obj, "error", &null_val, 1); 340 } 341 342 eventemitter_emit_args(js, st->obj, "close", NULL, 0); 343 return self; 344} 345 346static ant_value_t js_zlib_pause(ant_t *js, ant_value_t *args, int nargs) { 347 return js_getthis(js); 348} 349 350static ant_value_t js_zlib_resume(ant_t *js, ant_value_t *args, int nargs) { 351 return js_getthis(js); 352} 353 354static ant_value_t js_zlib_unpipe(ant_t *js, ant_value_t *args, int nargs) { 355 return js_getthis(js); 356} 357 358static ant_value_t pipe_on_data(ant_t *js, ant_value_t *args, int nargs) { 359 ant_value_t fn = js_getcurrentfunc(js); 360 ant_value_t dest = js_get_slot(fn, SLOT_DATA); 361 ant_value_t write_fn = js_get(js, dest, "write"); 362 363 if (is_callable(write_fn) && nargs > 0) 364 sv_vm_call(js->vm, js, write_fn, dest, args, 1, NULL, false); 365 366 return js_mkundef(); 367} 368 369static ant_value_t pipe_on_end(ant_t *js, ant_value_t *args, int nargs) { 370 ant_value_t fn = js_getcurrentfunc(js); 371 ant_value_t dest = js_get_slot(fn, SLOT_DATA); 372 ant_value_t end_fn = js_get(js, dest, "end"); 373 374 if (is_callable(end_fn)) 375 sv_vm_call(js->vm, js, end_fn, dest, NULL, 0, NULL, false); 376 377 return js_mkundef(); 378} 379 380static ant_value_t js_zlib_pipe(ant_t *js, ant_value_t *args, int nargs) { 381 if (nargs < 1 || !is_object_type(args[0])) return js_mkundef(); 382 ant_value_t self = js_getthis(js); 383 ant_value_t dest = args[0]; 384 385 ant_value_t data_handler = js_heavy_mkfun(js, pipe_on_data, dest); 386 ant_value_t end_handler = js_heavy_mkfun(js, pipe_on_end, dest); 387 388 eventemitter_add_listener(js, self, "data", data_handler, false); 389 eventemitter_add_listener(js, self, "end", end_handler, true); 390 391 return dest; 392} 393 394static ant_value_t js_zlib_get_bytes_written(ant_t *js, ant_value_t *args, int nargs) { 395 zlib_stream_t *st = zlib_stream_ptr(js_getthis(js)); 396 if (!st) return js_mknum(0); 397 return js_mknum((double)st->bytes_written); 398} 399 400static ant_value_t zlib_create_stream(ant_t *js, zlib_kind_t kind) { 401 bool compress = zlib_kind_is_compress(kind); 402 403 zlib_stream_t *st = calloc(1, sizeof(zlib_stream_t)); 404 if (!st) return js_mkerr(js, "out of memory"); 405 406 st->kind = kind; 407 st->js = js; 408 409 if (kind == ZLIB_KIND_BROTLI_COMPRESS || kind == ZLIB_KIND_BROTLI_DECOMPRESS) { 410 st->brotli = brotli_stream_state_new(kind == ZLIB_KIND_BROTLI_DECOMPRESS); 411 if (!st->brotli) { free(st); return js_mkerr(js, "brotli init failed"); } 412 st->initialized = true; 413 } else { 414 int wbits = zlib_window_bits(kind); 415 int ret; 416 if (compress) { 417 ret = deflateInit2(&st->strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, wbits, 8, Z_DEFAULT_STRATEGY); 418 } else ret = inflateInit2(&st->strm, wbits); 419 420 if (ret != Z_OK) { free(st); return js_mkerr(js, "zlib init failed"); } 421 st->initialized = true; 422 } 423 424 ant_value_t obj = js_mkobj(js); 425 if (is_object_type(g_transform_proto)) js_set_proto_init(obj, g_transform_proto); 426 427 js_set_native_ptr(obj, st); 428 js_set_native_tag(obj, ZLIB_STREAM_TAG); 429 430 js_set(js, obj, "readable", js_true); 431 js_set(js, obj, "writable", js_true); 432 js_set(js, obj, "_processChunk", js_mkfun(js_zlib_process_chunk)); 433 434 ant_value_t handle_obj = js_mkobj(js); 435 js_set(js, handle_obj, "close", js_mkfun(js_zlib_destroy)); 436 js_set(js, obj, "_handle", handle_obj); 437 438 st->obj = obj; 439 zlib_add_active(st); 440 return obj; 441} 442 443static ant_value_t js_create_gzip(ant_t *js, ant_value_t *args, int nargs) { 444 return zlib_create_stream(js, ZLIB_KIND_GZIP); 445} 446 447static ant_value_t js_create_gunzip(ant_t *js, ant_value_t *args, int nargs) { 448 return zlib_create_stream(js, ZLIB_KIND_GUNZIP); 449} 450 451static ant_value_t js_create_deflate(ant_t *js, ant_value_t *args, int nargs) { 452 return zlib_create_stream(js, ZLIB_KIND_DEFLATE); 453} 454 455static ant_value_t js_create_inflate(ant_t *js, ant_value_t *args, int nargs) { 456 return zlib_create_stream(js, ZLIB_KIND_INFLATE); 457} 458 459static ant_value_t js_create_deflate_raw(ant_t *js, ant_value_t *args, int nargs) { 460 return zlib_create_stream(js, ZLIB_KIND_DEFLATE_RAW); 461} 462 463static ant_value_t js_create_inflate_raw(ant_t *js, ant_value_t *args, int nargs) { 464 return zlib_create_stream(js, ZLIB_KIND_INFLATE_RAW); 465} 466 467static ant_value_t js_create_unzip(ant_t *js, ant_value_t *args, int nargs) { 468 return zlib_create_stream(js, ZLIB_KIND_UNZIP); 469} 470 471static ant_value_t js_create_brotli_compress(ant_t *js, ant_value_t *args, int nargs) { 472 return zlib_create_stream(js, ZLIB_KIND_BROTLI_COMPRESS); 473} 474 475static ant_value_t js_create_brotli_decompress(ant_t *js, ant_value_t *args, int nargs) { 476 return zlib_create_stream(js, ZLIB_KIND_BROTLI_DECOMPRESS); 477} 478 479typedef struct { 480 uint8_t *data; 481 size_t len; 482 size_t cap; 483 int error; 484} zbuf_t; 485 486static int zbuf_append(zbuf_t *b, const uint8_t *chunk, size_t n) { 487 if (b->len + n > b->cap) { 488 size_t newcap = b->cap ? b->cap * 2 : 4096; 489 while (newcap < b->len + n) newcap *= 2; 490 uint8_t *p = realloc(b->data, newcap); 491 492 if (!p) { b->error = 1; return -1; } 493 b->data = p; 494 b->cap = newcap; 495 } 496 497 memcpy(b->data + b->len, chunk, n); 498 b->len += n; 499 500 return 0; 501} 502 503static int zbuf_brotli_cb(void *ctx, const uint8_t *chunk, size_t n) { 504 return zbuf_append((zbuf_t *)ctx, chunk, n); 505} 506 507static ant_value_t zlib_sync_op( 508 ant_t *js, zlib_kind_t kind, 509 const uint8_t *input, size_t input_len 510) { 511 zbuf_t out = {0}; 512 uint8_t tmp[ZLIB_CHUNK]; 513 bool compress = zlib_kind_is_compress(kind); 514 515 if (kind == ZLIB_KIND_BROTLI_COMPRESS || kind == ZLIB_KIND_BROTLI_DECOMPRESS) { 516 brotli_stream_state_t *bs = brotli_stream_state_new(kind == ZLIB_KIND_BROTLI_DECOMPRESS); 517 if (!bs) return js_mkerr(js, "brotli init failed"); 518 519 int rc = brotli_stream_process(bs, input, input_len, zbuf_brotli_cb, &out); 520 if (rc >= 0) rc = brotli_stream_finish(bs, zbuf_brotli_cb, &out); 521 522 brotli_stream_state_destroy(bs); 523 if (rc < 0 || out.error) { free(out.data); return js_mkerr(js, "brotli operation failed"); } 524 ant_value_t buf = zlib_make_buffer(js, out.data, out.len); 525 free(out.data); 526 527 return buf; 528 } 529 530 z_stream strm = {0}; 531 int wbits = zlib_window_bits(kind); 532 int ret; 533 534 if (compress) ret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, wbits, 8, Z_DEFAULT_STRATEGY); 535 else ret = inflateInit2(&strm, wbits); 536 if (ret != Z_OK) return js_mkerr(js, "zlib init failed"); 537 538 strm.next_in = (Bytef *)input; 539 strm.avail_in = (uInt)input_len; 540 541 do { 542 strm.next_out = tmp; 543 strm.avail_out = ZLIB_CHUNK; 544 if (compress) ret = deflate(&strm, Z_FINISH); 545 else ret = inflate(&strm, Z_SYNC_FLUSH); 546 if (ret == Z_STREAM_ERROR || ret == Z_DATA_ERROR || ret == Z_MEM_ERROR) { 547 if (compress) deflateEnd(&strm); 548 else inflateEnd(&strm); 549 free(out.data); 550 return js_mkerr(js, "zlib operation failed"); 551 } 552 size_t have = ZLIB_CHUNK - strm.avail_out; 553 if (have > 0 && zbuf_append(&out, tmp, have) < 0) { 554 if (compress) deflateEnd(&strm); 555 else inflateEnd(&strm); 556 free(out.data); 557 return js_mkerr(js, "out of memory"); 558 } 559 if (ret == Z_STREAM_END) break; 560 } while (strm.avail_out == 0 || strm.avail_in > 0); 561 562 if (compress) deflateEnd(&strm); 563 else inflateEnd(&strm); 564 565 ant_value_t buf = zlib_make_buffer(js, out.data, out.len); 566 free(out.data); 567 return buf; 568} 569 570static bool get_input_bytes(ant_t *js, ant_value_t val, const uint8_t **out_bytes, size_t *out_len) { 571 if (is_object_type(val) && buffer_source_get_bytes(js, val, out_bytes, out_len)) return true; 572 size_t slen = 0; 573 char *s = js_getstr(js, val, &slen); 574 if (s) { *out_bytes = (const uint8_t *)s; *out_len = slen; return true; } 575 return false; 576} 577 578static ant_value_t zlib_sync_fn(ant_t *js, ant_value_t *args, int nargs, zlib_kind_t kind) { 579 if (nargs < 1) return js_mkerr(js, "argument required"); 580 const uint8_t *bytes = NULL; 581 size_t len = 0; 582 if (!get_input_bytes(js, args[0], &bytes, &len)) 583 return js_mkerr_typed(js, JS_ERR_TYPE, "argument must be a string or Buffer"); 584 return zlib_sync_op(js, kind, bytes, len); 585} 586 587static ant_value_t zlib_async_fn(ant_t *js, ant_value_t *args, int nargs, zlib_kind_t kind) { 588 if (nargs < 1) return js_mkerr(js, "argument required"); 589 590 const uint8_t *bytes = NULL; 591 size_t len = 0; 592 ant_value_t cb = pick_callback(args, nargs); 593 594 if (!get_input_bytes(js, args[0], &bytes, &len)) 595 return js_mkerr_typed(js, JS_ERR_TYPE, "argument must be a string or Buffer"); 596 597 ant_value_t result = zlib_sync_op(js, kind, bytes, len); 598 599 if (is_callable(cb)) { 600 if (is_err(result)) { 601 ant_value_t argv[1] = { result }; 602 sv_vm_call(js->vm, js, cb, js_mkundef(), argv, 1, NULL, false); 603 } else { 604 ant_value_t null_val = js_mknull(); 605 ant_value_t argv[2] = { null_val, result }; 606 sv_vm_call(js->vm, js, cb, js_mkundef(), argv, 2, NULL, false); 607 } 608 return js_mkundef(); 609 } 610 611 return result; 612} 613 614#define ZLIB_SYNC_FN(name, kind) \ 615 static ant_value_t js_##name##Sync(ant_t *js, ant_value_t *a, int n) { return zlib_sync_fn(js, a, n, kind); } 616 617#define ZLIB_ASYNC_FN(name, kind) \ 618 static ant_value_t js_##name(ant_t *js, ant_value_t *a, int n) { return zlib_async_fn(js, a, n, kind); } 619 620ZLIB_SYNC_FN(gzip, ZLIB_KIND_GZIP) 621ZLIB_SYNC_FN(gunzip, ZLIB_KIND_GUNZIP) 622ZLIB_SYNC_FN(deflate, ZLIB_KIND_DEFLATE) 623ZLIB_SYNC_FN(inflate, ZLIB_KIND_INFLATE) 624ZLIB_SYNC_FN(deflateRaw, ZLIB_KIND_DEFLATE_RAW) 625ZLIB_SYNC_FN(inflateRaw, ZLIB_KIND_INFLATE_RAW) 626ZLIB_SYNC_FN(unzip, ZLIB_KIND_UNZIP) 627ZLIB_SYNC_FN(brotliCompress, ZLIB_KIND_BROTLI_COMPRESS) 628ZLIB_SYNC_FN(brotliDecompress, ZLIB_KIND_BROTLI_DECOMPRESS) 629 630ZLIB_ASYNC_FN(gzip, ZLIB_KIND_GZIP) 631ZLIB_ASYNC_FN(gunzip, ZLIB_KIND_GUNZIP) 632ZLIB_ASYNC_FN(deflate, ZLIB_KIND_DEFLATE) 633ZLIB_ASYNC_FN(inflate, ZLIB_KIND_INFLATE) 634ZLIB_ASYNC_FN(deflateRaw, ZLIB_KIND_DEFLATE_RAW) 635ZLIB_ASYNC_FN(inflateRaw, ZLIB_KIND_INFLATE_RAW) 636ZLIB_ASYNC_FN(unzip, ZLIB_KIND_UNZIP) 637ZLIB_ASYNC_FN(brotliCompress, ZLIB_KIND_BROTLI_COMPRESS) 638ZLIB_ASYNC_FN(brotliDecompress, ZLIB_KIND_BROTLI_DECOMPRESS) 639 640static ant_value_t js_zlib_crc32(ant_t *js, ant_value_t *args, int nargs) { 641 if (nargs < 1) return js_mkerr(js, "argument required"); 642 643 const uint8_t *bytes = NULL; 644 size_t len = 0; 645 uLong init_val = 0; 646 647 if (nargs >= 2 && vtype(args[1]) == T_NUM) 648 init_val = (uLong)js_getnum(args[1]); 649 650 if (!get_input_bytes(js, args[0], &bytes, &len)) 651 return js_mkerr_typed(js, JS_ERR_TYPE, "argument must be a string or Buffer"); 652 653 uLong crc = crc32(init_val, bytes, (uInt)len); 654 return js_mknum((double)(uint32_t)crc); 655} 656 657static ant_value_t make_constants(ant_t *js) { 658 ant_value_t c = js_mkobj(js); 659 660 js_set(js, c, "Z_NO_FLUSH", js_mknum(Z_NO_FLUSH)); 661 js_set(js, c, "Z_PARTIAL_FLUSH", js_mknum(Z_PARTIAL_FLUSH)); 662 js_set(js, c, "Z_SYNC_FLUSH", js_mknum(Z_SYNC_FLUSH)); 663 js_set(js, c, "Z_FULL_FLUSH", js_mknum(Z_FULL_FLUSH)); 664 js_set(js, c, "Z_FINISH", js_mknum(Z_FINISH)); 665 js_set(js, c, "Z_BLOCK", js_mknum(Z_BLOCK)); 666 667 js_set(js, c, "Z_OK", js_mknum(Z_OK)); 668 js_set(js, c, "Z_STREAM_END", js_mknum(Z_STREAM_END)); 669 js_set(js, c, "Z_NEED_DICT", js_mknum(Z_NEED_DICT)); 670 js_set(js, c, "Z_ERRNO", js_mknum(Z_ERRNO)); 671 js_set(js, c, "Z_STREAM_ERROR", js_mknum(Z_STREAM_ERROR)); 672 js_set(js, c, "Z_DATA_ERROR", js_mknum(Z_DATA_ERROR)); 673 js_set(js, c, "Z_MEM_ERROR", js_mknum(Z_MEM_ERROR)); 674 js_set(js, c, "Z_BUF_ERROR", js_mknum(Z_BUF_ERROR)); 675 js_set(js, c, "Z_VERSION_ERROR", js_mknum(Z_VERSION_ERROR)); 676 677 js_set(js, c, "Z_NO_COMPRESSION", js_mknum(Z_NO_COMPRESSION)); 678 js_set(js, c, "Z_BEST_SPEED", js_mknum(Z_BEST_SPEED)); 679 js_set(js, c, "Z_BEST_COMPRESSION", js_mknum(Z_BEST_COMPRESSION)); 680 js_set(js, c, "Z_DEFAULT_COMPRESSION", js_mknum(Z_DEFAULT_COMPRESSION)); 681 682 js_set(js, c, "Z_FILTERED", js_mknum(Z_FILTERED)); 683 js_set(js, c, "Z_HUFFMAN_ONLY", js_mknum(Z_HUFFMAN_ONLY)); 684 js_set(js, c, "Z_RLE", js_mknum(Z_RLE)); 685 js_set(js, c, "Z_FIXED", js_mknum(Z_FIXED)); 686 js_set(js, c, "Z_DEFAULT_STRATEGY", js_mknum(Z_DEFAULT_STRATEGY)); 687 688 js_set(js, c, "BROTLI_OPERATION_PROCESS", js_mknum(0)); 689 js_set(js, c, "BROTLI_OPERATION_FLUSH", js_mknum(1)); 690 js_set(js, c, "BROTLI_OPERATION_FINISH", js_mknum(2)); 691 js_set(js, c, "BROTLI_OPERATION_EMIT_METADATA", js_mknum(3)); 692 693 js_set(js, c, "BROTLI_PARAM_MODE", js_mknum(0)); 694 js_set(js, c, "BROTLI_MODE_GENERIC", js_mknum(0)); 695 js_set(js, c, "BROTLI_MODE_TEXT", js_mknum(1)); 696 js_set(js, c, "BROTLI_MODE_FONT", js_mknum(2)); 697 js_set(js, c, "BROTLI_PARAM_QUALITY", js_mknum(1)); 698 js_set(js, c, "BROTLI_MIN_QUALITY", js_mknum(0)); 699 js_set(js, c, "BROTLI_MAX_QUALITY", js_mknum(11)); 700 js_set(js, c, "BROTLI_DEFAULT_QUALITY", js_mknum(11)); 701 js_set(js, c, "BROTLI_PARAM_LGWIN", js_mknum(2)); 702 js_set(js, c, "BROTLI_MIN_WINDOW_BITS", js_mknum(10)); 703 js_set(js, c, "BROTLI_MAX_WINDOW_BITS", js_mknum(24)); 704 js_set(js, c, "BROTLI_DEFAULT_WINDOW", js_mknum(22)); 705 js_set(js, c, "BROTLI_PARAM_SIZE_HINT", js_mknum(3)); 706 js_set(js, c, "BROTLI_PARAM_LARGE_WINDOW", js_mknum(4)); 707 js_set(js, c, "BROTLI_DECODER_PARAM_DISABLE_RING_BUFFER_REALLOCATION", js_mknum(0)); 708 js_set(js, c, "BROTLI_DECODER_PARAM_LARGE_WINDOW", js_mknum(1)); 709 710 js_set(js, c, "ZSTD_e_continue", js_mknum(0)); 711 js_set(js, c, "ZSTD_e_flush", js_mknum(1)); 712 js_set(js, c, "ZSTD_e_end", js_mknum(2)); 713 714 return c; 715} 716 717static void zlib_init_proto(ant_t *js) { 718 if (g_transform_proto) return; 719 720 ant_value_t events = events_library(js); 721 ant_value_t ee_ctor = js_get(js, events, "EventEmitter"); 722 ant_value_t ee_proto = js_get(js, ee_ctor, "prototype"); 723 724 g_transform_proto = js_mkobj(js); 725 js_set_proto_init(g_transform_proto, ee_proto); 726 727 js_set(js, g_transform_proto, "write", js_mkfun(js_zlib_write)); 728 js_set(js, g_transform_proto, "end", js_mkfun(js_zlib_end)); 729 js_set(js, g_transform_proto, "destroy", js_mkfun(js_zlib_destroy)); 730 js_set(js, g_transform_proto, "pause", js_mkfun(js_zlib_pause)); 731 js_set(js, g_transform_proto, "resume", js_mkfun(js_zlib_resume)); 732 js_set(js, g_transform_proto, "unpipe", js_mkfun(js_zlib_unpipe)); 733 js_set(js, g_transform_proto, "pipe", js_mkfun(js_zlib_pipe)); 734 735 js_set_getter_desc(js, g_transform_proto, "bytesWritten", 12, 736 js_mkfun(js_zlib_get_bytes_written), JS_DESC_C); 737} 738 739static ant_value_t zlib_mkctor(ant_t *js, ant_value_t (*fn)(ant_t *, ant_value_t *, int)) { 740 ant_value_t ctor = js_heavy_mkfun(js, fn, js_mkundef()); 741 js_mark_constructor(ctor, true); 742 return ctor; 743} 744 745ant_value_t zlib_library(ant_t *js) { 746 zlib_init_proto(js); 747 748 ant_value_t lib = js_mkobj(js); 749 ant_value_t consts = make_constants(js); 750 751 js_set(js, lib, "gzip", js_mkfun(js_gzip)); 752 js_set(js, lib, "gzipSync", js_mkfun(js_gzipSync)); 753 js_set(js, lib, "Gzip", zlib_mkctor(js, js_create_gzip)); 754 js_set(js, lib, "createGzip", js_mkfun(js_create_gzip)); 755 756 js_set(js, lib, "gunzip", js_mkfun(js_gunzip)); 757 js_set(js, lib, "gunzipSync", js_mkfun(js_gunzipSync)); 758 js_set(js, lib, "Gunzip", zlib_mkctor(js, js_create_gunzip)); 759 js_set(js, lib, "createGunzip", js_mkfun(js_create_gunzip)); 760 761 js_set(js, lib, "deflate", js_mkfun(js_deflate)); 762 js_set(js, lib, "deflateSync", js_mkfun(js_deflateSync)); 763 js_set(js, lib, "Deflate", zlib_mkctor(js, js_create_deflate)); 764 js_set(js, lib, "createDeflate", js_mkfun(js_create_deflate)); 765 766 js_set(js, lib, "inflate", js_mkfun(js_inflate)); 767 js_set(js, lib, "inflateSync", js_mkfun(js_inflateSync)); 768 js_set(js, lib, "Inflate", zlib_mkctor(js, js_create_inflate)); 769 js_set(js, lib, "createInflate", js_mkfun(js_create_inflate)); 770 771 js_set(js, lib, "deflateRaw", js_mkfun(js_deflateRaw)); 772 js_set(js, lib, "deflateRawSync", js_mkfun(js_deflateRawSync)); 773 js_set(js, lib, "DeflateRaw", zlib_mkctor(js, js_create_deflate_raw)); 774 js_set(js, lib, "createDeflateRaw", js_mkfun(js_create_deflate_raw)); 775 776 js_set(js, lib, "inflateRaw", js_mkfun(js_inflateRaw)); 777 js_set(js, lib, "inflateRawSync", js_mkfun(js_inflateRawSync)); 778 js_set(js, lib, "InflateRaw", zlib_mkctor(js, js_create_inflate_raw)); 779 js_set(js, lib, "createInflateRaw", js_mkfun(js_create_inflate_raw)); 780 781 js_set(js, lib, "unzip", js_mkfun(js_unzip)); 782 js_set(js, lib, "unzipSync", js_mkfun(js_unzipSync)); 783 js_set(js, lib, "Unzip", zlib_mkctor(js, js_create_unzip)); 784 js_set(js, lib, "createUnzip", js_mkfun(js_create_unzip)); 785 786 js_set(js, lib, "brotliCompress", js_mkfun(js_brotliCompress)); 787 js_set(js, lib, "brotliCompressSync", js_mkfun(js_brotliCompressSync)); 788 js_set(js, lib, "BrotliCompress", zlib_mkctor(js, js_create_brotli_compress)); 789 js_set(js, lib, "createBrotliCompress", js_mkfun(js_create_brotli_compress)); 790 791 js_set(js, lib, "brotliDecompress", js_mkfun(js_brotliDecompress)); 792 js_set(js, lib, "brotliDecompressSync", js_mkfun(js_brotliDecompressSync)); 793 js_set(js, lib, "BrotliDecompress", zlib_mkctor(js, js_create_brotli_decompress)); 794 js_set(js, lib, "createBrotliDecompress", js_mkfun(js_create_brotli_decompress)); 795 796 js_set(js, lib, "default", lib); 797 js_set(js, lib, "constants", consts); 798 js_set(js, lib, "crc32", js_mkfun(js_zlib_crc32)); 799 js_set_sym(js, lib, get_toStringTag_sym(), js_mkstr(js, "zlib", 4)); 800 801 return lib; 802} 803 804void gc_mark_zlib(ant_t *js, void (*mark)(ant_t *, ant_value_t)) { 805 if (g_transform_proto) mark(js, g_transform_proto); 806 for (zlib_stream_t *st = g_active_streams; st; st = st->next_active) mark(js, st->obj); 807}