- Consolidated duplicate UndoManagers to single instance - Fixed connection promise to only resolve on 'connected' status - Fixed WebSocketProvider import (WebsocketProvider) - Added proper doc.destroy() cleanup - Renamed isPresenceInitialized property to avoid conflict Co-Authored-By: Paperclip <noreply@paperclip.ing>
2390 lines
88 KiB
JavaScript
2390 lines
88 KiB
JavaScript
/* The MIT License (MIT)
|
|
*
|
|
* Copyright 2015-2018 Peter A. Bigot
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
* THE SOFTWARE.
|
|
*/
|
|
/**
|
|
* Support for translating between Uint8Array instances and JavaScript
|
|
* native types.
|
|
*
|
|
* {@link module:Layout~Layout|Layout} is the basis of a class
|
|
* hierarchy that associates property names with sequences of encoded
|
|
* bytes.
|
|
*
|
|
* Layouts are supported for these scalar (numeric) types:
|
|
* * {@link module:Layout~UInt|Unsigned integers in little-endian
|
|
* format} with {@link module:Layout.u8|8-bit}, {@link
|
|
* module:Layout.u16|16-bit}, {@link module:Layout.u24|24-bit},
|
|
* {@link module:Layout.u32|32-bit}, {@link
|
|
* module:Layout.u40|40-bit}, and {@link module:Layout.u48|48-bit}
|
|
* representation ranges;
|
|
* * {@link module:Layout~UIntBE|Unsigned integers in big-endian
|
|
* format} with {@link module:Layout.u16be|16-bit}, {@link
|
|
* module:Layout.u24be|24-bit}, {@link module:Layout.u32be|32-bit},
|
|
* {@link module:Layout.u40be|40-bit}, and {@link
|
|
* module:Layout.u48be|48-bit} representation ranges;
|
|
* * {@link module:Layout~Int|Signed integers in little-endian
|
|
* format} with {@link module:Layout.s8|8-bit}, {@link
|
|
* module:Layout.s16|16-bit}, {@link module:Layout.s24|24-bit},
|
|
* {@link module:Layout.s32|32-bit}, {@link
|
|
* module:Layout.s40|40-bit}, and {@link module:Layout.s48|48-bit}
|
|
* representation ranges;
|
|
* * {@link module:Layout~IntBE|Signed integers in big-endian format}
|
|
* with {@link module:Layout.s16be|16-bit}, {@link
|
|
* module:Layout.s24be|24-bit}, {@link module:Layout.s32be|32-bit},
|
|
* {@link module:Layout.s40be|40-bit}, and {@link
|
|
* module:Layout.s48be|48-bit} representation ranges;
|
|
* * 64-bit integral values that decode to an exact (if magnitude is
|
|
* less than 2^53) or nearby integral Number in {@link
|
|
* module:Layout.nu64|unsigned little-endian}, {@link
|
|
* module:Layout.nu64be|unsigned big-endian}, {@link
|
|
* module:Layout.ns64|signed little-endian}, and {@link
|
|
* module:Layout.ns64be|unsigned big-endian} encodings;
|
|
* * 32-bit floating point values with {@link
|
|
* module:Layout.f32|little-endian} and {@link
|
|
* module:Layout.f32be|big-endian} representations;
|
|
* * 64-bit floating point values with {@link
|
|
* module:Layout.f64|little-endian} and {@link
|
|
* module:Layout.f64be|big-endian} representations;
|
|
* * {@link module:Layout.const|Constants} that take no space in the
|
|
* encoded expression.
|
|
*
|
|
* and for these aggregate types:
|
|
* * {@link module:Layout.seq|Sequence}s of instances of a {@link
|
|
* module:Layout~Layout|Layout}, with JavaScript representation as
|
|
* an Array and constant or data-dependent {@link
|
|
* module:Layout~Sequence#count|length};
|
|
* * {@link module:Layout.struct|Structure}s that aggregate a
|
|
* heterogeneous sequence of {@link module:Layout~Layout|Layout}
|
|
* instances, with JavaScript representation as an Object;
|
|
* * {@link module:Layout.union|Union}s that support multiple {@link
|
|
* module:Layout~VariantLayout|variant layouts} over a fixed
|
|
* (padded) or variable (not padded) span of bytes, using an
|
|
* unsigned integer at the start of the data or a separate {@link
|
|
* module:Layout.unionLayoutDiscriminator|layout element} to
|
|
* determine which layout to use when interpreting the buffer
|
|
* contents;
|
|
* * {@link module:Layout.bits|BitStructure}s that contain a sequence
|
|
* of individual {@link
|
|
* module:Layout~BitStructure#addField|BitField}s packed into an 8,
|
|
* 16, 24, or 32-bit unsigned integer starting at the least- or
|
|
* most-significant bit;
|
|
* * {@link module:Layout.cstr|C strings} of varying length;
|
|
* * {@link module:Layout.blob|Blobs} of fixed- or variable-{@link
|
|
* module:Layout~Blob#length|length} raw data.
|
|
*
|
|
* All {@link module:Layout~Layout|Layout} instances are immutable
|
|
* after construction, to prevent internal state from becoming
|
|
* inconsistent.
|
|
*
|
|
* @local Layout
|
|
* @local ExternalLayout
|
|
* @local GreedyCount
|
|
* @local OffsetLayout
|
|
* @local UInt
|
|
* @local UIntBE
|
|
* @local Int
|
|
* @local IntBE
|
|
* @local NearUInt64
|
|
* @local NearUInt64BE
|
|
* @local NearInt64
|
|
* @local NearInt64BE
|
|
* @local Float
|
|
* @local FloatBE
|
|
* @local Double
|
|
* @local DoubleBE
|
|
* @local Sequence
|
|
* @local Structure
|
|
* @local UnionDiscriminator
|
|
* @local UnionLayoutDiscriminator
|
|
* @local Union
|
|
* @local VariantLayout
|
|
* @local BitStructure
|
|
* @local BitField
|
|
* @local Boolean
|
|
* @local Blob
|
|
* @local CString
|
|
* @local Constant
|
|
* @local bindConstructorLayout
|
|
* @module Layout
|
|
* @license MIT
|
|
* @author Peter A. Bigot
|
|
* @see {@link https://github.com/pabigot/buffer-layout|buffer-layout on GitHub}
|
|
*/
|
|
'use strict';
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.s16 = exports.s8 = exports.nu64be = exports.u48be = exports.u40be = exports.u32be = exports.u24be = exports.u16be = exports.nu64 = exports.u48 = exports.u40 = exports.u32 = exports.u24 = exports.u16 = exports.u8 = exports.offset = exports.greedy = exports.Constant = exports.UTF8 = exports.CString = exports.Blob = exports.Boolean = exports.BitField = exports.BitStructure = exports.VariantLayout = exports.Union = exports.UnionLayoutDiscriminator = exports.UnionDiscriminator = exports.Structure = exports.Sequence = exports.DoubleBE = exports.Double = exports.FloatBE = exports.Float = exports.NearInt64BE = exports.NearInt64 = exports.NearUInt64BE = exports.NearUInt64 = exports.IntBE = exports.Int = exports.UIntBE = exports.UInt = exports.OffsetLayout = exports.GreedyCount = exports.ExternalLayout = exports.bindConstructorLayout = exports.nameWithProperty = exports.Layout = exports.uint8ArrayToBuffer = exports.checkUint8Array = void 0;
|
|
exports.constant = exports.utf8 = exports.cstr = exports.blob = exports.unionLayoutDiscriminator = exports.union = exports.seq = exports.bits = exports.struct = exports.f64be = exports.f64 = exports.f32be = exports.f32 = exports.ns64be = exports.s48be = exports.s40be = exports.s32be = exports.s24be = exports.s16be = exports.ns64 = exports.s48 = exports.s40 = exports.s32 = exports.s24 = void 0;
|
|
const buffer_1 = require("buffer");
|
|
/* Check if a value is a Uint8Array.
|
|
*
|
|
* @ignore */
|
|
function checkUint8Array(b) {
|
|
if (!(b instanceof Uint8Array)) {
|
|
throw new TypeError('b must be a Uint8Array');
|
|
}
|
|
}
|
|
exports.checkUint8Array = checkUint8Array;
|
|
/* Create a Buffer instance from a Uint8Array.
|
|
*
|
|
* @ignore */
|
|
function uint8ArrayToBuffer(b) {
|
|
checkUint8Array(b);
|
|
return buffer_1.Buffer.from(b.buffer, b.byteOffset, b.length);
|
|
}
|
|
exports.uint8ArrayToBuffer = uint8ArrayToBuffer;
|
|
/**
|
|
* Base class for layout objects.
|
|
*
|
|
* **NOTE** This is an abstract base class; you can create instances
|
|
* if it amuses you, but they won't support the {@link
|
|
* Layout#encode|encode} or {@link Layout#decode|decode} functions.
|
|
*
|
|
* @param {Number} span - Initializer for {@link Layout#span|span}. The
|
|
* parameter must be an integer; a negative value signifies that the
|
|
* span is {@link Layout#getSpan|value-specific}.
|
|
*
|
|
* @param {string} [property] - Initializer for {@link
|
|
* Layout#property|property}.
|
|
*
|
|
* @abstract
|
|
*/
|
|
class Layout {
|
|
constructor(span, property) {
|
|
if (!Number.isInteger(span)) {
|
|
throw new TypeError('span must be an integer');
|
|
}
|
|
/** The span of the layout in bytes.
|
|
*
|
|
* Positive values are generally expected.
|
|
*
|
|
* Zero will only appear in {@link Constant}s and in {@link
|
|
* Sequence}s where the {@link Sequence#count|count} is zero.
|
|
*
|
|
* A negative value indicates that the span is value-specific, and
|
|
* must be obtained using {@link Layout#getSpan|getSpan}. */
|
|
this.span = span;
|
|
/** The property name used when this layout is represented in an
|
|
* Object.
|
|
*
|
|
* Used only for layouts that {@link Layout#decode|decode} to Object
|
|
* instances. If left undefined the span of the unnamed layout will
|
|
* be treated as padding: it will not be mutated by {@link
|
|
* Layout#encode|encode} nor represented as a property in the
|
|
* decoded Object. */
|
|
this.property = property;
|
|
}
|
|
/** Function to create an Object into which decoded properties will
|
|
* be written.
|
|
*
|
|
* Used only for layouts that {@link Layout#decode|decode} to Object
|
|
* instances, which means:
|
|
* * {@link Structure}
|
|
* * {@link Union}
|
|
* * {@link VariantLayout}
|
|
* * {@link BitStructure}
|
|
*
|
|
* If left undefined the JavaScript representation of these layouts
|
|
* will be Object instances.
|
|
*
|
|
* See {@link bindConstructorLayout}.
|
|
*/
|
|
makeDestinationObject() {
|
|
return {};
|
|
}
|
|
/**
|
|
* Calculate the span of a specific instance of a layout.
|
|
*
|
|
* @param {Uint8Array} b - the buffer that contains an encoded instance.
|
|
*
|
|
* @param {Number} [offset] - the offset at which the encoded instance
|
|
* starts. If absent a zero offset is inferred.
|
|
*
|
|
* @return {Number} - the number of bytes covered by the layout
|
|
* instance. If this method is not overridden in a subclass the
|
|
* definition-time constant {@link Layout#span|span} will be
|
|
* returned.
|
|
*
|
|
* @throws {RangeError} - if the length of the value cannot be
|
|
* determined.
|
|
*/
|
|
getSpan(b, offset) {
|
|
if (0 > this.span) {
|
|
throw new RangeError('indeterminate span');
|
|
}
|
|
return this.span;
|
|
}
|
|
/**
|
|
* Replicate the layout using a new property.
|
|
*
|
|
* This function must be used to get a structurally-equivalent layout
|
|
* with a different name since all {@link Layout} instances are
|
|
* immutable.
|
|
*
|
|
* **NOTE** This is a shallow copy. All fields except {@link
|
|
* Layout#property|property} are strictly equal to the origin layout.
|
|
*
|
|
* @param {String} property - the value for {@link
|
|
* Layout#property|property} in the replica.
|
|
*
|
|
* @returns {Layout} - the copy with {@link Layout#property|property}
|
|
* set to `property`.
|
|
*/
|
|
replicate(property) {
|
|
const rv = Object.create(this.constructor.prototype);
|
|
Object.assign(rv, this);
|
|
rv.property = property;
|
|
return rv;
|
|
}
|
|
/**
|
|
* Create an object from layout properties and an array of values.
|
|
*
|
|
* **NOTE** This function returns `undefined` if invoked on a layout
|
|
* that does not return its value as an Object. Objects are
|
|
* returned for things that are a {@link Structure}, which includes
|
|
* {@link VariantLayout|variant layouts} if they are structures, and
|
|
* excludes {@link Union}s. If you want this feature for a union
|
|
* you must use {@link Union.getVariant|getVariant} to select the
|
|
* desired layout.
|
|
*
|
|
* @param {Array} values - an array of values that correspond to the
|
|
* default order for properties. As with {@link Layout#decode|decode}
|
|
* layout elements that have no property name are skipped when
|
|
* iterating over the array values. Only the top-level properties are
|
|
* assigned; arguments are not assigned to properties of contained
|
|
* layouts. Any unused values are ignored.
|
|
*
|
|
* @return {(Object|undefined)}
|
|
*/
|
|
fromArray(values) {
|
|
return undefined;
|
|
}
|
|
}
|
|
exports.Layout = Layout;
|
|
/* Provide text that carries a name (such as for a function that will
|
|
* be throwing an error) annotated with the property of a given layout
|
|
* (such as one for which the value was unacceptable).
|
|
*
|
|
* @ignore */
|
|
function nameWithProperty(name, lo) {
|
|
if (lo.property) {
|
|
return name + '[' + lo.property + ']';
|
|
}
|
|
return name;
|
|
}
|
|
exports.nameWithProperty = nameWithProperty;
|
|
/**
|
|
* Augment a class so that instances can be encoded/decoded using a
|
|
* given layout.
|
|
*
|
|
* Calling this function couples `Class` with `layout` in several ways:
|
|
*
|
|
* * `Class.layout_` becomes a static member property equal to `layout`;
|
|
* * `layout.boundConstructor_` becomes a static member property equal
|
|
* to `Class`;
|
|
* * The {@link Layout#makeDestinationObject|makeDestinationObject()}
|
|
* property of `layout` is set to a function that returns a `new
|
|
* Class()`;
|
|
* * `Class.decode(b, offset)` becomes a static member function that
|
|
* delegates to {@link Layout#decode|layout.decode}. The
|
|
* synthesized function may be captured and extended.
|
|
* * `Class.prototype.encode(b, offset)` provides an instance member
|
|
* function that delegates to {@link Layout#encode|layout.encode}
|
|
* with `src` set to `this`. The synthesized function may be
|
|
* captured and extended, but when the extension is invoked `this`
|
|
* must be explicitly bound to the instance.
|
|
*
|
|
* @param {class} Class - a JavaScript class with a nullary
|
|
* constructor.
|
|
*
|
|
* @param {Layout} layout - the {@link Layout} instance used to encode
|
|
* instances of `Class`.
|
|
*/
|
|
// `Class` must be a constructor Function, but the assignment of a `layout_` property to it makes it difficult to type
|
|
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
|
function bindConstructorLayout(Class, layout) {
|
|
if ('function' !== typeof Class) {
|
|
throw new TypeError('Class must be constructor');
|
|
}
|
|
if (Object.prototype.hasOwnProperty.call(Class, 'layout_')) {
|
|
throw new Error('Class is already bound to a layout');
|
|
}
|
|
if (!(layout && (layout instanceof Layout))) {
|
|
throw new TypeError('layout must be a Layout');
|
|
}
|
|
if (Object.prototype.hasOwnProperty.call(layout, 'boundConstructor_')) {
|
|
throw new Error('layout is already bound to a constructor');
|
|
}
|
|
Class.layout_ = layout;
|
|
layout.boundConstructor_ = Class;
|
|
layout.makeDestinationObject = (() => new Class());
|
|
Object.defineProperty(Class.prototype, 'encode', {
|
|
value(b, offset) {
|
|
return layout.encode(this, b, offset);
|
|
},
|
|
writable: true,
|
|
});
|
|
Object.defineProperty(Class, 'decode', {
|
|
value(b, offset) {
|
|
return layout.decode(b, offset);
|
|
},
|
|
writable: true,
|
|
});
|
|
}
|
|
exports.bindConstructorLayout = bindConstructorLayout;
|
|
/**
|
|
* An object that behaves like a layout but does not consume space
|
|
* within its containing layout.
|
|
*
|
|
* This is primarily used to obtain metadata about a member, such as a
|
|
* {@link OffsetLayout} that can provide data about a {@link
|
|
* Layout#getSpan|value-specific span}.
|
|
*
|
|
* **NOTE** This is an abstract base class; you can create instances
|
|
* if it amuses you, but they won't support {@link
|
|
* ExternalLayout#isCount|isCount} or other {@link Layout} functions.
|
|
*
|
|
* @param {Number} span - initializer for {@link Layout#span|span}.
|
|
* The parameter can range from 1 through 6.
|
|
*
|
|
* @param {string} [property] - initializer for {@link
|
|
* Layout#property|property}.
|
|
*
|
|
* @abstract
|
|
* @augments {Layout}
|
|
*/
|
|
class ExternalLayout extends Layout {
|
|
/**
|
|
* Return `true` iff the external layout decodes to an unsigned
|
|
* integer layout.
|
|
*
|
|
* In that case it can be used as the source of {@link
|
|
* Sequence#count|Sequence counts}, {@link Blob#length|Blob lengths},
|
|
* or as {@link UnionLayoutDiscriminator#layout|external union
|
|
* discriminators}.
|
|
*
|
|
* @abstract
|
|
*/
|
|
isCount() {
|
|
throw new Error('ExternalLayout is abstract');
|
|
}
|
|
}
|
|
exports.ExternalLayout = ExternalLayout;
|
|
/**
|
|
* An {@link ExternalLayout} that determines its {@link
|
|
* Layout#decode|value} based on offset into and length of the buffer
|
|
* on which it is invoked.
|
|
*
|
|
* *Factory*: {@link module:Layout.greedy|greedy}
|
|
*
|
|
* @param {Number} [elementSpan] - initializer for {@link
|
|
* GreedyCount#elementSpan|elementSpan}.
|
|
*
|
|
* @param {string} [property] - initializer for {@link
|
|
* Layout#property|property}.
|
|
*
|
|
* @augments {ExternalLayout}
|
|
*/
|
|
class GreedyCount extends ExternalLayout {
|
|
constructor(elementSpan = 1, property) {
|
|
if ((!Number.isInteger(elementSpan)) || (0 >= elementSpan)) {
|
|
throw new TypeError('elementSpan must be a (positive) integer');
|
|
}
|
|
super(-1, property);
|
|
/** The layout for individual elements of the sequence. The value
|
|
* must be a positive integer. If not provided, the value will be
|
|
* 1. */
|
|
this.elementSpan = elementSpan;
|
|
}
|
|
/** @override */
|
|
isCount() {
|
|
return true;
|
|
}
|
|
/** @override */
|
|
decode(b, offset = 0) {
|
|
checkUint8Array(b);
|
|
const rem = b.length - offset;
|
|
return Math.floor(rem / this.elementSpan);
|
|
}
|
|
/** @override */
|
|
encode(src, b, offset) {
|
|
return 0;
|
|
}
|
|
}
|
|
exports.GreedyCount = GreedyCount;
|
|
/**
|
|
* An {@link ExternalLayout} that supports accessing a {@link Layout}
|
|
* at a fixed offset from the start of another Layout. The offset may
|
|
* be before, within, or after the base layout.
|
|
*
|
|
* *Factory*: {@link module:Layout.offset|offset}
|
|
*
|
|
* @param {Layout} layout - initializer for {@link
|
|
* OffsetLayout#layout|layout}, modulo `property`.
|
|
*
|
|
* @param {Number} [offset] - Initializes {@link
|
|
* OffsetLayout#offset|offset}. Defaults to zero.
|
|
*
|
|
* @param {string} [property] - Optional new property name for a
|
|
* {@link Layout#replicate| replica} of `layout` to be used as {@link
|
|
* OffsetLayout#layout|layout}. If not provided the `layout` is used
|
|
* unchanged.
|
|
*
|
|
* @augments {Layout}
|
|
*/
|
|
class OffsetLayout extends ExternalLayout {
|
|
constructor(layout, offset = 0, property) {
|
|
if (!(layout instanceof Layout)) {
|
|
throw new TypeError('layout must be a Layout');
|
|
}
|
|
if (!Number.isInteger(offset)) {
|
|
throw new TypeError('offset must be integer or undefined');
|
|
}
|
|
super(layout.span, property || layout.property);
|
|
/** The subordinated layout. */
|
|
this.layout = layout;
|
|
/** The location of {@link OffsetLayout#layout} relative to the
|
|
* start of another layout.
|
|
*
|
|
* The value may be positive or negative, but an error will thrown
|
|
* if at the point of use it goes outside the span of the Uint8Array
|
|
* being accessed. */
|
|
this.offset = offset;
|
|
}
|
|
/** @override */
|
|
isCount() {
|
|
return ((this.layout instanceof UInt)
|
|
|| (this.layout instanceof UIntBE));
|
|
}
|
|
/** @override */
|
|
decode(b, offset = 0) {
|
|
return this.layout.decode(b, offset + this.offset);
|
|
}
|
|
/** @override */
|
|
encode(src, b, offset = 0) {
|
|
return this.layout.encode(src, b, offset + this.offset);
|
|
}
|
|
}
|
|
exports.OffsetLayout = OffsetLayout;
|
|
/**
|
|
* Represent an unsigned integer in little-endian format.
|
|
*
|
|
* *Factory*: {@link module:Layout.u8|u8}, {@link
|
|
* module:Layout.u16|u16}, {@link module:Layout.u24|u24}, {@link
|
|
* module:Layout.u32|u32}, {@link module:Layout.u40|u40}, {@link
|
|
* module:Layout.u48|u48}
|
|
*
|
|
* @param {Number} span - initializer for {@link Layout#span|span}.
|
|
* The parameter can range from 1 through 6.
|
|
*
|
|
* @param {string} [property] - initializer for {@link
|
|
* Layout#property|property}.
|
|
*
|
|
* @augments {Layout}
|
|
*/
|
|
class UInt extends Layout {
|
|
constructor(span, property) {
|
|
super(span, property);
|
|
if (6 < this.span) {
|
|
throw new RangeError('span must not exceed 6 bytes');
|
|
}
|
|
}
|
|
/** @override */
|
|
decode(b, offset = 0) {
|
|
return uint8ArrayToBuffer(b).readUIntLE(offset, this.span);
|
|
}
|
|
/** @override */
|
|
encode(src, b, offset = 0) {
|
|
uint8ArrayToBuffer(b).writeUIntLE(src, offset, this.span);
|
|
return this.span;
|
|
}
|
|
}
|
|
exports.UInt = UInt;
|
|
/**
|
|
* Represent an unsigned integer in big-endian format.
|
|
*
|
|
* *Factory*: {@link module:Layout.u8be|u8be}, {@link
|
|
* module:Layout.u16be|u16be}, {@link module:Layout.u24be|u24be},
|
|
* {@link module:Layout.u32be|u32be}, {@link
|
|
* module:Layout.u40be|u40be}, {@link module:Layout.u48be|u48be}
|
|
*
|
|
* @param {Number} span - initializer for {@link Layout#span|span}.
|
|
* The parameter can range from 1 through 6.
|
|
*
|
|
* @param {string} [property] - initializer for {@link
|
|
* Layout#property|property}.
|
|
*
|
|
* @augments {Layout}
|
|
*/
|
|
class UIntBE extends Layout {
|
|
constructor(span, property) {
|
|
super(span, property);
|
|
if (6 < this.span) {
|
|
throw new RangeError('span must not exceed 6 bytes');
|
|
}
|
|
}
|
|
/** @override */
|
|
decode(b, offset = 0) {
|
|
return uint8ArrayToBuffer(b).readUIntBE(offset, this.span);
|
|
}
|
|
/** @override */
|
|
encode(src, b, offset = 0) {
|
|
uint8ArrayToBuffer(b).writeUIntBE(src, offset, this.span);
|
|
return this.span;
|
|
}
|
|
}
|
|
exports.UIntBE = UIntBE;
|
|
/**
|
|
* Represent a signed integer in little-endian format.
|
|
*
|
|
* *Factory*: {@link module:Layout.s8|s8}, {@link
|
|
* module:Layout.s16|s16}, {@link module:Layout.s24|s24}, {@link
|
|
* module:Layout.s32|s32}, {@link module:Layout.s40|s40}, {@link
|
|
* module:Layout.s48|s48}
|
|
*
|
|
* @param {Number} span - initializer for {@link Layout#span|span}.
|
|
* The parameter can range from 1 through 6.
|
|
*
|
|
* @param {string} [property] - initializer for {@link
|
|
* Layout#property|property}.
|
|
*
|
|
* @augments {Layout}
|
|
*/
|
|
class Int extends Layout {
|
|
constructor(span, property) {
|
|
super(span, property);
|
|
if (6 < this.span) {
|
|
throw new RangeError('span must not exceed 6 bytes');
|
|
}
|
|
}
|
|
/** @override */
|
|
decode(b, offset = 0) {
|
|
return uint8ArrayToBuffer(b).readIntLE(offset, this.span);
|
|
}
|
|
/** @override */
|
|
encode(src, b, offset = 0) {
|
|
uint8ArrayToBuffer(b).writeIntLE(src, offset, this.span);
|
|
return this.span;
|
|
}
|
|
}
|
|
exports.Int = Int;
|
|
/**
|
|
* Represent a signed integer in big-endian format.
|
|
*
|
|
* *Factory*: {@link module:Layout.s8be|s8be}, {@link
|
|
* module:Layout.s16be|s16be}, {@link module:Layout.s24be|s24be},
|
|
* {@link module:Layout.s32be|s32be}, {@link
|
|
* module:Layout.s40be|s40be}, {@link module:Layout.s48be|s48be}
|
|
*
|
|
* @param {Number} span - initializer for {@link Layout#span|span}.
|
|
* The parameter can range from 1 through 6.
|
|
*
|
|
* @param {string} [property] - initializer for {@link
|
|
* Layout#property|property}.
|
|
*
|
|
* @augments {Layout}
|
|
*/
|
|
class IntBE extends Layout {
|
|
constructor(span, property) {
|
|
super(span, property);
|
|
if (6 < this.span) {
|
|
throw new RangeError('span must not exceed 6 bytes');
|
|
}
|
|
}
|
|
/** @override */
|
|
decode(b, offset = 0) {
|
|
return uint8ArrayToBuffer(b).readIntBE(offset, this.span);
|
|
}
|
|
/** @override */
|
|
encode(src, b, offset = 0) {
|
|
uint8ArrayToBuffer(b).writeIntBE(src, offset, this.span);
|
|
return this.span;
|
|
}
|
|
}
|
|
exports.IntBE = IntBE;
|
|
const V2E32 = Math.pow(2, 32);
|
|
/* True modulus high and low 32-bit words, where low word is always
|
|
* non-negative. */
|
|
function divmodInt64(src) {
|
|
const hi32 = Math.floor(src / V2E32);
|
|
const lo32 = src - (hi32 * V2E32);
|
|
return { hi32, lo32 };
|
|
}
|
|
/* Reconstruct Number from quotient and non-negative remainder */
|
|
function roundedInt64(hi32, lo32) {
|
|
return hi32 * V2E32 + lo32;
|
|
}
|
|
/**
|
|
* Represent an unsigned 64-bit integer in little-endian format when
|
|
* encoded and as a near integral JavaScript Number when decoded.
|
|
*
|
|
* *Factory*: {@link module:Layout.nu64|nu64}
|
|
*
|
|
* **NOTE** Values with magnitude greater than 2^52 may not decode to
|
|
* the exact value of the encoded representation.
|
|
*
|
|
* @augments {Layout}
|
|
*/
|
|
class NearUInt64 extends Layout {
|
|
constructor(property) {
|
|
super(8, property);
|
|
}
|
|
/** @override */
|
|
decode(b, offset = 0) {
|
|
const buffer = uint8ArrayToBuffer(b);
|
|
const lo32 = buffer.readUInt32LE(offset);
|
|
const hi32 = buffer.readUInt32LE(offset + 4);
|
|
return roundedInt64(hi32, lo32);
|
|
}
|
|
/** @override */
|
|
encode(src, b, offset = 0) {
|
|
const split = divmodInt64(src);
|
|
const buffer = uint8ArrayToBuffer(b);
|
|
buffer.writeUInt32LE(split.lo32, offset);
|
|
buffer.writeUInt32LE(split.hi32, offset + 4);
|
|
return 8;
|
|
}
|
|
}
|
|
exports.NearUInt64 = NearUInt64;
|
|
/**
|
|
* Represent an unsigned 64-bit integer in big-endian format when
|
|
* encoded and as a near integral JavaScript Number when decoded.
|
|
*
|
|
* *Factory*: {@link module:Layout.nu64be|nu64be}
|
|
*
|
|
* **NOTE** Values with magnitude greater than 2^52 may not decode to
|
|
* the exact value of the encoded representation.
|
|
*
|
|
* @augments {Layout}
|
|
*/
|
|
class NearUInt64BE extends Layout {
|
|
constructor(property) {
|
|
super(8, property);
|
|
}
|
|
/** @override */
|
|
decode(b, offset = 0) {
|
|
const buffer = uint8ArrayToBuffer(b);
|
|
const hi32 = buffer.readUInt32BE(offset);
|
|
const lo32 = buffer.readUInt32BE(offset + 4);
|
|
return roundedInt64(hi32, lo32);
|
|
}
|
|
/** @override */
|
|
encode(src, b, offset = 0) {
|
|
const split = divmodInt64(src);
|
|
const buffer = uint8ArrayToBuffer(b);
|
|
buffer.writeUInt32BE(split.hi32, offset);
|
|
buffer.writeUInt32BE(split.lo32, offset + 4);
|
|
return 8;
|
|
}
|
|
}
|
|
exports.NearUInt64BE = NearUInt64BE;
|
|
/**
|
|
* Represent a signed 64-bit integer in little-endian format when
|
|
* encoded and as a near integral JavaScript Number when decoded.
|
|
*
|
|
* *Factory*: {@link module:Layout.ns64|ns64}
|
|
*
|
|
* **NOTE** Values with magnitude greater than 2^52 may not decode to
|
|
* the exact value of the encoded representation.
|
|
*
|
|
* @augments {Layout}
|
|
*/
|
|
class NearInt64 extends Layout {
|
|
constructor(property) {
|
|
super(8, property);
|
|
}
|
|
/** @override */
|
|
decode(b, offset = 0) {
|
|
const buffer = uint8ArrayToBuffer(b);
|
|
const lo32 = buffer.readUInt32LE(offset);
|
|
const hi32 = buffer.readInt32LE(offset + 4);
|
|
return roundedInt64(hi32, lo32);
|
|
}
|
|
/** @override */
|
|
encode(src, b, offset = 0) {
|
|
const split = divmodInt64(src);
|
|
const buffer = uint8ArrayToBuffer(b);
|
|
buffer.writeUInt32LE(split.lo32, offset);
|
|
buffer.writeInt32LE(split.hi32, offset + 4);
|
|
return 8;
|
|
}
|
|
}
|
|
exports.NearInt64 = NearInt64;
|
|
/**
|
|
* Represent a signed 64-bit integer in big-endian format when
|
|
* encoded and as a near integral JavaScript Number when decoded.
|
|
*
|
|
* *Factory*: {@link module:Layout.ns64be|ns64be}
|
|
*
|
|
* **NOTE** Values with magnitude greater than 2^52 may not decode to
|
|
* the exact value of the encoded representation.
|
|
*
|
|
* @augments {Layout}
|
|
*/
|
|
class NearInt64BE extends Layout {
|
|
constructor(property) {
|
|
super(8, property);
|
|
}
|
|
/** @override */
|
|
decode(b, offset = 0) {
|
|
const buffer = uint8ArrayToBuffer(b);
|
|
const hi32 = buffer.readInt32BE(offset);
|
|
const lo32 = buffer.readUInt32BE(offset + 4);
|
|
return roundedInt64(hi32, lo32);
|
|
}
|
|
/** @override */
|
|
encode(src, b, offset = 0) {
|
|
const split = divmodInt64(src);
|
|
const buffer = uint8ArrayToBuffer(b);
|
|
buffer.writeInt32BE(split.hi32, offset);
|
|
buffer.writeUInt32BE(split.lo32, offset + 4);
|
|
return 8;
|
|
}
|
|
}
|
|
exports.NearInt64BE = NearInt64BE;
|
|
/**
|
|
* Represent a 32-bit floating point number in little-endian format.
|
|
*
|
|
* *Factory*: {@link module:Layout.f32|f32}
|
|
*
|
|
* @param {string} [property] - initializer for {@link
|
|
* Layout#property|property}.
|
|
*
|
|
* @augments {Layout}
|
|
*/
|
|
class Float extends Layout {
|
|
constructor(property) {
|
|
super(4, property);
|
|
}
|
|
/** @override */
|
|
decode(b, offset = 0) {
|
|
return uint8ArrayToBuffer(b).readFloatLE(offset);
|
|
}
|
|
/** @override */
|
|
encode(src, b, offset = 0) {
|
|
uint8ArrayToBuffer(b).writeFloatLE(src, offset);
|
|
return 4;
|
|
}
|
|
}
|
|
exports.Float = Float;
|
|
/**
|
|
* Represent a 32-bit floating point number in big-endian format.
|
|
*
|
|
* *Factory*: {@link module:Layout.f32be|f32be}
|
|
*
|
|
* @param {string} [property] - initializer for {@link
|
|
* Layout#property|property}.
|
|
*
|
|
* @augments {Layout}
|
|
*/
|
|
class FloatBE extends Layout {
|
|
constructor(property) {
|
|
super(4, property);
|
|
}
|
|
/** @override */
|
|
decode(b, offset = 0) {
|
|
return uint8ArrayToBuffer(b).readFloatBE(offset);
|
|
}
|
|
/** @override */
|
|
encode(src, b, offset = 0) {
|
|
uint8ArrayToBuffer(b).writeFloatBE(src, offset);
|
|
return 4;
|
|
}
|
|
}
|
|
exports.FloatBE = FloatBE;
|
|
/**
|
|
* Represent a 64-bit floating point number in little-endian format.
|
|
*
|
|
* *Factory*: {@link module:Layout.f64|f64}
|
|
*
|
|
* @param {string} [property] - initializer for {@link
|
|
* Layout#property|property}.
|
|
*
|
|
* @augments {Layout}
|
|
*/
|
|
class Double extends Layout {
|
|
constructor(property) {
|
|
super(8, property);
|
|
}
|
|
/** @override */
|
|
decode(b, offset = 0) {
|
|
return uint8ArrayToBuffer(b).readDoubleLE(offset);
|
|
}
|
|
/** @override */
|
|
encode(src, b, offset = 0) {
|
|
uint8ArrayToBuffer(b).writeDoubleLE(src, offset);
|
|
return 8;
|
|
}
|
|
}
|
|
exports.Double = Double;
|
|
/**
|
|
* Represent a 64-bit floating point number in big-endian format.
|
|
*
|
|
* *Factory*: {@link module:Layout.f64be|f64be}
|
|
*
|
|
* @param {string} [property] - initializer for {@link
|
|
* Layout#property|property}.
|
|
*
|
|
* @augments {Layout}
|
|
*/
|
|
class DoubleBE extends Layout {
|
|
constructor(property) {
|
|
super(8, property);
|
|
}
|
|
/** @override */
|
|
decode(b, offset = 0) {
|
|
return uint8ArrayToBuffer(b).readDoubleBE(offset);
|
|
}
|
|
/** @override */
|
|
encode(src, b, offset = 0) {
|
|
uint8ArrayToBuffer(b).writeDoubleBE(src, offset);
|
|
return 8;
|
|
}
|
|
}
|
|
exports.DoubleBE = DoubleBE;
|
|
/**
|
|
* Represent a contiguous sequence of a specific layout as an Array.
|
|
*
|
|
* *Factory*: {@link module:Layout.seq|seq}
|
|
*
|
|
* @param {Layout} elementLayout - initializer for {@link
|
|
* Sequence#elementLayout|elementLayout}.
|
|
*
|
|
* @param {(Number|ExternalLayout)} count - initializer for {@link
|
|
* Sequence#count|count}. The parameter must be either a positive
|
|
* integer or an instance of {@link ExternalLayout}.
|
|
*
|
|
* @param {string} [property] - initializer for {@link
|
|
* Layout#property|property}.
|
|
*
|
|
* @augments {Layout}
|
|
*/
|
|
class Sequence extends Layout {
|
|
constructor(elementLayout, count, property) {
|
|
if (!(elementLayout instanceof Layout)) {
|
|
throw new TypeError('elementLayout must be a Layout');
|
|
}
|
|
if (!(((count instanceof ExternalLayout) && count.isCount())
|
|
|| (Number.isInteger(count) && (0 <= count)))) {
|
|
throw new TypeError('count must be non-negative integer '
|
|
+ 'or an unsigned integer ExternalLayout');
|
|
}
|
|
let span = -1;
|
|
if ((!(count instanceof ExternalLayout))
|
|
&& (0 < elementLayout.span)) {
|
|
span = count * elementLayout.span;
|
|
}
|
|
super(span, property);
|
|
/** The layout for individual elements of the sequence. */
|
|
this.elementLayout = elementLayout;
|
|
/** The number of elements in the sequence.
|
|
*
|
|
* This will be either a non-negative integer or an instance of
|
|
* {@link ExternalLayout} for which {@link
|
|
* ExternalLayout#isCount|isCount()} is `true`. */
|
|
this.count = count;
|
|
}
|
|
/** @override */
|
|
getSpan(b, offset = 0) {
|
|
if (0 <= this.span) {
|
|
return this.span;
|
|
}
|
|
let span = 0;
|
|
let count = this.count;
|
|
if (count instanceof ExternalLayout) {
|
|
count = count.decode(b, offset);
|
|
}
|
|
if (0 < this.elementLayout.span) {
|
|
span = count * this.elementLayout.span;
|
|
}
|
|
else {
|
|
let idx = 0;
|
|
while (idx < count) {
|
|
span += this.elementLayout.getSpan(b, offset + span);
|
|
++idx;
|
|
}
|
|
}
|
|
return span;
|
|
}
|
|
/** @override */
|
|
decode(b, offset = 0) {
|
|
const rv = [];
|
|
let i = 0;
|
|
let count = this.count;
|
|
if (count instanceof ExternalLayout) {
|
|
count = count.decode(b, offset);
|
|
}
|
|
while (i < count) {
|
|
rv.push(this.elementLayout.decode(b, offset));
|
|
offset += this.elementLayout.getSpan(b, offset);
|
|
i += 1;
|
|
}
|
|
return rv;
|
|
}
|
|
/** Implement {@link Layout#encode|encode} for {@link Sequence}.
|
|
*
|
|
* **NOTE** If `src` is shorter than {@link Sequence#count|count} then
|
|
* the unused space in the buffer is left unchanged. If `src` is
|
|
* longer than {@link Sequence#count|count} the unneeded elements are
|
|
* ignored.
|
|
*
|
|
* **NOTE** If {@link Layout#count|count} is an instance of {@link
|
|
* ExternalLayout} then the length of `src` will be encoded as the
|
|
* count after `src` is encoded. */
|
|
encode(src, b, offset = 0) {
|
|
const elo = this.elementLayout;
|
|
const span = src.reduce((span, v) => {
|
|
return span + elo.encode(v, b, offset + span);
|
|
}, 0);
|
|
if (this.count instanceof ExternalLayout) {
|
|
this.count.encode(src.length, b, offset);
|
|
}
|
|
return span;
|
|
}
|
|
}
|
|
exports.Sequence = Sequence;
|
|
/**
|
|
* Represent a contiguous sequence of arbitrary layout elements as an
|
|
* Object.
|
|
*
|
|
* *Factory*: {@link module:Layout.struct|struct}
|
|
*
|
|
* **NOTE** The {@link Layout#span|span} of the structure is variable
|
|
* if any layout in {@link Structure#fields|fields} has a variable
|
|
* span. When {@link Layout#encode|encoding} we must have a value for
|
|
* all variable-length fields, or we wouldn't be able to figure out
|
|
* how much space to use for storage. We can only identify the value
|
|
* for a field when it has a {@link Layout#property|property}. As
|
|
* such, although a structure may contain both unnamed fields and
|
|
* variable-length fields, it cannot contain an unnamed
|
|
* variable-length field.
|
|
*
|
|
* @param {Layout[]} fields - initializer for {@link
|
|
* Structure#fields|fields}. An error is raised if this contains a
|
|
* variable-length field for which a {@link Layout#property|property}
|
|
* is not defined.
|
|
*
|
|
* @param {string} [property] - initializer for {@link
|
|
* Layout#property|property}.
|
|
*
|
|
* @param {Boolean} [decodePrefixes] - initializer for {@link
|
|
* Structure#decodePrefixes|property}.
|
|
*
|
|
* @throws {Error} - if `fields` contains an unnamed variable-length
|
|
* layout.
|
|
*
|
|
* @augments {Layout}
|
|
*/
|
|
class Structure extends Layout {
|
|
constructor(fields, property, decodePrefixes) {
|
|
if (!(Array.isArray(fields)
|
|
&& fields.reduce((acc, v) => acc && (v instanceof Layout), true))) {
|
|
throw new TypeError('fields must be array of Layout instances');
|
|
}
|
|
if (('boolean' === typeof property)
|
|
&& (undefined === decodePrefixes)) {
|
|
decodePrefixes = property;
|
|
property = undefined;
|
|
}
|
|
/* Verify absence of unnamed variable-length fields. */
|
|
for (const fd of fields) {
|
|
if ((0 > fd.span)
|
|
&& (undefined === fd.property)) {
|
|
throw new Error('fields cannot contain unnamed variable-length layout');
|
|
}
|
|
}
|
|
let span = -1;
|
|
try {
|
|
span = fields.reduce((span, fd) => span + fd.getSpan(), 0);
|
|
}
|
|
catch (e) {
|
|
// ignore error
|
|
}
|
|
super(span, property);
|
|
/** The sequence of {@link Layout} values that comprise the
|
|
* structure.
|
|
*
|
|
* The individual elements need not be the same type, and may be
|
|
* either scalar or aggregate layouts. If a member layout leaves
|
|
* its {@link Layout#property|property} undefined the
|
|
* corresponding region of the buffer associated with the element
|
|
* will not be mutated.
|
|
*
|
|
* @type {Layout[]} */
|
|
this.fields = fields;
|
|
/** Control behavior of {@link Layout#decode|decode()} given short
|
|
* buffers.
|
|
*
|
|
* In some situations a structure many be extended with additional
|
|
* fields over time, with older installations providing only a
|
|
* prefix of the full structure. If this property is `true`
|
|
* decoding will accept those buffers and leave subsequent fields
|
|
* undefined, as long as the buffer ends at a field boundary.
|
|
* Defaults to `false`. */
|
|
this.decodePrefixes = !!decodePrefixes;
|
|
}
|
|
/** @override */
|
|
getSpan(b, offset = 0) {
|
|
if (0 <= this.span) {
|
|
return this.span;
|
|
}
|
|
let span = 0;
|
|
try {
|
|
span = this.fields.reduce((span, fd) => {
|
|
const fsp = fd.getSpan(b, offset);
|
|
offset += fsp;
|
|
return span + fsp;
|
|
}, 0);
|
|
}
|
|
catch (e) {
|
|
throw new RangeError('indeterminate span');
|
|
}
|
|
return span;
|
|
}
|
|
/** @override */
|
|
decode(b, offset = 0) {
|
|
checkUint8Array(b);
|
|
const dest = this.makeDestinationObject();
|
|
for (const fd of this.fields) {
|
|
if (undefined !== fd.property) {
|
|
dest[fd.property] = fd.decode(b, offset);
|
|
}
|
|
offset += fd.getSpan(b, offset);
|
|
if (this.decodePrefixes
|
|
&& (b.length === offset)) {
|
|
break;
|
|
}
|
|
}
|
|
return dest;
|
|
}
|
|
/** Implement {@link Layout#encode|encode} for {@link Structure}.
|
|
*
|
|
* If `src` is missing a property for a member with a defined {@link
|
|
* Layout#property|property} the corresponding region of the buffer is
|
|
* left unmodified. */
|
|
encode(src, b, offset = 0) {
|
|
const firstOffset = offset;
|
|
let lastOffset = 0;
|
|
let lastWrote = 0;
|
|
for (const fd of this.fields) {
|
|
let span = fd.span;
|
|
lastWrote = (0 < span) ? span : 0;
|
|
if (undefined !== fd.property) {
|
|
const fv = src[fd.property];
|
|
if (undefined !== fv) {
|
|
lastWrote = fd.encode(fv, b, offset);
|
|
if (0 > span) {
|
|
/* Read the as-encoded span, which is not necessarily the
|
|
* same as what we wrote. */
|
|
span = fd.getSpan(b, offset);
|
|
}
|
|
}
|
|
}
|
|
lastOffset = offset;
|
|
offset += span;
|
|
}
|
|
/* Use (lastOffset + lastWrote) instead of offset because the last
|
|
* item may have had a dynamic length and we don't want to include
|
|
* the padding between it and the end of the space reserved for
|
|
* it. */
|
|
return (lastOffset + lastWrote) - firstOffset;
|
|
}
|
|
/** @override */
|
|
fromArray(values) {
|
|
const dest = this.makeDestinationObject();
|
|
for (const fd of this.fields) {
|
|
if ((undefined !== fd.property)
|
|
&& (0 < values.length)) {
|
|
dest[fd.property] = values.shift();
|
|
}
|
|
}
|
|
return dest;
|
|
}
|
|
/**
|
|
* Get access to the layout of a given property.
|
|
*
|
|
* @param {String} property - the structure member of interest.
|
|
*
|
|
* @return {Layout} - the layout associated with `property`, or
|
|
* undefined if there is no such property.
|
|
*/
|
|
layoutFor(property) {
|
|
if ('string' !== typeof property) {
|
|
throw new TypeError('property must be string');
|
|
}
|
|
for (const fd of this.fields) {
|
|
if (fd.property === property) {
|
|
return fd;
|
|
}
|
|
}
|
|
return undefined;
|
|
}
|
|
/**
|
|
* Get the offset of a structure member.
|
|
*
|
|
* @param {String} property - the structure member of interest.
|
|
*
|
|
* @return {Number} - the offset in bytes to the start of `property`
|
|
* within the structure, or undefined if `property` is not a field
|
|
* within the structure. If the property is a member but follows a
|
|
* variable-length structure member a negative number will be
|
|
* returned.
|
|
*/
|
|
offsetOf(property) {
|
|
if ('string' !== typeof property) {
|
|
throw new TypeError('property must be string');
|
|
}
|
|
let offset = 0;
|
|
for (const fd of this.fields) {
|
|
if (fd.property === property) {
|
|
return offset;
|
|
}
|
|
if (0 > fd.span) {
|
|
offset = -1;
|
|
}
|
|
else if (0 <= offset) {
|
|
offset += fd.span;
|
|
}
|
|
}
|
|
return undefined;
|
|
}
|
|
}
|
|
exports.Structure = Structure;
|
|
/**
|
|
* An object that can provide a {@link
|
|
* Union#discriminator|discriminator} API for {@link Union}.
|
|
*
|
|
* **NOTE** This is an abstract base class; you can create instances
|
|
* if it amuses you, but they won't support the {@link
|
|
* UnionDiscriminator#encode|encode} or {@link
|
|
* UnionDiscriminator#decode|decode} functions.
|
|
*
|
|
* @param {string} [property] - Default for {@link
|
|
* UnionDiscriminator#property|property}.
|
|
*
|
|
* @abstract
|
|
*/
|
|
class UnionDiscriminator {
|
|
constructor(property) {
|
|
/** The {@link Layout#property|property} to be used when the
|
|
* discriminator is referenced in isolation (generally when {@link
|
|
* Union#decode|Union decode} cannot delegate to a specific
|
|
* variant). */
|
|
this.property = property;
|
|
}
|
|
/** Analog to {@link Layout#decode|Layout decode} for union discriminators.
|
|
*
|
|
* The implementation of this method need not reference the buffer if
|
|
* variant information is available through other means. */
|
|
decode(b, offset) {
|
|
throw new Error('UnionDiscriminator is abstract');
|
|
}
|
|
/** Analog to {@link Layout#decode|Layout encode} for union discriminators.
|
|
*
|
|
* The implementation of this method need not store the value if
|
|
* variant information is maintained through other means. */
|
|
encode(src, b, offset) {
|
|
throw new Error('UnionDiscriminator is abstract');
|
|
}
|
|
}
|
|
exports.UnionDiscriminator = UnionDiscriminator;
|
|
/**
|
|
* An object that can provide a {@link
|
|
* UnionDiscriminator|discriminator API} for {@link Union} using an
|
|
* unsigned integral {@link Layout} instance located either inside or
|
|
* outside the union.
|
|
*
|
|
* @param {ExternalLayout} layout - initializes {@link
|
|
* UnionLayoutDiscriminator#layout|layout}. Must satisfy {@link
|
|
* ExternalLayout#isCount|isCount()}.
|
|
*
|
|
* @param {string} [property] - Default for {@link
|
|
* UnionDiscriminator#property|property}, superseding the property
|
|
* from `layout`, but defaulting to `variant` if neither `property`
|
|
* nor layout provide a property name.
|
|
*
|
|
* @augments {UnionDiscriminator}
|
|
*/
|
|
class UnionLayoutDiscriminator extends UnionDiscriminator {
|
|
constructor(layout, property) {
|
|
if (!((layout instanceof ExternalLayout)
|
|
&& layout.isCount())) {
|
|
throw new TypeError('layout must be an unsigned integer ExternalLayout');
|
|
}
|
|
super(property || layout.property || 'variant');
|
|
/** The {@link ExternalLayout} used to access the discriminator
|
|
* value. */
|
|
this.layout = layout;
|
|
}
|
|
/** Delegate decoding to {@link UnionLayoutDiscriminator#layout|layout}. */
|
|
decode(b, offset) {
|
|
return this.layout.decode(b, offset);
|
|
}
|
|
/** Delegate encoding to {@link UnionLayoutDiscriminator#layout|layout}. */
|
|
encode(src, b, offset) {
|
|
return this.layout.encode(src, b, offset);
|
|
}
|
|
}
|
|
exports.UnionLayoutDiscriminator = UnionLayoutDiscriminator;
|
|
/**
|
|
* Represent any number of span-compatible layouts.
|
|
*
|
|
* *Factory*: {@link module:Layout.union|union}
|
|
*
|
|
* If the union has a {@link Union#defaultLayout|default layout} that
|
|
* layout must have a non-negative {@link Layout#span|span}. The span
|
|
* of a fixed-span union includes its {@link
|
|
* Union#discriminator|discriminator} if the variant is a {@link
|
|
* Union#usesPrefixDiscriminator|prefix of the union}, plus the span
|
|
* of its {@link Union#defaultLayout|default layout}.
|
|
*
|
|
* If the union does not have a default layout then the encoded span
|
|
* of the union depends on the encoded span of its variant (which may
|
|
* be fixed or variable).
|
|
*
|
|
* {@link VariantLayout#layout|Variant layout}s are added through
|
|
* {@link Union#addVariant|addVariant}. If the union has a default
|
|
* layout, the span of the {@link VariantLayout#layout|layout
|
|
* contained by the variant} must not exceed the span of the {@link
|
|
* Union#defaultLayout|default layout} (minus the span of a {@link
|
|
* Union#usesPrefixDiscriminator|prefix disriminator}, if used). The
|
|
* span of the variant will equal the span of the union itself.
|
|
*
|
|
* The variant for a buffer can only be identified from the {@link
|
|
* Union#discriminator|discriminator} {@link
|
|
* UnionDiscriminator#property|property} (in the case of the {@link
|
|
* Union#defaultLayout|default layout}), or by using {@link
|
|
* Union#getVariant|getVariant} and examining the resulting {@link
|
|
* VariantLayout} instance.
|
|
*
|
|
* A variant compatible with a JavaScript object can be identified
|
|
* using {@link Union#getSourceVariant|getSourceVariant}.
|
|
*
|
|
* @param {(UnionDiscriminator|ExternalLayout|Layout)} discr - How to
|
|
* identify the layout used to interpret the union contents. The
|
|
* parameter must be an instance of {@link UnionDiscriminator}, an
|
|
* {@link ExternalLayout} that satisfies {@link
|
|
* ExternalLayout#isCount|isCount()}, or {@link UInt} (or {@link
|
|
* UIntBE}). When a non-external layout element is passed the layout
|
|
* appears at the start of the union. In all cases the (synthesized)
|
|
* {@link UnionDiscriminator} instance is recorded as {@link
|
|
* Union#discriminator|discriminator}.
|
|
*
|
|
* @param {(Layout|null)} defaultLayout - initializer for {@link
|
|
* Union#defaultLayout|defaultLayout}. If absent defaults to `null`.
|
|
* If `null` there is no default layout: the union has data-dependent
|
|
* length and attempts to decode or encode unrecognized variants will
|
|
* throw an exception. A {@link Layout} instance must have a
|
|
* non-negative {@link Layout#span|span}, and if it lacks a {@link
|
|
* Layout#property|property} the {@link
|
|
* Union#defaultLayout|defaultLayout} will be a {@link
|
|
* Layout#replicate|replica} with property `content`.
|
|
*
|
|
* @param {string} [property] - initializer for {@link
|
|
* Layout#property|property}.
|
|
*
|
|
* @augments {Layout}
|
|
*/
|
|
class Union extends Layout {
|
|
constructor(discr, defaultLayout, property) {
|
|
let discriminator;
|
|
if ((discr instanceof UInt)
|
|
|| (discr instanceof UIntBE)) {
|
|
discriminator = new UnionLayoutDiscriminator(new OffsetLayout(discr));
|
|
}
|
|
else if ((discr instanceof ExternalLayout)
|
|
&& discr.isCount()) {
|
|
discriminator = new UnionLayoutDiscriminator(discr);
|
|
}
|
|
else if (!(discr instanceof UnionDiscriminator)) {
|
|
throw new TypeError('discr must be a UnionDiscriminator '
|
|
+ 'or an unsigned integer layout');
|
|
}
|
|
else {
|
|
discriminator = discr;
|
|
}
|
|
if (undefined === defaultLayout) {
|
|
defaultLayout = null;
|
|
}
|
|
if (!((null === defaultLayout)
|
|
|| (defaultLayout instanceof Layout))) {
|
|
throw new TypeError('defaultLayout must be null or a Layout');
|
|
}
|
|
if (null !== defaultLayout) {
|
|
if (0 > defaultLayout.span) {
|
|
throw new Error('defaultLayout must have constant span');
|
|
}
|
|
if (undefined === defaultLayout.property) {
|
|
defaultLayout = defaultLayout.replicate('content');
|
|
}
|
|
}
|
|
/* The union span can be estimated only if there's a default
|
|
* layout. The union spans its default layout, plus any prefix
|
|
* variant layout. By construction both layouts, if present, have
|
|
* non-negative span. */
|
|
let span = -1;
|
|
if (defaultLayout) {
|
|
span = defaultLayout.span;
|
|
if ((0 <= span) && ((discr instanceof UInt)
|
|
|| (discr instanceof UIntBE))) {
|
|
span += discriminator.layout.span;
|
|
}
|
|
}
|
|
super(span, property);
|
|
/** The interface for the discriminator value in isolation.
|
|
*
|
|
* This a {@link UnionDiscriminator} either passed to the
|
|
* constructor or synthesized from the `discr` constructor
|
|
* argument. {@link
|
|
* Union#usesPrefixDiscriminator|usesPrefixDiscriminator} will be
|
|
* `true` iff the `discr` parameter was a non-offset {@link
|
|
* Layout} instance. */
|
|
this.discriminator = discriminator;
|
|
/** `true` if the {@link Union#discriminator|discriminator} is the
|
|
* first field in the union.
|
|
*
|
|
* If `false` the discriminator is obtained from somewhere
|
|
* else. */
|
|
this.usesPrefixDiscriminator = (discr instanceof UInt)
|
|
|| (discr instanceof UIntBE);
|
|
/** The layout for non-discriminator content when the value of the
|
|
* discriminator is not recognized.
|
|
*
|
|
* This is the value passed to the constructor. It is
|
|
* structurally equivalent to the second component of {@link
|
|
* Union#layout|layout} but may have a different property
|
|
* name. */
|
|
this.defaultLayout = defaultLayout;
|
|
/** A registry of allowed variants.
|
|
*
|
|
* The keys are unsigned integers which should be compatible with
|
|
* {@link Union.discriminator|discriminator}. The property value
|
|
* is the corresponding {@link VariantLayout} instances assigned
|
|
* to this union by {@link Union#addVariant|addVariant}.
|
|
*
|
|
* **NOTE** The registry remains mutable so that variants can be
|
|
* {@link Union#addVariant|added} at any time. Users should not
|
|
* manipulate the content of this property. */
|
|
this.registry = {};
|
|
/* Private variable used when invoking getSourceVariant */
|
|
let boundGetSourceVariant = this.defaultGetSourceVariant.bind(this);
|
|
/** Function to infer the variant selected by a source object.
|
|
*
|
|
* Defaults to {@link
|
|
* Union#defaultGetSourceVariant|defaultGetSourceVariant} but may
|
|
* be overridden using {@link
|
|
* Union#configGetSourceVariant|configGetSourceVariant}.
|
|
*
|
|
* @param {Object} src - as with {@link
|
|
* Union#defaultGetSourceVariant|defaultGetSourceVariant}.
|
|
*
|
|
* @returns {(undefined|VariantLayout)} The default variant
|
|
* (`undefined`) or first registered variant that uses a property
|
|
* available in `src`. */
|
|
this.getSourceVariant = function (src) {
|
|
return boundGetSourceVariant(src);
|
|
};
|
|
/** Function to override the implementation of {@link
|
|
* Union#getSourceVariant|getSourceVariant}.
|
|
*
|
|
* Use this if the desired variant cannot be identified using the
|
|
* algorithm of {@link
|
|
* Union#defaultGetSourceVariant|defaultGetSourceVariant}.
|
|
*
|
|
* **NOTE** The provided function will be invoked bound to this
|
|
* Union instance, providing local access to {@link
|
|
* Union#registry|registry}.
|
|
*
|
|
* @param {Function} gsv - a function that follows the API of
|
|
* {@link Union#defaultGetSourceVariant|defaultGetSourceVariant}. */
|
|
this.configGetSourceVariant = function (gsv) {
|
|
boundGetSourceVariant = gsv.bind(this);
|
|
};
|
|
}
|
|
/** @override */
|
|
getSpan(b, offset = 0) {
|
|
if (0 <= this.span) {
|
|
return this.span;
|
|
}
|
|
/* Default layouts always have non-negative span, so we don't have
|
|
* one and we have to recognize the variant which will in turn
|
|
* determine the span. */
|
|
const vlo = this.getVariant(b, offset);
|
|
if (!vlo) {
|
|
throw new Error('unable to determine span for unrecognized variant');
|
|
}
|
|
return vlo.getSpan(b, offset);
|
|
}
|
|
/**
|
|
* Method to infer a registered Union variant compatible with `src`.
|
|
*
|
|
* The first satisfied rule in the following sequence defines the
|
|
* return value:
|
|
* * If `src` has properties matching the Union discriminator and
|
|
* the default layout, `undefined` is returned regardless of the
|
|
* value of the discriminator property (this ensures the default
|
|
* layout will be used);
|
|
* * If `src` has a property matching the Union discriminator, the
|
|
* value of the discriminator identifies a registered variant, and
|
|
* either (a) the variant has no layout, or (b) `src` has the
|
|
* variant's property, then the variant is returned (because the
|
|
* source satisfies the constraints of the variant it identifies);
|
|
* * If `src` does not have a property matching the Union
|
|
* discriminator, but does have a property matching a registered
|
|
* variant, then the variant is returned (because the source
|
|
* matches a variant without an explicit conflict);
|
|
* * An error is thrown (because we either can't identify a variant,
|
|
* or we were explicitly told the variant but can't satisfy it).
|
|
*
|
|
* @param {Object} src - an object presumed to be compatible with
|
|
* the content of the Union.
|
|
*
|
|
* @return {(undefined|VariantLayout)} - as described above.
|
|
*
|
|
* @throws {Error} - if `src` cannot be associated with a default or
|
|
* registered variant.
|
|
*/
|
|
defaultGetSourceVariant(src) {
|
|
if (Object.prototype.hasOwnProperty.call(src, this.discriminator.property)) {
|
|
if (this.defaultLayout && this.defaultLayout.property
|
|
&& Object.prototype.hasOwnProperty.call(src, this.defaultLayout.property)) {
|
|
return undefined;
|
|
}
|
|
const vlo = this.registry[src[this.discriminator.property]];
|
|
if (vlo
|
|
&& ((!vlo.layout)
|
|
|| (vlo.property && Object.prototype.hasOwnProperty.call(src, vlo.property)))) {
|
|
return vlo;
|
|
}
|
|
}
|
|
else {
|
|
for (const tag in this.registry) {
|
|
const vlo = this.registry[tag];
|
|
if (vlo.property && Object.prototype.hasOwnProperty.call(src, vlo.property)) {
|
|
return vlo;
|
|
}
|
|
}
|
|
}
|
|
throw new Error('unable to infer src variant');
|
|
}
|
|
/** Implement {@link Layout#decode|decode} for {@link Union}.
|
|
*
|
|
* If the variant is {@link Union#addVariant|registered} the return
|
|
* value is an instance of that variant, with no explicit
|
|
* discriminator. Otherwise the {@link Union#defaultLayout|default
|
|
* layout} is used to decode the content. */
|
|
decode(b, offset = 0) {
|
|
let dest;
|
|
const dlo = this.discriminator;
|
|
const discr = dlo.decode(b, offset);
|
|
const clo = this.registry[discr];
|
|
if (undefined === clo) {
|
|
const defaultLayout = this.defaultLayout;
|
|
let contentOffset = 0;
|
|
if (this.usesPrefixDiscriminator) {
|
|
contentOffset = dlo.layout.span;
|
|
}
|
|
dest = this.makeDestinationObject();
|
|
dest[dlo.property] = discr;
|
|
// defaultLayout.property can be undefined, but this is allowed by buffer-layout
|
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
dest[defaultLayout.property] = defaultLayout.decode(b, offset + contentOffset);
|
|
}
|
|
else {
|
|
dest = clo.decode(b, offset);
|
|
}
|
|
return dest;
|
|
}
|
|
/** Implement {@link Layout#encode|encode} for {@link Union}.
|
|
*
|
|
* This API assumes the `src` object is consistent with the union's
|
|
* {@link Union#defaultLayout|default layout}. To encode variants
|
|
* use the appropriate variant-specific {@link VariantLayout#encode}
|
|
* method. */
|
|
encode(src, b, offset = 0) {
|
|
const vlo = this.getSourceVariant(src);
|
|
if (undefined === vlo) {
|
|
const dlo = this.discriminator;
|
|
// this.defaultLayout is not undefined when vlo is undefined
|
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
const clo = this.defaultLayout;
|
|
let contentOffset = 0;
|
|
if (this.usesPrefixDiscriminator) {
|
|
contentOffset = dlo.layout.span;
|
|
}
|
|
dlo.encode(src[dlo.property], b, offset);
|
|
// clo.property is not undefined when vlo is undefined
|
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
return contentOffset + clo.encode(src[clo.property], b, offset + contentOffset);
|
|
}
|
|
return vlo.encode(src, b, offset);
|
|
}
|
|
/** Register a new variant structure within a union. The newly
|
|
* created variant is returned.
|
|
*
|
|
* @param {Number} variant - initializer for {@link
|
|
* VariantLayout#variant|variant}.
|
|
*
|
|
* @param {Layout} layout - initializer for {@link
|
|
* VariantLayout#layout|layout}.
|
|
*
|
|
* @param {String} property - initializer for {@link
|
|
* Layout#property|property}.
|
|
*
|
|
* @return {VariantLayout} */
|
|
addVariant(variant, layout, property) {
|
|
const rv = new VariantLayout(this, variant, layout, property);
|
|
this.registry[variant] = rv;
|
|
return rv;
|
|
}
|
|
/**
|
|
* Get the layout associated with a registered variant.
|
|
*
|
|
* If `vb` does not produce a registered variant the function returns
|
|
* `undefined`.
|
|
*
|
|
* @param {(Number|Uint8Array)} vb - either the variant number, or a
|
|
* buffer from which the discriminator is to be read.
|
|
*
|
|
* @param {Number} offset - offset into `vb` for the start of the
|
|
* union. Used only when `vb` is an instance of {Uint8Array}.
|
|
*
|
|
* @return {({VariantLayout}|undefined)}
|
|
*/
|
|
getVariant(vb, offset = 0) {
|
|
let variant;
|
|
if (vb instanceof Uint8Array) {
|
|
variant = this.discriminator.decode(vb, offset);
|
|
}
|
|
else {
|
|
variant = vb;
|
|
}
|
|
return this.registry[variant];
|
|
}
|
|
}
|
|
exports.Union = Union;
|
|
/**
|
|
* Represent a specific variant within a containing union.
|
|
*
|
|
* **NOTE** The {@link Layout#span|span} of the variant may include
|
|
* the span of the {@link Union#discriminator|discriminator} used to
|
|
* identify it, but values read and written using the variant strictly
|
|
* conform to the content of {@link VariantLayout#layout|layout}.
|
|
*
|
|
* **NOTE** User code should not invoke this constructor directly. Use
|
|
* the union {@link Union#addVariant|addVariant} helper method.
|
|
*
|
|
* @param {Union} union - initializer for {@link
|
|
* VariantLayout#union|union}.
|
|
*
|
|
* @param {Number} variant - initializer for {@link
|
|
* VariantLayout#variant|variant}.
|
|
*
|
|
* @param {Layout} [layout] - initializer for {@link
|
|
* VariantLayout#layout|layout}. If absent the variant carries no
|
|
* data.
|
|
*
|
|
* @param {String} [property] - initializer for {@link
|
|
* Layout#property|property}. Unlike many other layouts, variant
|
|
* layouts normally include a property name so they can be identified
|
|
* within their containing {@link Union}. The property identifier may
|
|
* be absent only if `layout` is is absent.
|
|
*
|
|
* @augments {Layout}
|
|
*/
|
|
class VariantLayout extends Layout {
|
|
constructor(union, variant, layout, property) {
|
|
if (!(union instanceof Union)) {
|
|
throw new TypeError('union must be a Union');
|
|
}
|
|
if ((!Number.isInteger(variant)) || (0 > variant)) {
|
|
throw new TypeError('variant must be a (non-negative) integer');
|
|
}
|
|
if (('string' === typeof layout)
|
|
&& (undefined === property)) {
|
|
property = layout;
|
|
layout = null;
|
|
}
|
|
if (layout) {
|
|
if (!(layout instanceof Layout)) {
|
|
throw new TypeError('layout must be a Layout');
|
|
}
|
|
if ((null !== union.defaultLayout)
|
|
&& (0 <= layout.span)
|
|
&& (layout.span > union.defaultLayout.span)) {
|
|
throw new Error('variant span exceeds span of containing union');
|
|
}
|
|
if ('string' !== typeof property) {
|
|
throw new TypeError('variant must have a String property');
|
|
}
|
|
}
|
|
let span = union.span;
|
|
if (0 > union.span) {
|
|
span = layout ? layout.span : 0;
|
|
if ((0 <= span) && union.usesPrefixDiscriminator) {
|
|
span += union.discriminator.layout.span;
|
|
}
|
|
}
|
|
super(span, property);
|
|
/** The {@link Union} to which this variant belongs. */
|
|
this.union = union;
|
|
/** The unsigned integral value identifying this variant within
|
|
* the {@link Union#discriminator|discriminator} of the containing
|
|
* union. */
|
|
this.variant = variant;
|
|
/** The {@link Layout} to be used when reading/writing the
|
|
* non-discriminator part of the {@link
|
|
* VariantLayout#union|union}. If `null` the variant carries no
|
|
* data. */
|
|
this.layout = layout || null;
|
|
}
|
|
/** @override */
|
|
getSpan(b, offset = 0) {
|
|
if (0 <= this.span) {
|
|
/* Will be equal to the containing union span if that is not
|
|
* variable. */
|
|
return this.span;
|
|
}
|
|
let contentOffset = 0;
|
|
if (this.union.usesPrefixDiscriminator) {
|
|
contentOffset = this.union.discriminator.layout.span;
|
|
}
|
|
/* Span is defined solely by the variant (and prefix discriminator) */
|
|
let span = 0;
|
|
if (this.layout) {
|
|
span = this.layout.getSpan(b, offset + contentOffset);
|
|
}
|
|
return contentOffset + span;
|
|
}
|
|
/** @override */
|
|
decode(b, offset = 0) {
|
|
const dest = this.makeDestinationObject();
|
|
if (this !== this.union.getVariant(b, offset)) {
|
|
throw new Error('variant mismatch');
|
|
}
|
|
let contentOffset = 0;
|
|
if (this.union.usesPrefixDiscriminator) {
|
|
contentOffset = this.union.discriminator.layout.span;
|
|
}
|
|
if (this.layout) {
|
|
dest[this.property] = this.layout.decode(b, offset + contentOffset);
|
|
}
|
|
else if (this.property) {
|
|
dest[this.property] = true;
|
|
}
|
|
else if (this.union.usesPrefixDiscriminator) {
|
|
dest[this.union.discriminator.property] = this.variant;
|
|
}
|
|
return dest;
|
|
}
|
|
/** @override */
|
|
encode(src, b, offset = 0) {
|
|
let contentOffset = 0;
|
|
if (this.union.usesPrefixDiscriminator) {
|
|
contentOffset = this.union.discriminator.layout.span;
|
|
}
|
|
if (this.layout
|
|
&& (!Object.prototype.hasOwnProperty.call(src, this.property))) {
|
|
throw new TypeError('variant lacks property ' + this.property);
|
|
}
|
|
this.union.discriminator.encode(this.variant, b, offset);
|
|
let span = contentOffset;
|
|
if (this.layout) {
|
|
this.layout.encode(src[this.property], b, offset + contentOffset);
|
|
span += this.layout.getSpan(b, offset + contentOffset);
|
|
if ((0 <= this.union.span)
|
|
&& (span > this.union.span)) {
|
|
throw new Error('encoded variant overruns containing union');
|
|
}
|
|
}
|
|
return span;
|
|
}
|
|
/** Delegate {@link Layout#fromArray|fromArray} to {@link
|
|
* VariantLayout#layout|layout}. */
|
|
fromArray(values) {
|
|
if (this.layout) {
|
|
return this.layout.fromArray(values);
|
|
}
|
|
return undefined;
|
|
}
|
|
}
|
|
exports.VariantLayout = VariantLayout;
|
|
/** JavaScript chose to define bitwise operations as operating on
|
|
* signed 32-bit values in 2's complement form, meaning any integer
|
|
* with bit 31 set is going to look negative. For right shifts that's
|
|
* not a problem, because `>>>` is a logical shift, but for every
|
|
* other bitwise operator we have to compensate for possible negative
|
|
* results. */
|
|
function fixBitwiseResult(v) {
|
|
if (0 > v) {
|
|
v += 0x100000000;
|
|
}
|
|
return v;
|
|
}
|
|
/**
|
|
* Contain a sequence of bit fields as an unsigned integer.
|
|
*
|
|
* *Factory*: {@link module:Layout.bits|bits}
|
|
*
|
|
* This is a container element; within it there are {@link BitField}
|
|
* instances that provide the extracted properties. The container
|
|
* simply defines the aggregate representation and its bit ordering.
|
|
* The representation is an object containing properties with numeric
|
|
* or {@link Boolean} values.
|
|
*
|
|
* {@link BitField}s are added with the {@link
|
|
* BitStructure#addField|addField} and {@link
|
|
* BitStructure#addBoolean|addBoolean} methods.
|
|
|
|
* @param {Layout} word - initializer for {@link
|
|
* BitStructure#word|word}. The parameter must be an instance of
|
|
* {@link UInt} (or {@link UIntBE}) that is no more than 4 bytes wide.
|
|
*
|
|
* @param {bool} [msb] - `true` if the bit numbering starts at the
|
|
* most significant bit of the containing word; `false` (default) if
|
|
* it starts at the least significant bit of the containing word. If
|
|
* the parameter at this position is a string and `property` is
|
|
* `undefined` the value of this argument will instead be used as the
|
|
* value of `property`.
|
|
*
|
|
* @param {string} [property] - initializer for {@link
|
|
* Layout#property|property}.
|
|
*
|
|
* @augments {Layout}
|
|
*/
|
|
class BitStructure extends Layout {
|
|
constructor(word, msb, property) {
|
|
if (!((word instanceof UInt)
|
|
|| (word instanceof UIntBE))) {
|
|
throw new TypeError('word must be a UInt or UIntBE layout');
|
|
}
|
|
if (('string' === typeof msb)
|
|
&& (undefined === property)) {
|
|
property = msb;
|
|
msb = false;
|
|
}
|
|
if (4 < word.span) {
|
|
throw new RangeError('word cannot exceed 32 bits');
|
|
}
|
|
super(word.span, property);
|
|
/** The layout used for the packed value. {@link BitField}
|
|
* instances are packed sequentially depending on {@link
|
|
* BitStructure#msb|msb}. */
|
|
this.word = word;
|
|
/** Whether the bit sequences are packed starting at the most
|
|
* significant bit growing down (`true`), or the least significant
|
|
* bit growing up (`false`).
|
|
*
|
|
* **NOTE** Regardless of this value, the least significant bit of
|
|
* any {@link BitField} value is the least significant bit of the
|
|
* corresponding section of the packed value. */
|
|
this.msb = !!msb;
|
|
/** The sequence of {@link BitField} layouts that comprise the
|
|
* packed structure.
|
|
*
|
|
* **NOTE** The array remains mutable to allow fields to be {@link
|
|
* BitStructure#addField|added} after construction. Users should
|
|
* not manipulate the content of this property.*/
|
|
this.fields = [];
|
|
/* Storage for the value. Capture a variable instead of using an
|
|
* instance property because we don't want anything to change the
|
|
* value without going through the mutator. */
|
|
let value = 0;
|
|
this._packedSetValue = function (v) {
|
|
value = fixBitwiseResult(v);
|
|
return this;
|
|
};
|
|
this._packedGetValue = function () {
|
|
return value;
|
|
};
|
|
}
|
|
/** @override */
|
|
decode(b, offset = 0) {
|
|
const dest = this.makeDestinationObject();
|
|
const value = this.word.decode(b, offset);
|
|
this._packedSetValue(value);
|
|
for (const fd of this.fields) {
|
|
if (undefined !== fd.property) {
|
|
dest[fd.property] = fd.decode(b);
|
|
}
|
|
}
|
|
return dest;
|
|
}
|
|
/** Implement {@link Layout#encode|encode} for {@link BitStructure}.
|
|
*
|
|
* If `src` is missing a property for a member with a defined {@link
|
|
* Layout#property|property} the corresponding region of the packed
|
|
* value is left unmodified. Unused bits are also left unmodified. */
|
|
encode(src, b, offset = 0) {
|
|
const value = this.word.decode(b, offset);
|
|
this._packedSetValue(value);
|
|
for (const fd of this.fields) {
|
|
if (undefined !== fd.property) {
|
|
const fv = src[fd.property];
|
|
if (undefined !== fv) {
|
|
fd.encode(fv);
|
|
}
|
|
}
|
|
}
|
|
return this.word.encode(this._packedGetValue(), b, offset);
|
|
}
|
|
/** Register a new bitfield with a containing bit structure. The
|
|
* resulting bitfield is returned.
|
|
*
|
|
* @param {Number} bits - initializer for {@link BitField#bits|bits}.
|
|
*
|
|
* @param {string} property - initializer for {@link
|
|
* Layout#property|property}.
|
|
*
|
|
* @return {BitField} */
|
|
addField(bits, property) {
|
|
const bf = new BitField(this, bits, property);
|
|
this.fields.push(bf);
|
|
return bf;
|
|
}
|
|
/** As with {@link BitStructure#addField|addField} for single-bit
|
|
* fields with `boolean` value representation.
|
|
*
|
|
* @param {string} property - initializer for {@link
|
|
* Layout#property|property}.
|
|
*
|
|
* @return {Boolean} */
|
|
// `Boolean` conflicts with the native primitive type
|
|
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
addBoolean(property) {
|
|
// This is my Boolean, not the Javascript one.
|
|
const bf = new Boolean(this, property);
|
|
this.fields.push(bf);
|
|
return bf;
|
|
}
|
|
/**
|
|
* Get access to the bit field for a given property.
|
|
*
|
|
* @param {String} property - the bit field of interest.
|
|
*
|
|
* @return {BitField} - the field associated with `property`, or
|
|
* undefined if there is no such property.
|
|
*/
|
|
fieldFor(property) {
|
|
if ('string' !== typeof property) {
|
|
throw new TypeError('property must be string');
|
|
}
|
|
for (const fd of this.fields) {
|
|
if (fd.property === property) {
|
|
return fd;
|
|
}
|
|
}
|
|
return undefined;
|
|
}
|
|
}
|
|
exports.BitStructure = BitStructure;
|
|
/**
|
|
* Represent a sequence of bits within a {@link BitStructure}.
|
|
*
|
|
* All bit field values are represented as unsigned integers.
|
|
*
|
|
* **NOTE** User code should not invoke this constructor directly.
|
|
* Use the container {@link BitStructure#addField|addField} helper
|
|
* method.
|
|
*
|
|
* **NOTE** BitField instances are not instances of {@link Layout}
|
|
* since {@link Layout#span|span} measures 8-bit units.
|
|
*
|
|
* @param {BitStructure} container - initializer for {@link
|
|
* BitField#container|container}.
|
|
*
|
|
* @param {Number} bits - initializer for {@link BitField#bits|bits}.
|
|
*
|
|
* @param {string} [property] - initializer for {@link
|
|
* Layout#property|property}.
|
|
*/
|
|
class BitField {
|
|
constructor(container, bits, property) {
|
|
if (!(container instanceof BitStructure)) {
|
|
throw new TypeError('container must be a BitStructure');
|
|
}
|
|
if ((!Number.isInteger(bits)) || (0 >= bits)) {
|
|
throw new TypeError('bits must be positive integer');
|
|
}
|
|
const totalBits = 8 * container.span;
|
|
const usedBits = container.fields.reduce((sum, fd) => sum + fd.bits, 0);
|
|
if ((bits + usedBits) > totalBits) {
|
|
throw new Error('bits too long for span remainder ('
|
|
+ (totalBits - usedBits) + ' of '
|
|
+ totalBits + ' remain)');
|
|
}
|
|
/** The {@link BitStructure} instance to which this bit field
|
|
* belongs. */
|
|
this.container = container;
|
|
/** The span of this value in bits. */
|
|
this.bits = bits;
|
|
/** A mask of {@link BitField#bits|bits} bits isolating value bits
|
|
* that fit within the field.
|
|
*
|
|
* That is, it masks a value that has not yet been shifted into
|
|
* position within its containing packed integer. */
|
|
this.valueMask = (1 << bits) - 1;
|
|
if (32 === bits) { // shifted value out of range
|
|
this.valueMask = 0xFFFFFFFF;
|
|
}
|
|
/** The offset of the value within the containing packed unsigned
|
|
* integer. The least significant bit of the packed value is at
|
|
* offset zero, regardless of bit ordering used. */
|
|
this.start = usedBits;
|
|
if (this.container.msb) {
|
|
this.start = totalBits - usedBits - bits;
|
|
}
|
|
/** A mask of {@link BitField#bits|bits} isolating the field value
|
|
* within the containing packed unsigned integer. */
|
|
this.wordMask = fixBitwiseResult(this.valueMask << this.start);
|
|
/** The property name used when this bitfield is represented in an
|
|
* Object.
|
|
*
|
|
* Intended to be functionally equivalent to {@link
|
|
* Layout#property}.
|
|
*
|
|
* If left undefined the corresponding span of bits will be
|
|
* treated as padding: it will not be mutated by {@link
|
|
* Layout#encode|encode} nor represented as a property in the
|
|
* decoded Object. */
|
|
this.property = property;
|
|
}
|
|
/** Store a value into the corresponding subsequence of the containing
|
|
* bit field. */
|
|
decode(b, offset) {
|
|
const word = this.container._packedGetValue();
|
|
const wordValue = fixBitwiseResult(word & this.wordMask);
|
|
const value = wordValue >>> this.start;
|
|
return value;
|
|
}
|
|
/** Store a value into the corresponding subsequence of the containing
|
|
* bit field.
|
|
*
|
|
* **NOTE** This is not a specialization of {@link
|
|
* Layout#encode|Layout.encode} and there is no return value. */
|
|
encode(value) {
|
|
if ('number' !== typeof value
|
|
|| !Number.isInteger(value)
|
|
|| (value !== fixBitwiseResult(value & this.valueMask))) {
|
|
throw new TypeError(nameWithProperty('BitField.encode', this)
|
|
+ ' value must be integer not exceeding ' + this.valueMask);
|
|
}
|
|
const word = this.container._packedGetValue();
|
|
const wordValue = fixBitwiseResult(value << this.start);
|
|
this.container._packedSetValue(fixBitwiseResult(word & ~this.wordMask)
|
|
| wordValue);
|
|
}
|
|
}
|
|
exports.BitField = BitField;
|
|
/**
|
|
* Represent a single bit within a {@link BitStructure} as a
|
|
* JavaScript boolean.
|
|
*
|
|
* **NOTE** User code should not invoke this constructor directly.
|
|
* Use the container {@link BitStructure#addBoolean|addBoolean} helper
|
|
* method.
|
|
*
|
|
* @param {BitStructure} container - initializer for {@link
|
|
* BitField#container|container}.
|
|
*
|
|
* @param {string} [property] - initializer for {@link
|
|
* Layout#property|property}.
|
|
*
|
|
* @augments {BitField}
|
|
*/
|
|
/* eslint-disable no-extend-native */
|
|
class Boolean extends BitField {
|
|
constructor(container, property) {
|
|
super(container, 1, property);
|
|
}
|
|
/** Override {@link BitField#decode|decode} for {@link Boolean|Boolean}.
|
|
*
|
|
* @returns {boolean} */
|
|
decode(b, offset) {
|
|
return !!super.decode(b, offset);
|
|
}
|
|
/** @override */
|
|
encode(value) {
|
|
if ('boolean' === typeof value) {
|
|
// BitField requires integer values
|
|
value = +value;
|
|
}
|
|
super.encode(value);
|
|
}
|
|
}
|
|
exports.Boolean = Boolean;
|
|
/* eslint-enable no-extend-native */
|
|
/**
|
|
* Contain a fixed-length block of arbitrary data, represented as a
|
|
* Uint8Array.
|
|
*
|
|
* *Factory*: {@link module:Layout.blob|blob}
|
|
*
|
|
* @param {(Number|ExternalLayout)} length - initializes {@link
|
|
* Blob#length|length}.
|
|
*
|
|
* @param {String} [property] - initializer for {@link
|
|
* Layout#property|property}.
|
|
*
|
|
* @augments {Layout}
|
|
*/
|
|
class Blob extends Layout {
|
|
constructor(length, property) {
|
|
if (!(((length instanceof ExternalLayout) && length.isCount())
|
|
|| (Number.isInteger(length) && (0 <= length)))) {
|
|
throw new TypeError('length must be positive integer '
|
|
+ 'or an unsigned integer ExternalLayout');
|
|
}
|
|
let span = -1;
|
|
if (!(length instanceof ExternalLayout)) {
|
|
span = length;
|
|
}
|
|
super(span, property);
|
|
/** The number of bytes in the blob.
|
|
*
|
|
* This may be a non-negative integer, or an instance of {@link
|
|
* ExternalLayout} that satisfies {@link
|
|
* ExternalLayout#isCount|isCount()}. */
|
|
this.length = length;
|
|
}
|
|
/** @override */
|
|
getSpan(b, offset) {
|
|
let span = this.span;
|
|
if (0 > span) {
|
|
span = this.length.decode(b, offset);
|
|
}
|
|
return span;
|
|
}
|
|
/** @override */
|
|
decode(b, offset = 0) {
|
|
let span = this.span;
|
|
if (0 > span) {
|
|
span = this.length.decode(b, offset);
|
|
}
|
|
return uint8ArrayToBuffer(b).slice(offset, offset + span);
|
|
}
|
|
/** Implement {@link Layout#encode|encode} for {@link Blob}.
|
|
*
|
|
* **NOTE** If {@link Layout#count|count} is an instance of {@link
|
|
* ExternalLayout} then the length of `src` will be encoded as the
|
|
* count after `src` is encoded. */
|
|
encode(src, b, offset) {
|
|
let span = this.length;
|
|
if (this.length instanceof ExternalLayout) {
|
|
span = src.length;
|
|
}
|
|
if (!(src instanceof Uint8Array && span === src.length)) {
|
|
throw new TypeError(nameWithProperty('Blob.encode', this)
|
|
+ ' requires (length ' + span + ') Uint8Array as src');
|
|
}
|
|
if ((offset + span) > b.length) {
|
|
throw new RangeError('encoding overruns Uint8Array');
|
|
}
|
|
const srcBuffer = uint8ArrayToBuffer(src);
|
|
uint8ArrayToBuffer(b).write(srcBuffer.toString('hex'), offset, span, 'hex');
|
|
if (this.length instanceof ExternalLayout) {
|
|
this.length.encode(span, b, offset);
|
|
}
|
|
return span;
|
|
}
|
|
}
|
|
exports.Blob = Blob;
|
|
/**
|
|
* Contain a `NUL`-terminated UTF8 string.
|
|
*
|
|
* *Factory*: {@link module:Layout.cstr|cstr}
|
|
*
|
|
* **NOTE** Any UTF8 string that incorporates a zero-valued byte will
|
|
* not be correctly decoded by this layout.
|
|
*
|
|
* @param {String} [property] - initializer for {@link
|
|
* Layout#property|property}.
|
|
*
|
|
* @augments {Layout}
|
|
*/
|
|
class CString extends Layout {
|
|
constructor(property) {
|
|
super(-1, property);
|
|
}
|
|
/** @override */
|
|
getSpan(b, offset = 0) {
|
|
checkUint8Array(b);
|
|
let idx = offset;
|
|
while ((idx < b.length) && (0 !== b[idx])) {
|
|
idx += 1;
|
|
}
|
|
return 1 + idx - offset;
|
|
}
|
|
/** @override */
|
|
decode(b, offset = 0) {
|
|
const span = this.getSpan(b, offset);
|
|
return uint8ArrayToBuffer(b).slice(offset, offset + span - 1).toString('utf-8');
|
|
}
|
|
/** @override */
|
|
encode(src, b, offset = 0) {
|
|
/* Must force this to a string, lest it be a number and the
|
|
* "utf8-encoding" below actually allocate a buffer of length
|
|
* src */
|
|
if ('string' !== typeof src) {
|
|
src = String(src);
|
|
}
|
|
const srcb = buffer_1.Buffer.from(src, 'utf8');
|
|
const span = srcb.length;
|
|
if ((offset + span) > b.length) {
|
|
throw new RangeError('encoding overruns Buffer');
|
|
}
|
|
const buffer = uint8ArrayToBuffer(b);
|
|
srcb.copy(buffer, offset);
|
|
buffer[offset + span] = 0;
|
|
return span + 1;
|
|
}
|
|
}
|
|
exports.CString = CString;
|
|
/**
|
|
* Contain a UTF8 string with implicit length.
|
|
*
|
|
* *Factory*: {@link module:Layout.utf8|utf8}
|
|
*
|
|
* **NOTE** Because the length is implicit in the size of the buffer
|
|
* this layout should be used only in isolation, or in a situation
|
|
* where the length can be expressed by operating on a slice of the
|
|
* containing buffer.
|
|
*
|
|
* @param {Number} [maxSpan] - the maximum length allowed for encoded
|
|
* string content. If not provided there is no bound on the allowed
|
|
* content.
|
|
*
|
|
* @param {String} [property] - initializer for {@link
|
|
* Layout#property|property}.
|
|
*
|
|
* @augments {Layout}
|
|
*/
|
|
class UTF8 extends Layout {
|
|
constructor(maxSpan, property) {
|
|
if (('string' === typeof maxSpan) && (undefined === property)) {
|
|
property = maxSpan;
|
|
maxSpan = undefined;
|
|
}
|
|
if (undefined === maxSpan) {
|
|
maxSpan = -1;
|
|
}
|
|
else if (!Number.isInteger(maxSpan)) {
|
|
throw new TypeError('maxSpan must be an integer');
|
|
}
|
|
super(-1, property);
|
|
/** The maximum span of the layout in bytes.
|
|
*
|
|
* Positive values are generally expected. Zero is abnormal.
|
|
* Attempts to encode or decode a value that exceeds this length
|
|
* will throw a `RangeError`.
|
|
*
|
|
* A negative value indicates that there is no bound on the length
|
|
* of the content. */
|
|
this.maxSpan = maxSpan;
|
|
}
|
|
/** @override */
|
|
getSpan(b, offset = 0) {
|
|
checkUint8Array(b);
|
|
return b.length - offset;
|
|
}
|
|
/** @override */
|
|
decode(b, offset = 0) {
|
|
const span = this.getSpan(b, offset);
|
|
if ((0 <= this.maxSpan)
|
|
&& (this.maxSpan < span)) {
|
|
throw new RangeError('text length exceeds maxSpan');
|
|
}
|
|
return uint8ArrayToBuffer(b).slice(offset, offset + span).toString('utf-8');
|
|
}
|
|
/** @override */
|
|
encode(src, b, offset = 0) {
|
|
/* Must force this to a string, lest it be a number and the
|
|
* "utf8-encoding" below actually allocate a buffer of length
|
|
* src */
|
|
if ('string' !== typeof src) {
|
|
src = String(src);
|
|
}
|
|
const srcb = buffer_1.Buffer.from(src, 'utf8');
|
|
const span = srcb.length;
|
|
if ((0 <= this.maxSpan)
|
|
&& (this.maxSpan < span)) {
|
|
throw new RangeError('text length exceeds maxSpan');
|
|
}
|
|
if ((offset + span) > b.length) {
|
|
throw new RangeError('encoding overruns Buffer');
|
|
}
|
|
srcb.copy(uint8ArrayToBuffer(b), offset);
|
|
return span;
|
|
}
|
|
}
|
|
exports.UTF8 = UTF8;
|
|
/**
|
|
* Contain a constant value.
|
|
*
|
|
* This layout may be used in cases where a JavaScript value can be
|
|
* inferred without an expression in the binary encoding. An example
|
|
* would be a {@link VariantLayout|variant layout} where the content
|
|
* is implied by the union {@link Union#discriminator|discriminator}.
|
|
*
|
|
* @param {Object|Number|String} value - initializer for {@link
|
|
* Constant#value|value}. If the value is an object (or array) and
|
|
* the application intends the object to remain unchanged regardless
|
|
* of what is done to values decoded by this layout, the value should
|
|
* be frozen prior passing it to this constructor.
|
|
*
|
|
* @param {String} [property] - initializer for {@link
|
|
* Layout#property|property}.
|
|
*
|
|
* @augments {Layout}
|
|
*/
|
|
class Constant extends Layout {
|
|
constructor(value, property) {
|
|
super(0, property);
|
|
/** The value produced by this constant when the layout is {@link
|
|
* Constant#decode|decoded}.
|
|
*
|
|
* Any JavaScript value including `null` and `undefined` is
|
|
* permitted.
|
|
*
|
|
* **WARNING** If `value` passed in the constructor was not
|
|
* frozen, it is possible for users of decoded values to change
|
|
* the content of the value. */
|
|
this.value = value;
|
|
}
|
|
/** @override */
|
|
decode(b, offset) {
|
|
return this.value;
|
|
}
|
|
/** @override */
|
|
encode(src, b, offset) {
|
|
/* Constants take no space */
|
|
return 0;
|
|
}
|
|
}
|
|
exports.Constant = Constant;
|
|
/** Factory for {@link GreedyCount}. */
|
|
exports.greedy = ((elementSpan, property) => new GreedyCount(elementSpan, property));
|
|
/** Factory for {@link OffsetLayout}. */
|
|
exports.offset = ((layout, offset, property) => new OffsetLayout(layout, offset, property));
|
|
/** Factory for {@link UInt|unsigned int layouts} spanning one
|
|
* byte. */
|
|
exports.u8 = ((property) => new UInt(1, property));
|
|
/** Factory for {@link UInt|little-endian unsigned int layouts}
|
|
* spanning two bytes. */
|
|
exports.u16 = ((property) => new UInt(2, property));
|
|
/** Factory for {@link UInt|little-endian unsigned int layouts}
|
|
* spanning three bytes. */
|
|
exports.u24 = ((property) => new UInt(3, property));
|
|
/** Factory for {@link UInt|little-endian unsigned int layouts}
|
|
* spanning four bytes. */
|
|
exports.u32 = ((property) => new UInt(4, property));
|
|
/** Factory for {@link UInt|little-endian unsigned int layouts}
|
|
* spanning five bytes. */
|
|
exports.u40 = ((property) => new UInt(5, property));
|
|
/** Factory for {@link UInt|little-endian unsigned int layouts}
|
|
* spanning six bytes. */
|
|
exports.u48 = ((property) => new UInt(6, property));
|
|
/** Factory for {@link NearUInt64|little-endian unsigned int
|
|
* layouts} interpreted as Numbers. */
|
|
exports.nu64 = ((property) => new NearUInt64(property));
|
|
/** Factory for {@link UInt|big-endian unsigned int layouts}
|
|
* spanning two bytes. */
|
|
exports.u16be = ((property) => new UIntBE(2, property));
|
|
/** Factory for {@link UInt|big-endian unsigned int layouts}
|
|
* spanning three bytes. */
|
|
exports.u24be = ((property) => new UIntBE(3, property));
|
|
/** Factory for {@link UInt|big-endian unsigned int layouts}
|
|
* spanning four bytes. */
|
|
exports.u32be = ((property) => new UIntBE(4, property));
|
|
/** Factory for {@link UInt|big-endian unsigned int layouts}
|
|
* spanning five bytes. */
|
|
exports.u40be = ((property) => new UIntBE(5, property));
|
|
/** Factory for {@link UInt|big-endian unsigned int layouts}
|
|
* spanning six bytes. */
|
|
exports.u48be = ((property) => new UIntBE(6, property));
|
|
/** Factory for {@link NearUInt64BE|big-endian unsigned int
|
|
* layouts} interpreted as Numbers. */
|
|
exports.nu64be = ((property) => new NearUInt64BE(property));
|
|
/** Factory for {@link Int|signed int layouts} spanning one
|
|
* byte. */
|
|
exports.s8 = ((property) => new Int(1, property));
|
|
/** Factory for {@link Int|little-endian signed int layouts}
|
|
* spanning two bytes. */
|
|
exports.s16 = ((property) => new Int(2, property));
|
|
/** Factory for {@link Int|little-endian signed int layouts}
|
|
* spanning three bytes. */
|
|
exports.s24 = ((property) => new Int(3, property));
|
|
/** Factory for {@link Int|little-endian signed int layouts}
|
|
* spanning four bytes. */
|
|
exports.s32 = ((property) => new Int(4, property));
|
|
/** Factory for {@link Int|little-endian signed int layouts}
|
|
* spanning five bytes. */
|
|
exports.s40 = ((property) => new Int(5, property));
|
|
/** Factory for {@link Int|little-endian signed int layouts}
|
|
* spanning six bytes. */
|
|
exports.s48 = ((property) => new Int(6, property));
|
|
/** Factory for {@link NearInt64|little-endian signed int layouts}
|
|
* interpreted as Numbers. */
|
|
exports.ns64 = ((property) => new NearInt64(property));
|
|
/** Factory for {@link Int|big-endian signed int layouts}
|
|
* spanning two bytes. */
|
|
exports.s16be = ((property) => new IntBE(2, property));
|
|
/** Factory for {@link Int|big-endian signed int layouts}
|
|
* spanning three bytes. */
|
|
exports.s24be = ((property) => new IntBE(3, property));
|
|
/** Factory for {@link Int|big-endian signed int layouts}
|
|
* spanning four bytes. */
|
|
exports.s32be = ((property) => new IntBE(4, property));
|
|
/** Factory for {@link Int|big-endian signed int layouts}
|
|
* spanning five bytes. */
|
|
exports.s40be = ((property) => new IntBE(5, property));
|
|
/** Factory for {@link Int|big-endian signed int layouts}
|
|
* spanning six bytes. */
|
|
exports.s48be = ((property) => new IntBE(6, property));
|
|
/** Factory for {@link NearInt64BE|big-endian signed int layouts}
|
|
* interpreted as Numbers. */
|
|
exports.ns64be = ((property) => new NearInt64BE(property));
|
|
/** Factory for {@link Float|little-endian 32-bit floating point} values. */
|
|
exports.f32 = ((property) => new Float(property));
|
|
/** Factory for {@link FloatBE|big-endian 32-bit floating point} values. */
|
|
exports.f32be = ((property) => new FloatBE(property));
|
|
/** Factory for {@link Double|little-endian 64-bit floating point} values. */
|
|
exports.f64 = ((property) => new Double(property));
|
|
/** Factory for {@link DoubleBE|big-endian 64-bit floating point} values. */
|
|
exports.f64be = ((property) => new DoubleBE(property));
|
|
/** Factory for {@link Structure} values. */
|
|
exports.struct = ((fields, property, decodePrefixes) => new Structure(fields, property, decodePrefixes));
|
|
/** Factory for {@link BitStructure} values. */
|
|
exports.bits = ((word, msb, property) => new BitStructure(word, msb, property));
|
|
/** Factory for {@link Sequence} values. */
|
|
exports.seq = ((elementLayout, count, property) => new Sequence(elementLayout, count, property));
|
|
/** Factory for {@link Union} values. */
|
|
exports.union = ((discr, defaultLayout, property) => new Union(discr, defaultLayout, property));
|
|
/** Factory for {@link UnionLayoutDiscriminator} values. */
|
|
exports.unionLayoutDiscriminator = ((layout, property) => new UnionLayoutDiscriminator(layout, property));
|
|
/** Factory for {@link Blob} values. */
|
|
exports.blob = ((length, property) => new Blob(length, property));
|
|
/** Factory for {@link CString} values. */
|
|
exports.cstr = ((property) => new CString(property));
|
|
/** Factory for {@link UTF8} values. */
|
|
exports.utf8 = ((maxSpan, property) => new UTF8(maxSpan, property));
|
|
/** Factory for {@link Constant} values. */
|
|
exports.constant = ((value, property) => new Constant(value, property));
|
|
//# sourceMappingURL=Layout.js.map
|