UNPKG

node-insim

Version:

An InSim library for NodeJS with TypeScript support

129 lines (128 loc) 4.69 kB
import { getFormat } from '../../decorators'; import { InSimError } from '../../errors'; import { determineLength, unpack } from '../../lfspack'; import { log as baseLog } from '../../log'; const log = baseLog.extend('struct'); export class Struct { constructor() { /** @ignore */ this.SIZE_MULTIPLIER = 4; /** All string properties in a raw format as it was received from LFS */ this._raw = {}; } initialize(data) { if (!data) { return; } Object.assign(this, data); } /** @ignore */ getValidPropertyNames() { const prototype = Object.getPrototypeOf(this); const ownPropertyNames = Object.getOwnPropertyNames(this); const prototypePropertyNames = Object.keys(Object.getOwnPropertyDescriptors(prototype)); return [...ownPropertyNames, ...prototypePropertyNames].filter((propertyName) => getFormat(this, propertyName) !== undefined); } /** @ignore */ getFormat(propertyFormats) { const propertyNames = this.getValidPropertyNames(); return propertyNames .map((propertyName) => { var _a; return (_a = propertyFormats === null || propertyFormats === void 0 ? void 0 : propertyFormats[propertyName]) !== null && _a !== void 0 ? _a : getFormat(this, propertyName); }) .join(''); } /** @ignore */ getFormatSize() { return determineLength(`<${this.getFormat()}`); } /** @ignore */ unpack(buffer, propertyFormatOverrides) { const format = this.getFormat(propertyFormatOverrides); const data = unpack(`<${format}`, buffer.buffer); if (!data) { throw new InSimError(`Unpacked no data using ${format} from buffer ${buffer.join()}`); } const propertyNames = this.getValidPropertyNames(); let i = 0; propertyNames.forEach((propertyName) => { const value = data[i]; if (i >= data.length) { return; } const propertyType = typeof this[propertyName]; if (value === undefined) { i++; return; } if (propertyName === 'Size') { this[propertyName] = value * this.SIZE_MULTIPLIER; i++; return; } // Tuple of [rawString, decodedString] if (Array.isArray(value) && value.length === 2) { this[propertyName] = value[1]; this._raw[propertyName] = value[0]; i++; return; } if (Array.isArray(value) && Array.isArray(this[propertyName])) { this[propertyName] = value; i++; return; } if (propertyType == 'object') { i = this.parseObject(this[propertyName], data, i, propertyName); return; } this[propertyName] = value; i++; }); log('Data unpacked:', this); return this; } parseArray(instance, data, i, instanceName) { for (let j = 0; j < instance.length; j++) { const item = instance[j]; if (typeof item === 'object') { i = this.parseObject(item, data, i, `${instanceName}[${j}]`); } else { instance[j] = data[i]; i++; } } return i; } parseObject(instance, data, i, instanceName) { if (Array.isArray(instance)) { return this.parseArray(instance, data, i, instanceName); } if (instance instanceof Struct) { const propertyNames = instance.getValidPropertyNames(); propertyNames.forEach((propertyName) => { const propInstance = instance[propertyName]; const sval = data[i]; const propType = typeof propInstance; const fullName = `${instanceName}.${propertyName}`; if (propType === 'object') { i = this.parseObject(propInstance, data, i, fullName); return; } // eslint-disable-next-line @typescript-eslint/no-explicit-any instance[propertyName] = sval; i++; }); } else { // should be handled by other parts of unpack function // because instance here is a reference to the target property and setter can't be accessed i++; } return i; } }