mirror of
https://github.com/gchq/CyberChef.git
synced 2025-04-21 07:16:17 -04:00
feat: working decompression
This commit is contained in:
parent
d635cca210
commit
3412296a76
3 changed files with 97 additions and 0 deletions
6
package-lock.json
generated
6
package-lock.json
generated
|
@ -44,6 +44,7 @@
|
||||||
"fernet": "^0.4.0",
|
"fernet": "^0.4.0",
|
||||||
"file-saver": "^2.0.5",
|
"file-saver": "^2.0.5",
|
||||||
"flat": "^6.0.1",
|
"flat": "^6.0.1",
|
||||||
|
"fzstd": "^0.1.1",
|
||||||
"geodesy": "1.1.3",
|
"geodesy": "1.1.3",
|
||||||
"highlight.js": "^11.9.0",
|
"highlight.js": "^11.9.0",
|
||||||
"ieee754": "^1.2.1",
|
"ieee754": "^1.2.1",
|
||||||
|
@ -7916,6 +7917,11 @@
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/fzstd": {
|
||||||
|
"version": "0.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/fzstd/-/fzstd-0.1.1.tgz",
|
||||||
|
"integrity": "sha512-dkuVSOKKwh3eas5VkJy1AW1vFpet8TA/fGmVA5krThl8YcOVE/8ZIoEA1+U1vEn5ckxxhLirSdY837azmbaNHA=="
|
||||||
|
},
|
||||||
"node_modules/gamma": {
|
"node_modules/gamma": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
|
|
|
@ -128,6 +128,7 @@
|
||||||
"fernet": "^0.4.0",
|
"fernet": "^0.4.0",
|
||||||
"file-saver": "^2.0.5",
|
"file-saver": "^2.0.5",
|
||||||
"flat": "^6.0.1",
|
"flat": "^6.0.1",
|
||||||
|
"fzstd": "^0.1.1",
|
||||||
"geodesy": "1.1.3",
|
"geodesy": "1.1.3",
|
||||||
"highlight.js": "^11.9.0",
|
"highlight.js": "^11.9.0",
|
||||||
"ieee754": "^1.2.1",
|
"ieee754": "^1.2.1",
|
||||||
|
|
90
src/core/operations/ZStandardDecompress.mjs
Normal file
90
src/core/operations/ZStandardDecompress.mjs
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
/**
|
||||||
|
* @author Scarjit [ferdinand@linnenberg.dev]
|
||||||
|
* @copyright Crown Copyright 2024
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
global.document = {};
|
||||||
|
import Operation from "../Operation.mjs";
|
||||||
|
import OperationError from "../errors/OperationError.mjs";
|
||||||
|
import {isWorkerEnvironment} from "../Utils.mjs";
|
||||||
|
import * as fzstd from "fzstd";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ZStandard Decompress operation
|
||||||
|
*/
|
||||||
|
class ZStandardDecompress extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ZStandardDecompress constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "ZStandard Decompress";
|
||||||
|
this.module = "Compress";
|
||||||
|
this.description = "ZStandard is a compression algorithm focused on fast decompression.";
|
||||||
|
this.infoURL = "https://wikipedia.org/wiki/Zstd"; // Usually a Wikipedia link. Remember to remove localisation (i.e. https://wikipedia.org/etc rather than https://en.wikipedia.org/etc)
|
||||||
|
this.inputType = "ArrayBuffer";
|
||||||
|
this.outputType = "ArrayBuffer";
|
||||||
|
this.args = [
|
||||||
|
{
|
||||||
|
"name": "Chunk Size (bytes)",
|
||||||
|
"type": "number",
|
||||||
|
"value": 65536
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {ArrayBuffer} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {ArrayBuffer}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
const chunkSize = args[0];
|
||||||
|
if (input.byteLength <= 0) {
|
||||||
|
throw new OperationError("Please provide an input.");
|
||||||
|
}
|
||||||
|
// Validate input starts with ZStandard magic number
|
||||||
|
const magicNumber = new Uint8Array(input, 0, 4);
|
||||||
|
if (magicNumber[0] !== 0x28 || magicNumber[1] !== 0xb5 || magicNumber[2] !== 0x2f || magicNumber[3] !== 0xfd) {
|
||||||
|
throw new OperationError("Invalid ZStandard input: does not start with magic number.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isWorkerEnvironment()) self.sendStatusMessage("Loading ZStandard...");
|
||||||
|
return new Promise(async (resolve, reject) => {
|
||||||
|
const compressed = new Uint8Array(input);
|
||||||
|
try {
|
||||||
|
const outChunks = []; // Array of Uint8Array chunks
|
||||||
|
const stream = new fzstd.Decompress((chunk, isLast) => {
|
||||||
|
// Add to list of output chunks
|
||||||
|
outChunks.push(chunk);
|
||||||
|
// Log after all chunks decompressed
|
||||||
|
if (isLast) {
|
||||||
|
// Combine all chunks into a single Uint8Array
|
||||||
|
const totalLength = outChunks.reduce((sum, chunk) => sum + chunk.length, 0);
|
||||||
|
const result = new Uint8Array(totalLength);
|
||||||
|
let offset = 0;
|
||||||
|
for (const chunk of outChunks) {
|
||||||
|
result.set(chunk, offset);
|
||||||
|
offset += chunk.length;
|
||||||
|
}
|
||||||
|
resolve(result.buffer);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
for (let i = 0; i < compressed.length; i += chunkSize) {
|
||||||
|
if (isWorkerEnvironment()) self.sendStatusMessage(`Decompressing chunk ${i / chunkSize + 1} of ${Math.ceil(compressed.length / chunkSize)}`);
|
||||||
|
const chunk = compressed.subarray(i, i + chunkSize);
|
||||||
|
stream.push(chunk);
|
||||||
|
}
|
||||||
|
stream.push(new Uint8Array(0), true); // Signal end of stream
|
||||||
|
} catch (error) {
|
||||||
|
reject(new OperationError("Decompression failed: " + error.message));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ZStandardDecompress;
|
Loading…
Add table
Add a link
Reference in a new issue