import { Name } from "./name"; import { memcpy } from "./env"; import { check } from "./system"; export interface Packer { pack(enc: Encoder): usize; unpack(data: u8[]): usize; getSize(): usize; } class Template implements Packer { pack(enc: Encoder): usize { return 0; } unpack(data: u8[]): usize { let dec = new Decoder(data); return dec.getPos(); } getSize(): usize { return 0; } } export class Encoder { buf: Array; pos: usize; constructor(bufferSize: usize) { this.buf = new Array(bufferSize); } checkPos(n: usize): void { if (this.pos + n > this.buf.length) { check(false, `checkPos: buffer overflow`); } } incPos(n: usize): void { this.pos += n; if (this.pos > this.buf.length) { check(false, `incPos: buffer overflow`); } } getPos(): usize { return this.pos; } @inline public static pack(packer: T): u8[] { let enc = new Encoder(packer.getSize()); packer.pack(enc); return enc.getBytes(); } pack(ser: T): usize { return ser.pack(this); } writeBytes(arr: u8[]): usize { let dataSize = arr.length; this.checkPos(dataSize); let src = arr.dataStart; let pos = this.pos; let dest = this.buf.dataStart + pos; memcpy(dest, src, dataSize); this.incPos(dataSize); return dataSize; } packNumberArray(arr: T[]): usize { let lengthBytes = this.packLength(arr.length); let dataSize = sizeof()*arr.length; let src = arr.dataStart; let pos = this.pos; this.incPos(dataSize); let dest = this.buf.dataStart + pos; memcpy(dest, src, dataSize); return lengthBytes + dataSize; } packNumber(n: T): usize { let pos = this.pos; let size = sizeof(); this.incPos(size); store(this.buf.dataStart + pos, n); return size; } packName(n: Name): usize { this.packNumber(n.N); return 8; } packLength(val: u32): usize { let length: u32 = 0; while (true) { let b = (val & 0x7f); val >>= 7; if (val > 0) { b |= (1 << 7); } this.packNumber(b); length += 1; if (val <= 0) { break; } } return length; } packString(s: string): usize { let utf8Str = String.UTF8.encode(s); let packedLength = this.packLength(utf8Str.byteLength); // let view = new DataView(utf8Str); let src = changetype(utf8Str); let dest = this.buf.dataStart + this.pos; this.incPos(utf8Str.byteLength); memcpy(dest, src, utf8Str.byteLength); return packedLength + utf8Str.byteLength; } packStringArray(arr: string[]): usize { let oldPos = this.pos; this.packLength(arr.length); for (let i=0; i(arr: T[]): usize { let oldPos = this.pos; this.packLength(arr.length); for (let i=0; ithis.pos); } } export class Decoder { buf: u8[]; pos: u32; constructor(buf: u8[]) { this.buf = buf; this.pos = 0; } remains(): u8[] { return this.buf.slice(this.pos, this.buf.length); } isEnd(): bool { return this.pos >= this.buf.length; } incPos(n: u32): void { this.pos += n; if (this.pos > this.buf.length) { check(false, "Decoder.incPos: buffer overflow"); } } getPos(): u32 { return this.pos; } unpack(ser: Packer): usize { let size = ser.unpack(this.remains()); this.incPos(size); return size; } unpackNumber(): T { let value = load(this.buf.dataStart + this.pos); this.incPos(sizeof()); return value; } unpackName(): Name { let n = this.unpackNumber(); return new Name(n); } unpackLength(): u32 { let by: u32 = 0; let value: u32 = 0; let length: u32 = 0; while (true) { let b = this.unpackNumber(); value |= (b & 0x7f) << by; by += 7; length += 1; if ((b & 0x80) == 0) { break; } } return value; } unpackBytes(size: usize): u8[] { let arr = new Array(size); let dest = arr.dataStart; let src = this.buf.dataStart + this.pos; memcpy(dest, src, size); this.incPos(size); return arr; } unpackNumberArray(): T[] { let oldPos = this.pos; let length = this.unpackLength(); let arr = new Array(length); let copySize = length * sizeof(); let src = this.buf.dataStart + this.pos; memcpy(arr.dataStart, src, copySize); this.incPos(copySize); return arr; } unpackString(): string { let length = this.unpackLength(); let rawStr = this.buf.slice(this.pos, this.pos + length); this.incPos(length); return String.UTF8.decode(rawStr.buffer); } unpackStringArray(): string[] { let length = this.unpackLength(); let arr = new Array(length); for (let i=0; i< length; i++) { arr[i] = this.unpackString(); } return arr; } }