import {Options, Value} from './tstype'; import {IsNumberArray} from '../utils'; class Buffalo { protected position: number; protected buffer: Buffer; public constructor(buffer: Buffer, position = 0) { this.position = position; this.buffer = buffer; } public getPosition(): number { return this.position; } public getBuffer(): Buffer { return this.buffer; } public readEmpty(): Value { return null; } public writeEmpty(): void { } public writeInt8(value: number): void { this.buffer.writeInt8(value, this.position); this.position++; } public readInt8(): Value { const value = this.buffer.readInt8(this.position); this.position++; return value; } public writeUInt8(value: number): void { this.buffer.writeUInt8(value, this.position); this.position++; } public readUInt8(): Value { const value = this.buffer.readUInt8(this.position); this.position++; return value; } public writeUInt16(value: number): void { this.buffer.writeUInt16LE(value, this.position); this.position += 2; } public readUInt24(): Value { const lsb = this.readUInt16(); const msb = this.readUInt8(); return (msb * 65536) + lsb; } public writeUInt24(value: number): void { let temp = Buffer.alloc(4); temp.writeUInt32LE(value, 0); temp = temp.slice(0, 3); this.writeBuffer(temp, 3); } public readInt24(): Value { const lsb = this.readUInt16(); const msb = this.readUInt8(); const sign = (msb & 0x80) >> 7; let value = ((msb & 0x7F) * 65536) + lsb; if (sign) { value = -(0x7FFFFF - value + 1); } return value; } public writeInt24(value: number): void { let temp = Buffer.alloc(4); temp.writeInt32LE(value, 0); temp = temp.slice(0, 3); this.writeBuffer(temp, 3); } public readUInt16(): Value { const value = this.buffer.readUInt16LE(this.position); this.position += 2; return value; } public writeInt16(value: number): void { this.buffer.writeInt16LE(value, this.position); this.position += 2; } public readInt16(): Value { const value = this.buffer.readInt16LE(this.position); this.position += 2; return value; } public writeUInt32(value: number): void { this.buffer.writeUInt32LE(value, this.position); this.position += 4; } public readUInt32(): Value { const value = this.buffer.readUInt32LE(this.position); this.position += 4; return value; } public writeInt32(value: number): void { this.buffer.writeInt32LE(value, this.position); this.position += 4; } public readInt32(): Value { const value = this.buffer.readInt32LE(this.position); this.position += 4; return value; } public writeFloatLE(value: number): void { this.buffer.writeFloatLE(value, this.position); this.position += 4; } public readFloatLE(): Value { const value = this.buffer.readFloatLE(this.position); this.position += 4; return value; } public writeDoubleLE(value: number): void { this.buffer.writeDoubleLE(value, this.position); this.position += 8; } public readDoubleLE(): Value { const value = this.buffer.readDoubleLE(this.position); this.position += 8; return value; } public writeIeeeAddr(value: string): void { this.writeUInt32(parseInt(value.slice(10), 16)); this.writeUInt32(parseInt(value.slice(2, 10), 16)); } public readIeeeAddr(): Value { const length = 8; const value = this.buffer.slice(this.position, this.position + length); this.position += length; return Buffalo.addressBufferToString(value); } private static addressBufferToString(buffer: Buffer): string { let address = '0x'; for (let i = 0; i < buffer.length; i++) { const value = buffer.readUInt8(buffer.length - i - 1); if (value <= 15) { address += '0' + value.toString(16); } else { address += value.toString(16); } } return address; } protected readBuffer(length: number): Value { const value = this.buffer.slice(this.position, this.position + length); this.position += length; return value; } protected writeBuffer(values: Buffer | number[], length: number): void { if (values.length !== length) { throw new Error(`Length of values: '${values}' is not consitent with expected length '${length}'`); } for (const value of values) { this.writeUInt8(value); } } public writeListUInt8(values: number[]): void { for (const value of values) { this.writeUInt8(value); } } public readListUInt8(options: Options): Value { const value = []; for (let i = 0; i < options.length; i++) { value.push(this.readUInt8()); } return value; } public writeListUInt16(values: number[]): void { for (const value of values) { this.writeUInt16(value); } } public readListUInt16(options: Options): Value { const value = []; for (let i = 0; i < options.length; i++) { value.push(this.readUInt16()); } return value; } public writeListUInt24(values: number[]): void { for (const value of values) { this.writeUInt24(value); } } public readListUInt24(options: Options): Value { const value = []; for (let i = 0; i < options.length; i++) { value.push(this.readUInt24()); } return value; } public writeListUInt32(values: number[]): void { for (const value of values) { this.writeUInt32(value); } } public readListUInt32(options: Options): Value { const value = []; for (let i = 0; i < options.length; i++) { value.push(this.readUInt32()); } return value; } public write(type: string, value: Value, options: Options): void { options; // prevent not used eslint warning if (type === 'UINT8') { this.writeUInt8(value); } else if (type === 'UINT16') { this.writeUInt16(value); } else if (type === 'UINT32') { this.writeUInt32(value); } else if (type === 'IEEEADDR') { this.writeIeeeAddr(value); } else if (type.startsWith('BUFFER') && (Buffer.isBuffer(value) || IsNumberArray(value))) { let length = Number(type.replace('BUFFER', '')); length = length != 0 ? length : value.length; this.writeBuffer(value, length); } else if (type === 'INT8') { this.writeInt8(value); } else if (type === 'INT16') { this.writeInt16(value); } else if (type === 'UINT24') { this.writeUInt24(value); } else if (type === 'INT24') { this.writeInt24(value); } else if (type === 'INT32') { this.writeInt32(value); } else if (type === 'FLOATLE') { this.writeFloatLE(value); } else if (type === 'DOUBLELE') { this.writeDoubleLE(value); } else if (type === 'EMPTY') { this.writeEmpty(); } else if (type === 'LIST_UINT8') { this.writeListUInt8(value); } else if (type === 'LIST_UINT16') { this.writeListUInt16(value); } else if (type === 'LIST_UINT24') { this.writeListUInt24(value); } else if (type === 'LIST_UINT32') { this.writeListUInt32(value); } else { throw new Error(`Write for '${type}' not available`); } } public read(type: string, options: Options): Value { if (type === 'UINT8') { return this.readUInt8(); } else if (type === 'UINT16') { return this.readUInt16(); } else if (type === 'UINT32') { return this.readUInt32(); } else if (type === 'IEEEADDR') { return this.readIeeeAddr(); } else if (type.startsWith('BUFFER')) { let length = Number(type.replace('BUFFER', '')); length = length != 0 ? length : options.length; return this.readBuffer(length); } else if (type === 'INT8') { return this.readInt8(); } else if (type === 'INT16') { return this.readInt16(); } else if (type === 'UINT24') { return this.readUInt24(); } else if (type === 'INT24') { return this.readInt24(); } else if (type === 'INT32') { return this.readInt32(); } else if (type === 'FLOATLE') { return this.readFloatLE(); } else if (type === 'DOUBLELE') { return this.readDoubleLE(); } else if (type === 'EMPTY') { return this.readEmpty(); } else if (type === 'LIST_UINT8') { return this.readListUInt8(options); } else if (type === 'LIST_UINT16') { return this.readListUInt16(options); } else if (type === 'LIST_UINT24') { return this.readListUInt24(options); } else if (type === 'LIST_UINT32') { return this.readListUInt32(options); } else { throw new Error(`Read for '${type}' not available`); } } } export default Buffalo;