/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
import { fromBase64 } from "../../utils/base64";
import { WASM_BASE64 } from "./lzxd-bg";
/**
* Minimal glue for the lzxd WebAssembly module. Mirrors the wasm-bindgen
* exports of lzxd 0.1.5 (https://github.com/Lonami/lzxd) while being
* self-contained (the wasm binary is embedded as base64).
*/
export enum WindowSize {
KB32 = 32768,
KB64 = 65536,
KB128 = 131072,
KB256 = 262144,
KB512 = 524288,
MB1 = 1048576,
MB2 = 2097152,
MB4 = 4194304,
MB8 = 8388608,
MB16 = 16777216,
MB32 = 33554432
}
type WasmExports = {
memory: WebAssembly.Memory;
__wbindgen_malloc: (len: number) => number;
__wbindgen_realloc: (ptr: number, oldSize: number, newSize: number) => number;
__wbindgen_free: (ptr: number, size: number) => void;
__wbindgen_add_to_stack_pointer: (delta: number) => number;
lzxd_new: (windowSize: number) => number;
lzxd_decompress_next: (
retptr: number,
ptr: number,
dataPtr: number,
len: number
) => void;
__wbg_lzxd_free: (ptr: number) => void;
};
let wasmPromise: Promise | undefined;
async function getWasm(): Promise {
if (!wasmPromise) {
wasmPromise = (async () => {
const bytes = fromBase64(WASM_BASE64);
const imports = {
__wbindgen_placeholder__: {
__wbindgen_string_new: () => addHeapObject(new Error()),
__wbg_new_abda76e883ba8a5f: () => addHeapObject(new Error()),
__wbg_stack_658279fe44541cf6: () => {},
__wbg_error_f851667af71bcfc6: () => {},
__wbindgen_object_drop_ref: () => {},
__wbindgen_throw: () => {}
}
};
const { instance } = await WebAssembly.instantiate(bytes, imports);
return instance.exports as unknown as WasmExports;
})();
}
return wasmPromise;
}
const heap: unknown[] = new Array(128).fill(undefined);
heap.push(undefined, null, true, false);
let heapNext = heap.length;
function addHeapObject(obj: unknown): number {
if (heapNext === heap.length) heap.push(heap.length + 1);
const idx = heapNext;
heapNext = heap[idx] as number;
heap[idx] = obj;
return idx;
}
function takeObject(idx: number): unknown {
const ret = heap[idx];
if (idx < 132) return ret;
heap[idx] = heapNext;
heapNext = idx;
return ret;
}
let wasmVectorLen = 0;
export class Lzxd {
private ptr: number;
private constructor(ptr: number, private readonly wasm: WasmExports) {
this.ptr = ptr;
}
static async create(windowSize: number): Promise {
const wasm = await getWasm();
const ptr = wasm.lzxd_new(windowSize);
return new Lzxd(ptr, wasm);
}
free() {
this.wasm.__wbg_lzxd_free(this.ptr);
this.ptr = 0;
}
/** Decompresses the next compressed chunk. */
decompressNext(chunk: Uint8Array): Uint8Array {
const wasm = this.wasm;
// The wasm memory may grow during the call which invalidates cached
// views, so create fresh views on every call.
let uint8Memory = new Uint8Array(wasm.memory.buffer);
let int32Memory = new Int32Array(wasm.memory.buffer);
try {
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
const ptr0 = wasm.__wbindgen_malloc(chunk.length);
uint8Memory.set(chunk, ptr0);
wasmVectorLen = chunk.length;
wasm.lzxd_decompress_next(retptr, this.ptr, ptr0, wasmVectorLen);
uint8Memory = new Uint8Array(wasm.memory.buffer);
int32Memory = new Int32Array(wasm.memory.buffer);
const r0 = int32Memory[retptr / 4 + 0];
const r1 = int32Memory[retptr / 4 + 1];
const r2 = int32Memory[retptr / 4 + 2];
const r3 = int32Memory[retptr / 4 + 3];
if (r3) {
throw takeObject(r2) as Error;
}
const result = new Uint8Array(uint8Memory.slice(r0, r0 + r1));
wasm.__wbindgen_free(r0, r1);
return result;
} finally {
wasm.__wbindgen_add_to_stack_pointer(16);
}
}
}