diff --git a/packages/bun-types/globals.d.ts b/packages/bun-types/globals.d.ts index 54b50e79ea1327..fb2727ca0d0a6a 100644 --- a/packages/bun-types/globals.d.ts +++ b/packages/bun-types/globals.d.ts @@ -1918,6 +1918,9 @@ declare global { * closely to the `BodyMixin` API. */ formData(): Promise; + + arrayBuffer(): Promise; + /** * Returns a promise that resolves to the contents of the blob as a Uint8Array (array of bytes) its the same as `new Uint8Array(await blob.arrayBuffer())` */ diff --git a/scripts/runner.node.mjs b/scripts/runner.node.mjs index 8339114482c2ce..245875d5cf7e2e 100755 --- a/scripts/runner.node.mjs +++ b/scripts/runner.node.mjs @@ -233,6 +233,8 @@ async function runTests() { reportOutputToGitHubAction("failing_tests", markdown); } + if (!isCI) console.log("-------"); + if (!isCI) console.log("passing", results.length - failedTests.length, "/", results.length); return results; } diff --git a/src/brotli.zig b/src/brotli.zig index 7dcfe457da83a8..80c9dbce30785a 100644 --- a/src/brotli.zig +++ b/src/brotli.zig @@ -181,17 +181,28 @@ pub const BrotliCompressionStream = struct { state: State = State.Inflating, total_out: usize = 0, total_in: usize = 0, - - pub fn init() !BrotliCompressionStream { + flushOp: BrotliEncoder.Operation, + finishFlushOp: BrotliEncoder.Operation, + fullFlushOp: BrotliEncoder.Operation, + + pub fn init( + flushOp: BrotliEncoder.Operation, + finishFlushOp: BrotliEncoder.Operation, + fullFlushOp: BrotliEncoder.Operation, + ) !BrotliCompressionStream { const instance = BrotliEncoder.createInstance(&BrotliAllocator.alloc, &BrotliAllocator.free, null) orelse return error.BrotliFailedToCreateInstance; return BrotliCompressionStream{ .brotli = instance, + .flushOp = flushOp, + .finishFlushOp = finishFlushOp, + .fullFlushOp = fullFlushOp, }; } pub fn writeChunk(this: *BrotliCompressionStream, input: []const u8, last: bool) ![]const u8 { - const result = this.brotli.compressStream(if (last) BrotliEncoder.Operation.finish else .process, input); + this.total_in += input.len; + const result = this.brotli.compressStream(if (last) this.finishFlushOp else this.flushOp, input); if (!result.success) { this.state = .Error; diff --git a/src/bun.js/api/js_brotli.classes.ts b/src/bun.js/api/js_brotli.classes.ts deleted file mode 100644 index 2095a2c10433c9..00000000000000 --- a/src/bun.js/api/js_brotli.classes.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { define } from "../../codegen/class-definitions"; - -export default [ - define({ - name: "BrotliEncoder", - construct: true, - noConstructor: true, - finalize: true, - configurable: false, - hasPendingActivity: true, - klass: {}, - JSType: "0b11101110", - values: ["callback"], - proto: { - encode: { - fn: "encode", - length: 2, - }, - encodeSync: { - fn: "encodeSync", - length: 2, - }, - end: { - fn: "end", - length: 2, - }, - endSync: { - fn: "endSync", - length: 2, - }, - }, - }), - define({ - name: "BrotliDecoder", - construct: true, - noConstructor: true, - finalize: true, - configurable: false, - hasPendingActivity: true, - klass: {}, - JSType: "0b11101110", - values: ["callback"], - - proto: { - decode: { - fn: "decode", - length: 2, - }, - decodeSync: { - fn: "decodeSync", - length: 2, - }, - end: { - fn: "end", - length: 2, - }, - endSync: { - fn: "endSync", - length: 2, - }, - }, - }), -]; diff --git a/src/bun.js/api/js_brotli.zig b/src/bun.js/api/js_brotli.zig index 58243e43035ed5..aebcde73652acb 100644 --- a/src/bun.js/api/js_brotli.zig +++ b/src/bun.js/api/js_brotli.zig @@ -37,10 +37,12 @@ pub const BrotliEncoder = struct { pub usingnamespace JSC.Codegen.JSBrotliEncoder; stream: brotli.BrotliCompressionStream, + maxOutputLength: usize, freelist: FreeList = .{}, globalThis: *JSC.JSGlobalObject, + mode: u8, input: Queue = Queue.init(bun.default_allocator), input_lock: bun.Lock = .{}, @@ -54,10 +56,11 @@ pub const BrotliEncoder = struct { has_pending_activity: std.atomic.Value(u32) = std.atomic.Value(u32).init(0), pending_encode_job_count: std.atomic.Value(u32) = std.atomic.Value(u32).init(0), ref_count: u32 = 1, - write_failed: bool = false, + write_failure: ?JSC.DeferredError = null, poll_ref: bun.Async.KeepAlive = .{}, + closed: bool = false, - pub fn hasPendingActivity(this: *BrotliEncoder) callconv(.C) bool { + pub fn hasPendingActivity(this: *BrotliEncoder) bool { return this.has_pending_activity.load(.monotonic) > 0; } @@ -67,51 +70,71 @@ pub const BrotliEncoder = struct { } pub fn create(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) JSC.JSValue { - const arguments = callframe.arguments(3).slice(); + const arguments = callframe.arguments(4).slice(); - if (arguments.len < 3) { - globalThis.throwNotEnoughArguments("BrotliEncoder", 3, arguments.len); + if (arguments.len < 4) { + globalThis.throwNotEnoughArguments("BrotliEncoder", 4, arguments.len); return .zero; } const opts = arguments[0]; const callback = arguments[2]; + const mode = arguments[3].to(u8); + + _ = globalThis.checkMinOrGetDefault(opts, "chunkSize", u32, 64, 1024 * 16) orelse return .zero; + const maxOutputLength = globalThis.checkMinOrGetDefaultU64(opts, "maxOutputLength", usize, 0, std.math.maxInt(u52)) orelse return .zero; + const flush = globalThis.checkRangesOrGetDefault(opts, "flush", u8, 0, 3, 0) orelse return .zero; + const finishFlush = globalThis.checkRangesOrGetDefault(opts, "finishFlush", u8, 0, 3, 2) orelse return .zero; + const fullFlush = globalThis.checkRangesOrGetDefault(opts, "fullFlush", u8, 0, 3, 1) orelse return .zero; var this: *BrotliEncoder = BrotliEncoder.new(.{ .globalThis = globalThis, - .stream = brotli.BrotliCompressionStream.init() catch { + .stream = brotli.BrotliCompressionStream.init(@enumFromInt(flush), @enumFromInt(finishFlush), @enumFromInt(fullFlush)) catch { globalThis.throw("Failed to create BrotliEncoder", .{}); return .zero; }, + .maxOutputLength = maxOutputLength, + .mode = mode, }); if (opts.get(globalThis, "params")) |params| { inline for (std.meta.fields(bun.brotli.c.BrotliEncoderParameter)) |f| { - const idx = params.getIndex(globalThis, f.value); - if (!idx.isNumber()) break; - const was_set = this.stream.brotli.setParameter(@enumFromInt(f.value), idx.toU32()); - if (!was_set) { - globalThis.ERR_ZLIB_INITIALIZATION_FAILED("Initialization failed", .{}).throw(); - this.deinit(); - return .zero; + if (params.hasOwnPropertyValue(globalThis, JSC.ZigString.static(std.fmt.comptimePrint("{d}", .{f.value})).toJS(globalThis))) { + const idx = params.getIndex(globalThis, f.value); + if (!idx.isNumber()) { + globalThis.throwValue(globalThis.ERR_INVALID_ARG_TYPE_static( + JSC.ZigString.static("options.params[key]"), + JSC.ZigString.static("number"), + idx, + )); + this.deinit(); + return .zero; + } + const was_set = this.stream.brotli.setParameter(@enumFromInt(f.value), idx.toU32()); + if (!was_set) { + globalThis.ERR_ZLIB_INITIALIZATION_FAILED("Initialization failed", .{}).throw(); + this.deinit(); + return .zero; + } } } } + if (globalThis.hasException()) return .zero; const out = this.toJS(globalThis); - @This().callbackSetCached(out, globalThis, callback); this.callback_value.set(globalThis, callback); return out; } - pub fn finalize(this: *BrotliEncoder) callconv(.C) void { + pub fn finalize(this: *BrotliEncoder) void { this.deinit(); } pub fn deinit(this: *BrotliEncoder) void { this.callback_value.deinit(); this.freelist.deinit(); + this.output.deinit(bun.default_allocator); this.stream.deinit(); this.input.deinit(); this.destroy(); @@ -135,14 +158,14 @@ pub const BrotliEncoder = struct { defer _ = this.has_pending_activity.fetchSub(1, .monotonic); this.drainFreelist(); - const result = this.callback_value.get().?.call(this.globalThis, .undefined, &.{ - if (this.write_failed) - // TODO: propagate error from brotli - this.globalThis.createErrorInstance("BrotliError", .{}) + const result = this.callback_value.get().?.call( + this.globalThis, + .undefined, + if (this.write_failure != null) + &.{this.write_failure.?.toError(this.globalThis)} else - JSC.JSValue.null, - this.collectOutputValue(), - }); + &.{ .null, this.collectOutputValue() }, + ); if (result.toError()) |err| { _ = this.globalThis.bunVM().uncaughtException(this.globalThis, err, false); @@ -167,6 +190,8 @@ pub const BrotliEncoder = struct { } pub fn run(this: *EncodeJob) void { + const vm = this.encoder.globalThis.bunVMConcurrently(); + defer this.encoder.poll_ref.unrefConcurrently(vm); defer { _ = this.encoder.has_pending_activity.fetchSub(1, .monotonic); } @@ -201,9 +226,19 @@ pub const BrotliEncoder = struct { var writer = this.encoder.stream.writer(Writer{ .encoder = this.encoder }); writer.writeAll(input.slice()) catch { _ = this.encoder.pending_encode_job_count.fetchSub(1, .monotonic); - this.encoder.write_failed = true; + if (!this.is_async) { + this.encoder.closed = true; + this.encoder.globalThis.throw("BrotliError", .{}); + return; + } + this.encoder.write_failure = JSC.DeferredError.from(.plainerror, .ERR_OPERATION_FAILED, "BrotliError", .{}); // TODO propogate better error return; }; + if (this.encoder.output.items.len > this.encoder.maxOutputLength) { + _ = this.encoder.pending_encode_job_count.fetchSub(1, .monotonic); + this.encoder.write_failure = JSC.DeferredError.from(.rangeerror, .ERR_BUFFER_TOO_LARGE, "Cannot create a Buffer larger than {d} bytes", .{this.encoder.maxOutputLength}); + return; + } } any = any or pending.len > 0; @@ -219,30 +254,35 @@ pub const BrotliEncoder = struct { output.appendSlice(bun.default_allocator, this.encoder.stream.end() catch { _ = this.encoder.pending_encode_job_count.fetchSub(1, .monotonic); - this.encoder.write_failed = true; + this.encoder.write_failure = JSC.DeferredError.from(.plainerror, .ERR_OPERATION_FAILED, "BrotliError", .{}); // TODO propogate better error return; }) catch { _ = this.encoder.pending_encode_job_count.fetchSub(1, .monotonic); - this.encoder.write_failed = true; + this.encoder.write_failure = JSC.DeferredError.from(.plainerror, .ERR_OPERATION_FAILED, "BrotliError", .{}); // TODO propogate better error return; }; + if (output.items.len > this.encoder.maxOutputLength) { + _ = this.encoder.pending_encode_job_count.fetchSub(1, .monotonic); + this.encoder.write_failure = JSC.DeferredError.from(.rangeerror, .ERR_BUFFER_TOO_LARGE, "Cannot create a Buffer larger than {d} bytes", .{this.encoder.maxOutputLength}); + return; + } } } if (this.is_async and any) { - var vm = this.encoder.globalThis.bunVMConcurrently(); _ = this.encoder.has_pending_activity.fetchAdd(1, .monotonic); this.encoder.poll_ref.refConcurrently(vm); + this.encoder.poll_ref.refConcurrently(vm); vm.enqueueTaskConcurrent(JSC.ConcurrentTask.create(JSC.Task.init(this.encoder))); } } }; - pub fn encode(this: *BrotliEncoder, globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) JSC.JSValue { + pub fn transform(this: *BrotliEncoder, globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) JSC.JSValue { const arguments = callframe.arguments(3); - if (arguments.len < 2) { - globalThis.throwNotEnoughArguments("BrotliEncoder.encode", 2, arguments.len); + if (arguments.len < 3) { + globalThis.throwNotEnoughArguments("BrotliEncoder.encode", 3, arguments.len); return .zero; } @@ -277,16 +317,17 @@ pub const BrotliEncoder = struct { input_to_queue.protect(); this.input.writeItem(input_to_queue) catch bun.outOfMemory(); } + this.poll_ref.ref(this.globalThis.bunVM()); JSC.WorkPool.schedule(&task.task); return .undefined; } - pub fn encodeSync(this: *BrotliEncoder, globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) JSC.JSValue { - const arguments = callframe.arguments(3); + pub fn transformSync(this: *BrotliEncoder, globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) JSC.JSValue { + const arguments = callframe.arguments(4); - if (arguments.len < 2) { - globalThis.throwNotEnoughArguments("BrotliEncoder.encode", 2, arguments.len); + if (arguments.len < 3) { + globalThis.throwNotEnoughArguments("BrotliEncoder.encode", 3, arguments.len); return .zero; } @@ -298,6 +339,17 @@ pub const BrotliEncoder = struct { const input = callframe.argument(0); const optional_encoding = callframe.argument(1); const is_last = callframe.argument(2).toBoolean(); + const optional_flushFlag = arguments.ptr[3]; + + const old_flushFlag = this.stream.flushOp; + defer this.stream.flushOp = old_flushFlag; + blk: { + if (!optional_flushFlag.isInt32()) break :blk; + const int = optional_flushFlag.asInt32(); + if (int < 0) break :blk; + if (int > 3) break :blk; + this.stream.flushOp = @enumFromInt(int); + } const input_to_queue = JSC.Node.BlobOrStringOrBuffer.fromJSWithEncodingValueMaybeAsync(globalThis, bun.default_allocator, input, optional_encoding, true) orelse { globalThis.throwInvalidArgumentType("BrotliEncoder.encode", "input", "Blob, String, or Buffer"); @@ -322,23 +374,38 @@ pub const BrotliEncoder = struct { this.input.writeItem(input_to_queue) catch bun.outOfMemory(); } task.run(); - return if (!is_last and this.output.items.len == 0) .undefined else this.collectOutputValue(); + if (!is_last and this.output.items.len == 0) { + return JSC.Buffer.fromBytes(&.{}, bun.default_allocator, .Uint8Array).toNodeBuffer(globalThis); + } + if (this.write_failure != null) { + globalThis.vm().throwError(globalThis, this.write_failure.?.toError(globalThis)); + return .zero; + } + return this.collectOutputValue(); } - pub fn end(this: *BrotliEncoder, globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) JSC.JSValue { + pub fn reset(this: *@This(), globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) JSC.JSValue { _ = this; _ = globalThis; _ = callframe; + return .undefined; + } - return .zero; + pub fn getBytesWritten(this: *@This(), globalObject: *JSC.JSGlobalObject) JSC.JSValue { + _ = globalObject; + return JSC.JSValue.jsNumber(this.stream.total_in); } - pub fn endSync(this: *BrotliEncoder, globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) JSC.JSValue { + pub fn getClosed(this: *@This(), globalObject: *JSC.JSGlobalObject) JSC.JSValue { + _ = globalObject; + return JSC.JSValue.jsBoolean(this.closed); + } + + pub fn close(this: *@This(), globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) JSC.JSValue { _ = this; _ = globalThis; _ = callframe; - - return .zero; + return .undefined; } }; @@ -348,14 +415,17 @@ pub const BrotliDecoder = struct { globalThis: *JSC.JSGlobalObject, stream: brotli.BrotliReaderArrayList, + maxOutputLength: usize, + mode: u8, has_pending_activity: std.atomic.Value(u32) = std.atomic.Value(u32).init(0), ref_count: u32 = 1, poll_ref: bun.Async.KeepAlive = .{}, - write_failed: bool = false, + write_failure: ?JSC.DeferredError = null, callback_value: JSC.Strong = .{}, has_called_end: bool = false, pending_decode_job_count: std.atomic.Value(u32) = std.atomic.Value(u32).init(0), + closed: bool = false, input: Queue = Queue.init(bun.default_allocator), input_lock: bun.Lock = .{}, @@ -365,7 +435,7 @@ pub const BrotliDecoder = struct { freelist: FreeList = .{}, - pub fn hasPendingActivity(this: *BrotliDecoder) callconv(.C) bool { + pub fn hasPendingActivity(this: *BrotliDecoder) bool { return this.has_pending_activity.load(.monotonic) > 0; } @@ -379,29 +449,41 @@ pub const BrotliDecoder = struct { } pub fn constructor(globalThis: *JSC.JSGlobalObject, _: *JSC.CallFrame) ?*BrotliDecoder { - globalThis.throw("Crypto is not constructable", .{}); + globalThis.throw("BrotliDecoder is not constructable", .{}); return null; } pub fn create(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) JSC.JSValue { - const arguments = callframe.arguments(3).slice(); + const arguments = callframe.arguments(4).slice(); - if (arguments.len < 3) { - globalThis.throwNotEnoughArguments("BrotliDecoder", 3, arguments.len); + if (arguments.len < 4) { + globalThis.throwNotEnoughArguments("BrotliDecoder", 4, arguments.len); return .zero; } const opts = arguments[0]; const callback = arguments[2]; + const mode = arguments[3].to(u8); + + _ = globalThis.checkMinOrGetDefault(opts, "chunkSize", u32, 64, 1024 * 16) orelse return .zero; + const maxOutputLength = globalThis.checkMinOrGetDefaultU64(opts, "maxOutputLength", usize, 0, std.math.maxInt(u52)) orelse return .zero; + const flush = globalThis.checkRangesOrGetDefault(opts, "flush", u8, 0, 6, 0) orelse return .zero; + const finishFlush = globalThis.checkRangesOrGetDefault(opts, "finishFlush", u8, 0, 6, 2) orelse return .zero; + const fullFlush = globalThis.checkRangesOrGetDefault(opts, "fullFlush", u8, 0, 6, 1) orelse return .zero; var this: *BrotliDecoder = BrotliDecoder.new(.{ .globalThis = globalThis, .stream = undefined, // &this.output needs to be a stable pointer + .maxOutputLength = maxOutputLength, + .mode = mode, }); this.stream = brotli.BrotliReaderArrayList.initWithOptions("", &this.output, bun.default_allocator, .{}) catch { globalThis.throw("Failed to create BrotliDecoder", .{}); return .zero; }; + _ = flush; + _ = finishFlush; + _ = fullFlush; if (opts.get(globalThis, "params")) |params| { inline for (std.meta.fields(bun.brotli.c.BrotliDecoderParameter)) |f| { @@ -415,15 +497,15 @@ pub const BrotliDecoder = struct { } } } + if (globalThis.hasException()) return .zero; const out = this.toJS(globalThis); - @This().callbackSetCached(out, globalThis, callback); this.callback_value.set(globalThis, callback); return out; } - pub fn finalize(this: *BrotliDecoder) callconv(.C) void { + pub fn finalize(this: *BrotliDecoder) void { this.deinit(); } @@ -441,14 +523,14 @@ pub const BrotliDecoder = struct { defer _ = this.has_pending_activity.fetchSub(1, .monotonic); this.drainFreelist(); - const result = this.callback_value.get().?.call(this.globalThis, .undefined, &.{ - if (this.write_failed) - // TODO: propagate error from brotli - this.globalThis.createErrorInstance("BrotliError", .{}) + const result = this.callback_value.get().?.call( + this.globalThis, + .undefined, + if (this.write_failure != null) + &.{this.write_failure.?.toError(this.globalThis)} else - JSC.JSValue.null, - this.collectOutputValue(), - }); + &.{ .null, this.collectOutputValue() }, + ); if (result.toError()) |err| { _ = this.globalThis.bunVM().uncaughtException(this.globalThis, err, false); @@ -459,11 +541,11 @@ pub const BrotliDecoder = struct { this.freelist.drain(); } - pub fn decode(this: *BrotliDecoder, globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) JSC.JSValue { + pub fn transform(this: *BrotliDecoder, globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) JSC.JSValue { const arguments = callframe.arguments(3); - if (arguments.len < 2) { - globalThis.throwNotEnoughArguments("BrotliEncoder.decode", 2, arguments.len); + if (arguments.len < 3) { + globalThis.throwNotEnoughArguments("BrotliEncoder.decode", 3, arguments.len); return .zero; } @@ -498,16 +580,17 @@ pub const BrotliDecoder = struct { input_to_queue.protect(); this.input.writeItem(input_to_queue) catch bun.outOfMemory(); } + this.poll_ref.ref(this.globalThis.bunVM()); JSC.WorkPool.schedule(&task.task); return .undefined; } - pub fn decodeSync(this: *BrotliDecoder, globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) JSC.JSValue { - const arguments = callframe.arguments(3); + pub fn transformSync(this: *BrotliDecoder, globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) JSC.JSValue { + const arguments = callframe.arguments(4); - if (arguments.len < 2) { - globalThis.throwNotEnoughArguments("BrotliEncoder.decode", 2, arguments.len); + if (arguments.len < 3) { + globalThis.throwNotEnoughArguments("BrotliEncoder.decode", 3, arguments.len); return .zero; } @@ -519,6 +602,17 @@ pub const BrotliDecoder = struct { const input = callframe.argument(0); const optional_encoding = callframe.argument(1); const is_last = callframe.argument(2).toBoolean(); + // const optional_flushFlag = arguments.ptr[3]; + + // const old_flushFlag = this.stream.flushOp; + // defer this.stream.flushOp = old_flushFlag; + // blk: { + // if (!optional_flushFlag.isInt32()) break :blk; + // const int = optional_flushFlag.asInt32(); + // if (int < 0) break :blk; + // if (int > 3) break :blk; + // this.stream.flushOp = @enumFromInt(int); + // } const input_to_queue = JSC.Node.BlobOrStringOrBuffer.fromJSWithEncodingValueMaybeAsync(globalThis, bun.default_allocator, input, optional_encoding, true) orelse { globalThis.throwInvalidArgumentType("BrotliEncoder.decode", "input", "Blob, String, or Buffer"); @@ -543,7 +637,14 @@ pub const BrotliDecoder = struct { this.input.writeItem(input_to_queue) catch bun.outOfMemory(); } task.run(); - return if (!is_last) .undefined else this.collectOutputValue(); + if (!is_last and this.output.items.len == 0) { + return JSC.Buffer.fromBytes(&.{}, bun.default_allocator, .Uint8Array).toNodeBuffer(globalThis); + } + if (this.write_failure != null) { + globalThis.vm().throwError(globalThis, this.write_failure.?.toError(globalThis)); + return .zero; + } + return this.collectOutputValue(); } // We can only run one decode job at a time @@ -564,6 +665,8 @@ pub const BrotliDecoder = struct { } pub fn run(this: *DecodeJob) void { + const vm = this.decoder.globalThis.bunVMConcurrently(); + defer this.decoder.poll_ref.unrefConcurrently(vm); defer { _ = this.decoder.has_pending_activity.fetchSub(1, .monotonic); } @@ -605,10 +708,22 @@ pub const BrotliDecoder = struct { const input = if (pending.len <= 1) pending[0].slice() else input_list.items; this.decoder.stream.input = input; this.decoder.stream.readAll(false) catch { + any = true; _ = this.decoder.pending_decode_job_count.fetchSub(1, .monotonic); - this.decoder.write_failed = true; - return; + if (!this.is_async) { + this.decoder.closed = true; + this.decoder.globalThis.throw("BrotliError", .{}); + return; + } + this.decoder.write_failure = JSC.DeferredError.from(.plainerror, .ERR_OPERATION_FAILED, "BrotliError", .{}); // TODO propogate better error + break; }; + if (this.decoder.output.items.len > this.decoder.maxOutputLength) { + any = true; + _ = this.decoder.pending_decode_job_count.fetchSub(1, .monotonic); + this.decoder.write_failure = JSC.DeferredError.from(.rangeerror, .ERR_BUFFER_TOO_LARGE, "Cannot create a Buffer larger than {d} bytes", .{this.decoder.maxOutputLength}); + break; + } } any = any or pending.len > 0; @@ -619,27 +734,35 @@ pub const BrotliDecoder = struct { } if (this.is_async and any) { - var vm = this.decoder.globalThis.bunVMConcurrently(); _ = this.decoder.has_pending_activity.fetchAdd(1, .monotonic); this.decoder.poll_ref.refConcurrently(vm); + this.decoder.poll_ref.refConcurrently(vm); vm.enqueueTaskConcurrent(JSC.ConcurrentTask.create(JSC.Task.init(this.decoder))); } } }; - pub fn end(this: *BrotliDecoder, globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) JSC.JSValue { + pub fn reset(this: *@This(), globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) JSC.JSValue { _ = this; _ = globalThis; _ = callframe; + return .undefined; + } + + pub fn getBytesWritten(this: *@This(), globalObject: *JSC.JSGlobalObject) JSC.JSValue { + _ = globalObject; + return JSC.JSValue.jsNumber(this.stream.total_in); + } - return .zero; + pub fn getClosed(this: *@This(), globalObject: *JSC.JSGlobalObject) JSC.JSValue { + _ = globalObject; + return JSC.JSValue.jsBoolean(this.closed); } - pub fn endSync(this: *BrotliDecoder, globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) JSC.JSValue { + pub fn close(this: *@This(), globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) JSC.JSValue { _ = this; _ = globalThis; _ = callframe; - - return .zero; + return .undefined; } }; diff --git a/src/bun.js/api/js_zlib.zig b/src/bun.js/api/js_zlib.zig new file mode 100644 index 00000000000000..ab134c6369198f --- /dev/null +++ b/src/bun.js/api/js_zlib.zig @@ -0,0 +1,997 @@ +const std = @import("std"); +const bun = @import("root").bun; +const Environment = bun.Environment; +const JSC = bun.JSC; +const string = bun.string; +const Output = bun.Output; +const ZigString = JSC.ZigString; +const Queue = std.fifo.LinearFifo(JSC.Node.BlobOrStringOrBuffer, .Dynamic); + +pub const ZlibEncoder = struct { + pub usingnamespace bun.New(@This()); + pub usingnamespace JSC.Codegen.JSZlibEncoder; + + globalThis: *JSC.JSGlobalObject, + stream: bun.zlib.ZlibCompressorStreaming, + maxOutputLength: usize, + + freelist: Queue = Queue.init(bun.default_allocator), + freelist_write_lock: bun.Lock = .{}, + + input: Queue = Queue.init(bun.default_allocator), + input_lock: bun.Lock = .{}, + + has_called_end: bool = false, + callback_value: JSC.Strong = .{}, + + output: std.ArrayListUnmanaged(u8) = .{}, + output_lock: bun.Lock = .{}, + + has_pending_activity: std.atomic.Value(u32) = std.atomic.Value(u32).init(0), + pending_encode_job_count: std.atomic.Value(u32) = std.atomic.Value(u32).init(0), + ref_count: u32 = 1, + write_failure: ?JSC.DeferredError = null, + poll_ref: bun.Async.KeepAlive = .{}, + closed: bool = false, + + pub fn constructor(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) ?*@This() { + _ = callframe; + globalThis.throw("ZlibEncoder is not constructable", .{}); + return null; + } + + pub fn create(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) JSC.JSValue { + const arguments = callframe.arguments(4).slice(); + + if (arguments.len < 4) { + globalThis.throwNotEnoughArguments("ZlibEncoder", 4, arguments.len); + return .zero; + } + + const opts = arguments[0]; + const callback = arguments[2]; + const mode = arguments[3].to(bun.zlib.NodeMode); + + var options = Options.fromJS(globalThis, mode, opts) orelse return .zero; + + if (mode == .GZIP or mode == .GUNZIP) options.windowBits += 16; + if (mode == .UNZIP) options.windowBits += 32; + if (mode == .DEFLATERAW or mode == .INFLATERAW) options.windowBits *= -1; + + // In zlib v1.2.9, 8 become an invalid value for this parameter, so we gracefully fix it. + // Ref: https://github.com/nodejs/node/commit/241eb6122ee6f36de16ee4ed4a6a291510b1807f + if (mode == .DEFLATERAW and options.windowBits == -8) options.windowBits = -9; + + var this: *ZlibEncoder = ZlibEncoder.new(.{ + .globalThis = globalThis, + .maxOutputLength = options.maxOutputLength, + .stream = .{ + .mode = mode, + .chunkSize = options.chunkSize, + .flush = @enumFromInt(options.flush), + .finishFlush = @enumFromInt(options.finishFlush), + .fullFlush = @enumFromInt(options.fullFlush), + .level = options.level, + .windowBits = options.windowBits, + .memLevel = options.memLevel, + .strategy = options.strategy, + .dictionary = options.dictionary.slice(), + }, + }); + this.stream.init() catch { + globalThis.throw("Failed to create ZlibEncoder", .{}); + return .zero; + }; + + const out = this.toJS(globalThis); + this.callback_value.set(globalThis, callback); + + return out; + } + + pub fn finalize(this: *@This()) callconv(.C) void { + this.deinit(); + } + + pub fn deinit(this: *@This()) void { + this.input.deinit(); + this.output.deinit(bun.default_allocator); + this.callback_value.deinit(); + this.destroy(); + } + + pub fn transformSync(this: *@This(), globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) JSC.JSValue { + const arguments = callframe.arguments(4); + + if (arguments.len < 3) { + globalThis.throwNotEnoughArguments("ZlibEncoder.encode", 3, arguments.len); + return .zero; + } + + if (this.has_called_end) { + globalThis.throw("ZlibEncoder.encodeSync called after ZlibEncoder.end", .{}); + return .zero; + } + + const input = callframe.argument(0); + const optional_encoding = callframe.argument(1); + const is_last = callframe.argument(2).toBoolean(); + const optional_flushFlag = arguments.ptr[3]; + + const old_flushFlag = this.stream.flush; + defer this.stream.flush = old_flushFlag; + blk: { + if (!optional_flushFlag.isInt32()) break :blk; + const int = optional_flushFlag.asInt32(); + if (int < 0) break :blk; + if (int > 5) break :blk; + this.stream.flush = @enumFromInt(int); + } + + const input_to_queue = JSC.Node.BlobOrStringOrBuffer.fromJSWithEncodingValueMaybeAsync(globalThis, bun.default_allocator, input, optional_encoding, true) orelse { + return globalThis.throwInvalidArgumentTypeValue("buffer", "string or an instance of Buffer, TypedArray, DataView, or ArrayBuffer", input); + }; + + if (is_last) + this.has_called_end = true; + + { + this.stream.write(input_to_queue.slice(), &this.output, true) catch |err| return handleTransformSyncStreamError(err, globalThis, this.stream.err_msg, &this.closed); + } + if (this.output.items.len > this.maxOutputLength) { + globalThis.ERR_BUFFER_TOO_LARGE("Cannot create a Buffer larger than {d} bytes", .{this.maxOutputLength}).throw(); + return .zero; + } + if (is_last) { + this.stream.end(&this.output) catch |err| return handleTransformSyncStreamError(err, globalThis, this.stream.err_msg, &this.closed); + } + if (this.output.items.len > this.maxOutputLength) { + globalThis.ERR_BUFFER_TOO_LARGE("Cannot create a Buffer larger than {d} bytes", .{this.maxOutputLength}).throw(); + return .zero; + } + + if (!is_last and this.output.items.len == 0) { + return JSC.Buffer.fromBytes(&.{}, bun.default_allocator, .Uint8Array).toNodeBuffer(globalThis); + } + if (this.write_failure != null) { + globalThis.vm().throwError(globalThis, this.write_failure.?.toError(globalThis)); + return .zero; + } + return this.collectOutputValue(); + } + + pub fn transformWith(this: *@This(), globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) JSC.JSValue { + const arguments = callframe.arguments(4); + + if (arguments.len < 4) { + globalThis.throwNotEnoughArguments("ZlibEncoder.encode", 4, arguments.len); + return .zero; + } + + if (this.has_called_end) { + globalThis.throw("ZlibEncoder.encodeSync called after ZlibEncoder.end", .{}); + return .zero; + } + + const input = callframe.argument(0); + const optional_encoding = callframe.argument(1); + const thisctx = arguments.ptr[2]; + const is_last = callframe.argument(3).toBoolean(); + + const push_fn = thisctx.get(globalThis, "push") orelse { + globalThis.throw("are you sure this is a stream.Transform?", .{}); + return .zero; + }; + if (globalThis.hasException()) return .zero; + + const input_to_queue = JSC.Node.BlobOrStringOrBuffer.fromJSWithEncodingValueMaybeAsync(globalThis, bun.default_allocator, input, optional_encoding, true) orelse { + return globalThis.throwInvalidArgumentTypeValue("buffer", "string or an instance of Buffer, TypedArray, DataView, or ArrayBuffer", input); + }; + + if (is_last) + this.has_called_end = true; + + const err_buffer_too_large = globalThis.ERR_BUFFER_TOO_LARGE("Cannot create a Buffer larger than {d} bytes", .{this.maxOutputLength}); + + { + this.stream.write(input_to_queue.slice(), &this.output, false) catch |err| return handleTransformSyncStreamError(err, globalThis, this.stream.err_msg, &this.closed); + if (this.output.items.len > this.maxOutputLength) { + err_buffer_too_large.throw(); + return .zero; + } + while (true) { + const done = this.stream.doWork(&this.output, this.stream.flush) catch |err| return handleTransformSyncStreamError(err, globalThis, this.stream.err_msg, &this.closed); + if (this.output.items.len > this.maxOutputLength) { + err_buffer_too_large.throw(); + return .zero; + } + if (this.output.items.len > 0) runCallback(push_fn, globalThis, thisctx, &.{this.collectOutputValue()}) orelse return .zero; + if (done) break; + } + } + if (is_last) { + this.stream.end(&this.output) catch |err| return handleTransformSyncStreamError(err, globalThis, this.stream.err_msg, &this.closed); + if (this.output.items.len > this.maxOutputLength) { + globalThis.ERR_BUFFER_TOO_LARGE("Cannot create a Buffer larger than {d} bytes", .{this.maxOutputLength}).throw(); + return .zero; + } + if (this.output.items.len > 0) runCallback(push_fn, globalThis, thisctx, &.{this.collectOutputValue()}) orelse return .zero; + } + return .undefined; + } + + pub fn transform(this: *@This(), globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) JSC.JSValue { + const arguments = callframe.arguments(3); + + if (arguments.len < 3) { + globalThis.throwNotEnoughArguments("ZlibEncoder.encode", 3, arguments.len); + return .zero; + } + + if (this.has_called_end) { + globalThis.throw("ZlibEncoder.encode called after ZlibEncoder.end", .{}); + return .zero; + } + + const input = callframe.argument(0); + const optional_encoding = callframe.argument(1); + const is_last = callframe.argument(2).toBoolean(); + + const input_to_queue = JSC.Node.BlobOrStringOrBuffer.fromJSWithEncodingValueMaybeAsync(globalThis, bun.default_allocator, input, optional_encoding, true) orelse { + globalThis.throwInvalidArgumentType("ZlibEncoder.encode", "input", "Blob, String, or Buffer"); + return .zero; + }; + + _ = this.has_pending_activity.fetchAdd(1, .monotonic); + if (is_last) + this.has_called_end = true; + + var task = EncodeJob.new(.{ + .encoder = this, + }); + + { + this.input_lock.lock(); + defer this.input_lock.unlock(); + + this.input.writeItem(input_to_queue) catch unreachable; + } + this.poll_ref.ref(globalThis.bunVM()); + JSC.WorkPool.schedule(&task.task); + + return .undefined; + } + + pub fn runFromJSThread(this: *@This()) void { + this.poll_ref.unref(this.globalThis.bunVM()); + + defer _ = this.has_pending_activity.fetchSub(1, .monotonic); + this.drainFreelist(); + + const result = this.callback_value.get().?.call( + this.globalThis, + .undefined, + if (this.write_failure != null) + &.{this.write_failure.?.toError(this.globalThis)} + else + &.{ .null, this.collectOutputValue() }, + ); + + if (result.toError()) |err| { + _ = this.globalThis.bunVM().uncaughtException(this.globalThis, err, false); + } + } + + pub fn hasPendingActivity(this: *@This()) callconv(.C) bool { + return this.has_pending_activity.load(.monotonic) > 0; + } + + fn drainFreelist(this: *ZlibEncoder) void { + this.freelist_write_lock.lock(); + defer this.freelist_write_lock.unlock(); + const to_free = this.freelist.readableSlice(0); + for (to_free) |*input| { + input.deinit(); + } + this.freelist.discard(to_free.len); + } + + fn collectOutputValue(this: *ZlibEncoder) JSC.JSValue { + this.output_lock.lock(); + defer this.output_lock.unlock(); + + defer this.output.clearRetainingCapacity(); + return JSC.ArrayBuffer.createBuffer(this.globalThis, this.output.items); + } + + const EncodeJob = struct { + task: JSC.WorkPoolTask = .{ .callback = &runTask }, + encoder: *ZlibEncoder, + + pub usingnamespace bun.New(@This()); + + pub fn runTask(this: *JSC.WorkPoolTask) void { + var job: *EncodeJob = @fieldParentPtr("task", this); + job.run(); + job.destroy(); + } + + pub fn run(this: *EncodeJob) void { + const vm = this.encoder.globalThis.bunVMConcurrently(); + defer this.encoder.poll_ref.unrefConcurrently(vm); + defer { + _ = this.encoder.has_pending_activity.fetchSub(1, .monotonic); + } + + var any = false; + + if (this.encoder.pending_encode_job_count.fetchAdd(1, .monotonic) >= 0) { + const is_last = this.encoder.has_called_end; + outer: while (true) { + this.encoder.input_lock.lock(); + defer this.encoder.input_lock.unlock(); + const readable = this.encoder.input.readableSlice(0); + defer this.encoder.input.discard(readable.len); + const pending = readable; + + defer { + this.encoder.freelist_write_lock.lock(); + this.encoder.freelist.write(pending) catch unreachable; + this.encoder.freelist_write_lock.unlock(); + } + for (pending) |input| { + const output = &this.encoder.output; + this.encoder.stream.write(input.slice(), output, true) catch |e| { + any = true; + _ = this.encoder.pending_encode_job_count.fetchSub(1, .monotonic); + this.encoder.write_failure = JSC.DeferredError.from(.plainerror, .ERR_OPERATION_FAILED, "ZlibError: {s}", .{@errorName(e)}); // TODO propogate better error + break :outer; + }; + if (this.encoder.output.items.len > this.encoder.maxOutputLength) { + any = true; + _ = this.encoder.pending_encode_job_count.fetchSub(1, .monotonic); + this.encoder.write_failure = JSC.DeferredError.from(.rangeerror, .ERR_BUFFER_TOO_LARGE, "Cannot create a Buffer larger than {d} bytes", .{this.encoder.maxOutputLength}); + break :outer; + } + } + + any = any or pending.len > 0; + + if (this.encoder.pending_encode_job_count.fetchSub(1, .monotonic) == 0) + break; + } + + if (is_last and any) { + const output = &this.encoder.output; + this.encoder.output_lock.lock(); + defer this.encoder.output_lock.unlock(); + + this.encoder.stream.end(output) catch |e| { + _ = this.encoder.pending_encode_job_count.fetchSub(1, .monotonic); + this.encoder.write_failure = JSC.DeferredError.from(.plainerror, .ERR_OPERATION_FAILED, "ZlibError: {s}", .{@errorName(e)}); // TODO propogate better error + return; + }; + if (this.encoder.output.items.len > this.encoder.maxOutputLength) { + _ = this.encoder.pending_encode_job_count.fetchSub(1, .monotonic); + this.encoder.write_failure = JSC.DeferredError.from(.rangeerror, .ERR_BUFFER_TOO_LARGE, "Cannot create a Buffer larger than {d} bytes", .{this.encoder.maxOutputLength}); + return; + } + } + } + + if (any) { + _ = this.encoder.has_pending_activity.fetchAdd(1, .monotonic); + this.encoder.poll_ref.refConcurrently(vm); + this.encoder.poll_ref.refConcurrently(vm); + vm.enqueueTaskConcurrent(JSC.ConcurrentTask.create(JSC.Task.init(this.encoder))); + } + } + }; + + pub fn reset(this: *@This(), globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) JSC.JSValue { + _ = globalThis; + _ = callframe; + _ = bun.zlib.deflateReset(&this.stream.state); + return .undefined; + } + + pub fn getBytesWritten(this: *@This(), globalObject: *JSC.JSGlobalObject) callconv(.C) JSC.JSValue { + _ = globalObject; + return JSC.JSValue.jsNumber(@as(u64, this.stream.state.total_in)); + } + + pub fn getLevel(this: *@This(), globalObject: *JSC.JSGlobalObject) JSC.JSValue { + _ = globalObject; + return JSC.JSValue.jsNumber(this.stream.level); + } + + pub fn getStrategy(this: *@This(), globalObject: *JSC.JSGlobalObject) JSC.JSValue { + _ = globalObject; + return JSC.JSValue.jsNumber(this.stream.strategy); + } + + pub fn getClosed(this: *@This(), globalObject: *JSC.JSGlobalObject) JSC.JSValue { + _ = globalObject; + return JSC.JSValue.jsBoolean(this.closed); + } + + pub fn close(this: *@This(), globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) JSC.JSValue { + _ = this; + _ = globalThis; + _ = callframe; + return .undefined; + } + + pub fn params(this: *@This(), globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) JSC.JSValue { + const arguments = callframe.arguments(3).ptr; + if (this.stream.mode != .DEFLATE) return .undefined; + + const level = if (arguments[0] != .zero) (globalThis.checkRanges(arguments[0], "level", i16, -1, 9, -1) orelse return .zero) else this.stream.level; + const strategy = if (arguments[1] != .zero) (globalThis.checkRanges(arguments[1], "strategy", u8, 0, 4, 0) orelse return .zero) else this.stream.strategy; + this.stream.params(level, strategy); + + if (arguments[2] != .zero) { + if (!arguments[2].isFunction()) { + return globalThis.throwInvalidArgumentTypeValue("callback", "function", arguments[2]); + } + this.callback_value.set(globalThis, arguments[2]); + } + + return .undefined; + } +}; + +pub const ZlibDecoder = struct { + pub usingnamespace bun.New(@This()); + pub usingnamespace JSC.Codegen.JSZlibDecoder; + + globalThis: *JSC.JSGlobalObject, + stream: bun.zlib.ZlibDecompressorStreaming, + maxOutputLength: usize, + + freelist: Queue = Queue.init(bun.default_allocator), + freelist_write_lock: bun.Lock = .{}, + + input: Queue = Queue.init(bun.default_allocator), + input_lock: bun.Lock = .{}, + + has_called_end: bool = false, + callback_value: JSC.Strong = .{}, + + output: std.ArrayListUnmanaged(u8) = .{}, + output_lock: bun.Lock = .{}, + + has_pending_activity: std.atomic.Value(u32) = std.atomic.Value(u32).init(0), + pending_encode_job_count: std.atomic.Value(u32) = std.atomic.Value(u32).init(0), + ref_count: u32 = 1, + write_failure: ?JSC.DeferredError = null, + poll_ref: bun.Async.KeepAlive = .{}, + closed: bool = false, + + pub fn constructor(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) ?*@This() { + _ = callframe; + globalThis.throw("ZlibDecoder is not constructable", .{}); + return null; + } + + pub fn create(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) JSC.JSValue { + const arguments = callframe.arguments(4).slice(); + + if (arguments.len < 4) { + globalThis.throwNotEnoughArguments("ZlibDecoder", 4, arguments.len); + return .zero; + } + + const opts = arguments[0]; + const callback = arguments[2]; + const mode = arguments[3].to(bun.zlib.NodeMode); + + var options = Options.fromJS(globalThis, mode, opts) orelse return .zero; + + if (mode == .GZIP or mode == .GUNZIP) options.windowBits += 16; + if (mode == .UNZIP) options.windowBits += 32; + if (mode == .DEFLATERAW or mode == .INFLATERAW) options.windowBits *= -1; + + var this: *ZlibDecoder = ZlibDecoder.new(.{ + .globalThis = globalThis, + .maxOutputLength = options.maxOutputLength, + .stream = .{ + .mode = mode, + .chunkSize = options.chunkSize, + .flush = @enumFromInt(options.flush), + .finishFlush = @enumFromInt(options.finishFlush), + .fullFlush = @enumFromInt(options.fullFlush), + .windowBits = options.windowBits, + .dictionary = options.dictionary.slice(), + }, + }); + this.stream.init() catch { + globalThis.throw("Failed to create ZlibDecoder", .{}); + return .zero; + }; + + const out = this.toJS(globalThis); + this.callback_value.set(globalThis, callback); + + return out; + } + + pub fn finalize(this: *@This()) callconv(.C) void { + this.deinit(); + } + + pub fn deinit(this: *@This()) void { + this.input.deinit(); + this.output.deinit(bun.default_allocator); + this.callback_value.deinit(); + this.destroy(); + } + + pub fn transformSync(this: *@This(), globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) JSC.JSValue { + const arguments = callframe.arguments(4); + + if (arguments.len < 3) { + globalThis.throwNotEnoughArguments("ZlibDecoder.encode", 3, arguments.len); + return .zero; + } + + if (this.has_called_end) { + globalThis.throw("ZlibDecoder.encodeSync called after ZlibDecoder.end", .{}); + return .zero; + } + + const input = callframe.argument(0); + const optional_encoding = callframe.argument(1); + const is_last = callframe.argument(2).toBoolean(); + const optional_flushFlag = arguments.ptr[3]; + + const old_flushFlag = this.stream.flush; + defer this.stream.flush = old_flushFlag; + blk: { + if (!optional_flushFlag.isInt32()) break :blk; + const int = optional_flushFlag.asInt32(); + if (int < 0) break :blk; + if (int > 5) break :blk; + this.stream.flush = @enumFromInt(int); + } + + const input_to_queue = JSC.Node.BlobOrStringOrBuffer.fromJSWithEncodingValueMaybeAsync(globalThis, bun.default_allocator, input, optional_encoding, true) orelse { + return globalThis.throwInvalidArgumentTypeValue("buffer", "string or an instance of Buffer, TypedArray, DataView, or ArrayBuffer", input); + }; + + if (is_last) + this.has_called_end = true; + + { + this.stream.writeAll(input_to_queue.slice(), &this.output, true) catch |err| return handleTransformSyncStreamError(err, globalThis, this.stream.err_msg, &this.closed); + } + if (this.output.items.len > this.maxOutputLength) { + globalThis.ERR_BUFFER_TOO_LARGE("Cannot create a Buffer larger than {d} bytes", .{this.maxOutputLength}).throw(); + return .zero; + } + if (is_last) { + this.stream.end(&this.output) catch |err| return handleTransformSyncStreamError(err, globalThis, this.stream.err_msg, &this.closed); + } + if (this.output.items.len > this.maxOutputLength) { + globalThis.ERR_BUFFER_TOO_LARGE("Cannot create a Buffer larger than {d} bytes", .{this.maxOutputLength}).throw(); + return .zero; + } + + if (!is_last and this.output.items.len == 0) { + return JSC.Buffer.fromBytes(&.{}, bun.default_allocator, .Uint8Array).toNodeBuffer(globalThis); + } + if (this.write_failure != null) { + globalThis.vm().throwError(globalThis, this.write_failure.?.toError(globalThis)); + return .zero; + } + return this.collectOutputValue(); + } + + pub fn transformWith(this: *@This(), globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) JSC.JSValue { + const arguments = callframe.arguments(4); + + if (arguments.len < 4) { + globalThis.throwNotEnoughArguments("ZlibEncoder.encode", 4, arguments.len); + return .zero; + } + + if (this.has_called_end) { + globalThis.throw("ZlibEncoder.encodeSync called after ZlibEncoder.end", .{}); + return .zero; + } + + const input = callframe.argument(0); + const optional_encoding = callframe.argument(1); + const thisctx = arguments.ptr[2]; + const is_last = callframe.argument(3).toBoolean(); + + const push_fn = thisctx.get(globalThis, "push") orelse { + globalThis.throw("are you sure this is a stream.Transform?", .{}); + return .zero; + }; + if (globalThis.hasException()) return .zero; + + const input_to_queue = JSC.Node.BlobOrStringOrBuffer.fromJSWithEncodingValueMaybeAsync(globalThis, bun.default_allocator, input, optional_encoding, true) orelse { + return globalThis.throwInvalidArgumentTypeValue("buffer", "string or an instance of Buffer, TypedArray, DataView, or ArrayBuffer", input); + }; + + if (is_last) + this.has_called_end = true; + + const err_buffer_too_large = globalThis.ERR_BUFFER_TOO_LARGE("Cannot create a Buffer larger than {d} bytes", .{this.maxOutputLength}); + + { + const input_slice = input_to_queue.slice(); + this.stream.writeAll(input_slice, &this.output, false) catch |err| return handleTransformSyncStreamError(err, globalThis, this.stream.err_msg, &this.closed); + if (this.output.items.len > this.maxOutputLength) { + err_buffer_too_large.throw(); + return .zero; + } + while (this.stream.do_inflate_loop) { + const done = this.stream.doWork(&this.output, this.stream.flush) catch |err| return handleTransformSyncStreamError(err, globalThis, this.stream.err_msg, &this.closed); + if (this.output.items.len > this.maxOutputLength) { + err_buffer_too_large.throw(); + return .zero; + } + if (this.output.items.len > 0) runCallback(push_fn, globalThis, thisctx, &.{this.collectOutputValue()}) orelse return .zero; + if (done) break; + } + } + if (is_last) { + this.stream.end(&this.output) catch |err| return handleTransformSyncStreamError(err, globalThis, this.stream.err_msg, &this.closed); + if (this.output.items.len > this.maxOutputLength) { + globalThis.ERR_BUFFER_TOO_LARGE("Cannot create a Buffer larger than {d} bytes", .{this.maxOutputLength}).throw(); + return .zero; + } + if (this.output.items.len > 0) runCallback(push_fn, globalThis, thisctx, &.{this.collectOutputValue()}) orelse return .zero; + } + return .undefined; + } + + pub fn transform(this: *@This(), globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) JSC.JSValue { + const arguments = callframe.arguments(3); + + if (arguments.len < 3) { + globalThis.throwNotEnoughArguments("ZlibDecoder.encode", 3, arguments.len); + return .zero; + } + + if (this.has_called_end) { + globalThis.throw("ZlibDecoder.encode called after ZlibDecoder.end", .{}); + return .zero; + } + + const input = callframe.argument(0); + const optional_encoding = callframe.argument(1); + const is_last = callframe.argument(2).toBoolean(); + + const input_to_queue = JSC.Node.BlobOrStringOrBuffer.fromJSWithEncodingValueMaybeAsync(globalThis, bun.default_allocator, input, optional_encoding, true) orelse { + globalThis.throwInvalidArgumentType("ZlibDecoder.encode", "input", "Blob, String, or Buffer"); + return .zero; + }; + + _ = this.has_pending_activity.fetchAdd(1, .monotonic); + if (is_last) + this.has_called_end = true; + + var task = DecodeJob.new(.{ + .decoder = this, + }); + + { + this.input_lock.lock(); + defer this.input_lock.unlock(); + + this.input.writeItem(input_to_queue) catch unreachable; + } + this.poll_ref.ref(globalThis.bunVM()); + JSC.WorkPool.schedule(&task.task); + + return .undefined; + } + + pub fn runFromJSThread(this: *@This()) void { + this.poll_ref.unref(this.globalThis.bunVM()); + + defer _ = this.has_pending_activity.fetchSub(1, .monotonic); + this.drainFreelist(); + + const result = this.callback_value.get().?.call( + this.globalThis, + .undefined, + if (this.write_failure != null) + &.{this.write_failure.?.toError(this.globalThis)} + else + &.{ .null, this.collectOutputValue() }, + ); + + if (result.toError()) |err| { + _ = this.globalThis.bunVM().uncaughtException(this.globalThis, err, false); + } + } + + pub fn hasPendingActivity(this: *@This()) callconv(.C) bool { + return this.has_pending_activity.load(.monotonic) > 0; + } + + fn drainFreelist(this: *ZlibDecoder) void { + this.freelist_write_lock.lock(); + defer this.freelist_write_lock.unlock(); + const to_free = this.freelist.readableSlice(0); + for (to_free) |*input| { + input.deinit(); + } + this.freelist.discard(to_free.len); + } + + fn collectOutputValue(this: *ZlibDecoder) JSC.JSValue { + this.output_lock.lock(); + defer this.output_lock.unlock(); + + defer this.output.clearRetainingCapacity(); + return JSC.ArrayBuffer.createBuffer(this.globalThis, this.output.items); + } + + const DecodeJob = struct { + task: JSC.WorkPoolTask = .{ .callback = &runTask }, + decoder: *ZlibDecoder, + + pub usingnamespace bun.New(@This()); + + pub fn runTask(this: *JSC.WorkPoolTask) void { + var job: *DecodeJob = @fieldParentPtr("task", this); + job.run(); + job.destroy(); + } + + pub fn run(this: *DecodeJob) void { + const vm = this.decoder.globalThis.bunVMConcurrently(); + defer this.decoder.poll_ref.unrefConcurrently(vm); + defer { + _ = this.decoder.has_pending_activity.fetchSub(1, .monotonic); + } + + var any = false; + + if (this.decoder.pending_encode_job_count.fetchAdd(1, .monotonic) >= 0) outer: { + const is_last = this.decoder.has_called_end; + while (true) { + this.decoder.input_lock.lock(); + defer this.decoder.input_lock.unlock(); + const readable = this.decoder.input.readableSlice(0); + defer this.decoder.input.discard(readable.len); + const pending = readable; + + defer { + this.decoder.freelist_write_lock.lock(); + this.decoder.freelist.write(pending) catch unreachable; + this.decoder.freelist_write_lock.unlock(); + } + for (pending) |input| { + const output = &this.decoder.output; + this.decoder.stream.writeAll(input.slice(), output, true) catch |e| { + any = true; + _ = this.decoder.pending_encode_job_count.fetchSub(1, .monotonic); + switch (e) { + error.ZlibError => { + const message = std.mem.sliceTo(this.decoder.stream.err_msg.?, 0); + this.decoder.write_failure = JSC.DeferredError.from(.plainerror, .ERR_OPERATION_FAILED, "{s}", .{message}); + break :outer; + }, + else => {}, + } + this.decoder.write_failure = JSC.DeferredError.from(.plainerror, .ERR_OPERATION_FAILED, "ZlibError: {s}", .{@errorName(e)}); // TODO propogate better error + break :outer; + }; + } + + any = any or pending.len > 0; + + if (this.decoder.pending_encode_job_count.fetchSub(1, .monotonic) == 0) + break; + } + + if (is_last and any) { + const output = &this.decoder.output; + this.decoder.output_lock.lock(); + defer this.decoder.output_lock.unlock(); + + this.decoder.stream.end(output) catch |e| { + any = true; + _ = this.decoder.pending_encode_job_count.fetchSub(1, .monotonic); + switch (e) { + error.ZlibError => { + const message = std.mem.sliceTo(this.decoder.stream.err_msg.?, 0); + this.decoder.write_failure = JSC.DeferredError.from(.plainerror, .ERR_OPERATION_FAILED, "{s}", .{message}); + break :outer; + }, + else => { + this.decoder.write_failure = JSC.DeferredError.from(.plainerror, .ERR_OPERATION_FAILED, "ZlibError: {s}", .{@errorName(e)}); // TODO propogate better error + break :outer; + }, + } + }; + if (output.items.len > this.decoder.maxOutputLength) { + any = true; + _ = this.decoder.pending_encode_job_count.fetchSub(1, .monotonic); + this.decoder.write_failure = JSC.DeferredError.from(.rangeerror, .ERR_BUFFER_TOO_LARGE, "Cannot create a Buffer larger than {d} bytes", .{this.decoder.maxOutputLength}); + break :outer; + } + } + } + + if (any) { + _ = this.decoder.has_pending_activity.fetchAdd(1, .monotonic); + this.decoder.poll_ref.refConcurrently(vm); + this.decoder.poll_ref.refConcurrently(vm); + vm.enqueueTaskConcurrent(JSC.ConcurrentTask.create(JSC.Task.init(this.decoder))); + } + } + }; + + pub fn reset(this: *@This(), globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) JSC.JSValue { + _ = globalThis; + _ = callframe; + _ = bun.zlib.inflateReset(&this.stream.state); + return .undefined; + } + + pub fn getBytesWritten(this: *@This(), globalObject: *JSC.JSGlobalObject) callconv(.C) JSC.JSValue { + _ = globalObject; + return JSC.JSValue.jsNumber(@as(u64, this.stream.state.total_in)); + } + + pub fn getLevel(this: *@This(), globalObject: *JSC.JSGlobalObject) JSC.JSValue { + _ = this; + _ = globalObject; + return JSC.JSValue.jsUndefined(); + } + + pub fn getStrategy(this: *@This(), globalObject: *JSC.JSGlobalObject) JSC.JSValue { + _ = this; + _ = globalObject; + return JSC.JSValue.jsUndefined(); + } + + pub fn getClosed(this: *@This(), globalObject: *JSC.JSGlobalObject) JSC.JSValue { + _ = globalObject; + return JSC.JSValue.jsBoolean(this.closed); + } + + pub fn close(this: *@This(), globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) JSC.JSValue { + _ = this; + _ = globalThis; + _ = callframe; + return .undefined; + } + + pub fn params(this: *@This(), globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) JSC.JSValue { + _ = this; + _ = globalThis; + _ = callframe; + return .undefined; + } +}; + +const Options = struct { + chunkSize: c_uint, + level: c_int, + windowBits: c_int, + memLevel: c_int, + strategy: c_int, + dictionary: JSC.Buffer, + maxOutputLength: usize, + flush: u8, + finishFlush: u8, + fullFlush: u8, + + pub fn fromJS(globalThis: *JSC.JSGlobalObject, mode: bun.zlib.NodeMode, opts: JSC.JSValue) ?Options { + const chunkSize = globalThis.checkMinOrGetDefault(opts, "chunkSize", c_uint, 64, 1024 * 16) orelse return null; + const level = globalThis.checkRangesOrGetDefault(opts, "level", i16, -1, 9, -1) orelse return null; + const memLevel = globalThis.checkRangesOrGetDefault(opts, "memLevel", u8, 1, 9, 8) orelse return null; + const strategy = globalThis.checkRangesOrGetDefault(opts, "strategy", u8, 0, 4, 0) orelse return null; + const maxOutputLength = globalThis.checkMinOrGetDefaultU64(opts, "maxOutputLength", usize, 0, std.math.maxInt(u52)) orelse return null; + const flush = globalThis.checkRangesOrGetDefault(opts, "flush", u8, 0, 5, 0) orelse return null; + const finishFlush = globalThis.checkRangesOrGetDefault(opts, "finishFlush", u8, 0, 5, 4) orelse return null; + const fullFlush = globalThis.checkRangesOrGetDefault(opts, "fullFlush", u8, 0, 5, 3) orelse return null; + + const windowBits = switch (mode) { + .NONE, + .BROTLI_DECODE, + .BROTLI_ENCODE, + => unreachable, + .DEFLATE, .DEFLATERAW => globalThis.checkRangesOrGetDefault(opts, "windowBits", u8, 8, 15, 15) orelse return null, + .INFLATE, .INFLATERAW => getWindowBits(globalThis, opts, "windowBits", u8, 8, 15, 15) orelse return null, + .GZIP => globalThis.checkRangesOrGetDefault(opts, "windowBits", i16, 9, 15, 15) orelse return null, + .GUNZIP, .UNZIP => getWindowBits(globalThis, opts, "windowBits", i16, 9, 15, 15) orelse return null, + }; + + const dictionary = blk: { + var exceptionref: JSC.C.JSValueRef = null; + const value: JSC.JSValue = opts.get(globalThis, "dictionary") orelse { + if (globalThis.hasException()) return null; + break :blk JSC.Buffer.fromBytes(&.{}, bun.default_allocator, .Uint8Array); + }; + const buffer = JSC.Buffer.fromJS(globalThis, value, &exceptionref) orelse { + const ty_str = value.jsTypeString(globalThis).toSlice(globalThis, bun.default_allocator); + defer ty_str.deinit(); + globalThis.ERR_INVALID_ARG_TYPE("The \"options.dictionary\" property must be an instance of Buffer, TypedArray, DataView, or ArrayBuffer. Received {s}", .{ty_str.slice()}).throw(); + return null; + }; + if (exceptionref) |ptr| { + globalThis.throwValue(JSC.JSValue.c(ptr)); + return null; + } + break :blk buffer; + }; + + return .{ + .chunkSize = chunkSize, + .level = level, + .windowBits = windowBits, + .memLevel = memLevel, + .strategy = strategy, + .dictionary = dictionary, + .maxOutputLength = maxOutputLength, + .flush = flush, + .finishFlush = finishFlush, + .fullFlush = fullFlush, + }; + } + + // Specialization of globalThis.checkRangesOrGetDefault since windowBits also allows 0 when decompressing + fn getWindowBits(this: *JSC.JSGlobalObject, obj: JSC.JSValue, comptime field_name: []const u8, comptime T: type, min: T, max: T, default: T) ?T { + if (obj.get(this, field_name)) |level_val| { + if (!level_val.isNumber()) { + _ = this.throwInvalidPropertyTypeValue("options." ++ field_name, "number", level_val); + return null; + } + const level_f64 = level_val.asNumber(); + if (level_f64 == 0) return 0; + if (std.math.isNan(level_f64)) return default; + if (level_f64 == std.math.inf(f64)) { + this.ERR_OUT_OF_RANGE("The value of \"options.{s}\" is out of range. It must be >= {d}. Received Infinity", .{ field_name, min }).throw(); + return null; + } + if (level_f64 == -std.math.inf(f64)) { + this.ERR_OUT_OF_RANGE("The value of \"options.{s}\" is out of range. It must be >= {d}. Received -Infinity", .{ field_name, min }).throw(); + return null; + } + if (@floor(level_f64) != level_f64) { + _ = this.throwInvalidPropertyTypeValue("options." ++ field_name, "integer", level_val); + return null; + } + if (level_f64 > std.math.maxInt(i32)) { + this.ERR_OUT_OF_RANGE("The value of \"options.{s}\" is out of range. It must be >= {d} and <= {d}. Received {d}", .{ field_name, min, max, level_f64 }).throw(); + return null; + } + const level_i32 = level_val.toInt32(); + if (level_i32 < min or level_i32 > max) { + this.ERR_OUT_OF_RANGE("The value of \"options.{s}\" is out of range. It must be >= {d} and <= {d}. Received {d}", .{ field_name, min, max, level_i32 }).throw(); + return null; + } + return @intCast(level_i32); + } + if (this.hasException()) return null; + return default; + } +}; + +fn handleTransformSyncStreamError(err: anyerror, globalThis: *JSC.JSGlobalObject, err_msg: ?[*:0]const u8, closed: *bool) JSC.JSValue { + switch (err) { + error.ZlibError => { + globalThis.throw("{s}", .{std.mem.sliceTo(err_msg.?, 0)}); + }, + else => { + globalThis.throw("ZlibError: {s}", .{@errorName(err)}); + }, + } + closed.* = true; + return .zero; +} + +fn runCallback(callback: JSC.JSValue, globalObject: *JSC.JSGlobalObject, thisValue: JSC.JSValue, arguments: []const JSC.JSValue) ?void { + _ = callback.call(globalObject, thisValue, arguments); + if (globalObject.hasException()) return null; + return; +} diff --git a/src/bun.js/api/zlib.classes.ts b/src/bun.js/api/zlib.classes.ts new file mode 100644 index 00000000000000..23a46a55e20f56 --- /dev/null +++ b/src/bun.js/api/zlib.classes.ts @@ -0,0 +1,186 @@ +import { define } from "../../codegen/class-definitions"; + +export default [ + define({ + name: "BrotliEncoder", + construct: true, + noConstructor: true, + finalize: true, + configurable: false, + hasPendingActivity: true, + klass: {}, + JSType: "0b11101110", + values: ["callback"], + proto: { + transform: { + fn: "transform", + length: 2, + }, + transformSync: { + fn: "transformSync", + length: 2, + }, + reset: { + fn: "reset", + length: 0, + }, + bytesWritten: { + getter: "getBytesWritten", + }, + bytesRead: { // deprecated + value: "bytesWritten", + }, + closed: { + getter: "getClosed", + }, + close: { + fn: "close", + length: 0, + }, + }, + }), + define({ + name: "BrotliDecoder", + construct: true, + noConstructor: true, + finalize: true, + configurable: false, + hasPendingActivity: true, + klass: {}, + JSType: "0b11101110", + values: ["callback"], + + proto: { + transform: { + fn: "transform", + length: 2, + }, + transformSync: { + fn: "transformSync", + length: 2, + }, + reset: { + fn: "reset", + length: 0, + }, + bytesWritten: { + getter: "getBytesWritten", + }, + bytesRead: { // deprecated + value: "bytesWritten", + }, + closed: { + getter: "getClosed", + }, + close: { + fn: "close", + length: 0, + }, + }, + }), + define({ + name: "ZlibEncoder", + construct: true, + noConstructor: true, + finalize: true, + configurable: false, + hasPendingActivity: true, + klass: {}, + JSType: "0b11101110", + values: ["callback"], + proto: { + transform: { + fn: "transform", + length: 2, + }, + transformSync: { + fn: "transformSync", + length: 2, + }, + transformWith: { + fn: "transformWith", + length: 4, + }, + reset: { + fn: "reset", + length: 0, + }, + bytesWritten: { + getter: "getBytesWritten", + }, + bytesRead: { // deprecated + value: "bytesWritten", + }, + level: { + getter: "getLevel", + }, + strategy: { + getter: "getStrategy", + }, + closed: { + getter: "getClosed", + }, + close: { + fn: "close", + length: 0, + }, + params: { + fn: "params", + length: 3, + }, + }, + }), + define({ + name: "ZlibDecoder", + construct: true, + noConstructor: true, + finalize: true, + configurable: false, + hasPendingActivity: true, + klass: {}, + JSType: "0b11101110", + values: ["callback"], + + proto: { + transform: { + fn: "transform", + length: 2, + }, + transformSync: { + fn: "transformSync", + length: 2, + }, + transformWith: { + fn: "transformWith", + length: 4, + }, + reset: { + fn: "reset", + length: 0, + }, + bytesWritten: { + getter: "getBytesWritten", + }, + bytesRead: { // deprecated + value: "bytesWritten", + }, + level: { + getter: "getLevel", + }, + strategy: { + getter: "getStrategy", + }, + closed: { + getter: "getClosed", + }, + close: { + fn: "close", + length: 0, + }, + params: { + fn: "params", + length: 3, + }, + }, + }), +]; diff --git a/src/bun.js/base.zig b/src/bun.js/base.zig index c140be3e69131f..8c3884a4d34ea0 100644 --- a/src/bun.js/base.zig +++ b/src/bun.js/base.zig @@ -647,18 +647,18 @@ pub const MarkedArrayBuffer = struct { } } - pub fn init(allocator: std.mem.Allocator, size: u32, typed_array_type: js.JSTypedArrayType) !*MarkedArrayBuffer { + pub fn init(allocator: std.mem.Allocator, size: u32, typed_array_type: JSC.JSValue.JSType) !*MarkedArrayBuffer { const bytes = try allocator.alloc(u8, size); const container = try allocator.create(MarkedArrayBuffer); container.* = MarkedArrayBuffer.fromBytes(bytes, allocator, typed_array_type); return container; } - pub fn toNodeBuffer(this: MarkedArrayBuffer, ctx: js.JSContextRef) JSC.JSValue { + pub fn toNodeBuffer(this: *const MarkedArrayBuffer, ctx: js.JSContextRef) JSC.JSValue { return JSValue.createBufferWithCtx(ctx, this.buffer.byteSlice(), this.buffer.ptr, MarkedArrayBuffer_deallocator); } - pub fn toJSObjectRef(this: MarkedArrayBuffer, ctx: js.JSContextRef, exception: js.ExceptionRef) js.JSObjectRef { + pub fn toJSObjectRef(this: *const MarkedArrayBuffer, ctx: js.JSContextRef, exception: js.ExceptionRef) js.JSObjectRef { if (!this.buffer.value.isEmptyOrUndefinedOrNull()) { return this.buffer.value.asObjectRef(); } @@ -684,7 +684,7 @@ pub const MarkedArrayBuffer = struct { } // TODO: refactor this - pub fn toJS(this: *MarkedArrayBuffer, globalObject: *JSC.JSGlobalObject) JSC.JSValue { + pub fn toJS(this: *const MarkedArrayBuffer, globalObject: *JSC.JSGlobalObject) JSC.JSValue { var exception = [_]JSC.C.JSValueRef{null}; const obj = this.toJSObjectRef(globalObject, &exception); diff --git a/src/bun.js/bindings/ErrorCode.ts b/src/bun.js/bindings/ErrorCode.ts index fdc964fb1c1a69..3a42a53c0e7c0d 100644 --- a/src/bun.js/bindings/ErrorCode.ts +++ b/src/bun.js/bindings/ErrorCode.ts @@ -34,10 +34,14 @@ export default [ ["ERR_STREAM_DESTROYED", TypeError, "TypeError"], ["ERR_STREAM_NULL_VALUES", TypeError, "TypeError"], ["ERR_STREAM_WRITE_AFTER_END", TypeError, "TypeError"], + ["ERR_ZLIB_INITIALIZATION_FAILED", Error, "Error"], ["ERR_STRING_TOO_LONG", Error, "Error"], - ["ERR_ZLIB_INITIALIZATION_FAILED", TypeError, "TypeError"], + ["ERR_CRYPTO_SCRYPT_INVALID_PARAMETER", Error, "Error"], + ["ERR_CRYPTO_INVALID_SCRYPT_PARAMS", RangeError, "RangeError"], + ["MODULE_NOT_FOUND", Error, "Error"], ["ERR_ILLEGAL_CONSTRUCTOR", TypeError, "TypeError"], ["ERR_INVALID_URL", TypeError, "TypeError"], + ["ERR_BUFFER_TOO_LARGE", RangeError, "RangeError"], // Bun-specific ["ERR_FORMDATA_PARSE_ERROR", TypeError, "TypeError"], diff --git a/src/bun.js/bindings/bindings.cpp b/src/bun.js/bindings/bindings.cpp index a9f3cc2ddc0f0e..014382a320d55a 100644 --- a/src/bun.js/bindings/bindings.cpp +++ b/src/bun.js/bindings/bindings.cpp @@ -5749,6 +5749,16 @@ extern "C" EncodedJSValue JSC__createError(JSC::JSGlobalObject* globalObject, co return JSValue::encode(JSC::createError(globalObject, str->toWTFString(BunString::ZeroCopy))); } +extern "C" EncodedJSValue JSC__createTypeError(JSC::JSGlobalObject* globalObject, const BunString* str) +{ + return JSValue::encode(JSC::createTypeError(globalObject, str->toWTFString(BunString::ZeroCopy))); +} + +extern "C" EncodedJSValue JSC__createRangeError(JSC::JSGlobalObject* globalObject, const BunString* str) +{ + return JSValue::encode(JSC::createRangeError(globalObject, str->toWTFString(BunString::ZeroCopy))); +} + extern "C" EncodedJSValue ExpectMatcherUtils__getSingleton(JSC::JSGlobalObject* globalObject_) { Zig::GlobalObject* globalObject = reinterpret_cast(globalObject_); diff --git a/src/bun.js/bindings/bindings.zig b/src/bun.js/bindings/bindings.zig index eeb62dd6b8bc0e..79cc52d108bb84 100644 --- a/src/bun.js/bindings/bindings.zig +++ b/src/bun.js/bindings/bindings.zig @@ -2933,6 +2933,18 @@ pub const JSGlobalObject = opaque { return .zero; } + pub fn throwInvalidPropertyTypeValue( + this: *JSGlobalObject, + field: []const u8, + typename: []const u8, + value: JSValue, + ) JSValue { + const ty_str = value.jsTypeString(this).toSlice(this, bun.default_allocator); + defer ty_str.deinit(); + this.ERR_INVALID_ARG_TYPE("The \"{s}\" property must be of type {s}. Received {s}", .{ field, typename, ty_str.slice() }).throw(); + return .zero; + } + pub fn createNotEnoughArguments( this: *JSGlobalObject, comptime name_: []const u8, @@ -3011,12 +3023,6 @@ pub const JSGlobalObject = opaque { } } - pub fn createErrorInstanceWithCode(this: *JSGlobalObject, code: JSC.Node.ErrorCode, comptime fmt: [:0]const u8, args: anytype) JSValue { - var err = this.createErrorInstance(fmt, args); - err.put(this, ZigString.static("code"), ZigString.init(@tagName(code)).toJS(this)); - return err; - } - pub fn createTypeErrorInstance(this: *JSGlobalObject, comptime fmt: [:0]const u8, args: anytype) JSValue { if (comptime std.meta.fieldNames(@TypeOf(args)).len > 0) { var stack_fallback = std.heap.stackFallback(1024 * 4, this.allocator()); @@ -3031,12 +3037,6 @@ pub const JSGlobalObject = opaque { } } - fn createTypeErrorInstanceWithCode(this: *JSGlobalObject, code: JSC.Node.ErrorCode, comptime fmt: [:0]const u8, args: anytype) JSValue { - var err = this.createTypeErrorInstance(fmt, args); - err.put(this, ZigString.static("code"), ZigString.init(@tagName(code)).toJS(this)); - return err; - } - pub fn createSyntaxErrorInstance(this: *JSGlobalObject, comptime fmt: [:0]const u8, args: anytype) JSValue { if (comptime std.meta.fieldNames(@TypeOf(args)).len > 0) { var stack_fallback = std.heap.stackFallback(1024 * 4, this.allocator()); @@ -3065,12 +3065,6 @@ pub const JSGlobalObject = opaque { } } - pub fn createRangeErrorInstanceWithCode(this: *JSGlobalObject, code: JSC.Node.ErrorCode, comptime fmt: [:0]const u8, args: anytype) JSValue { - var err = this.createRangeErrorInstance(fmt, args); - err.put(this, ZigString.static("code"), ZigString.init(@tagName(code)).toJS(this)); - return err; - } - pub fn createRangeError(this: *JSGlobalObject, comptime fmt: [:0]const u8, args: anytype) JSValue { const err = createErrorInstance(this, fmt, args); err.put(this, ZigString.static("code"), ZigString.static(@tagName(JSC.Node.ErrorCode.ERR_OUT_OF_RANGE)).toJS(this)); @@ -3321,6 +3315,139 @@ pub const JSGlobalObject = opaque { return Bun__ERR_INVALID_ARG_TYPE_static(this, arg_name, etype, atype); } + pub fn checkRanges(this: *JSGlobalObject, value: JSValue, field_name: []const u8, comptime T: type, min: T, max: T, default: T) ?T { + if (!value.isNumber()) { + _ = this.throwInvalidPropertyTypeValue(field_name, "number", value); + return null; + } + const level_f64 = value.asNumber(); + if (std.math.isNan(level_f64)) { + return default; + } + if (level_f64 == std.math.inf(f64)) { + this.ERR_OUT_OF_RANGE("The value of \"{s}\" is out of range. It must be >= {d}. Received Infinity", .{ field_name, min }).throw(); + return null; + } + if (level_f64 == -std.math.inf(f64)) { + this.ERR_OUT_OF_RANGE("The value of \"{s}\" is out of range. It must be >= {d}. Received -Infinity", .{ field_name, min }).throw(); + return null; + } + if (@floor(level_f64) != level_f64) { + _ = this.throwInvalidPropertyTypeValue(field_name, "integer", value); + return null; + } + if (level_f64 > std.math.maxInt(i32)) { + this.ERR_OUT_OF_RANGE("The value of \"{s}\" is out of range. It must be >= {d} and <= {d}. Received {d}", .{ field_name, min, max, level_f64 }).throw(); + return null; + } + const level_i32 = value.toInt32(); + if (level_i32 < min or level_i32 > max) { + this.ERR_OUT_OF_RANGE("The value of \"{s}\" is out of range. It must be >= {d} and <= {d}. Received {d}", .{ field_name, min, max, level_i32 }).throw(); + return null; + } + return @intCast(level_i32); + } + + pub fn checkRangesOrGetDefault(this: *JSGlobalObject, obj: JSValue, comptime field_name: []const u8, comptime T: type, min: T, max: T, default: T) ?T { + if (obj.get(this, field_name)) |level_val| { + if (!level_val.isNumber()) { + _ = this.throwInvalidPropertyTypeValue("options." ++ field_name, "number", level_val); + return null; + } + const level_f64 = level_val.asNumber(); + if (std.math.isNan(level_f64)) { + return default; + } + if (level_f64 == std.math.inf(f64)) { + this.ERR_OUT_OF_RANGE("The value of \"options.{s}\" is out of range. It must be >= {d}. Received Infinity", .{ field_name, min }).throw(); + return null; + } + if (level_f64 == -std.math.inf(f64)) { + this.ERR_OUT_OF_RANGE("The value of \"options.{s}\" is out of range. It must be >= {d}. Received -Infinity", .{ field_name, min }).throw(); + return null; + } + if (@floor(level_f64) != level_f64) { + _ = this.throwInvalidPropertyTypeValue("options." ++ field_name, "integer", level_val); + return null; + } + if (level_f64 > std.math.maxInt(i32)) { + this.ERR_OUT_OF_RANGE("The value of \"options.{s}\" is out of range. It must be >= {d} and <= {d}. Received {d}", .{ field_name, min, max, level_f64 }).throw(); + return null; + } + const level_i32 = level_val.toInt32(); + if (level_i32 < min or level_i32 > max) { + this.ERR_OUT_OF_RANGE("The value of \"options.{s}\" is out of range. It must be >= {d} and <= {d}. Received {d}", .{ field_name, min, max, level_i32 }).throw(); + return null; + } + return @intCast(level_i32); + } + if (this.hasException()) return null; + return default; + } + + pub fn checkMinOrGetDefault(this: *JSGlobalObject, obj: JSValue, comptime field_name: []const u8, comptime T: type, min: T, default: T) ?T { + if (obj.get(this, field_name)) |level_val| { + if (!level_val.isNumber()) { + _ = this.throwInvalidPropertyTypeValue("options." ++ field_name, "number", level_val); + return null; + } + const level_f64 = level_val.asNumber(); + if (std.math.isNan(level_f64)) { + return default; + } + if (level_f64 == std.math.inf(f64)) { + this.ERR_OUT_OF_RANGE("The value of \"options.{s}\" is out of range. It must be >= {d}. Received Infinity", .{ field_name, min }).throw(); + return null; + } + if (level_f64 == -std.math.inf(f64)) { + this.ERR_OUT_OF_RANGE("The value of \"options.{s}\" is out of range. It must be >= {d}. Received -Infinity", .{ field_name, min }).throw(); + return null; + } + if (@floor(level_f64) != level_f64) { + _ = this.throwInvalidPropertyTypeValue("options." ++ field_name, "integer", level_val); + return null; + } + if (level_f64 > std.math.maxInt(i32)) { + this.ERR_OUT_OF_RANGE("The value of \"options.{s}\" is out of range. It must be >= {d}. Received {d}", .{ field_name, min, level_f64 }).throw(); + return null; + } + const level_i32 = level_val.toInt32(); + if (level_i32 < min) { + this.ERR_OUT_OF_RANGE("The value of \"options.{s}\" is out of range. It must be >= {d}. Received {d}", .{ field_name, min, level_i32 }).throw(); + return null; + } + return @intCast(level_i32); + } + if (this.hasException()) return null; + return default; + } + + pub fn checkMinOrGetDefaultU64(this: *JSGlobalObject, obj: JSValue, comptime field_name: []const u8, comptime T: type, min: T, default: T) ?T { + if (obj.get(this, field_name)) |level_val| { + if (!level_val.isNumber()) { + _ = this.throwInvalidPropertyTypeValue("options." ++ field_name, "number", level_val); + return null; + } + const level_double = level_val.asNumber(); + if (level_double == std.math.inf(f64)) { + this.ERR_OUT_OF_RANGE("The value of \"options.{s}\" is out of range. It must be >= {d}. Received Infinity", .{ field_name, min }).throw(); + return null; + } + if (level_double == -std.math.inf(f64)) { + this.ERR_OUT_OF_RANGE("The value of \"options.{s}\" is out of range. It must be >= {d}. Received -Infinity", .{ field_name, min }).throw(); + return null; + } + const level_int = level_val.to(i64); + if (level_int < min) { + this.ERR_OUT_OF_RANGE("The value of \"options.{s}\" is out of range. It must be >= {d}. Received {d}", .{ field_name, min, level_int }).throw(); + return null; + } + return @intCast(level_int); + } + if (this.hasException()) return null; + return default; + } + extern fn Bun__ERR_MISSING_ARGS_static(*JSGlobalObject, *const ZigString, ?*const ZigString, ?*const ZigString) JSValue; pub fn ERR_MISSING_ARGS_static(this: *JSGlobalObject, arg1: *const ZigString, arg2: ?*const ZigString, arg3: ?*const ZigString) JSValue { return Bun__ERR_MISSING_ARGS_static(this, arg1, arg2, arg3); @@ -3847,6 +3974,10 @@ pub const JSValue = enum(JSValueReprInt) { /// This does not call [Symbol.toPrimitive] or [Symbol.toStringTag]. /// This is only safe when you don't want to do conversions across non-primitive types. pub fn to(this: JSValue, comptime T: type) T { + if (@typeInfo(T) == .Enum) { + const Int = @typeInfo(T).Enum.tag_type; + return @enumFromInt(this.to(Int)); + } return switch (comptime T) { u32 => toU32(this), u16 => toU16(this), @@ -6571,3 +6702,31 @@ comptime { // because zig will complain about outside-of-module stuff _ = @import("./GeneratedJS2Native.zig"); } + +// Error's cannot be created off of the main thread. So we use this to store the +// information until its ready to be materialized later. +pub const DeferredError = struct { + kind: Kind, + code: JSC.Node.ErrorCode, + msg: bun.String, + + pub const Kind = enum { plainerror, typeerror, rangeerror }; + + pub fn from(kind: Kind, code: JSC.Node.ErrorCode, comptime fmt: [:0]const u8, args: anytype) DeferredError { + return .{ + .kind = kind, + .code = code, + .msg = bun.String.createFormat(fmt, args) catch bun.outOfMemory(), + }; + } + + pub fn toError(this: *const DeferredError, globalThis: *JSGlobalObject) JSValue { + const err = switch (this.kind) { + .plainerror => this.msg.toErrorInstance(globalThis), + .typeerror => this.msg.toTypeErrorInstance(globalThis), + .rangeerror => this.msg.toRangeErrorInstance(globalThis), + }; + err.put(globalThis, ZigString.static("code"), ZigString.init(@tagName(this.code)).toJS(globalThis)); + return err; + } +}; diff --git a/src/bun.js/bindings/generated_classes_list.zig b/src/bun.js/bindings/generated_classes_list.zig index a18896fbb409b1..7550e84910e8bf 100644 --- a/src/bun.js/bindings/generated_classes_list.zig +++ b/src/bun.js/bindings/generated_classes_list.zig @@ -76,4 +76,6 @@ pub const Classes = struct { pub const BrotliEncoder = JSC.API.BrotliEncoder; pub const BrotliDecoder = JSC.API.BrotliDecoder; pub const TextEncoderStreamEncoder = JSC.WebCore.TextEncoderStreamEncoder; + pub const ZlibEncoder = JSC.API.ZlibEncoder; + pub const ZlibDecoder = JSC.API.ZlibDecoder; }; diff --git a/src/bun.js/event_loop.zig b/src/bun.js/event_loop.zig index c441bed170475f..14206bf82cd17e 100644 --- a/src/bun.js/event_loop.zig +++ b/src/bun.js/event_loop.zig @@ -382,6 +382,8 @@ const Lchown = JSC.Node.Async.lchown; const Unlink = JSC.Node.Async.unlink; const BrotliDecoder = JSC.API.BrotliDecoder; const BrotliEncoder = JSC.API.BrotliEncoder; +const ZlibDecoder = JSC.API.ZlibDecoder; +const ZlibEncoder = JSC.API.ZlibEncoder; const ShellGlobTask = bun.shell.interpret.Interpreter.Expansion.ShellGlobTask; const ShellRmTask = bun.shell.Interpreter.Builtin.Rm.ShellRmTask; @@ -466,6 +468,8 @@ pub const Task = TaggedPointerUnion(.{ Unlink, BrotliEncoder, BrotliDecoder, + ZlibEncoder, + ZlibDecoder, ShellGlobTask, ShellRmTask, ShellRmDirTask, @@ -1221,6 +1225,14 @@ pub const EventLoop = struct { var any: *BrotliDecoder = task.get(BrotliDecoder).?; any.runFromJSThread(); }, + @field(Task.Tag, typeBaseName(@typeName(ZlibEncoder))) => { + var any: *ZlibEncoder = task.get(ZlibEncoder).?; + any.runFromJSThread(); + }, + @field(Task.Tag, typeBaseName(@typeName(ZlibDecoder))) => { + var any: *ZlibDecoder = task.get(ZlibDecoder).?; + any.runFromJSThread(); + }, @field(Task.Tag, typeBaseName(@typeName(ProcessWaiterThreadTask))) => { bun.markPosixOnly(); var any: *ProcessWaiterThreadTask = task.get(ProcessWaiterThreadTask).?; diff --git a/src/bun.js/module_loader.zig b/src/bun.js/module_loader.zig index cdb18c0045affa..f091e91d489e69 100644 --- a/src/bun.js/module_loader.zig +++ b/src/bun.js/module_loader.zig @@ -2344,7 +2344,7 @@ pub const ModuleLoader = struct { virtual_source = &virtual_source_to_use.?; } } else { - ret.* = ErrorableResolvedSource.err(error.JSErrorObject, globalObject.createErrorInstanceWithCode(.MODULE_NOT_FOUND, "Blob not found", .{}).asVoid()); + ret.* = ErrorableResolvedSource.err(error.JSErrorObject, globalObject.MODULE_NOT_FOUND("Blob not found", .{}).toJS().asVoid()); return null; } } diff --git a/src/bun.js/node/node_zlib_binding.zig b/src/bun.js/node/node_zlib_binding.zig index 18f9abc97c7ff1..a7d1eccba9a335 100644 --- a/src/bun.js/node/node_zlib_binding.zig +++ b/src/bun.js/node/node_zlib_binding.zig @@ -5,3 +5,64 @@ const JSC = bun.JSC; const string = bun.string; const Output = bun.Output; const ZigString = JSC.ZigString; + +pub const createBrotliEncoder = bun.JSC.API.BrotliEncoder.create; + +pub const createBrotliDecoder = bun.JSC.API.BrotliDecoder.create; + +pub const createZlibEncoder = bun.JSC.API.ZlibEncoder.create; + +pub const createZlibDecoder = bun.JSC.API.ZlibDecoder.create; + +pub fn crc32(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) JSC.JSValue { + const arguments = callframe.arguments(2).ptr; + + const data: []const u8 = blk: { + const data: JSC.JSValue = arguments[0]; + var exceptionref: JSC.C.JSValueRef = null; + + if (data == .zero) { + return globalThis.throwInvalidArgumentTypeValue("data", "string or an instance of Buffer, TypedArray, or DataView", .undefined); + } + if (data.isString()) { + break :blk data.asString().toSlice(globalThis, bun.default_allocator).slice(); + } + const buffer = JSC.Buffer.fromJS(globalThis, data, &exceptionref) orelse { + const ty_str = data.jsTypeString(globalThis).toSlice(globalThis, bun.default_allocator); + defer ty_str.deinit(); + globalThis.ERR_INVALID_ARG_TYPE("The \"data\" property must be an instance of Buffer, TypedArray, DataView, or ArrayBuffer. Received {s}", .{ty_str.slice()}).throw(); + return .zero; + }; + if (exceptionref) |ptr| { + globalThis.throwValue(JSC.JSValue.c(ptr)); + return .zero; + } + break :blk buffer.slice(); + }; + + const value: u32 = blk: { + const value: JSC.JSValue = arguments[1]; + if (value == .zero) { + break :blk 0; + } + if (!value.isNumber()) { + return globalThis.throwInvalidArgumentTypeValue("value", "number", value); + } + const valuef = value.asNumber(); + const min = 0; + const max = std.math.maxInt(u32); + + if (@floor(valuef) != valuef) { + globalThis.ERR_OUT_OF_RANGE("The value of \"{s}\" is out of range. It must be an integer. Received {}", .{ "value", valuef }).throw(); + return .zero; + } + if (valuef < min or valuef > max) { + globalThis.ERR_OUT_OF_RANGE("The value of \"{s}\" is out of range. It must be >= {d} and <= {d}. Received {d}", .{ "value", min, max, valuef }).throw(); + return .zero; + } + break :blk @intFromFloat(valuef); + }; + + // crc32 returns a u64 but the data will always be within a u32 range so the outer @intCast is always safe. + return JSC.JSValue.jsNumber(@as(u32, @intCast(bun.zlib.crc32(value, data.ptr, @intCast(data.len))))); +} diff --git a/src/bun.js/webcore.zig b/src/bun.js/webcore.zig index 8a869afff65d8f..26aa7f7c18af82 100644 --- a/src/bun.js/webcore.zig +++ b/src/bun.js/webcore.zig @@ -538,25 +538,13 @@ pub const Crypto = struct { } fn throwInvalidParameter(globalThis: *JSC.JSGlobalObject) JSC.JSValue { - const err = globalThis.createErrorInstanceWithCode( - .ERR_CRYPTO_SCRYPT_INVALID_PARAMETER, - "Invalid scrypt parameters", - .{}, - ); - globalThis.throwValue(err); + globalThis.ERR_CRYPTO_SCRYPT_INVALID_PARAMETER("Invalid scrypt parameters", .{}).throw(); return .zero; } fn throwInvalidParams(globalThis: *JSC.JSGlobalObject, comptime error_type: @Type(.EnumLiteral), comptime message: [:0]const u8, fmt: anytype) JSC.JSValue { - const err = switch (error_type) { - .RangeError => globalThis.createRangeErrorInstanceWithCode( - .ERR_CRYPTO_INVALID_SCRYPT_PARAMS, - message, - fmt, - ), - else => @compileError("Error type not added!"), - }; - globalThis.throwValue(err); + if (error_type != .RangeError) @compileError("Error type not added!"); + globalThis.ERR_CRYPTO_INVALID_SCRYPT_PARAMS(message, fmt).throw(); BoringSSL.ERR_clear_error(); return .zero; } diff --git a/src/deps/zlib.posix.zig b/src/deps/zlib.posix.zig index b38cf143796c99..0cb5dec403704c 100644 --- a/src/deps/zlib.posix.zig +++ b/src/deps/zlib.posix.zig @@ -38,7 +38,7 @@ pub const zStream_struct = extern struct { total_out: uLong, /// last error message, NULL if no error - err_msg: [*c]const u8, + err_msg: ?[*:0]const u8, /// not visible by applications internal_state: ?*struct_internal_state, diff --git a/src/js/node/stream.ts b/src/js/node/stream.ts index 78379f16cccc59..ec669f047c51e2 100644 --- a/src/js/node/stream.ts +++ b/src/js/node/stream.ts @@ -3891,6 +3891,10 @@ var require_writable = __commonJS({ return writeOrBuffer(stream, state, chunk, encoding, cb); } Writable.prototype.write = function (chunk, encoding, cb) { + if ($isCallable(encoding)) { + cb = encoding; + encoding = null; + } return _write(this, chunk, encoding, cb) === true; }; Writable.prototype.cork = function () { diff --git a/src/js/node/zlib.ts b/src/js/node/zlib.ts index c3e616b3c2ce89..9208e8591db69b 100644 --- a/src/js/node/zlib.ts +++ b/src/js/node/zlib.ts @@ -1,4608 +1,470 @@ // Hardcoded module "node:zlib" +const assert = require("node:assert"); const stream = require("node:stream"); +const BufferModule = require("node:buffer"); +const { ERR_INVALID_ARG_TYPE } = require("internal/errors"); + +const ObjectDefineProperty = Object.defineProperty; -const ObjectSetPrototypeOf = Object.setPrototypeOf; +const createBrotliEncoder = $newZigFunction("node_zlib_binding.zig", "createBrotliEncoder", 3); +const createBrotliDecoder = $newZigFunction("node_zlib_binding.zig", "createBrotliDecoder", 3); +const createZlibEncoder = $newZigFunction("node_zlib_binding.zig", "createZlibEncoder", 3); +const createZlibDecoder = $newZigFunction("node_zlib_binding.zig", "createZlibDecoder", 3); -const createBrotliEncoder = $newZigFunction("js_brotli.zig", "BrotliEncoder.create", 2); -const createBrotliDecoder = $newZigFunction("js_brotli.zig", "BrotliDecoder.create", 2); +const maxOutputLengthDefault = $requireMap.$get("buffer")?.exports.kMaxLength ?? BufferModule.kMaxLength; -function brotliCompress(buffer, opts, callback) { - if (typeof opts === "function") { - callback = opts; - opts = {}; +// + +const kHandle = Symbol("kHandle"); +const kFlushFlag = Symbol("kFlushFlag"); +const kFlushBuffers: Buffer[] = []; +{ + const dummyArrayBuffer = new ArrayBuffer(); + for (const flushFlag of [0, 1, 2, 3, 4, 5]) { + kFlushBuffers[flushFlag] = Buffer.from(dummyArrayBuffer); + kFlushBuffers[flushFlag][kFlushFlag] = flushFlag; } - if (typeof callback !== "function") throw new TypeError("BrotliEncoder callback is not callable"); - const encoder = createBrotliEncoder(opts, {}, callback); - encoder.encode(buffer, undefined, true); } -function brotliDecompress(buffer, opts, callback) { - if (typeof opts === "function") { - callback = opts; - opts = {}; +// + +function Base(method, options) { + if (options == null) options = {}; + if ($isObject(options)) { + options.maxOutputLength ??= maxOutputLengthDefault; + + if (options.encoding || options.objectMode || options.writableObjectMode) { + options = { ...options }; + options.encoding = null; + options.objectMode = false; + options.writableObjectMode = false; + } } - if (typeof callback !== "function") throw new TypeError("BrotliDecoder callback is not callable"); - const decoder = createBrotliDecoder(opts, {}, callback); - decoder.decode(buffer, undefined, true); + const [, , private_constructor] = methods[method]; + this[kHandle] = private_constructor(options, {}, null, method); + stream.Transform.$call(this, options); } +Base.prototype = Object.create(stream.Transform.prototype); +ObjectDefineProperty(Base.prototype, "_handle", { + get: function () { + return this[kHandle]; + }, + set: function (newval) { + //noop + }, +}); +ObjectDefineProperty(Base.prototype, "bytesWritten", { + get: function () { + return this[kHandle].bytesWritten; + }, +}); +ObjectDefineProperty(Base.prototype, "bytesRead", { + get: function () { + return this[kHandle].bytesRead; + }, +}); +ObjectDefineProperty(Base.prototype, "_closed", { + get: function () { + return this[kHandle].closed; + }, +}); +Base.prototype.flush = function (kind, callback) { + if (typeof kind === "function" || (kind === undefined && !callback)) { + callback = kind; + kind = 3; + } + if (this.writableFinished) { + if (callback) process.nextTick(callback); + } else if (this.writableEnded) { + if (callback) this.once("end", callback); + } else { + this.write(kFlushBuffers[kind], "", callback); + } +}; +Base.prototype.reset = function () { + assert(this[kHandle], "zlib binding closed"); + return this[kHandle].reset(); +}; +Base.prototype.close = function (callback) { + if (callback) stream.finished(this, callback); + this.destroy(); +}; +Base.prototype._transform = function _transform(chunk, encoding, callback) { + try { + callback(undefined, this[kHandle].transformSync(chunk, encoding, false)); + } catch (err) { + callback(err, undefined); + } +}; +Base.prototype._flush = function _flush(callback) { + try { + callback(undefined, this[kHandle].transformSync("", undefined, true)); + } catch (err) { + callback(err, undefined); + } +}; +Base.prototype._final = function (callback) { + callback(); +}; +Base.prototype._processChunk = function (chunk, flushFlag, cb) { + // _processChunk() is left for backwards compatibility + if (typeof cb === "function") processChunk(this, chunk, flushFlag, cb); + else return processChunkSync(this, chunk, flushFlag); +}; -function brotliCompressSync(buffer, opts) { - const encoder = createBrotliEncoder(opts, {}, null); - return encoder.encodeSync(buffer, undefined, true); +function processChunkSync(self, chunk, flushFlag) { + return self[kHandle].transformSync(chunk, undefined, false, flushFlag); } -function brotliDecompressSync(buffer, opts) { - const decoder = createBrotliDecoder(opts, {}, null); - return decoder.decodeSync(buffer, undefined, true); +function processChunk(self, chunk, flushFlag, cb) { + if (self._closed) return process.nextTick(cb); + self[kHandle].transformSync(chunk, undefined, false, flushFlag); } -function createBrotliCompress(opts) { - return new BrotliCompress(opts); +// + +function Zlib(method, options) { + Base.$call(this, method, options); } +Zlib.prototype = Object.create(Base.prototype); +ObjectDefineProperty(Zlib.prototype, "_level", { + get: function () { + return this[kHandle].level; + }, +}); +ObjectDefineProperty(Zlib.prototype, "_strategy", { + get: function () { + return this[kHandle].strategy; + }, +}); +Zlib.prototype.params = function (level, strategy, callback) { + return this[kHandle].params(level, strategy, callback); +}; +Zlib.prototype._transform = function _transform(chunk, encoding, callback) { + try { + this[kHandle].transformWith(chunk, encoding, this, false); + callback(); + } catch (err) { + callback(err, undefined); + } +}; -const kHandle = Symbol("kHandle"); +// function BrotliCompress(opts) { if (!(this instanceof BrotliCompress)) return new BrotliCompress(opts); - this[kHandle] = createBrotliEncoder(opts, {}, null); - stream.Transform.$apply(this, arguments); + Base.$call(this, BROTLI_ENCODE, opts); } -BrotliCompress.prototype = Object.create(stream.Transform.prototype); +BrotliCompress.prototype = Object.create(Base.prototype); -BrotliCompress.prototype._transform = function _transform(chunk, encoding, callback) { - callback(undefined, this[kHandle].encodeSync(chunk, encoding, false)); -}; -BrotliCompress.prototype._flush = function _flush(callback) { - callback(undefined, this[kHandle].encodeSync("", undefined, true)); -}; - -function createBrotliDecompress(opts) { - return new BrotliDecompress(opts); -} +// function BrotliDecompress(opts) { if (!(this instanceof BrotliDecompress)) return new BrotliDecompress(opts); - this[kHandle] = createBrotliDecoder(opts, {}, null); - stream.Transform.$apply(this, arguments); + Base.$call(this, BROTLI_DECODE, opts); } -BrotliDecompress.prototype = Object.create(stream.Transform.prototype); +BrotliDecompress.prototype = Object.create(Base.prototype); -BrotliDecompress.prototype._transform = function (chunk, encoding, callback) { - callback(undefined, this[kHandle].decodeSync(chunk, encoding, false)); -}; -BrotliDecompress.prototype._flush = function (callback) { - callback(undefined, this[kHandle].decodeSync("", undefined, true)); -}; +// -// TODO: **use a native binding from Bun for this!!** -// This is a very slow module! -// It should really be fixed. It will show up in benchmarking. It also loads -// slowly. We need to fix it! -const assert = require("node:assert"); -const BufferModule = require("node:buffer"); -const StreamModule = require("node:stream"); -const Util = require("node:util"); -const { isAnyArrayBuffer, isArrayBufferView } = require("node:util/types"); +function Deflate(opts) { + if (!(this instanceof Deflate)) return new Deflate(opts); + Zlib.$call(this, DEFLATE, opts); +} +Deflate.prototype = Object.create(Zlib.prototype); -var __getOwnPropNames = Object.getOwnPropertyNames; -var __commonJS = (cb, mod: typeof module | undefined = undefined) => - function __require() { - return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; - }; +// -// node_modules/pako/lib/zlib/zstream.js -var require_zstream = __commonJS({ - "node_modules/pako/lib/zlib/zstream.js"(exports, module2) { - "use strict"; - function ZStream() { - this.input = null; - this.next_in = 0; - this.avail_in = 0; - this.total_in = 0; - this.output = null; - this.next_out = 0; - this.avail_out = 0; - this.total_out = 0; - this.msg = ""; - this.state = null; - this.data_type = 2; - this.adler = 0; - } - module2.exports = ZStream; - }, -}); +function Inflate(opts) { + if (!(this instanceof Inflate)) return new Inflate(opts); + Zlib.$call(this, INFLATE, opts); +} +Inflate.prototype = Object.create(Zlib.prototype); -// node_modules/pako/lib/utils/common.js -var require_common = __commonJS({ - "node_modules/pako/lib/utils/common.js"(exports) { - "use strict"; - var TYPED_OK = - typeof Uint8Array !== "undefined" && typeof Uint16Array !== "undefined" && typeof Int32Array !== "undefined"; - function _has(obj, key) { - return Object.prototype.hasOwnProperty.$call(obj, key); - } - exports.assign = function (obj) { - var sources = Array.prototype.slice.$call(arguments, 1); - while (sources.length) { - var source = sources.shift(); - if (!source) { - continue; - } - if (typeof source !== "object") { - throw new TypeError(source + "must be non-object"); - } - for (var p in source) { - if (_has(source, p)) { - obj[p] = source[p]; - } - } - } - return obj; - }; - exports.shrinkBuf = function (buf, size) { - if (buf.length === size) { - return buf; - } - if (buf.subarray) { - return buf.subarray(0, size); - } - buf.length = size; - return buf; - }; - var fnTyped = { - arraySet: function (dest, src, src_offs, len, dest_offs) { - if (src.subarray && dest.subarray) { - dest.set(src.subarray(src_offs, src_offs + len), dest_offs); - return; - } - for (var i = 0; i < len; i++) { - dest[dest_offs + i] = src[src_offs + i]; - } - }, - flattenChunks: function (chunks) { - var i, l, len, pos, chunk, result; - len = 0; - for (i = 0, l = chunks.length; i < l; i++) { - len += chunks[i].length; - } - result = new Uint8Array(len); - pos = 0; - for (i = 0, l = chunks.length; i < l; i++) { - chunk = chunks[i]; - result.set(chunk, pos); - pos += chunk.length; - } - return result; - }, - }; - var fnUntyped = { - arraySet: function (dest, src, src_offs, len, dest_offs) { - for (var i = 0; i < len; i++) { - dest[dest_offs + i] = src[src_offs + i]; - } - }, - flattenChunks: function (chunks) { - return [].concat.$apply([], chunks); - }, - }; - exports.setTyped = function (on) { - if (on) { - exports.Buf8 = Uint8Array; - exports.Buf16 = Uint16Array; - exports.Buf32 = Int32Array; - exports.assign(exports, fnTyped); - } else { - exports.Buf8 = Array; - exports.Buf16 = Array; - exports.Buf32 = Array; - exports.assign(exports, fnUntyped); - } - }; - exports.setTyped(TYPED_OK); - }, -}); +// -// node_modules/pako/lib/zlib/trees.js -var require_trees = __commonJS({ - "node_modules/pako/lib/zlib/trees.js"(exports) { - "use strict"; - var utils = require_common(); - var Z_FIXED = 4; - var Z_BINARY = 0; - var Z_TEXT = 1; - var Z_UNKNOWN = 2; - function zero(buf) { - var len = buf.length; - while (--len >= 0) { - buf[len] = 0; - } - } - var STORED_BLOCK = 0; - var STATIC_TREES = 1; - var DYN_TREES = 2; - var MIN_MATCH = 3; - var MAX_MATCH = 258; - var LENGTH_CODES = 29; - var LITERALS = 256; - var L_CODES = LITERALS + 1 + LENGTH_CODES; - var D_CODES = 30; - var BL_CODES = 19; - var HEAP_SIZE = 2 * L_CODES + 1; - var MAX_BITS = 15; - var Buf_size = 16; - var MAX_BL_BITS = 7; - var END_BLOCK = 256; - var REP_3_6 = 16; - var REPZ_3_10 = 17; - var REPZ_11_138 = 18; - var extra_lbits = [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0]; - var extra_dbits = [ - 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, - ]; - var extra_blbits = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 7]; - var bl_order = [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]; - var DIST_CODE_LEN = 512; - var static_ltree = new Array((L_CODES + 2) * 2); - zero(static_ltree); - var static_dtree = new Array(D_CODES * 2); - zero(static_dtree); - var _dist_code = new Array(DIST_CODE_LEN); - zero(_dist_code); - var _length_code = new Array(MAX_MATCH - MIN_MATCH + 1); - zero(_length_code); - var base_length = new Array(LENGTH_CODES); - zero(base_length); - var base_dist = new Array(D_CODES); - zero(base_dist); - function StaticTreeDesc(static_tree, extra_bits, extra_base, elems, max_length) { - this.static_tree = static_tree; - this.extra_bits = extra_bits; - this.extra_base = extra_base; - this.elems = elems; - this.max_length = max_length; - this.has_stree = static_tree && static_tree.length; - } - var static_l_desc; - var static_d_desc; - var static_bl_desc; - function TreeDesc(dyn_tree, stat_desc) { - this.dyn_tree = dyn_tree; - this.max_code = 0; - this.stat_desc = stat_desc; - } - function d_code(dist) { - return dist < 256 ? _dist_code[dist] : _dist_code[256 + (dist >>> 7)]; - } - function put_short(s, w) { - s.pending_buf[s.pending++] = w & 255; - s.pending_buf[s.pending++] = (w >>> 8) & 255; - } - function send_bits(s, value, length) { - if (s.bi_valid > Buf_size - length) { - s.bi_buf |= (value << s.bi_valid) & 65535; - put_short(s, s.bi_buf); - s.bi_buf = value >> (Buf_size - s.bi_valid); - s.bi_valid += length - Buf_size; - } else { - s.bi_buf |= (value << s.bi_valid) & 65535; - s.bi_valid += length; - } - } - function send_code(s, c, tree) { - send_bits(s, tree[c * 2], tree[c * 2 + 1]); - } - function bi_reverse(code, len) { - var res = 0; - do { - res |= code & 1; - code >>>= 1; - res <<= 1; - } while (--len > 0); - return res >>> 1; - } - function bi_flush(s) { - if (s.bi_valid === 16) { - put_short(s, s.bi_buf); - s.bi_buf = 0; - s.bi_valid = 0; - } else if (s.bi_valid >= 8) { - s.pending_buf[s.pending++] = s.bi_buf & 255; - s.bi_buf >>= 8; - s.bi_valid -= 8; - } - } - function gen_bitlen(s, desc) { - var tree = desc.dyn_tree; - var max_code = desc.max_code; - var stree = desc.stat_desc.static_tree; - var has_stree = desc.stat_desc.has_stree; - var extra = desc.stat_desc.extra_bits; - var base = desc.stat_desc.extra_base; - var max_length = desc.stat_desc.max_length; - var h; - var n, m; - var bits; - var xbits; - var f; - var overflow = 0; - for (bits = 0; bits <= MAX_BITS; bits++) { - s.bl_count[bits] = 0; - } - tree[s.heap[s.heap_max] * 2 + 1] = 0; - for (h = s.heap_max + 1; h < HEAP_SIZE; h++) { - n = s.heap[h]; - bits = tree[tree[n * 2 + 1] * 2 + 1] + 1; - if (bits > max_length) { - bits = max_length; - overflow++; - } - tree[n * 2 + 1] = bits; - if (n > max_code) { - continue; - } - s.bl_count[bits]++; - xbits = 0; - if (n >= base) { - xbits = extra[n - base]; - } - f = tree[n * 2]; - s.opt_len += f * (bits + xbits); - if (has_stree) { - s.static_len += f * (stree[n * 2 + 1] + xbits); - } - } - if (overflow === 0) { - return; - } - do { - bits = max_length - 1; - while (s.bl_count[bits] === 0) { - bits--; - } - s.bl_count[bits]--; - s.bl_count[bits + 1] += 2; - s.bl_count[max_length]--; - overflow -= 2; - } while (overflow > 0); - for (bits = max_length; bits !== 0; bits--) { - n = s.bl_count[bits]; - while (n !== 0) { - m = s.heap[--h]; - if (m > max_code) { - continue; - } - if (tree[m * 2 + 1] !== bits) { - s.opt_len += (bits - tree[m * 2 + 1]) * tree[m * 2]; - tree[m * 2 + 1] = bits; - } - n--; - } - } - } - function gen_codes(tree, max_code, bl_count) { - var next_code = new Array(MAX_BITS + 1); - var code = 0; - var bits; - var n; - for (bits = 1; bits <= MAX_BITS; bits++) { - next_code[bits] = code = (code + bl_count[bits - 1]) << 1; - } - for (n = 0; n <= max_code; n++) { - var len = tree[n * 2 + 1]; - if (len === 0) { - continue; - } - tree[n * 2] = bi_reverse(next_code[len]++, len); - } - } - function tr_static_init() { - var n; - var bits; - var length; - var code; - var dist; - var bl_count = new Array(MAX_BITS + 1); - length = 0; - for (code = 0; code < LENGTH_CODES - 1; code++) { - base_length[code] = length; - for (n = 0; n < 1 << extra_lbits[code]; n++) { - _length_code[length++] = code; - } - } - _length_code[length - 1] = code; - dist = 0; - for (code = 0; code < 16; code++) { - base_dist[code] = dist; - for (n = 0; n < 1 << extra_dbits[code]; n++) { - _dist_code[dist++] = code; - } - } - dist >>= 7; - for (; code < D_CODES; code++) { - base_dist[code] = dist << 7; - for (n = 0; n < 1 << (extra_dbits[code] - 7); n++) { - _dist_code[256 + dist++] = code; - } - } - for (bits = 0; bits <= MAX_BITS; bits++) { - bl_count[bits] = 0; - } - n = 0; - while (n <= 143) { - static_ltree[n * 2 + 1] = 8; - n++; - bl_count[8]++; - } - while (n <= 255) { - static_ltree[n * 2 + 1] = 9; - n++; - bl_count[9]++; - } - while (n <= 279) { - static_ltree[n * 2 + 1] = 7; - n++; - bl_count[7]++; - } - while (n <= 287) { - static_ltree[n * 2 + 1] = 8; - n++; - bl_count[8]++; - } - gen_codes(static_ltree, L_CODES + 1, bl_count); - for (n = 0; n < D_CODES; n++) { - static_dtree[n * 2 + 1] = 5; - static_dtree[n * 2] = bi_reverse(n, 5); - } - static_l_desc = new StaticTreeDesc(static_ltree, extra_lbits, LITERALS + 1, L_CODES, MAX_BITS); - static_d_desc = new StaticTreeDesc(static_dtree, extra_dbits, 0, D_CODES, MAX_BITS); - static_bl_desc = new StaticTreeDesc(new Array(0), extra_blbits, 0, BL_CODES, MAX_BL_BITS); - } - function init_block(s) { - var n; - for (n = 0; n < L_CODES; n++) { - s.dyn_ltree[n * 2] = 0; - } - for (n = 0; n < D_CODES; n++) { - s.dyn_dtree[n * 2] = 0; - } - for (n = 0; n < BL_CODES; n++) { - s.bl_tree[n * 2] = 0; - } - s.dyn_ltree[END_BLOCK * 2] = 1; - s.opt_len = s.static_len = 0; - s.last_lit = s.matches = 0; - } - function bi_windup(s) { - if (s.bi_valid > 8) { - put_short(s, s.bi_buf); - } else if (s.bi_valid > 0) { - s.pending_buf[s.pending++] = s.bi_buf; - } - s.bi_buf = 0; - s.bi_valid = 0; - } - function copy_block(s, buf, len, header) { - bi_windup(s); - if (header) { - put_short(s, len); - put_short(s, ~len); - } - utils.arraySet(s.pending_buf, s.window, buf, len, s.pending); - s.pending += len; - } - function smaller(tree, n, m, depth) { - var _n2 = n * 2; - var _m2 = m * 2; - return tree[_n2] < tree[_m2] || (tree[_n2] === tree[_m2] && depth[n] <= depth[m]); - } - function pqdownheap(s, tree, k) { - var v = s.heap[k]; - var j = k << 1; - while (j <= s.heap_len) { - if (j < s.heap_len && smaller(tree, s.heap[j + 1], s.heap[j], s.depth)) { - j++; - } - if (smaller(tree, v, s.heap[j], s.depth)) { - break; - } - s.heap[k] = s.heap[j]; - k = j; - j <<= 1; - } - s.heap[k] = v; - } - function compress_block(s, ltree, dtree) { - var dist; - var lc; - var lx = 0; - var code; - var extra; - if (s.last_lit !== 0) { - do { - dist = (s.pending_buf[s.d_buf + lx * 2] << 8) | s.pending_buf[s.d_buf + lx * 2 + 1]; - lc = s.pending_buf[s.l_buf + lx]; - lx++; - if (dist === 0) { - send_code(s, lc, ltree); - } else { - code = _length_code[lc]; - send_code(s, code + LITERALS + 1, ltree); - extra = extra_lbits[code]; - if (extra !== 0) { - lc -= base_length[code]; - send_bits(s, lc, extra); - } - dist--; - code = d_code(dist); - send_code(s, code, dtree); - extra = extra_dbits[code]; - if (extra !== 0) { - dist -= base_dist[code]; - send_bits(s, dist, extra); - } - } - } while (lx < s.last_lit); - } - send_code(s, END_BLOCK, ltree); - } - function build_tree(s, desc) { - var tree = desc.dyn_tree; - var stree = desc.stat_desc.static_tree; - var has_stree = desc.stat_desc.has_stree; - var elems = desc.stat_desc.elems; - var n, m; - var max_code = -1; - var node; - s.heap_len = 0; - s.heap_max = HEAP_SIZE; - for (n = 0; n < elems; n++) { - if (tree[n * 2] !== 0) { - s.heap[++s.heap_len] = max_code = n; - s.depth[n] = 0; - } else { - tree[n * 2 + 1] = 0; - } - } - while (s.heap_len < 2) { - node = s.heap[++s.heap_len] = max_code < 2 ? ++max_code : 0; - tree[node * 2] = 1; - s.depth[node] = 0; - s.opt_len--; - if (has_stree) { - s.static_len -= stree[node * 2 + 1]; - } - } - desc.max_code = max_code; - for (n = s.heap_len >> 1; n >= 1; n--) { - pqdownheap(s, tree, n); - } - node = elems; - do { - n = s.heap[1]; - s.heap[1] = s.heap[s.heap_len--]; - pqdownheap(s, tree, 1); - m = s.heap[1]; - s.heap[--s.heap_max] = n; - s.heap[--s.heap_max] = m; - tree[node * 2] = tree[n * 2] + tree[m * 2]; - s.depth[node] = (s.depth[n] >= s.depth[m] ? s.depth[n] : s.depth[m]) + 1; - tree[n * 2 + 1] = tree[m * 2 + 1] = node; - s.heap[1] = node++; - pqdownheap(s, tree, 1); - } while (s.heap_len >= 2); - s.heap[--s.heap_max] = s.heap[1]; - gen_bitlen(s, desc); - gen_codes(tree, max_code, s.bl_count); - } - function scan_tree(s, tree, max_code) { - var n; - var prevlen = -1; - var curlen; - var nextlen = tree[0 * 2 + 1]; - var count = 0; - var max_count = 7; - var min_count = 4; - if (nextlen === 0) { - max_count = 138; - min_count = 3; - } - tree[(max_code + 1) * 2 + 1] = 65535; - for (n = 0; n <= max_code; n++) { - curlen = nextlen; - nextlen = tree[(n + 1) * 2 + 1]; - if (++count < max_count && curlen === nextlen) { - continue; - } else if (count < min_count) { - s.bl_tree[curlen * 2] += count; - } else if (curlen !== 0) { - if (curlen !== prevlen) { - s.bl_tree[curlen * 2]++; - } - s.bl_tree[REP_3_6 * 2]++; - } else if (count <= 10) { - s.bl_tree[REPZ_3_10 * 2]++; - } else { - s.bl_tree[REPZ_11_138 * 2]++; - } - count = 0; - prevlen = curlen; - if (nextlen === 0) { - max_count = 138; - min_count = 3; - } else if (curlen === nextlen) { - max_count = 6; - min_count = 3; - } else { - max_count = 7; - min_count = 4; - } - } - } - function send_tree(s, tree, max_code) { - var n; - var prevlen = -1; - var curlen; - var nextlen = tree[0 * 2 + 1]; - var count = 0; - var max_count = 7; - var min_count = 4; - if (nextlen === 0) { - max_count = 138; - min_count = 3; - } - for (n = 0; n <= max_code; n++) { - curlen = nextlen; - nextlen = tree[(n + 1) * 2 + 1]; - if (++count < max_count && curlen === nextlen) { - continue; - } else if (count < min_count) { - do { - send_code(s, curlen, s.bl_tree); - } while (--count !== 0); - } else if (curlen !== 0) { - if (curlen !== prevlen) { - send_code(s, curlen, s.bl_tree); - count--; - } - send_code(s, REP_3_6, s.bl_tree); - send_bits(s, count - 3, 2); - } else if (count <= 10) { - send_code(s, REPZ_3_10, s.bl_tree); - send_bits(s, count - 3, 3); - } else { - send_code(s, REPZ_11_138, s.bl_tree); - send_bits(s, count - 11, 7); - } - count = 0; - prevlen = curlen; - if (nextlen === 0) { - max_count = 138; - min_count = 3; - } else if (curlen === nextlen) { - max_count = 6; - min_count = 3; - } else { - max_count = 7; - min_count = 4; - } - } - } - function build_bl_tree(s) { - var max_blindex; - scan_tree(s, s.dyn_ltree, s.l_desc.max_code); - scan_tree(s, s.dyn_dtree, s.d_desc.max_code); - build_tree(s, s.bl_desc); - for (max_blindex = BL_CODES - 1; max_blindex >= 3; max_blindex--) { - if (s.bl_tree[bl_order[max_blindex] * 2 + 1] !== 0) { - break; - } - } - s.opt_len += 3 * (max_blindex + 1) + 5 + 5 + 4; - return max_blindex; - } - function send_all_trees(s, lcodes, dcodes, blcodes) { - var rank; - send_bits(s, lcodes - 257, 5); - send_bits(s, dcodes - 1, 5); - send_bits(s, blcodes - 4, 4); - for (rank = 0; rank < blcodes; rank++) { - send_bits(s, s.bl_tree[bl_order[rank] * 2 + 1], 3); - } - send_tree(s, s.dyn_ltree, lcodes - 1); - send_tree(s, s.dyn_dtree, dcodes - 1); - } - function detect_data_type(s) { - var black_mask = 4093624447; - var n; - for (n = 0; n <= 31; n++, black_mask >>>= 1) { - if (black_mask & 1 && s.dyn_ltree[n * 2] !== 0) { - return Z_BINARY; - } - } - if (s.dyn_ltree[9 * 2] !== 0 || s.dyn_ltree[10 * 2] !== 0 || s.dyn_ltree[13 * 2] !== 0) { - return Z_TEXT; - } - for (n = 32; n < LITERALS; n++) { - if (s.dyn_ltree[n * 2] !== 0) { - return Z_TEXT; - } - } - return Z_BINARY; - } - var static_init_done = false; - function _tr_init(s) { - if (!static_init_done) { - tr_static_init(); - static_init_done = true; - } - s.l_desc = new TreeDesc(s.dyn_ltree, static_l_desc); - s.d_desc = new TreeDesc(s.dyn_dtree, static_d_desc); - s.bl_desc = new TreeDesc(s.bl_tree, static_bl_desc); - s.bi_buf = 0; - s.bi_valid = 0; - init_block(s); - } - function _tr_stored_block(s, buf, stored_len, last) { - send_bits(s, (STORED_BLOCK << 1) + (last ? 1 : 0), 3); - copy_block(s, buf, stored_len, true); - } - function _tr_align(s) { - send_bits(s, STATIC_TREES << 1, 3); - send_code(s, END_BLOCK, static_ltree); - bi_flush(s); - } - function _tr_flush_block(s, buf, stored_len, last) { - var opt_lenb, static_lenb; - var max_blindex = 0; - if (s.level > 0) { - if (s.strm.data_type === Z_UNKNOWN) { - s.strm.data_type = detect_data_type(s); - } - build_tree(s, s.l_desc); - build_tree(s, s.d_desc); - max_blindex = build_bl_tree(s); - opt_lenb = (s.opt_len + 3 + 7) >>> 3; - static_lenb = (s.static_len + 3 + 7) >>> 3; - if (static_lenb <= opt_lenb) { - opt_lenb = static_lenb; - } - } else { - opt_lenb = static_lenb = stored_len + 5; - } - if (stored_len + 4 <= opt_lenb && buf !== -1) { - _tr_stored_block(s, buf, stored_len, last); - } else if (s.strategy === Z_FIXED || static_lenb === opt_lenb) { - send_bits(s, (STATIC_TREES << 1) + (last ? 1 : 0), 3); - compress_block(s, static_ltree, static_dtree); - } else { - send_bits(s, (DYN_TREES << 1) + (last ? 1 : 0), 3); - send_all_trees(s, s.l_desc.max_code + 1, s.d_desc.max_code + 1, max_blindex + 1); - compress_block(s, s.dyn_ltree, s.dyn_dtree); - } - init_block(s); - if (last) { - bi_windup(s); - } - } - function _tr_tally(s, dist, lc) { - s.pending_buf[s.d_buf + s.last_lit * 2] = (dist >>> 8) & 255; - s.pending_buf[s.d_buf + s.last_lit * 2 + 1] = dist & 255; - s.pending_buf[s.l_buf + s.last_lit] = lc & 255; - s.last_lit++; - if (dist === 0) { - s.dyn_ltree[lc * 2]++; - } else { - s.matches++; - dist--; - s.dyn_ltree[(_length_code[lc] + LITERALS + 1) * 2]++; - s.dyn_dtree[d_code(dist) * 2]++; - } - return s.last_lit === s.lit_bufsize - 1; - } - exports._tr_init = _tr_init; - exports._tr_stored_block = _tr_stored_block; - exports._tr_flush_block = _tr_flush_block; - exports._tr_tally = _tr_tally; - exports._tr_align = _tr_align; - }, -}); +function DeflateRaw(opts) { + if (!(this instanceof DeflateRaw)) return new DeflateRaw(opts); + Zlib.$call(this, DEFLATERAW, opts); +} +DeflateRaw.prototype = Object.create(Zlib.prototype); -// node_modules/pako/lib/zlib/adler32.js -var require_adler32 = __commonJS({ - "node_modules/pako/lib/zlib/adler32.js"(exports, module2) { - "use strict"; - function adler32(adler, buf, len, pos) { - var s1 = (adler & 65535) | 0, - s2 = ((adler >>> 16) & 65535) | 0, - n = 0; - while (len !== 0) { - n = len > 2e3 ? 2e3 : len; - len -= n; - do { - s1 = (s1 + buf[pos++]) | 0; - s2 = (s2 + s1) | 0; - } while (--n); - s1 %= 65521; - s2 %= 65521; - } - return s1 | (s2 << 16) | 0; - } - module2.exports = adler32; - }, -}); +// -// node_modules/pako/lib/zlib/crc32.js -var require_crc32 = __commonJS({ - "node_modules/pako/lib/zlib/crc32.js"(exports, module2) { - "use strict"; - function makeTable() { - var c, - table = []; - for (var n = 0; n < 256; n++) { - c = n; - for (var k = 0; k < 8; k++) { - c = c & 1 ? 3988292384 ^ (c >>> 1) : c >>> 1; - } - table[n] = c; - } - return table; - } - var crcTable = makeTable(); - function crc32(crc, buf, len, pos) { - var t = crcTable, - end = pos + len; - crc ^= -1; - for (var i = pos; i < end; i++) { - crc = (crc >>> 8) ^ t[(crc ^ buf[i]) & 255]; - } - return crc ^ -1; - } - module2.exports = crc32; - }, -}); +function InflateRaw(opts) { + if (!(this instanceof InflateRaw)) return new InflateRaw(opts); + Zlib.$call(this, INFLATERAW, opts); +} +InflateRaw.prototype = Object.create(Zlib.prototype); -// node_modules/pako/lib/zlib/messages.js -var require_messages = __commonJS({ - "node_modules/pako/lib/zlib/messages.js"(exports, module2) { - "use strict"; - module2.exports = { - 2: "need dictionary", - 1: "stream end", - 0: "", - "-1": "file error", - "-2": "stream error", - "-3": "data error", - "-4": "insufficient memory", - "-5": "buffer error", - "-6": "incompatible version", - }; - }, -}); +// -// node_modules/pako/lib/zlib/deflate.js -var require_deflate = __commonJS({ - "node_modules/pako/lib/zlib/deflate.js"(exports) { - "use strict"; - var utils = require_common(); - var trees = require_trees(); - var adler32 = require_adler32(); - var crc32 = require_crc32(); - var msg = require_messages(); - var Z_NO_FLUSH = 0; - var Z_PARTIAL_FLUSH = 1; - var Z_FULL_FLUSH = 3; - var Z_FINISH = 4; - var Z_BLOCK = 5; - var Z_OK = 0; - var Z_STREAM_END = 1; - var Z_STREAM_ERROR = -2; - var Z_DATA_ERROR = -3; - var Z_BUF_ERROR = -5; - var Z_DEFAULT_COMPRESSION = -1; - var Z_FILTERED = 1; - var Z_HUFFMAN_ONLY = 2; - var Z_RLE = 3; - var Z_FIXED = 4; - var Z_DEFAULT_STRATEGY = 0; - var Z_UNKNOWN = 2; - var Z_DEFLATED = 8; - var MAX_MEM_LEVEL = 9; - var MAX_WBITS = 15; - var DEF_MEM_LEVEL = 8; - var LENGTH_CODES = 29; - var LITERALS = 256; - var L_CODES = LITERALS + 1 + LENGTH_CODES; - var D_CODES = 30; - var BL_CODES = 19; - var HEAP_SIZE = 2 * L_CODES + 1; - var MAX_BITS = 15; - var MIN_MATCH = 3; - var MAX_MATCH = 258; - var MIN_LOOKAHEAD = MAX_MATCH + MIN_MATCH + 1; - var PRESET_DICT = 32; - var INIT_STATE = 42; - var EXTRA_STATE = 69; - var NAME_STATE = 73; - var COMMENT_STATE = 91; - var HCRC_STATE = 103; - var BUSY_STATE = 113; - var FINISH_STATE = 666; - var BS_NEED_MORE = 1; - var BS_BLOCK_DONE = 2; - var BS_FINISH_STARTED = 3; - var BS_FINISH_DONE = 4; - var OS_CODE = 3; - function err(strm, errorCode) { - strm.msg = msg[errorCode]; - return errorCode; - } - function rank(f) { - return (f << 1) - (f > 4 ? 9 : 0); - } - function zero(buf) { - var len = buf.length; - while (--len >= 0) { - buf[len] = 0; - } - } - function flush_pending(strm) { - var s = strm.state; - var len = s.pending; - if (len > strm.avail_out) { - len = strm.avail_out; - } - if (len === 0) { - return; - } - utils.arraySet(strm.output, s.pending_buf, s.pending_out, len, strm.next_out); - strm.next_out += len; - s.pending_out += len; - strm.total_out += len; - strm.avail_out -= len; - s.pending -= len; - if (s.pending === 0) { - s.pending_out = 0; - } - } - function flush_block_only(s, last) { - trees._tr_flush_block(s, s.block_start >= 0 ? s.block_start : -1, s.strstart - s.block_start, last); - s.block_start = s.strstart; - flush_pending(s.strm); - } - function put_byte(s, b) { - s.pending_buf[s.pending++] = b; - } - function putShortMSB(s, b) { - s.pending_buf[s.pending++] = (b >>> 8) & 255; - s.pending_buf[s.pending++] = b & 255; - } - function read_buf(strm, buf, start, size) { - var len = strm.avail_in; - if (len > size) { - len = size; - } - if (len === 0) { - return 0; - } - strm.avail_in -= len; - utils.arraySet(buf, strm.input, strm.next_in, len, start); - if (strm.state.wrap === 1) { - strm.adler = adler32(strm.adler, buf, len, start); - } else if (strm.state.wrap === 2) { - strm.adler = crc32(strm.adler, buf, len, start); - } - strm.next_in += len; - strm.total_in += len; - return len; - } - function longest_match(s, cur_match) { - var chain_length = s.max_chain_length; - var scan = s.strstart; - var match; - var len; - var best_len = s.prev_length; - var nice_match = s.nice_match; - var limit = s.strstart > s.w_size - MIN_LOOKAHEAD ? s.strstart - (s.w_size - MIN_LOOKAHEAD) : 0; - var _win = s.window; - var wmask = s.w_mask; - var prev = s.prev; - var strend = s.strstart + MAX_MATCH; - var scan_end1 = _win[scan + best_len - 1]; - var scan_end = _win[scan + best_len]; - if (s.prev_length >= s.good_match) { - chain_length >>= 2; - } - if (nice_match > s.lookahead) { - nice_match = s.lookahead; - } - do { - match = cur_match; - if ( - _win[match + best_len] !== scan_end || - _win[match + best_len - 1] !== scan_end1 || - _win[match] !== _win[scan] || - _win[++match] !== _win[scan + 1] - ) { - continue; - } - scan += 2; - match++; - do {} while ( - _win[++scan] === _win[++match] && - _win[++scan] === _win[++match] && - _win[++scan] === _win[++match] && - _win[++scan] === _win[++match] && - _win[++scan] === _win[++match] && - _win[++scan] === _win[++match] && - _win[++scan] === _win[++match] && - _win[++scan] === _win[++match] && - scan < strend - ); - len = MAX_MATCH - (strend - scan); - scan = strend - MAX_MATCH; - if (len > best_len) { - s.match_start = cur_match; - best_len = len; - if (len >= nice_match) { - break; - } - scan_end1 = _win[scan + best_len - 1]; - scan_end = _win[scan + best_len]; - } - } while ((cur_match = prev[cur_match & wmask]) > limit && --chain_length !== 0); - if (best_len <= s.lookahead) { - return best_len; - } - return s.lookahead; - } - function fill_window(s) { - var _w_size = s.w_size; - var p, n, m, more, str; - do { - more = s.window_size - s.lookahead - s.strstart; - if (s.strstart >= _w_size + (_w_size - MIN_LOOKAHEAD)) { - utils.arraySet(s.window, s.window, _w_size, _w_size, 0); - s.match_start -= _w_size; - s.strstart -= _w_size; - s.block_start -= _w_size; - n = s.hash_size; - p = n; - do { - m = s.head[--p]; - s.head[p] = m >= _w_size ? m - _w_size : 0; - } while (--n); - n = _w_size; - p = n; - do { - m = s.prev[--p]; - s.prev[p] = m >= _w_size ? m - _w_size : 0; - } while (--n); - more += _w_size; - } - if (s.strm.avail_in === 0) { - break; - } - n = read_buf(s.strm, s.window, s.strstart + s.lookahead, more); - s.lookahead += n; - if (s.lookahead + s.insert >= MIN_MATCH) { - str = s.strstart - s.insert; - s.ins_h = s.window[str]; - s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[str + 1]) & s.hash_mask; - while (s.insert) { - s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[str + MIN_MATCH - 1]) & s.hash_mask; - s.prev[str & s.w_mask] = s.head[s.ins_h]; - s.head[s.ins_h] = str; - str++; - s.insert--; - if (s.lookahead + s.insert < MIN_MATCH) { - break; - } - } - } - } while (s.lookahead < MIN_LOOKAHEAD && s.strm.avail_in !== 0); - } - function deflate_stored(s, flush) { - var max_block_size = 65535; - if (max_block_size > s.pending_buf_size - 5) { - max_block_size = s.pending_buf_size - 5; - } - for (;;) { - if (s.lookahead <= 1) { - fill_window(s); - if (s.lookahead === 0 && flush === Z_NO_FLUSH) { - return BS_NEED_MORE; - } - if (s.lookahead === 0) { - break; - } - } - s.strstart += s.lookahead; - s.lookahead = 0; - var max_start = s.block_start + max_block_size; - if (s.strstart === 0 || s.strstart >= max_start) { - s.lookahead = s.strstart - max_start; - s.strstart = max_start; - flush_block_only(s, false); - if (s.strm.avail_out === 0) { - return BS_NEED_MORE; - } - } - if (s.strstart - s.block_start >= s.w_size - MIN_LOOKAHEAD) { - flush_block_only(s, false); - if (s.strm.avail_out === 0) { - return BS_NEED_MORE; - } - } - } - s.insert = 0; - if (flush === Z_FINISH) { - flush_block_only(s, true); - if (s.strm.avail_out === 0) { - return BS_FINISH_STARTED; - } - return BS_FINISH_DONE; - } - if (s.strstart > s.block_start) { - flush_block_only(s, false); - if (s.strm.avail_out === 0) { - return BS_NEED_MORE; - } - } - return BS_NEED_MORE; - } - function deflate_fast(s, flush) { - var hash_head; - var bflush; - for (;;) { - if (s.lookahead < MIN_LOOKAHEAD) { - fill_window(s); - if (s.lookahead < MIN_LOOKAHEAD && flush === Z_NO_FLUSH) { - return BS_NEED_MORE; - } - if (s.lookahead === 0) { - break; - } - } - hash_head = 0; - if (s.lookahead >= MIN_MATCH) { - s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask; - hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h]; - s.head[s.ins_h] = s.strstart; - } - if (hash_head !== 0 && s.strstart - hash_head <= s.w_size - MIN_LOOKAHEAD) { - s.match_length = longest_match(s, hash_head); - } - if (s.match_length >= MIN_MATCH) { - bflush = trees._tr_tally(s, s.strstart - s.match_start, s.match_length - MIN_MATCH); - s.lookahead -= s.match_length; - if (s.match_length <= s.max_lazy_match && s.lookahead >= MIN_MATCH) { - s.match_length--; - do { - s.strstart++; - s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask; - hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h]; - s.head[s.ins_h] = s.strstart; - } while (--s.match_length !== 0); - s.strstart++; - } else { - s.strstart += s.match_length; - s.match_length = 0; - s.ins_h = s.window[s.strstart]; - s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + 1]) & s.hash_mask; - } - } else { - bflush = trees._tr_tally(s, 0, s.window[s.strstart]); - s.lookahead--; - s.strstart++; - } - if (bflush) { - flush_block_only(s, false); - if (s.strm.avail_out === 0) { - return BS_NEED_MORE; - } - } - } - s.insert = s.strstart < MIN_MATCH - 1 ? s.strstart : MIN_MATCH - 1; - if (flush === Z_FINISH) { - flush_block_only(s, true); - if (s.strm.avail_out === 0) { - return BS_FINISH_STARTED; - } - return BS_FINISH_DONE; - } - if (s.last_lit) { - flush_block_only(s, false); - if (s.strm.avail_out === 0) { - return BS_NEED_MORE; - } - } - return BS_BLOCK_DONE; - } - function deflate_slow(s, flush) { - var hash_head; - var bflush; - var max_insert; - for (;;) { - if (s.lookahead < MIN_LOOKAHEAD) { - fill_window(s); - if (s.lookahead < MIN_LOOKAHEAD && flush === Z_NO_FLUSH) { - return BS_NEED_MORE; - } - if (s.lookahead === 0) { - break; - } - } - hash_head = 0; - if (s.lookahead >= MIN_MATCH) { - s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask; - hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h]; - s.head[s.ins_h] = s.strstart; - } - s.prev_length = s.match_length; - s.prev_match = s.match_start; - s.match_length = MIN_MATCH - 1; - if (hash_head !== 0 && s.prev_length < s.max_lazy_match && s.strstart - hash_head <= s.w_size - MIN_LOOKAHEAD) { - s.match_length = longest_match(s, hash_head); - if ( - s.match_length <= 5 && - (s.strategy === Z_FILTERED || (s.match_length === MIN_MATCH && s.strstart - s.match_start > 4096)) - ) { - s.match_length = MIN_MATCH - 1; - } - } - if (s.prev_length >= MIN_MATCH && s.match_length <= s.prev_length) { - max_insert = s.strstart + s.lookahead - MIN_MATCH; - bflush = trees._tr_tally(s, s.strstart - 1 - s.prev_match, s.prev_length - MIN_MATCH); - s.lookahead -= s.prev_length - 1; - s.prev_length -= 2; - do { - if (++s.strstart <= max_insert) { - s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask; - hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h]; - s.head[s.ins_h] = s.strstart; - } - } while (--s.prev_length !== 0); - s.match_available = 0; - s.match_length = MIN_MATCH - 1; - s.strstart++; - if (bflush) { - flush_block_only(s, false); - if (s.strm.avail_out === 0) { - return BS_NEED_MORE; - } - } - } else if (s.match_available) { - bflush = trees._tr_tally(s, 0, s.window[s.strstart - 1]); - if (bflush) { - flush_block_only(s, false); - } - s.strstart++; - s.lookahead--; - if (s.strm.avail_out === 0) { - return BS_NEED_MORE; - } - } else { - s.match_available = 1; - s.strstart++; - s.lookahead--; - } - } - if (s.match_available) { - bflush = trees._tr_tally(s, 0, s.window[s.strstart - 1]); - s.match_available = 0; - } - s.insert = s.strstart < MIN_MATCH - 1 ? s.strstart : MIN_MATCH - 1; - if (flush === Z_FINISH) { - flush_block_only(s, true); - if (s.strm.avail_out === 0) { - return BS_FINISH_STARTED; - } - return BS_FINISH_DONE; - } - if (s.last_lit) { - flush_block_only(s, false); - if (s.strm.avail_out === 0) { - return BS_NEED_MORE; - } - } - return BS_BLOCK_DONE; - } - function deflate_rle(s, flush) { - var bflush; - var prev; - var scan, strend; - var _win = s.window; - for (;;) { - if (s.lookahead <= MAX_MATCH) { - fill_window(s); - if (s.lookahead <= MAX_MATCH && flush === Z_NO_FLUSH) { - return BS_NEED_MORE; - } - if (s.lookahead === 0) { - break; - } - } - s.match_length = 0; - if (s.lookahead >= MIN_MATCH && s.strstart > 0) { - scan = s.strstart - 1; - prev = _win[scan]; - if (prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan]) { - strend = s.strstart + MAX_MATCH; - do {} while ( - prev === _win[++scan] && - prev === _win[++scan] && - prev === _win[++scan] && - prev === _win[++scan] && - prev === _win[++scan] && - prev === _win[++scan] && - prev === _win[++scan] && - prev === _win[++scan] && - scan < strend - ); - s.match_length = MAX_MATCH - (strend - scan); - if (s.match_length > s.lookahead) { - s.match_length = s.lookahead; - } - } - } - if (s.match_length >= MIN_MATCH) { - bflush = trees._tr_tally(s, 1, s.match_length - MIN_MATCH); - s.lookahead -= s.match_length; - s.strstart += s.match_length; - s.match_length = 0; - } else { - bflush = trees._tr_tally(s, 0, s.window[s.strstart]); - s.lookahead--; - s.strstart++; - } - if (bflush) { - flush_block_only(s, false); - if (s.strm.avail_out === 0) { - return BS_NEED_MORE; - } - } - } - s.insert = 0; - if (flush === Z_FINISH) { - flush_block_only(s, true); - if (s.strm.avail_out === 0) { - return BS_FINISH_STARTED; - } - return BS_FINISH_DONE; - } - if (s.last_lit) { - flush_block_only(s, false); - if (s.strm.avail_out === 0) { - return BS_NEED_MORE; - } - } - return BS_BLOCK_DONE; - } - function deflate_huff(s, flush) { - var bflush; - for (;;) { - if (s.lookahead === 0) { - fill_window(s); - if (s.lookahead === 0) { - if (flush === Z_NO_FLUSH) { - return BS_NEED_MORE; - } - break; - } - } - s.match_length = 0; - bflush = trees._tr_tally(s, 0, s.window[s.strstart]); - s.lookahead--; - s.strstart++; - if (bflush) { - flush_block_only(s, false); - if (s.strm.avail_out === 0) { - return BS_NEED_MORE; - } - } - } - s.insert = 0; - if (flush === Z_FINISH) { - flush_block_only(s, true); - if (s.strm.avail_out === 0) { - return BS_FINISH_STARTED; - } - return BS_FINISH_DONE; - } - if (s.last_lit) { - flush_block_only(s, false); - if (s.strm.avail_out === 0) { - return BS_NEED_MORE; - } - } - return BS_BLOCK_DONE; - } - function Config(good_length, max_lazy, nice_length, max_chain, func) { - this.good_length = good_length; - this.max_lazy = max_lazy; - this.nice_length = nice_length; - this.max_chain = max_chain; - this.func = func; - } - var configuration_table; - configuration_table = [ - new Config(0, 0, 0, 0, deflate_stored), - new Config(4, 4, 8, 4, deflate_fast), - new Config(4, 5, 16, 8, deflate_fast), - new Config(4, 6, 32, 32, deflate_fast), - new Config(4, 4, 16, 16, deflate_slow), - new Config(8, 16, 32, 32, deflate_slow), - new Config(8, 16, 128, 128, deflate_slow), - new Config(8, 32, 128, 256, deflate_slow), - new Config(32, 128, 258, 1024, deflate_slow), - new Config(32, 258, 258, 4096, deflate_slow), - ]; - function lm_init(s) { - s.window_size = 2 * s.w_size; - zero(s.head); - s.max_lazy_match = configuration_table[s.level].max_lazy; - s.good_match = configuration_table[s.level].good_length; - s.nice_match = configuration_table[s.level].nice_length; - s.max_chain_length = configuration_table[s.level].max_chain; - s.strstart = 0; - s.block_start = 0; - s.lookahead = 0; - s.insert = 0; - s.match_length = s.prev_length = MIN_MATCH - 1; - s.match_available = 0; - s.ins_h = 0; - } - function DeflateState() { - this.strm = null; - this.status = 0; - this.pending_buf = null; - this.pending_buf_size = 0; - this.pending_out = 0; - this.pending = 0; - this.wrap = 0; - this.gzhead = null; - this.gzindex = 0; - this.method = Z_DEFLATED; - this.last_flush = -1; - this.w_size = 0; - this.w_bits = 0; - this.w_mask = 0; - this.window = null; - this.window_size = 0; - this.prev = null; - this.head = null; - this.ins_h = 0; - this.hash_size = 0; - this.hash_bits = 0; - this.hash_mask = 0; - this.hash_shift = 0; - this.block_start = 0; - this.match_length = 0; - this.prev_match = 0; - this.match_available = 0; - this.strstart = 0; - this.match_start = 0; - this.lookahead = 0; - this.prev_length = 0; - this.max_chain_length = 0; - this.max_lazy_match = 0; - this.level = 0; - this.strategy = 0; - this.good_match = 0; - this.nice_match = 0; - this.dyn_ltree = new utils.Buf16(HEAP_SIZE * 2); - this.dyn_dtree = new utils.Buf16((2 * D_CODES + 1) * 2); - this.bl_tree = new utils.Buf16((2 * BL_CODES + 1) * 2); - zero(this.dyn_ltree); - zero(this.dyn_dtree); - zero(this.bl_tree); - this.l_desc = null; - this.d_desc = null; - this.bl_desc = null; - this.bl_count = new utils.Buf16(MAX_BITS + 1); - this.heap = new utils.Buf16(2 * L_CODES + 1); - zero(this.heap); - this.heap_len = 0; - this.heap_max = 0; - this.depth = new utils.Buf16(2 * L_CODES + 1); - zero(this.depth); - this.l_buf = 0; - this.lit_bufsize = 0; - this.last_lit = 0; - this.d_buf = 0; - this.opt_len = 0; - this.static_len = 0; - this.matches = 0; - this.insert = 0; - this.bi_buf = 0; - this.bi_valid = 0; - } - function deflateResetKeep(strm) { - var s; - if (!strm || !strm.state) { - return err(strm, Z_STREAM_ERROR); - } - strm.total_in = strm.total_out = 0; - strm.data_type = Z_UNKNOWN; - s = strm.state; - s.pending = 0; - s.pending_out = 0; - if (s.wrap < 0) { - s.wrap = -s.wrap; - } - s.status = s.wrap ? INIT_STATE : BUSY_STATE; - strm.adler = s.wrap === 2 ? 0 : 1; - s.last_flush = Z_NO_FLUSH; - trees._tr_init(s); - return Z_OK; - } - function deflateReset(strm) { - var ret = deflateResetKeep(strm); - if (ret === Z_OK) { - lm_init(strm.state); - } - return ret; - } - function deflateSetHeader(strm, head) { - if (!strm || !strm.state) { - return Z_STREAM_ERROR; - } - if (strm.state.wrap !== 2) { - return Z_STREAM_ERROR; - } - strm.state.gzhead = head; - return Z_OK; - } - function deflateInit2(strm, level, method, windowBits, memLevel, strategy) { - if (!strm) { - return Z_STREAM_ERROR; - } - var wrap = 1; - if (level === Z_DEFAULT_COMPRESSION) { - level = 6; - } - if (windowBits < 0) { - wrap = 0; - windowBits = -windowBits; - } else if (windowBits > 15) { - wrap = 2; - windowBits -= 16; - } - if ( - memLevel < 1 || - memLevel > MAX_MEM_LEVEL || - method !== Z_DEFLATED || - windowBits < 8 || - windowBits > 15 || - level < 0 || - level > 9 || - strategy < 0 || - strategy > Z_FIXED - ) { - return err(strm, Z_STREAM_ERROR); - } - if (windowBits === 8) { - windowBits = 9; - } - var s = new DeflateState(); - strm.state = s; - s.strm = strm; - s.wrap = wrap; - s.gzhead = null; - s.w_bits = windowBits; - s.w_size = 1 << s.w_bits; - s.w_mask = s.w_size - 1; - s.hash_bits = memLevel + 7; - s.hash_size = 1 << s.hash_bits; - s.hash_mask = s.hash_size - 1; - s.hash_shift = ~~((s.hash_bits + MIN_MATCH - 1) / MIN_MATCH); - s.window = new utils.Buf8(s.w_size * 2); - s.head = new utils.Buf16(s.hash_size); - s.prev = new utils.Buf16(s.w_size); - s.lit_bufsize = 1 << (memLevel + 6); - s.pending_buf_size = s.lit_bufsize * 4; - s.pending_buf = new utils.Buf8(s.pending_buf_size); - s.d_buf = 1 * s.lit_bufsize; - s.l_buf = (1 + 2) * s.lit_bufsize; - s.level = level; - s.strategy = strategy; - s.method = method; - return deflateReset(strm); - } - function deflateInit(strm, level) { - return deflateInit2(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY); - } - function deflate(strm, flush) { - var old_flush, s; - var beg, val; - if (!strm || !strm.state || flush > Z_BLOCK || flush < 0) { - return strm ? err(strm, Z_STREAM_ERROR) : Z_STREAM_ERROR; - } - s = strm.state; - if (!strm.output || (!strm.input && strm.avail_in !== 0) || (s.status === FINISH_STATE && flush !== Z_FINISH)) { - return err(strm, strm.avail_out === 0 ? Z_BUF_ERROR : Z_STREAM_ERROR); - } - s.strm = strm; - old_flush = s.last_flush; - s.last_flush = flush; - if (s.status === INIT_STATE) { - if (s.wrap === 2) { - strm.adler = 0; - put_byte(s, 31); - put_byte(s, 139); - put_byte(s, 8); - if (!s.gzhead) { - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, s.level === 9 ? 2 : s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ? 4 : 0); - put_byte(s, OS_CODE); - s.status = BUSY_STATE; - } else { - put_byte( - s, - (s.gzhead.text ? 1 : 0) + - (s.gzhead.hcrc ? 2 : 0) + - (!s.gzhead.extra ? 0 : 4) + - (!s.gzhead.name ? 0 : 8) + - (!s.gzhead.comment ? 0 : 16), - ); - put_byte(s, s.gzhead.time & 255); - put_byte(s, (s.gzhead.time >> 8) & 255); - put_byte(s, (s.gzhead.time >> 16) & 255); - put_byte(s, (s.gzhead.time >> 24) & 255); - put_byte(s, s.level === 9 ? 2 : s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ? 4 : 0); - put_byte(s, s.gzhead.os & 255); - if (s.gzhead.extra && s.gzhead.extra.length) { - put_byte(s, s.gzhead.extra.length & 255); - put_byte(s, (s.gzhead.extra.length >> 8) & 255); - } - if (s.gzhead.hcrc) { - strm.adler = crc32(strm.adler, s.pending_buf, s.pending, 0); - } - s.gzindex = 0; - s.status = EXTRA_STATE; - } - } else { - var header = (Z_DEFLATED + ((s.w_bits - 8) << 4)) << 8; - var level_flags = -1; - if (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2) { - level_flags = 0; - } else if (s.level < 6) { - level_flags = 1; - } else if (s.level === 6) { - level_flags = 2; - } else { - level_flags = 3; - } - header |= level_flags << 6; - if (s.strstart !== 0) { - header |= PRESET_DICT; - } - header += 31 - (header % 31); - s.status = BUSY_STATE; - putShortMSB(s, header); - if (s.strstart !== 0) { - putShortMSB(s, strm.adler >>> 16); - putShortMSB(s, strm.adler & 65535); - } - strm.adler = 1; - } - } - if (s.status === EXTRA_STATE) { - if (s.gzhead.extra) { - beg = s.pending; - while (s.gzindex < (s.gzhead.extra.length & 65535)) { - if (s.pending === s.pending_buf_size) { - if (s.gzhead.hcrc && s.pending > beg) { - strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg); - } - flush_pending(strm); - beg = s.pending; - if (s.pending === s.pending_buf_size) { - break; - } - } - put_byte(s, s.gzhead.extra[s.gzindex] & 255); - s.gzindex++; - } - if (s.gzhead.hcrc && s.pending > beg) { - strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg); - } - if (s.gzindex === s.gzhead.extra.length) { - s.gzindex = 0; - s.status = NAME_STATE; - } - } else { - s.status = NAME_STATE; - } - } - if (s.status === NAME_STATE) { - if (s.gzhead.name) { - beg = s.pending; - do { - if (s.pending === s.pending_buf_size) { - if (s.gzhead.hcrc && s.pending > beg) { - strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg); - } - flush_pending(strm); - beg = s.pending; - if (s.pending === s.pending_buf_size) { - val = 1; - break; - } - } - if (s.gzindex < s.gzhead.name.length) { - val = s.gzhead.name.charCodeAt(s.gzindex++) & 255; - } else { - val = 0; - } - put_byte(s, val); - } while (val !== 0); - if (s.gzhead.hcrc && s.pending > beg) { - strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg); - } - if (val === 0) { - s.gzindex = 0; - s.status = COMMENT_STATE; - } - } else { - s.status = COMMENT_STATE; - } - } - if (s.status === COMMENT_STATE) { - if (s.gzhead.comment) { - beg = s.pending; - do { - if (s.pending === s.pending_buf_size) { - if (s.gzhead.hcrc && s.pending > beg) { - strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg); - } - flush_pending(strm); - beg = s.pending; - if (s.pending === s.pending_buf_size) { - val = 1; - break; - } - } - if (s.gzindex < s.gzhead.comment.length) { - val = s.gzhead.comment.charCodeAt(s.gzindex++) & 255; - } else { - val = 0; - } - put_byte(s, val); - } while (val !== 0); - if (s.gzhead.hcrc && s.pending > beg) { - strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg); - } - if (val === 0) { - s.status = HCRC_STATE; - } - } else { - s.status = HCRC_STATE; - } - } - if (s.status === HCRC_STATE) { - if (s.gzhead.hcrc) { - if (s.pending + 2 > s.pending_buf_size) { - flush_pending(strm); - } - if (s.pending + 2 <= s.pending_buf_size) { - put_byte(s, strm.adler & 255); - put_byte(s, (strm.adler >> 8) & 255); - strm.adler = 0; - s.status = BUSY_STATE; - } - } else { - s.status = BUSY_STATE; - } - } - if (s.pending !== 0) { - flush_pending(strm); - if (strm.avail_out === 0) { - s.last_flush = -1; - return Z_OK; - } - } else if (strm.avail_in === 0 && rank(flush) <= rank(old_flush) && flush !== Z_FINISH) { - return err(strm, Z_BUF_ERROR); - } - if (s.status === FINISH_STATE && strm.avail_in !== 0) { - return err(strm, Z_BUF_ERROR); - } - if (strm.avail_in !== 0 || s.lookahead !== 0 || (flush !== Z_NO_FLUSH && s.status !== FINISH_STATE)) { - var bstate = - s.strategy === Z_HUFFMAN_ONLY - ? deflate_huff(s, flush) - : s.strategy === Z_RLE - ? deflate_rle(s, flush) - : configuration_table[s.level].func(s, flush); - if (bstate === BS_FINISH_STARTED || bstate === BS_FINISH_DONE) { - s.status = FINISH_STATE; - } - if (bstate === BS_NEED_MORE || bstate === BS_FINISH_STARTED) { - if (strm.avail_out === 0) { - s.last_flush = -1; - } - return Z_OK; - } - if (bstate === BS_BLOCK_DONE) { - if (flush === Z_PARTIAL_FLUSH) { - trees._tr_align(s); - } else if (flush !== Z_BLOCK) { - trees._tr_stored_block(s, 0, 0, false); - if (flush === Z_FULL_FLUSH) { - zero(s.head); - if (s.lookahead === 0) { - s.strstart = 0; - s.block_start = 0; - s.insert = 0; - } - } - } - flush_pending(strm); - if (strm.avail_out === 0) { - s.last_flush = -1; - return Z_OK; - } - } - } - if (flush !== Z_FINISH) { - return Z_OK; - } - if (s.wrap <= 0) { - return Z_STREAM_END; - } - if (s.wrap === 2) { - put_byte(s, strm.adler & 255); - put_byte(s, (strm.adler >> 8) & 255); - put_byte(s, (strm.adler >> 16) & 255); - put_byte(s, (strm.adler >> 24) & 255); - put_byte(s, strm.total_in & 255); - put_byte(s, (strm.total_in >> 8) & 255); - put_byte(s, (strm.total_in >> 16) & 255); - put_byte(s, (strm.total_in >> 24) & 255); - } else { - putShortMSB(s, strm.adler >>> 16); - putShortMSB(s, strm.adler & 65535); - } - flush_pending(strm); - if (s.wrap > 0) { - s.wrap = -s.wrap; - } - return s.pending !== 0 ? Z_OK : Z_STREAM_END; - } - function deflateEnd(strm) { - var status; - if (!strm || !strm.state) { - return Z_STREAM_ERROR; - } - status = strm.state.status; - if ( - status !== INIT_STATE && - status !== EXTRA_STATE && - status !== NAME_STATE && - status !== COMMENT_STATE && - status !== HCRC_STATE && - status !== BUSY_STATE && - status !== FINISH_STATE - ) { - return err(strm, Z_STREAM_ERROR); - } - strm.state = null; - return status === BUSY_STATE ? err(strm, Z_DATA_ERROR) : Z_OK; - } - function deflateSetDictionary(strm, dictionary) { - var dictLength = dictionary.length; - var s; - var str, n; - var wrap; - var avail; - var next; - var input; - var tmpDict; - if (!strm || !strm.state) { - return Z_STREAM_ERROR; - } - s = strm.state; - wrap = s.wrap; - if (wrap === 2 || (wrap === 1 && s.status !== INIT_STATE) || s.lookahead) { - return Z_STREAM_ERROR; - } - if (wrap === 1) { - strm.adler = adler32(strm.adler, dictionary, dictLength, 0); - } - s.wrap = 0; - if (dictLength >= s.w_size) { - if (wrap === 0) { - zero(s.head); - s.strstart = 0; - s.block_start = 0; - s.insert = 0; - } - tmpDict = new utils.Buf8(s.w_size); - utils.arraySet(tmpDict, dictionary, dictLength - s.w_size, s.w_size, 0); - dictionary = tmpDict; - dictLength = s.w_size; - } - avail = strm.avail_in; - next = strm.next_in; - input = strm.input; - strm.avail_in = dictLength; - strm.next_in = 0; - strm.input = dictionary; - fill_window(s); - while (s.lookahead >= MIN_MATCH) { - str = s.strstart; - n = s.lookahead - (MIN_MATCH - 1); - do { - s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[str + MIN_MATCH - 1]) & s.hash_mask; - s.prev[str & s.w_mask] = s.head[s.ins_h]; - s.head[s.ins_h] = str; - str++; - } while (--n); - s.strstart = str; - s.lookahead = MIN_MATCH - 1; - fill_window(s); - } - s.strstart += s.lookahead; - s.block_start = s.strstart; - s.insert = s.lookahead; - s.lookahead = 0; - s.match_length = s.prev_length = MIN_MATCH - 1; - s.match_available = 0; - strm.next_in = next; - strm.input = input; - strm.avail_in = avail; - s.wrap = wrap; - return Z_OK; - } - exports.deflateInit = deflateInit; - exports.deflateInit2 = deflateInit2; - exports.deflateReset = deflateReset; - exports.deflateResetKeep = deflateResetKeep; - exports.deflateSetHeader = deflateSetHeader; - exports.deflate = deflate; - exports.deflateEnd = deflateEnd; - exports.deflateSetDictionary = deflateSetDictionary; - exports.deflateInfo = "pako deflate (from Nodeca project)"; - }, -}); +function Gzip(opts) { + if (!(this instanceof Gzip)) return new Gzip(opts); + Zlib.$call(this, GZIP, opts); +} +Gzip.prototype = Object.create(Zlib.prototype); -// node_modules/pako/lib/zlib/inffast.js -var require_inffast = __commonJS({ - "node_modules/pako/lib/zlib/inffast.js"(exports, module2) { - "use strict"; - var BAD = 30; - var TYPE = 12; - module2.exports = function inflate_fast(strm, start) { - var state; - var _in; - var last; - var _out; - var beg; - var end; - var dmax; - var wsize; - var whave; - var wnext; - var s_window; - var hold; - var bits; - var lcode; - var dcode; - var lmask; - var dmask; - var here; - var op; - var len; - var dist; - var from; - var from_source; - var input, output; - state = strm.state; - _in = strm.next_in; - input = strm.input; - last = _in + (strm.avail_in - 5); - _out = strm.next_out; - output = strm.output; - beg = _out - (start - strm.avail_out); - end = _out + (strm.avail_out - 257); - dmax = state.dmax; - wsize = state.wsize; - whave = state.whave; - wnext = state.wnext; - s_window = state.window; - hold = state.hold; - bits = state.bits; - lcode = state.lencode; - dcode = state.distcode; - lmask = (1 << state.lenbits) - 1; - dmask = (1 << state.distbits) - 1; - top: do { - if (bits < 15) { - hold += input[_in++] << bits; - bits += 8; - hold += input[_in++] << bits; - bits += 8; - } - here = lcode[hold & lmask]; - dolen: for (;;) { - op = here >>> 24; - hold >>>= op; - bits -= op; - op = (here >>> 16) & 255; - if (op === 0) { - output[_out++] = here & 65535; - } else if (op & 16) { - len = here & 65535; - op &= 15; - if (op) { - if (bits < op) { - hold += input[_in++] << bits; - bits += 8; - } - len += hold & ((1 << op) - 1); - hold >>>= op; - bits -= op; - } - if (bits < 15) { - hold += input[_in++] << bits; - bits += 8; - hold += input[_in++] << bits; - bits += 8; - } - here = dcode[hold & dmask]; - dodist: for (;;) { - op = here >>> 24; - hold >>>= op; - bits -= op; - op = (here >>> 16) & 255; - if (op & 16) { - dist = here & 65535; - op &= 15; - if (bits < op) { - hold += input[_in++] << bits; - bits += 8; - if (bits < op) { - hold += input[_in++] << bits; - bits += 8; - } - } - dist += hold & ((1 << op) - 1); - if (dist > dmax) { - strm.msg = "invalid distance too far back"; - state.mode = BAD; - break top; - } - hold >>>= op; - bits -= op; - op = _out - beg; - if (dist > op) { - op = dist - op; - if (op > whave) { - if (state.sane) { - strm.msg = "invalid distance too far back"; - state.mode = BAD; - break top; - } - } - from = 0; - from_source = s_window; - if (wnext === 0) { - from += wsize - op; - if (op < len) { - len -= op; - do { - output[_out++] = s_window[from++]; - } while (--op); - from = _out - dist; - from_source = output; - } - } else if (wnext < op) { - from += wsize + wnext - op; - op -= wnext; - if (op < len) { - len -= op; - do { - output[_out++] = s_window[from++]; - } while (--op); - from = 0; - if (wnext < len) { - op = wnext; - len -= op; - do { - output[_out++] = s_window[from++]; - } while (--op); - from = _out - dist; - from_source = output; - } - } - } else { - from += wnext - op; - if (op < len) { - len -= op; - do { - output[_out++] = s_window[from++]; - } while (--op); - from = _out - dist; - from_source = output; - } - } - while (len > 2) { - output[_out++] = from_source[from++]; - output[_out++] = from_source[from++]; - output[_out++] = from_source[from++]; - len -= 3; - } - if (len) { - output[_out++] = from_source[from++]; - if (len > 1) { - output[_out++] = from_source[from++]; - } - } - } else { - from = _out - dist; - do { - output[_out++] = output[from++]; - output[_out++] = output[from++]; - output[_out++] = output[from++]; - len -= 3; - } while (len > 2); - if (len) { - output[_out++] = output[from++]; - if (len > 1) { - output[_out++] = output[from++]; - } - } - } - } else if ((op & 64) === 0) { - here = dcode[(here & 65535) + (hold & ((1 << op) - 1))]; - continue dodist; - } else { - strm.msg = "invalid distance code"; - state.mode = BAD; - break top; - } - break; - } - } else if ((op & 64) === 0) { - here = lcode[(here & 65535) + (hold & ((1 << op) - 1))]; - continue dolen; - } else if (op & 32) { - state.mode = TYPE; - break top; - } else { - strm.msg = "invalid literal/length code"; - state.mode = BAD; - break top; - } - break; - } - } while (_in < last && _out < end); - len = bits >> 3; - _in -= len; - bits -= len << 3; - hold &= (1 << bits) - 1; - strm.next_in = _in; - strm.next_out = _out; - strm.avail_in = _in < last ? 5 + (last - _in) : 5 - (_in - last); - strm.avail_out = _out < end ? 257 + (end - _out) : 257 - (_out - end); - state.hold = hold; - state.bits = bits; - return; - }; - }, -}); +// -// node_modules/pako/lib/zlib/inftrees.js -var require_inftrees = __commonJS({ - "node_modules/pako/lib/zlib/inftrees.js"(exports, module2) { - "use strict"; - var utils = require_common(); - var MAXBITS = 15; - var ENOUGH_LENS = 852; - var ENOUGH_DISTS = 592; - var CODES = 0; - var LENS = 1; - var DISTS = 2; - var lbase = [ - 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, - 0, 0, - ]; - var lext = [ - 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, - 16, 72, 78, - ]; - var dbase = [ - 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, - 8193, 12289, 16385, 24577, 0, 0, - ]; - var dext = [ - 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, - 29, 29, 64, 64, - ]; - module2.exports = function inflate_table(type, lens, lens_index, codes, table, table_index, work, opts) { - var bits = opts.bits; - var len = 0; - var sym = 0; - var min = 0, - max = 0; - var root = 0; - var curr = 0; - var drop = 0; - var left = 0; - var used = 0; - var huff = 0; - var incr; - var fill; - var low; - var mask; - var next; - var base: number[] | null = null; - var base_index = 0; - var end; - var count = new utils.Buf16(MAXBITS + 1); - var offs = new utils.Buf16(MAXBITS + 1); - var extra: number[] | null = null; - var extra_index = 0; - var here_bits, here_op, here_val; - for (len = 0; len <= MAXBITS; len++) { - count[len] = 0; - } - for (sym = 0; sym < codes; sym++) { - count[lens[lens_index + sym]]++; - } - root = bits; - for (max = MAXBITS; max >= 1; max--) { - if (count[max] !== 0) { - break; - } - } - if (root > max) { - root = max; - } - if (max === 0) { - table[table_index++] = (1 << 24) | (64 << 16) | 0; - table[table_index++] = (1 << 24) | (64 << 16) | 0; - opts.bits = 1; - return 0; - } - for (min = 1; min < max; min++) { - if (count[min] !== 0) { - break; - } - } - if (root < min) { - root = min; - } - left = 1; - for (len = 1; len <= MAXBITS; len++) { - left <<= 1; - left -= count[len]; - if (left < 0) { - return -1; - } - } - if (left > 0 && (type === CODES || max !== 1)) { - return -1; - } - offs[1] = 0; - for (len = 1; len < MAXBITS; len++) { - offs[len + 1] = offs[len] + count[len]; - } - for (sym = 0; sym < codes; sym++) { - if (lens[lens_index + sym] !== 0) { - work[offs[lens[lens_index + sym]]++] = sym; - } - } - if (type === CODES) { - base = extra = work; - end = 19; - } else if (type === LENS) { - base = lbase; - base_index -= 257; - extra = lext; - extra_index -= 257; - end = 256; - } else { - base = dbase; - extra = dext; - end = -1; - } - huff = 0; - sym = 0; - len = min; - next = table_index; - curr = root; - drop = 0; - low = -1; - used = 1 << root; - mask = used - 1; - if ((type === LENS && used > ENOUGH_LENS) || (type === DISTS && used > ENOUGH_DISTS)) { - return 1; - } - for (;;) { - here_bits = len - drop; - if (work[sym] < end) { - here_op = 0; - here_val = work[sym]; - } else if (work[sym] > end) { - here_op = extra![extra_index + work[sym]]; - here_val = base![base_index + work[sym]]; - } else { - here_op = 32 + 64; - here_val = 0; - } - incr = 1 << (len - drop); - fill = 1 << curr; - min = fill; - do { - fill -= incr; - table[next + (huff >> drop) + fill] = (here_bits << 24) | (here_op << 16) | here_val | 0; - } while (fill !== 0); - incr = 1 << (len - 1); - while (huff & incr) { - incr >>= 1; - } - if (incr !== 0) { - huff &= incr - 1; - huff += incr; - } else { - huff = 0; - } - sym++; - if (--count[len] === 0) { - if (len === max) { - break; - } - len = lens[lens_index + work[sym]]; - } - if (len > root && (huff & mask) !== low) { - if (drop === 0) { - drop = root; - } - next += min; - curr = len - drop; - left = 1 << curr; - while (curr + drop < max) { - left -= count[curr + drop]; - if (left <= 0) { - break; - } - curr++; - left <<= 1; - } - used += 1 << curr; - if ((type === LENS && used > ENOUGH_LENS) || (type === DISTS && used > ENOUGH_DISTS)) { - return 1; - } - low = huff & mask; - table[low] = (root << 24) | (curr << 16) | (next - table_index) | 0; - } - } - if (huff !== 0) { - table[next + huff] = ((len - drop) << 24) | (64 << 16) | 0; - } - opts.bits = root; - return 0; - }; - }, -}); +function Gunzip(opts) { + if (!(this instanceof Gunzip)) return new Gunzip(opts); + Zlib.$call(this, GUNZIP, opts); +} +Gunzip.prototype = Object.create(Zlib.prototype); -// node_modules/pako/lib/zlib/inflate.js -var require_inflate = __commonJS({ - "node_modules/pako/lib/zlib/inflate.js"(exports) { - "use strict"; - var utils = require_common(); - var adler32 = require_adler32(); - var crc32 = require_crc32(); - var inflate_fast = require_inffast(); - var inflate_table = require_inftrees(); - var CODES = 0; - var LENS = 1; - var DISTS = 2; - var Z_FINISH = 4; - var Z_BLOCK = 5; - var Z_TREES = 6; - var Z_OK = 0; - var Z_STREAM_END = 1; - var Z_NEED_DICT = 2; - var Z_STREAM_ERROR = -2; - var Z_DATA_ERROR = -3; - var Z_MEM_ERROR = -4; - var Z_BUF_ERROR = -5; - var Z_DEFLATED = 8; - var HEAD = 1; - var FLAGS = 2; - var TIME = 3; - var OS = 4; - var EXLEN = 5; - var EXTRA = 6; - var NAME = 7; - var COMMENT = 8; - var HCRC = 9; - var DICTID = 10; - var DICT = 11; - var TYPE = 12; - var TYPEDO = 13; - var STORED = 14; - var COPY_ = 15; - var COPY = 16; - var TABLE = 17; - var LENLENS = 18; - var CODELENS = 19; - var LEN_ = 20; - var LEN = 21; - var LENEXT = 22; - var DIST = 23; - var DISTEXT = 24; - var MATCH = 25; - var LIT = 26; - var CHECK = 27; - var LENGTH = 28; - var DONE = 29; - var BAD = 30; - var MEM = 31; - var SYNC = 32; - var ENOUGH_LENS = 852; - var ENOUGH_DISTS = 592; - var MAX_WBITS = 15; - var DEF_WBITS = MAX_WBITS; - function zswap32(q) { - return ((q >>> 24) & 255) + ((q >>> 8) & 65280) + ((q & 65280) << 8) + ((q & 255) << 24); - } - function InflateState() { - this.mode = 0; - this.last = false; - this.wrap = 0; - this.havedict = false; - this.flags = 0; - this.dmax = 0; - this.check = 0; - this.total = 0; - this.head = null; - this.wbits = 0; - this.wsize = 0; - this.whave = 0; - this.wnext = 0; - this.window = null; - this.hold = 0; - this.bits = 0; - this.length = 0; - this.offset = 0; - this.extra = 0; - this.lencode = null; - this.distcode = null; - this.lenbits = 0; - this.distbits = 0; - this.ncode = 0; - this.nlen = 0; - this.ndist = 0; - this.have = 0; - this.next = null; - this.lens = new utils.Buf16(320); - this.work = new utils.Buf16(288); - this.lendyn = null; - this.distdyn = null; - this.sane = 0; - this.back = 0; - this.was = 0; - } - function inflateResetKeep(strm) { - var state; - if (!strm || !strm.state) { - return Z_STREAM_ERROR; - } - state = strm.state; - strm.total_in = strm.total_out = state.total = 0; - strm.msg = ""; - if (state.wrap) { - strm.adler = state.wrap & 1; - } - state.mode = HEAD; - state.last = 0; - state.havedict = 0; - state.dmax = 32768; - state.head = null; - state.hold = 0; - state.bits = 0; - state.lencode = state.lendyn = new utils.Buf32(ENOUGH_LENS); - state.distcode = state.distdyn = new utils.Buf32(ENOUGH_DISTS); - state.sane = 1; - state.back = -1; - return Z_OK; - } - function inflateReset(strm) { - var state; - if (!strm || !strm.state) { - return Z_STREAM_ERROR; - } - state = strm.state; - state.wsize = 0; - state.whave = 0; - state.wnext = 0; - return inflateResetKeep(strm); - } - function inflateReset2(strm, windowBits) { - var wrap; - var state; - if (!strm || !strm.state) { - return Z_STREAM_ERROR; - } - state = strm.state; - if (windowBits < 0) { - wrap = 0; - windowBits = -windowBits; - } else { - wrap = (windowBits >> 4) + 1; - if (windowBits < 48) { - windowBits &= 15; - } - } - if (windowBits && (windowBits < 8 || windowBits > 15)) { - return Z_STREAM_ERROR; - } - if (state.window !== null && state.wbits !== windowBits) { - state.window = null; - } - state.wrap = wrap; - state.wbits = windowBits; - return inflateReset(strm); - } - function inflateInit2(strm, windowBits) { - var ret; - var state; - if (!strm) { - return Z_STREAM_ERROR; - } - state = new InflateState(); - strm.state = state; - state.window = null; - ret = inflateReset2(strm, windowBits); - if (ret !== Z_OK) { - strm.state = null; - } - return ret; - } - function inflateInit(strm) { - return inflateInit2(strm, DEF_WBITS); - } - var virgin = true; - var lenfix; - var distfix; - function fixedtables(state) { - if (virgin) { - var sym; - lenfix = new utils.Buf32(512); - distfix = new utils.Buf32(32); - sym = 0; - while (sym < 144) { - state.lens[sym++] = 8; - } - while (sym < 256) { - state.lens[sym++] = 9; - } - while (sym < 280) { - state.lens[sym++] = 7; - } - while (sym < 288) { - state.lens[sym++] = 8; - } - inflate_table(LENS, state.lens, 0, 288, lenfix, 0, state.work, { - bits: 9, - }); - sym = 0; - while (sym < 32) { - state.lens[sym++] = 5; - } - inflate_table(DISTS, state.lens, 0, 32, distfix, 0, state.work, { - bits: 5, - }); - virgin = false; - } - state.lencode = lenfix; - state.lenbits = 9; - state.distcode = distfix; - state.distbits = 5; - } - function updatewindow(strm, src, end, copy) { - var dist; - var state = strm.state; - if (state.window === null) { - state.wsize = 1 << state.wbits; - state.wnext = 0; - state.whave = 0; - state.window = new utils.Buf8(state.wsize); - } - if (copy >= state.wsize) { - utils.arraySet(state.window, src, end - state.wsize, state.wsize, 0); - state.wnext = 0; - state.whave = state.wsize; - } else { - dist = state.wsize - state.wnext; - if (dist > copy) { - dist = copy; - } - utils.arraySet(state.window, src, end - copy, dist, state.wnext); - copy -= dist; - if (copy) { - utils.arraySet(state.window, src, end - copy, copy, 0); - state.wnext = copy; - state.whave = state.wsize; - } else { - state.wnext += dist; - if (state.wnext === state.wsize) { - state.wnext = 0; - } - if (state.whave < state.wsize) { - state.whave += dist; - } - } - } - return 0; - } - function inflate(strm, flush) { - var state; - var input, output; - var next; - var put; - var have, left; - var hold; - var bits; - var _in, _out; - var copy; - var from; - var from_source; - var here = 0; - var here_bits, here_op, here_val; - var last_bits, last_op, last_val; - var len; - var ret; - var hbuf = new utils.Buf8(4); - var opts; - var n; - var order = [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]; - if (!strm || !strm.state || !strm.output || (!strm.input && strm.avail_in !== 0)) { - return Z_STREAM_ERROR; - } - state = strm.state; - if (state.mode === TYPE) { - state.mode = TYPEDO; - } - put = strm.next_out; - output = strm.output; - left = strm.avail_out; - next = strm.next_in; - input = strm.input; - have = strm.avail_in; - hold = state.hold; - bits = state.bits; - _in = have; - _out = left; - ret = Z_OK; - inf_leave: for (;;) { - switch (state.mode) { - case HEAD: - if (state.wrap === 0) { - state.mode = TYPEDO; - break; - } - while (bits < 16) { - if (have === 0) { - break inf_leave; - } - have--; - hold += input[next++] << bits; - bits += 8; - } - if (state.wrap & 2 && hold === 35615) { - state.check = 0; - hbuf[0] = hold & 255; - hbuf[1] = (hold >>> 8) & 255; - state.check = crc32(state.check, hbuf, 2, 0); - hold = 0; - bits = 0; - state.mode = FLAGS; - break; - } - state.flags = 0; - if (state.head) { - state.head.done = false; - } - if (!(state.wrap & 1) || (((hold & 255) << 8) + (hold >> 8)) % 31) { - strm.msg = "incorrect header check"; - state.mode = BAD; - break; - } - if ((hold & 15) !== Z_DEFLATED) { - strm.msg = "unknown compression method"; - state.mode = BAD; - break; - } - hold >>>= 4; - bits -= 4; - len = (hold & 15) + 8; - if (state.wbits === 0) { - state.wbits = len; - } else if (len > state.wbits) { - strm.msg = "invalid window size"; - state.mode = BAD; - break; - } - state.dmax = 1 << len; - strm.adler = state.check = 1; - state.mode = hold & 512 ? DICTID : TYPE; - hold = 0; - bits = 0; - break; - case FLAGS: - while (bits < 16) { - if (have === 0) { - break inf_leave; - } - have--; - hold += input[next++] << bits; - bits += 8; - } - state.flags = hold; - if ((state.flags & 255) !== Z_DEFLATED) { - strm.msg = "unknown compression method"; - state.mode = BAD; - break; - } - if (state.flags & 57344) { - strm.msg = "unknown header flags set"; - state.mode = BAD; - break; - } - if (state.head) { - state.head.text = (hold >> 8) & 1; - } - if (state.flags & 512) { - hbuf[0] = hold & 255; - hbuf[1] = (hold >>> 8) & 255; - state.check = crc32(state.check, hbuf, 2, 0); - } - hold = 0; - bits = 0; - state.mode = TIME; - case TIME: - while (bits < 32) { - if (have === 0) { - break inf_leave; - } - have--; - hold += input[next++] << bits; - bits += 8; - } - if (state.head) { - state.head.time = hold; - } - if (state.flags & 512) { - hbuf[0] = hold & 255; - hbuf[1] = (hold >>> 8) & 255; - hbuf[2] = (hold >>> 16) & 255; - hbuf[3] = (hold >>> 24) & 255; - state.check = crc32(state.check, hbuf, 4, 0); - } - hold = 0; - bits = 0; - state.mode = OS; - case OS: - while (bits < 16) { - if (have === 0) { - break inf_leave; - } - have--; - hold += input[next++] << bits; - bits += 8; - } - if (state.head) { - state.head.xflags = hold & 255; - state.head.os = hold >> 8; - } - if (state.flags & 512) { - hbuf[0] = hold & 255; - hbuf[1] = (hold >>> 8) & 255; - state.check = crc32(state.check, hbuf, 2, 0); - } - hold = 0; - bits = 0; - state.mode = EXLEN; - case EXLEN: - if (state.flags & 1024) { - while (bits < 16) { - if (have === 0) { - break inf_leave; - } - have--; - hold += input[next++] << bits; - bits += 8; - } - state.length = hold; - if (state.head) { - state.head.extra_len = hold; - } - if (state.flags & 512) { - hbuf[0] = hold & 255; - hbuf[1] = (hold >>> 8) & 255; - state.check = crc32(state.check, hbuf, 2, 0); - } - hold = 0; - bits = 0; - } else if (state.head) { - state.head.extra = null; - } - state.mode = EXTRA; - case EXTRA: - if (state.flags & 1024) { - copy = state.length; - if (copy > have) { - copy = have; - } - if (copy) { - if (state.head) { - len = state.head.extra_len - state.length; - if (!state.head.extra) { - state.head.extra = new Array(state.head.extra_len); - } - utils.arraySet(state.head.extra, input, next, copy, len); - } - if (state.flags & 512) { - state.check = crc32(state.check, input, copy, next); - } - have -= copy; - next += copy; - state.length -= copy; - } - if (state.length) { - break inf_leave; - } - } - state.length = 0; - state.mode = NAME; - case NAME: - if (state.flags & 2048) { - if (have === 0) { - break inf_leave; - } - copy = 0; - do { - len = input[next + copy++]; - if (state.head && len && state.length < 65536) { - state.head.name += String.fromCharCode(len); - } - } while (len && copy < have); - if (state.flags & 512) { - state.check = crc32(state.check, input, copy, next); - } - have -= copy; - next += copy; - if (len) { - break inf_leave; - } - } else if (state.head) { - state.head.name = null; - } - state.length = 0; - state.mode = COMMENT; - case COMMENT: - if (state.flags & 4096) { - if (have === 0) { - break inf_leave; - } - copy = 0; - do { - len = input[next + copy++]; - if (state.head && len && state.length < 65536) { - state.head.comment += String.fromCharCode(len); - } - } while (len && copy < have); - if (state.flags & 512) { - state.check = crc32(state.check, input, copy, next); - } - have -= copy; - next += copy; - if (len) { - break inf_leave; - } - } else if (state.head) { - state.head.comment = null; - } - state.mode = HCRC; - case HCRC: - if (state.flags & 512) { - while (bits < 16) { - if (have === 0) { - break inf_leave; - } - have--; - hold += input[next++] << bits; - bits += 8; - } - if (hold !== (state.check & 65535)) { - strm.msg = "header crc mismatch"; - state.mode = BAD; - break; - } - hold = 0; - bits = 0; - } - if (state.head) { - state.head.hcrc = (state.flags >> 9) & 1; - state.head.done = true; - } - strm.adler = state.check = 0; - state.mode = TYPE; - break; - case DICTID: - while (bits < 32) { - if (have === 0) { - break inf_leave; - } - have--; - hold += input[next++] << bits; - bits += 8; - } - strm.adler = state.check = zswap32(hold); - hold = 0; - bits = 0; - state.mode = DICT; - case DICT: - if (state.havedict === 0) { - strm.next_out = put; - strm.avail_out = left; - strm.next_in = next; - strm.avail_in = have; - state.hold = hold; - state.bits = bits; - return Z_NEED_DICT; - } - strm.adler = state.check = 1; - state.mode = TYPE; - case TYPE: - if (flush === Z_BLOCK || flush === Z_TREES) { - break inf_leave; - } - case TYPEDO: - if (state.last) { - hold >>>= bits & 7; - bits -= bits & 7; - state.mode = CHECK; - break; - } - while (bits < 3) { - if (have === 0) { - break inf_leave; - } - have--; - hold += input[next++] << bits; - bits += 8; - } - state.last = hold & 1; - hold >>>= 1; - bits -= 1; - switch (hold & 3) { - case 0: - state.mode = STORED; - break; - case 1: - fixedtables(state); - state.mode = LEN_; - if (flush === Z_TREES) { - hold >>>= 2; - bits -= 2; - break inf_leave; - } - break; - case 2: - state.mode = TABLE; - break; - case 3: - strm.msg = "invalid block type"; - state.mode = BAD; - } - hold >>>= 2; - bits -= 2; - break; - case STORED: - hold >>>= bits & 7; - bits -= bits & 7; - while (bits < 32) { - if (have === 0) { - break inf_leave; - } - have--; - hold += input[next++] << bits; - bits += 8; - } - if ((hold & 65535) !== ((hold >>> 16) ^ 65535)) { - strm.msg = "invalid stored block lengths"; - state.mode = BAD; - break; - } - state.length = hold & 65535; - hold = 0; - bits = 0; - state.mode = COPY_; - if (flush === Z_TREES) { - break inf_leave; - } - case COPY_: - state.mode = COPY; - case COPY: - copy = state.length; - if (copy) { - if (copy > have) { - copy = have; - } - if (copy > left) { - copy = left; - } - if (copy === 0) { - break inf_leave; - } - utils.arraySet(output, input, next, copy, put); - have -= copy; - next += copy; - left -= copy; - put += copy; - state.length -= copy; - break; - } - state.mode = TYPE; - break; - case TABLE: - while (bits < 14) { - if (have === 0) { - break inf_leave; - } - have--; - hold += input[next++] << bits; - bits += 8; - } - state.nlen = (hold & 31) + 257; - hold >>>= 5; - bits -= 5; - state.ndist = (hold & 31) + 1; - hold >>>= 5; - bits -= 5; - state.ncode = (hold & 15) + 4; - hold >>>= 4; - bits -= 4; - if (state.nlen > 286 || state.ndist > 30) { - strm.msg = "too many length or distance symbols"; - state.mode = BAD; - break; - } - state.have = 0; - state.mode = LENLENS; - case LENLENS: - while (state.have < state.ncode) { - while (bits < 3) { - if (have === 0) { - break inf_leave; - } - have--; - hold += input[next++] << bits; - bits += 8; - } - state.lens[order[state.have++]] = hold & 7; - hold >>>= 3; - bits -= 3; - } - while (state.have < 19) { - state.lens[order[state.have++]] = 0; - } - state.lencode = state.lendyn; - state.lenbits = 7; - opts = { bits: state.lenbits }; - ret = inflate_table(CODES, state.lens, 0, 19, state.lencode, 0, state.work, opts); - state.lenbits = opts.bits; - if (ret) { - strm.msg = "invalid code lengths set"; - state.mode = BAD; - break; - } - state.have = 0; - state.mode = CODELENS; - case CODELENS: - while (state.have < state.nlen + state.ndist) { - for (;;) { - here = state.lencode[hold & ((1 << state.lenbits) - 1)]; - here_bits = here >>> 24; - here_op = (here >>> 16) & 255; - here_val = here & 65535; - if (here_bits <= bits) { - break; - } - if (have === 0) { - break inf_leave; - } - have--; - hold += input[next++] << bits; - bits += 8; - } - if (here_val < 16) { - hold >>>= here_bits; - bits -= here_bits; - state.lens[state.have++] = here_val; - } else { - if (here_val === 16) { - n = here_bits + 2; - while (bits < n) { - if (have === 0) { - break inf_leave; - } - have--; - hold += input[next++] << bits; - bits += 8; - } - hold >>>= here_bits; - bits -= here_bits; - if (state.have === 0) { - strm.msg = "invalid bit length repeat"; - state.mode = BAD; - break; - } - len = state.lens[state.have - 1]; - copy = 3 + (hold & 3); - hold >>>= 2; - bits -= 2; - } else if (here_val === 17) { - n = here_bits + 3; - while (bits < n) { - if (have === 0) { - break inf_leave; - } - have--; - hold += input[next++] << bits; - bits += 8; - } - hold >>>= here_bits; - bits -= here_bits; - len = 0; - copy = 3 + (hold & 7); - hold >>>= 3; - bits -= 3; - } else { - n = here_bits + 7; - while (bits < n) { - if (have === 0) { - break inf_leave; - } - have--; - hold += input[next++] << bits; - bits += 8; - } - hold >>>= here_bits; - bits -= here_bits; - len = 0; - copy = 11 + (hold & 127); - hold >>>= 7; - bits -= 7; - } - if (state.have + copy > state.nlen + state.ndist) { - strm.msg = "invalid bit length repeat"; - state.mode = BAD; - break; - } - while (copy--) { - state.lens[state.have++] = len; - } - } - } - if (state.mode === BAD) { - break; - } - if (state.lens[256] === 0) { - strm.msg = "invalid code -- missing end-of-block"; - state.mode = BAD; - break; - } - state.lenbits = 9; - opts = { bits: state.lenbits }; - ret = inflate_table(LENS, state.lens, 0, state.nlen, state.lencode, 0, state.work, opts); - state.lenbits = opts.bits; - if (ret) { - strm.msg = "invalid literal/lengths set"; - state.mode = BAD; - break; - } - state.distbits = 6; - state.distcode = state.distdyn; - opts = { bits: state.distbits }; - ret = inflate_table(DISTS, state.lens, state.nlen, state.ndist, state.distcode, 0, state.work, opts); - state.distbits = opts.bits; - if (ret) { - strm.msg = "invalid distances set"; - state.mode = BAD; - break; - } - state.mode = LEN_; - if (flush === Z_TREES) { - break inf_leave; - } - case LEN_: - state.mode = LEN; - case LEN: - if (have >= 6 && left >= 258) { - strm.next_out = put; - strm.avail_out = left; - strm.next_in = next; - strm.avail_in = have; - state.hold = hold; - state.bits = bits; - inflate_fast(strm, _out); - put = strm.next_out; - output = strm.output; - left = strm.avail_out; - next = strm.next_in; - input = strm.input; - have = strm.avail_in; - hold = state.hold; - bits = state.bits; - if (state.mode === TYPE) { - state.back = -1; - } - break; - } - state.back = 0; - for (;;) { - here = state.lencode[hold & ((1 << state.lenbits) - 1)]; - here_bits = here >>> 24; - here_op = (here >>> 16) & 255; - here_val = here & 65535; - if (here_bits <= bits) { - break; - } - if (have === 0) { - break inf_leave; - } - have--; - hold += input[next++] << bits; - bits += 8; - } - if (here_op && (here_op & 240) === 0) { - last_bits = here_bits; - last_op = here_op; - last_val = here_val; - for (;;) { - here = state.lencode[last_val + ((hold & ((1 << (last_bits + last_op)) - 1)) >> last_bits)]; - here_bits = here >>> 24; - here_op = (here >>> 16) & 255; - here_val = here & 65535; - if (last_bits + here_bits <= bits) { - break; - } - if (have === 0) { - break inf_leave; - } - have--; - hold += input[next++] << bits; - bits += 8; - } - hold >>>= last_bits; - bits -= last_bits; - state.back += last_bits; - } - hold >>>= here_bits; - bits -= here_bits; - state.back += here_bits; - state.length = here_val; - if (here_op === 0) { - state.mode = LIT; - break; - } - if (here_op & 32) { - state.back = -1; - state.mode = TYPE; - break; - } - if (here_op & 64) { - strm.msg = "invalid literal/length code"; - state.mode = BAD; - break; - } - state.extra = here_op & 15; - state.mode = LENEXT; - case LENEXT: - if (state.extra) { - n = state.extra; - while (bits < n) { - if (have === 0) { - break inf_leave; - } - have--; - hold += input[next++] << bits; - bits += 8; - } - state.length += hold & ((1 << state.extra) - 1); - hold >>>= state.extra; - bits -= state.extra; - state.back += state.extra; - } - state.was = state.length; - state.mode = DIST; - case DIST: - for (;;) { - here = state.distcode[hold & ((1 << state.distbits) - 1)]; - here_bits = here >>> 24; - here_op = (here >>> 16) & 255; - here_val = here & 65535; - if (here_bits <= bits) { - break; - } - if (have === 0) { - break inf_leave; - } - have--; - hold += input[next++] << bits; - bits += 8; - } - if ((here_op & 240) === 0) { - last_bits = here_bits; - last_op = here_op; - last_val = here_val; - for (;;) { - here = state.distcode[last_val + ((hold & ((1 << (last_bits + last_op)) - 1)) >> last_bits)]; - here_bits = here >>> 24; - here_op = (here >>> 16) & 255; - here_val = here & 65535; - if (last_bits + here_bits <= bits) { - break; - } - if (have === 0) { - break inf_leave; - } - have--; - hold += input[next++] << bits; - bits += 8; - } - hold >>>= last_bits; - bits -= last_bits; - state.back += last_bits; - } - hold >>>= here_bits; - bits -= here_bits; - state.back += here_bits; - if (here_op & 64) { - strm.msg = "invalid distance code"; - state.mode = BAD; - break; - } - state.offset = here_val; - state.extra = here_op & 15; - state.mode = DISTEXT; - case DISTEXT: - if (state.extra) { - n = state.extra; - while (bits < n) { - if (have === 0) { - break inf_leave; - } - have--; - hold += input[next++] << bits; - bits += 8; - } - state.offset += hold & ((1 << state.extra) - 1); - hold >>>= state.extra; - bits -= state.extra; - state.back += state.extra; - } - if (state.offset > state.dmax) { - strm.msg = "invalid distance too far back"; - state.mode = BAD; - break; - } - state.mode = MATCH; - case MATCH: - if (left === 0) { - break inf_leave; - } - copy = _out - left; - if (state.offset > copy) { - copy = state.offset - copy; - if (copy > state.whave) { - if (state.sane) { - strm.msg = "invalid distance too far back"; - state.mode = BAD; - break; - } - } - if (copy > state.wnext) { - copy -= state.wnext; - from = state.wsize - copy; - } else { - from = state.wnext - copy; - } - if (copy > state.length) { - copy = state.length; - } - from_source = state.window; - } else { - from_source = output; - from = put - state.offset; - copy = state.length; - } - if (copy > left) { - copy = left; - } - left -= copy; - state.length -= copy; - do { - output[put++] = from_source[from++]; - } while (--copy); - if (state.length === 0) { - state.mode = LEN; - } - break; - case LIT: - if (left === 0) { - break inf_leave; - } - output[put++] = state.length; - left--; - state.mode = LEN; - break; - case CHECK: - if (state.wrap) { - while (bits < 32) { - if (have === 0) { - break inf_leave; - } - have--; - hold |= input[next++] << bits; - bits += 8; - } - _out -= left; - strm.total_out += _out; - state.total += _out; - if (_out) { - strm.adler = state.check = state.flags - ? crc32(state.check, output, _out, put - _out) - : adler32(state.check, output, _out, put - _out); - } - _out = left; - if ((state.flags ? hold : zswap32(hold)) !== state.check) { - strm.msg = "incorrect data check"; - state.mode = BAD; - break; - } - hold = 0; - bits = 0; - } - state.mode = LENGTH; - case LENGTH: - if (state.wrap && state.flags) { - while (bits < 32) { - if (have === 0) { - break inf_leave; - } - have--; - hold += input[next++] << bits; - bits += 8; - } - if (hold !== (state.total & 4294967295)) { - strm.msg = "incorrect length check"; - state.mode = BAD; - break; - } - hold = 0; - bits = 0; - } - state.mode = DONE; - case DONE: - ret = Z_STREAM_END; - break inf_leave; - case BAD: - ret = Z_DATA_ERROR; - break inf_leave; - case MEM: - return Z_MEM_ERROR; - case SYNC: - default: - return Z_STREAM_ERROR; - } - } - strm.next_out = put; - strm.avail_out = left; - strm.next_in = next; - strm.avail_in = have; - state.hold = hold; - state.bits = bits; - if (state.wsize || (_out !== strm.avail_out && state.mode < BAD && (state.mode < CHECK || flush !== Z_FINISH))) { - if (updatewindow(strm, strm.output, strm.next_out, _out - strm.avail_out)) { - state.mode = MEM; - return Z_MEM_ERROR; - } - } - _in -= strm.avail_in; - _out -= strm.avail_out; - strm.total_in += _in; - strm.total_out += _out; - state.total += _out; - if (state.wrap && _out) { - strm.adler = state.check = state.flags - ? crc32(state.check, output, _out, strm.next_out - _out) - : adler32(state.check, output, _out, strm.next_out - _out); - } - strm.data_type = - state.bits + - (state.last ? 64 : 0) + - (state.mode === TYPE ? 128 : 0) + - (state.mode === LEN_ || state.mode === COPY_ ? 256 : 0); - if (((_in === 0 && _out === 0) || flush === Z_FINISH) && ret === Z_OK) { - ret = Z_BUF_ERROR; - } - return ret; - } - function inflateEnd(strm) { - if (!strm || !strm.state) { - return Z_STREAM_ERROR; - } - var state = strm.state; - if (state.window) { - state.window = null; - } - strm.state = null; - return Z_OK; - } - function inflateGetHeader(strm, head) { - var state; - if (!strm || !strm.state) { - return Z_STREAM_ERROR; - } - state = strm.state; - if ((state.wrap & 2) === 0) { - return Z_STREAM_ERROR; - } - state.head = head; - head.done = false; - return Z_OK; - } - function inflateSetDictionary(strm, dictionary) { - var dictLength = dictionary.length; - var state; - var dictid; - var ret; - if (!strm || !strm.state) { - return Z_STREAM_ERROR; - } - state = strm.state; - if (state.wrap !== 0 && state.mode !== DICT) { - return Z_STREAM_ERROR; - } - if (state.mode === DICT) { - dictid = 1; - dictid = adler32(dictid, dictionary, dictLength, 0); - if (dictid !== state.check) { - return Z_DATA_ERROR; - } - } - ret = updatewindow(strm, dictionary, dictLength, dictLength); - if (ret) { - state.mode = MEM; - return Z_MEM_ERROR; - } - state.havedict = 1; - return Z_OK; - } - exports.inflateReset = inflateReset; - exports.inflateReset2 = inflateReset2; - exports.inflateResetKeep = inflateResetKeep; - exports.inflateInit = inflateInit; - exports.inflateInit2 = inflateInit2; - exports.inflate = inflate; - exports.inflateEnd = inflateEnd; - exports.inflateGetHeader = inflateGetHeader; - exports.inflateSetDictionary = inflateSetDictionary; - exports.inflateInfo = "pako inflate (from Nodeca project)"; - }, -}); +// -// node_modules/pako/lib/zlib/constants.js -var require_constants = __commonJS({ - "node_modules/pako/lib/zlib/constants.js"(exports, module2) { - "use strict"; - module2.exports = { - Z_NO_FLUSH: 0, - Z_PARTIAL_FLUSH: 1, - Z_SYNC_FLUSH: 2, - Z_FULL_FLUSH: 3, - Z_FINISH: 4, - Z_BLOCK: 5, - Z_TREES: 6, - Z_OK: 0, - Z_STREAM_END: 1, - Z_NEED_DICT: 2, - Z_ERRNO: -1, - Z_STREAM_ERROR: -2, - Z_DATA_ERROR: -3, - Z_MEM_ERROR: -4, - Z_BUF_ERROR: -5, - Z_VERSION_ERROR: -6, - Z_NO_COMPRESSION: 0, - Z_BEST_SPEED: 1, - Z_BEST_COMPRESSION: 9, - Z_DEFAULT_COMPRESSION: -1, - Z_FILTERED: 1, - Z_HUFFMAN_ONLY: 2, - Z_RLE: 3, - Z_FIXED: 4, - Z_DEFAULT_STRATEGY: 0, - Z_BINARY: 0, - Z_TEXT: 1, - Z_ASCII: 1, - Z_UNKNOWN: 2, - Z_DEFLATED: 8, - DEFLATE: 1, - INFLATE: 2, - GZIP: 3, - GUNZIP: 4, - DEFLATERAW: 5, - INFLATERAW: 6, - UNZIP: 7, - BROTLI_DECODE: 8, - BROTLI_ENCODE: 9, - Z_MIN_WINDOWBITS: 8, - Z_MAX_WINDOWBITS: 15, - Z_DEFAULT_WINDOWBITS: 15, - Z_MIN_CHUNK: 64, - Z_MAX_CHUNK: Infinity, - Z_DEFAULT_CHUNK: 16384, - Z_MIN_MEMLEVEL: 1, - Z_MAX_MEMLEVEL: 9, - Z_DEFAULT_MEMLEVEL: 8, - Z_MIN_LEVEL: -1, - Z_MAX_LEVEL: 9, - Z_DEFAULT_LEVEL: -1, - BROTLI_OPERATION_PROCESS: 0, - BROTLI_OPERATION_FLUSH: 1, - BROTLI_OPERATION_FINISH: 2, - BROTLI_OPERATION_EMIT_METADATA: 3, - BROTLI_PARAM_MODE: 0, - BROTLI_MODE_GENERIC: 0, - BROTLI_MODE_TEXT: 1, - BROTLI_MODE_FONT: 2, - BROTLI_DEFAULT_MODE: 0, - BROTLI_PARAM_QUALITY: 1, - BROTLI_MIN_QUALITY: 0, - BROTLI_MAX_QUALITY: 11, - BROTLI_DEFAULT_QUALITY: 11, - BROTLI_PARAM_LGWIN: 2, - BROTLI_MIN_WINDOW_BITS: 10, - BROTLI_MAX_WINDOW_BITS: 24, - BROTLI_LARGE_MAX_WINDOW_BITS: 30, - BROTLI_DEFAULT_WINDOW: 22, - BROTLI_PARAM_LGBLOCK: 3, - BROTLI_MIN_INPUT_BLOCK_BITS: 16, - BROTLI_MAX_INPUT_BLOCK_BITS: 24, - BROTLI_PARAM_DISABLE_LITERAL_CONTEXT_MODELING: 4, - BROTLI_PARAM_SIZE_HINT: 5, - BROTLI_PARAM_LARGE_WINDOW: 6, - BROTLI_PARAM_NPOSTFIX: 7, - BROTLI_PARAM_NDIRECT: 8, - BROTLI_DECODER_RESULT_ERROR: 0, - BROTLI_DECODER_RESULT_SUCCESS: 1, - BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT: 2, - BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT: 3, - BROTLI_DECODER_PARAM_DISABLE_RING_BUFFER_REALLOCATION: 0, - BROTLI_DECODER_PARAM_LARGE_WINDOW: 1, - BROTLI_DECODER_NO_ERROR: 0, - BROTLI_DECODER_SUCCESS: 1, - BROTLI_DECODER_NEEDS_MORE_INPUT: 2, - BROTLI_DECODER_NEEDS_MORE_OUTPUT: 3, - BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_NIBBLE: -1, - BROTLI_DECODER_ERROR_FORMAT_RESERVED: -2, - BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_META_NIBBLE: -3, - BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_ALPHABET: -4, - BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_SAME: -5, - BROTLI_DECODER_ERROR_FORMAT_CL_SPACE: -6, - BROTLI_DECODER_ERROR_FORMAT_HUFFMAN_SPACE: -7, - BROTLI_DECODER_ERROR_FORMAT_CONTEXT_MAP_REPEAT: -8, - BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_1: -9, - BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_2: -10, - BROTLI_DECODER_ERROR_FORMAT_TRANSFORM: -11, - BROTLI_DECODER_ERROR_FORMAT_DICTIONARY: -12, - BROTLI_DECODER_ERROR_FORMAT_WINDOW_BITS: -13, - BROTLI_DECODER_ERROR_FORMAT_PADDING_1: -14, - BROTLI_DECODER_ERROR_FORMAT_PADDING_2: -15, - BROTLI_DECODER_ERROR_FORMAT_DISTANCE: -16, - BROTLI_DECODER_ERROR_DICTIONARY_NOT_SET: -19, - BROTLI_DECODER_ERROR_INVALID_ARGUMENTS: -20, - BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MODES: -21, - BROTLI_DECODER_ERROR_ALLOC_TREE_GROUPS: -22, - BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MAP: -25, - BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_1: -26, - BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_2: -27, - BROTLI_DECODER_ERROR_ALLOC_BLOCK_TYPE_TREES: -30, - BROTLI_DECODER_ERROR_UNREACHABLE: -31, - }; - }, -}); +function Unzip(opts) { + if (!(this instanceof Unzip)) return new Unzip(opts); + Zlib.$call(this, UNZIP, opts); +} +Unzip.prototype = Object.create(Zlib.prototype); + +// + +const constants = { + Z_NO_FLUSH: 0, + Z_PARTIAL_FLUSH: 1, + Z_SYNC_FLUSH: 2, + Z_FULL_FLUSH: 3, + Z_FINISH: 4, + Z_BLOCK: 5, + Z_TREES: 6, + Z_OK: 0, + Z_STREAM_END: 1, + Z_NEED_DICT: 2, + Z_ERRNO: -1, + Z_STREAM_ERROR: -2, + Z_DATA_ERROR: -3, + Z_MEM_ERROR: -4, + Z_BUF_ERROR: -5, + Z_VERSION_ERROR: -6, + Z_NO_COMPRESSION: 0, + Z_BEST_SPEED: 1, + Z_BEST_COMPRESSION: 9, + Z_DEFAULT_COMPRESSION: -1, + Z_FILTERED: 1, + Z_HUFFMAN_ONLY: 2, + Z_RLE: 3, + Z_FIXED: 4, + Z_DEFAULT_STRATEGY: 0, + Z_BINARY: 0, + Z_TEXT: 1, + Z_ASCII: 1, + Z_UNKNOWN: 2, + Z_DEFLATED: 8, + DEFLATE: 1, + INFLATE: 2, + GZIP: 3, + GUNZIP: 4, + DEFLATERAW: 5, + INFLATERAW: 6, + UNZIP: 7, + BROTLI_DECODE: 8, + BROTLI_ENCODE: 9, + Z_MIN_WINDOWBITS: 8, + Z_MAX_WINDOWBITS: 15, + Z_DEFAULT_WINDOWBITS: 15, + Z_MIN_CHUNK: 64, + Z_MAX_CHUNK: Infinity, + Z_DEFAULT_CHUNK: 16384, + Z_MIN_MEMLEVEL: 1, + Z_MAX_MEMLEVEL: 9, + Z_DEFAULT_MEMLEVEL: 8, + Z_MIN_LEVEL: -1, + Z_MAX_LEVEL: 9, + Z_DEFAULT_LEVEL: -1, + BROTLI_OPERATION_PROCESS: 0, + BROTLI_OPERATION_FLUSH: 1, + BROTLI_OPERATION_FINISH: 2, + BROTLI_OPERATION_EMIT_METADATA: 3, + BROTLI_PARAM_MODE: 0, + BROTLI_MODE_GENERIC: 0, + BROTLI_MODE_TEXT: 1, + BROTLI_MODE_FONT: 2, + BROTLI_DEFAULT_MODE: 0, + BROTLI_PARAM_QUALITY: 1, + BROTLI_MIN_QUALITY: 0, + BROTLI_MAX_QUALITY: 11, + BROTLI_DEFAULT_QUALITY: 11, + BROTLI_PARAM_LGWIN: 2, + BROTLI_MIN_WINDOW_BITS: 10, + BROTLI_MAX_WINDOW_BITS: 24, + BROTLI_LARGE_MAX_WINDOW_BITS: 30, + BROTLI_DEFAULT_WINDOW: 22, + BROTLI_PARAM_LGBLOCK: 3, + BROTLI_MIN_INPUT_BLOCK_BITS: 16, + BROTLI_MAX_INPUT_BLOCK_BITS: 24, + BROTLI_PARAM_DISABLE_LITERAL_CONTEXT_MODELING: 4, + BROTLI_PARAM_SIZE_HINT: 5, + BROTLI_PARAM_LARGE_WINDOW: 6, + BROTLI_PARAM_NPOSTFIX: 7, + BROTLI_PARAM_NDIRECT: 8, + BROTLI_DECODER_RESULT_ERROR: 0, + BROTLI_DECODER_RESULT_SUCCESS: 1, + BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT: 2, + BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT: 3, + BROTLI_DECODER_PARAM_DISABLE_RING_BUFFER_REALLOCATION: 0, + BROTLI_DECODER_PARAM_LARGE_WINDOW: 1, + BROTLI_DECODER_NO_ERROR: 0, + BROTLI_DECODER_SUCCESS: 1, + BROTLI_DECODER_NEEDS_MORE_INPUT: 2, + BROTLI_DECODER_NEEDS_MORE_OUTPUT: 3, + BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_NIBBLE: -1, + BROTLI_DECODER_ERROR_FORMAT_RESERVED: -2, + BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_META_NIBBLE: -3, + BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_ALPHABET: -4, + BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_SAME: -5, + BROTLI_DECODER_ERROR_FORMAT_CL_SPACE: -6, + BROTLI_DECODER_ERROR_FORMAT_HUFFMAN_SPACE: -7, + BROTLI_DECODER_ERROR_FORMAT_CONTEXT_MAP_REPEAT: -8, + BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_1: -9, + BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_2: -10, + BROTLI_DECODER_ERROR_FORMAT_TRANSFORM: -11, + BROTLI_DECODER_ERROR_FORMAT_DICTIONARY: -12, + BROTLI_DECODER_ERROR_FORMAT_WINDOW_BITS: -13, + BROTLI_DECODER_ERROR_FORMAT_PADDING_1: -14, + BROTLI_DECODER_ERROR_FORMAT_PADDING_2: -15, + BROTLI_DECODER_ERROR_FORMAT_DISTANCE: -16, + BROTLI_DECODER_ERROR_DICTIONARY_NOT_SET: -19, + BROTLI_DECODER_ERROR_INVALID_ARGUMENTS: -20, + BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MODES: -21, + BROTLI_DECODER_ERROR_ALLOC_TREE_GROUPS: -22, + BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MAP: -25, + BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_1: -26, + BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_2: -27, + BROTLI_DECODER_ERROR_ALLOC_BLOCK_TYPE_TREES: -30, + BROTLI_DECODER_ERROR_UNREACHABLE: -31, +}; +const { DEFLATE, INFLATE, GZIP, GUNZIP, DEFLATERAW, INFLATERAW, UNZIP, BROTLI_DECODE, BROTLI_ENCODE } = constants; + +// Translation table for return codes. +const codes = { + Z_OK: constants.Z_OK, + Z_STREAM_END: constants.Z_STREAM_END, + Z_NEED_DICT: constants.Z_NEED_DICT, + Z_ERRNO: constants.Z_ERRNO, + Z_STREAM_ERROR: constants.Z_STREAM_ERROR, + Z_DATA_ERROR: constants.Z_DATA_ERROR, + Z_MEM_ERROR: constants.Z_MEM_ERROR, + Z_BUF_ERROR: constants.Z_BUF_ERROR, + Z_VERSION_ERROR: constants.Z_VERSION_ERROR, +}; -// node_modules/browserify-zlib/lib/binding.js -var require_binding = __commonJS({ - "node_modules/browserify-zlib/lib/binding.js"(exports) { - "use strict"; +for (const ckey of Object.keys(codes)) { + codes[codes[ckey]] = ckey; +} - var Zstream = require_zstream(); - var zlib_deflate = require_deflate(); - var zlib_inflate = require_inflate(); - var constants = require_constants(); - for (key in constants) { - exports[key] = constants[key]; - } - var key; - exports.NONE = 0; - exports.DEFLATE = 1; - exports.INFLATE = 2; - exports.GZIP = 3; - exports.GUNZIP = 4; - exports.DEFLATERAW = 5; - exports.INFLATERAW = 6; - exports.UNZIP = 7; - var GZIP_HEADER_ID1 = 31; - var GZIP_HEADER_ID2 = 139; - function Zlib(mode) { - if (typeof mode !== "number" || mode < exports.DEFLATE || mode > exports.UNZIP) { - throw new TypeError("Bad argument"); - } - this.dictionary = null; - this.err = 0; - this.flush = 0; - this.init_done = false; - this.level = 0; - this.memLevel = 0; - this.mode = mode; - this.strategy = 0; - this.windowBits = 0; - this.write_in_progress = false; - this.pending_close = false; - this.gzip_id_bytes_read = 0; - } - Zlib.prototype = {}; - Zlib.prototype.close = function () { - if (this.write_in_progress) { - this.pending_close = true; - return; - } - this.pending_close = false; - assert(this.init_done, "close before init"); - assert(this.mode <= exports.UNZIP); - if (this.mode === exports.DEFLATE || this.mode === exports.GZIP || this.mode === exports.DEFLATERAW) { - zlib_deflate.deflateEnd(this.strm); - } else if ( - this.mode === exports.INFLATE || - this.mode === exports.GUNZIP || - this.mode === exports.INFLATERAW || - this.mode === exports.UNZIP - ) { - zlib_inflate.inflateEnd(this.strm); - } - this.mode = exports.NONE; - this.dictionary = null; - }; - Zlib.prototype.write = function (flush, input, in_off, in_len, out, out_off, out_len) { - return this._write(true, flush, input, in_off, in_len, out, out_off, out_len); - }; - Zlib.prototype.writeSync = function (flush, input, in_off, in_len, out, out_off, out_len) { - return this._write(false, flush, input, in_off, in_len, out, out_off, out_len); - }; - Zlib.prototype._write = function (async, flush, input, in_off, in_len, out, out_off, out_len) { - assert.equal(arguments.length, 8); - assert(this.init_done, "write before init"); - assert(this.mode !== exports.NONE, "already finalized"); - assert.equal(false, this.write_in_progress, "write already in progress"); - assert.equal(false, this.pending_close, "close is pending"); - this.write_in_progress = true; - assert.equal(false, flush === void 0, "must provide flush value"); - this.write_in_progress = true; - if ( - flush !== exports.Z_NO_FLUSH && - flush !== exports.Z_PARTIAL_FLUSH && - flush !== exports.Z_SYNC_FLUSH && - flush !== exports.Z_FULL_FLUSH && - flush !== exports.Z_FINISH && - flush !== exports.Z_BLOCK - ) { - throw new Error("Invalid flush value"); - } - if (input == null) { - input = Buffer.alloc(0); - in_len = 0; - in_off = 0; - } - this.strm.avail_in = in_len; - this.strm.input = input; - this.strm.next_in = in_off; - this.strm.avail_out = out_len; - this.strm.output = out; - this.strm.next_out = out_off; - this.flush = flush; - if (!async) { - this._process(); - if (this._checkError()) { - return this._afterSync(); - } - return; - } - var self = this; - process.nextTick(function () { - self._process(); - self._after(); - }); - return this; - }; - Zlib.prototype._afterSync = function () { - var avail_out = this.strm.avail_out; - var avail_in = this.strm.avail_in; - this.write_in_progress = false; - return [avail_in, avail_out]; - }; - Zlib.prototype._process = function () { - var next_expected_header_byte = null; - switch (this.mode) { - case exports.DEFLATE: - case exports.GZIP: - case exports.DEFLATERAW: - this.err = zlib_deflate.deflate(this.strm, this.flush); - break; - case exports.UNZIP: - if (this.strm.avail_in > 0) { - next_expected_header_byte = this.strm.next_in; - } - switch (this.gzip_id_bytes_read) { - case 0: - if (next_expected_header_byte === null) { - break; - } - if (this.strm.input[next_expected_header_byte] === GZIP_HEADER_ID1) { - this.gzip_id_bytes_read = 1; - next_expected_header_byte++; - if (this.strm.avail_in === 1) { - break; - } - } else { - this.mode = exports.INFLATE; - break; - } - case 1: - if (next_expected_header_byte === null) { - break; - } - if (this.strm.input[next_expected_header_byte] === GZIP_HEADER_ID2) { - this.gzip_id_bytes_read = 2; - this.mode = exports.GUNZIP; - } else { - this.mode = exports.INFLATE; - } - break; - default: - throw new Error("invalid number of gzip magic number bytes read"); - } - case exports.INFLATE: - case exports.GUNZIP: - case exports.INFLATERAW: - this.err = zlib_inflate.inflate(this.strm, this.flush); - if (this.err === exports.Z_NEED_DICT && this.dictionary) { - this.err = zlib_inflate.inflateSetDictionary(this.strm, this.dictionary); - if (this.err === exports.Z_OK) { - this.err = zlib_inflate.inflate(this.strm, this.flush); - } else if (this.err === exports.Z_DATA_ERROR) { - this.err = exports.Z_NEED_DICT; - } - } - while ( - this.strm.avail_in > 0 && - this.mode === exports.GUNZIP && - this.err === exports.Z_STREAM_END && - this.strm.next_in[0] !== 0 - ) { - this.reset(); - this.err = zlib_inflate.inflate(this.strm, this.flush); - } - break; - default: - throw new Error("Unknown mode " + this.mode); - } - }; - Zlib.prototype._checkError = function () { - switch (this.err) { - case exports.Z_OK: - case exports.Z_BUF_ERROR: - if (this.strm.avail_out !== 0 && this.flush === exports.Z_FINISH) { - this._error("unexpected end of file"); - return false; - } - break; - case exports.Z_STREAM_END: - break; - case exports.Z_NEED_DICT: - if (this.dictionary == null) { - this._error("Missing dictionary"); - } else { - this._error("Bad dictionary"); - } - return false; - default: - this._error("Zlib error"); - return false; - } - return true; - }; - Zlib.prototype._after = function () { - if (!this._checkError()) { - return; - } - var avail_out = this.strm.avail_out; - var avail_in = this.strm.avail_in; - this.write_in_progress = false; - this.callback(avail_in, avail_out); - if (this.pending_close) { - this.close(); - } - }; - Zlib.prototype._error = function (message) { - if (this.strm.msg) { - message = this.strm.msg; - } - this.onerror(message, this.err); - this.write_in_progress = false; - if (this.pending_close) { - this.close(); - } - }; - Zlib.prototype.init = function (windowBits, level, memLevel, strategy, dictionary) { - assert( - arguments.length === 4 || arguments.length === 5, - "init(windowBits, level, memLevel, strategy, [dictionary])", - ); - assert(windowBits >= 8 && windowBits <= 15, "invalid windowBits"); - assert(level >= -1 && level <= 9, "invalid compression level"); - assert(memLevel >= 1 && memLevel <= 9, "invalid memlevel"); - assert( - strategy === exports.Z_FILTERED || - strategy === exports.Z_HUFFMAN_ONLY || - strategy === exports.Z_RLE || - strategy === exports.Z_FIXED || - strategy === exports.Z_DEFAULT_STRATEGY, - "invalid strategy", - ); - this._init(level, windowBits, memLevel, strategy, dictionary); - this._setDictionary(); - }; - Zlib.prototype.params = function () { - throw new Error("deflateParams Not supported"); - }; - Zlib.prototype.reset = function () { - this._reset(); - this._setDictionary(); - }; - Zlib.prototype._init = function (level, windowBits, memLevel, strategy, dictionary) { - this.level = level; - this.windowBits = windowBits; - this.memLevel = memLevel; - this.strategy = strategy; - this.flush = exports.Z_NO_FLUSH; - this.err = exports.Z_OK; - if (this.mode === exports.GZIP || this.mode === exports.GUNZIP) { - this.windowBits += 16; - } - if (this.mode === exports.UNZIP) { - this.windowBits += 32; - } - if (this.mode === exports.DEFLATERAW || this.mode === exports.INFLATERAW) { - this.windowBits = -1 * this.windowBits; - } - this.strm = new Zstream(); - switch (this.mode) { - case exports.DEFLATE: - case exports.GZIP: - case exports.DEFLATERAW: - this.err = zlib_deflate.deflateInit2( - this.strm, - this.level, - exports.Z_DEFLATED, - this.windowBits, - this.memLevel, - this.strategy, - ); - break; - case exports.INFLATE: - case exports.GUNZIP: - case exports.INFLATERAW: - case exports.UNZIP: - this.err = zlib_inflate.inflateInit2(this.strm, this.windowBits); - break; - default: - throw new Error("Unknown mode " + this.mode); - } - if (this.err !== exports.Z_OK) { - this._error("Init error"); - } - this.dictionary = dictionary; - this.write_in_progress = false; - this.init_done = true; - }; - Zlib.prototype._setDictionary = function () { - if (this.dictionary == null) { - return; - } - this.err = exports.Z_OK; - switch (this.mode) { - case exports.DEFLATE: - case exports.DEFLATERAW: - this.err = zlib_deflate.deflateSetDictionary(this.strm, this.dictionary); - break; - default: - break; - } - if (this.err !== exports.Z_OK) { - this._error("Failed to set dictionary"); - } - }; - Zlib.prototype._reset = function () { - this.err = exports.Z_OK; - switch (this.mode) { - case exports.DEFLATE: - case exports.DEFLATERAW: - case exports.GZIP: - this.err = zlib_deflate.deflateReset(this.strm); - break; - case exports.INFLATE: - case exports.INFLATERAW: - case exports.GUNZIP: - this.err = zlib_inflate.inflateReset(this.strm); - break; - default: - break; - } - if (this.err !== exports.Z_OK) { - this._error("Failed to reset stream"); - } - }; - exports.Zlib = Zlib; - }, -}); +const methods = [ + [], + [Deflate, true, createZlibEncoder], + [Inflate, false, createZlibDecoder], + [Gzip, true, createZlibEncoder], + [Gunzip, false, createZlibDecoder], + [DeflateRaw, true, createZlibEncoder], + [InflateRaw, false, createZlibDecoder], + [Unzip, false, createZlibDecoder], + [BrotliDecompress, false, createBrotliDecoder], + [BrotliCompress, true, createBrotliEncoder], +] as const; + +function createConvenienceMethod(method: number, is_sync: boolean) { + const [, , private_constructor] = methods[method]; + + switch (is_sync) { + case false: + return function (buffer, options, callback) { + if (typeof options === "function") { + callback = options; + options = {}; + } + if (options == null) options = {}; + if ($isObject(options)) options.maxOutputLength ??= maxOutputLengthDefault; + if (typeof callback !== "function") throw ERR_INVALID_ARG_TYPE("callback", "function", callback); + const coder = private_constructor(options, {}, callback, method); + coder.transform(buffer, undefined, true); + }; + case true: + return function (buffer, options) { + if (options == null) options = {}; + if ($isObject(options)) options.maxOutputLength ??= maxOutputLengthDefault; + const coder = private_constructor(options, {}, null, method); + return coder.transformSync(buffer, undefined, true); + }; + } +} -// node_modules/browserify-zlib/lib/index.js -var require_lib = __commonJS({ - "node_modules/browserify-zlib/lib/index.js"(exports) { - "use strict"; - var Buffer2 = BufferModule.Buffer; - var Transform = StreamModule.Transform; - var binding = require_binding(); - var util = Util; - var kMaxLength = BufferModule.kMaxLength; - var kRangeErrorMessage = - "Cannot create final Buffer. It would be larger than 0x" + kMaxLength.toString(16) + " bytes"; - binding.Z_MIN_WINDOWBITS = 8; - binding.Z_MAX_WINDOWBITS = 15; - binding.Z_DEFAULT_WINDOWBITS = 15; - binding.Z_MIN_CHUNK = 64; - binding.Z_MAX_CHUNK = Infinity; - binding.Z_DEFAULT_CHUNK = 16 * 1024; - binding.Z_MIN_MEMLEVEL = 1; - binding.Z_MAX_MEMLEVEL = 9; - binding.Z_DEFAULT_MEMLEVEL = 8; - binding.Z_MIN_LEVEL = -1; - binding.Z_MAX_LEVEL = 9; - binding.Z_DEFAULT_LEVEL = binding.Z_DEFAULT_COMPRESSION; - var bkeys = Object.keys(binding); - for (bk = 0; bk < bkeys.length; bk++) { - bkey = bkeys[bk]; - if (bkey.match(/^Z/)) { - Object.defineProperty(exports, bkey, { - enumerable: true, - value: binding[bkey], - writable: false, - }); - } - } - var bkey; - var bk; - var codes = { - Z_OK: binding.Z_OK, - Z_STREAM_END: binding.Z_STREAM_END, - Z_NEED_DICT: binding.Z_NEED_DICT, - Z_ERRNO: binding.Z_ERRNO, - Z_STREAM_ERROR: binding.Z_STREAM_ERROR, - Z_DATA_ERROR: binding.Z_DATA_ERROR, - Z_MEM_ERROR: binding.Z_MEM_ERROR, - Z_BUF_ERROR: binding.Z_BUF_ERROR, - Z_VERSION_ERROR: binding.Z_VERSION_ERROR, - }; - var ckeys = Object.keys(codes); - for (ck = 0; ck < ckeys.length; ck++) { - ckey = ckeys[ck]; - codes[codes[ckey]] = ckey; - } - var ckey; - var ck; - Object.defineProperty(exports, "codes", { - enumerable: true, - value: Object.freeze(codes), - writable: false, - }); - exports.constants = require_constants(); - exports.Deflate = Deflate; - exports.Inflate = Inflate; - exports.Gzip = Gzip; - exports.Gunzip = Gunzip; - exports.DeflateRaw = DeflateRaw; - exports.InflateRaw = InflateRaw; - exports.Unzip = Unzip; - exports.createDeflate = function (o) { - return new Deflate(o); - }; - exports.createInflate = function (o) { - return new Inflate(o); - }; - exports.createDeflateRaw = function (o) { - return new DeflateRaw(o); - }; - exports.createInflateRaw = function (o) { - return new InflateRaw(o); - }; - exports.createGzip = function (o) { - return new Gzip(o); - }; - exports.createGunzip = function (o) { - return new Gunzip(o); - }; - exports.createUnzip = function (o) { - return new Unzip(o); - }; - exports.deflate = function (buffer, opts, callback) { - if (typeof opts === "function") { - callback = opts; - opts = {}; - } - return zlibBuffer(new Deflate(opts), buffer, callback); - }; - exports.deflateSync = function (buffer, opts) { - return zlibBufferSync(new Deflate(opts), buffer); - }; - exports.gzip = function (buffer, opts, callback) { - if (typeof opts === "function") { - callback = opts; - opts = {}; - } - return zlibBuffer(new Gzip(opts), buffer, callback); - }; - exports.gzipSync = function (buffer, opts) { - return zlibBufferSync(new Gzip(opts), buffer); - }; - exports.deflateRaw = function (buffer, opts, callback) { - if (typeof opts === "function") { - callback = opts; - opts = {}; - } - return zlibBuffer(new DeflateRaw(opts), buffer, callback); - }; - exports.deflateRawSync = function (buffer, opts) { - return zlibBufferSync(new DeflateRaw(opts), buffer); - }; - exports.unzip = function (buffer, opts, callback) { - if (typeof opts === "function") { - callback = opts; - opts = {}; - } - return zlibBuffer(new Unzip(opts), buffer, callback); - }; - exports.unzipSync = function (buffer, opts) { - return zlibBufferSync(new Unzip(opts), buffer); - }; - exports.inflate = function (buffer, opts, callback) { - if (typeof opts === "function") { - callback = opts; - opts = {}; - } - return zlibBuffer(new Inflate(opts), buffer, callback); - }; - exports.inflateSync = function (buffer, opts) { - return zlibBufferSync(new Inflate(opts), buffer); - }; - exports.gunzip = function (buffer, opts, callback) { - if (typeof opts === "function") { - callback = opts; - opts = {}; - } - return zlibBuffer(new Gunzip(opts), buffer, callback); - }; - exports.gunzipSync = function (buffer, opts) { - return zlibBufferSync(new Gunzip(opts), buffer); - }; - exports.inflateRaw = function (buffer, opts, callback) { - if (typeof opts === "function") { - callback = opts; - opts = {}; - } - return zlibBuffer(new InflateRaw(opts), buffer, callback); - }; - exports.inflateRawSync = function (buffer, opts) { - return zlibBufferSync(new InflateRaw(opts), buffer); - }; +function createCreator(method: number) { + const Constructor = methods[method][0]; + return function (opts) { + return new Constructor(opts); + }; +} - exports.brotliCompress = brotliCompress; - exports.brotliDecompress = brotliDecompress; - exports.brotliCompressSync = brotliCompressSync; - exports.brotliDecompressSync = brotliDecompressSync; - exports.createBrotliCompress = createBrotliCompress; - exports.BrotliCompress = BrotliCompress; - exports.createBrotliDecompress = createBrotliDecompress; - exports.BrotliDecompress = BrotliDecompress; +const functions = { + crc32: $newZigFunction("node_zlib_binding.zig", "crc32", 1), + + deflate: createConvenienceMethod(DEFLATE, false), + deflateSync: createConvenienceMethod(DEFLATE, true), + gzip: createConvenienceMethod(GZIP, false), + gzipSync: createConvenienceMethod(GZIP, true), + deflateRaw: createConvenienceMethod(DEFLATERAW, false), + deflateRawSync: createConvenienceMethod(DEFLATERAW, true), + unzip: createConvenienceMethod(UNZIP, false), + unzipSync: createConvenienceMethod(UNZIP, true), + inflate: createConvenienceMethod(INFLATE, false), + inflateSync: createConvenienceMethod(INFLATE, true), + gunzip: createConvenienceMethod(GUNZIP, false), + gunzipSync: createConvenienceMethod(GUNZIP, true), + inflateRaw: createConvenienceMethod(INFLATERAW, false), + inflateRawSync: createConvenienceMethod(INFLATERAW, true), + brotliCompress: createConvenienceMethod(BROTLI_ENCODE, false), + brotliCompressSync: createConvenienceMethod(BROTLI_ENCODE, true), + brotliDecompress: createConvenienceMethod(BROTLI_DECODE, false), + brotliDecompressSync: createConvenienceMethod(BROTLI_DECODE, true), + + createDeflate: createCreator(DEFLATE), + createInflate: createCreator(INFLATE), + createDeflateRaw: createCreator(DEFLATERAW), + createInflateRaw: createCreator(INFLATERAW), + createGzip: createCreator(GZIP), + createGunzip: createCreator(GUNZIP), + createUnzip: createCreator(UNZIP), + createBrotliCompress: createCreator(BROTLI_ENCODE), + createBrotliDecompress: createCreator(BROTLI_DECODE), +}; +for (const f in functions) { + Object.defineProperty(functions[f], "name", { + value: f, + }); +} - function zlibBuffer(engine, buffer, callback) { - var buffers = []; - var nread = 0; - engine.on("error", onError); - engine.on("end", onEnd); - engine.end(buffer); - flow(); - function flow() { - var chunk; - while (null !== (chunk = engine.read())) { - buffers.push(chunk); - nread += chunk.length; - } - engine.once("readable", flow); - } - function onError(err) { - engine.removeListener("end", onEnd); - engine.removeListener("readable", flow); - callback(err); - } - function onEnd() { - var buf; - var err = null; - if (nread >= kMaxLength) { - err = new RangeError(kRangeErrorMessage); - } else { - buf = Buffer2.concat(buffers, nread); - } - buffers = []; - engine.close(); - callback(err, buf); - } - } - function zlibBufferSync(engine, buffer) { - if (typeof buffer === "string") { - buffer = Buffer2.from(buffer); - } else if (!isArrayBufferView(buffer)) { - if (!isAnyArrayBuffer(buffer)) { - throw new ERR_INVALID_ARG_TYPE( - "buffer", - ["string", "Buffer", "TypedArray", "DataView", "ArrayBuffer"], - buffer, - ); - } - buffer = Buffer2.from(buffer); - } - var flushFlag = engine._finishFlushFlag; - return engine._processChunk(buffer, flushFlag); - } - function Deflate(opts) { - if (!(this instanceof Deflate)) return new Deflate(opts); - Zlib.$call(this, opts, binding.DEFLATE); - } - Deflate.prototype = {}; - function Inflate(opts) { - if (!(this instanceof Inflate)) return new Inflate(opts); - Zlib.$call(this, opts, binding.INFLATE); - } - Inflate.prototype = {}; - function Gzip(opts) { - if (!(this instanceof Gzip)) return new Gzip(opts); - Zlib.$call(this, opts, binding.GZIP); - } - Gzip.prototype = {}; - function Gunzip(opts) { - if (!(this instanceof Gunzip)) return new Gunzip(opts); - Zlib.$call(this, opts, binding.GUNZIP); - } - Gunzip.prototype = {}; - function DeflateRaw(opts) { - if (!(this instanceof DeflateRaw)) return new DeflateRaw(opts); - Zlib.$call(this, opts, binding.DEFLATERAW); - } - DeflateRaw.prototype = {}; - function InflateRaw(opts) { - if (!(this instanceof InflateRaw)) return new InflateRaw(opts); - Zlib.$call(this, opts, binding.INFLATERAW); - } - InflateRaw.prototype = {}; - function Unzip(opts) { - if (!(this instanceof Unzip)) return new Unzip(opts); - Zlib.$call(this, opts, binding.UNZIP); - } - Unzip.prototype = {}; - function isValidFlushFlag(flag) { - return ( - flag === binding.Z_NO_FLUSH || - flag === binding.Z_PARTIAL_FLUSH || - flag === binding.Z_SYNC_FLUSH || - flag === binding.Z_FULL_FLUSH || - flag === binding.Z_FINISH || - flag === binding.Z_BLOCK - ); - } - function Zlib(opts, mode) { - var _this = this; - this._opts = opts = opts || {}; - this._chunkSize = opts.chunkSize || exports.Z_DEFAULT_CHUNK; - Transform.$call(this, opts); - if (opts.flush && !isValidFlushFlag(opts.flush)) { - throw new Error("Invalid flush flag: " + opts.flush); - } - if (opts.finishFlush && !isValidFlushFlag(opts.finishFlush)) { - throw new Error("Invalid flush flag: " + opts.finishFlush); - } - this._flushFlag = opts.flush || binding.Z_NO_FLUSH; - this._finishFlushFlag = typeof opts.finishFlush !== "undefined" ? opts.finishFlush : binding.Z_FINISH; - if (opts.chunkSize) { - if (opts.chunkSize < exports.Z_MIN_CHUNK || opts.chunkSize > exports.Z_MAX_CHUNK) { - throw new Error("Invalid chunk size: " + opts.chunkSize); - } - } - if (opts.windowBits) { - if (opts.windowBits < exports.Z_MIN_WINDOWBITS || opts.windowBits > exports.Z_MAX_WINDOWBITS) { - throw new Error("Invalid windowBits: " + opts.windowBits); - } - } - if (opts.level) { - if (opts.level < exports.Z_MIN_LEVEL || opts.level > exports.Z_MAX_LEVEL) { - throw new Error("Invalid compression level: " + opts.level); - } - } - if (opts.memLevel) { - if (opts.memLevel < exports.Z_MIN_MEMLEVEL || opts.memLevel > exports.Z_MAX_MEMLEVEL) { - throw new Error("Invalid memLevel: " + opts.memLevel); - } - } - if (opts.strategy) { - if ( - opts.strategy != exports.Z_FILTERED && - opts.strategy != exports.Z_HUFFMAN_ONLY && - opts.strategy != exports.Z_RLE && - opts.strategy != exports.Z_FIXED && - opts.strategy != exports.Z_DEFAULT_STRATEGY - ) { - throw new Error("Invalid strategy: " + opts.strategy); - } - } - if (opts.dictionary) { - if (!Buffer2.isBuffer(opts.dictionary)) { - throw new Error("Invalid dictionary: it should be a Buffer instance"); - } - } - this._handle = new binding.Zlib(mode); - var self = this; - this._hadError = false; - this._handle.onerror = function (message, errno) { - _close(self); - self._hadError = true; - var error = new Error(message); - error.errno = errno; - error.code = exports.codes[errno]; - self.emit("error", error); - }; - var level = exports.Z_DEFAULT_COMPRESSION; - if (typeof opts.level === "number") level = opts.level; - var strategy = exports.Z_DEFAULT_STRATEGY; - if (typeof opts.strategy === "number") strategy = opts.strategy; - this._handle.init( - opts.windowBits || exports.Z_DEFAULT_WINDOWBITS, - level, - opts.memLevel || exports.Z_DEFAULT_MEMLEVEL, - strategy, - opts.dictionary, - ); - this._buffer = Buffer2.allocUnsafe(this._chunkSize); - this._offset = 0; - this._level = level; - this._strategy = strategy; - this.once("end", this.close); - Object.defineProperty(this, "_closed", { - get: function () { - return !_this._handle; - }, - configurable: true, - enumerable: true, - }); - } - Zlib.prototype = {}; - util.inherits(Zlib, Transform); - Zlib.prototype.params = function (level, strategy, callback) { - if (level < exports.Z_MIN_LEVEL || level > exports.Z_MAX_LEVEL) { - throw new RangeError("Invalid compression level: " + level); - } - if ( - strategy != exports.Z_FILTERED && - strategy != exports.Z_HUFFMAN_ONLY && - strategy != exports.Z_RLE && - strategy != exports.Z_FIXED && - strategy != exports.Z_DEFAULT_STRATEGY - ) { - throw new TypeError("Invalid strategy: " + strategy); - } - if (this._level !== level || this._strategy !== strategy) { - var self = this; - this.flush(binding.Z_SYNC_FLUSH, function () { - assert(self._handle, "zlib binding closed"); - self._handle.params(level, strategy); - if (!self._hadError) { - self._level = level; - self._strategy = strategy; - if (callback) callback(); - } - }); - } else { - process.nextTick(callback); - } - }; - Zlib.prototype.reset = function () { - assert(this._handle, "zlib binding closed"); - return this._handle.reset(); - }; - Zlib.prototype._flush = function (callback) { - this._transform(Buffer2.alloc(0), "", callback); - }; - Zlib.prototype.flush = function (kind, callback) { - var _this2 = this; - var ws = this._writableState; - if (typeof kind === "function" || (kind === void 0 && !callback)) { - callback = kind; - kind = binding.Z_FULL_FLUSH; - } - if (ws.ended) { - if (callback) process.nextTick(callback); - } else if (ws.ending) { - if (callback) this.once("end", callback); - } else if (ws.needDrain) { - if (callback) { - this.once("drain", function () { - return _this2.flush(kind, callback); - }); - } - } else { - this._flushFlag = kind; - this.write(Buffer2.alloc(0), "", callback); - } - }; - Zlib.prototype.close = function (callback) { - _close(this, callback); - process.nextTick(emitCloseNT, this); - }; - function _close(engine, callback?) { - if (callback) process.nextTick(callback); - if (!engine._handle) return; - engine._handle.close(); - engine._handle = null; - } - function emitCloseNT(self) { - self.emit("close"); - } - Zlib.prototype._transform = function (chunk, encoding, cb) { - var flushFlag; - var ws = this._writableState; - var ending = ws.ending || ws.ended; - var last = ending && (!chunk || ws.length === chunk.length); - if (chunk !== null && !Buffer2.isBuffer(chunk)) return cb(new Error("invalid input")); - if (!this._handle) return cb(new Error("zlib binding closed")); - if (last) flushFlag = this._finishFlushFlag; - else { - flushFlag = this._flushFlag; - if (chunk.length >= ws.length) { - this._flushFlag = this._opts.flush || binding.Z_NO_FLUSH; - } - } - this._processChunk(chunk, flushFlag, cb); - }; - Zlib.prototype._processChunk = function (chunk, flushFlag, cb) { - var availInBefore = chunk && chunk.length; - var availOutBefore = this._chunkSize - this._offset; - var inOff = 0; - var self = this; - var async = typeof cb === "function"; - if (!async) { - var buffers = []; - var nread = 0; - var error; - this.on("error", function (er) { - error = er; - }); - assert(this._handle, "zlib binding closed"); - do { - var res = this._handle.writeSync( - flushFlag, - chunk, - inOff, - availInBefore, - this._buffer, - this._offset, - availOutBefore, - ); - } while (!this._hadError && callback(res[0], res[1])); - if (this._hadError) { - throw error; - } - if (nread >= kMaxLength) { - _close(this); - throw new RangeError(kRangeErrorMessage); - } - var buf = Buffer2.concat(buffers, nread); - _close(this); - return buf; - } - assert(this._handle, "zlib binding closed"); - var req = this._handle.write(flushFlag, chunk, inOff, availInBefore, this._buffer, this._offset, availOutBefore); - req.buffer = chunk; - req.callback = callback; - function callback(availInAfter, availOutAfter) { - if (this) { - this.buffer = null; - this.callback = null; - } - if (self._hadError) return; - var have = availOutBefore - availOutAfter; - assert(have >= 0, "have should not go down"); - if (have > 0) { - var out = self._buffer.slice(self._offset, self._offset + have); - self._offset += have; - if (async) { - self.push(out); - } else { - buffers.push(out); - nread += out.length; - } - } - if (availOutAfter === 0 || self._offset >= self._chunkSize) { - availOutBefore = self._chunkSize; - self._offset = 0; - self._buffer = Buffer2.allocUnsafe(self._chunkSize); - } - if (availOutAfter === 0) { - inOff += availInBefore - availInAfter; - availInBefore = availInAfter; - if (!async) return true; - var newReq = self._handle.write( - flushFlag, - chunk, - inOff, - availInBefore, - self._buffer, - self._offset, - self._chunkSize, - ); - newReq.callback = callback; - newReq.buffer = chunk; - return; - } - if (!async) return false; - cb(); - } - }; - util.inherits(Deflate, Zlib); - util.inherits(Inflate, Zlib); - util.inherits(Gzip, Zlib); - util.inherits(Gunzip, Zlib); - util.inherits(DeflateRaw, Zlib); - util.inherits(InflateRaw, Zlib); - util.inherits(Unzip, Zlib); - }, +const zlib = { + Deflate, + Inflate, + Gzip, + Gunzip, + DeflateRaw, + InflateRaw, + Unzip, + BrotliCompress, + BrotliDecompress, + + ...functions, +}; +Object.defineProperty(zlib, "constants", { + writable: false, + configurable: false, + enumerable: true, + value: Object.freeze(constants), +}); +Object.defineProperty(zlib, "codes", { + writable: false, + configurable: false, + enumerable: true, + value: Object.freeze(codes), }); -function ERR_INVALID_ARG_TYPE(name, type, value) { - const err = new TypeError(`The "${name}" argument must be of type ${type}. Received ${value?.toString()}`); - err.code = "ERR_INVALID_ARG_TYPE"; - return err; -} - -// zlib.js -export default require_lib(); +export default zlib; diff --git a/src/jsc.zig b/src/jsc.zig index c10ef6f96ba60d..387894b806eb5e 100644 --- a/src/jsc.zig +++ b/src/jsc.zig @@ -51,6 +51,8 @@ pub const API = struct { pub const H2FrameParser = @import("./bun.js/api/bun/h2_frame_parser.zig").H2FrameParser; pub const BrotliEncoder = @import("./bun.js/api/js_brotli.zig").BrotliEncoder; pub const BrotliDecoder = @import("./bun.js/api/js_brotli.zig").BrotliDecoder; + pub const ZlibEncoder = @import("./bun.js/api/js_zlib.zig").ZlibEncoder; + pub const ZlibDecoder = @import("./bun.js/api/js_zlib.zig").ZlibDecoder; }; pub const Postgres = @import("./sql/postgres.zig"); pub const DNS = @import("./bun.js/api/bun/dns_resolver.zig"); diff --git a/src/shell/interpreter.zig b/src/shell/interpreter.zig index c8210534df3212..5c79f18655feed 100644 --- a/src/shell/interpreter.zig +++ b/src/shell/interpreter.zig @@ -1663,15 +1663,11 @@ pub const Interpreter = struct { fn ioToJSValue(globalThis: *JSGlobalObject, buf: *bun.ByteList) JSValue { const bytelist = buf.*; buf.* = .{}; - const value = JSC.MarkedArrayBuffer.toNodeBuffer( - .{ - .allocator = bun.default_allocator, - .buffer = JSC.ArrayBuffer.fromBytes(@constCast(bytelist.slice()), .Uint8Array), - }, - globalThis, - ); - - return value; + const buffer: JSC.Buffer = .{ + .allocator = bun.default_allocator, + .buffer = JSC.ArrayBuffer.fromBytes(@constCast(bytelist.slice()), .Uint8Array), + }; + return buffer.toNodeBuffer(globalThis); } fn asyncCmdDone(this: *ThisInterpreter, @"async": *Async) void { diff --git a/src/string.zig b/src/string.zig index f5f84a699116e0..32b7d05e62d851 100644 --- a/src/string.zig +++ b/src/string.zig @@ -592,6 +592,16 @@ pub const String = extern struct { return JSC__createError(globalObject, this); } + pub fn toTypeErrorInstance(this: *const String, globalObject: *JSC.JSGlobalObject) JSC.JSValue { + defer this.deref(); + return JSC__createTypeError(globalObject, this); + } + + pub fn toRangeErrorInstance(this: *const String, globalObject: *JSC.JSGlobalObject) JSC.JSValue { + defer this.deref(); + return JSC__createRangeError(globalObject, this); + } + extern fn BunString__createExternal( bytes: [*]const u8, len: usize, @@ -1258,6 +1268,8 @@ pub const String = extern struct { } extern fn JSC__createError(*JSC.JSGlobalObject, str: *const String) JSC.JSValue; + extern fn JSC__createTypeError(*JSC.JSGlobalObject, str: *const String) JSC.JSValue; + extern fn JSC__createRangeError(*JSC.JSGlobalObject, str: *const String) JSC.JSValue; fn concat(comptime n: usize, allocator: std.mem.Allocator, strings: *const [n]String) !String { var num_16bit: usize = 0; diff --git a/src/zlib.zig b/src/zlib.zig index b337c9b507361f..b141b9137b961d 100644 --- a/src/zlib.zig +++ b/src/zlib.zig @@ -5,9 +5,10 @@ const bun = @import("root").bun; const mimalloc = @import("./allocators/mimalloc.zig"); +pub const MIN_WBITS = 8; pub const MAX_WBITS = 15; -pub extern fn zlibVersion() [*c]const u8; +pub extern fn zlibVersion() [*:0]const u8; pub extern fn compress(dest: [*]Bytef, destLen: *uLongf, source: [*]const Bytef, sourceLen: uLong) c_int; pub extern fn compress2(dest: [*]Bytef, destLen: *uLongf, source: [*]const Bytef, sourceLen: uLong, level: c_int) c_int; @@ -37,9 +38,10 @@ const z_crc_t = c_uint; // typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); // typedef void (*free_func) OF((voidpf opaque, voidpf address)); +const internal = @import("zlib-internal"); const zStream_struct = @import("zlib-internal").zStream_struct; -const z_stream = @import("zlib-internal").z_stream; -const z_streamp = @import("zlib-internal").z_streamp; +pub const z_stream = @import("zlib-internal").z_stream; +pub const z_streamp = @import("zlib-internal").z_streamp; // typedef struct z_stream_s { // z_const Bytef *next_in; /* next input byte */ @@ -75,6 +77,24 @@ pub const ReturnCode = @import("zlib-internal").ReturnCode; pub extern fn inflateInit_(strm: z_streamp, version: [*c]const u8, stream_size: c_int) ReturnCode; pub extern fn inflateInit2_(strm: z_streamp, window_size: c_int, version: [*c]const u8, stream_size: c_int) ReturnCode; +/// Initializes the compression dictionary from the given byte sequence without producing any compressed output. This function must be called immediately after deflateInit, deflateInit2 or deflateReset, before any call of deflate. The compressor and decompressor must use exactly the same dictionary (see inflateSetDictionary). without producing any compressed output. When using the zlib format, this function must be called immediately after deflateInit, deflateInit2 or deflateReset, and before any call of deflate. When doing raw deflate, this function must be called either before any call of deflate, or immediately after the completion of a deflate block, i.e. after all input has been consumed and all output has been delivered when using any of the flush options Z_BLOCK, Z_PARTIAL_FLUSH, Z_SYNC_FLUSH, or Z_FULL_FLUSH. The compressor and decompressor must use exactly the same dictionary (see inflateSetDictionary). +/// The dictionary should consist of strings (byte sequences) that are likely to be encountered later in the data to be compressed, with the most commonly used strings preferably put towards the end of the dictionary. Using a dictionary is most useful when the data to be compressed is short and can be predicted with good accuracy; the data can then be compressed better than with the default empty dictionary. +/// +/// Depending on the size of the compression data structures selected by deflateInit or deflateInit2, a part of the dictionary may in effect be discarded, for example if the dictionary is larger than the window size in deflateInit or deflateInit2. Thus the strings most likely to be useful should be put at the end of the dictionary, not at the front. In addition, the current implementation of deflate will use at most the window size minus 262 bytes of the provided dictionary. +/// +/// Upon return of this function, strm->adler is set to the Adler-32 value of the dictionary; the decompressor may later use this value to determine which dictionary has been used by the compressor. (The Adler-32 value applies to the whole dictionary even if only a subset of the dictionary is actually used by the compressor.) If a raw deflate was requested, then the Adler-32 value is not computed and strm->adler is not set. +/// +/// deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a parameter is invalid (such as NULL dictionary) or the stream state is inconsistent (for example if deflate has already been called for this stream or if not at a block boundary for raw deflate). deflateSetDictionary does not perform any compression: this will be done by deflate(). +pub extern fn deflateSetDictionary(strm: z_streamp, dictionary: ?[*]const u8, length: c_uint) ReturnCode; + +/// Dynamically update the compression level and compression strategy. The interpretation of level and strategy is as in deflateInit2(). This can be used to switch between compression and straight copy of the input data, or to switch to a different kind of input data requiring a different strategy. If the compression approach (which is a function of the level) or the strategy is changed, and if there have been any deflate() calls since the state was initialized or reset, then the input available so far is compressed with the old level and strategy using deflate(strm, Z_BLOCK). There are three approaches for the compression levels 0, 1..3, and 4..9 respectively. The new level and strategy will take effect at the next call of deflate(). +/// If a deflate(strm, Z_BLOCK) is performed by deflateParams(), and it does not have enough output space to complete, then the parameter change will not take effect. In this case, deflateParams() can be called again with the same parameters and more output space to try again. +/// +/// In order to assure a change in the parameters on the first try, the deflate stream should be flushed using deflate() with Z_BLOCK or other flush request until strm.avail_out is not zero, before calling deflateParams(). Then no more input data should be provided before the deflateParams() call. If this is done, the old level and strategy will be applied to the data compressed before deflateParams(), and the new level and strategy will be applied to the data compressed after deflateParams(). +/// +/// deflateParams returns Z_OK on success, Z_STREAM_ERROR if the source stream state was inconsistent or if a parameter was invalid, or Z_BUF_ERROR if there was not enough output space to complete the compression of the available input data before a change in the strategy or approach. Note that in the case of a Z_BUF_ERROR, the parameters are not changed. A return value of Z_BUF_ERROR is not fatal, in which case deflateParams() can be retried with more output space. +pub extern fn deflateParams(strm: z_streamp, level: c_int, strategy: c_int) ReturnCode; + /// inflate decompresses as much data as possible, and stops when the input buffer becomes empty or the output buffer becomes full. It may introduce some output latency (reading input without producing any output) except when forced to flush. /// The detailed semantics are as follows. inflate performs one or both of the following actions: /// @@ -98,16 +118,15 @@ pub extern fn inflateInit2_(strm: z_streamp, window_size: c_int, version: [*c]co /// inflate() will decompress and check either zlib-wrapped or gzip-wrapped deflate data. The header type is detected automatically, if requested when initializing with inflateInit2(). Any information contained in the gzip header is not retained unless inflateGetHeader() is used. When processing gzip-wrapped deflate data, strm->adler32 is set to the CRC-32 of the output produced so far. The CRC-32 is checked against the gzip trailer, as is the uncompressed length, modulo 2^32. /// /// inflate() returns Z_OK if some progress has been made (more input processed or more output produced), Z_STREAM_END if the end of the compressed data has been reached and all uncompressed output has been produced, Z_NEED_DICT if a preset dictionary is needed at this point, Z_DATA_ERROR if the input data was corrupted (input stream not conforming to the zlib format or incorrect check value, in which case strm->msg points to a string with a more specific error), Z_STREAM_ERROR if the stream structure was inconsistent (for example next_in or next_out was Z_NULL, or the state was inadvertently written over by the application), Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if no progress was possible or if there was not enough room in the output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and inflate() can be called again with more input and more output space to continue decompressing. If Z_DATA_ERROR is returned, the application may then call inflateSync() to look for a good compression block if a partial recovery of the data is to be attempted. -extern fn inflate(stream: [*c]zStream_struct, flush: FlushValue) ReturnCode; +pub extern fn inflate(stream: *zStream_struct, flush: FlushValue) ReturnCode; /// inflateEnd returns Z_OK if success, or Z_STREAM_ERROR if the stream state was inconsistent. -const InflateEndResult = enum(c_int) { - Ok = 0, - StreamEnd = 1, -}; - /// All dynamically allocated data structures for this stream are freed. This function discards any unprocessed input and does not flush any pending output. -extern fn inflateEnd(stream: [*c]zStream_struct) InflateEndResult; +pub extern fn inflateEnd(stream: *zStream_struct) ReturnCode; + +pub extern fn inflateReset(stream: *zStream_struct) ReturnCode; + +pub extern fn crc32(crc: uLong, buf: [*]const Bytef, len: uInt) uLong; pub fn NewZlibReader(comptime Writer: type, comptime buffer_size: usize) type { return struct { @@ -520,7 +539,7 @@ pub const Options = struct { /// with the version assumed by the caller (ZLIB_VERSION). msg is set to null /// if there is no error message. deflateInit does not perform any compression: /// this will be done by deflate(). -extern fn deflateInit_(strm: z_stream, level: c_int, stream_size: c_int) c_int; +pub extern fn deflateInit_(strm: z_streamp, level: c_int, version: [*:0]const u8, stream_size: c_int) ReturnCode; /// /// deflate compresses as much data as possible, and stops when the input @@ -626,7 +645,7 @@ extern fn deflateInit_(strm: z_stream, level: c_int, stream_size: c_int) c_int; /// fatal, and deflate() can be called again with more input and more output /// space to continue compressing. /// -extern fn deflate(strm: z_streamp, flush: FlushValue) ReturnCode; +pub extern fn deflate(strm: z_streamp, flush: FlushValue) ReturnCode; /// /// All dynamically allocated data structures for this stream are freed. @@ -638,7 +657,9 @@ extern fn deflate(strm: z_streamp, flush: FlushValue) ReturnCode; /// prematurely (some input or output was discarded). In the error case, msg /// may be set but then points to a static string (which must not be /// deallocated). -extern fn deflateEnd(stream: z_streamp) ReturnCode; +pub extern fn deflateEnd(stream: z_streamp) ReturnCode; + +pub extern fn deflateReset(stream: z_streamp) c_int; // deflateBound() returns an upper bound on the compressed size after // deflation of sourceLen bytes. It must be called after deflateInit() or @@ -650,7 +671,7 @@ extern fn deflateEnd(stream: z_streamp) ReturnCode; // to return Z_STREAM_END. Note that it is possible for the compressed size to // be larger than the value returned by deflateBound() if flush options other // than Z_FINISH or Z_NO_FLUSH are used. -extern fn deflateBound(strm: z_streamp, sourceLen: u64) u64; +pub extern fn deflateBound(strm: z_streamp, sourceLen: u64) u64; /// /// This is another version of deflateInit with more compression options. The @@ -704,7 +725,25 @@ extern fn deflateBound(strm: z_streamp, sourceLen: u64) u64; /// incompatible with the version assumed by the caller (ZLIB_VERSION). msg is /// set to null if there is no error message. deflateInit2 does not perform any /// compression: this will be done by deflate(). -extern fn deflateInit2_(strm: z_streamp, level: c_int, method: c_int, windowBits: c_int, memLevel: c_int, strategy: c_int, version: [*c]const u8, stream_size: c_int) ReturnCode; +pub extern fn deflateInit2_(strm: z_streamp, level: c_int, method: c_int, windowBits: c_int, memLevel: c_int, strategy: c_int, version: [*c]const u8, stream_size: c_int) ReturnCode; + +/// Initializes the decompression dictionary from the given uncompressed byte sequence. This function must be called immediately after a call of inflate, if that call returned Z_NEED_DICT. The dictionary chosen by the compressor can be determined from the Adler-32 value returned by that call of inflate. The compressor and decompressor must use exactly the same dictionary (see deflateSetDictionary). For raw inflate, this function can be called at any time to set the dictionary. If the provided dictionary is smaller than the window and there is already data in the window, then the provided dictionary will amend what's there. The application must insure that the dictionary that was used for compression is provided. +/// +/// inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a parameter is invalid (such as NULL dictionary) or the stream state is inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the expected one (incorrect Adler-32 value). inflateSetDictionary does not perform any decompression: this will be done by subsequent calls of inflate(). +pub extern fn inflateSetDictionary(strm: z_streamp, dictionary: ?[*]const u8, length: c_uint) ReturnCode; + +pub const NodeMode = enum(u8) { + NONE = 0, + DEFLATE = 1, + INFLATE = 2, + GZIP = 3, + GUNZIP = 4, + DEFLATERAW = 5, + INFLATERAW = 6, + UNZIP = 7, + BROTLI_DECODE = 8, + BROTLI_ENCODE = 9, +}; /// Not for streaming! pub const ZlibCompressorArrayList = struct { @@ -901,3 +940,280 @@ pub const ZlibCompressorArrayList = struct { } } }; + +const CHUNK = 1024 * 64; + +pub const ZlibCompressorStreaming = struct { + mode: NodeMode, + state: z_stream = std.mem.zeroes(z_stream), + chunkSize: c_uint, + flush: FlushValue = .NoFlush, + finishFlush: FlushValue = .Finish, + fullFlush: FlushValue = .FullFlush, + level: c_int, + windowBits: c_int, + memLevel: c_int, + strategy: c_int, + dictionary: []const u8, + err: ReturnCode = .Ok, + err_msg: ?[*:0]const u8 = null, + + pub fn init(this: *ZlibCompressorStreaming) !void { + const ret_code = deflateInit2_(&this.state, this.level, 8, this.windowBits, this.memLevel, this.strategy, zlibVersion(), @sizeOf(z_stream)); + if (ret_code != .Ok) return error.ZlibError9; + + this.setDictionary() catch {}; + this.err_msg = null; + return; + } + + fn setDictionary(this: *ZlibCompressorStreaming) !void { + switch (this.mode) { + .DEFLATE, .DEFLATERAW => { + this.err = deflateSetDictionary(&this.state, this.dictionary.ptr, @intCast(this.dictionary.len)); + }, + .INFLATERAW => { + this.err = inflateSetDictionary(&this.state, this.dictionary.ptr, @intCast(this.dictionary.len)); + }, + else => {}, + } + if (this.err != .Ok) { + return error.ZlibFailedSetDictionary; + } + } + + pub fn params(this: *ZlibCompressorStreaming, level: c_int, strategy: c_int) void { + const err = deflateParams(&this.state, level, strategy); + bun.debugAssert(err == .Ok); + this.level = level; + this.strategy = strategy; + } + + pub fn write(this: *ZlibCompressorStreaming, bytes: []const u8, output: *std.ArrayListUnmanaged(u8), process_all_input: bool) !void { + const state = &this.state; + state.next_in = bytes.ptr; + state.avail_in = @intCast(bytes.len); + if (state.avail_in == 0) state.next_in = null; + + if (!process_all_input) return; + while (true) { + if (try this.doWork(output, this.flush)) { + break; + } + } + // bun.assert(state.avail_in == 0); + } + + pub fn doWork(this: *ZlibCompressorStreaming, output: *std.ArrayListUnmanaged(u8), flush: FlushValue) !bool { + const state = &this.state; + var out: [CHUNK]u8 = undefined; + state.avail_out = CHUNK; + state.next_out = &out; + + this.err = deflate(state, flush); + bun.assert(this.err != .StreamError); + const have = CHUNK - state.avail_out; + try output.appendSlice(bun.default_allocator, out[0..have]); + if (state.avail_out == 0) return false; + return true; + } + + pub fn end(this: *ZlibCompressorStreaming, output: *std.ArrayListUnmanaged(u8)) !void { + const state = &this.state; + state.next_in = null; + state.avail_in = 0; + + const done = try this.doWork(output, this.finishFlush); + bun.assert(done); + // bun.assert(state.avail_in == 0); + + const ret = deflateEnd(&this.state); + bun.assert(ret == .Ok or ret == .StreamEnd); + if (this.err != .StreamEnd and this.finishFlush == .Finish) return error.ZlibError10; + } +}; + +pub const ZlibDecompressorStreaming = struct { + mode: NodeMode, + state: z_stream = std.mem.zeroes(z_stream), + chunkSize: c_uint, + next_expected_header_byte: ?[*]const u8 = null, + gzip_id_bytes_read: u16 = 0, + flush: FlushValue = .NoFlush, + finishFlush: FlushValue = .Finish, + fullFlush: FlushValue = .FullFlush, + windowBits: c_int, + dictionary: []const u8, + err: ReturnCode = .Ok, + err_msg: ?[*:0]const u8 = null, + do_inflate_loop: bool = true, + + pub fn init(this: *ZlibDecompressorStreaming) !void { + const ret_code = inflateInit2_(&this.state, this.windowBits, zlibVersion(), @sizeOf(z_stream)); + if (ret_code != .Ok) return error.ZlibError1; + + this.setDictionary() catch {}; + this.err_msg = null; + return; + } + + fn setDictionary(this: *ZlibDecompressorStreaming) !void { + this.err = .Ok; + const dictionary = this.dictionary; + switch (this.mode) { + .DEFLATE, .DEFLATERAW => { + if (dictionary.len > 0) this.err = deflateSetDictionary(&this.state, dictionary.ptr, @intCast(dictionary.len)); + }, + .INFLATERAW => { + if (dictionary.len > 0) this.err = inflateSetDictionary(&this.state, dictionary.ptr, @intCast(dictionary.len)); + }, + else => {}, + } + if (this.err != .Ok) { + return this.error_for_message("Failed to set dictionary"); + } + } + + fn error_for_message(this: *ZlibDecompressorStreaming, default: [*:0]const u8) error{ZlibError} { + var message = default; + if (this.state.err_msg) |msg| message = msg; + this.err_msg = message; + return error.ZlibError; + } + + pub fn writeAll(this: *ZlibDecompressorStreaming, bytes: []const u8, output: *std.ArrayListUnmanaged(u8), process_all_input: bool) !void { + var index: usize = 0; + while (index != bytes.len) { + index += try this.write(bytes[index..], output, process_all_input); + } + } + + fn write(this: *ZlibDecompressorStreaming, bytes: []const u8, output: *std.ArrayListUnmanaged(u8), process_all_input: bool) !usize { + const state = &this.state; + state.next_in = bytes.ptr; + state.avail_in = @intCast(bytes.len); + if (state.avail_in == 0) state.next_in = null; + + // UNZIP mode allows the input to be either gzip or deflate data and we do a two-byte header detection in order to disambiguate. + // the ordering of this logic is a bit abstract because we dont know ahead of time how large 'bytes' will be. + // additionally, if the first byte is "correct" but the second is not, we don't want to lose it from it being consumed. + // Ref: https://github.com/nodejs/node/blob/v22.8.0/src/node_zlib.cc#L777 + if (this.mode == .UNZIP) { + var redd: usize = 0; + this.do_inflate_loop = false; + + if (bytes.len > 0) { + this.next_expected_header_byte = state.next_in; + } + if (this.gzip_id_bytes_read == 0) { + if (this.next_expected_header_byte == null) { + return 0; + } + + if (this.next_expected_header_byte.?[redd] == GZIP_HEADER_ID1) { + this.gzip_id_bytes_read += 1; + redd += 1; + // next_expected_header_byte++; + + if (bytes.len == 1) { + // The only available byte was already read. + return 1; + } + } else { + // the stream did not match the gzip header, bail. + this.mode = .INFLATE; + return 0; + } + } + if (this.gzip_id_bytes_read == 1) { + if (this.next_expected_header_byte == null) { + return 0; + } + + if (this.next_expected_header_byte.?[redd] == GZIP_HEADER_ID2) { + this.gzip_id_bytes_read += 1; + redd += 1; + // next_expected_header_byte++; + + // the gzip header was found. send the header to inflate() and tell writeAll how much we read to do this detection + // if we continued to doWork right now GZIP_HEADER_ID2 might get processed twice. + this.mode = .GUNZIP; + { + const header = &[_]u8{ GZIP_HEADER_ID1, GZIP_HEADER_ID2 }; + state.next_in = header.ptr; + state.avail_in = @intCast(header.len); + var out: [1]u8 = .{0}; + state.avail_out = 0; + state.next_out = &out; // passing a null pointer here causes it to return Z_STREAM_ERROR so we send zero-length instead. + const ret = inflate(state, this.flush); + bun.assert(ret == .Ok); + } + } else { + // There is no actual difference between INFLATE and INFLATERAW (after initialization). + // the stream only partially matched the gzip header, bail. + this.mode = .INFLATE; + } + return redd; + } + + bun.assert(false); // invalid number of gzip magic number bytes read + } + + // we're passed the header or there was no header. it is now safe to send everying to inflate(). + this.do_inflate_loop = true; + if (!process_all_input) return bytes.len; + while (true) { + if (try this.doWork(output, this.flush)) { + break; + } + } + // bun.assert(state.avail_in == 0); + + return bytes.len; + } + + pub fn doWork(this: *ZlibDecompressorStreaming, output: *std.ArrayListUnmanaged(u8), flush: FlushValue) !bool { + const state = &this.state; + var out: [CHUNK]u8 = undefined; + const len = @min(CHUNK, this.chunkSize); + state.avail_out = len; + state.next_out = &out; + + this.err = inflate(state, flush); + const ret = this.err; + bun.assert(ret != .StreamError); + if (ret == .NeedDict) return this.error_for_message((if (this.dictionary.len == 0) "Missing dictionary" else "Bad dictionary").ptr); + if (ret == .DataError) return this.error_for_message("Zlib error"); + if (ret == .MemError) return error.ZlibError4; + const have = len - state.avail_out; + try output.appendSlice(bun.default_allocator, out[0..have]); + if (ret == .StreamEnd and this.mode == .GUNZIP and state.avail_in > 0 and state.next_in.?[0] != 0) { + _ = inflateReset(state); + return false; + } + if (ret == .StreamEnd) return true; + if (state.avail_out == 0) return false; + if (ret == .BufError and flush == .Finish) return this.error_for_message("unexpected end of file"); + return true; + } + + pub fn end(this: *ZlibDecompressorStreaming, output: *std.ArrayListUnmanaged(u8)) !void { + const state = &this.state; + state.next_in = null; + state.avail_in = 0; + + const done = try this.doWork(output, this.finishFlush); + bun.assert(done); + // bun.assert(state.avail_in == 0); + + const ret = inflateEnd(&this.state); + bun.assert(ret == .Ok or ret == .StreamEnd); + if (this.err != .StreamEnd and this.finishFlush == .Finish) return error.ZlibError8; + } +}; + +// +// + +const GZIP_HEADER_ID1: u8 = 0x1f; +const GZIP_HEADER_ID2: u8 = 0x8b; diff --git a/test/js/node/http/node-http.test.ts b/test/js/node/http/node-http.test.ts index fd55bf53ef5711..d36b2bc05a4c21 100644 --- a/test/js/node/http/node-http.test.ts +++ b/test/js/node/http/node-http.test.ts @@ -1139,14 +1139,14 @@ describe("node:http", () => { const server = createServer((req, res) => { res.end(); }); - server.listen({ port: 42069 }, () => { + server.listen({ port: 0 }, () => { const server2 = createServer((_, res) => { res.end(); }); server2.on("error", err => { resolve(err); }); - server2.listen({ port: 42069 }, () => {}); + server2.listen({ port: server.address().port }, () => {}); }); const err = await promise; expect(err.code).toBe("EADDRINUSE"); diff --git a/test/js/node/test/parallel/zlib-brotli.test.js b/test/js/node/test/parallel/zlib-brotli.test.js new file mode 100644 index 00000000000000..e97933cab87367 --- /dev/null +++ b/test/js/node/test/parallel/zlib-brotli.test.js @@ -0,0 +1,101 @@ +//#FILE: test-zlib-brotli.js +//#SHA1: 53d893f351dd67279a8561e244183e38864c0c92 +//----------------- +"use strict"; + +const fixtures = require("../common/fixtures"); +const zlib = require("zlib"); + +// Test some brotli-specific properties of the brotli streams that can not +// be easily covered through expanding zlib-only tests. + +const sampleBuffer = fixtures.readSync("/pss-vectors.json"); + +test("Quality parameter at stream creation", () => { + const sizes = []; + for (let quality = zlib.constants.BROTLI_MIN_QUALITY; quality <= zlib.constants.BROTLI_MAX_QUALITY; quality++) { + const encoded = zlib.brotliCompressSync(sampleBuffer, { + params: { + [zlib.constants.BROTLI_PARAM_QUALITY]: quality, + }, + }); + sizes.push(encoded.length); + } + + // Increasing quality should roughly correspond to decreasing compressed size: + for (let i = 0; i < sizes.length - 1; i++) { + expect(sizes[i + 1]).toBeLessThanOrEqual(sizes[i] * 1.05); // 5 % margin of error. + } + expect(sizes[0]).toBeGreaterThan(sizes[sizes.length - 1]); +}); + +test("Setting out-of-bounds option values or keys", () => { + // expect(() => { + // zlib.createBrotliCompress({ + // params: { + // 10000: 0, + // }, + // }); + // }).toThrow( + // expect.objectContaining({ + // code: "ERR_BROTLI_INVALID_PARAM", + // name: "RangeError", + // message: expect.any(String), + // }), + // ); + + // Test that accidentally using duplicate keys fails. + // expect(() => { + // zlib.createBrotliCompress({ + // params: { + // 0: 0, + // "00": 0, + // }, + // }); + // }).toThrow( + // expect.objectContaining({ + // code: "ERR_BROTLI_INVALID_PARAM", + // name: "RangeError", + // message: expect.any(String), + // }), + // ); + + expect(() => { + zlib.createBrotliCompress({ + params: { + // This is a boolean flag + [zlib.constants.BROTLI_PARAM_DISABLE_LITERAL_CONTEXT_MODELING]: 42, + }, + }); + }).toThrow( + expect.objectContaining({ + code: "ERR_ZLIB_INITIALIZATION_FAILED", + name: "Error", + message: expect.any(String), + }), + ); +}); + +test("Options.flush range", () => { + expect(() => { + zlib.brotliCompressSync("", { flush: zlib.constants.Z_FINISH }); + }).toThrow( + expect.objectContaining({ + code: "ERR_OUT_OF_RANGE", + name: "RangeError", + message: expect.any(String), + }), + ); + + expect(() => { + zlib.brotliCompressSync("", { finishFlush: zlib.constants.Z_FINISH }); + }).toThrow( + expect.objectContaining({ + code: "ERR_OUT_OF_RANGE", + name: "RangeError", + message: expect.any(String), + }), + ); +}); + +//<#END_FILE: test-zlib-brotli.js diff --git a/test/js/node/test/parallel/zlib-const.test.js b/test/js/node/test/parallel/zlib-const.test.js new file mode 100644 index 00000000000000..a81535e446e6b8 --- /dev/null +++ b/test/js/node/test/parallel/zlib-const.test.js @@ -0,0 +1,23 @@ +//#FILE: test-zlib-const.js +//#SHA1: d85ad9e395d5781dbe5bf05e5514104bd9503be8 +//----------------- +const zlib = require("zlib"); + +test("zlib constants and codes are immutable", () => { + // Test Z_OK constant + expect(zlib.constants.Z_OK).toBe(0); + zlib.constants.Z_OK = 1; + expect(zlib.constants.Z_OK).toBe(0); + + // Test Z_OK code + expect(zlib.codes.Z_OK).toBe(0); + zlib.codes.Z_OK = 1; + expect(zlib.codes.Z_OK).toBe(0); + zlib.codes = { Z_OK: 1 }; + expect(zlib.codes.Z_OK).toBe(0); + + // Test if zlib.codes is frozen + expect(Object.isFrozen(zlib.codes)).toBe(true); +}); + +//<#END_FILE: test-zlib-const.js diff --git a/test/js/node/test/parallel/zlib-crc32.test.js b/test/js/node/test/parallel/zlib-crc32.test.js new file mode 100644 index 00000000000000..5c1e51b63ae359 --- /dev/null +++ b/test/js/node/test/parallel/zlib-crc32.test.js @@ -0,0 +1,249 @@ +//#FILE: test-zlib-crc32.js +//#SHA1: a46ac98c5c568eec892b62f9da1effc368081b07 +//----------------- +"use strict"; + +const zlib = require("zlib"); +const { Buffer } = require("buffer"); + +// The following test data comes from +// https://github.com/zlib-ng/zlib-ng/blob/5401b24/test/test_crc32.cc +// test_crc32.cc -- crc32 unit test +// Copyright (C) 2019-2021 IBM Corporation +// Authors: Rogerio Alves +// Matheus Castanho +// For conditions of distribution and use, see copyright notice in zlib.h +// +const tests = [ + [0x0, 0x0, 0, 0x0], + [0xffffffff, 0x0, 0, 0x0], + [0x0, 0x0, 255, 0x0] /* BZ 174799. */, + [0x0, 0x0, 256, 0x0], + [0x0, 0x0, 257, 0x0], + [0x0, 0x0, 32767, 0x0], + [0x0, 0x0, 32768, 0x0], + [0x0, 0x0, 32769, 0x0], + [0x0, "", 0, 0x0], + [0xffffffff, "", 0, 0xffffffff], + [0x0, "abacus", 6, 0xc3d7115b], + [0x0, "backlog", 7, 0x269205], + [0x0, "campfire", 8, 0x22a515f8], + [0x0, "delta", 5, 0x9643fed9], + [0x0, "executable", 10, 0xd68eda01], + [0x0, "file", 4, 0x8c9f3610], + [0x0, "greatest", 8, 0xc1abd6cd], + [0x0, "hello", 5, 0x3610a686], + [0x0, "inverter", 8, 0xc9e962c9], + [0x0, "jigsaw", 6, 0xce4e3f69], + [0x0, "karate", 6, 0x890be0e2], + [0x0, "landscape", 9, 0xc4e0330b], + [0x0, "machine", 7, 0x1505df84], + [0x0, "nanometer", 9, 0xd4e19f39], + [0x0, "oblivion", 8, 0xdae9de77], + [0x0, "panama", 6, 0x66b8979c], + [0x0, "quest", 5, 0x4317f817], + [0x0, "resource", 8, 0xbc91f416], + [0x0, "secret", 6, 0x5ca2e8e5], + [0x0, "test", 4, 0xd87f7e0c], + [0x0, "ultimate", 8, 0x3fc79b0b], + [0x0, "vector", 6, 0x1b6e485b], + [0x0, "walrus", 6, 0xbe769b97], + [0x0, "xeno", 4, 0xe7a06444], + [0x0, "yelling", 7, 0xfe3944e5], + [0x0, "zlib", 4, 0x73887d3a], + [0x0, "4BJD7PocN1VqX0jXVpWB", 20, 0xd487a5a1], + [0x0, "F1rPWI7XvDs6nAIRx41l", 20, 0x61a0132e], + [0x0, "ldhKlsVkPFOveXgkGtC2", 20, 0xdf02f76], + [0x0, "5KKnGOOrs8BvJ35iKTOS", 20, 0x579b2b0a], + [0x0, "0l1tw7GOcem06Ddu7yn4", 20, 0xf7d16e2d], + [0x0, "MCr47CjPIn9R1IvE1Tm5", 20, 0x731788f5], + [0x0, "UcixbzPKTIv0SvILHVdO", 20, 0x7112bb11], + [0x0, "dGnAyAhRQDsWw0ESou24", 20, 0xf32a0dac], + [0x0, "di0nvmY9UYMYDh0r45XT", 20, 0x625437bb], + [0x0, "2XKDwHfAhFsV0RhbqtvH", 20, 0x896930f9], + [0x0, "ZhrANFIiIvRnqClIVyeD", 20, 0x8579a37], + [0x0, "v7Q9ehzioTOVeDIZioT1", 20, 0x632aa8e0], + [0x0, "Yod5hEeKcYqyhfXbhxj2", 20, 0xc829af29], + [0x0, "GehSWY2ay4uUKhehXYb0", 20, 0x1b08b7e8], + [0x0, "kwytJmq6UqpflV8Y8GoE", 20, 0x4e33b192], + [0x0, "70684206568419061514", 20, 0x59a179f0], + [0x0, "42015093765128581010", 20, 0xcd1013d7], + [0x0, "88214814356148806939", 20, 0xab927546], + [0x0, "43472694284527343838", 20, 0x11f3b20c], + [0x0, "49769333513942933689", 20, 0xd562d4ca], + [0x0, "54979784887993251199", 20, 0x233395f7], + [0x0, "58360544869206793220", 20, 0x2d167fd5], + [0x0, "27347953487840714234", 20, 0x8b5108ba], + [0x0, "07650690295365319082", 20, 0xc46b3cd8], + [0x0, "42655507906821911703", 20, 0xc10b2662], + [0x0, "29977409200786225655", 20, 0xc9a0f9d2], + [0x0, "85181542907229116674", 20, 0x9341357b], + [0x0, "87963594337989416799", 20, 0xf0424937], + [0x0, "21395988329504168551", 20, 0xd7c4c31f], + [0x0, "51991013580943379423", 20, 0xf11edcc4], + [0x0, "*]+@!);({_$;}[_},?{?;(_?,=-][@", 30, 0x40795df4], + [0x0, "_@:_).&(#.[:[{[:)$++-($_;@[)}+", 30, 0xdd61a631], + [0x0, "&[!,[$_==}+.]@!;*(+},[;:)$;)-@", 30, 0xca907a99], + [0x0, "]{.[.+?+[[=;[?}_#&;[=)__$$:+=_", 30, 0xf652deac], + [0x0, "-%.)=/[@].:.(:,()$;=%@-$?]{%+%", 30, 0xaf39a5a9], + [0x0, "+]#$(@&.=:,*];/.!]%/{:){:@(;)$", 30, 0x6bebb4cf], + // eslint-disable-next-line no-template-curly-in-string + [0x0, ")-._.:?[&:.=+}(*$/=!.${;(=$@!}", 30, 0x76430bac], + [0x0, ":(_*&%/[[}+,?#$&*+#[([*-/#;%(]", 30, 0x6c80c388], + [0x0, "{[#-;:$/{)(+[}#]/{&!%(@)%:@-$:", 30, 0xd54d977d], + [0x0, "_{$*,}(&,@.)):=!/%(&(,,-?$}}}!", 30, 0xe3966ad5], + [ + 0x0, + "e$98KNzqaV)Y:2X?]77].{gKRD4G5{mHZk,Z)SpU%L3FSgv!Wb8MLAFdi{+fp)c,@8m6v)yXg@]HBDFk?.4&}g5_udE*JHCiH=aL", + 100, + 0xe7c71db9, + ], + [ + 0x0, + "r*Fd}ef+5RJQ;+W=4jTR9)R*p!B;]Ed7tkrLi;88U7g@3v!5pk2X6D)vt,.@N8c]@yyEcKi[vwUu@.Ppm@C6%Mv*3Nw}Y,58_aH)", + 100, + 0xeaa52777, + ], + [ + 0x0, + "h{bcmdC+a;t+Cf{6Y_dFq-{X4Yu&7uNfVDh?q&_u.UWJU],-GiH7ADzb7-V.Q%4=+v!$L9W+T=bP]$_:]Vyg}A.ygD.r;h-D]m%&", + 100, + 0xcd472048, + ], + [0x7a30360d, "abacus", 6, 0xf8655a84], + [0x6fd767ee, "backlog", 7, 0x1ed834b1], + [0xefeb7589, "campfire", 8, 0x686cfca], + [0x61cf7e6b, "delta", 5, 0x1554e4b1], + [0xdc712e2, "executable", 10, 0x761b4254], + [0xad23c7fd, "file", 4, 0x7abdd09b], + [0x85cb2317, "greatest", 8, 0x4ba91c6b], + [0x9eed31b0, "inverter", 8, 0xd5e78ba5], + [0xb94f34ca, "jigsaw", 6, 0x23649109], + [0xab058a2, "karate", 6, 0xc5591f41], + [0x5bff2b7a, "landscape", 9, 0xf10eb644], + [0x605c9a5f, "machine", 7, 0xbaa0a636], + [0x51bdeea5, "nanometer", 9, 0x6af89afb], + [0x85c21c79, "oblivion", 8, 0xecae222b], + [0x97216f56, "panama", 6, 0x47dffac4], + [0x18444af2, "quest", 5, 0x70c2fe36], + [0xbe6ce359, "resource", 8, 0x1471d925], + [0x843071f1, "secret", 6, 0x50c9a0db], + [0xf2480c60, "ultimate", 8, 0xf973daf8], + [0x2d2feb3d, "vector", 6, 0x344ac03d], + [0x7490310a, "walrus", 6, 0x6d1408ef], + [0x97d247d4, "xeno", 4, 0xe62670b5], + [0x93cf7599, "yelling", 7, 0x1b36da38], + [0x73c84278, "zlib", 4, 0x6432d127], + [0x228a87d1, "4BJD7PocN1VqX0jXVpWB", 20, 0x997107d0], + [0xa7a048d0, "F1rPWI7XvDs6nAIRx41l", 20, 0xdc567274], + [0x1f0ded40, "ldhKlsVkPFOveXgkGtC2", 20, 0xdcc63870], + [0xa804a62f, "5KKnGOOrs8BvJ35iKTOS", 20, 0x6926cffd], + [0x508fae6a, "0l1tw7GOcem06Ddu7yn4", 20, 0xb52b38bc], + [0xe5adaf4f, "MCr47CjPIn9R1IvE1Tm5", 20, 0xf83b8178], + [0x67136a40, "UcixbzPKTIv0SvILHVdO", 20, 0xc5213070], + [0xb00c4a10, "dGnAyAhRQDsWw0ESou24", 20, 0xbc7648b0], + [0x2e0c84b5, "di0nvmY9UYMYDh0r45XT", 20, 0xd8123a72], + [0x81238d44, "2XKDwHfAhFsV0RhbqtvH", 20, 0xd5ac5620], + [0xf853aa92, "ZhrANFIiIvRnqClIVyeD", 20, 0xceae099d], + [0x5a692325, "v7Q9ehzioTOVeDIZioT1", 20, 0xb07d2b24], + [0x3275b9f, "Yod5hEeKcYqyhfXbhxj2", 20, 0x24ce91df], + [0x38371feb, "GehSWY2ay4uUKhehXYb0", 20, 0x707b3b30], + [0xafc8bf62, "kwytJmq6UqpflV8Y8GoE", 20, 0x16abc6a9], + [0x9b07db73, "70684206568419061514", 20, 0xae1fb7b7], + [0xe75b214, "42015093765128581010", 20, 0xd4eecd2d], + [0x72d0fe6f, "88214814356148806939", 20, 0x4660ec7], + [0xf857a4b1, "43472694284527343838", 20, 0xfd8afdf7], + [0x54b8e14, "49769333513942933689", 20, 0xc6d1b5f2], + [0xd6aa5616, "54979784887993251199", 20, 0x32476461], + [0x11e63098, "58360544869206793220", 20, 0xd917cf1a], + [0xbe92385, "27347953487840714234", 20, 0x4ad14a12], + [0x49511de0, "07650690295365319082", 20, 0xe37b5c6c], + [0x3db13bc1, "42655507906821911703", 20, 0x7cc497f1], + [0xbb899bea, "29977409200786225655", 20, 0x99781bb2], + [0xf6cd9436, "85181542907229116674", 20, 0x132256a1], + [0x9109e6c3, "87963594337989416799", 20, 0xbfdb2c83], + [0x75770fc, "21395988329504168551", 20, 0x8d9d1e81], + [0x69b1d19b, "51991013580943379423", 20, 0x7b6d4404], + [0xc6132975, "*]+@!);({_$;}[_},?{?;(_?,=-][@", 30, 0x8619f010], + [0xd58cb00c, "_@:_).&(#.[:[{[:)$++-($_;@[)}+", 30, 0x15746ac3], + [0xb63b8caa, "&[!,[$_==}+.]@!;*(+},[;:)$;)-@", 30, 0xaccf812f], + [0x8a45a2b8, "]{.[.+?+[[=;[?}_#&;[=)__$$:+=_", 30, 0x78af45de], + [0xcbe95b78, "-%.)=/[@].:.(:,()$;=%@-$?]{%+%", 30, 0x25b06b59], + [0x4ef8a54b, "+]#$(@&.=:,*];/.!]%/{:){:@(;)$", 30, 0x4ba0d08f], + // eslint-disable-next-line no-template-curly-in-string + [0x76ad267a, ")-._.:?[&:.=+}(*$/=!.${;(=$@!}", 30, 0xe26b6aac], + [0x569e613c, ":(_*&%/[[}+,?#$&*+#[([*-/#;%(]", 30, 0x7e2b0a66], + [0x36aa61da, "{[#-;:$/{)(+[}#]/{&!%(@)%:@-$:", 30, 0xb3430dc7], + [0xf67222df, "_{$*,}(&,@.)):=!/%(&(,,-?$}}}!", 30, 0x626c17a], + [ + 0x74b34fd3, + "e$98KNzqaV)Y:2X?]77].{gKRD4G5{mHZk,Z)SpU%L3FSgv!Wb8MLAFdi{+fp)c,@8m6v)yXg@]HBDFk?.4&}g5_udE*JHCiH=aL", + 100, + 0xccf98060, + ], + [ + 0x351fd770, + "r*Fd}ef+5RJQ;+W=4jTR9)R*p!B;]Ed7tkrLi;88U7g@3v!5pk2X6D)vt,.@N8c]@yyEcKi[vwUu@.Ppm@C6%Mv*3Nw}Y,58_aH)", + 100, + 0xd8b95312, + ], + [ + 0xc45aef77, + "h{bcmdC+a;t+Cf{6Y_dFq-{X4Yu&7uNfVDh?q&_u.UWJU],-GiH7ADzb7-V.Q%4=+v!$L9W+T=bP]$_:]Vyg}A.ygD.r;h-D]m%&", + 100, + 0xbb1c9912, + ], + [ + 0xc45aef77, + "h{bcmdC+a;t+Cf{6Y_dFq-{X4Yu&7uNfVDh?q&_u.UWJU],-GiH7ADzb7-V.Q%4=+v!$L9W+T=bP]$_:]Vyg}A.ygD.r;h-D]m%&" + + "h{bcmdC+a;t+Cf{6Y_dFq-{X4Yu&7uNfVDh?q&_u.UWJU],-GiH7ADzb7-V.Q%4=+v!$L9W+T=bP]$_:]Vyg}A.ygD.r;h-D]m%&" + + "h{bcmdC+a;t+Cf{6Y_dFq-{X4Yu&7uNfVDh?q&_u.UWJU],-GiH7ADzb7-V.Q%4=+v!$L9W+T=bP]$_:]Vyg}A.ygD.r;h-D]m%&" + + "h{bcmdC+a;t+Cf{6Y_dFq-{X4Yu&7uNfVDh?q&_u.UWJU],-GiH7ADzb7-V.Q%4=+v!$L9W+T=bP]$_:]Vyg}A.ygD.r;h-D]m%&" + + "h{bcmdC+a;t+Cf{6Y_dFq-{X4Yu&7uNfVDh?q&_u.UWJU],-GiH7ADzb7-V.Q%4=+v!$L9W+T=bP]$_:]Vyg}A.ygD.r;h-D]m%&" + + "h{bcmdC+a;t+Cf{6Y_dFq-{X4Yu&7uNfVDh?q&_u.UWJU],-GiH7ADzb7-V.Q%4=+v!$L9W+T=bP]$_:]Vyg}A.ygD.r;h-D]m%&", + 600, + 0x888afa5b, + ], +]; + +describe("zlib.crc32", () => { + test("crc32 test case", () => { + for (const [crc, data, len, expected] of tests) { + if (data === 0) { + return; + } + const buf = Buffer.from(data, "utf8"); + expect(buf.length).toBe(len); + expect(zlib.crc32(buf, crc)).toBe(expected); + expect(zlib.crc32(buf.toString(), crc)).toBe(expected); + if (crc === 0) { + expect(zlib.crc32(buf)).toBe(expected); + expect(zlib.crc32(buf.toString())).toBe(expected); + } + } + }); + + test("invalid input types", () => { + [undefined, null, true, 1, () => {}, {}].forEach(invalid => { + expect(() => zlib.crc32(invalid)).toThrow( + expect.objectContaining({ + code: "ERR_INVALID_ARG_TYPE", + message: expect.any(String), + }), + ); + }); + }); + + test("invalid crc types", () => { + [null, true, () => {}, {}].forEach(invalid => { + expect(() => zlib.crc32("test", invalid)).toThrow( + expect.objectContaining({ + code: "ERR_INVALID_ARG_TYPE", + message: expect.any(String), + }), + ); + }); + }); +}); + +//<#END_FILE: test-zlib-crc32.js diff --git a/test/js/node/test/parallel/zlib-deflate-constructors.test.js b/test/js/node/test/parallel/zlib-deflate-constructors.test.js new file mode 100644 index 00000000000000..d9a0411de2771a --- /dev/null +++ b/test/js/node/test/parallel/zlib-deflate-constructors.test.js @@ -0,0 +1,281 @@ +//#FILE: test-zlib-deflate-constructors.js +//#SHA1: fdacb219f8fcceeeb4800473b37fca16fcf4c241 +//----------------- +"use strict"; + +const zlib = require("zlib"); + +// Work with and without `new` keyword +test("Deflate constructor works with and without new keyword", () => { + expect(zlib.Deflate()).toBeInstanceOf(zlib.Deflate); + expect(new zlib.Deflate()).toBeInstanceOf(zlib.Deflate); +}); + +test("DeflateRaw constructor works with and without new keyword", () => { + expect(zlib.DeflateRaw()).toBeInstanceOf(zlib.DeflateRaw); + expect(new zlib.DeflateRaw()).toBeInstanceOf(zlib.DeflateRaw); +}); + +// Throws if `options.chunkSize` is invalid +test("Deflate constructor throws for invalid chunkSize", () => { + expect(() => new zlib.Deflate({ chunkSize: "test" })).toThrow( + expect.objectContaining({ + code: "ERR_INVALID_ARG_TYPE", + name: "TypeError", + message: expect.any(String), + }), + ); + + expect(() => new zlib.Deflate({ chunkSize: -Infinity })).toThrow( + expect.objectContaining({ + code: "ERR_OUT_OF_RANGE", + name: "RangeError", + message: expect.any(String), + }), + ); + + expect(() => new zlib.Deflate({ chunkSize: 0 })).toThrow( + expect.objectContaining({ + code: "ERR_OUT_OF_RANGE", + name: "RangeError", + message: expect.any(String), + }), + ); +}); + +// Confirm that maximum chunk size cannot be exceeded because it is `Infinity`. +test("Z_MAX_CHUNK is Infinity", () => { + expect(zlib.constants.Z_MAX_CHUNK).toBe(Infinity); +}); + +// Throws if `options.windowBits` is invalid +test("Deflate constructor throws for invalid windowBits", () => { + expect(() => new zlib.Deflate({ windowBits: "test" })).toThrow( + expect.objectContaining({ + code: "ERR_INVALID_ARG_TYPE", + name: "TypeError", + message: expect.any(String), + }), + ); + + expect(() => new zlib.Deflate({ windowBits: -Infinity })).toThrow( + expect.objectContaining({ + code: "ERR_OUT_OF_RANGE", + name: "RangeError", + message: expect.any(String), + }), + ); + + expect(() => new zlib.Deflate({ windowBits: Infinity })).toThrow( + expect.objectContaining({ + code: "ERR_OUT_OF_RANGE", + name: "RangeError", + message: expect.any(String), + }), + ); + + expect(() => new zlib.Deflate({ windowBits: 0 })).toThrow( + expect.objectContaining({ + code: "ERR_OUT_OF_RANGE", + name: "RangeError", + message: expect.any(String), + }), + ); +}); + +// Throws if `options.level` is invalid +test("Deflate constructor throws for invalid level", () => { + expect(() => new zlib.Deflate({ level: "test" })).toThrow( + expect.objectContaining({ + code: "ERR_INVALID_ARG_TYPE", + name: "TypeError", + message: expect.any(String), + }), + ); + + expect(() => new zlib.Deflate({ level: -Infinity })).toThrow( + expect.objectContaining({ + code: "ERR_OUT_OF_RANGE", + name: "RangeError", + message: expect.any(String), + }), + ); + + expect(() => new zlib.Deflate({ level: Infinity })).toThrow( + expect.objectContaining({ + code: "ERR_OUT_OF_RANGE", + name: "RangeError", + message: expect.any(String), + }), + ); + + expect(() => new zlib.Deflate({ level: -2 })).toThrow( + expect.objectContaining({ + code: "ERR_OUT_OF_RANGE", + name: "RangeError", + message: expect.any(String), + }), + ); +}); + +// Throws if `level` invalid in `Deflate.prototype.params()` +test("Deflate.prototype.params throws for invalid level", () => { + expect(() => new zlib.Deflate().params("test")).toThrow( + expect.objectContaining({ + code: "ERR_INVALID_ARG_TYPE", + name: "TypeError", + message: expect.any(String), + }), + ); + + expect(() => new zlib.Deflate().params(-Infinity)).toThrow( + expect.objectContaining({ + code: "ERR_OUT_OF_RANGE", + name: "RangeError", + message: expect.any(String), + }), + ); + + expect(() => new zlib.Deflate().params(Infinity)).toThrow( + expect.objectContaining({ + code: "ERR_OUT_OF_RANGE", + name: "RangeError", + message: expect.any(String), + }), + ); + + expect(() => new zlib.Deflate().params(-2)).toThrow( + expect.objectContaining({ + code: "ERR_OUT_OF_RANGE", + name: "RangeError", + message: expect.any(String), + }), + ); +}); + +// Throws if options.memLevel is invalid +test("Deflate constructor throws for invalid memLevel", () => { + expect(() => new zlib.Deflate({ memLevel: "test" })).toThrow( + expect.objectContaining({ + code: "ERR_INVALID_ARG_TYPE", + name: "TypeError", + message: expect.any(String), + }), + ); + + expect(() => new zlib.Deflate({ memLevel: -Infinity })).toThrow( + expect.objectContaining({ + code: "ERR_OUT_OF_RANGE", + name: "RangeError", + message: expect.any(String), + }), + ); + + expect(() => new zlib.Deflate({ memLevel: Infinity })).toThrow( + expect.objectContaining({ + code: "ERR_OUT_OF_RANGE", + name: "RangeError", + message: expect.any(String), + }), + ); + + expect(() => new zlib.Deflate({ memLevel: -2 })).toThrow( + expect.objectContaining({ + code: "ERR_OUT_OF_RANGE", + name: "RangeError", + message: expect.any(String), + }), + ); +}); + +// Does not throw if opts.strategy is valid +test("Deflate constructor does not throw for valid strategy", () => { + expect(() => new zlib.Deflate({ strategy: zlib.constants.Z_FILTERED })).not.toThrow(); + expect(() => new zlib.Deflate({ strategy: zlib.constants.Z_HUFFMAN_ONLY })).not.toThrow(); + expect(() => new zlib.Deflate({ strategy: zlib.constants.Z_RLE })).not.toThrow(); + expect(() => new zlib.Deflate({ strategy: zlib.constants.Z_FIXED })).not.toThrow(); + expect(() => new zlib.Deflate({ strategy: zlib.constants.Z_DEFAULT_STRATEGY })).not.toThrow(); +}); + +// Throws if options.strategy is invalid +test("Deflate constructor throws for invalid strategy", () => { + expect(() => new zlib.Deflate({ strategy: "test" })).toThrow( + expect.objectContaining({ + code: "ERR_INVALID_ARG_TYPE", + name: "TypeError", + message: expect.any(String), + }), + ); + + expect(() => new zlib.Deflate({ strategy: -Infinity })).toThrow( + expect.objectContaining({ + code: "ERR_OUT_OF_RANGE", + name: "RangeError", + message: expect.any(String), + }), + ); + + expect(() => new zlib.Deflate({ strategy: Infinity })).toThrow( + expect.objectContaining({ + code: "ERR_OUT_OF_RANGE", + name: "RangeError", + message: expect.any(String), + }), + ); + + expect(() => new zlib.Deflate({ strategy: -2 })).toThrow( + expect.objectContaining({ + code: "ERR_OUT_OF_RANGE", + name: "RangeError", + message: expect.any(String), + }), + ); +}); + +// Throws TypeError if `strategy` is invalid in `Deflate.prototype.params()` +test("Deflate.prototype.params throws for invalid strategy", () => { + expect(() => new zlib.Deflate().params(0, "test")).toThrow( + expect.objectContaining({ + code: "ERR_INVALID_ARG_TYPE", + name: "TypeError", + message: expect.any(String), + }), + ); + + expect(() => new zlib.Deflate().params(0, -Infinity)).toThrow( + expect.objectContaining({ + code: "ERR_OUT_OF_RANGE", + name: "RangeError", + message: expect.any(String), + }), + ); + + expect(() => new zlib.Deflate().params(0, Infinity)).toThrow( + expect.objectContaining({ + code: "ERR_OUT_OF_RANGE", + name: "RangeError", + message: expect.any(String), + }), + ); + + expect(() => new zlib.Deflate().params(0, -2)).toThrow( + expect.objectContaining({ + code: "ERR_OUT_OF_RANGE", + name: "RangeError", + message: expect.any(String), + }), + ); +}); + +// Throws if opts.dictionary is not a Buffer +test("Deflate constructor throws if dictionary is not a Buffer", () => { + expect(() => new zlib.Deflate({ dictionary: "not a buffer" })).toThrow( + expect.objectContaining({ + code: "ERR_INVALID_ARG_TYPE", + name: "TypeError", + message: expect.any(String), + }), + ); +}); + +//<#END_FILE: test-zlib-deflate-constructors.js diff --git a/test/js/node/test/parallel/zlib-failed-init.test.js b/test/js/node/test/parallel/zlib-failed-init.test.js new file mode 100644 index 00000000000000..6eb2bb2b44e136 --- /dev/null +++ b/test/js/node/test/parallel/zlib-failed-init.test.js @@ -0,0 +1,48 @@ +//#FILE: test-zlib-failed-init.js +//#SHA1: a1c770e81c677ebefa0e5969e3441b28e63ab75a +//----------------- +"use strict"; + +const zlib = require("zlib"); + +test("zlib createGzip with invalid chunkSize", () => { + expect(() => zlib.createGzip({ chunkSize: 0 })).toThrow( + expect.objectContaining({ + code: "ERR_OUT_OF_RANGE", + name: "RangeError", + message: expect.stringContaining('The value of "options.chunkSize" is out of range'), + }), + ); +}); + +test("zlib createGzip with invalid windowBits", () => { + expect(() => zlib.createGzip({ windowBits: 0 })).toThrow( + expect.objectContaining({ + code: "ERR_OUT_OF_RANGE", + name: "RangeError", + message: expect.stringContaining('The value of "options.windowBits" is out of range'), + }), + ); +}); + +test("zlib createGzip with invalid memLevel", () => { + expect(() => zlib.createGzip({ memLevel: 0 })).toThrow( + expect.objectContaining({ + code: "ERR_OUT_OF_RANGE", + name: "RangeError", + message: expect.stringContaining('The value of "options.memLevel" is out of range'), + }), + ); +}); + +test("zlib createGzip with NaN level", () => { + const stream = zlib.createGzip({ level: NaN }); + expect(stream._level).toBe(zlib.constants.Z_DEFAULT_COMPRESSION); +}); + +test("zlib createGzip with NaN strategy", () => { + const stream = zlib.createGzip({ strategy: NaN }); + expect(stream._strategy).toBe(zlib.constants.Z_DEFAULT_STRATEGY); +}); + +//<#END_FILE: test-zlib-failed-init.js diff --git a/test/js/node/test/parallel/zlib-flush-flags.test.js b/test/js/node/test/parallel/zlib-flush-flags.test.js new file mode 100644 index 00000000000000..306fe03791982f --- /dev/null +++ b/test/js/node/test/parallel/zlib-flush-flags.test.js @@ -0,0 +1,56 @@ +//#FILE: test-zlib-flush-flags.js +//#SHA1: 9fb4201163deb1a6dc1f74c5c7a2723ec1a9d342 +//----------------- +"use strict"; + +const zlib = require("zlib"); + +test("createGzip with valid flush option", () => { + expect(() => zlib.createGzip({ flush: zlib.constants.Z_SYNC_FLUSH })).not.toThrow(); +}); + +test("createGzip with invalid flush option type", () => { + expect(() => zlib.createGzip({ flush: "foobar" })).toThrow( + expect.objectContaining({ + code: "ERR_INVALID_ARG_TYPE", + name: "TypeError", + message: expect.any(String), + }), + ); +}); + +test("createGzip with out of range flush option", () => { + expect(() => zlib.createGzip({ flush: 10000 })).toThrow( + expect.objectContaining({ + code: "ERR_OUT_OF_RANGE", + name: "RangeError", + message: expect.any(String), + }), + ); +}); + +test("createGzip with valid finishFlush option", () => { + expect(() => zlib.createGzip({ finishFlush: zlib.constants.Z_SYNC_FLUSH })).not.toThrow(); +}); + +test("createGzip with invalid finishFlush option type", () => { + expect(() => zlib.createGzip({ finishFlush: "foobar" })).toThrow( + expect.objectContaining({ + code: "ERR_INVALID_ARG_TYPE", + name: "TypeError", + message: expect.any(String), + }), + ); +}); + +test("createGzip with out of range finishFlush option", () => { + expect(() => zlib.createGzip({ finishFlush: 10000 })).toThrow( + expect.objectContaining({ + code: "ERR_OUT_OF_RANGE", + name: "RangeError", + message: expect.any(String), + }), + ); +}); + +//<#END_FILE: test-zlib-flush-flags.js diff --git a/test/js/node/test/parallel/zlib-invalid-arg-value-brotli-compress.test.js b/test/js/node/test/parallel/zlib-invalid-arg-value-brotli-compress.test.js new file mode 100644 index 00000000000000..4fbb56f1a066f4 --- /dev/null +++ b/test/js/node/test/parallel/zlib-invalid-arg-value-brotli-compress.test.js @@ -0,0 +1,27 @@ +//#FILE: test-zlib-invalid-arg-value-brotli-compress.js +//#SHA1: fab88f892e21351603b5ae7227837d01149bdae6 +//----------------- +"use strict"; + +// This test ensures that the BrotliCompress function throws +// ERR_INVALID_ARG_TYPE when the values of the `params` key-value object are +// neither numbers nor booleans. + +const { BrotliCompress, constants } = require("zlib"); + +test("BrotliCompress throws ERR_INVALID_ARG_TYPE for invalid params value", () => { + const opts = { + params: { + [constants.BROTLI_PARAM_MODE]: "lol", + }, + }; + + expect(() => BrotliCompress(opts)).toThrow( + expect.objectContaining({ + code: "ERR_INVALID_ARG_TYPE", + message: expect.any(String), + }), + ); +}); + +//<#END_FILE: test-zlib-invalid-arg-value-brotli-compress.js diff --git a/test/js/node/test/parallel/zlib-not-string-or-buffer.test.js b/test/js/node/test/parallel/zlib-not-string-or-buffer.test.js new file mode 100644 index 00000000000000..5353bea54f2a47 --- /dev/null +++ b/test/js/node/test/parallel/zlib-not-string-or-buffer.test.js @@ -0,0 +1,27 @@ +//#FILE: test-zlib-not-string-or-buffer.js +//#SHA1: d07db97d9393df2ab9453800ae80f2921d93b6e2 +//----------------- +"use strict"; + +// Check the error condition testing for passing something other than a string +// or buffer. + +const zlib = require("zlib"); + +test("zlib.deflateSync throws for invalid input types", () => { + const invalidInputs = [undefined, null, true, false, 0, 1, [1, 2, 3], { foo: "bar" }]; + + invalidInputs.forEach(input => { + expect(() => zlib.deflateSync(input)).toThrow( + expect.objectContaining({ + code: "ERR_INVALID_ARG_TYPE", + name: "TypeError", + message: expect.stringContaining( + 'The "buffer" argument must be of type string or an instance of Buffer, TypedArray, DataView, or ArrayBuffer.', + ), + }), + ); + }); +}); + +//<#END_FILE: test-zlib-not-string-or-buffer.js diff --git a/test/js/node/test/parallel/zlib-object-write.test.js b/test/js/node/test/parallel/zlib-object-write.test.js new file mode 100644 index 00000000000000..63934f60b27632 --- /dev/null +++ b/test/js/node/test/parallel/zlib-object-write.test.js @@ -0,0 +1,28 @@ +//#FILE: test-zlib-object-write.js +//#SHA1: 8866194c1a944026a655101d66189f364b414ad7 +//----------------- +"use strict"; + +const { Gunzip } = require("zlib"); + +test("Gunzip in object mode throws on non-buffer write", () => { + const gunzip = new Gunzip({ objectMode: true }); + + // We use jest.fn() to create a mock function that we expect not to be called + const errorHandler = jest.fn(); + gunzip.on("error", errorHandler); + + expect(() => { + gunzip.write({}); + }).toThrow( + expect.objectContaining({ + name: "TypeError", + code: "ERR_INVALID_ARG_TYPE", + }), + ); + + // Verify that the error handler was not called + expect(errorHandler).not.toHaveBeenCalled(); +}); + +//<#END_FILE: test-zlib-object-write.js diff --git a/test/js/node/test/parallel/zlib-sync-no-event.test.js b/test/js/node/test/parallel/zlib-sync-no-event.test.js index 5d443ae88afe9c..9e821acfe9683e 100644 --- a/test/js/node/test/parallel/zlib-sync-no-event.test.js +++ b/test/js/node/test/parallel/zlib-sync-no-event.test.js @@ -20,11 +20,20 @@ test("zlib sync compression and decompression without events", () => { const unzipped = unzipper._processChunk(zipped, zlib.constants.Z_FINISH); - expect(zipped.toString()).not.toBe(message); - expect(unzipped.toString()).toBe(message); + expect(zipped).toEqual( + // prettier-ignore + Buffer.from([ 31, 139, 8, 0, 0, 0, 0, 0, 0, osbyte(), 115, 206, 207, 77, 85, 200, 207, 211, 81, 112, 203, 40, 44, 207, 72, 79, 76, 41, 214, 3, 0, 160, 120, 128, 220, 19, 0, 0, 0 ]), + ); + expect(unzipped.toString()).toEqual(message); expect(closeSpy).not.toHaveBeenCalled(); expect(unzipperCloseSpy).not.toHaveBeenCalled(); }); //<#END_FILE: test-zlib-sync-no-event.js + +function osbyte() { + if (process.platform === "darwin") return 19; + if (process.platform === "linux") return 3; + if (process.platform === "win32") return 10; +} diff --git a/test/js/node/test/parallel/zlib-write-after-flush.test.js b/test/js/node/test/parallel/zlib-write-after-flush.test.js new file mode 100644 index 00000000000000..3bdcfb8d4f346f --- /dev/null +++ b/test/js/node/test/parallel/zlib-write-after-flush.test.js @@ -0,0 +1,57 @@ +//#FILE: test-zlib-write-after-flush.js +//#SHA1: 2cd2c91ba7a105560cdf6831ece0e95174aac860 +//----------------- +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +"use strict"; +const zlib = require("zlib"); + +const compressionMethods = [ + [zlib.createGzip, zlib.createGunzip], + [zlib.createBrotliCompress, zlib.createBrotliDecompress], +]; + +compressionMethods.forEach(([createCompress, createDecompress]) => { + test(`${createCompress.name} and ${createDecompress.name}`, done => { + const gzip = createCompress(); + const gunz = createDecompress(); + + gzip.pipe(gunz); + + let output = ""; + const input = "A line of data\n"; + gunz.setEncoding("utf8"); + gunz.on("data", c => (output += c)); + gunz.on("end", () => { + expect(output).toBe(input); + done(); + }); + + // Make sure that flush/write doesn't trigger an assert failure + gzip.flush(); + gzip.write(input); + gzip.end(); + gunz.read(0); + }); +}); + +//<#END_FILE: test-zlib-write-after-flush.js diff --git a/test/js/node/test/parallel/zlib-zero-windowbits.test.js b/test/js/node/test/parallel/zlib-zero-windowbits.test.js new file mode 100644 index 00000000000000..32f4225a309cbb --- /dev/null +++ b/test/js/node/test/parallel/zlib-zero-windowbits.test.js @@ -0,0 +1,32 @@ +//#FILE: test-zlib-zero-windowBits.js +//#SHA1: 3f1f031d2f5ab37f2ea2a963d6de0e2ececa9d33 +//----------------- +"use strict"; + +const zlib = require("zlib"); + +// windowBits is a special case in zlib. On the compression side, 0 is invalid. +// On the decompression side, it indicates that zlib should use the value from +// the header of the compressed stream. +test("windowBits 0 for decompression", () => { + const inflate = zlib.createInflate({ windowBits: 0 }); + expect(inflate).toBeInstanceOf(zlib.Inflate); + + const gunzip = zlib.createGunzip({ windowBits: 0 }); + expect(gunzip).toBeInstanceOf(zlib.Gunzip); + + const unzip = zlib.createUnzip({ windowBits: 0 }); + expect(unzip).toBeInstanceOf(zlib.Unzip); +}); + +test("windowBits 0 for compression throws error", () => { + expect(() => zlib.createGzip({ windowBits: 0 })).toThrow( + expect.objectContaining({ + code: "ERR_OUT_OF_RANGE", + name: "RangeError", + message: expect.any(String), + }), + ); +}); + +//<#END_FILE: test-zlib-zero-windowBits.js diff --git a/test/js/node/test/parallel/zlib.test.js b/test/js/node/test/parallel/zlib.test.js new file mode 100644 index 00000000000000..75a3514a68b5b8 --- /dev/null +++ b/test/js/node/test/parallel/zlib.test.js @@ -0,0 +1,234 @@ +//#FILE: test-zlib.js +//#SHA1: 0e67da3898d627175ffca51fdbd1042571d0c405 +//----------------- +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +"use strict"; +const zlib = require("zlib"); +const stream = require("stream"); +const fs = require("fs"); +const path = require("path"); + +const fixturesPath = path.join(__dirname, "..", "fixtures"); + +// Should not segfault. +test("gzipSync with invalid windowBits", () => { + expect(() => zlib.gzipSync(Buffer.alloc(0), { windowBits: 8 })).toThrow( + expect.objectContaining({ + code: "ERR_OUT_OF_RANGE", + name: "RangeError", + message: expect.stringContaining('The value of "options.windowBits" is out of range'), + }), + ); +}); + +let zlibPairs = [ + [zlib.Deflate, zlib.Inflate], + [zlib.Gzip, zlib.Gunzip], + [zlib.Deflate, zlib.Unzip], + [zlib.Gzip, zlib.Unzip], + [zlib.DeflateRaw, zlib.InflateRaw], + [zlib.BrotliCompress, zlib.BrotliDecompress], +]; + +// How fast to trickle through the slowstream +let trickle = [128, 1024, 1024 * 1024]; + +// Tunable options for zlib classes. + +// several different chunk sizes +let chunkSize = [128, 1024, 1024 * 16, 1024 * 1024]; + +// This is every possible value. +let level = [-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; +let windowBits = [8, 9, 10, 11, 12, 13, 14, 15]; +let memLevel = [1, 2, 3, 4, 5, 6, 7, 8, 9]; +let strategy = [0, 1, 2, 3, 4]; + +// It's nice in theory to test every combination, but it +// takes WAY too long. Maybe a pummel test could do this? +if (!process.env.PUMMEL) { + trickle = [1024]; + chunkSize = [1024 * 16]; + level = [6]; + memLevel = [8]; + windowBits = [15]; + strategy = [0]; +} + +let testFiles = ["person.jpg", "elipses.txt", "empty.txt"]; + +if (process.env.FAST) { + zlibPairs = [[zlib.Gzip, zlib.Unzip]]; + testFiles = ["person.jpg"]; +} + +const tests = {}; +testFiles.forEach(file => { + tests[file] = fs.readFileSync(path.join(fixturesPath, file)); +}); + +// Stream that saves everything +class BufferStream extends stream.Stream { + constructor() { + super(); + this.chunks = []; + this.length = 0; + this.writable = true; + this.readable = true; + } + + write(c) { + this.chunks.push(c); + this.length += c.length; + return true; + } + + end(c) { + if (c) this.write(c); + // flatten + const buf = Buffer.allocUnsafe(this.length); + let i = 0; + this.chunks.forEach(c => { + c.copy(buf, i); + i += c.length; + }); + this.emit("data", buf); + this.emit("end"); + return true; + } +} + +class SlowStream extends stream.Stream { + constructor(trickle) { + super(); + this.trickle = trickle; + this.offset = 0; + this.readable = this.writable = true; + } + + write() { + throw new Error("not implemented, just call ss.end(chunk)"); + } + + pause() { + this.paused = true; + this.emit("pause"); + } + + resume() { + const emit = () => { + if (this.paused) return; + if (this.offset >= this.length) { + this.ended = true; + return this.emit("end"); + } + const end = Math.min(this.offset + this.trickle, this.length); + const c = this.chunk.slice(this.offset, end); + this.offset += c.length; + this.emit("data", c); + process.nextTick(emit); + }; + + if (this.ended) return; + this.emit("resume"); + if (!this.chunk) return; + this.paused = false; + emit(); + } + + end(chunk) { + // Walk over the chunk in blocks. + this.chunk = chunk; + this.length = chunk.length; + this.resume(); + return this.ended; + } +} + +test("createDeflateRaw with windowBits 8", () => { + expect(() => zlib.createDeflateRaw({ windowBits: 8 })).not.toThrow(); +}); + +test("inflate raw with windowBits 8", async () => { + const node = fs.createReadStream(path.join(fixturesPath, "person.jpg")); + const raw = []; + const reinflated = []; + + await new Promise((resolve, reject) => { + node.on("data", chunk => raw.push(chunk)); + + node + .pipe(zlib.createDeflateRaw({ windowBits: 9 })) + .pipe(zlib.createInflateRaw({ windowBits: 8 })) + .on("data", chunk => reinflated.push(chunk)) + .on("end", () => { + expect(Buffer.concat(raw)).toEqual(Buffer.concat(reinflated)); + resolve(); + }) + .on("error", reject); + }); +}); + +// For each of the files, make sure that compressing and +// decompressing results in the same data, for every combination +// of the options set above. + +const testKeys = Object.keys(tests); +testKeys.forEach(file => { + const test = tests[file]; + chunkSize.forEach(chunkSize => { + trickle.forEach(trickle => { + windowBits.forEach(windowBits => { + level.forEach(level => { + memLevel.forEach(memLevel => { + strategy.forEach(strategy => { + zlibPairs.forEach(pair => { + const [Def, Inf] = pair; + const opts = { level, windowBits, memLevel, strategy }; + + it(`${file} ${chunkSize} ${JSON.stringify(opts)} ${Def.name} -> ${Inf.name}`, done => { + const def = new Def(opts); + const inf = new Inf(opts); + const ss = new SlowStream(trickle); + const buf = new BufferStream(); + + // Verify that the same exact buffer comes out the other end. + buf.on("data", c => { + expect(c).toEqual(test); + done(); + }); + + // The magic happens here. + ss.pipe(def).pipe(inf).pipe(buf); + ss.end(test); + }); + }); + }); + }); + }); + }); + }); + }); +}); + +//<#END_FILE: test-zlib.js diff --git a/test/js/node/zlib/bytesWritten.test.ts b/test/js/node/zlib/bytesWritten.test.ts new file mode 100644 index 00000000000000..4367523403ed74 --- /dev/null +++ b/test/js/node/zlib/bytesWritten.test.ts @@ -0,0 +1,103 @@ +import { test, expect } from "bun:test"; +import * as zlib from "zlib"; + +const expectStr = "abcdefghijklmnopqrstuvwxyz".repeat(2); +const expectBuf = Buffer.from(expectStr); + +function createWriter(target: zlib.Zlib, buffer: Buffer): Promise { + return new Promise(resolve => { + let size = 0; + const write = () => { + if (size < buffer.length) { + target.write(Buffer.from([buffer[size++]]), () => { + target.flush(() => write()); + }); + } else { + target.end(() => resolve()); + } + }; + write(); + }); +} + +const methods = [ + ["createGzip", "createGunzip", false], + ["createGzip", "createUnzip", false], + ["createDeflate", "createInflate", true], + ["createDeflateRaw", "createInflateRaw", true], + ["createBrotliCompress", "createBrotliDecompress", true], +] as const; +type C = (typeof methods)[number][0]; +type D = (typeof methods)[number][1]; + +for (const [compressMethod, decompressMethod, allowExtra] of methods) { + test(`Test ${compressMethod} and ${decompressMethod}`, async () => { + let compData = Buffer.alloc(0); + const comp = zlib[compressMethod](); + + comp.on("data", (d: Buffer) => { + compData = Buffer.concat([compData, d]); + }); + + const compPromise = new Promise(resolve => { + comp.on("end", () => { + expect(comp.bytesWritten).toBe(expectStr.length); + resolve(); + }); + }); + + await createWriter(comp, expectBuf); + await compPromise; + + // Decompression test + await testDecompression(decompressMethod, compData); + + // Test with extra data if allowed + if (allowExtra) { + await testDecompressionWithExtra(decompressMethod, compData); + } + }); +} + +async function testDecompression(decompressMethod: D, compData: Buffer) { + let decompData = Buffer.alloc(0); + const decomp = zlib[decompressMethod](); + + decomp.on("data", (d: Buffer) => { + decompData = Buffer.concat([decompData, d]); + }); + + const decompPromise = new Promise(resolve => { + decomp.on("end", () => { + expect(decomp.bytesWritten).toBe(compData.length); + expect(decompData.toString()).toBe(expectStr); + resolve(); + }); + }); + + await createWriter(decomp, compData); + await decompPromise; +} + +async function testDecompressionWithExtra(decompressMethod: D, compData: Buffer) { + const compDataExtra = Buffer.concat([compData, Buffer.from("extra")]); + let decompData = Buffer.alloc(0); + const decomp = zlib[decompressMethod](); + + decomp.on("data", (d: Buffer) => { + decompData = Buffer.concat([decompData, d]); + }); + + const decompPromise = new Promise(resolve => { + decomp.on("end", () => { + expect(decomp.bytesWritten).toBe(compData.length); + // Checking legacy name. + expect(decomp.bytesWritten).toBe((decomp as any).bytesWritten); + expect(decompData.toString()).toBe(expectStr); + resolve(); + }); + }); + + await createWriter(decomp, compDataExtra); + await decompPromise; +} diff --git a/test/js/node/zlib/deflate-streaming.test.ts b/test/js/node/zlib/deflate-streaming.test.ts new file mode 100644 index 00000000000000..26693b24d08b5b --- /dev/null +++ b/test/js/node/zlib/deflate-streaming.test.ts @@ -0,0 +1,50 @@ +import { test, expect } from "bun:test"; +import zlib from "node:zlib"; +import { Readable } from "node:stream"; + +test("yields data in more than one chunk", () => { + const hasher_in = new Bun.CryptoHasher("sha256"); + const hasher_out = new Bun.CryptoHasher("sha256"); + + // Generate 512 KB of random data + const randomData = Buffer.alloc(512 * 1024); + for (let i = 0; i < randomData.length; i++) { + randomData[i] = Math.floor(Math.random() * 256); + } + hasher_in.update(randomData); + + console.log("Original data size:", randomData.length, "bytes"); + + // Compress the data + const compressed = zlib.deflateSync(randomData); + console.log("Compressed data size:", compressed.length, "bytes"); + + // Create a readable stream from the compressed data + const compressedStream = Readable.from(compressed); + + // Decompress the data using a streaming approach + const decompressor = zlib.createInflate(); + + let totalReceived = 0; + let chunksReceived = 0; + + decompressor.on("data", chunk => { + totalReceived += chunk.length; + chunksReceived += 1; + console.count(`Received chunk: ${chunk.length} bytes`); + hasher_out.update(chunk); + }); + + decompressor.on("end", () => { + console.log("Decompression complete"); + console.log("Total data received:", totalReceived, "bytes"); + + const digest_in = hasher_in.digest().toString("hex"); + const digest_out = hasher_out.digest().toString("hex"); + expect(digest_out).toEqual(digest_in); + expect(chunksReceived).toBe(32); + }); + + // Pipe the compressed data through the decompressor + compressedStream.pipe(decompressor); +}); diff --git a/test/js/node/zlib/zlib.kMaxLength.global.test.js b/test/js/node/zlib/zlib.kMaxLength.global.test.js new file mode 100644 index 00000000000000..b71cf0d3fd2b60 --- /dev/null +++ b/test/js/node/zlib/zlib.kMaxLength.global.test.js @@ -0,0 +1,25 @@ +import { expect, it } from "bun:test"; +const util = require("node:util"); +const buffer = require("node:buffer"); +buffer.kMaxLength = 64; +const zlib = require("node:zlib"); + +const data_sync = { + brotli: ["1b7f00f825c222b1402003", zlib.brotliDecompress, zlib.brotliDecompressSync], + inflate: ["789c4b4c1c58000039743081", zlib.inflate, zlib.inflateSync], + gunzip: ["1f8b08000000000000034b4c1c5800008c362bf180000000", zlib.gunzip, zlib.gunzipSync], + unzip: ["1f8b08000000000000034b4c1c5800008c362bf180000000", zlib.unzip, zlib.unzipSync], +}; + +for (const method in data_sync) { + const [encoded_hex, f_async, f_sync] = data_sync[method]; + const encoded = Buffer.from(encoded_hex, "hex"); + + it(`decompress synchronous ${method}`, () => { + expect(() => f_sync(encoded)).toThrow(RangeError); + }); + + it(`decompress asynchronous ${method}`, async () => { + expect(async () => await util.promisify(f_async)(encoded)).toThrow(RangeError); + }); +} diff --git a/test/js/node/zlib/zlib.test.js b/test/js/node/zlib/zlib.test.js index 7f748a5f032e9f..f2600e919211d1 100644 --- a/test/js/node/zlib/zlib.test.js +++ b/test/js/node/zlib/zlib.test.js @@ -114,7 +114,7 @@ describe("zlib.brotli", () => { for (const chunk of window(inputString, 55)) { encoder._transform(chunk, undefined, (err, data) => { expect(err).toBeUndefined(); - expect(data).toBeUndefined(); + expect(data).toEqual(Buffer(0)); }); } encoder._flush((err, data) => { @@ -128,7 +128,7 @@ describe("zlib.brotli", () => { for (const chunk of window(compressedBuffer, 10)) { decoder._transform(chunk, undefined, (err, data) => { expect(err).toBeUndefined(); - expect(data).toBeUndefined(); + expect(data).toEqual(Buffer(0)); }); } decoder._flush((err, data) => { @@ -150,7 +150,7 @@ describe("zlib.brotli", () => { for (const chunk of window(inputString+inputString+inputString+inputString, 65)) { encoder._transform(chunk, undefined, (err, data) => { expect(err).toBeUndefined(); - expect(data).toBeUndefined(); + expect(data).toEqual(Buffer(0)); }); } encoder._flush((err, data) => { @@ -265,3 +265,144 @@ describe("zlib.brotli", () => { } }); }); + +it.each([ + "BrotliCompress", + "BrotliDecompress", + "Deflate", + "Inflate", + "DeflateRaw", + "InflateRaw", + "Gzip", + "Gunzip", + "Unzip", +])("%s should work with and without `new` keyword", constructor_name => { + const C = zlib[constructor_name]; + expect(C()).toBeInstanceOf(C); + expect(new C()).toBeInstanceOf(C); +}); + +describe.each(["Deflate", "DeflateRaw", "Gzip"])("%s", constructor_name => { + describe.each(["chunkSize", "level", "windowBits", "memLevel", "strategy", "maxOutputLength"])( + "should throw if options.%s is", + option_name => { + // [], // error: Test "-3.4416124249222144e-103" timed out after 5000ms + it.each(["test", Symbol("bun"), 2n, {}, true])("%p", value => { + expect(() => new zlib[constructor_name]({ [option_name]: value })).toThrow(TypeError); + }); + it.each([Infinity, -Infinity, -2])("%p", value => { + expect(() => new zlib[constructor_name]({ [option_name]: value })).toThrow(RangeError); + }); + }, + ); +}); + +for (const [compress, decompressor] of [ + [zlib.deflateRawSync, zlib.createInflateRaw], + [zlib.deflateSync, zlib.createInflate], + [zlib.brotliCompressSync, zlib.createBrotliDecompress], + // [zlib.gzipSync, zlib.createGunzip], + // [zlib.gzipSync, zlib.createUnzip], +]) { + const input = "0123456789".repeat(4); + const compressed = compress(input); + const trailingData = Buffer.from("not valid compressed data"); + + const variants = [ + stream => { + stream.end(compressed); + }, + // stream => { + // stream.write(compressed); + // stream.write(trailingData); + // }, + stream => { + stream.write(compressed); + stream.end(trailingData); + }, + // stream => { + // stream.write(Buffer.concat([compressed, trailingData])); + // }, + stream => { + stream.end(Buffer.concat([compressed, trailingData])); + }, + ]; + for (const i in variants) { + it(`premature end handles bytesWritten properly: ${compress.name} + ${decompressor.name}: variant ${i}`, async () => { + const variant = variants[i]; + const { promise, resolve, reject } = Promise.withResolvers(); + let output = ""; + const stream = decompressor(); + stream.setEncoding("utf8"); + stream.on("data", chunk => (output += chunk)); + stream.on("end", () => { + try { + expect(output).toBe(input); + expect(stream.bytesWritten).toBe(compressed.length); + resolve(); + } catch (e) { + reject(e); + } + }); + variant(stream); + await promise; + }); + } +} + +const inputString = + "ΩΩLorem ipsum dolor sit amet, consectetur adipiscing eli" + + "t. Morbi faucibus, purus at gravida dictum, libero arcu " + + "convallis lacus, in commodo libero metus eu nisi. Nullam" + + " commodo, neque nec porta placerat, nisi est fermentum a" + + "ugue, vitae gravida tellus sapien sit amet tellus. Aenea" + + "n non diam orci. Proin quis elit turpis. Suspendisse non" + + " diam ipsum. Suspendisse nec ullamcorper odio. Vestibulu" + + "m arcu mi, sodales non suscipit id, ultrices ut massa. S" + + "ed ac sem sit amet arcu malesuada fermentum. Nunc sed. "; + +const errMessage = /unexpected end of file/; + +it.each([ + ["gzip", "gunzip", "gunzipSync"], + ["gzip", "unzip", "unzipSync"], + ["deflate", "inflate", "inflateSync"], + ["deflateRaw", "inflateRaw", "inflateRawSync"], +])("%s %s should handle truncated input correctly", async (comp, decomp, decompSync) => { + const comp_p = util.promisify(zlib[comp]); + const decomp_p = util.promisify(zlib[decomp]); + + const compressed = await comp_p(inputString); + + const truncated = compressed.slice(0, compressed.length / 2); + const toUTF8 = buffer => buffer.toString("utf-8"); + + // sync sanity + const decompressed = zlib[decompSync](compressed); + expect(toUTF8(decompressed)).toEqual(inputString); + + // async sanity + expect(toUTF8(await decomp_p(compressed))).toEqual(inputString); + + // Sync truncated input test + expect(() => zlib[decompSync](truncated)).toThrow(); + + // Async truncated input test + expect(async () => await decomp_p(truncated)).toThrow(); + + const syncFlushOpt = { finishFlush: zlib.constants.Z_SYNC_FLUSH }; + + // Sync truncated input test, finishFlush = Z_SYNC_FLUSH + { + const result = toUTF8(zlib[decompSync](truncated, syncFlushOpt)); + const expected = inputString.slice(0, result.length); + expect(result).toBe(expected); + } + + // Async truncated input test, finishFlush = Z_SYNC_FLUSH + { + const result = toUTF8(await decomp_p(truncated, syncFlushOpt)); + const expected = inputString.slice(0, result.length); + expect(result).toBe(expected); + } +}); diff --git a/test/node.js/runner.mjs b/test/node.js/runner.mjs index 2ec6bcde12a0a0..5507638616613e 100644 --- a/test/node.js/runner.mjs +++ b/test/node.js/runner.mjs @@ -1,6 +1,6 @@ import { parseArgs } from "node:util"; import { spawnSync } from "node:child_process"; -import { existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, writeFileSync, appendFileSync } from "node:fs"; +import { existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, writeFileSync, appendFileSync, realpathSync } from "node:fs"; import { tmpdir } from "node:os"; import { basename, join } from "node:path"; import readline from "node:readline/promises"; @@ -427,6 +427,10 @@ function getMetadata(execPath) { }; } +function tmpdirSync(pattern = "bun.test.") { + return mkdtempSync(join(realpathSync(tmpdir()), pattern)); +} + main().catch(error => { console.error(error); process.exit(1); diff --git a/test/v8/v8.test.ts b/test/v8/v8.test.ts index eb57502d346776..2a0e9ee7cc9bd8 100644 --- a/test/v8/v8.test.ts +++ b/test/v8/v8.test.ts @@ -68,19 +68,15 @@ beforeAll(async () => { directories.node = tmpdirSync(); directories.badModules = tmpdirSync(); - // run installs sequentially and builds in parallel due to bug with simultaneous - // bun install invocations await install(srcDir, directories.bunRelease, Runtime.bun); await install(srcDir, directories.bunDebug, Runtime.bun); await install(srcDir, directories.node, Runtime.node); await install(join(__dirname, "bad-modules"), directories.badModules, Runtime.node); - await Promise.all([ - build(srcDir, directories.bunRelease, Runtime.bun, BuildMode.release), - build(srcDir, directories.bunDebug, Runtime.bun, BuildMode.debug), - build(srcDir, directories.node, Runtime.node, BuildMode.release), - build(join(__dirname, "bad-modules"), directories.badModules, Runtime.node, BuildMode.release), - ]); + await build(srcDir, directories.bunRelease, Runtime.bun, BuildMode.release); + await build(srcDir, directories.bunDebug, Runtime.bun, BuildMode.debug); + await build(srcDir, directories.node, Runtime.node, BuildMode.release); + await build(join(__dirname, "bad-modules"), directories.badModules, Runtime.node, BuildMode.release); }); describe("module lifecycle", () => { @@ -194,15 +190,6 @@ describe("HandleScope", () => { }, 10000); }); -afterAll(async () => { - await Promise.all([ - fs.rm(directories.bunRelease, { recursive: true, force: true }), - fs.rm(directories.bunDebug, { recursive: true, force: true }), - fs.rm(directories.node, { recursive: true, force: true }), - fs.rm(directories.badModules, { recursive: true, force: true }), - ]); -}); - enum Runtime { node, bun,