class ProcessableData { constructor(data, from = 0, to){ if(data){ this.data = data; this.init(from, to); } } /** @type {Uint8Array} */ data = null; /** @type {DataView} */ dt = null; /** @type {number} */ cursor = 0; /** * @param {number} from * @param {number} to */ init(from, to){ if(this.data == null) { this.data = new Uint8Array(1024 * 1024); } this.dt = new DataView(this.data.buffer, from, to); } /** @param {number} value */ writeUInt8(value){ this.dt.setUint8(this.cursor,value); this.cursor += 1; } /** @param {number} value */ writeUInt16(value){ this.dt.setUint16(this.cursor,value); this.cursor += 2; } /** @param {number} value */ writeUInt32(value){ this.dt.setUint32(this.cursor,value); this.cursor += 4; } /** @param {number} value */ writeInt8(value){ this.dt.setInt8(this.cursor,value); this.cursor += 1; } /** @param {number} value */ writeInt16(value){ this.dt.setInt16(this.cursor,value); this.cursor += 2; } /** @param {number} value */ writeInt32(value){ this.dt.setInt32(this.cursor,value); this.cursor += 4; } /** @param {number} value */ writeFloat32(value){ this.dt.setFloat32(this.cursor,value); this.cursor += 4; } /** @param {number} value */ writeFloat64(value){ this.dt.setFloat64(this.cursor,value); this.cursor += 8; } /** @returns {number} */ readUInt8(){ let value = this.dt.getUint8(this.cursor); this.cursor += 1; return value; } /** @returns {number} */ readUInt16(){ let value = this.dt.getUint16(this.cursor); this.cursor += 2; return value; } /** @returns {number} */ readUInt32(){ let value = this.dt.getUint32(this.cursor); this.cursor += 4; return value; } /** @returns {number} */ readInt8(){ let value = this.dt.getInt8(this.cursor); this.cursor += 1; return value; } /** @returns {number} */ readInt16(){ let value = this.dt.getInt16(this.cursor); this.cursor += 2; return value; } /** @returns {number} */ readInt32(){ let value = this.dt.getInt32(this.cursor); this.cursor += 4; return value; } /** @returns {number} */ readFloat32(){ let value = this.dt.getFloat32(this.cursor); this.cursor += 4; return value; } /** @returns {number} */ readFloat64(){ let value = this.dt.getFloat64(this.cursor); this.cursor += 8; return value; } getAllData(){ return this.dt.buffer.slice(0, this.cursor); } } class ConstructedData extends ProcessableData { /** @param {string} value */ writeString(value){ let encodedText = new TextEncoder().encode(value); for (const byte of encodedText) { this.writeUInt8(byte); } } /** * @param {number} value * @returns {string} */ readString(size){ let minibuffer = this.data.buffer.slice(this.cursor, this.cursor + size); return new TextDecoder().decode(minibuffer); } /** * @param {boolean|0|1} flag1 * @param {boolean|0|1} flag2 * @param {boolean|0|1} flag3 * @param {boolean|0|1} flag4 * @param {boolean|0|1} flag5 * @param {boolean|0|1} flag6 * @param {boolean|0|1} flag7 * @param {boolean|0|1} flag8 */ writeFlags(flag1, flag2, flag3, flag4, flag5, flag6, flag7, flag8){ let value = ( (flag1 << 1) | (flag2 << 2) | (flag3 << 3) | (flag4 << 4) | (flag5 << 5) | (flag6 << 6) | (flag7 << 7) | (flag8 << 8) ); this.writeUInt8(value); } /** @returns {number[]} */ readFlags(){ let value = this.readUInt8(); let result = ( (value >> 0 & 0x1), (value >> 1 & 0x1), (value >> 2 & 0x1), (value >> 3 & 0x1), (value >> 4 & 0x1), (value >> 5 & 0x1), (value >> 6 & 0x1), (value >> 7 & 0x1) ); return result; } /** * @param {number} r * @param {number} g * @param {number} b */ writeRGB(r,g,b){ this.writeUInt8(r); this.writeUInt8(g); this.writeUInt8(b); } /** @returns {{r:number,g:number,b:number}} */ readRGB(){ return { r: this.readUInt8(), g: this.readUInt8(), b: this.readUInt8() } } /** * @param {number} r * @param {number} g * @param {number} b */ writeRGBA(r,g,b,a){ this.writeUInt8(r); this.writeUInt8(g); this.writeUInt8(b); this.writeUInt8(a); } /** @returns {{r:number,g:number,b:number,a:number}} */ readRGBA(){ return { r: this.readUInt8(), g: this.readUInt8(), b: this.readUInt8(), a: this.readUInt8() } } /** @param {number} size */ writeVarNumber(size){ let iszero = false; let isInt = Number.isInteger(size); let is1Byte = false; let is2Byte = false; let is4Byte = false; let is8Byte = false; let issigned = false; issigned = size < 0; if(isInt){ if(size === 0) { iszero = true; }else if(size >= 0 && size <= 255) { is1Byte = true; }else if(size >= -127 && size <= 127) { is1Byte = true; }else if(size >= -32768 && size <= 32767) { is2Byte = true; }else if(size >= -2147483648 && size <= 2147483647) { is4Byte = true; } }else { if(size >= -3.4028235e38 && size <= 3.4028235e38) { is4Byte = true; }else { is8Byte = true; } }; this.writeFlags( iszero, isInt, is1Byte, is2Byte, is4Byte, is8Byte, issigned, 255 ); if(isInt == false) { if(is4Byte) { this.writeFloat32(size); } if(is8Byte) { this.writeFloat64(size); } }else{ if(is1Byte) { if(issigned) { this.writeInt16(size); }else{ this.writeUInt8(size); } } if(is2Byte) { if(issigned) { this.writeInt32(size); }else{ this.writeUInt16(size); } } if(is4Byte) { if(issigned) { this.writeInt32(size); }else{ this.writeUInt32(size); } } } } /** @returns {number} */ readVarNumber(){ let [ iszero, isInt, is1Byte, is2Byte, is4Byte, is8Byte, issigned ] = this.readFlags(); if(iszero) { return 0; } if(!isInt) { if(is4Byte) { return this.readFloat32(); // 32-bit float }else if(is8Byte) { return this.readFloat64(); // 64-bit float } }else { if(is1Byte) { if(issigned) { return this.readInt8(); }else { return this.readUInt8(); } }else if(is2Byte) { if(issigned) { return this.readInt16(); }else { return this.readUInt16(); } }else if(is4Byte) { if(issigned) { return this.readInt32(); }else { return this.readUInt32(); } } } } /** @param {Date|string} dateorString */ writeDate(dateorString){ let date = new Date(dateorString); this.writeUInt32(+date); } /** @returns {Date} */ readDate(){ return new Date(this.readUInt32()); } };