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.

add node:zlib

+912
+196
examples/spec/zlib.js
··· 1 + import { test, testThrows, summary } from './helpers.js'; 2 + import zlib from 'node:zlib'; 3 + 4 + console.log('node:zlib Tests\n'); 5 + 6 + test('zlib is object', typeof zlib, 'object'); 7 + test('zlib toStringTag', Object.prototype.toString.call(zlib), '[object zlib]'); 8 + 9 + test('constants exists', typeof zlib.constants, 'object'); 10 + test('Z_OK is 0', zlib.constants.Z_OK, 0); 11 + test('Z_NO_FLUSH is 0', zlib.constants.Z_NO_FLUSH, 0); 12 + test('Z_FINISH is 4', zlib.constants.Z_FINISH, 4); 13 + test('Z_DEFAULT_COMPRESSION is -1', zlib.constants.Z_DEFAULT_COMPRESSION, -1); 14 + test('Z_BEST_SPEED is 1', zlib.constants.Z_BEST_SPEED, 1); 15 + test('Z_BEST_COMPRESSION is 9', zlib.constants.Z_BEST_COMPRESSION, 9); 16 + 17 + test('createGzip is function', typeof zlib.createGzip, 'function'); 18 + test('createGunzip is function', typeof zlib.createGunzip, 'function'); 19 + test('createDeflate is function', typeof zlib.createDeflate, 'function'); 20 + test('createInflate is function', typeof zlib.createInflate, 'function'); 21 + test('createDeflateRaw is function', typeof zlib.createDeflateRaw, 'function'); 22 + test('createInflateRaw is function', typeof zlib.createInflateRaw, 'function'); 23 + test('createUnzip is function', typeof zlib.createUnzip, 'function'); 24 + test('createBrotliCompress is function', typeof zlib.createBrotliCompress, 'function'); 25 + test('createBrotliDecompress is function', typeof zlib.createBrotliDecompress, 'function'); 26 + 27 + test('gzipSync is function', typeof zlib.gzipSync, 'function'); 28 + test('gunzipSync is function', typeof zlib.gunzipSync, 'function'); 29 + test('deflateSync is function', typeof zlib.deflateSync, 'function'); 30 + test('inflateSync is function', typeof zlib.inflateSync, 'function'); 31 + test('deflateRawSync is function', typeof zlib.deflateRawSync, 'function'); 32 + test('inflateRawSync is function', typeof zlib.inflateRawSync, 'function'); 33 + test('unzipSync is function', typeof zlib.unzipSync, 'function'); 34 + test('brotliCompressSync is function', typeof zlib.brotliCompressSync, 'function'); 35 + test('brotliDecompressSync is function', typeof zlib.brotliDecompressSync, 'function'); 36 + 37 + test('gzip is function', typeof zlib.gzip, 'function'); 38 + test('gunzip is function', typeof zlib.gunzip, 'function'); 39 + test('deflate is function', typeof zlib.deflate, 'function'); 40 + test('inflate is function', typeof zlib.inflate, 'function'); 41 + test('crc32 is function', typeof zlib.crc32, 'function'); 42 + 43 + const gz = zlib.createGzip(); 44 + test('createGzip returns object', typeof gz, 'object'); 45 + test('createGzip has write', typeof gz.write, 'function'); 46 + test('createGzip has end', typeof gz.end, 'function'); 47 + test('createGzip has on', typeof gz.on, 'function'); 48 + test('createGzip has pipe', typeof gz.pipe, 'function'); 49 + test('createGzip has destroy', typeof gz.destroy, 'function'); 50 + test('createGzip readable=true', gz.readable, true); 51 + test('createGzip writable=true', gz.writable, true); 52 + test('createGzip bytesWritten starts 0', gz.bytesWritten, 0); 53 + 54 + const gun = zlib.createGunzip(); 55 + test('createGunzip has write', typeof gun.write, 'function'); 56 + test('createGunzip readable=true', gun.readable, true); 57 + 58 + const inf = zlib.createInflate(); 59 + test('createInflate has write', typeof inf.write, 'function'); 60 + 61 + const br = zlib.createBrotliDecompress(); 62 + test('createBrotliDecompress returns object', typeof br, 'object'); 63 + test('createBrotliDecompress has write', typeof br.write, 'function'); 64 + 65 + const input = Buffer.from('Hello, zlib world!'); 66 + 67 + const gzipped = zlib.gzipSync(input); 68 + test('gzipSync returns Buffer', gzipped instanceof Uint8Array, true); 69 + test('gzipSync has gzip magic bytes', gzipped[0], 0x1f); 70 + test('gzipSync magic byte 2', gzipped[1], 0x8b); 71 + test('gzipSync result is smaller for repetitive input', gzipped.length > 0, true); 72 + 73 + const gunzipped = zlib.gunzipSync(gzipped); 74 + test('gunzipSync roundtrip length', gunzipped.length, input.length); 75 + test('gunzipSync roundtrip value', Buffer.from(gunzipped).toString(), 'Hello, zlib world!'); 76 + 77 + const deflated = zlib.deflateSync(input); 78 + test('deflateSync returns Buffer', deflated instanceof Uint8Array, true); 79 + test('deflateSync result non-empty', deflated.length > 0, true); 80 + 81 + const inflated = zlib.inflateSync(deflated); 82 + test('inflateSync roundtrip', Buffer.from(inflated).toString(), 'Hello, zlib world!'); 83 + 84 + const deflatedRaw = zlib.deflateRawSync(input); 85 + test('deflateRawSync result non-empty', deflatedRaw.length > 0, true); 86 + 87 + const inflatedRaw = zlib.inflateRawSync(deflatedRaw); 88 + test('inflateRawSync roundtrip', Buffer.from(inflatedRaw).toString(), 'Hello, zlib world!'); 89 + 90 + const brotliCompressed = zlib.brotliCompressSync(input); 91 + test('brotliCompressSync result non-empty', brotliCompressed.length > 0, true); 92 + 93 + const brotliDecompressed = zlib.brotliDecompressSync(brotliCompressed); 94 + test('brotliDecompressSync roundtrip', Buffer.from(brotliDecompressed).toString(), 'Hello, zlib world!'); 95 + 96 + const unzipped = zlib.unzipSync(gzipped); 97 + test('unzipSync gzip roundtrip', Buffer.from(unzipped).toString(), 'Hello, zlib world!'); 98 + 99 + const fromString = zlib.gzipSync('hello string'); 100 + test('gzipSync accepts string', fromString instanceof Uint8Array, true); 101 + const fromStringBack = zlib.gunzipSync(fromString); 102 + test('gunzipSync string roundtrip', Buffer.from(fromStringBack).toString(), 'hello string'); 103 + 104 + const repetitive = Buffer.from('a'.repeat(1000)); 105 + const compressedRep = zlib.gzipSync(repetitive); 106 + test('gzip compresses repetitive data', compressedRep.length < repetitive.length, true); 107 + 108 + const crc0 = zlib.crc32('hello'); 109 + test('crc32 returns number', typeof crc0, 'number'); 110 + test('crc32 hello is consistent', crc0, zlib.crc32('hello')); 111 + test('crc32 chaining', zlib.crc32('world', zlib.crc32('hello')) !== zlib.crc32('hello'), true); 112 + test('crc32 different inputs differ', zlib.crc32('hello') !== zlib.crc32('world'), true); 113 + 114 + function testAsyncGzip() { 115 + return new Promise((resolve) => { 116 + zlib.gzip(input, (err, result) => { 117 + test('async gzip no error', err, null); 118 + test('async gzip returns Buffer', result instanceof Uint8Array, true); 119 + test('async gzip magic byte', result[0], 0x1f); 120 + 121 + zlib.gunzip(result, (err2, result2) => { 122 + test('async gunzip no error', err2, null); 123 + test('async gunzip roundtrip', Buffer.from(result2).toString(), 'Hello, zlib world!'); 124 + resolve(); 125 + }); 126 + }); 127 + }); 128 + } 129 + 130 + function testAsyncDeflate() { 131 + return new Promise((resolve) => { 132 + zlib.deflate(input, (err, result) => { 133 + test('async deflate no error', err, null); 134 + test('async deflate result non-empty', result.length > 0, true); 135 + 136 + zlib.inflate(result, (err2, result2) => { 137 + test('async inflate no error', err2, null); 138 + test('async inflate roundtrip', Buffer.from(result2).toString(), 'Hello, zlib world!'); 139 + resolve(); 140 + }); 141 + }); 142 + }); 143 + } 144 + 145 + function testAsyncBrotli() { 146 + return new Promise((resolve) => { 147 + zlib.brotliCompress(input, (err, result) => { 148 + test('async brotliCompress no error', err, null); 149 + test('async brotliCompress result non-empty', result.length > 0, true); 150 + 151 + zlib.brotliDecompress(result, (err2, result2) => { 152 + test('async brotliDecompress no error', err2, null); 153 + test('async brotliDecompress roundtrip', Buffer.from(result2).toString(), 'Hello, zlib world!'); 154 + resolve(); 155 + }); 156 + }); 157 + }); 158 + } 159 + 160 + function testTransformStream() { 161 + return new Promise((resolve) => { 162 + const chunks = []; 163 + const stream = zlib.createGunzip(); 164 + 165 + stream.on('data', (chunk) => chunks.push(chunk)); 166 + stream.on('end', () => { 167 + let total = 0; 168 + for (const c of chunks) total += c.length; 169 + const out = new Uint8Array(total); 170 + let off = 0; 171 + for (const c of chunks) { out.set(c, off); off += c.length; } 172 + test('transform stream roundtrip', Buffer.from(out).toString(), 'Hello, zlib world!'); 173 + resolve(); 174 + }); 175 + 176 + const compressed = zlib.gzipSync(input); 177 + stream.write(compressed); 178 + stream.end(); 179 + }); 180 + } 181 + 182 + function testBytesWritten() { 183 + const stream = zlib.createDeflate(); 184 + const data = Buffer.from('track bytes written'); 185 + stream.write(data); 186 + test('bytesWritten after write', stream.bytesWritten, data.length); 187 + } 188 + 189 + testBytesWritten(); 190 + 191 + await testAsyncGzip(); 192 + await testAsyncDeflate(); 193 + await testAsyncBrotli(); 194 + await testTransformStream(); 195 + 196 + summary();
+1
include/gc/modules.h
··· 28 28 void gc_mark_transform_streams(ant_t *js, gc_mark_fn mark); 29 29 void gc_mark_codec_streams(ant_t *js, gc_mark_fn mark); 30 30 void gc_mark_compression_streams(ant_t *js, gc_mark_fn mark); 31 + void gc_mark_zlib(ant_t *js, gc_mark_fn mark); 31 32 32 33 #endif
+9
include/modules/zlib.h
··· 1 + #ifndef ANT_ZLIB_MODULE_H 2 + #define ANT_ZLIB_MODULE_H 3 + 4 + #include "types.h" 5 + 6 + ant_value_t zlib_library(ant_t *js); 7 + void gc_mark_zlib(ant_t *js, void (*mark)(ant_t *, ant_value_t)); 8 + 9 + #endif
+1
src/gc/objects.c
··· 461 461 gc_mark_transform_streams(js, gc_mark_value); 462 462 gc_mark_codec_streams(js, gc_mark_value); 463 463 gc_mark_compression_streams(js, gc_mark_value); 464 + gc_mark_zlib(js, gc_mark_value); 464 465 465 466 for ( 466 467 ant_object_t *obj = g_pending_promises;
+2
src/main.c
··· 83 83 #include "modules/headers.h" 84 84 #include "modules/blob.h" 85 85 #include "modules/formdata.h" 86 + #include "modules/zlib.h" 86 87 #include "streams/queuing.h" 87 88 #include "streams/readable.h" 88 89 #include "streams/writable.h" ··· 638 639 ant_standard_library("worker_threads", worker_threads_library); 639 640 ant_standard_library("async_hooks", async_hooks_library); 640 641 ant_standard_library("v8", v8_library); 642 + ant_standard_library("zlib", zlib_library); 641 643 642 644 ant_value_t snapshot_result = ant_load_snapshot(js); 643 645 if (vtype(snapshot_result) == T_ERR) {
+703
src/modules/zlib.c
··· 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 + 22 + typedef 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 + 34 + typedef 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 + 47 + static ant_value_t g_transform_proto = 0; 48 + static zlib_stream_t *g_active_streams = NULL; 49 + 50 + static 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 + 58 + static 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 + 71 + static 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 + 77 + static 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 + 82 + static void zlib_add_active(zlib_stream_t *st) { 83 + st->next_active = g_active_streams; 84 + g_active_streams = st; 85 + } 86 + 87 + static 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 + 97 + static 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 + 109 + static 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 + 116 + static 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 + 121 + typedef struct { ant_t *js; ant_value_t obj; } brotli_emit_ctx_t; 122 + 123 + static int brotli_emit_cb(void *ctx, const uint8_t *chunk, size_t len) { 124 + brotli_emit_ctx_t *ec = (brotli_emit_ctx_t *)ctx; 125 + zlib_emit_data(ec->js, ec->obj, chunk, len); 126 + return 0; 127 + } 128 + 129 + static ant_value_t zlib_do_process( 130 + ant_t *js, zlib_stream_t *st, 131 + const uint8_t *input, size_t input_len, 132 + bool finish 133 + ) { 134 + if (st->destroyed || st->ended) return js_mkundef(); 135 + 136 + if (st->brotli) { 137 + brotli_emit_ctx_t ctx = { js, st->obj }; 138 + int rc; 139 + if (finish) { 140 + rc = brotli_stream_finish(st->brotli, brotli_emit_cb, &ctx); 141 + } else { 142 + rc = brotli_stream_process(st->brotli, input, input_len, brotli_emit_cb, &ctx); 143 + } 144 + if (rc < 0) return js_mkerr(js, "brotli operation failed"); 145 + return js_mkundef(); 146 + } 147 + 148 + bool compress = zlib_kind_is_compress(st->kind); 149 + int flush = finish ? Z_FINISH : Z_NO_FLUSH; 150 + uint8_t out[ZLIB_CHUNK]; 151 + 152 + if (!finish) { 153 + st->strm.next_in = (Bytef *)input; 154 + st->strm.avail_in = (uInt)input_len; 155 + } else { 156 + st->strm.next_in = NULL; 157 + st->strm.avail_in = 0; 158 + } 159 + 160 + int ret; 161 + do { 162 + st->strm.next_out = out; 163 + st->strm.avail_out = ZLIB_CHUNK; 164 + 165 + if (compress) { 166 + ret = deflate(&st->strm, flush); 167 + if (ret == Z_STREAM_ERROR) return js_mkerr(js, "zlib deflate error"); 168 + } else { 169 + ret = inflate(&st->strm, flush == Z_FINISH ? Z_SYNC_FLUSH : flush); 170 + if (ret == Z_NEED_DICT || ret == Z_DATA_ERROR || ret == Z_MEM_ERROR) 171 + return js_mkerr(js, "zlib inflate error"); 172 + } 173 + 174 + size_t have = ZLIB_CHUNK - st->strm.avail_out; 175 + if (have > 0) zlib_emit_data(js, st->obj, out, have); 176 + if (ret == Z_STREAM_END) break; 177 + } while (st->strm.avail_out == 0); 178 + 179 + return js_mkundef(); 180 + } 181 + 182 + static ant_value_t js_zlib_write(ant_t *js, ant_value_t *args, int nargs) { 183 + zlib_stream_t *st = zlib_stream_ptr(js_getthis(js)); 184 + if (!st) return js_mkerr_typed(js, JS_ERR_TYPE, "Invalid zlib stream"); 185 + if (st->destroyed) return js_false; 186 + if (st->ended) return js_false; 187 + 188 + if (nargs < 1 || vtype(args[0]) == T_UNDEF || vtype(args[0]) == T_NULL) 189 + return js_true; 190 + 191 + const uint8_t *bytes = NULL; 192 + size_t len = 0; 193 + 194 + if (is_object_type(args[0])) { 195 + buffer_source_get_bytes(js, args[0], &bytes, &len); 196 + } 197 + 198 + if (!bytes) { 199 + size_t slen = 0; 200 + char *s = js_getstr(js, args[0], &slen); 201 + if (s) { bytes = (const uint8_t *)s; len = slen; } 202 + } 203 + 204 + if (!bytes || len == 0) return js_true; 205 + st->bytes_written += (uint32_t)len; 206 + 207 + ant_value_t r = zlib_do_process(js, st, bytes, len, false); 208 + if (is_err(r)) { 209 + eventemitter_emit_args(js, st->obj, "error", &r, 1); 210 + return js_false; 211 + } 212 + 213 + ant_value_t cb = pick_callback(args, nargs); 214 + if (is_callable(cb)) { 215 + ant_value_t null_val = js_mknull(); 216 + sv_vm_call(js->vm, js, cb, js_mkundef(), &null_val, 1, NULL, false); 217 + } 218 + 219 + return js_true; 220 + } 221 + 222 + static ant_value_t js_zlib_end(ant_t *js, ant_value_t *args, int nargs) { 223 + zlib_stream_t *st = zlib_stream_ptr(js_getthis(js)); 224 + ant_value_t self = js_getthis(js); 225 + 226 + if (!st) return js_mkerr_typed(js, JS_ERR_TYPE, "Invalid zlib stream"); 227 + if (st->destroyed || st->ended) return self; 228 + 229 + if (nargs > 0 && vtype(args[0]) != T_UNDEF && vtype(args[0]) != T_NULL) { 230 + ant_value_t write_args[1] = { args[0] }; 231 + js_zlib_write(js, write_args, 1); 232 + } 233 + 234 + st->ended = true; 235 + ant_value_t r = zlib_do_process(js, st, NULL, 0, true); 236 + 237 + if (is_err(r)) { 238 + eventemitter_emit_args(js, st->obj, "error", &r, 1); 239 + return self; 240 + } 241 + 242 + eventemitter_emit_args(js, st->obj, "end", NULL, 0); 243 + eventemitter_emit_args(js, st->obj, "finish", NULL, 0); 244 + eventemitter_emit_args(js, st->obj, "close", NULL, 0); 245 + 246 + ant_value_t cb = pick_callback(args, nargs); 247 + if (is_callable(cb)) 248 + sv_vm_call(js->vm, js, cb, js_mkundef(), NULL, 0, NULL, false); 249 + 250 + return self; 251 + } 252 + 253 + static ant_value_t js_zlib_destroy(ant_t *js, ant_value_t *args, int nargs) { 254 + zlib_stream_t *st = zlib_stream_ptr(js_getthis(js)); 255 + ant_value_t self = js_getthis(js); 256 + 257 + if (!st || st->destroyed) return self; 258 + st->destroyed = true; 259 + zlib_stream_release(st); 260 + 261 + if (nargs > 0 && !js_truthy(js, args[0])) { 262 + ant_value_t null_val = js_mknull(); 263 + eventemitter_emit_args(js, st->obj, "error", &null_val, 1); 264 + } 265 + 266 + eventemitter_emit_args(js, st->obj, "close", NULL, 0); 267 + return self; 268 + } 269 + 270 + static ant_value_t js_zlib_pause(ant_t *js, ant_value_t *args, int nargs) { 271 + return js_getthis(js); 272 + } 273 + 274 + static ant_value_t js_zlib_resume(ant_t *js, ant_value_t *args, int nargs) { 275 + return js_getthis(js); 276 + } 277 + 278 + static ant_value_t js_zlib_unpipe(ant_t *js, ant_value_t *args, int nargs) { 279 + return js_getthis(js); 280 + } 281 + 282 + static ant_value_t pipe_on_data(ant_t *js, ant_value_t *args, int nargs) { 283 + ant_value_t fn = js_getcurrentfunc(js); 284 + ant_value_t dest = js_get_slot(fn, SLOT_DATA); 285 + ant_value_t write_fn = js_get(js, dest, "write"); 286 + 287 + if (is_callable(write_fn) && nargs > 0) 288 + sv_vm_call(js->vm, js, write_fn, dest, args, 1, NULL, false); 289 + 290 + return js_mkundef(); 291 + } 292 + 293 + static ant_value_t pipe_on_end(ant_t *js, ant_value_t *args, int nargs) { 294 + ant_value_t fn = js_getcurrentfunc(js); 295 + ant_value_t dest = js_get_slot(fn, SLOT_DATA); 296 + ant_value_t end_fn = js_get(js, dest, "end"); 297 + 298 + if (is_callable(end_fn)) 299 + sv_vm_call(js->vm, js, end_fn, dest, NULL, 0, NULL, false); 300 + 301 + return js_mkundef(); 302 + } 303 + 304 + static ant_value_t js_zlib_pipe(ant_t *js, ant_value_t *args, int nargs) { 305 + if (nargs < 1 || !is_object_type(args[0])) return js_mkundef(); 306 + ant_value_t self = js_getthis(js); 307 + ant_value_t dest = args[0]; 308 + 309 + ant_value_t data_handler = js_heavy_mkfun(js, pipe_on_data, dest); 310 + ant_value_t end_handler = js_heavy_mkfun(js, pipe_on_end, dest); 311 + 312 + eventemitter_add_listener(js, self, "data", data_handler, false); 313 + eventemitter_add_listener(js, self, "end", end_handler, true); 314 + 315 + return dest; 316 + } 317 + 318 + static ant_value_t js_zlib_get_bytes_written(ant_t *js, ant_value_t *args, int nargs) { 319 + zlib_stream_t *st = zlib_stream_ptr(js_getthis(js)); 320 + if (!st) return js_mknum(0); 321 + return js_mknum((double)st->bytes_written); 322 + } 323 + 324 + static ant_value_t zlib_create_stream(ant_t *js, zlib_kind_t kind) { 325 + bool compress = zlib_kind_is_compress(kind); 326 + 327 + zlib_stream_t *st = calloc(1, sizeof(zlib_stream_t)); 328 + if (!st) return js_mkerr(js, "out of memory"); 329 + 330 + st->kind = kind; 331 + st->js = js; 332 + 333 + if (kind == ZLIB_KIND_BROTLI_COMPRESS || kind == ZLIB_KIND_BROTLI_DECOMPRESS) { 334 + st->brotli = brotli_stream_state_new(kind == ZLIB_KIND_BROTLI_DECOMPRESS); 335 + if (!st->brotli) { free(st); return js_mkerr(js, "brotli init failed"); } 336 + st->initialized = true; 337 + } else { 338 + int wbits = zlib_window_bits(kind); 339 + int ret; 340 + if (compress) { 341 + ret = deflateInit2(&st->strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, wbits, 8, Z_DEFAULT_STRATEGY); 342 + } else ret = inflateInit2(&st->strm, wbits); 343 + 344 + if (ret != Z_OK) { free(st); return js_mkerr(js, "zlib init failed"); } 345 + st->initialized = true; 346 + } 347 + 348 + ant_value_t obj = js_mkobj(js); 349 + if (is_object_type(g_transform_proto)) js_set_proto_init(obj, g_transform_proto); 350 + 351 + js_set_native_ptr(obj, st); 352 + js_set_native_tag(obj, ZLIB_STREAM_TAG); 353 + 354 + js_set(js, obj, "readable", js_true); 355 + js_set(js, obj, "writable", js_true); 356 + 357 + st->obj = obj; 358 + zlib_add_active(st); 359 + return obj; 360 + } 361 + 362 + static ant_value_t js_create_gzip(ant_t *js, ant_value_t *args, int nargs) { 363 + return zlib_create_stream(js, ZLIB_KIND_GZIP); 364 + } 365 + 366 + static ant_value_t js_create_gunzip(ant_t *js, ant_value_t *args, int nargs) { 367 + return zlib_create_stream(js, ZLIB_KIND_GUNZIP); 368 + } 369 + 370 + static ant_value_t js_create_deflate(ant_t *js, ant_value_t *args, int nargs) { 371 + return zlib_create_stream(js, ZLIB_KIND_DEFLATE); 372 + } 373 + 374 + static ant_value_t js_create_inflate(ant_t *js, ant_value_t *args, int nargs) { 375 + return zlib_create_stream(js, ZLIB_KIND_INFLATE); 376 + } 377 + 378 + static ant_value_t js_create_deflate_raw(ant_t *js, ant_value_t *args, int nargs) { 379 + return zlib_create_stream(js, ZLIB_KIND_DEFLATE_RAW); 380 + } 381 + 382 + static ant_value_t js_create_inflate_raw(ant_t *js, ant_value_t *args, int nargs) { 383 + return zlib_create_stream(js, ZLIB_KIND_INFLATE_RAW); 384 + } 385 + 386 + static ant_value_t js_create_unzip(ant_t *js, ant_value_t *args, int nargs) { 387 + return zlib_create_stream(js, ZLIB_KIND_UNZIP); 388 + } 389 + 390 + static ant_value_t js_create_brotli_compress(ant_t *js, ant_value_t *args, int nargs) { 391 + return zlib_create_stream(js, ZLIB_KIND_BROTLI_COMPRESS); 392 + } 393 + 394 + static ant_value_t js_create_brotli_decompress(ant_t *js, ant_value_t *args, int nargs) { 395 + return zlib_create_stream(js, ZLIB_KIND_BROTLI_DECOMPRESS); 396 + } 397 + 398 + typedef struct { 399 + uint8_t *data; 400 + size_t len; 401 + size_t cap; 402 + int error; 403 + } zbuf_t; 404 + 405 + static int zbuf_append(zbuf_t *b, const uint8_t *chunk, size_t n) { 406 + if (b->len + n > b->cap) { 407 + size_t newcap = b->cap ? b->cap * 2 : 4096; 408 + while (newcap < b->len + n) newcap *= 2; 409 + uint8_t *p = realloc(b->data, newcap); 410 + if (!p) { b->error = 1; return -1; } 411 + b->data = p; 412 + b->cap = newcap; 413 + } 414 + memcpy(b->data + b->len, chunk, n); 415 + b->len += n; 416 + return 0; 417 + } 418 + 419 + static int zbuf_brotli_cb(void *ctx, const uint8_t *chunk, size_t n) { 420 + return zbuf_append((zbuf_t *)ctx, chunk, n); 421 + } 422 + 423 + static ant_value_t zlib_sync_op( 424 + ant_t *js, zlib_kind_t kind, 425 + const uint8_t *input, size_t input_len 426 + ) { 427 + zbuf_t out = {0}; 428 + uint8_t tmp[ZLIB_CHUNK]; 429 + bool compress = zlib_kind_is_compress(kind); 430 + 431 + if (kind == ZLIB_KIND_BROTLI_COMPRESS || kind == ZLIB_KIND_BROTLI_DECOMPRESS) { 432 + brotli_stream_state_t *bs = brotli_stream_state_new(kind == ZLIB_KIND_BROTLI_DECOMPRESS); 433 + if (!bs) return js_mkerr(js, "brotli init failed"); 434 + 435 + int rc = brotli_stream_process(bs, input, input_len, zbuf_brotli_cb, &out); 436 + if (rc >= 0) rc = brotli_stream_finish(bs, zbuf_brotli_cb, &out); 437 + 438 + brotli_stream_state_destroy(bs); 439 + if (rc < 0 || out.error) { free(out.data); return js_mkerr(js, "brotli operation failed"); } 440 + ant_value_t buf = zlib_make_buffer(js, out.data, out.len); 441 + free(out.data); 442 + 443 + return buf; 444 + } 445 + 446 + z_stream strm = {0}; 447 + int wbits = zlib_window_bits(kind); 448 + int ret; 449 + 450 + if (compress) ret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, wbits, 8, Z_DEFAULT_STRATEGY); 451 + else ret = inflateInit2(&strm, wbits); 452 + if (ret != Z_OK) return js_mkerr(js, "zlib init failed"); 453 + 454 + strm.next_in = (Bytef *)input; 455 + strm.avail_in = (uInt)input_len; 456 + 457 + do { 458 + strm.next_out = tmp; 459 + strm.avail_out = ZLIB_CHUNK; 460 + if (compress) ret = deflate(&strm, Z_FINISH); 461 + else ret = inflate(&strm, Z_SYNC_FLUSH); 462 + if (ret == Z_STREAM_ERROR || ret == Z_DATA_ERROR || ret == Z_MEM_ERROR) { 463 + if (compress) deflateEnd(&strm); 464 + else inflateEnd(&strm); 465 + free(out.data); 466 + return js_mkerr(js, "zlib operation failed"); 467 + } 468 + size_t have = ZLIB_CHUNK - strm.avail_out; 469 + if (have > 0 && zbuf_append(&out, tmp, have) < 0) { 470 + if (compress) deflateEnd(&strm); 471 + else inflateEnd(&strm); 472 + free(out.data); 473 + return js_mkerr(js, "out of memory"); 474 + } 475 + if (ret == Z_STREAM_END) break; 476 + } while (strm.avail_out == 0 || strm.avail_in > 0); 477 + 478 + if (compress) deflateEnd(&strm); 479 + else inflateEnd(&strm); 480 + 481 + ant_value_t buf = zlib_make_buffer(js, out.data, out.len); 482 + free(out.data); 483 + return buf; 484 + } 485 + 486 + static bool get_input_bytes(ant_t *js, ant_value_t val, const uint8_t **out_bytes, size_t *out_len) { 487 + if (is_object_type(val) && buffer_source_get_bytes(js, val, out_bytes, out_len)) return true; 488 + size_t slen = 0; 489 + char *s = js_getstr(js, val, &slen); 490 + if (s) { *out_bytes = (const uint8_t *)s; *out_len = slen; return true; } 491 + return false; 492 + } 493 + 494 + static ant_value_t zlib_sync_fn(ant_t *js, ant_value_t *args, int nargs, zlib_kind_t kind) { 495 + if (nargs < 1) return js_mkerr(js, "argument required"); 496 + const uint8_t *bytes = NULL; 497 + size_t len = 0; 498 + if (!get_input_bytes(js, args[0], &bytes, &len)) 499 + return js_mkerr_typed(js, JS_ERR_TYPE, "argument must be a string or Buffer"); 500 + return zlib_sync_op(js, kind, bytes, len); 501 + } 502 + 503 + static ant_value_t zlib_async_fn(ant_t *js, ant_value_t *args, int nargs, zlib_kind_t kind) { 504 + if (nargs < 1) return js_mkerr(js, "argument required"); 505 + 506 + const uint8_t *bytes = NULL; 507 + size_t len = 0; 508 + ant_value_t cb = pick_callback(args, nargs); 509 + 510 + if (!get_input_bytes(js, args[0], &bytes, &len)) 511 + return js_mkerr_typed(js, JS_ERR_TYPE, "argument must be a string or Buffer"); 512 + 513 + ant_value_t result = zlib_sync_op(js, kind, bytes, len); 514 + 515 + if (is_callable(cb)) { 516 + if (is_err(result)) { 517 + ant_value_t argv[1] = { result }; 518 + sv_vm_call(js->vm, js, cb, js_mkundef(), argv, 1, NULL, false); 519 + } else { 520 + ant_value_t null_val = js_mknull(); 521 + ant_value_t argv[2] = { null_val, result }; 522 + sv_vm_call(js->vm, js, cb, js_mkundef(), argv, 2, NULL, false); 523 + } 524 + return js_mkundef(); 525 + } 526 + 527 + return result; 528 + } 529 + 530 + #define ZLIB_SYNC_FN(name, kind) \ 531 + static ant_value_t js_##name##Sync(ant_t *js, ant_value_t *a, int n) { return zlib_sync_fn(js, a, n, kind); } 532 + 533 + #define ZLIB_ASYNC_FN(name, kind) \ 534 + static ant_value_t js_##name(ant_t *js, ant_value_t *a, int n) { return zlib_async_fn(js, a, n, kind); } 535 + 536 + ZLIB_SYNC_FN(gzip, ZLIB_KIND_GZIP) 537 + ZLIB_SYNC_FN(gunzip, ZLIB_KIND_GUNZIP) 538 + ZLIB_SYNC_FN(deflate, ZLIB_KIND_DEFLATE) 539 + ZLIB_SYNC_FN(inflate, ZLIB_KIND_INFLATE) 540 + ZLIB_SYNC_FN(deflateRaw, ZLIB_KIND_DEFLATE_RAW) 541 + ZLIB_SYNC_FN(inflateRaw, ZLIB_KIND_INFLATE_RAW) 542 + ZLIB_SYNC_FN(unzip, ZLIB_KIND_UNZIP) 543 + ZLIB_SYNC_FN(brotliCompress, ZLIB_KIND_BROTLI_COMPRESS) 544 + ZLIB_SYNC_FN(brotliDecompress, ZLIB_KIND_BROTLI_DECOMPRESS) 545 + 546 + ZLIB_ASYNC_FN(gzip, ZLIB_KIND_GZIP) 547 + ZLIB_ASYNC_FN(gunzip, ZLIB_KIND_GUNZIP) 548 + ZLIB_ASYNC_FN(deflate, ZLIB_KIND_DEFLATE) 549 + ZLIB_ASYNC_FN(inflate, ZLIB_KIND_INFLATE) 550 + ZLIB_ASYNC_FN(deflateRaw, ZLIB_KIND_DEFLATE_RAW) 551 + ZLIB_ASYNC_FN(inflateRaw, ZLIB_KIND_INFLATE_RAW) 552 + ZLIB_ASYNC_FN(unzip, ZLIB_KIND_UNZIP) 553 + ZLIB_ASYNC_FN(brotliCompress, ZLIB_KIND_BROTLI_COMPRESS) 554 + ZLIB_ASYNC_FN(brotliDecompress, ZLIB_KIND_BROTLI_DECOMPRESS) 555 + 556 + static ant_value_t js_zlib_crc32(ant_t *js, ant_value_t *args, int nargs) { 557 + if (nargs < 1) return js_mkerr(js, "argument required"); 558 + 559 + const uint8_t *bytes = NULL; 560 + size_t len = 0; 561 + uLong init_val = 0; 562 + 563 + if (nargs >= 2 && vtype(args[1]) == T_NUM) 564 + init_val = (uLong)js_getnum(args[1]); 565 + 566 + if (!get_input_bytes(js, args[0], &bytes, &len)) 567 + return js_mkerr_typed(js, JS_ERR_TYPE, "argument must be a string or Buffer"); 568 + 569 + uLong crc = crc32(init_val, bytes, (uInt)len); 570 + return js_mknum((double)(uint32_t)crc); 571 + } 572 + 573 + static ant_value_t make_constants(ant_t *js) { 574 + ant_value_t c = js_mkobj(js); 575 + 576 + js_set(js, c, "Z_NO_FLUSH", js_mknum(Z_NO_FLUSH)); 577 + js_set(js, c, "Z_PARTIAL_FLUSH", js_mknum(Z_PARTIAL_FLUSH)); 578 + js_set(js, c, "Z_SYNC_FLUSH", js_mknum(Z_SYNC_FLUSH)); 579 + js_set(js, c, "Z_FULL_FLUSH", js_mknum(Z_FULL_FLUSH)); 580 + js_set(js, c, "Z_FINISH", js_mknum(Z_FINISH)); 581 + js_set(js, c, "Z_BLOCK", js_mknum(Z_BLOCK)); 582 + 583 + js_set(js, c, "Z_OK", js_mknum(Z_OK)); 584 + js_set(js, c, "Z_STREAM_END", js_mknum(Z_STREAM_END)); 585 + js_set(js, c, "Z_NEED_DICT", js_mknum(Z_NEED_DICT)); 586 + js_set(js, c, "Z_ERRNO", js_mknum(Z_ERRNO)); 587 + js_set(js, c, "Z_STREAM_ERROR", js_mknum(Z_STREAM_ERROR)); 588 + js_set(js, c, "Z_DATA_ERROR", js_mknum(Z_DATA_ERROR)); 589 + js_set(js, c, "Z_MEM_ERROR", js_mknum(Z_MEM_ERROR)); 590 + js_set(js, c, "Z_BUF_ERROR", js_mknum(Z_BUF_ERROR)); 591 + js_set(js, c, "Z_VERSION_ERROR", js_mknum(Z_VERSION_ERROR)); 592 + 593 + js_set(js, c, "Z_NO_COMPRESSION", js_mknum(Z_NO_COMPRESSION)); 594 + js_set(js, c, "Z_BEST_SPEED", js_mknum(Z_BEST_SPEED)); 595 + js_set(js, c, "Z_BEST_COMPRESSION", js_mknum(Z_BEST_COMPRESSION)); 596 + js_set(js, c, "Z_DEFAULT_COMPRESSION", js_mknum(Z_DEFAULT_COMPRESSION)); 597 + 598 + js_set(js, c, "Z_FILTERED", js_mknum(Z_FILTERED)); 599 + js_set(js, c, "Z_HUFFMAN_ONLY", js_mknum(Z_HUFFMAN_ONLY)); 600 + js_set(js, c, "Z_RLE", js_mknum(Z_RLE)); 601 + js_set(js, c, "Z_FIXED", js_mknum(Z_FIXED)); 602 + js_set(js, c, "Z_DEFAULT_STRATEGY", js_mknum(Z_DEFAULT_STRATEGY)); 603 + 604 + js_set(js, c, "BROTLI_OPERATION_PROCESS", js_mknum(0)); 605 + js_set(js, c, "BROTLI_OPERATION_FLUSH", js_mknum(1)); 606 + js_set(js, c, "BROTLI_OPERATION_FINISH", js_mknum(2)); 607 + js_set(js, c, "BROTLI_OPERATION_EMIT_METADATA", js_mknum(3)); 608 + 609 + js_set(js, c, "BROTLI_PARAM_MODE", js_mknum(0)); 610 + js_set(js, c, "BROTLI_MODE_GENERIC", js_mknum(0)); 611 + js_set(js, c, "BROTLI_MODE_TEXT", js_mknum(1)); 612 + js_set(js, c, "BROTLI_MODE_FONT", js_mknum(2)); 613 + js_set(js, c, "BROTLI_PARAM_QUALITY", js_mknum(1)); 614 + js_set(js, c, "BROTLI_MIN_QUALITY", js_mknum(0)); 615 + js_set(js, c, "BROTLI_MAX_QUALITY", js_mknum(11)); 616 + js_set(js, c, "BROTLI_DEFAULT_QUALITY", js_mknum(11)); 617 + js_set(js, c, "BROTLI_PARAM_LGWIN", js_mknum(2)); 618 + js_set(js, c, "BROTLI_MIN_WINDOW_BITS", js_mknum(10)); 619 + js_set(js, c, "BROTLI_MAX_WINDOW_BITS", js_mknum(24)); 620 + js_set(js, c, "BROTLI_DEFAULT_WINDOW", js_mknum(22)); 621 + js_set(js, c, "BROTLI_PARAM_SIZE_HINT", js_mknum(3)); 622 + js_set(js, c, "BROTLI_PARAM_LARGE_WINDOW", js_mknum(4)); 623 + js_set(js, c, "BROTLI_DECODER_PARAM_DISABLE_RING_BUFFER_REALLOCATION", js_mknum(0)); 624 + js_set(js, c, "BROTLI_DECODER_PARAM_LARGE_WINDOW", js_mknum(1)); 625 + 626 + js_set(js, c, "ZSTD_e_continue", js_mknum(0)); 627 + js_set(js, c, "ZSTD_e_flush", js_mknum(1)); 628 + js_set(js, c, "ZSTD_e_end", js_mknum(2)); 629 + 630 + return c; 631 + } 632 + 633 + static void zlib_init_proto(ant_t *js) { 634 + if (g_transform_proto) return; 635 + 636 + ant_value_t events = events_library(js); 637 + ant_value_t ee_ctor = js_get(js, events, "EventEmitter"); 638 + ant_value_t ee_proto = js_get(js, ee_ctor, "prototype"); 639 + 640 + g_transform_proto = js_mkobj(js); 641 + js_set_proto_init(g_transform_proto, ee_proto); 642 + 643 + js_set(js, g_transform_proto, "write", js_mkfun(js_zlib_write)); 644 + js_set(js, g_transform_proto, "end", js_mkfun(js_zlib_end)); 645 + js_set(js, g_transform_proto, "destroy", js_mkfun(js_zlib_destroy)); 646 + js_set(js, g_transform_proto, "pause", js_mkfun(js_zlib_pause)); 647 + js_set(js, g_transform_proto, "resume", js_mkfun(js_zlib_resume)); 648 + js_set(js, g_transform_proto, "unpipe", js_mkfun(js_zlib_unpipe)); 649 + js_set(js, g_transform_proto, "pipe", js_mkfun(js_zlib_pipe)); 650 + 651 + js_set_getter_desc(js, g_transform_proto, "bytesWritten", 12, 652 + js_mkfun(js_zlib_get_bytes_written), JS_DESC_C); 653 + } 654 + 655 + ant_value_t zlib_library(ant_t *js) { 656 + zlib_init_proto(js); 657 + 658 + ant_value_t lib = js_mkobj(js); 659 + ant_value_t consts = make_constants(js); 660 + 661 + js_set(js, lib, "constants", consts); 662 + 663 + js_set(js, lib, "createGzip", js_mkfun(js_create_gzip)); 664 + js_set(js, lib, "createGunzip", js_mkfun(js_create_gunzip)); 665 + js_set(js, lib, "createDeflate", js_mkfun(js_create_deflate)); 666 + js_set(js, lib, "createInflate", js_mkfun(js_create_inflate)); 667 + js_set(js, lib, "createDeflateRaw", js_mkfun(js_create_deflate_raw)); 668 + js_set(js, lib, "createInflateRaw", js_mkfun(js_create_inflate_raw)); 669 + js_set(js, lib, "createUnzip", js_mkfun(js_create_unzip)); 670 + js_set(js, lib, "createBrotliCompress", js_mkfun(js_create_brotli_compress)); 671 + js_set(js, lib, "createBrotliDecompress", js_mkfun(js_create_brotli_decompress)); 672 + 673 + js_set(js, lib, "gzip", js_mkfun(js_gzip)); 674 + js_set(js, lib, "gunzip", js_mkfun(js_gunzip)); 675 + js_set(js, lib, "deflate", js_mkfun(js_deflate)); 676 + js_set(js, lib, "inflate", js_mkfun(js_inflate)); 677 + js_set(js, lib, "deflateRaw", js_mkfun(js_deflateRaw)); 678 + js_set(js, lib, "inflateRaw", js_mkfun(js_inflateRaw)); 679 + js_set(js, lib, "unzip", js_mkfun(js_unzip)); 680 + js_set(js, lib, "brotliCompress", js_mkfun(js_brotliCompress)); 681 + js_set(js, lib, "brotliDecompress", js_mkfun(js_brotliDecompress)); 682 + 683 + js_set(js, lib, "gzipSync", js_mkfun(js_gzipSync)); 684 + js_set(js, lib, "gunzipSync", js_mkfun(js_gunzipSync)); 685 + js_set(js, lib, "deflateSync", js_mkfun(js_deflateSync)); 686 + js_set(js, lib, "inflateSync", js_mkfun(js_inflateSync)); 687 + js_set(js, lib, "deflateRawSync", js_mkfun(js_deflateRawSync)); 688 + js_set(js, lib, "inflateRawSync", js_mkfun(js_inflateRawSync)); 689 + js_set(js, lib, "unzipSync", js_mkfun(js_unzipSync)); 690 + js_set(js, lib, "brotliCompressSync", js_mkfun(js_brotliCompressSync)); 691 + js_set(js, lib, "brotliDecompressSync", js_mkfun(js_brotliDecompressSync)); 692 + 693 + js_set(js, lib, "crc32", js_mkfun(js_zlib_crc32)); 694 + js_set(js, lib, "default", lib); 695 + 696 + js_set_sym(js, lib, get_toStringTag_sym(), js_mkstr(js, "zlib", 4)); 697 + return lib; 698 + } 699 + 700 + void gc_mark_zlib(ant_t *js, void (*mark)(ant_t *, ant_value_t)) { 701 + if (g_transform_proto) mark(js, g_transform_proto); 702 + for (zlib_stream_t *st = g_active_streams; st; st = st->next_active) mark(js, st->obj); 703 + }