blob: fec79cfad533c79cf431d3818910dbfeba3c11ca [file] [log] [blame]
/**
* @fileoverview Helper methods for reading data from the binary wire format.
*/
goog.module('protobuf.binary.reader');
const BufferDecoder = goog.require('protobuf.binary.BufferDecoder');
const ByteString = goog.require('protobuf.ByteString');
const Int64 = goog.require('protobuf.Int64');
/******************************************************************************
* OPTIONAL FUNCTIONS
******************************************************************************/
/**
* Reads a boolean from the binary bytes.
* Also returns the first position after the boolean.
* @param {!BufferDecoder} bufferDecoder Binary format encoded bytes.
* @param {number} index Start of the data.
* @return {{value: boolean, nextCursor: number}}
*/
function readBoolValue(bufferDecoder, index) {
const {lowBits, highBits, dataStart} = bufferDecoder.getVarint(index);
return {value: lowBits !== 0 || highBits !== 0, nextCursor: dataStart};
}
/**
* Reads a boolean value from the binary bytes.
* @param {!BufferDecoder} bufferDecoder Binary format encoded bytes.
* @param {number} start Start of the data.
* @return {boolean}
* @package
*/
function readBool(bufferDecoder, start) {
return readBoolValue(bufferDecoder, start).value;
}
/**
* Reads a double value from the binary bytes.
* @param {!BufferDecoder} bufferDecoder Binary format encoded bytes.
* @param {number} start Start of the data.
* @return {!ByteString}
* @package
*/
function readBytes(bufferDecoder, start) {
return readDelimited(bufferDecoder, start).asByteString();
}
/**
* Reads a int32 value from the binary bytes encoded as varint.
* @param {!BufferDecoder} bufferDecoder Binary format encoded bytes.
* @param {number} index Start of the data.
* @return {{value: number, nextCursor: number}}
* @package
*/
function readInt32Value(bufferDecoder, index) {
const {lowBits, dataStart} = bufferDecoder.getVarint(index);
// Negative 32 bit integers are encoded with 64 bit values.
// Clients are expected to truncate back to 32 bits.
// This is why we are dropping the upper bytes here.
return {value: lowBits | 0, nextCursor: dataStart};
}
/**
* Reads a int32 value from the binary bytes encoded as varint.
* @param {!BufferDecoder} bufferDecoder Binary format encoded bytes.
* @param {number} start Start of the data.
* @return {number}
* @package
*/
function readInt32(bufferDecoder, start) {
return readInt32Value(bufferDecoder, start).value;
}
/**
* Reads a int32 value from the binary bytes encoded as varint.
* @param {!BufferDecoder} bufferDecoder Binary format encoded bytes.
* @param {number} index Start of the data.
* @return {{ value: !Int64, nextCursor: number}}
* @package
*/
function readInt64Value(bufferDecoder, index) {
const {lowBits, highBits, dataStart} = bufferDecoder.getVarint(index);
return {value: Int64.fromBits(lowBits, highBits), nextCursor: dataStart};
}
/**
* Reads a int32 value from the binary bytes encoded as varint.
* @param {!BufferDecoder} bufferDecoder Binary format encoded bytes.
* @param {number} start Start of the data.
* @return {!Int64}
* @package
*/
function readInt64(bufferDecoder, start) {
return readInt64Value(bufferDecoder, start).value;
}
/**
* Reads a fixed int32 value from the binary bytes.
* @param {!BufferDecoder} bufferDecoder Binary format encoded bytes.
* @param {number} start Start of the data.
* @return {number}
* @package
*/
function readFixed32(bufferDecoder, start) {
return bufferDecoder.getUint32(start);
}
/**
* Reads a float value from the binary bytes.
* @param {!BufferDecoder} bufferDecoder Binary format encoded bytes.
* @param {number} start Start of the data.
* @return {number}
* @package
*/
function readFloat(bufferDecoder, start) {
return bufferDecoder.getFloat32(start);
}
/**
* Reads a fixed int64 value from the binary bytes.
* @param {!BufferDecoder} bufferDecoder Binary format encoded bytes.
* @param {number} start Start of the data.
* @return {!Int64}
* @package
*/
function readSfixed64(bufferDecoder, start) {
const lowBits = bufferDecoder.getInt32(start);
const highBits = bufferDecoder.getInt32(start + 4);
return Int64.fromBits(lowBits, highBits);
}
/**
* Reads a sint32 value from the binary bytes encoded as varint.
* Also returns the first position after the boolean.
* @param {!BufferDecoder} bufferDecoder Binary format encoded bytes.
* @param {number} index Start of the data.
* @return {{value: number, nextCursor: number}}
*/
function readSint32Value(bufferDecoder, index) {
const {lowBits, dataStart} = bufferDecoder.getVarint(index);
// Truncate upper bits and convert from zig zag to signd int
return {value: (lowBits >>> 1) ^ -(lowBits & 0x01), nextCursor: dataStart};
}
/**
* Reads a sint32 value from the binary bytes encoded as varint.
* @param {!BufferDecoder} bufferDecoder Binary format encoded bytes.
* @param {number} start Start of the data.
* @return {number}
* @package
*/
function readSint32(bufferDecoder, start) {
return readSint32Value(bufferDecoder, start).value;
}
/**
* Reads a sint64 value from the binary bytes encoded as varint.
* Also returns the first position after the value.
* @param {!BufferDecoder} bufferDecoder Binary format encoded bytes.
* @param {number} index Start of the data.
* @return {{value: !Int64, nextCursor: number}}
* @package
*/
function readSint64Value(bufferDecoder, index) {
const {lowBits, highBits, dataStart} = bufferDecoder.getVarint(index);
const sign = -(lowBits & 0x01);
const decodedLowerBits = ((lowBits >>> 1) | (highBits & 0x01) << 31) ^ sign;
const decodedUpperBits = (highBits >>> 1) ^ sign;
return {
value: Int64.fromBits(decodedLowerBits, decodedUpperBits),
nextCursor: dataStart
};
}
/**
* Reads a sint64 value from the binary bytes encoded as varint.
* @param {!BufferDecoder} bufferDecoder Binary format encoded bytes.
* @param {number} start Start of the data.
* @return {!Int64}
* @package
*/
function readSint64(bufferDecoder, start) {
return readSint64Value(bufferDecoder, start).value;
}
/**
* Read a subarray of bytes representing a length delimited field.
* @param {!BufferDecoder} bufferDecoder Binary format encoded bytes.
* @param {number} start Start of the data.
* @return {!BufferDecoder}
* @package
*/
function readDelimited(bufferDecoder, start) {
const {lowBits, dataStart} = bufferDecoder.getVarint(start);
const unsignedLength = lowBits >>> 0;
return bufferDecoder.subBufferDecoder(dataStart, unsignedLength);
}
/**
* Reads a string value from the binary bytes.
* @param {!BufferDecoder} bufferDecoder Binary format encoded bytes.
* @param {number} start Start of the data.
* @return {string}
* @package
*/
function readString(bufferDecoder, start) {
return readDelimited(bufferDecoder, start).asString();
}
/**
* Reads a uint32 value from the binary bytes encoded as varint.
* Also returns the first position after the value.
* @param {!BufferDecoder} bufferDecoder Binary format encoded bytes.
* @param {number} index Start of the data.
* @return {{value: number, nextCursor: number}}
*/
function readUint32Value(bufferDecoder, index) {
const {lowBits, dataStart} = bufferDecoder.getVarint(index);
return {value: lowBits >>> 0, nextCursor: dataStart};
}
/**
* Reads a uint32 value from the binary bytes encoded as varint.
* @param {!BufferDecoder} bufferDecoder Binary format encoded bytes.
* @param {number} start Start of the data.
* @return {number}
* @package
*/
function readUint32(bufferDecoder, start) {
return readUint32Value(bufferDecoder, start).value;
}
/**
* Reads a double value from the binary bytes.
* @param {!BufferDecoder} bufferDecoder Binary format encoded bytes.
* @param {number} start Start of the data.
* @return {number}
* @package
*/
function readDouble(bufferDecoder, start) {
return bufferDecoder.getFloat64(start);
}
/**
* Reads a fixed int32 value from the binary bytes.
* @param {!BufferDecoder} bufferDecoder Binary format encoded bytes.
* @param {number} start Start of the data.
* @return {number}
* @package
*/
function readSfixed32(bufferDecoder, start) {
return bufferDecoder.getInt32(start);
}
/******************************************************************************
* REPEATED FUNCTIONS
******************************************************************************/
/**
* Reads a packed bool field, which consists of a length header and a list of
* unsigned varints.
* @param {!BufferDecoder} bufferDecoder Binary format encoded bytes.
* @param {number} start Start of the data.
* @return {!Array<boolean>}
* @package
*/
function readPackedBool(bufferDecoder, start) {
return readPackedVariableLength(bufferDecoder, start, readBoolValue);
}
/**
* Reads a packed double field, which consists of a length header and a list of
* fixed64.
* @param {!BufferDecoder} bufferDecoder Binary format encoded bytes.
* @param {number} start Start of the data.
* @return {!Array<number>}
* @package
*/
function readPackedDouble(bufferDecoder, start) {
return readPackedFixed(bufferDecoder, start, 8, readDouble);
}
/**
* Reads a packed fixed32 field, which consists of a length header and a list of
* fixed32.
* @param {!BufferDecoder} bufferDecoder Binary format encoded bytes.
* @param {number} start Start of the data.
* @return {!Array<number>}
* @package
*/
function readPackedFixed32(bufferDecoder, start) {
return readPackedFixed(bufferDecoder, start, 4, readFixed32);
}
/**
* Reads a packed float field, which consists of a length header and a list of
* fixed64.
* @param {!BufferDecoder} bufferDecoder Binary format encoded bytes.
* @param {number} start Start of the data.
* @return {!Array<number>}
* @package
*/
function readPackedFloat(bufferDecoder, start) {
return readPackedFixed(bufferDecoder, start, 4, readFloat);
}
/**
* Reads a packed int32 field, which consists of a length header and a list of
* varint.
* @param {!BufferDecoder} bufferDecoder Binary format encoded bytes.
* @param {number} start Start of the data.
* @return {!Array<number>}
* @package
*/
function readPackedInt32(bufferDecoder, start) {
return readPackedVariableLength(bufferDecoder, start, readInt32Value);
}
/**
* Reads a packed int64 field, which consists of a length header and a list
* of int64.
* @param {!BufferDecoder} bufferDecoder Binary format encoded bytes.
* @param {number} start Start of the data.
* @return {!Array<!Int64>}
* @package
*/
function readPackedInt64(bufferDecoder, start) {
return readPackedVariableLength(bufferDecoder, start, readInt64Value);
}
/**
* Reads a packed sfixed32 field, which consists of a length header and a list
* of sfixed32.
* @param {!BufferDecoder} bufferDecoder Binary format encoded bytes.
* @param {number} start Start of the data.
* @return {!Array<number>}
* @package
*/
function readPackedSfixed32(bufferDecoder, start) {
return readPackedFixed(bufferDecoder, start, 4, readSfixed32);
}
/**
* Reads a packed sfixed64 field, which consists of a length header and a list
* of sfixed64.
* @param {!BufferDecoder} bufferDecoder Binary format encoded bytes.
* @param {number} start Start of the data.
* @return {!Array<!Int64>}
* @package
*/
function readPackedSfixed64(bufferDecoder, start) {
return readPackedFixed(bufferDecoder, start, 8, readSfixed64);
}
/**
* Reads a packed sint32 field, which consists of a length header and a list of
* varint.
* @param {!BufferDecoder} bufferDecoder Binary format encoded bytes.
* @param {number} start Start of the data.
* @return {!Array<number>}
* @package
*/
function readPackedSint32(bufferDecoder, start) {
return readPackedVariableLength(bufferDecoder, start, readSint32Value);
}
/**
* Reads a packed sint64 field, which consists of a length header and a list
* of sint64.
* @param {!BufferDecoder} bufferDecoder Binary format encoded bytes.
* @param {number} start Start of the data.
* @return {!Array<!Int64>}
* @package
*/
function readPackedSint64(bufferDecoder, start) {
return readPackedVariableLength(bufferDecoder, start, readSint64Value);
}
/**
* Reads a packed uint32 field, which consists of a length header and a list of
* varint.
* @param {!BufferDecoder} bufferDecoder Binary format encoded bytes.
* @param {number} start Start of the data.
* @return {!Array<number>}
* @package
*/
function readPackedUint32(bufferDecoder, start) {
return readPackedVariableLength(bufferDecoder, start, readUint32Value);
}
/**
* Read packed variable length values.
* @param {!BufferDecoder} bufferDecoder Binary format encoded bytes.
* @param {number} start Start of the data.
* @param {function(!BufferDecoder, number):{value:T, nextCursor: number}}
* valueFunction
* @return {!Array<T>}
* @package
* @template T
*/
function readPackedVariableLength(bufferDecoder, start, valueFunction) {
const /** !Array<T> */ result = [];
const {lowBits, dataStart} = bufferDecoder.getVarint(start);
let cursor = dataStart;
const unsignedLength = lowBits >>> 0;
while (cursor < dataStart + unsignedLength) {
const {value, nextCursor} = valueFunction(bufferDecoder, cursor);
cursor = nextCursor;
result.push(value);
}
return result;
}
/**
* Read a packed fixed values.
* @param {!BufferDecoder} bufferDecoder Binary format encoded bytes.
* @param {number} start Start of the data.
* @param {number} size End of the data.
* @param {function(!BufferDecoder, number):T} valueFunction
* @return {!Array<T>}
* @package
* @template T
*/
function readPackedFixed(bufferDecoder, start, size, valueFunction) {
const {lowBits, dataStart} = bufferDecoder.getVarint(start);
const unsignedLength = lowBits >>> 0;
const noOfEntries = unsignedLength / size;
const /** !Array<T> */ result = new Array(noOfEntries);
let cursor = dataStart;
for (let i = 0; i < noOfEntries; i++) {
result[i] = valueFunction(bufferDecoder, cursor);
cursor += size;
}
return result;
}
exports = {
readBool,
readBytes,
readDelimited,
readDouble,
readFixed32,
readFloat,
readInt32,
readInt64,
readSint32,
readSint64,
readSfixed32,
readSfixed64,
readString,
readUint32,
readPackedBool,
readPackedDouble,
readPackedFixed32,
readPackedFloat,
readPackedInt32,
readPackedInt64,
readPackedSfixed32,
readPackedSfixed64,
readPackedSint32,
readPackedSint64,
readPackedUint32,
};