Source: node_modules/node-int64/Int64.js

//     Int64.js
//
//     Copyright (c) 2012 Robert Kieffer
//     MIT License - http://opensource.org/licenses/mit-license.php

/*
 * Support for handling 64-bit int numbers in Javascript (node.js)
 *
 * JS Numbers are IEEE-754 binary double-precision floats, which limits the
 * range of values that can be represented with integer precision to:
 *
 * 2^^53 <= N <= 2^53
 *
 * Int64 objects wrap a node Buffer that holds the 8-bytes of int64 data.  These
 * objects operate directly on the buffer which means that if they are created
 * using an existing buffer then setting the value will modify the Buffer, and
 * vice-versa.
 *
 * Internal Representation
 *
 * The internal buffer format is Big Endian.  I.e. the most-significant byte is
 * at buffer[0], the least-significant at buffer[7].  For the purposes of
 * converting to/from JS native numbers, the value is assumed to be a signed
 * integer stored in 2's complement form.
 *
 * For details about IEEE-754 see:
 * http://en.wikipedia.org/wiki/Double_precision_floating-point_format
 */

var MASK31 =  0x7fffffff, VAL31 = 0x80000000;
var MASK32 =  0xffffffff, VAL32 = 0x100000000;

var _HEX = [];
for (var i = 0; i < 256; i++) {
  _HEX[i] = (i > 0xF ? '' : '0') + i.toString(16);
}

//
// Int64
//

/**
 * Javascript Numbers are IEEE-754 binary double-precision floats, which limits
 * the range of values that can be represented with integer precision to:
 * <pre>
 * -(2^53) <= N <= 2^53
 * </pre>
 * Int64 objects wrap a node Buffer that holds the 8-bytes of int64 data.  These
 * objects operate directly on the buffer which means that if they are created
 * using an existing buffer then setting the value will modify the Buffer, and
 * vice-versa.
 * <p/>
 * <h4>Internal Representation</h4>
 *
 * The internal buffer byte order is big-endian (i.e. the most-significant byte
 * is at {@link Int64#buffer buffer}[{@link Int64#offset offset}+0], the least
 * significant at {@link Int64#buffer buffer}[{@link Int64#offset offset}+7]).
 * For the purposes of converting to/from Javascript native numbers, the value
 * is assumed to be a signed integer stored in 2's complement form.
 * <p/>
 * For details about IEEE-754 see:
 * <a href="http://en.wikipedia.org/wiki/Double-precision_floating-point_format">
 * Double-precision floating-point format</a>
 *
 * Constructor accepts any of the following argument types:
 * <p/>
 * <table>
 *   <tr>
 *     <td>new Int64(buffer[, offset=0])&nbsp;</td>
 *     <td>Buffer, with byte offset, holding 64-bit, big-endian encoded integer</td>
 *   </tr>
 *   <tr>
 *     <td>new Int64(Uint8Array[, offset=0])&nbsp;</td>
 *     <td>Uint8Array, with byte offset, holding 64-bit, big-endian encoded integer</td>
 *  </tr>
 *  <tr>
 *     <td>new Int64(string)&nbsp;</td>
 *     <td>Hex string (throws if n is outside int64 range)</td>
 *  </tr>
 *  <tr>
 *     <td>new Int64(number)&nbsp;</td>
 *     <td>Number (throws if n is outside int64 range)</td>
 *  </tr>
 *  <tr>
 *     <td>new Int64(high, low)&nbsp;</td>
 *     <td>Raw bits as two 32-bit values</td>
 *  </tr>
 * </table>
 * @class
 * @classdesc Holds a 64-bit integer.
 */
var Int64 = module.exports = function(a1, a2) {

  /**
   * Holds 8 byte integer in big-endian order.
   * @name Int64#buffer
   * @type Buffer
   */

  /**
   * Offset within {@link Int64#buffer buffer} of beginning of integer bytes.
   * @name Int64#offset
   * @type Number
   */

  if (a1 instanceof Buffer) {
    this.buffer = a1;
    this.offset = a2 || 0;
  } else if (Object.prototype.toString.call(a1) == '[object Uint8Array]') {
    // Under Browserify, Buffers can extend Uint8Arrays rather than an
    // instance of Buffer. We could assume the passed in Uint8Array is actually
    // a buffer but that won't handle the case where a raw Uint8Array is passed
    // in. We construct a new Buffer just in case.
    this.buffer = new Buffer(a1);
    this.offset = a2 || 0;
  } else {
    this.buffer = this.buffer || new Buffer(8);
    this.offset = 0;
    this.setValue.apply(this, arguments);
  }
};


/**
 * Maximum integer value that JS can accurately represent (2^52).
 * @type {Number}
 * @constant
 * @default
 */
Int64.MAX_INT = Math.pow(2, 53);

/**
 * Maximum integer value that JS can accurately represent -(2^52).
 * @type {Number}
 * @constant
 * @default
 */
Int64.MIN_INT = -Math.pow(2, 53);

