text: const Iconv = require('iconv-lite'),
      Long = require('long');
  
  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 {
      constructor(query,buffer) {
          this.query = query;
          this.buffer = buffer;
          this.i = 0;
      }
  
      offset() {
          return this.i;
      }
  
      skip(i) {
          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];
          }
  
          options.encoding = options.encoding || this.query.encoding;
          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;
      }
  
      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;
  