Added Zstd Compress / Zstd Decompress operations.
This commit is contained in:
parent
1eccfa729b
commit
8bb4748c5e
7
package-lock.json
generated
7
package-lock.json
generated
@ -13,6 +13,7 @@
|
|||||||
"@astronautlabs/amf": "^0.0.6",
|
"@astronautlabs/amf": "^0.0.6",
|
||||||
"@babel/polyfill": "^7.12.1",
|
"@babel/polyfill": "^7.12.1",
|
||||||
"@blu3r4y/lzma": "^2.3.3",
|
"@blu3r4y/lzma": "^2.3.3",
|
||||||
|
"@bokuweb/zstd-wasm": "^0.0.27",
|
||||||
"@wavesenterprise/crypto-gost-js": "^2.1.0-RC1",
|
"@wavesenterprise/crypto-gost-js": "^2.1.0-RC1",
|
||||||
"@xmldom/xmldom": "^0.8.11",
|
"@xmldom/xmldom": "^0.8.11",
|
||||||
"argon2-browser": "^1.18.0",
|
"argon2-browser": "^1.18.0",
|
||||||
@ -1838,6 +1839,12 @@
|
|||||||
"lzma.js": "bin/lzma.js"
|
"lzma.js": "bin/lzma.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@bokuweb/zstd-wasm": {
|
||||||
|
"version": "0.0.27",
|
||||||
|
"resolved": "https://registry.npmjs.org/@bokuweb/zstd-wasm/-/zstd-wasm-0.0.27.tgz",
|
||||||
|
"integrity": "sha512-GDm2uOTK3ESjnYmSeLQifJnBsRCWajKLvN32D2ZcQaaCIJI/Hse9s74f7APXjHit95S10UImsRGkTsbwHmrtmg==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@codemirror/commands": {
|
"node_modules/@codemirror/commands": {
|
||||||
"version": "6.10.2",
|
"version": "6.10.2",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.10.2.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.10.2.tgz",
|
||||||
|
|||||||
@ -99,6 +99,7 @@
|
|||||||
"@astronautlabs/amf": "^0.0.6",
|
"@astronautlabs/amf": "^0.0.6",
|
||||||
"@babel/polyfill": "^7.12.1",
|
"@babel/polyfill": "^7.12.1",
|
||||||
"@blu3r4y/lzma": "^2.3.3",
|
"@blu3r4y/lzma": "^2.3.3",
|
||||||
|
"@bokuweb/zstd-wasm": "^0.0.27",
|
||||||
"@wavesenterprise/crypto-gost-js": "^2.1.0-RC1",
|
"@wavesenterprise/crypto-gost-js": "^2.1.0-RC1",
|
||||||
"@xmldom/xmldom": "^0.8.11",
|
"@xmldom/xmldom": "^0.8.11",
|
||||||
"argon2-browser": "^1.18.0",
|
"argon2-browser": "^1.18.0",
|
||||||
|
|||||||
@ -402,7 +402,9 @@
|
|||||||
"LZMA Compress",
|
"LZMA Compress",
|
||||||
"LZ4 Decompress",
|
"LZ4 Decompress",
|
||||||
"LZ4 Compress",
|
"LZ4 Compress",
|
||||||
"LZNT1 Decompress"
|
"LZNT1 Decompress",
|
||||||
|
"Zstd Compress",
|
||||||
|
"Zstd Decompress"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
30
src/core/lib/Zstd.mjs
Normal file
30
src/core/lib/Zstd.mjs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
/**
|
||||||
|
* Zstd shared initialisation.
|
||||||
|
*
|
||||||
|
* Both ZstdCompress and ZstdDecompress import from here so that
|
||||||
|
* WebAssembly.instantiate is called exactly once, regardless of how many
|
||||||
|
* operations use it or in what order they run.
|
||||||
|
*
|
||||||
|
* @author n1474335 [n1474335@gmail.com]
|
||||||
|
* @copyright Crown Copyright 2024
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { init, compress, decompress } from "@bokuweb/zstd-wasm";
|
||||||
|
|
||||||
|
let initPromise = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a promise that resolves once the Zstd WASM module is ready.
|
||||||
|
* Safe to call multiple times — the module is only instantiated once.
|
||||||
|
*
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
export function zstdInit() {
|
||||||
|
if (!initPromise) {
|
||||||
|
initPromise = init();
|
||||||
|
}
|
||||||
|
return initPromise;
|
||||||
|
}
|
||||||
|
|
||||||
|
export { compress, decompress };
|
||||||
61
src/core/operations/ZstdCompress.mjs
Normal file
61
src/core/operations/ZstdCompress.mjs
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
/**
|
||||||
|
* @author Leon Zandman [leon@wirwar.com]
|
||||||
|
* @copyright Crown Copyright 2027
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Operation from "../Operation.mjs";
|
||||||
|
import OperationError from "../errors/OperationError.mjs";
|
||||||
|
import { isWorkerEnvironment } from "../Utils.mjs";
|
||||||
|
import { zstdInit, compress } from "../lib/Zstd.mjs";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Zstd Compress operation
|
||||||
|
*/
|
||||||
|
class ZstdCompress extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ZstdCompress constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "Zstd Compress";
|
||||||
|
this.module = "Compression";
|
||||||
|
this.description = "Compresses data using the Zstandard (Zstd) algorithm. Zstd offers high compression ratios at fast speeds and is widely used in Linux, databases, container images, and network protocols.";
|
||||||
|
this.infoURL = "https://wikipedia.org/wiki/Zstandard";
|
||||||
|
this.inputType = "ArrayBuffer";
|
||||||
|
this.outputType = "ArrayBuffer";
|
||||||
|
this.args = [
|
||||||
|
{
|
||||||
|
name: "Compression level",
|
||||||
|
type: "number",
|
||||||
|
value: 3,
|
||||||
|
min: 1,
|
||||||
|
max: 22
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {ArrayBuffer} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {ArrayBuffer}
|
||||||
|
*/
|
||||||
|
async run(input, args) {
|
||||||
|
const [level] = args;
|
||||||
|
if (input.byteLength === 0) throw new OperationError("Please provide an input.");
|
||||||
|
if (isWorkerEnvironment()) self.sendStatusMessage("Loading Zstd...");
|
||||||
|
await zstdInit();
|
||||||
|
if (isWorkerEnvironment()) self.sendStatusMessage("Compressing data...");
|
||||||
|
try {
|
||||||
|
const result = compress(new Uint8Array(input), level);
|
||||||
|
return result.buffer.slice(result.byteOffset, result.byteOffset + result.byteLength);
|
||||||
|
} catch (err) {
|
||||||
|
throw new OperationError(`Failed to compress: ${err.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ZstdCompress;
|
||||||
59
src/core/operations/ZstdDecompress.mjs
Normal file
59
src/core/operations/ZstdDecompress.mjs
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
/**
|
||||||
|
* @author Leon Zandman [leon@wirwar.com]
|
||||||
|
* @copyright Crown Copyright 2027
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Operation from "../Operation.mjs";
|
||||||
|
import OperationError from "../errors/OperationError.mjs";
|
||||||
|
import { isWorkerEnvironment } from "../Utils.mjs";
|
||||||
|
import { zstdInit, decompress } from "../lib/Zstd.mjs";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Zstd Decompress operation
|
||||||
|
*/
|
||||||
|
class ZstdDecompress extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ZstdDecompress constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "Zstd Decompress";
|
||||||
|
this.module = "Compression";
|
||||||
|
this.description = "Decompresses data compressed with the Zstandard (Zstd) algorithm.";
|
||||||
|
this.infoURL = "https://wikipedia.org/wiki/Zstandard";
|
||||||
|
this.inputType = "ArrayBuffer";
|
||||||
|
this.outputType = "ArrayBuffer";
|
||||||
|
this.args = [];
|
||||||
|
this.checks = [
|
||||||
|
{
|
||||||
|
pattern: "^\\x28\\xb5\\x2f\\xfd",
|
||||||
|
flags: "",
|
||||||
|
args: []
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {ArrayBuffer} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {ArrayBuffer}
|
||||||
|
*/
|
||||||
|
async run(input, args) {
|
||||||
|
if (input.byteLength === 0) throw new OperationError("Please provide an input.");
|
||||||
|
if (isWorkerEnvironment()) self.sendStatusMessage("Loading Zstd...");
|
||||||
|
await zstdInit();
|
||||||
|
if (isWorkerEnvironment()) self.sendStatusMessage("Decompressing data...");
|
||||||
|
try {
|
||||||
|
const result = decompress(new Uint8Array(input));
|
||||||
|
return result.buffer.slice(result.byteOffset, result.byteOffset + result.byteLength);
|
||||||
|
} catch (err) {
|
||||||
|
throw new OperationError(`Failed to decompress: ${err.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ZstdDecompress;
|
||||||
@ -182,6 +182,7 @@ import "./tests/JSONtoYAML.mjs";
|
|||||||
import "./tests/YARA.mjs";
|
import "./tests/YARA.mjs";
|
||||||
import "./tests/ParseCSR.mjs";
|
import "./tests/ParseCSR.mjs";
|
||||||
import "./tests/XXTEA.mjs";
|
import "./tests/XXTEA.mjs";
|
||||||
|
import "./tests/Zstd.mjs";
|
||||||
|
|
||||||
const testStatus = {
|
const testStatus = {
|
||||||
allTestsPassing: true,
|
allTestsPassing: true,
|
||||||
|
|||||||
80
tests/operations/tests/Zstd.mjs
Normal file
80
tests/operations/tests/Zstd.mjs
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
/**
|
||||||
|
* Zstd tests.
|
||||||
|
*
|
||||||
|
* @author n1474335 [n1474335@gmail.com]
|
||||||
|
* @copyright Crown Copyright 2024
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
import TestRegister from "../../lib/TestRegister.mjs";
|
||||||
|
|
||||||
|
TestRegister.addTests([
|
||||||
|
{
|
||||||
|
name: "Zstd compress & decompress: string",
|
||||||
|
input: "The cat sat on the mat.",
|
||||||
|
expectedOutput: "The cat sat on the mat.",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Zstd Compress",
|
||||||
|
args: [3]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
op: "Zstd Decompress",
|
||||||
|
args: []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Generated using: node --input-type=module -e "import {init,compress} from '@bokuweb/zstd-wasm'; await init(); const r=compress(new TextEncoder().encode('The cat sat on the mat.'),3); console.log(Buffer.from(r).toString('hex'));"
|
||||||
|
name: "Zstd compress: level 3",
|
||||||
|
input: "The cat sat on the mat.",
|
||||||
|
expectedOutput: "28b52ffd2017b900005468652063617420736174206f6e20746865206d61742e",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Zstd Compress",
|
||||||
|
args: [3]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
op: "To Hex",
|
||||||
|
args: ["None", 0]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Generated using: node --input-type=module -e "import {init,compress} from '@bokuweb/zstd-wasm'; await init(); const r=compress(new TextEncoder().encode('The cat sat on the mat.'),3); console.log(Buffer.from(r).toString('hex'));"
|
||||||
|
name: "Zstd decompress: known vector",
|
||||||
|
input: "28b52ffd2017b900005468652063617420736174206f6e20746865206d61742e",
|
||||||
|
expectedOutput: "The cat sat on the mat.",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "From Hex",
|
||||||
|
args: ["None"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
op: "Zstd Decompress",
|
||||||
|
args: []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Zstd compress: empty input error",
|
||||||
|
input: "",
|
||||||
|
expectedOutput: "Please provide an input.",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Zstd Compress",
|
||||||
|
args: [3]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Zstd decompress: empty input error",
|
||||||
|
input: "",
|
||||||
|
expectedOutput: "Please provide an input.",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Zstd Decompress",
|
||||||
|
args: []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]);
|
||||||
Loading…
x
Reference in New Issue
Block a user