blob: 205841ab75ad94918f3879cf2c29aa3b3ff9cceb [file] [log] [blame]
// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
/*global escape: true */
/**
* @fileoverview Definition of RawVomReader.
* @private
*/
module.exports = RawVomReader;
var BigInt = require('../vdl/big-int.js');
var BinaryReader = require('./binary-reader.js');
var ByteUtil = require('../vdl/byte-util.js');
/**
* RawVomReader reads VOM primitive values (numbers, strings, bools) from a
* provided Uint8Array.
* @private
* @param {Uint8Array|StreamReader} arr The array to read from.
* @constructor
*/
function RawVomReader(arr) {
if (arr instanceof Uint8Array) {
this._reader = new BinaryReader(arr);
} else {
this._reader = arr;
}
}
/**
* Reads a uint as a BigInt.
* @return {Promise<BigInt>} The BigUint that was read.
*/
RawVomReader.prototype.readBigUint = function() {
var reader = this;
return this._reader.readByte().then(function(firstByte) {
if (firstByte <= 0x7f) {
if (firstByte === 0) {
return new BigInt(0, new Uint8Array(0));
}
return new BigInt(1, new Uint8Array([firstByte]));
}
var numBytes = 0x100 - firstByte;
if (numBytes > 8 || numBytes < 1) {
throw new Error('Invalid size ' + numBytes);
}
return reader._reader.readByteArray(numBytes).then(function(uintBytes) {
return new BigInt(1, uintBytes);
});
});
};
/**
* Returns a control byte if the next byte is a control byte.
* @returns {Promise<number>} a control byte if there is one, null if there
* is no control byte.
*/
RawVomReader.prototype.tryReadControlByte = function() {
var reader = this;
return this.peekByte().then(function(firstByte) {
if (firstByte === null) {
return null;
}
if (firstByte > 0x7f && firstByte <= 0xef) {
return reader.readByte();
}
return null;
});
};
/**
* Reads a BigInt.
* @return {Promise<BigInt>} The BigInt that was read.
*/
RawVomReader.prototype.readBigInt = function() {
return this.readBigUint().then(function(uint) {
var bytes = uint.getUintBytes();
var sign;
if (uint.getSign() === 0) {
sign = 0;
} else if (bytes.length > 0 && (bytes[bytes.length - 1] & 0x01) !== 0) {
sign = -1;
} else {
sign = 1;
}
bytes = ByteUtil.shiftRightOne(bytes);
if (sign === -1) {
bytes = ByteUtil.increment(bytes);
}
return new BigInt(sign, bytes);
});
};
/**
* Reads a unsigned integer as a native JavaScript number.
* @return {Promise<number>} The uint that was read.
*/
RawVomReader.prototype.readUint = function() {
return this.readBigUint().then(function(uint) {
return uint.toNativeNumber();
});
};
/**
* Reads a integer as a native JavaScript number.
* @return {Promise<number>} The int that was read.
*/
RawVomReader.prototype.readInt = function() {
return this.readBigInt().then(function(uint) {
return uint.toNativeNumber();
});
};
/**
* Reads a float as a native JavaScript number.
* @return {Promise<number>} The float that was read.
*/
RawVomReader.prototype.readFloat = function() {
return this.readBigUint().then(function (bigInt) {
var uintBytes = bigInt.getUintBytes();
var arr = new Uint8Array(8);
arr.set(uintBytes, arr.length - uintBytes.length);
var view = new DataView(arr.buffer);
return view.getFloat64(0, true);
});
};
/**
* Reads a string.
* @return {Promise<string>} The string that was read.
*/
RawVomReader.prototype.readString = function() {
var reader = this;
return this.readUint().then(function(length) {
return reader._reader.readByteArray(length);
}).then(function(bytes) {
var str = '';
for (var i = 0; i < bytes.length; i++) {
str += String.fromCharCode(bytes[i]);
}
return decodeURIComponent(escape(str));
});
};
/**
* Reads a boolean.
* @return {Promise<boolean>} The boolean that was read.
*/
RawVomReader.prototype.readBool = function() {
return this._reader.readByte().then(function(b) {
if (b === 1) {
return true;
} else if (b === 0) {
return false;
}
throw new Error('Invalid boolean byte ' + b);
});
};
/**
* Reads a single VOM byte.
* @return {Promise<byte>} The byte that was read.
*/
RawVomReader.prototype.readByte = function() {
return this._reader.readByte();
};
/**
* Reads a single VOM byte without advancing the reader
* @return {Promise<number>} The byte that was read.
*/
RawVomReader.prototype.peekByte = function() {
return this._reader.peekByte();
};
/**
* Reads raw bytes.
* @param {number} amt The number of bytes to read.
* @return {Promise<Uint8Array>} The bytes that were read.
*/
RawVomReader.prototype._readRawBytes = function(amt) {
return this._reader.readByteArray(amt);
};
RawVomReader.prototype.hasData = function() {
return this._reader.hasData();
};