@lichtblick/cdr
Version:
Common Data Representation serialization and deserialization library
358 lines • 20.4 kB
JavaScript
"use strict";
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
if (kind === "m") throw new TypeError("Private method is not writable");
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
};
var _CdrReader_instances, _CdrReader_view, _CdrReader_littleEndian, _CdrReader_hostLittleEndian, _CdrReader_eightByteAlignment, _CdrReader_isCDR2, _CdrReader_origin, _CdrReader_memberHeaderV1, _CdrReader_resetOrigin, _CdrReader_memberHeaderV2, _CdrReader_emHeaderObjectSize, _CdrReader_align, _CdrReader_typedArray, _CdrReader_typedArrayUnaligned, _CdrReader_typedArraySlow;
Object.defineProperty(exports, "__esModule", { value: true });
exports.CdrReader = void 0;
const getEncapsulationKindInfo_1 = require("./getEncapsulationKindInfo");
const isBigEndian_1 = require("./isBigEndian");
const lengthCodes_1 = require("./lengthCodes");
const reservedPIDs_1 = require("./reservedPIDs");
const textDecoder = new TextDecoder("utf8");
class CdrReader {
get kind() {
return __classPrivateFieldGet(this, _CdrReader_view, "f").getUint8(1);
}
get decodedBytes() {
return this.offset;
}
get byteLength() {
return __classPrivateFieldGet(this, _CdrReader_view, "f").byteLength;
}
constructor(data) {
_CdrReader_instances.add(this);
_CdrReader_view.set(this, void 0);
_CdrReader_littleEndian.set(this, void 0);
_CdrReader_hostLittleEndian.set(this, void 0);
_CdrReader_eightByteAlignment.set(this, void 0); // Alignment for 64-bit values, 4 on CDR2 8 on CDR1
_CdrReader_isCDR2.set(this, void 0);
/** Origin offset into stream used for alignment */
_CdrReader_origin.set(this, 0);
if (data.byteLength < 4) {
throw new Error(`Invalid CDR data size ${data.byteLength}, must contain at least a 4-byte header`);
}
__classPrivateFieldSet(this, _CdrReader_view, new DataView(data.buffer, data.byteOffset, data.byteLength), "f");
const kind = this.kind;
const { isCDR2, littleEndian, usesDelimiterHeader, usesMemberHeader } = (0, getEncapsulationKindInfo_1.getEncapsulationKindInfo)(kind);
this.usesDelimiterHeader = usesDelimiterHeader;
this.usesMemberHeader = usesMemberHeader;
__classPrivateFieldSet(this, _CdrReader_littleEndian, littleEndian, "f");
__classPrivateFieldSet(this, _CdrReader_hostLittleEndian, !(0, isBigEndian_1.isBigEndian)(), "f");
__classPrivateFieldSet(this, _CdrReader_isCDR2, isCDR2, "f");
__classPrivateFieldSet(this, _CdrReader_eightByteAlignment, isCDR2 ? 4 : 8, "f");
__classPrivateFieldSet(this, _CdrReader_origin, 4, "f");
this.offset = 4;
}
int8() {
const value = __classPrivateFieldGet(this, _CdrReader_view, "f").getInt8(this.offset);
this.offset += 1;
return value;
}
uint8() {
const value = __classPrivateFieldGet(this, _CdrReader_view, "f").getUint8(this.offset);
this.offset += 1;
return value;
}
int16() {
__classPrivateFieldGet(this, _CdrReader_instances, "m", _CdrReader_align).call(this, 2);
const value = __classPrivateFieldGet(this, _CdrReader_view, "f").getInt16(this.offset, __classPrivateFieldGet(this, _CdrReader_littleEndian, "f"));
this.offset += 2;
return value;
}
uint16() {
__classPrivateFieldGet(this, _CdrReader_instances, "m", _CdrReader_align).call(this, 2);
const value = __classPrivateFieldGet(this, _CdrReader_view, "f").getUint16(this.offset, __classPrivateFieldGet(this, _CdrReader_littleEndian, "f"));
this.offset += 2;
return value;
}
int32() {
__classPrivateFieldGet(this, _CdrReader_instances, "m", _CdrReader_align).call(this, 4);
const value = __classPrivateFieldGet(this, _CdrReader_view, "f").getInt32(this.offset, __classPrivateFieldGet(this, _CdrReader_littleEndian, "f"));
this.offset += 4;
return value;
}
uint32() {
__classPrivateFieldGet(this, _CdrReader_instances, "m", _CdrReader_align).call(this, 4);
const value = __classPrivateFieldGet(this, _CdrReader_view, "f").getUint32(this.offset, __classPrivateFieldGet(this, _CdrReader_littleEndian, "f"));
this.offset += 4;
return value;
}
int64() {
__classPrivateFieldGet(this, _CdrReader_instances, "m", _CdrReader_align).call(this, __classPrivateFieldGet(this, _CdrReader_eightByteAlignment, "f"));
const value = __classPrivateFieldGet(this, _CdrReader_view, "f").getBigInt64(this.offset, __classPrivateFieldGet(this, _CdrReader_littleEndian, "f"));
this.offset += 8;
return value;
}
uint64() {
__classPrivateFieldGet(this, _CdrReader_instances, "m", _CdrReader_align).call(this, __classPrivateFieldGet(this, _CdrReader_eightByteAlignment, "f"));
const value = __classPrivateFieldGet(this, _CdrReader_view, "f").getBigUint64(this.offset, __classPrivateFieldGet(this, _CdrReader_littleEndian, "f"));
this.offset += 8;
return value;
}
uint16BE() {
__classPrivateFieldGet(this, _CdrReader_instances, "m", _CdrReader_align).call(this, 2);
const value = __classPrivateFieldGet(this, _CdrReader_view, "f").getUint16(this.offset, false);
this.offset += 2;
return value;
}
uint32BE() {
__classPrivateFieldGet(this, _CdrReader_instances, "m", _CdrReader_align).call(this, 4);
const value = __classPrivateFieldGet(this, _CdrReader_view, "f").getUint32(this.offset, false);
this.offset += 4;
return value;
}
uint64BE() {
__classPrivateFieldGet(this, _CdrReader_instances, "m", _CdrReader_align).call(this, __classPrivateFieldGet(this, _CdrReader_eightByteAlignment, "f"));
const value = __classPrivateFieldGet(this, _CdrReader_view, "f").getBigUint64(this.offset, false);
this.offset += 8;
return value;
}
float32() {
__classPrivateFieldGet(this, _CdrReader_instances, "m", _CdrReader_align).call(this, 4);
const value = __classPrivateFieldGet(this, _CdrReader_view, "f").getFloat32(this.offset, __classPrivateFieldGet(this, _CdrReader_littleEndian, "f"));
this.offset += 4;
return value;
}
float64() {
__classPrivateFieldGet(this, _CdrReader_instances, "m", _CdrReader_align).call(this, __classPrivateFieldGet(this, _CdrReader_eightByteAlignment, "f"));
const value = __classPrivateFieldGet(this, _CdrReader_view, "f").getFloat64(this.offset, __classPrivateFieldGet(this, _CdrReader_littleEndian, "f"));
this.offset += 8;
return value;
}
string(prereadLength) {
const length = prereadLength ?? this.uint32();
if (length <= 1) {
this.offset += length;
return "";
}
const data = new Uint8Array(__classPrivateFieldGet(this, _CdrReader_view, "f").buffer, __classPrivateFieldGet(this, _CdrReader_view, "f").byteOffset + this.offset, length - 1);
const value = textDecoder.decode(data);
this.offset += length;
return value;
}
/** Reads the delimiter header which contains and returns the object size */
dHeader() {
const header = this.uint32();
return header;
}
/**
* Reads the member header (EMHEADER) and returns the member ID, mustUnderstand flag, and object size with optional length code
* The length code is only present in CDR2 and should prompt objectSize to be used in place of sequence length if applicable.
* See Extensible and Dynamic Topic Types (DDS-XTypes) v1.3 @ `7.4.3.4.2` for more info about CDR2 EMHEADER composition.
* If a sentinelHeader was read (PL_CDR v1), the readSentinelHeader flag is set to true.
*/
emHeader() {
if (__classPrivateFieldGet(this, _CdrReader_isCDR2, "f")) {
return __classPrivateFieldGet(this, _CdrReader_instances, "m", _CdrReader_memberHeaderV2).call(this);
}
else {
return __classPrivateFieldGet(this, _CdrReader_instances, "m", _CdrReader_memberHeaderV1).call(this);
}
}
/** Reads the PID_SENTINEL value if encapsulation kind supports it (PL_CDR version 1)*/
sentinelHeader() {
if (!__classPrivateFieldGet(this, _CdrReader_isCDR2, "f")) {
__classPrivateFieldGet(this, _CdrReader_instances, "m", _CdrReader_align).call(this, 4);
const header = this.uint16();
// Indicates the end of the parameter list structure
const sentinelPIDFlag = (header & 0x3fff) === reservedPIDs_1.SENTINEL_PID;
if (!sentinelPIDFlag) {
throw Error(`Expected SENTINEL_PID (${reservedPIDs_1.SENTINEL_PID.toString(16)}) flag, but got ${header.toString(16)}`);
}
this.uint16();
}
}
sequenceLength() {
return this.uint32();
}
int8Array(count = this.sequenceLength()) {
const array = new Int8Array(__classPrivateFieldGet(this, _CdrReader_view, "f").buffer, __classPrivateFieldGet(this, _CdrReader_view, "f").byteOffset + this.offset, count);
this.offset += count;
return array;
}
uint8Array(count = this.sequenceLength()) {
const array = new Uint8Array(__classPrivateFieldGet(this, _CdrReader_view, "f").buffer, __classPrivateFieldGet(this, _CdrReader_view, "f").byteOffset + this.offset, count);
this.offset += count;
return array;
}
int16Array(count = this.sequenceLength()) {
return __classPrivateFieldGet(this, _CdrReader_instances, "m", _CdrReader_typedArray).call(this, Int16Array, "getInt16", count);
}
uint16Array(count = this.sequenceLength()) {
return __classPrivateFieldGet(this, _CdrReader_instances, "m", _CdrReader_typedArray).call(this, Uint16Array, "getUint16", count);
}
int32Array(count = this.sequenceLength()) {
return __classPrivateFieldGet(this, _CdrReader_instances, "m", _CdrReader_typedArray).call(this, Int32Array, "getInt32", count);
}
uint32Array(count = this.sequenceLength()) {
return __classPrivateFieldGet(this, _CdrReader_instances, "m", _CdrReader_typedArray).call(this, Uint32Array, "getUint32", count);
}
int64Array(count = this.sequenceLength()) {
return __classPrivateFieldGet(this, _CdrReader_instances, "m", _CdrReader_typedArray).call(this, BigInt64Array, "getBigInt64", count, __classPrivateFieldGet(this, _CdrReader_eightByteAlignment, "f"));
}
uint64Array(count = this.sequenceLength()) {
return __classPrivateFieldGet(this, _CdrReader_instances, "m", _CdrReader_typedArray).call(this, BigUint64Array, "getBigUint64", count, __classPrivateFieldGet(this, _CdrReader_eightByteAlignment, "f"));
}
float32Array(count = this.sequenceLength()) {
return __classPrivateFieldGet(this, _CdrReader_instances, "m", _CdrReader_typedArray).call(this, Float32Array, "getFloat32", count);
}
float64Array(count = this.sequenceLength()) {
return __classPrivateFieldGet(this, _CdrReader_instances, "m", _CdrReader_typedArray).call(this, Float64Array, "getFloat64", count, __classPrivateFieldGet(this, _CdrReader_eightByteAlignment, "f"));
}
stringArray(count = this.sequenceLength()) {
const output = [];
for (let i = 0; i < count; i++) {
output.push(this.string());
}
return output;
}
/**
* Seek the current read pointer a number of bytes relative to the current position. Note that
* seeking before the four-byte header is invalid
* @param relativeOffset A positive or negative number of bytes to seek
*/
seek(relativeOffset) {
const newOffset = this.offset + relativeOffset;
if (newOffset < 4 || newOffset >= __classPrivateFieldGet(this, _CdrReader_view, "f").byteLength) {
throw new Error(`seek(${relativeOffset}) failed, ${newOffset} is outside the data range`);
}
this.offset = newOffset;
}
/**
* Seek to an absolute byte position in the data. Note that seeking before the four-byte header is
* invalid
* @param offset An absolute byte offset in the range of [4-byteLength)
*/
seekTo(offset) {
if (offset < 4 || offset >= __classPrivateFieldGet(this, _CdrReader_view, "f").byteLength) {
throw new Error(`seekTo(${offset}) failed, value is outside the data range`);
}
this.offset = offset;
}
}
exports.CdrReader = CdrReader;
_CdrReader_view = new WeakMap(), _CdrReader_littleEndian = new WeakMap(), _CdrReader_hostLittleEndian = new WeakMap(), _CdrReader_eightByteAlignment = new WeakMap(), _CdrReader_isCDR2 = new WeakMap(), _CdrReader_origin = new WeakMap(), _CdrReader_instances = new WeakSet(), _CdrReader_memberHeaderV1 = function _CdrReader_memberHeaderV1() {
// 4-byte header with two 16-bit fields
__classPrivateFieldGet(this, _CdrReader_instances, "m", _CdrReader_align).call(this, 4);
const idHeader = this.uint16();
const mustUnderstandFlag = (idHeader & 0x4000) >> 14 === 1;
// indicates that the parameter has a implementation-specific interpretation
const implementationSpecificFlag = (idHeader & 0x8000) >> 15 === 1;
// Allows the specification of large member ID and/or data length values
// requires the reading in of two uint32's for ID and size
const extendedPIDFlag = (idHeader & 0x3fff) === reservedPIDs_1.EXTENDED_PID;
// Indicates the end of the parameter list structure
const sentinelPIDFlag = (idHeader & 0x3fff) === reservedPIDs_1.SENTINEL_PID;
if (sentinelPIDFlag) {
// Return that we have read the sentinel header when we expected to read an emHeader.
// This can happen for absent optional members at the end of a struct.
return { id: reservedPIDs_1.SENTINEL_PID, objectSize: 0, mustUnderstand: false, readSentinelHeader: true };
}
// Indicates that the ID should be ignored
// const ignorePIDFlag = (idHeader & 0x3fff) === 0x3f03;
const usesReservedParameterId = (idHeader & 0x3fff) > reservedPIDs_1.SENTINEL_PID;
// Not trying to support right now if we don't need to
if (usesReservedParameterId || implementationSpecificFlag) {
throw new Error(`Unsupported parameter ID header ${idHeader.toString(16)}`);
}
if (extendedPIDFlag) {
// Need to consume last part of header (is just an 8 in this case)
// Alignment could take care of this, but I want to be explicit
this.uint16();
}
const id = extendedPIDFlag ? this.uint32() : idHeader & 0x3fff;
const objectSize = extendedPIDFlag ? this.uint32() : this.uint16();
__classPrivateFieldGet(this, _CdrReader_instances, "m", _CdrReader_resetOrigin).call(this);
return { id, objectSize, mustUnderstand: mustUnderstandFlag };
}, _CdrReader_resetOrigin = function _CdrReader_resetOrigin() {
__classPrivateFieldSet(this, _CdrReader_origin, this.offset, "f");
}, _CdrReader_memberHeaderV2 = function _CdrReader_memberHeaderV2() {
const header = this.uint32();
// EMHEADER = (M_FLAG<<31) + (LC<<28) + M.id
// M is the member of a structure
// M_FLAG is the value of the Must Understand option for the member
const mustUnderstand = Math.abs((header & 0x80000000) >> 31) === 1;
// LC is the value of the Length Code for the member.
const lengthCode = ((header & 0x70000000) >> 28);
const id = header & 0x0fffffff;
const objectSize = __classPrivateFieldGet(this, _CdrReader_instances, "m", _CdrReader_emHeaderObjectSize).call(this, lengthCode);
return { mustUnderstand, id, objectSize, lengthCode };
}, _CdrReader_emHeaderObjectSize = function _CdrReader_emHeaderObjectSize(lengthCode) {
// 7.4.3.4.2 Member Header (EMHEADER), Length Code (LC) and NEXTINT
switch (lengthCode) {
case 0:
case 1:
case 2:
case 3:
return lengthCodes_1.lengthCodeToObjectSizes[lengthCode];
// LC > 3 -> NEXTINT exists after header
case 4:
case 5:
// both 4 and 5 just read the next uint32
return this.uint32();
case 6:
return 4 * this.uint32();
case 7:
return 8 * this.uint32();
default:
throw new Error(
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
`Invalid length code ${lengthCode} in EMHEADER at offset ${this.offset - 4}`);
}
}, _CdrReader_align = function _CdrReader_align(size) {
const alignment = (this.offset - __classPrivateFieldGet(this, _CdrReader_origin, "f")) % size;
if (alignment > 0) {
this.offset += size - alignment;
}
}, _CdrReader_typedArray = function _CdrReader_typedArray(TypedArrayConstructor, getter, count, alignment = TypedArrayConstructor.BYTES_PER_ELEMENT) {
if (count === 0) {
return new TypedArrayConstructor();
}
__classPrivateFieldGet(this, _CdrReader_instances, "m", _CdrReader_align).call(this, alignment);
const totalOffset = __classPrivateFieldGet(this, _CdrReader_view, "f").byteOffset + this.offset;
if (__classPrivateFieldGet(this, _CdrReader_littleEndian, "f") !== __classPrivateFieldGet(this, _CdrReader_hostLittleEndian, "f")) {
// Slowest path
return __classPrivateFieldGet(this, _CdrReader_instances, "m", _CdrReader_typedArraySlow).call(this, TypedArrayConstructor, getter, count);
}
else if (totalOffset % TypedArrayConstructor.BYTES_PER_ELEMENT === 0) {
// Fastest path
const array = new TypedArrayConstructor(__classPrivateFieldGet(this, _CdrReader_view, "f").buffer, totalOffset, count);
this.offset += TypedArrayConstructor.BYTES_PER_ELEMENT * count;
return array;
}
else {
// Slower path
return __classPrivateFieldGet(this, _CdrReader_instances, "m", _CdrReader_typedArrayUnaligned).call(this, TypedArrayConstructor, getter, count);
}
}, _CdrReader_typedArrayUnaligned = function _CdrReader_typedArrayUnaligned(TypedArrayConstructor, getter, count) {
// Benchmarks indicate for count < ~10 doing each individually is faster than copy
if (count < 10) {
return __classPrivateFieldGet(this, _CdrReader_instances, "m", _CdrReader_typedArraySlow).call(this, TypedArrayConstructor, getter, count);
}
// If the length is > 10, then doing a copy of the data to #align it is faster
// using _set_ is slightly faster than slice on the array buffer according to today's benchmarks
const byteLength = TypedArrayConstructor.BYTES_PER_ELEMENT * count;
const copy = new Uint8Array(byteLength);
copy.set(new Uint8Array(__classPrivateFieldGet(this, _CdrReader_view, "f").buffer, __classPrivateFieldGet(this, _CdrReader_view, "f").byteOffset + this.offset, byteLength));
this.offset += byteLength;
return new TypedArrayConstructor(copy.buffer, copy.byteOffset, count);
}, _CdrReader_typedArraySlow = function _CdrReader_typedArraySlow(TypedArrayConstructor, getter, count) {
const array = new TypedArrayConstructor(count);
let offset = this.offset;
for (let i = 0; i < count; i++) {
array[i] = __classPrivateFieldGet(this, _CdrReader_view, "f")[getter](offset, __classPrivateFieldGet(this, _CdrReader_littleEndian, "f"));
offset += TypedArrayConstructor.BYTES_PER_ELEMENT;
}
this.offset = offset;
return array;
};
//# sourceMappingURL=CdrReader.js.map