94 lines
3.2 KiB
JavaScript
94 lines
3.2 KiB
JavaScript
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 ! unrecognized action '${
|
|
JSON.stringify(buffer)
|
|
}'`,
|
|
);
|
|
}
|
|
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 components = [];
|
|
for (let componentsIdx = 0; componentsIdx < 3; ++componentsIdx) {
|
|
let componentContentIdx = 0;
|
|
while (componentContentIdx < sizes[componentsIdx]) {
|
|
const byte = bytes[idx];
|
|
buffer.push(byte);
|
|
idx++;
|
|
componentContentIdx++;
|
|
}
|
|
components.push(buffer);
|
|
buffer = [];
|
|
}
|
|
const [name, mime, content] = components;
|
|
ret.push({
|
|
tag: String.fromCharCode(...tag),
|
|
name: String.fromCharCode(...name),
|
|
mime: String.fromCharCode(...mime),
|
|
content: new Uint8Array(content),
|
|
});
|
|
}
|
|
return ret;
|
|
}
|
|
}
|