mirror of
https://github.com/denoland/deno.git
synced 2024-11-21 15:04:11 -05:00
feat: port node:zlib to rust (#18291)
This commit is contained in:
parent
9ebce6e725
commit
b2fd0742bd
33 changed files with 897 additions and 7471 deletions
13
Cargo.lock
generated
13
Cargo.lock
generated
|
@ -1150,6 +1150,7 @@ dependencies = [
|
|||
"hex",
|
||||
"idna 0.3.0",
|
||||
"indexmap",
|
||||
"libz-sys",
|
||||
"md-5",
|
||||
"md4",
|
||||
"once_cell",
|
||||
|
@ -2582,6 +2583,18 @@ dependencies = [
|
|||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libz-sys"
|
||||
version = "1.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9702761c3935f8cc2f101793272e202c72b99da8f4224a19ddcf1279a6450bbf"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linked-hash-map"
|
||||
version = "0.5.6"
|
||||
|
|
|
@ -22,6 +22,7 @@ ecb.workspace = true
|
|||
hex.workspace = true
|
||||
idna = "0.3.0"
|
||||
indexmap.workspace = true
|
||||
libz-sys = { version = "1.1.8", features = ["static"] }
|
||||
md-5 = "0.10.5"
|
||||
md4 = "0.10.2"
|
||||
once_cell.workspace = true
|
||||
|
|
|
@ -20,6 +20,7 @@ mod polyfill;
|
|||
mod resolution;
|
||||
mod v8;
|
||||
mod winerror;
|
||||
mod zlib;
|
||||
|
||||
pub use package_json::PackageJson;
|
||||
pub use path::PathClean;
|
||||
|
@ -119,6 +120,13 @@ deno_core::extension!(deno_node,
|
|||
idna::op_node_idna_domain_to_unicode,
|
||||
idna::op_node_idna_punycode_decode,
|
||||
idna::op_node_idna_punycode_encode,
|
||||
zlib::op_zlib_new,
|
||||
zlib::op_zlib_close,
|
||||
zlib::op_zlib_close_if_pending,
|
||||
zlib::op_zlib_write,
|
||||
zlib::op_zlib_write_async,
|
||||
zlib::op_zlib_init,
|
||||
zlib::op_zlib_reset,
|
||||
op_node_build_os,
|
||||
|
||||
ops::op_require_init_paths,
|
||||
|
@ -195,7 +203,6 @@ deno_core::extension!(deno_node,
|
|||
"_http_common.ts",
|
||||
"_http_outgoing.ts",
|
||||
"_next_tick.ts",
|
||||
"_pako.mjs",
|
||||
"_process/exiting.ts",
|
||||
"_process/process.ts",
|
||||
"_process/streams.mjs",
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,42 +1,37 @@
|
|||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
// Copyright (c) 2014-2015 Devon Govett <devongovett@gmail.com>
|
||||
// Forked from https://github.com/browserify/browserify-zlib
|
||||
|
||||
// deno-lint-ignore-file
|
||||
|
||||
import assert from "ext:deno_node/assert.ts";
|
||||
import { constants, zlib_deflate, zlib_inflate, Zstream } from "ext:deno_node/_pako.mjs";
|
||||
import { nextTick } from "ext:deno_node/_next_tick.ts";
|
||||
|
||||
export const Z_NO_FLUSH = constants.Z_NO_FLUSH;
|
||||
export const Z_PARTIAL_FLUSH = constants.Z_PARTIAL_FLUSH;
|
||||
export const Z_SYNC_FLUSH = constants.Z_SYNC_FLUSH;
|
||||
export const Z_FULL_FLUSH = constants.Z_FULL_FLUSH;
|
||||
export const Z_FINISH = constants.Z_FINISH;
|
||||
export const Z_BLOCK = constants.Z_BLOCK;
|
||||
export const Z_TREES = constants.Z_TREES;
|
||||
export const Z_OK = constants.Z_OK;
|
||||
export const Z_STREAM_END = constants.Z_STREAM_END;
|
||||
export const Z_NEED_DICT = constants.Z_NEED_DICT;
|
||||
export const Z_ERRNO = constants.Z_ERRNO;
|
||||
export const Z_STREAM_ERROR = constants.Z_STREAM_ERROR;
|
||||
export const Z_DATA_ERROR = constants.Z_DATA_ERROR;
|
||||
export const Z_MEM_ERROR = constants.Z_MEM_ERROR;
|
||||
export const Z_BUF_ERROR = constants.Z_BUF_ERROR;
|
||||
export const Z_VERSION_ERROR = constants.Z_VERSION_ERROR;
|
||||
export const Z_NO_COMPRESSION = constants.Z_NO_COMPRESSION;
|
||||
export const Z_BEST_SPEED = constants.Z_BEST_SPEED;
|
||||
export const Z_BEST_COMPRESSION = constants.Z_BEST_COMPRESSION;
|
||||
export const Z_DEFAULT_COMPRESSION = constants.Z_DEFAULT_COMPRESSION;
|
||||
export const Z_FILTERED = constants.Z_FILTERED;
|
||||
export const Z_HUFFMAN_ONLY = constants.Z_HUFFMAN_ONLYZ_FILTERED;
|
||||
export const Z_RLE = constants.Z_RLE;
|
||||
export const Z_FIXED = constants.Z_FIXED;
|
||||
export const Z_DEFAULT_STRATEGY = constants.Z_DEFAULT_STRATEGY;
|
||||
export const Z_BINARY = constants.Z_BINARY;
|
||||
export const Z_TEXT = constants.Z_TEXT;
|
||||
export const Z_UNKNOWN = constants.Z_UNKNOWN;
|
||||
export const Z_DEFLATED = constants.Z_DEFLATED;
|
||||
// https://github.com/nodeca/pako/blob/master/lib/zlib/constants.js
|
||||
export const Z_NO_FLUSH = 0;
|
||||
export const Z_PARTIAL_FLUSH = 1;
|
||||
export const Z_SYNC_FLUSH = 2;
|
||||
export const Z_FULL_FLUSH = 3;
|
||||
export const Z_FINISH = 4;
|
||||
export const Z_BLOCK = 5;
|
||||
export const Z_TREES = 6;
|
||||
export const Z_OK = 0;
|
||||
export const Z_STREAM_END = 1;
|
||||
export const Z_NEED_DICT = 2;
|
||||
export const Z_ERRNO = -1;
|
||||
export const Z_STREAM_ERROR = -2;
|
||||
export const Z_DATA_ERROR = -3;
|
||||
export const Z_MEM_ERROR = -4;
|
||||
export const Z_BUF_ERROR = -5;
|
||||
export const Z_VERSION_ERROR = -6;
|
||||
export const Z_NO_COMPRESSION = 0;
|
||||
export const Z_BEST_SPEED = 1;
|
||||
export const Z_BEST_COMPRESSION = 9;
|
||||
export const Z_DEFAULT_COMPRESSION = -1;
|
||||
export const Z_FILTERED = 1;
|
||||
export const Z_HUFFMAN_ONLY = 2;
|
||||
export const Z_RLE = 3;
|
||||
export const Z_FIXED = 4;
|
||||
export const Z_DEFAULT_STRATEGY = 0;
|
||||
export const Z_BINARY = 0;
|
||||
export const Z_TEXT = 1;
|
||||
export const Z_UNKNOWN = 2;
|
||||
export const Z_DEFLATED = 8;
|
||||
|
||||
// zlib modes
|
||||
export const NONE = 0;
|
||||
|
@ -48,79 +43,23 @@ export const DEFLATERAW = 5;
|
|||
export const INFLATERAW = 6;
|
||||
export const UNZIP = 7;
|
||||
|
||||
var GZIP_HEADER_ID1 = 0x1f;
|
||||
var GZIP_HEADER_ID2 = 0x8b;
|
||||
const { core } = globalThis.__bootstrap;
|
||||
const { ops } = core;
|
||||
|
||||
/**
|
||||
* Emulate Node's zlib C++ layer for use by the JS layer in index.js
|
||||
*/
|
||||
function Zlib(mode) {
|
||||
if (typeof mode !== "number" || mode < DEFLATE || mode > UNZIP) {
|
||||
throw new TypeError("Bad argument");
|
||||
const writeResult = new Uint32Array(2);
|
||||
|
||||
class Zlib {
|
||||
#handle;
|
||||
|
||||
constructor(mode) {
|
||||
this.#handle = ops.op_zlib_new(mode);
|
||||
}
|
||||
|
||||
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.close = function () {
|
||||
if (this.write_in_progress) {
|
||||
this.pending_close = true;
|
||||
return;
|
||||
close() {
|
||||
ops.op_zlib_close(this.#handle);
|
||||
}
|
||||
|
||||
this.pending_close = false;
|
||||
|
||||
assert(this.init_done, "close before init");
|
||||
assert(this.mode <= UNZIP);
|
||||
|
||||
if (this.mode === DEFLATE || this.mode === GZIP || this.mode === DEFLATERAW) {
|
||||
zlib_deflate.deflateEnd(this.strm);
|
||||
} else if (
|
||||
this.mode === INFLATE || this.mode === GUNZIP || this.mode === INFLATERAW ||
|
||||
this.mode === UNZIP
|
||||
) {
|
||||
zlib_inflate.inflateEnd(this.strm);
|
||||
}
|
||||
|
||||
this.mode = 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,
|
||||
writeSync(
|
||||
flush,
|
||||
input,
|
||||
in_off,
|
||||
|
@ -128,384 +67,111 @@ Zlib.prototype.writeSync = function (
|
|||
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 !== 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 === undefined, "must provide flush value");
|
||||
|
||||
this.write_in_progress = true;
|
||||
|
||||
if (
|
||||
flush !== Z_NO_FLUSH && flush !== Z_PARTIAL_FLUSH &&
|
||||
flush !== Z_SYNC_FLUSH && flush !== Z_FULL_FLUSH && flush !== Z_FINISH &&
|
||||
flush !== Z_BLOCK
|
||||
) {
|
||||
throw new Error("Invalid flush value");
|
||||
}
|
||||
const err = ops.op_zlib_write(
|
||||
this.#handle,
|
||||
flush,
|
||||
input,
|
||||
in_off,
|
||||
in_len,
|
||||
out,
|
||||
out_off,
|
||||
out_len,
|
||||
writeResult,
|
||||
);
|
||||
|
||||
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) {
|
||||
// sync version
|
||||
this._process();
|
||||
|
||||
if (this._checkError()) {
|
||||
return this._afterSync();
|
||||
if (this.#checkError(err)) {
|
||||
return [writeResult[1], writeResult[0]];
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// async version
|
||||
var self = this;
|
||||
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;
|
||||
|
||||
// If the avail_out is left at 0, then it means that it ran out
|
||||
// of room. If there was avail_out left over, then it means
|
||||
// that all of the input was consumed.
|
||||
switch (this.mode) {
|
||||
case DEFLATE:
|
||||
case GZIP:
|
||||
case DEFLATERAW:
|
||||
this.err = zlib_deflate.deflate(this.strm, this.flush);
|
||||
break;
|
||||
case 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) {
|
||||
// The only available byte was already read.
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
this.mode = INFLATE;
|
||||
break;
|
||||
}
|
||||
|
||||
// fallthrough
|
||||
|
||||
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 = GUNZIP;
|
||||
} else {
|
||||
// There is no actual difference between INFLATE and INFLATERAW
|
||||
// (after initialization).
|
||||
this.mode = INFLATE;
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
throw new Error("invalid number of gzip magic number bytes read");
|
||||
}
|
||||
|
||||
// fallthrough
|
||||
|
||||
case INFLATE:
|
||||
case GUNZIP:
|
||||
case INFLATERAW:
|
||||
this.err = zlib_inflate.inflate(this.strm, this.flush);
|
||||
|
||||
// If data was encoded with dictionary
|
||||
if (this.err === Z_NEED_DICT && this.dictionary) {
|
||||
// Load it
|
||||
this.err = zlib_inflate.inflateSetDictionary(
|
||||
this.strm,
|
||||
this.dictionary,
|
||||
);
|
||||
if (this.err === Z_OK) {
|
||||
// And try to decode again
|
||||
this.err = zlib_inflate.inflate(this.strm, this.flush);
|
||||
} else if (this.err === Z_DATA_ERROR) {
|
||||
// Both inflateSetDictionary() and inflate() return Z_DATA_ERROR.
|
||||
// Make it possible for After() to tell a bad dictionary from bad
|
||||
// input.
|
||||
this.err = Z_NEED_DICT;
|
||||
}
|
||||
}
|
||||
while (
|
||||
this.strm.avail_in > 0 && this.mode === GUNZIP &&
|
||||
this.err === Z_STREAM_END && this.strm.next_in[0] !== 0x00
|
||||
) {
|
||||
// Bytes remain in input buffer. Perhaps this is another compressed
|
||||
// member in the same archive, or just trailing garbage.
|
||||
// Trailing zero bytes are okay, though, since they are frequently
|
||||
// used for padding.
|
||||
|
||||
this.reset();
|
||||
this.err = zlib_inflate.inflate(this.strm, this.flush);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new Error("Unknown mode " + this.mode);
|
||||
}
|
||||
};
|
||||
|
||||
Zlib.prototype._checkError = function () {
|
||||
// Acceptable error states depend on the type of zlib stream.
|
||||
switch (this.err) {
|
||||
case Z_OK:
|
||||
case Z_BUF_ERROR:
|
||||
if (this.strm.avail_out !== 0 && this.flush === Z_FINISH) {
|
||||
this._error("unexpected end of file");
|
||||
#checkError(err) {
|
||||
// Acceptable error states depend on the type of zlib stream.
|
||||
switch (err) {
|
||||
case Z_BUF_ERROR:
|
||||
this.#error("unexpected end of file", err);
|
||||
return false;
|
||||
case Z_OK:
|
||||
case Z_STREAM_END:
|
||||
// normal statuses, not fatal
|
||||
break;
|
||||
case Z_NEED_DICT:
|
||||
this.#error("Bad dictionary", err);
|
||||
return false;
|
||||
default:
|
||||
// something else.
|
||||
this.#error("Zlib error", err);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
write(
|
||||
flush,
|
||||
input,
|
||||
in_off,
|
||||
in_len,
|
||||
out,
|
||||
out_off,
|
||||
out_len,
|
||||
) {
|
||||
core.opAsync(
|
||||
"op_zlib_write_async",
|
||||
this.#handle,
|
||||
flush,
|
||||
input,
|
||||
in_off,
|
||||
in_len,
|
||||
out,
|
||||
out_off,
|
||||
out_len,
|
||||
).then(([err, availOut, availIn]) => {
|
||||
if (this.#checkError(err)) {
|
||||
this.callback(availIn, availOut);
|
||||
}
|
||||
break;
|
||||
case Z_STREAM_END:
|
||||
// normal statuses, not fatal
|
||||
break;
|
||||
case Z_NEED_DICT:
|
||||
if (this.dictionary == null) {
|
||||
this._error("Missing dictionary");
|
||||
} else {
|
||||
this._error("Bad dictionary");
|
||||
}
|
||||
return false;
|
||||
default:
|
||||
// something else.
|
||||
this._error("Zlib error");
|
||||
return false;
|
||||
});
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
init(
|
||||
windowBits,
|
||||
level,
|
||||
memLevel,
|
||||
strategy,
|
||||
dictionary,
|
||||
) {
|
||||
const err = ops.op_zlib_init(
|
||||
this.#handle,
|
||||
level,
|
||||
windowBits,
|
||||
memLevel,
|
||||
strategy,
|
||||
dictionary,
|
||||
);
|
||||
|
||||
Zlib.prototype._after = function () {
|
||||
if (!this._checkError()) {
|
||||
return;
|
||||
if (err != Z_OK) {
|
||||
this.#error("Failed to initialize zlib", err);
|
||||
}
|
||||
}
|
||||
|
||||
var avail_out = this.strm.avail_out;
|
||||
var avail_in = this.strm.avail_in;
|
||||
|
||||
this.write_in_progress = false;
|
||||
|
||||
// call the write() cb
|
||||
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);
|
||||
|
||||
// no hope of rescue.
|
||||
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 === Z_FILTERED || strategy === Z_HUFFMAN_ONLY ||
|
||||
strategy === Z_RLE || strategy === Z_FIXED ||
|
||||
strategy === 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 = Z_NO_FLUSH;
|
||||
|
||||
this.err = Z_OK;
|
||||
|
||||
if (this.mode === GZIP || this.mode === GUNZIP) {
|
||||
this.windowBits += 16;
|
||||
params() {
|
||||
throw new Error("deflateParams Not supported");
|
||||
}
|
||||
|
||||
if (this.mode === UNZIP) {
|
||||
this.windowBits += 32;
|
||||
reset() {
|
||||
const err = ops.op_zlib_reset(this.#handle);
|
||||
if (err != Z_OK) {
|
||||
this.#error("Failed to reset stream", err);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.mode === DEFLATERAW || this.mode === INFLATERAW) {
|
||||
this.windowBits = -1 * this.windowBits;
|
||||
#error(message, err) {
|
||||
this.onerror(message, err);
|
||||
ops.op_zlib_close_if_pending(this.#handle);
|
||||
}
|
||||
|
||||
this.strm = new Zstream();
|
||||
|
||||
switch (this.mode) {
|
||||
case DEFLATE:
|
||||
case GZIP:
|
||||
case DEFLATERAW:
|
||||
this.err = zlib_deflate.deflateInit2(
|
||||
this.strm,
|
||||
this.level,
|
||||
Z_DEFLATED,
|
||||
this.windowBits,
|
||||
this.memLevel,
|
||||
this.strategy,
|
||||
);
|
||||
break;
|
||||
case INFLATE:
|
||||
case GUNZIP:
|
||||
case INFLATERAW:
|
||||
case UNZIP:
|
||||
this.err = zlib_inflate.inflateInit2(this.strm, this.windowBits);
|
||||
break;
|
||||
default:
|
||||
throw new Error("Unknown mode " + this.mode);
|
||||
}
|
||||
|
||||
if (this.err !== 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 = Z_OK;
|
||||
|
||||
switch (this.mode) {
|
||||
case DEFLATE:
|
||||
case DEFLATERAW:
|
||||
this.err = zlib_deflate.deflateSetDictionary(this.strm, this.dictionary);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (this.err !== Z_OK) {
|
||||
this._error("Failed to set dictionary");
|
||||
}
|
||||
};
|
||||
|
||||
Zlib.prototype._reset = function () {
|
||||
this.err = Z_OK;
|
||||
|
||||
switch (this.mode) {
|
||||
case DEFLATE:
|
||||
case DEFLATERAW:
|
||||
case GZIP:
|
||||
this.err = zlib_deflate.deflateReset(this.strm);
|
||||
break;
|
||||
case INFLATE:
|
||||
case INFLATERAW:
|
||||
case GUNZIP:
|
||||
this.err = zlib_inflate.inflateReset(this.strm);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (this.err !== Z_OK) {
|
||||
this._error("Failed to reset stream");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export { Zlib };
|
||||
|
|
64
ext/node/zlib/alloc.rs
Normal file
64
ext/node/zlib/alloc.rs
Normal file
|
@ -0,0 +1,64 @@
|
|||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
// Workaround for https://github.com/rust-lang/libz-sys/issues/55
|
||||
// See https://github.com/rust-lang/flate2-rs/blob/31fb07820345691352aaa64f367c1e482ad9cfdc/src/ffi/c.rs#L60
|
||||
use std::alloc::Layout;
|
||||
use std::alloc::{self};
|
||||
use std::os::raw::c_void;
|
||||
use std::ptr;
|
||||
|
||||
const ALIGN: usize = std::mem::align_of::<usize>();
|
||||
|
||||
fn align_up(size: usize, align: usize) -> usize {
|
||||
(size + align - 1) & !(align - 1)
|
||||
}
|
||||
|
||||
pub extern "C" fn zalloc(
|
||||
_ptr: *mut c_void,
|
||||
items: u32,
|
||||
item_size: u32,
|
||||
) -> *mut c_void {
|
||||
// We need to multiply `items` and `item_size` to get the actual desired
|
||||
// allocation size. Since `zfree` doesn't receive a size argument we
|
||||
// also need to allocate space for a `usize` as a header so we can store
|
||||
// how large the allocation is to deallocate later.
|
||||
let size = match (items as usize)
|
||||
.checked_mul(item_size as usize)
|
||||
.map(|size| align_up(size, ALIGN))
|
||||
.and_then(|i| i.checked_add(std::mem::size_of::<usize>()))
|
||||
{
|
||||
Some(i) => i,
|
||||
None => return ptr::null_mut(),
|
||||
};
|
||||
|
||||
// Make sure the `size` isn't too big to fail `Layout`'s restrictions
|
||||
let layout = match Layout::from_size_align(size, ALIGN) {
|
||||
Ok(layout) => layout,
|
||||
Err(_) => return ptr::null_mut(),
|
||||
};
|
||||
|
||||
// SAFETY: `layout` has non-zero size, guaranteed to be a sentinel address
|
||||
// or a null pointer.
|
||||
unsafe {
|
||||
// Allocate the data, and if successful store the size we allocated
|
||||
// at the beginning and then return an offset pointer.
|
||||
let ptr = alloc::alloc(layout) as *mut usize;
|
||||
if ptr.is_null() {
|
||||
return ptr as *mut c_void;
|
||||
}
|
||||
*ptr = size;
|
||||
ptr.add(1) as *mut c_void
|
||||
}
|
||||
}
|
||||
|
||||
pub extern "C" fn zfree(_ptr: *mut c_void, address: *mut c_void) {
|
||||
// SAFETY: Move our address being free'd back one pointer, read the size we
|
||||
// stored in `zalloc`, and then free it using the standard Rust
|
||||
// allocator.
|
||||
unsafe {
|
||||
let ptr = (address as *mut usize).offset(-1);
|
||||
let size = *ptr;
|
||||
let layout = Layout::from_size_align_unchecked(size, ALIGN);
|
||||
alloc::dealloc(ptr as *mut u8, layout)
|
||||
}
|
||||
}
|
450
ext/node/zlib/mod.rs
Normal file
450
ext/node/zlib/mod.rs
Normal file
|
@ -0,0 +1,450 @@
|
|||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use deno_core::error::bad_resource_id;
|
||||
use deno_core::error::type_error;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::op;
|
||||
use deno_core::OpState;
|
||||
use libz_sys::*;
|
||||
use std::borrow::Cow;
|
||||
use std::cell::RefCell;
|
||||
use std::future::Future;
|
||||
use std::rc::Rc;
|
||||
|
||||
mod alloc;
|
||||
mod mode;
|
||||
mod stream;
|
||||
|
||||
use mode::Flush;
|
||||
use mode::Mode;
|
||||
|
||||
use self::stream::StreamWrapper;
|
||||
|
||||
#[inline]
|
||||
fn check(condition: bool, msg: &str) -> Result<(), AnyError> {
|
||||
if condition {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(type_error(msg.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn zlib(state: &mut OpState, handle: u32) -> Result<Rc<Zlib>, AnyError> {
|
||||
state
|
||||
.resource_table
|
||||
.get::<Zlib>(handle)
|
||||
.map_err(|_| bad_resource_id())
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct ZlibInner {
|
||||
dictionary: Option<Vec<u8>>,
|
||||
err: i32,
|
||||
flush: Flush,
|
||||
init_done: bool,
|
||||
level: i32,
|
||||
mem_level: i32,
|
||||
mode: Mode,
|
||||
strategy: i32,
|
||||
window_bits: i32,
|
||||
write_in_progress: bool,
|
||||
pending_close: bool,
|
||||
gzib_id_bytes_read: u32,
|
||||
strm: StreamWrapper,
|
||||
}
|
||||
|
||||
const GZIP_HEADER_ID1: u8 = 0x1f;
|
||||
const GZIP_HEADER_ID2: u8 = 0x8b;
|
||||
|
||||
impl ZlibInner {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn start_write(
|
||||
&mut self,
|
||||
input: &[u8],
|
||||
in_off: u32,
|
||||
in_len: u32,
|
||||
out: &mut [u8],
|
||||
out_off: u32,
|
||||
out_len: u32,
|
||||
flush: Flush,
|
||||
) -> Result<(), AnyError> {
|
||||
check(self.init_done, "write before init")?;
|
||||
check(!self.write_in_progress, "write already in progress")?;
|
||||
check(!self.pending_close, "close already in progress")?;
|
||||
|
||||
self.write_in_progress = true;
|
||||
|
||||
let next_in = input
|
||||
.get(in_off as usize..in_off as usize + in_len as usize)
|
||||
.ok_or_else(|| type_error("invalid input range"))?
|
||||
.as_ptr() as *mut _;
|
||||
let next_out = out
|
||||
.get_mut(out_off as usize..out_off as usize + out_len as usize)
|
||||
.ok_or_else(|| type_error("invalid output range"))?
|
||||
.as_mut_ptr();
|
||||
|
||||
self.strm.avail_in = in_len;
|
||||
self.strm.next_in = next_in;
|
||||
self.strm.avail_out = out_len;
|
||||
self.strm.next_out = next_out;
|
||||
|
||||
self.flush = flush;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn do_write(&mut self, flush: Flush) -> Result<(), AnyError> {
|
||||
self.flush = flush;
|
||||
match self.mode {
|
||||
Mode::Deflate | Mode::Gzip | Mode::DeflateRaw => {
|
||||
self.err = self.strm.deflate(flush);
|
||||
}
|
||||
// Auto-detect mode.
|
||||
Mode::Unzip if self.strm.avail_in > 0 => 'blck: {
|
||||
let mut next_expected_header_byte = Some(0);
|
||||
// SAFETY: `self.strm.next_in` is valid pointer to the input buffer.
|
||||
// `self.strm.avail_in` is the length of the input buffer that is only set by
|
||||
// `start_write`.
|
||||
let strm = unsafe {
|
||||
std::slice::from_raw_parts(
|
||||
self.strm.next_in,
|
||||
self.strm.avail_in as usize,
|
||||
)
|
||||
};
|
||||
|
||||
if self.gzib_id_bytes_read == 0 {
|
||||
if strm[0] == GZIP_HEADER_ID1 {
|
||||
self.gzib_id_bytes_read = 1;
|
||||
next_expected_header_byte = Some(1);
|
||||
|
||||
// Not enough.
|
||||
if self.strm.avail_in == 1 {
|
||||
break 'blck;
|
||||
}
|
||||
} else {
|
||||
self.mode = Mode::Inflate;
|
||||
next_expected_header_byte = None;
|
||||
}
|
||||
}
|
||||
|
||||
if self.gzib_id_bytes_read == 1 {
|
||||
let byte = match next_expected_header_byte {
|
||||
Some(i) => strm[i],
|
||||
None => break 'blck,
|
||||
};
|
||||
if byte == GZIP_HEADER_ID2 {
|
||||
self.gzib_id_bytes_read = 2;
|
||||
self.mode = Mode::Gunzip;
|
||||
} else {
|
||||
self.mode = Mode::Inflate;
|
||||
}
|
||||
} else if next_expected_header_byte.is_some() {
|
||||
return Err(type_error(
|
||||
"invalid number of gzip magic number bytes read",
|
||||
));
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match self.mode {
|
||||
Mode::Inflate
|
||||
| Mode::Gunzip
|
||||
| Mode::InflateRaw
|
||||
// We're still reading the header.
|
||||
| Mode::Unzip => {
|
||||
self.err = self.strm.inflate(self.flush);
|
||||
// TODO(@littledivy): Use if let chain when it is stable.
|
||||
// https://github.com/rust-lang/rust/issues/53667
|
||||
//
|
||||
// Data was encoded with dictionary
|
||||
if let (Z_NEED_DICT, Some(dictionary)) = (self.err, &self.dictionary) {
|
||||
self.err = self.strm.inflate_set_dictionary(dictionary);
|
||||
|
||||
if self.err == Z_OK {
|
||||
self.err = self.strm.inflate(flush);
|
||||
} else if self.err == Z_DATA_ERROR {
|
||||
self.err = Z_NEED_DICT;
|
||||
}
|
||||
}
|
||||
|
||||
while self.strm.avail_in > 0
|
||||
&& self.mode == Mode::Gunzip
|
||||
&& self.err == Z_STREAM_END
|
||||
// SAFETY: `strm` is a valid pointer to zlib strm.
|
||||
// `strm.next_in` is initialized to the input buffer.
|
||||
&& unsafe { *self.strm.next_in } != 0x00
|
||||
{
|
||||
self.err = self.strm.reset(self.mode);
|
||||
self.err = self.strm.inflate(flush);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
let done = self.strm.avail_out != 0 && self.flush == Flush::Finish;
|
||||
// We're are not done yet, but output buffer is full
|
||||
if self.err == Z_BUF_ERROR && !done {
|
||||
// Set to Z_OK to avoid reporting the error in JS.
|
||||
self.err = Z_OK;
|
||||
}
|
||||
|
||||
self.write_in_progress = false;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn init_stream(&mut self) -> Result<(), AnyError> {
|
||||
match self.mode {
|
||||
Mode::Gzip | Mode::Gunzip => self.window_bits += 16,
|
||||
Mode::Unzip => self.window_bits += 32,
|
||||
Mode::DeflateRaw | Mode::InflateRaw => self.window_bits *= -1,
|
||||
_ => {}
|
||||
}
|
||||
|
||||
self.err = match self.mode {
|
||||
Mode::Deflate | Mode::Gzip | Mode::DeflateRaw => self.strm.deflate_init(
|
||||
self.level,
|
||||
self.window_bits,
|
||||
self.mem_level,
|
||||
self.strategy,
|
||||
),
|
||||
Mode::Inflate | Mode::Gunzip | Mode::InflateRaw | Mode::Unzip => {
|
||||
self.strm.inflate_init(self.window_bits)
|
||||
}
|
||||
Mode::None => return Err(type_error("Unknown mode")),
|
||||
};
|
||||
|
||||
self.write_in_progress = false;
|
||||
self.init_done = true;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn close(&mut self) -> Result<bool, AnyError> {
|
||||
if self.write_in_progress {
|
||||
self.pending_close = true;
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
self.pending_close = false;
|
||||
check(self.init_done, "close before init")?;
|
||||
|
||||
self.strm.end(self.mode);
|
||||
self.mode = Mode::None;
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
fn reset_stream(&mut self) -> Result<(), AnyError> {
|
||||
self.err = self.strm.reset(self.mode);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
struct Zlib {
|
||||
inner: RefCell<ZlibInner>,
|
||||
}
|
||||
|
||||
impl deno_core::Resource for Zlib {
|
||||
fn name(&self) -> Cow<str> {
|
||||
"zlib".into()
|
||||
}
|
||||
}
|
||||
|
||||
#[op]
|
||||
pub fn op_zlib_new(state: &mut OpState, mode: i32) -> Result<u32, AnyError> {
|
||||
let mode = Mode::try_from(mode)?;
|
||||
|
||||
let inner = ZlibInner {
|
||||
mode,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
Ok(state.resource_table.add(Zlib {
|
||||
inner: RefCell::new(inner),
|
||||
}))
|
||||
}
|
||||
|
||||
#[op]
|
||||
pub fn op_zlib_close(state: &mut OpState, handle: u32) -> Result<(), AnyError> {
|
||||
let resource = zlib(state, handle)?;
|
||||
let mut zlib = resource.inner.borrow_mut();
|
||||
|
||||
// If there is a pending write, defer the close until the write is done.
|
||||
zlib.close()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[op]
|
||||
pub fn op_zlib_write_async(
|
||||
state: Rc<RefCell<OpState>>,
|
||||
handle: u32,
|
||||
flush: i32,
|
||||
input: &[u8],
|
||||
in_off: u32,
|
||||
in_len: u32,
|
||||
out: &mut [u8],
|
||||
out_off: u32,
|
||||
out_len: u32,
|
||||
) -> Result<
|
||||
impl Future<Output = Result<(i32, u32, u32), AnyError>> + 'static,
|
||||
AnyError,
|
||||
> {
|
||||
let mut state_mut = state.borrow_mut();
|
||||
let resource = zlib(&mut state_mut, handle)?;
|
||||
|
||||
let mut strm = resource.inner.borrow_mut();
|
||||
let flush = Flush::try_from(flush)?;
|
||||
strm.start_write(input, in_off, in_len, out, out_off, out_len, flush)?;
|
||||
|
||||
let state = state.clone();
|
||||
Ok(async move {
|
||||
let mut state_mut = state.borrow_mut();
|
||||
let resource = zlib(&mut state_mut, handle)?;
|
||||
let mut zlib = resource.inner.borrow_mut();
|
||||
|
||||
zlib.do_write(flush)?;
|
||||
Ok((zlib.err, zlib.strm.avail_out, zlib.strm.avail_in))
|
||||
})
|
||||
}
|
||||
|
||||
#[op]
|
||||
pub fn op_zlib_write(
|
||||
state: &mut OpState,
|
||||
handle: u32,
|
||||
flush: i32,
|
||||
input: &[u8],
|
||||
in_off: u32,
|
||||
in_len: u32,
|
||||
out: &mut [u8],
|
||||
out_off: u32,
|
||||
out_len: u32,
|
||||
result: &mut [u32],
|
||||
) -> Result<i32, AnyError> {
|
||||
let resource = zlib(state, handle)?;
|
||||
|
||||
let mut zlib = resource.inner.borrow_mut();
|
||||
let flush = Flush::try_from(flush)?;
|
||||
zlib.start_write(input, in_off, in_len, out, out_off, out_len, flush)?;
|
||||
zlib.do_write(flush)?;
|
||||
|
||||
result[0] = zlib.strm.avail_out;
|
||||
result[1] = zlib.strm.avail_in;
|
||||
|
||||
Ok(zlib.err)
|
||||
}
|
||||
|
||||
#[op]
|
||||
pub fn op_zlib_init(
|
||||
state: &mut OpState,
|
||||
handle: u32,
|
||||
level: i32,
|
||||
window_bits: i32,
|
||||
mem_level: i32,
|
||||
strategy: i32,
|
||||
dictionary: Option<&[u8]>,
|
||||
) -> Result<i32, AnyError> {
|
||||
let resource = zlib(state, handle)?;
|
||||
let mut zlib = resource.inner.borrow_mut();
|
||||
|
||||
check((8..=15).contains(&window_bits), "invalid windowBits")?;
|
||||
check((-1..=9).contains(&level), "invalid level")?;
|
||||
|
||||
check((1..=9).contains(&mem_level), "invalid memLevel")?;
|
||||
|
||||
check(
|
||||
strategy == Z_DEFAULT_STRATEGY
|
||||
|| strategy == Z_FILTERED
|
||||
|| strategy == Z_HUFFMAN_ONLY
|
||||
|| strategy == Z_RLE
|
||||
|| strategy == Z_FIXED,
|
||||
"invalid strategy",
|
||||
)?;
|
||||
|
||||
zlib.level = level;
|
||||
zlib.window_bits = window_bits;
|
||||
zlib.mem_level = mem_level;
|
||||
zlib.strategy = strategy;
|
||||
|
||||
zlib.flush = Flush::None;
|
||||
zlib.err = Z_OK;
|
||||
|
||||
zlib.init_stream()?;
|
||||
|
||||
zlib.dictionary = dictionary.map(|buf| buf.to_vec());
|
||||
|
||||
Ok(zlib.err)
|
||||
}
|
||||
|
||||
#[op]
|
||||
pub fn op_zlib_reset(
|
||||
state: &mut OpState,
|
||||
handle: u32,
|
||||
) -> Result<i32, AnyError> {
|
||||
let resource = zlib(state, handle)?;
|
||||
|
||||
let mut zlib = resource.inner.borrow_mut();
|
||||
zlib.reset_stream()?;
|
||||
|
||||
Ok(zlib.err)
|
||||
}
|
||||
|
||||
#[op]
|
||||
pub fn op_zlib_close_if_pending(
|
||||
state: &mut OpState,
|
||||
handle: u32,
|
||||
) -> Result<(), AnyError> {
|
||||
let resource = zlib(state, handle)?;
|
||||
let pending_close = {
|
||||
let mut zlib = resource.inner.borrow_mut();
|
||||
zlib.write_in_progress = false;
|
||||
zlib.pending_close
|
||||
};
|
||||
if pending_close {
|
||||
drop(resource);
|
||||
state.resource_table.close(handle)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn zlib_start_write() {
|
||||
// buffer, length, should pass
|
||||
type WriteVector = (&'static [u8], u32, u32, bool);
|
||||
const WRITE_VECTORS: [WriteVector; 8] = [
|
||||
(b"Hello", 5, 0, true),
|
||||
(b"H", 1, 0, true),
|
||||
(b"", 0, 0, true),
|
||||
// Overrun the buffer
|
||||
(b"H", 5, 0, false),
|
||||
(b"ello", 5, 0, false),
|
||||
(b"Hello", 5, 1, false),
|
||||
(b"H", 1, 1, false),
|
||||
(b"", 0, 1, false),
|
||||
];
|
||||
|
||||
for (input, len, offset, expected) in WRITE_VECTORS.iter() {
|
||||
let mut stream = ZlibInner {
|
||||
mode: Mode::Inflate,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
stream.init_stream().unwrap();
|
||||
assert_eq!(stream.err, Z_OK);
|
||||
assert_eq!(
|
||||
stream
|
||||
.start_write(input, *offset, *len, &mut [], 0, 0, Flush::None)
|
||||
.is_ok(),
|
||||
*expected
|
||||
);
|
||||
assert_eq!(stream.err, Z_OK);
|
||||
stream.close().unwrap();
|
||||
}
|
||||
}
|
||||
}
|
71
ext/node/zlib/mode.rs
Normal file
71
ext/node/zlib/mode.rs
Normal file
|
@ -0,0 +1,71 @@
|
|||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use libz_sys as sys;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
BadArgument,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Error::BadArgument => write!(f, "bad argument"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for Error {}
|
||||
|
||||
macro_rules! repr_i32 {
|
||||
($(#[$meta:meta])* $vis:vis enum $name:ident {
|
||||
$($(#[$vmeta:meta])* $vname:ident $(= $val:expr)?,)*
|
||||
}) => {
|
||||
$(#[$meta])*
|
||||
$vis enum $name {
|
||||
$($(#[$vmeta])* $vname $(= $val)?,)*
|
||||
}
|
||||
|
||||
impl core::convert::TryFrom<i32> for $name {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(v: i32) -> Result<Self, Self::Error> {
|
||||
match v {
|
||||
$(x if x == $name::$vname as i32 => Ok($name::$vname),)*
|
||||
_ => Err(Error::BadArgument),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
repr_i32! {
|
||||
#[repr(i32)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Default)]
|
||||
pub enum Mode {
|
||||
#[default]
|
||||
None,
|
||||
Deflate,
|
||||
Inflate,
|
||||
Gzip,
|
||||
Gunzip,
|
||||
DeflateRaw,
|
||||
InflateRaw,
|
||||
Unzip,
|
||||
}
|
||||
}
|
||||
|
||||
repr_i32! {
|
||||
#[repr(i32)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Default)]
|
||||
pub enum Flush {
|
||||
#[default]
|
||||
None = sys::Z_NO_FLUSH,
|
||||
Partial = sys::Z_PARTIAL_FLUSH,
|
||||
Sync = sys::Z_SYNC_FLUSH,
|
||||
Full = sys::Z_FULL_FLUSH,
|
||||
Finish = sys::Z_FINISH,
|
||||
Block = sys::Z_BLOCK,
|
||||
Trees = sys::Z_TREES,
|
||||
}
|
||||
}
|
136
ext/node/zlib/stream.rs
Normal file
136
ext/node/zlib/stream.rs
Normal file
|
@ -0,0 +1,136 @@
|
|||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use super::mode::Flush;
|
||||
use super::mode::Mode;
|
||||
use libz_sys as sys;
|
||||
use std::ffi::c_int;
|
||||
use std::ops::Deref;
|
||||
use std::ops::DerefMut;
|
||||
|
||||
pub struct StreamWrapper {
|
||||
pub strm: sys::z_stream,
|
||||
}
|
||||
|
||||
impl Default for StreamWrapper {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
strm: sys::z_stream {
|
||||
next_in: std::ptr::null_mut(),
|
||||
avail_in: 0,
|
||||
total_in: 0,
|
||||
next_out: std::ptr::null_mut(),
|
||||
avail_out: 0,
|
||||
total_out: 0,
|
||||
msg: std::ptr::null_mut(),
|
||||
state: std::ptr::null_mut(),
|
||||
zalloc: super::alloc::zalloc,
|
||||
zfree: super::alloc::zfree,
|
||||
opaque: 0 as sys::voidpf,
|
||||
data_type: 0,
|
||||
adler: 0,
|
||||
reserved: 0,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for StreamWrapper {
|
||||
type Target = sys::z_stream;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.strm
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for StreamWrapper {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.strm
|
||||
}
|
||||
}
|
||||
|
||||
impl StreamWrapper {
|
||||
pub fn reset(&mut self, mode: Mode) -> c_int {
|
||||
// SAFETY: `self.strm` is an initialized `z_stream`.
|
||||
unsafe {
|
||||
match mode {
|
||||
Mode::Deflate | Mode::Gzip | Mode::DeflateRaw => {
|
||||
sys::deflateReset(&mut self.strm)
|
||||
}
|
||||
Mode::Inflate | Mode::Gunzip | Mode::InflateRaw | Mode::Unzip => {
|
||||
sys::inflateReset(&mut self.strm)
|
||||
}
|
||||
Mode::None => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn end(&mut self, mode: Mode) {
|
||||
// SAFETY: `self.strm` is an initialized `z_stream`.
|
||||
unsafe {
|
||||
match mode {
|
||||
Mode::Deflate | Mode::Gzip | Mode::DeflateRaw => {
|
||||
sys::deflateEnd(&mut self.strm);
|
||||
}
|
||||
Mode::Inflate | Mode::Gunzip | Mode::InflateRaw | Mode::Unzip => {
|
||||
sys::inflateEnd(&mut self.strm);
|
||||
}
|
||||
Mode::None => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deflate_init(
|
||||
&mut self,
|
||||
level: c_int,
|
||||
window_bits: c_int,
|
||||
mem_level: c_int,
|
||||
strategy: c_int,
|
||||
) -> c_int {
|
||||
// SAFETY: `self.strm` is an initialized `z_stream`.
|
||||
unsafe {
|
||||
sys::deflateInit2_(
|
||||
&mut self.strm,
|
||||
level,
|
||||
sys::Z_DEFLATED,
|
||||
window_bits,
|
||||
mem_level,
|
||||
strategy,
|
||||
sys::zlibVersion(),
|
||||
std::mem::size_of::<sys::z_stream>() as i32,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn inflate_init(&mut self, window_bits: c_int) -> c_int {
|
||||
// SAFETY: `self.strm` is an initialized `z_stream`.
|
||||
unsafe {
|
||||
sys::inflateInit2_(
|
||||
&mut self.strm,
|
||||
window_bits,
|
||||
sys::zlibVersion(),
|
||||
std::mem::size_of::<sys::z_stream>() as i32,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deflate(&mut self, flush: Flush) -> c_int {
|
||||
// SAFETY: `self.strm` is an initialized `z_stream`.
|
||||
unsafe { sys::deflate(&mut self.strm, flush as _) }
|
||||
}
|
||||
|
||||
pub fn inflate(&mut self, flush: Flush) -> c_int {
|
||||
// SAFETY: `self.strm` is an initialized `z_stream`.
|
||||
unsafe { sys::inflate(&mut self.strm, flush as _) }
|
||||
}
|
||||
|
||||
pub fn inflate_set_dictionary(&mut self, dictionary: &[u8]) -> c_int {
|
||||
// SAFETY: `self.strm` is an initialized `z_stream`.
|
||||
unsafe {
|
||||
sys::inflateSetDictionary(
|
||||
&mut self.strm,
|
||||
dictionary.as_ptr() as *const _,
|
||||
dictionary.len() as _,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -329,6 +329,7 @@ pub(crate) fn generate(
|
|||
let fast_fn = q!(
|
||||
Vars { core, pre_transforms, op_name_fast: &fast_fn_ident, op_name: &ident, fast_fn_inputs, generics, call_generics: &caller_generics, where_clause, idents, transforms, output_transforms, output: &output },
|
||||
{
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn op_name_fast generics (_: core::v8::Local<core::v8::Object>, fast_fn_inputs) -> output where_clause {
|
||||
use core::v8;
|
||||
use core::_ops;
|
||||
|
|
|
@ -253,7 +253,7 @@ fn codegen_v8_async(
|
|||
let rust_i0 = special_args.len();
|
||||
let args_head = special_args.into_iter().collect::<TokenStream2>();
|
||||
|
||||
let (arg_decls, args_tail, _) = codegen_args(core, f, rust_i0, 1, true);
|
||||
let (arg_decls, args_tail, _) = codegen_args(core, f, rust_i0, 1, asyncness);
|
||||
let type_params = exclude_lifetime_params(&f.sig.generics.params);
|
||||
|
||||
let (pre_result, mut result_fut) = match asyncness {
|
||||
|
|
|
@ -101,6 +101,7 @@ impl<'scope> deno_core::v8::fast_api::FastFunction for op_void_async_fast {
|
|||
deno_core::v8::fast_api::CType::Void
|
||||
}
|
||||
}
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn op_void_async_fast_fn<'scope>(
|
||||
_: deno_core::v8::Local<deno_core::v8::Object>,
|
||||
__promise_id: i32,
|
||||
|
|
|
@ -111,6 +111,7 @@ impl<'scope> deno_core::v8::fast_api::FastFunction for op_async_result_fast {
|
|||
deno_core::v8::fast_api::CType::Void
|
||||
}
|
||||
}
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn op_async_result_fast_fn<'scope>(
|
||||
_: deno_core::v8::Local<deno_core::v8::Object>,
|
||||
__promise_id: i32,
|
||||
|
|
|
@ -70,6 +70,7 @@ impl<'scope> deno_core::v8::fast_api::FastFunction for op_fallback_fast {
|
|||
deno_core::v8::fast_api::CType::Void
|
||||
}
|
||||
}
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn op_fallback_fast_fn<'scope>(
|
||||
_: deno_core::v8::Local<deno_core::v8::Object>,
|
||||
fast_api_callback_options: *mut deno_core::v8::fast_api::FastApiCallbackOptions,
|
||||
|
|
|
@ -78,6 +78,7 @@ impl<'scope> deno_core::v8::fast_api::FastFunction for op_cow_str_fast {
|
|||
deno_core::v8::fast_api::CType::Void
|
||||
}
|
||||
}
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn op_cow_str_fast_fn<'scope>(
|
||||
_: deno_core::v8::Local<deno_core::v8::Object>,
|
||||
c: *const deno_core::v8::fast_api::FastApiOneByteString,
|
||||
|
|
|
@ -96,6 +96,7 @@ impl<'scope> deno_core::v8::fast_api::FastFunction for op_f64_buf_fast {
|
|||
deno_core::v8::fast_api::CType::Void
|
||||
}
|
||||
}
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn op_f64_buf_fast_fn<'scope>(
|
||||
_: deno_core::v8::Local<deno_core::v8::Object>,
|
||||
buffer: *const deno_core::v8::fast_api::FastApiTypedArray<f64>,
|
||||
|
|
|
@ -110,6 +110,7 @@ impl<'scope> deno_core::v8::fast_api::FastFunction for op_ffi_ptr_value_fast {
|
|||
deno_core::v8::fast_api::CType::Void
|
||||
}
|
||||
}
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn op_ffi_ptr_value_fast_fn<'scope>(
|
||||
_: deno_core::v8::Local<deno_core::v8::Object>,
|
||||
ptr: *mut ::std::ffi::c_void,
|
||||
|
|
|
@ -78,6 +78,7 @@ impl<'scope> deno_core::v8::fast_api::FastFunction for op_set_exit_code_fast {
|
|||
deno_core::v8::fast_api::CType::Void
|
||||
}
|
||||
}
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn op_set_exit_code_fast_fn<'scope>(
|
||||
_: deno_core::v8::Local<deno_core::v8::Object>,
|
||||
code: i32,
|
||||
|
|
|
@ -105,6 +105,7 @@ impl<'scope> deno_core::v8::fast_api::FastFunction for foo_fast {
|
|||
deno_core::v8::fast_api::CType::Uint32
|
||||
}
|
||||
}
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn foo_fast_fn<'scope>(
|
||||
_: deno_core::v8::Local<deno_core::v8::Object>,
|
||||
a: u32,
|
||||
|
|
|
@ -80,6 +80,7 @@ where
|
|||
deno_core::v8::fast_api::CType::Void
|
||||
}
|
||||
}
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn op_foo_fast_fn<'scope, SP>(
|
||||
_: deno_core::v8::Local<deno_core::v8::Object>,
|
||||
fast_api_callback_options: *mut deno_core::v8::fast_api::FastApiCallbackOptions,
|
||||
|
|
|
@ -118,6 +118,7 @@ impl<'scope> deno_core::v8::fast_api::FastFunction for foo_fast {
|
|||
deno_core::v8::fast_api::CType::Uint32
|
||||
}
|
||||
}
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn foo_fast_fn<'scope>(
|
||||
_: deno_core::v8::Local<deno_core::v8::Object>,
|
||||
a: u32,
|
||||
|
|
|
@ -109,6 +109,7 @@ impl<'scope> deno_core::v8::fast_api::FastFunction for op_listen_fast {
|
|||
deno_core::v8::fast_api::CType::Uint32
|
||||
}
|
||||
}
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn op_listen_fast_fn<'scope>(
|
||||
_: deno_core::v8::Local<deno_core::v8::Object>,
|
||||
fast_api_callback_options: *mut deno_core::v8::fast_api::FastApiCallbackOptions,
|
||||
|
|
|
@ -127,6 +127,7 @@ where
|
|||
deno_core::v8::fast_api::CType::Void
|
||||
}
|
||||
}
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn op_now_fast_fn<'scope, TP>(
|
||||
_: deno_core::v8::Local<deno_core::v8::Object>,
|
||||
buf: *const deno_core::v8::fast_api::FastApiTypedArray<u8>,
|
||||
|
|
|
@ -136,6 +136,7 @@ impl<'scope> deno_core::v8::fast_api::FastFunction for op_add_4_fast {
|
|||
deno_core::v8::fast_api::CType::Uint32
|
||||
}
|
||||
}
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn op_add_4_fast_fn<'scope>(
|
||||
_: deno_core::v8::Local<deno_core::v8::Object>,
|
||||
x1: u32,
|
||||
|
|
|
@ -90,6 +90,7 @@ impl<'scope> deno_core::v8::fast_api::FastFunction for op_string_length_fast {
|
|||
deno_core::v8::fast_api::CType::Uint32
|
||||
}
|
||||
}
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn op_string_length_fast_fn<'scope>(
|
||||
_: deno_core::v8::Local<deno_core::v8::Object>,
|
||||
string: *const deno_core::v8::fast_api::FastApiOneByteString,
|
||||
|
|
|
@ -153,6 +153,7 @@ where
|
|||
deno_core::v8::fast_api::CType::Void
|
||||
}
|
||||
}
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn op_ffi_ptr_of_fast_fn<'scope, FP>(
|
||||
_: deno_core::v8::Local<deno_core::v8::Object>,
|
||||
buf: *const deno_core::v8::fast_api::FastApiTypedArray<u8>,
|
||||
|
|
|
@ -90,6 +90,7 @@ impl<'scope> deno_core::v8::fast_api::FastFunction for op_is_proxy_fast {
|
|||
deno_core::v8::fast_api::CType::Bool
|
||||
}
|
||||
}
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn op_is_proxy_fast_fn<'scope>(
|
||||
_: deno_core::v8::Local<deno_core::v8::Object>,
|
||||
value: deno_core::v8::Local<v8::Value>,
|
||||
|
|
|
@ -91,6 +91,7 @@ impl<'scope> deno_core::v8::fast_api::FastFunction for op_string_length_fast {
|
|||
deno_core::v8::fast_api::CType::Uint32
|
||||
}
|
||||
}
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn op_string_length_fast_fn<'scope>(
|
||||
_: deno_core::v8::Local<deno_core::v8::Object>,
|
||||
string: *const deno_core::v8::fast_api::FastApiOneByteString,
|
||||
|
|
|
@ -167,6 +167,7 @@ impl<'scope> deno_core::v8::fast_api::FastFunction for op_import_spki_x25519_fas
|
|||
deno_core::v8::fast_api::CType::Bool
|
||||
}
|
||||
}
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn op_import_spki_x25519_fast_fn<'scope>(
|
||||
_: deno_core::v8::Local<deno_core::v8::Object>,
|
||||
key_data: *const deno_core::v8::fast_api::FastApiTypedArray<u8>,
|
||||
|
|
|
@ -90,6 +90,7 @@ impl<'scope> deno_core::v8::fast_api::FastFunction for op_unit_result_fast {
|
|||
deno_core::v8::fast_api::CType::Void
|
||||
}
|
||||
}
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn op_unit_result_fast_fn<'scope>(
|
||||
_: deno_core::v8::Local<deno_core::v8::Object>,
|
||||
fast_api_callback_options: *mut deno_core::v8::fast_api::FastApiCallbackOptions,
|
||||
|
|
|
@ -123,6 +123,7 @@ impl<'scope> deno_core::v8::fast_api::FastFunction for op_set_nodelay_fast {
|
|||
deno_core::v8::fast_api::CType::Void
|
||||
}
|
||||
}
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn op_set_nodelay_fast_fn<'scope>(
|
||||
_: deno_core::v8::Local<deno_core::v8::Object>,
|
||||
rid: ResourceId,
|
||||
|
|
|
@ -79,6 +79,7 @@ impl<'scope> deno_core::v8::fast_api::FastFunction for op_unit_fast {
|
|||
deno_core::v8::fast_api::CType::Void
|
||||
}
|
||||
}
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn op_unit_fast_fn<'scope>(_: deno_core::v8::Local<deno_core::v8::Object>) -> () {
|
||||
use deno_core::v8;
|
||||
use deno_core::_ops;
|
||||
|
|
|
@ -66,6 +66,7 @@ impl<'scope> deno_core::v8::fast_api::FastFunction for op_wasm_fast {
|
|||
deno_core::v8::fast_api::CType::Void
|
||||
}
|
||||
}
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn op_wasm_fast_fn<'scope>(
|
||||
_: deno_core::v8::Local<deno_core::v8::Object>,
|
||||
fast_api_callback_options: *mut deno_core::v8::fast_api::FastApiCallbackOptions,
|
||||
|
|
Loading…
Reference in a new issue