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); 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 << 0) | (flag2 << 1) | (flag3 << 2) | (flag4 << 3) | (flag5 << 4) | (flag6 << 5) | (flag7 << 6) | (flag8 << 7) ); 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 */ writeTime(dateorString){ let date = new Date(dateorString); this.writeUInt32(+date); } /** @returns {Date} */ readTime(){ return new Date(this.readUInt32()); } }; class DataAnchor extends ConstructedData { /** * @param {string|number} name * @returns {{read:Function,write:Function,sign:number,name:string,primitive:boolean}} */ getProcessor(name) { switch(name) { case "uint8": case "byte": case 1: return { read : () => this.readUInt8(), write : value => this.writeUInt8(value), sign: 1, name: "uint8", primitive: true } case "uint16": case 2: return { read : () => this.readUInt16(), write : value => this.writeUInt16(value), sign: 2, name: "uint16", primitive: true } case "uint32": case 3: return { read : () => this.readUInt32(), write : value => this.writeUInt32(value), sign: 3, name: "uint32", primitive: true } case "int8": case 4: return { read : () => this.readInt8(), write : value => this.writeInt8(value), sign: 4, name: "int8", primitive: true } case "int16": case 5: return { read : () => this.readInt16(), write : value => this.writeInt16(value), sign: 5, name: "int16", primitive: true } case "int32": case 6: return { read : () => this.readInt32(), write : value => this.writeInt32(value), sign: 6, name: "int32", primitive: true } case "float32": case 7: return { read : () => this.readFloat32(), write : value => this.writeFloat32(value), sign: 7, name: "float32", primitive: true } case "float64": case 8: return { read : () => this.readFloat64(), write : value => this.writeFloat64(value), sign: 8, name: "float64", primitive: true } case "string": case 9: return { read : size => this.readString(size), write : value => this.writeString(value), sign: 9, name: "string", primitive: false } case "rgb": case 10: return { read : () => this.readRGB(), write : value => this.writeRGB(value), sign: 10, name: "rgb", primitive: true } case "rgba": case 11: return { read : () => this.readRGBA(), write : value => this.writeRGBA(value), sign: 11, name: "rgba", primitive: true } case "varnumber": case 12: return { read : () => this.readVarNumber(), write : value => this.writeVarNumber(value), sign: 12, name: "varnumber", primitive: true } case "time": case 13: return { read : () => this.readTime(), write : value => this.writeTime(value), sign: 13, name: "time", primitive: true } }; } } class DataStructure { /** @type {boolean} */ sign = true; /** @type {string} */ type = "uint8"; /** @type {boolean} */ list = true; /** @type {boolean} */ fixedLength = true; /** @type {any} */ value = null; size = 1; /** @param {DataAnchor} da */ setData(da){ let dataCost = da.getProcessor(this.type); if(this.sign == true) { // Verinin içine veri türüni işliyor da.writeUInt8(dataCost.sign); } if(this.fixedLength == false && this.list == true) { // Eğer sabit uzunlukta değilse ne kadar uzun olduğunu bildirmeli da.writeVarNumber(this.size) } if(dataCost.primitive) { if(this.list == true) { for (const data of this.value) { dataCost.write(data); } }else{ dataCost.write(this.value); } }else{ if(this.list == true) { for (const data of this.value) { da.writeVarNumber(data.length); dataCost.write(data); } }else{ da.writeVarNumber(this.value.length); dataCost.write(this.value); } } } /** @param {DataAnchor} da */ getData(da){ let result = null, sign; if(this.sign == true) { // Verinin içine veri türüni işliyor sign = da.readUInt8(); } let dataCost = da.getProcessor(this.type); if(this.fixedLength == false && this.list == true) { // Eğer sabit uzunlukta değilse ne kadar uzun olduğunu bildirmeli this.size = da.readVarNumber(); } if(dataCost.primitive) { if(this.list == true) { result = []; for (const data of this.value) { result.push(dataCost.read()); } }else{ result = dataCost.read(); } }else{ if(this.list == true) { result = []; for (const data of this.value) { let length = da.readVarNumber(data.length); result.push(dataCost.read(length)); } }else{ let length = da.readVarNumber(data.length); result = dataCost.read(length); } } return result; } /** @param {string} dataSigner */ setHeadSigner(dataSigner){ let regex = /^(\w+)(\[\d*\])?$/.exec(dataSigner); if(regex[1] == 'any') { this.sign = true; }else{ this.sign = false; this.type = regex[1]; } if(regex[2]) { this.list = true; this.fixedLength = regex[2] != '[]' this.size = regex[2].slice(1,-1) | 0; }else{ this.list = false; } } }