const KEYWORDS = ["asset", "code"]; const MIN_KW_LENGTH = Math.min(...KEYWORDS.map((x) => x.length)); const MAX_KW_LENGTH = Math.max(...KEYWORDS.map((x) => x.length)); const SEMICOLON_CHARCODE = ";".charCodeAt(0); function isKeyword(buffer) { const kw = buffer.map((x) => String.fromCharCode(x)).join(""); return KEYWORDS.includes(kw); } function strToBytes(str) { return str.split("").map((x) => x.charCodeAt(0)); } export class Vermiparous { static en(code, assets) { const ret = []; for (const asset of assets) { ret.push(...strToBytes("asset")); ret.push(...strToBytes(asset.name.length.toString())); ret.push(...strToBytes(";")); ret.push(...strToBytes(asset.mime.length.toString())); ret.push(...strToBytes(";")); ret.push(...strToBytes(asset.bytes.length.toString())); ret.push(...strToBytes(";")); ret.push(...strToBytes(asset.name)); ret.push(...strToBytes(asset.mime)); ret.push(...asset.bytes); } ret.push(...strToBytes("code")); ret.push(...strToBytes("0;0;")); ret.push(...strToBytes(code.length.toString())); ret.push(...strToBytes(";")); ret.push(...strToBytes(code)); return new Uint8Array(ret); } static de(bytes) { const ret = []; let buffer = []; let idx = 0; while (idx < bytes.length) { buffer.push(bytes[idx]); if (buffer.length >= MAX_KW_LENGTH) { throw new Error("unreachable: something went wrong !"); } if (buffer.length < MIN_KW_LENGTH || !isKeyword(buffer)) { ++idx; continue; } const tag = buffer; buffer = []; ++idx; /* skip keyword last byte */ const sizes = []; for (let sizeIdx = 0; sizeIdx < 3; ++sizeIdx) { while (idx < bytes.length) { if (bytes[idx] === SEMICOLON_CHARCODE) { ++idx; break; } buffer.push(bytes[idx]); ++idx; } sizes.push(parseInt(String.fromCharCode(...buffer))); buffer = []; } const consoom = []; for (let consoomIdx = 0; consoomIdx < 3; ++consoomIdx) { let idekman = 0; while (idekman < sizes[consoomIdx]) { const byte = bytes[idx]; buffer.push(byte); idx++; idekman++; } consoom.push(buffer); buffer = []; } const [name, mime, content] = consoom; ret.push({ tag: String.fromCharCode(...tag), name: String.fromCharCode(...name), mime: String.fromCharCode(...mime), content: new Uint8Array(content), }); } return ret; } }