Advertisement
Guest User

Untitled

a guest
Aug 24th, 2019
107
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. 'use strict'
  2.  
  3. const { deflateSync, deflateRawSync, inflateSync, inflateRawSync } = require('zlib')
  4. const { encodingExists, decode, encode } = require('iconv-lite')
  5.  
  6. /**
  7.  * @exports
  8.  * @class
  9.  */
  10. module.exports = class ByteArray {
  11.   /**
  12.    * @constructor
  13.    * @param {Buffer|Array} buffer
  14.    */
  15.   constructor(buffer) {
  16.     /**
  17.      * Holds the data
  18.      * @type {Buffer}
  19.      */
  20.     this.buffer = Buffer.isBuffer(buffer) ? buffer : Array.isArray(buffer) ? Buffer.from(buffer) : Buffer.alloc(0)
  21.     /**
  22.      * The current position
  23.      * @type {Number}
  24.      */
  25.     this.position = 0
  26.     /**
  27.      * The byte order
  28.      * @type {Boolean}
  29.      */
  30.     this.endian = true
  31.   }
  32.  
  33.   /**
  34.    * Returns the length of the buffer
  35.    * @returns {Number}
  36.    */
  37.   get length() {
  38.     return this.buffer.length
  39.   }
  40.  
  41.   /**
  42.    * Returns the endianness but then as a string
  43.    * @returns {String}
  44.    */
  45.   get endianStr() {
  46.     return this.endian ? 'BE' : 'LE'
  47.   }
  48.  
  49.   /**
  50.    * Sets the length of the buffer
  51.    * @param {Number} value
  52.    */
  53.   set length(value) {
  54.     if (value === 0) {
  55.       this.clear()
  56.     } else if (value !== this.length) {
  57.       if (value < this.length) {
  58.         this.buffer = this.buffer.slice(0, value)
  59.         this.position = this.length
  60.       } else {
  61.         this.expand(this.position !== 0 ? value - this.position : value)
  62.       }
  63.     }
  64.   }
  65.  
  66.   /**
  67.    * Returns the amount of bytes available
  68.    * @returns {Number}
  69.    */
  70.   get bytesAvailable() {
  71.     return this.length - this.position
  72.   }
  73.  
  74.   /**
  75.    * Expands the buffer when needed
  76.    * @param {Number} value
  77.    */
  78.   expand(value) {
  79.     if (this.bytesAvailable < value) {
  80.       const toExpand = value - this.bytesAvailable
  81.       const needsExpand = this.bytesAvailable + toExpand === value
  82.  
  83.       this.buffer = Buffer.concat([this.buffer, Buffer.alloc(needsExpand ? toExpand : value)])
  84.     }
  85.   }
  86.  
  87.   /**
  88.    * Clears the buffer and sets the position to 0
  89.    */
  90.   clear() {
  91.     this.buffer = Buffer.alloc(0)
  92.     this.position = 0
  93.   }
  94.  
  95.   /**
  96.    * Compresses the buffer
  97.    * @param {String} algorithm
  98.    */
  99.   compress(algorithm) {
  100.     switch (algorithm.toLowerCase()) {
  101.       case 'zlib': this.buffer = deflateSync(this.buffer, { level: 9 }); break
  102.       case 'deflate': this.buffer = deflateRawSync(this.buffer); break
  103.       default: throw new Error(`Invalid compression algorithm: ${algorithm}`)
  104.     }
  105.  
  106.     this.position = this.length
  107.   }
  108.  
  109.   /**
  110.    * Reads a boolean
  111.    * @returns {Boolean}
  112.    */
  113.   readBoolean() {
  114.     return this.readByte() !== 0
  115.   }
  116.  
  117.   /**
  118.    * Reads a signed byte
  119.    * @returns {Number}
  120.    */
  121.   readByte() {
  122.     return this.buffer.readInt8(this.position++)
  123.   }
  124.  
  125.   /**
  126.    * Reads multiple signed bytes from a ByteArray
  127.    * @param {ByteArray} bytes
  128.    * @param {Number} offset
  129.    * @param {Number} length
  130.    */
  131.   readBytes(bytes, offset = 0, length = 0) {
  132.     const available = this.bytesAvailable
  133.  
  134.     if (length === 0) length = available
  135.     if (length > available) throw new RangeError('End of buffer was encountered')
  136.     if (bytes.length < offset + length) bytes.expand(offset + length - bytes.position)
  137.  
  138.     for (let i = 0; i < length; i++) {
  139.       bytes.buffer[i + offset] = this.buffer[i + this.position]
  140.     }
  141.  
  142.     this.position += length
  143.   }
  144.  
  145.   /**
  146.    * Reads a double
  147.    * @returns {Number}
  148.    */
  149.   readDouble() {
  150.     const value = this.buffer[`readDouble${this.endianStr}`](this.position)
  151.     this.position += 8
  152.     return value
  153.   }
  154.  
  155.   /**
  156.    * Reads a float
  157.    * @returns {Number}
  158.    */
  159.   readFloat() {
  160.     const value = this.buffer[`readFloat${this.endianStr}`](this.position)
  161.     this.position += 4
  162.     return value
  163.   }
  164.  
  165.   /**
  166.    * Reads a signed int
  167.    * @returns {Number}
  168.    */
  169.   readInt() {
  170.     const value = this.buffer[`readInt32${this.endianStr}`](this.position)
  171.     this.position += 4
  172.     return value
  173.   }
  174.  
  175.   /**
  176.    * Reads a multibyte string
  177.    * @param {Number} length
  178.    * @param {String} charset
  179.    * @returns {String}
  180.    */
  181.   readMultiByte(length, charset = 'utf8') {
  182.     const position = this.position
  183.     this.position += length
  184.  
  185.     if (encodingExists(charset)) {
  186.       return decode(this.buffer.slice(position, position + length), charset)
  187.     } else {
  188.       throw new Error(`Invalid character set: ${charset}`)
  189.     }
  190.   }
  191.  
  192.   /**
  193.    * Reads a signed short
  194.    * @returns {Number}
  195.    */
  196.   readShort() {
  197.     const value = this.buffer[`readInt16${this.endianStr}`](this.position)
  198.     this.position += 2
  199.     return value
  200.   }
  201.  
  202.   /**
  203.    * Reads an unsigned byte
  204.    * @returns {Number}
  205.    */
  206.   readUnsignedByte() {
  207.     return this.buffer.readUInt8(this.position++)
  208.   }
  209.  
  210.   /**
  211.    * Reads an unsigned int
  212.    * @returns {Number}
  213.    */
  214.   readUnsignedInt() {
  215.     const value = this.buffer[`readUInt32${this.endianStr}`](this.position)
  216.     this.position += 4
  217.     return value
  218.   }
  219.  
  220.   /**
  221.    * Reads an unsigned short
  222.    * @returns {Number}
  223.    */
  224.   readUnsignedShort() {
  225.     const value = this.buffer[`readUInt16${this.endianStr}`](this.position)
  226.     this.position += 2
  227.     return value
  228.   }
  229.  
  230.   /**
  231.    * Reads a UTF-8 string
  232.    * @returns {String}
  233.    */
  234.   readUTF() {
  235.     return this.readMultiByte(this.readUnsignedShort())
  236.   }
  237.  
  238.   /**
  239.    * Reads multiple UTF-8 bytes
  240.    * @param {Number} length
  241.    * @returns {String}
  242.    */
  243.   readUTFBytes(length) {
  244.     return this.readMultiByte(length)
  245.   }
  246.  
  247.   /**
  248.    * Converts the buffer to JSON
  249.    * @returns {Object}
  250.    */
  251.   toJSON() {
  252.     return this.buffer.toJSON()
  253.   }
  254.  
  255.   /**
  256.    * Converts the buffer to a string
  257.    * @returns {String}
  258.    */
  259.   toString() {
  260.     return this.buffer.toString('utf8')
  261.   }
  262.  
  263.   /**
  264.    * Decompresses the buffer
  265.    * @param {String} algorithm
  266.    */
  267.   uncompress(algorithm) {
  268.     switch (algorithm.toLowerCase()) {
  269.       case 'zlib': this.buffer = inflateSync(this.buffer, { level: 9 }); break
  270.       case 'deflate': this.buffer = inflateRawSync(this.buffer); break
  271.       default: throw new Error(`Invalid compression algorithm: ${algorithm}`)
  272.     }
  273.  
  274.     this.position = 0
  275.   }
  276.  
  277.   /**
  278.    * Writes a boolean
  279.    * @param {Boolean} value
  280.    */
  281.   writeBoolean(value) {
  282.     this.writeByte(value ? 1 : 0)
  283.   }
  284.  
  285.   /**
  286.    * Writes a signed byte
  287.    * @param {Number} value
  288.    */
  289.   writeByte(value) {
  290.     value = value > 127 ? value - 256 : value;
  291.     this.expand(1)
  292.     this.buffer.writeInt8(value, this.position++)
  293.   }
  294.  
  295.   /**
  296.    * Writes multiple signed bytes to a ByteArray
  297.    * @param {ByteArray} bytes
  298.    * @param {Number} offset
  299.    * @param {Number} length
  300.    */
  301.   writeBytes(bytes, offset = 0, length = 0) {
  302.     if (length === 0) length = bytes.length - offset
  303.  
  304.     this.expand(this.position + length - this.position)
  305.  
  306.     for (let i = 0; i < length; i++) {
  307.       this.buffer[i + this.position] = bytes.buffer[i + offset]
  308.     }
  309.  
  310.     this.position += length
  311.   }
  312.  
  313.   /**
  314.   * Writes a double
  315.   * @param {Number} value
  316.   */
  317.   writeDouble(value) {
  318.     this.expand(8)
  319.     this.buffer[`writeDouble${this.endianStr}`](value, this.position)
  320.     this.position += 8
  321.   }
  322.  
  323.   /**
  324.    * Writes a float
  325.    * @param {Number} value
  326.    */
  327.   writeFloat(value) {
  328.     this.expand(4)
  329.     this.buffer[`writeFloat${this.endianStr}`](value, this.position)
  330.     this.position += 4
  331.   }
  332.  
  333.   /**
  334.    * Writes a signed int
  335.    * @param {Number} value
  336.    */
  337.   writeInt(value) {
  338.     this.expand(4)
  339.     this.buffer[`writeInt32${this.endianStr}`](value, this.position)
  340.     this.position += 4
  341.   }
  342.  
  343.   /**
  344.    * Writes a multibyte string
  345.    * @param {String} value
  346.    * @param {String} charset
  347.    */
  348.   writeMultiByte(value, charset = 'utf8') {
  349.     const length = Buffer.byteLength(value)
  350.  
  351.     if (encodingExists(charset)) {
  352.       this.buffer = Buffer.concat([this.buffer, encode(value, charset)])
  353.       this.position += length
  354.     } else {
  355.       throw new Error(`Invalid character set: ${charset}`)
  356.     }
  357.   }
  358.  
  359.   /**
  360.    * Writes a signed short
  361.    * @param {Number} value
  362.    */
  363.   writeShort(value) {
  364.     value = value > 32767 ? (value - 65536) : value;
  365.     this.expand(2)
  366.     this.buffer[`writeInt16${this.endianStr}`](value, this.position)
  367.     this.position += 2
  368.   }
  369.  
  370.   /**
  371.    * Writes an unsigned byte
  372.    * @param {Number} value
  373.    */
  374.   writeUnsignedByte(value) {
  375.     this.expand(1)
  376.     this.buffer.writeUInt8(value, this.position++)
  377.   }
  378.  
  379.   /**
  380.    * Writes an unsigned int
  381.    * @param {Number} value
  382.    */
  383.   writeUnsignedInt(value) {
  384.     this.expand(4)
  385.     this.buffer[`writeUInt32${this.endianStr}`](value, this.position)
  386.     this.position += 4
  387.   }
  388.  
  389.   /**
  390.    * Writes an unsigned short
  391.    * @param {Number} value
  392.    */
  393.   writeUnsignedShort(value) {
  394.     this.expand(2)
  395.     this.buffer[`writeUInt16${this.endianStr}`](value, this.position)
  396.     this.position += 2
  397.   }
  398.  
  399.   /**
  400.    * Writes a UTF-8 string
  401.    * @param {String} value
  402.    */
  403.   writeUTF(value) {
  404.     const length = Buffer.byteLength(value)
  405.  
  406.     if (length > 65535) throw new RangeError('Out of range for writeUTF length')
  407.  
  408.     this.writeUnsignedShort(length)
  409.     this.writeMultiByte(value)
  410.   }
  411.  
  412.   /**
  413.    * Writes multiple UTF-8 bytes
  414.    * @param {String} value
  415.    */
  416.   writeUTFBytes(value) {
  417.     this.writeMultiByte(value)
  418.   }
  419. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement