(() => { const fcp = String.fromCodePoint; const L = "length"; /** * @param {Uint8Array} input * @returns {Uint8Array} */ function compress(input) { const codewords = []; const dictionary = new Map(); for (let i = 0; i < 256; i++) dictionary.set(fcp(i), i); let buf = "", next = "", bufnext = ""; for (let x of input) { next = fcp(x); bufnext = buf + next; if (dictionary.has(bufnext)) buf = bufnext; else { codewords.push(dictionary.set(bufnext, dictionary.size).get(buf)); buf = next; } } codewords.push(dictionary.get(buf)); return ((input) => { /** * Condenses a byte array into an array of numbers. * @param {Uint32Array} input * @returns {Uint8Array} */ const max = input.reduce((p = 0, n) => n > p ? n : p); const bits = 1 + Math.floor(Math.log2(max)); const output = new Uint8Array(1 + 4 + Math.ceil(input[L] * bits / 8)); output[0] = bits; for (let i = 0; i < 4; i++) output[1 + i] = (input[L] >> (i * 8)) & 0xff; for (let i = 0; i < input[L]; i++) for (let j = 0; j < bits; j++) { const k = 8 * 5 + (i * bits + j); output[k >> 3] |= (1 << ((k % 8))) * ((input[i] >> j) & 1); } return output; })(codewords); } /** * @param {Uint8Array} input * @returns {Uint8Array} */ function decompress(input) { const codewords = ((input) => { /** * Uncondenses a byte array into an array of numbers. * @param {Uint8Array} input * @returns {Uint32Array} */ const bits = input[0]; const length = input.slice(1, 5).reverse().reduce((p, n) => (p << 8) | n, 0); const output = new Uint32Array(length); for (let i = 0; i < input[L]; i++) for (let j = 0; j < bits; j++) { const k = 8 * 5 + (i * bits + j); output[i] |= (1 << j) * ((input[k >> 3] >> (k % 8)) & 1); } return output; })(input); const dictionary = []; for (let i = 0; i < 256; i++) dictionary.push(fcp(i)); let prev = dictionary[codewords[0]], next = ""; const values = [prev]; for (let k of codewords.slice(1)) { values.push(next = k < dictionary[L] ? dictionary[k] : prev + prev[0]); dictionary.push(prev + next[0]); prev = next; } const output = []; for (let c of values.join("")) output.push(c.codePointAt(0)); return new Uint8Array(output); } return { compress, decompress }; })()