load/save algorithm
This commit is contained in:
parent
b9dbcc5de8
commit
a4f2da333f
103
src/vermiparous.ts
Normal file
103
src/vermiparous.ts
Normal file
@ -0,0 +1,103 @@
|
||||
const KEYWORDS = ["asset", "code"];
|
||||
const MIN_KW_LENGTH = Math.min(...KEYWORDS.map((x) => x.length));
|
||||
const SEMICOLON_CHARCODE = ";".charCodeAt(0);
|
||||
|
||||
function isKeyword(buffer: number[]) {
|
||||
const kw = String.fromCharCode(...buffer);
|
||||
return KEYWORDS.includes(kw);
|
||||
}
|
||||
|
||||
function strToBytes(str: string): number[] {
|
||||
return str.split("").map((x) => x.charCodeAt(0));
|
||||
}
|
||||
|
||||
type EncAsset = {
|
||||
name: string;
|
||||
mime: string;
|
||||
content: Uint8Array;
|
||||
};
|
||||
|
||||
type DecAssic = {
|
||||
tag: "code" | "asset";
|
||||
name: string;
|
||||
mime: string;
|
||||
content: Uint8Array;
|
||||
};
|
||||
|
||||
export class Vermiparous {
|
||||
private constructor() {}
|
||||
static en(code: string, assets: EncAsset[]): Uint8Array {
|
||||
const ret: number[] = [];
|
||||
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.content.length.toString()));
|
||||
ret.push(...strToBytes(";"));
|
||||
ret.push(...strToBytes(asset.name));
|
||||
ret.push(...strToBytes(asset.mime));
|
||||
ret.push(...asset.content);
|
||||
}
|
||||
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: Uint8Array): DecAssic[] {
|
||||
const ret = [];
|
||||
let buffer = [];
|
||||
let idx = 0;
|
||||
while (idx < bytes.length) {
|
||||
buffer.push(bytes[idx]);
|
||||
if (buffer.length < MIN_KW_LENGTH) {
|
||||
++idx;
|
||||
continue;
|
||||
}
|
||||
if (!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) as DecAssic["tag"],
|
||||
name: String.fromCharCode(...name),
|
||||
mime: String.fromCharCode(...mime),
|
||||
content: new Uint8Array(content),
|
||||
});
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user