Int64.prototype = {
  /**
   * Performs in-place two's compliment of 8 byte number stored in
   * {@link Int64#buffer buffer}, starting at {@link Int64#offset offset}.  See
   * <a href="http://en.wikipedia.org/wiki/Two's_complement">Two's complement</a>.
   */
  _2scomp: function() {
    var b = this.buffer, o = this.offset, carry = 1;
    for (var i = o + 7; i >= o; i--) {
      var v = (b[i] ^ 0xff) + carry;
      b[i] = v & 0xff;
      carry = v >> 8;
    }
  },

  /**
   * Sets the integer value. Takes any of the following arguments:
   * <p/>
   * <table>
   * <tr><td>setValue(string)&nbsp;</td><td>- A hexidecimal string</td></tr>
   * <tr><td>setValue(number)&nbsp;</td><td>- Number (throws if n is outside int64 range)</td></tr>
   * <tr><td>setValue(high, low)&nbsp;</td><td>- Raw bits as two 32-bit values</td></tr>
   * </table>
   */
  setValue: function(hi, lo) {
    var negate = false;
    if (arguments.length == 1) {
      if (typeof(hi) == 'number') {
        // Simplify bitfield retrieval by using abs() value.  We restore sign
        // later
        negate = hi < 0;
        hi = Math.abs(hi);
        lo = hi % VAL32;
        hi = hi / VAL32;
        if (hi > VAL32) throw new RangeError(hi  + ' is outside Int64 range');
        hi = hi | 0;
      } else if (typeof(hi) == 'string') {
        hi = (hi + '').replace(/^0x/, '');
        lo = hi.substr(-8);
        hi = hi.length > 8 ? hi.substr(0, hi.length - 8) : '';
        hi = parseInt(hi, 16);
        lo = parseInt(lo, 16);
      } else {
        throw new Error(hi + ' must be a Number or String');
      }
    }

    // Technically we should throw if hi or lo is outside int32 range here, but
    // it's not worth the effort. Anything past the 32'nd bit is ignored.

    // Copy bytes to buffer
    var b = this.buffer, o = this.offset;
    for (var i = 7; i >= 0; i--) {
      b[o+i] = lo & 0xff;
      lo = i == 4 ? hi : lo >>> 8;
    }

    // Restore sign of passed argument
    if (negate) this._2scomp();
  },

  /**
   * Convert to a native Javascript number.
   * <p/>
   * WARNING: Do not expect this value to be accurate to integer precision for
   * large (positive or negative) numbers!
   * @param {Boolean} allowImprecise If <i>true</i>, no check is performed to
   * verify the returned value is accurate to integer precision.  If
   * <i>false</i>, imprecise numbers (very large positive or negative numbers)
   * will be forced to +/-Infinity.
   * @return {Number} Javascript number representing the integer, or +/-Infinity
   * if not enough precision available and <code>allowImprecise</code> is set to
   * <i>true</i>.
   */
  toNumber: function(allowImprecise) {
    var b = this.buffer, o = this.offset;

    // Running sum of octets, doing a 2's complement
    var negate = b[o] & 0x80, x = 0, carry = 1;
    for (var i = 7, m = 1; i >= 0; i--, m *= 256) {
      var v = b[o+i];

      // 2's complement for negative numbers
      if (negate) {
        v = (v ^ 0xff) + carry;
        carry = v >> 8;
        v = v & 0xff;
      }

      x += v * m;
    }

    // Return Infinity if we've lost integer precision
    if (!allowImprecise && x >= Int64.MAX_INT) {
      return negate ? -Infinity : Infinity;
    }

    return negate ? -x : x;
  },

  /**
   * Convert to a Javascript Number.  Does the conversion with a call to
   * {@link Int64#toNumber toNumber}<code>(false)</code>.
   * @see {@link Int64#toNumber toNumber()}
   * @return {Number} Javascript number representing the integer, or +/-Infinity
   * if not enough precision to hold the integer.
   */
  valueOf: function() {
    return this.toNumber(false);
  },

  /**
   * Return string representation of integer.  Conversion is performed with
   * {@link Int64#valueOf valueOf()}<code>.toString(radix)</code>.
   *
   * @param {Number} [radix=10] Just like <code>Number.toString()</code> radix
   */
  toString: function(radix) {
    return this.valueOf().toString(radix || 10);
  },

  /**
   * Return a string showing the buffer octets, with MSB on the left.
   *
   * @param {String} sep Separator string. default is '' (empty string)
   */
  toOctetString: function(sep) {
    var out = new Array(8);
    var b = this.buffer, o = this.offset;
    for (var i = 0; i < 8; i++) {
      out[i] = _HEX[b[o+i]];
    }
    return out.join(sep || '');
  },

  /**
   * Returns newly allocated Buffer holding integer encoded as 8 bytes in
   * big-endian order.
   *
   * @param {bool} [rawBuffer=false]  If no offset and this is <i>true</i>,
   * return the internal buffer.  Should only be used if you're discarding the
   * Int64 afterwards, as it breaks encapsulation.
   */
  toBuffer: function(rawBuffer) {
    if (rawBuffer && this.offset === 0) return this.buffer;

    var out = new Buffer(8);
    this.buffer.copy(out, 0, this.offset, this.offset + 8);
    return out;
  },

  /**
   * Copy 8 bytes of int64 into target buffer at target offset.
   *
   * @param {Buffer} targetBuffer       Buffer to copy into.
   * @param {number} [targetOffset=0]   Offset into target buffer.
   */
  copy: function(targetBuffer, targetOffset) {
    this.buffer.copy(targetBuffer, targetOffset || 0, this.offset, this.offset + 8);
  },

  /**
   * Returns a string represenation of the Int64 object.
   * <pre>
   * [Int64 value:1006414150992247 octets:00 03 93 54 0d f7 81 77]
   * </pre>
   * @return {String} String representation of object
   */
  inspect: function() {
    return '[Int64 value:' + this + ' octets:' + this.toOctetString(' ') + ']';
  }
};