UNPKG

@lichtblick/cdr

Version:

Common Data Representation serialization and deserialization library

358 lines 20.4 kB
"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