summaryrefslogtreecommitdiff
path: root/src/file.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/file.ts')
-rw-r--r--src/file.ts90
1 files changed, 90 insertions, 0 deletions
diff --git a/src/file.ts b/src/file.ts
new file mode 100644
index 0000000..82194c3
--- /dev/null
+++ b/src/file.ts
@@ -0,0 +1,90 @@
+import { packetName, PACKET_TYPES } from "./constants";
+import { parse } from "./packets";
+import { DumpLastModifiedPacket, PortControllerPacket } from "./packets/general";
+import { InputChunkPacket } from "./packets/input";
+import { TASDPacket } from "./packets/utils";
+import { readUint16, readUint8, readUintN, writeUint16, writeUint8, concatUint8Array } from "./utils";
+
+export class TASD {
+ static MAGIC = new Uint8Array([0x54, 0x41, 0x53, 0x44]);
+ public version: number;
+ public g_keylen: number;
+ public packets: TASDPacket[];
+ private _isDirty: boolean = false;
+ constructor(_version: number, _keylen: number) {
+ this.version = _version;
+ this.g_keylen = _keylen;
+ this.packets = [];
+ }
+ get dirty() {
+ return this._isDirty;
+ }
+ markDirty() {
+ this._isDirty = true;
+ }
+ toBuffer() {
+ const header = new Uint8Array(7);
+ header.set(TASD.MAGIC, 0);
+ writeUint16(this.version, header, 4);
+ writeUint8(this.g_keylen, header, 6);
+ const packets = [ header ];
+ if (this._isDirty) {
+ this.packets = this.packets.filter((packet) => packet.key === PACKET_TYPES.DUMP_LAST_MODIFIED);
+ this.packets.push(new DumpLastModifiedPacket(BigInt(Date.now())));
+ }
+ for (const packet of this.packets) {
+ packets.push(packet.toBuffer(this.g_keylen));
+ }
+ return concatUint8Array(packets);
+ }
+ pprint() {
+ console.log('VERSION', this.version);
+ console.log('G_KEYLEN', this.g_keylen);
+ for (const packet of this.packets) {
+ console.log(packet.toString());
+ }
+ }
+ compactInputs() {
+ if (this.packets.some(packet => packet.key === PACKET_TYPES.INPUT_MOMENT)) return;
+ const otherPackets = this.packets.filter(packet => packet.key !== PACKET_TYPES.INPUT_CHUNK);
+ const inputPackets = this.packets.filter(packet => packet.key === PACKET_TYPES.INPUT_CHUNK);
+ const ports: Uint8Array[][] = [];
+ for (const packet of otherPackets.filter(packet => packet.key === PACKET_TYPES.PORT_CONTROLLER)) {
+ ports[(packet as PortControllerPacket).port] = [];
+ }
+ for (const packet of inputPackets as InputChunkPacket[]) {
+ ports[packet.port].push(packet.inputs);
+ }
+ for (let port = 1; port < 256; port++) {
+ if (ports[port]) {
+ otherPackets.push(new InputChunkPacket(port, concatUint8Array(ports[port])));
+ }
+ }
+ this.packets = otherPackets;
+ this.markDirty();
+ }
+ static parseFile(buffer: Uint8Array) {
+ if (buffer.length < 7) throw new Error('Input Too Short');
+ for (let i = 0; i < TASD.MAGIC.length; i++) {
+ if (buffer[i] !== TASD.MAGIC[i]) throw new Error('Invalid Magic Bytes');
+ }
+ const version = readUint16(buffer, 4);
+ if (version !== 1) throw new Error('Unsupported Version');
+ const g_keylen = readUint8(buffer, 6);
+ if (g_keylen !== 2) throw new Error('G_KEYLEN not equal to 2, unsupported');
+ const file = new TASD(version, g_keylen);
+ let index = 7;
+ while (index < buffer.length) {
+ const p_key = readUintN(buffer, index, g_keylen);
+ index += g_keylen;
+ const p_pexp = readUint8(buffer, index);
+ index += 1;
+ const p_plen = readUintN(buffer, index, p_pexp);
+ index += p_pexp;
+ const p_payload = buffer.subarray(index, index+p_plen);
+ index += p_plen;
+ file.packets.push(parse(p_key, p_payload));
+ }
+ return file;
+ }
+}