diff --git a/lib/reader.js b/lib/reader.js index b5aafa9..5dbc2f2 100644 --- a/lib/reader.js +++ b/lib/reader.js @@ -21,7 +21,9 @@ class Reader { * @param {Buffer} buffer **/ constructor(query,buffer) { - this.query = query; + this.defaultEncoding = query.options.encoding || query.encoding; + this.defaultDelimiter = query.delimiter; + this.defaultByteOrder = query.byteorder; this.buffer = buffer; this.i = 0; } @@ -34,56 +36,64 @@ class Reader { this.i += i; } - string(...args) { - let options = {}; - if(args.length === 0) { - options = {}; - } else if(args.length === 1) { - if(typeof args[0] === 'string') options = { delimiter: args[0] }; - else if(typeof args[0] === 'number') options = { length: args[0] }; - else options = args[0]; + pascalString(bytesForSize, adjustment=0) { + const length = this.uint(bytesForSize) + adjustment; + return this.string(length); + } + + string(arg) { + let encoding = this.defaultEncoding; + let length = null; + let delimiter = this.defaultDelimiter; + + if(typeof arg === 'string') delimiter = arg; + else if(typeof arg === 'number') length = arg; + else if(typeof arg === 'object') { + if ('encoding' in arg) encoding = arg.encoding; + if ('length' in arg) length = arg.length; + if ('delimiter' in arg) delimiter = arg.delimiter; } - options.encoding = options.encoding || this.query.options.encoding || this.query.encoding; - if(options.encoding === 'latin1') options.encoding = 'win1252'; + if(encoding === 'latin1') encoding = 'win1252'; - const start = this.i+0; + const start = this.i; let end = start; - if(!('length' in options)) { + if(length === null) { // terminated by the delimiter - let delim = options.delimiter || this.query.delimiter; - if(typeof delim === 'string') delim = delim.charCodeAt(0); - while(true) { - if(end >= this.buffer.length) { + let delim = delimiter; + if (typeof delim === 'string') delim = delim.charCodeAt(0); + while (true) { + if (end >= this.buffer.length) { end = this.buffer.length; break; } - if(this.buffer.readUInt8(end) === delim) break; + if (this.buffer.readUInt8(end) === delim) break; end++; } - this.i = end+1; + this.i = end + 1; + } else if (length <= 0) { + return ''; } else { - end = start+options.length; + end = start+length; if(end >= this.buffer.length) { end = this.buffer.length; } this.i = end; } - let out = this.buffer.slice(start, end); - const enc = options.encoding; + const slice = this.buffer.slice(start, end); + const enc = encoding; if(enc === 'utf8' || enc === 'ucs2' || enc === 'binary') { - out = out.toString(enc); + return slice.toString(enc); } else { - out = Iconv.decode(out,enc); + return Iconv.decode(slice,enc); } - return out; } int(bytes) { let r = 0; if(this.remaining() >= bytes) { - if(this.query.byteorder === 'be') { + if(this.defaultByteOrder === 'be') { if(bytes === 1) r = this.buffer.readInt8(this.i); else if(bytes === 2) r = this.buffer.readInt16BE(this.i); else if(bytes === 4) r = this.buffer.readInt32BE(this.i); @@ -101,7 +111,7 @@ class Reader { uint(bytes) { let r = 0; if(this.remaining() >= bytes) { - if(this.query.byteorder === 'be') { + if(this.defaultByteOrder === 'be') { if(bytes === 1) r = this.buffer.readUInt8(this.i); else if(bytes === 2) r = this.buffer.readUInt16BE(this.i); else if(bytes === 4) r = this.buffer.readUInt32BE(this.i); @@ -120,7 +130,7 @@ class Reader { float() { let r = 0; if(this.remaining() >= 4) { - if(this.query.byteorder === 'be') r = this.buffer.readFloatBE(this.i); + if(this.defaultByteOrder === 'be') r = this.buffer.readFloatBE(this.i); else r = this.buffer.readFloatLE(this.i); } this.i += 4; diff --git a/protocols/ase.js b/protocols/ase.js index c6332b1..beb8eb4 100644 --- a/protocols/ase.js +++ b/protocols/ase.js @@ -4,7 +4,7 @@ class Ase extends Core { async run(state) { const buffer = await this.udpSend('s',(buffer) => { const reader = this.reader(buffer); - const header = reader.string({length: 4}); + const header = reader.string(4); if (header === 'EYE1') return reader.rest(); }); @@ -40,8 +40,7 @@ class Ase extends Core { } readString(reader) { - const len = reader.uint(1); - return reader.string({length:len-1}); + return reader.pascalString(1, -1); } } diff --git a/protocols/battlefield.js b/protocols/battlefield.js index 609da3f..898e6ea 100644 --- a/protocols/battlefield.js +++ b/protocols/battlefield.js @@ -153,8 +153,7 @@ class Battlefield extends Core { const paramCount = reader.uint(4); const params = []; for(let i = 0; i < paramCount; i++) { - const len = reader.uint(4); - params.push(reader.string({length:len})); + params.push(reader.pascalString(4)); const strNull = reader.uint(1); } return params; diff --git a/protocols/cs2d.js b/protocols/cs2d.js index c23ad53..6e98836 100644 --- a/protocols/cs2d.js +++ b/protocols/cs2d.js @@ -66,8 +66,7 @@ class Cs2d extends Core { } readString(reader) { - const length = reader.uint(1); - return reader.string({length:length}); + return reader.pascalString(1); } } diff --git a/protocols/doom3.js b/protocols/doom3.js index 401aa1a..3e23e35 100644 --- a/protocols/doom3.js +++ b/protocols/doom3.js @@ -16,10 +16,10 @@ class Doom3 extends Core { if(header !== 0xffff) return; const header2 = reader.string(); if(header2 !== 'infoResponse') return; - const challengePart1 = reader.string({length:4}); + const challengePart1 = reader.string(4); if (challengePart1 !== "PiNG") return; // some doom3 implementations only return the first 4 bytes of the challenge - const challengePart2 = reader.string({length:4}); + const challengePart2 = reader.string(4); if (challengePart2 !== 'PoNg') reader.skip(-4); return reader.rest(); }); diff --git a/protocols/gamespy1.js b/protocols/gamespy1.js index 39da5ae..bd1f0a7 100644 --- a/protocols/gamespy1.js +++ b/protocols/gamespy1.js @@ -102,7 +102,7 @@ class Gamespy1 extends Core { return await this.udpSend('\\'+type+'\\', buffer => { const reader = this.reader(buffer); - const str = reader.string({length:buffer.length}); + const str = reader.string(buffer.length); const split = str.split('\\'); split.shift(); const data = {}; diff --git a/protocols/m2mp.js b/protocols/m2mp.js index 3d21fbc..809f505 100644 --- a/protocols/m2mp.js +++ b/protocols/m2mp.js @@ -9,7 +9,7 @@ class M2mp extends Core { async run(state) { const body = await this.udpSend('M2MP',(buffer) => { const reader = this.reader(buffer); - const header = reader.string({length: 4}); + const header = reader.string(4); if (header !== 'M2MP') return; return reader.rest(); }); @@ -32,8 +32,7 @@ class M2mp extends Core { } readString(reader) { - const length = reader.uint(1); - return reader.string({length:length-1}); + return reader.pascalString(1,-1); } } diff --git a/protocols/quake2.js b/protocols/quake2.js index 78215be..3290ac2 100644 --- a/protocols/quake2.js +++ b/protocols/quake2.js @@ -17,7 +17,7 @@ class Quake2 extends Core { if (header !== '\xff\xff\xff\xff') return; let type; if (this.isQuake1) { - type = reader.string({length: this.responseHeader.length}); + type = reader.string(this.responseHeader.length); } else { type = reader.string({encoding: 'latin1'}); } diff --git a/protocols/samp.js b/protocols/samp.js index 34a8b77..bc452aa 100644 --- a/protocols/samp.js +++ b/protocols/samp.js @@ -20,9 +20,9 @@ class Samp extends Core { state.password = !!reader.uint(1); state.raw.numplayers = reader.uint(2); state.maxplayers = reader.uint(2); - state.name = this.readString(reader,4); - state.raw.gamemode = this.readString(reader,4); - state.raw.map = this.readString(reader,4); + state.name = reader.pascalString(4); + state.raw.gamemode = reader.pascalString(4); + state.raw.map = reader.pascalString(4); } // read rules @@ -31,8 +31,8 @@ class Samp extends Core { const ruleCount = reader.uint(2); state.raw.rules = {}; for(let i = 0; i < ruleCount; i++) { - const key = this.readString(reader,1); - const value = this.readString(reader,1); + const key = reader.pascalString(1); + const value = reader.pascalString(1); state.raw.rules[key] = value; } } @@ -48,7 +48,7 @@ class Samp extends Core { const playerCount = reader.uint(2); for(let i = 0; i < playerCount; i++) { const player = {}; - player.name = this.readString(reader,1); + player.name = reader.pascalString(1); state.players.push(player); } } @@ -60,7 +60,7 @@ class Samp extends Core { for(let i = 0; i < playerCount; i++) { const player = {}; player.id = reader.uint(1); - player.name = this.readString(reader,1); + player.name = reader.pascalString(1); player.score = reader.int(4); player.ping = reader.uint(4); state.players.push(player); @@ -72,11 +72,6 @@ class Samp extends Core { state.players = state.raw.numplayers; } } - readString(reader,lenBytes) { - const length = reader.uint(lenBytes); - if(!length) return ''; - return reader.string({length:length}); - } async sendPacket(type,allowTimeout) { const outBuffer = Buffer.alloc(11); outBuffer.write(this.magicHeader,0, 4); diff --git a/protocols/tribes1.js b/protocols/tribes1.js index dfd546e..a0a3d8a 100644 --- a/protocols/tribes1.js +++ b/protocols/tribes1.js @@ -145,9 +145,7 @@ class Tribes1 extends Core { .map((a) => a.trim()); } readString(reader) { - const length = reader.uint(1); - if(!length) return ''; - return reader.string({length:length}); + return reader.pascalString(1); } } diff --git a/protocols/tribes1master.js b/protocols/tribes1master.js index c9bfb47..9939242 100644 --- a/protocols/tribes1master.js +++ b/protocols/tribes1master.js @@ -74,9 +74,7 @@ class Tribes1Master extends Core { } } readString(reader) { - const length = reader.uint(1); - if(!length) return ''; - return reader.string({length:length}); + return reader.pascalString(1); } } diff --git a/protocols/unreal2.js b/protocols/unreal2.js index e2c8d08..7726afc 100644 --- a/protocols/unreal2.js +++ b/protocols/unreal2.js @@ -89,7 +89,7 @@ class Unreal2 extends Core { let length = reader.uint(1); let out; if(length < 0x80) { - //out = reader.string({length:length}); + //out = reader.string(length); out = ''; if(length > 0) out = reader.string(); } else {