const Iconv = require('iconv-lite'), Long = require('long'), Core = require('../protocols/core'), Buffer = require('buffer'), Varint = require('varint'); function readUInt64BE(buffer,offset) { const high = buffer.readUInt32BE(offset); const low = buffer.readUInt32BE(offset+4); return new Long(low,high,true); } function readUInt64LE(buffer,offset) { const low = buffer.readUInt32LE(offset); const high = buffer.readUInt32LE(offset+4); return new Long(low,high,true); } class Reader { /** * @param {Core} query * @param {Buffer} buffer **/ constructor(query,buffer) { this.defaultEncoding = query.options.encoding || query.encoding; this.defaultDelimiter = query.delimiter; this.defaultByteOrder = query.byteorder; this.buffer = buffer; this.i = 0; } offset() { return this.i; } skip(i) { this.i += i; } 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; } if(encoding === 'latin1') encoding = 'win1252'; const start = this.i; let end = start; if(length === null) { // terminated by the delimiter 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; end++; } this.i = end + 1; } else if (length <= 0) { return ''; } else { end = start+length; if(end >= this.buffer.length) { end = this.buffer.length; } this.i = end; } const slice = this.buffer.slice(start, end); const enc = encoding; if(enc === 'utf8' || enc === 'ucs2' || enc === 'binary') { return slice.toString(enc); } else { return Iconv.decode(slice,enc); } } int(bytes) { let r = 0; if(this.remaining() >= bytes) { 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); } 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.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); 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.defaultByteOrder === 'be') r = this.buffer.readFloatBE(this.i); else r = this.buffer.readFloatLE(this.i); } this.i += 4; return r; } varint() { const out = Varint.decode(this.buffer, this.i); this.i += Varint.decode.bytes; return out; } /** @returns Buffer */ 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; } } module.exports = Reader;