node-gamedig/lib/reader.js

162 lines
4.7 KiB
JavaScript
Raw Normal View History

const Iconv = require('iconv-lite'),
Long = require('long'),
Core = require('../protocols/core'),
2019-01-10 13:03:07 +01:00
Buffer = require('buffer'),
Varint = require('varint');
2014-10-29 08:02:03 +01:00
function readUInt64BE(buffer,offset) {
const high = buffer.readUInt32BE(offset);
const low = buffer.readUInt32BE(offset+4);
2017-08-09 12:32:09 +02:00
return new Long(low,high,true);
2014-10-29 08:02:03 +01:00
}
function readUInt64LE(buffer,offset) {
const low = buffer.readUInt32LE(offset);
const high = buffer.readUInt32LE(offset+4);
2017-08-09 12:32:09 +02:00
return new Long(low,high,true);
2014-10-29 08:02:03 +01:00
}
class Reader {
/**
* @param {Core} query
* @param {Buffer} buffer
**/
2017-08-09 12:32:09 +02:00
constructor(query,buffer) {
this.query = query;
this.buffer = buffer;
this.i = 0;
}
2017-08-09 12:32:09 +02:00
offset() {
return this.i;
}
2017-08-09 12:32:09 +02:00
skip(i) {
this.i += i;
}
2014-10-29 08:02:03 +01:00
2017-08-09 12:32:09 +02:00
string(...args) {
let options = {};
2017-08-09 12:32:09 +02:00
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];
}
options.encoding = options.encoding || this.query.options.encoding || this.query.encoding;
2017-08-09 12:32:09 +02:00
if(options.encoding === 'latin1') options.encoding = 'win1252';
const start = this.i+0;
let end = start;
if(!('length' in options)) {
// 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) {
end = this.buffer.length;
break;
}
if(this.buffer.readUInt8(end) === delim) break;
end++;
}
this.i = end+1;
} else {
end = start+options.length;
if(end >= this.buffer.length) {
end = this.buffer.length;
}
this.i = end;
}
let out = this.buffer.slice(start, end);
const enc = options.encoding;
if(enc === 'utf8' || enc === 'ucs2' || enc === 'binary') {
out = out.toString(enc);
} else {
out = Iconv.decode(out,enc);
}
return out;
}
int(bytes) {
let r = 0;
if(this.remaining() >= bytes) {
if(this.query.byteorder === '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);
} else {
if(bytes === 1) r = this.buffer.readInt8(this.i);
else if(bytes === 2) r = this.buffer.readInt16LE(this.i);
else if(bytes === 4) r = this.buffer.readInt32LE(this.i);
}
}
this.i += bytes;
return r;
}
/** @returns {number} */
uint(bytes) {
let r = 0;
if(this.remaining() >= bytes) {
if(this.query.byteorder === '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);
else if(bytes === 8) r = readUInt64BE(this.buffer,this.i).toString();
} else {
if(bytes === 1) r = this.buffer.readUInt8(this.i);
else if(bytes === 2) r = this.buffer.readUInt16LE(this.i);
else if(bytes === 4) r = this.buffer.readUInt32LE(this.i);
else if(bytes === 8) r = readUInt64LE(this.buffer,this.i).toString();
}
}
this.i += bytes;
return r;
}
float() {
let r = 0;
if(this.remaining() >= 4) {
if(this.query.byteorder === 'be') r = this.buffer.readFloatBE(this.i);
else r = this.buffer.readFloatLE(this.i);
}
this.i += 4;
return r;
}
2019-01-10 13:03:07 +01:00
varint() {
const out = Varint.decode(this.buffer, this.i);
this.i += Varint.decode.bytes;
return out;
}
/** @returns Buffer */
2017-08-09 12:32:09 +02:00
part(bytes) {
let r;
if(this.remaining() >= bytes) {
r = this.buffer.slice(this.i,this.i+bytes);
} else {
r = Buffer.from([]);
}
this.i += bytes;
return r;
}
remaining() {
return this.buffer.length-this.i;
}
rest() {
return this.buffer.slice(this.i);
}
done() {
return this.i >= this.buffer.length;
}
}
2014-10-29 08:02:03 +01:00
module.exports = Reader;