Files
packet.ts/src/index.ts

864 lines
28 KiB
TypeScript

/**
* A utility class for reading various primitive types and strings from an ArrayBuffer,
* supporting configurable byte order (endianness).
*/
export class Reader {
private buffer: ArrayBuffer;
private view: DataView;
private offset: number;
private littleEndian: boolean;
constructor(buffer: ArrayBuffer | ArrayBufferLike | Uint8Array, littleEndian: boolean = true) {
if (buffer instanceof ArrayBuffer) {
this.buffer = buffer;
} else if (buffer instanceof Uint8Array || ArrayBuffer.isView(buffer)) {
const srcBuffer = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
this.buffer = srcBuffer instanceof ArrayBuffer ? srcBuffer : new ArrayBuffer(srcBuffer.byteLength);
} else {
throw new TypeError("Invalid buffer type. Expected ArrayBuffer, Uint8Array, or ArrayBufferView.");
}
this.view = new DataView(this.buffer);
this.offset = 0;
this.littleEndian = littleEndian;
}
/**
* Read a boolean value from the buffer. A boolean is stored as a single byte, where 0 represents
* `false` and any non-zero value represents `true`.
*
* @returns A boolean value read from the buffer.
*/
public bool(): boolean {
this.checkBounds(1);
const value = this.view.getUint8(this.offset);
this.offset += 1;
return value !== 0;
}
/**
* Read an 8-bit character from the buffer at the current offset, and advance the offset by 1 byte.
* @returns A string containing the character read from the buffer.
*/
public char(): string {
this.checkBounds(1);
const value = this.view.getUint8(this.offset);
this.offset += 1;
return String.fromCharCode(value);
}
/**
* Read an 8-bit signed integer from the buffer at the current offset, and advance the offset by 1 byte.
*
* @returns An 8-bit signed integer read from the buffer.
*/
public int8(): number {
this.checkBounds(1);
const value = this.view.getInt8(this.offset);
this.offset += 1;
return value;
}
/**
* Read a 16-bit signed integer from the buffer at the current offset, using the specified byte order, and
* advance the offset by 2 bytes.
*
* @returns A 16-bit signed integer read from the buffer.
*/
public int16(): number {
this.checkBounds(2);
const value = this.view.getInt16(this.offset, this.littleEndian);
this.offset += 2;
return value;
}
/**
* Read a 32-bit signed integer from the buffer at the current offset, using the specified byte order, and
* advance the offset by 4 bytes.
*
* @returns A 32-bit signed integer read from the buffer.
*/
public int32(): number {
this.checkBounds(4);
const value = this.view.getInt32(this.offset, this.littleEndian);
this.offset += 4;
return value;
}
/**
* Read a 64-bit signed integer from the buffer at the current offset, using the specified byte order, and
* advance the offset by 8 bytes.
*
* @returns A 64-bit signed integer read from the buffer.
*/
public int64(): bigint {
this.checkBounds(8);
const value = this.view.getBigInt64(this.offset, this.littleEndian);
this.offset += 8;
return value;
}
/**
* Read an 8-bit unsigned integer from the buffer at the current offset, and advance the offset by 1 byte.
*
* @returns An 8-bit unsigned integer read from the buffer.
*/
public uint8(): number {
this.checkBounds(1);
const value = this.view.getUint8(this.offset);
this.offset += 1;
return value;
}
/**
* Read a 16-bit unsigned integer from the buffer at the current offset, using the specified byte order, and
* advance the offset by 2 bytes.
*
* @returns A 16-bit unsigned integer read from the buffer.
*/
public uint16(): number {
this.checkBounds(2);
const value = this.view.getUint16(this.offset, this.littleEndian);
this.offset += 2;
return value;
}
/**
* Read a 32-bit unsigned integer from the buffer at the current offset, using the specified byte order, and
* advance the offset by 4 bytes.
*
* @returns A 32-bit unsigned integer read from the buffer.
*/
public uint32(): number {
this.checkBounds(4);
const value = this.view.getUint32(this.offset, this.littleEndian);
this.offset += 4;
return value;
}
/**
* Read a 64-bit unsigned integer from the buffer at the current offset, using the specified byte order, and
* advance the offset by 8 bytes.
*
* @returns A 64-bit unsigned integer read from the buffer.
*/
public uint64(): bigint {
this.checkBounds(8);
const value = this.view.getBigUint64(this.offset, this.littleEndian);
this.offset += 8;
return value;
}
/**
* Read a 32-bit floating point number from the buffer at the current offset, using the specified byte order, and
* advance the offset by 4 bytes.
*
* @returns A 32-bit floating point number read from the buffer.
*/
public float32(): number {
this.checkBounds(4);
const value = this.view.getFloat32(this.offset, this.littleEndian);
this.offset += 4;
return value;
}
/**
* Read a 64-bit floating point number from the buffer at the current offset, using the specified byte order, and
* advance the offset by 8 bytes.
*
* @returns A 64-bit floating point number read from the buffer.
*/
public float64(): number {
this.checkBounds(8);
const value = this.view.getFloat64(this.offset, this.littleEndian);
this.offset += 8;
return value;
}
/**
* Read a variable-length unsigned integer from the buffer using LEB128 encoding. The method reads
* bytes until it encounters a byte with the most significant bit (MSB) set to 0, which indicates
* the end of the varint.
*
* The value is constructed by concatenating the lower 7 bits of each byte, and shifting them
* according to their position.
*
* @returns A number representing the decoded unsigned varint value.
*/
public varint(): number {
let result = 0;
let shift = 0;
while (true) {
this.checkBounds(1);
const byte = this.view.getUint8(this.offset++);
result |= (byte & 0x7f) << shift;
if ((byte & 0x80) === 0) {
break; // Last byte of the varint
}
shift += 7;
}
return result;
}
/**
* Read a variable-length signed integer from the buffer using LEB128 encoding. The method reads
* bytes until it encounters a byte with the most significant bit (MSB) set to 0, which indicates
* the end of the varint.
*
* The value is constructed by concatenating the lower 7 bits of each byte, and shifting them
* according to their position. If the sign bit (the highest bit of the last byte) is set, the
* result is sign-extended to produce a negative number.
*
* @returns A number representing the decoded signed varint value.
*/
public varsint(): number {
let result = 0;
let shift = 0;
while (true) {
this.checkBounds(1);
const byte = this.view.getUint8(this.offset++);
result |= (byte & 0x7f) << shift;
if ((byte & 0x80) === 0) {
break; // Last byte of the varint
}
shift += 7;
}
// Sign-extend the result if the sign bit is set
if (shift < 32 && (result & (1 << (shift - 1))) !== 0) {
result |= ~0 << shift;
}
return result;
}
/**
* Read a 32-bit date (stored as 32-bit seconds since epoch).
*
* @returns A Date object representing the date/time read from the buffer.
*/
public date32(): Date {
this.checkBounds(4);
const timestamp = this.view.getUint32(this.offset, this.littleEndian);
this.offset += 4;
return new Date(timestamp * 1000); // Convert seconds to milliseconds
}
/**
* Read a 64-bit date (stored as 64-bit milliseconds since epoch).
*
* @returns A Date object representing the date/time read from the buffer.
*/
public date64(): Date {
this.checkBounds(8);
const timestamp = this.view.getBigUint64(this.offset, this.littleEndian);
this.offset += 8;
return new Date(Number(timestamp)); // Convert bigint to number (ms since epoch)
}
/**
* Read a sequence of bytes from the buffer. If length is not provided, reads until the end of the buffer.
*
* @param length The number of bytes to read. If not provided, reads until the end of the buffer.
* @returns A Uint8Array containing the bytes read from the buffer.
*/
public bytes(length?: number): Uint8Array {
if (length === undefined) {
length = this.view.byteLength - this.offset;
}
this.checkBounds(length);
const bytes = new Uint8Array(this.view.buffer, this.offset, length);
this.offset += length;
return bytes;
}
/**
* Read a null-terminated C-style string from the buffer. Reads bytes until a null terminator
* (0 byte) is found or the end of the buffer is reached, and decodes them as a UTF-8 string.
*
* @returns A string containing the decoded characters up to the null terminator or the end of the buffer.
*/
public cString(): string {
const bytes = [];
while (this.offset < this.view.byteLength) {
const byte = this.view.getUint8(this.offset++);
if (byte === 0) {
break; // Null terminator found
}
bytes.push(byte);
}
return new TextDecoder().decode(new Uint8Array(bytes));
}
/**
* Read a UTF-8 encoded string from the buffer. If length is provided, reads that many bytes and
* decodes them as a UTF-8 string.
*
* @param length The number of bytes to read. If not provided, reads until the end of the buffer.
* @returns A string containing the decoded characters.
*/
public utf8String(length?: number): string {
if (length === undefined) {
length = this.view.byteLength - this.offset;
}
this.checkBounds(length);
const bytes = new Uint8Array(this.view.buffer, this.offset, length);
this.offset += length;
return new TextDecoder().decode(bytes);
}
/**
* Read an array of 16-bit words.
*
* @param length The number of 16-bit words to read.
* @returns A Uint16Array containing the words read from the buffer.
*/
public words(length: number): Uint16Array {
this.checkBounds(length * 2);
const bytes = new Uint8Array(this.view.buffer, this.offset, length * 2);
const copy = bytes.slice();
const words = new Uint16Array(copy.buffer);
this.offset += length * 2;
return words;
}
/**
* Read an array of 32-bit double words.
*
* @param length The number of 32-bit double words to read.
* @returns A Uint32Array containing the double words read from the buffer.
*/
public dwords(length: number): Uint32Array {
this.checkBounds(length * 4);
const bytes = new Uint8Array(this.view.buffer, this.offset, length * 4);
const copy = bytes.slice();
const dwords = new Uint32Array(copy.buffer);
this.offset += length * 4;
return dwords;
}
/**
* Read an array of 64-bit quad words.
*
* @param length The number of 64-bit quad words to read.
* @returns A BigUint64Array containing the quad words read from the buffer.
*/
public qwords(length: number): BigUint64Array {
this.checkBounds(length * 8);
const bytes = new Uint8Array(this.view.buffer, this.offset, length * 8);
const copy = bytes.slice();
const qwords = new BigUint64Array(copy.buffer);
this.offset += length * 8;
return qwords;
}
public static fromBytes(bytes: Uint8Array, littleEndian: boolean = true): Reader {
return new Reader(bytes, littleEndian);
}
public static fromString(
str: string,
encoding: "utf8" | "ascii" | "hex" | "base64" | "rawbase64" | "urlbase64" | "rawurlbase64" = "utf8",
littleEndian: boolean = true
): Reader {
let bytes: Uint8Array;
switch (encoding) {
case "utf8":
bytes = new TextEncoder().encode(str);
break;
case "ascii":
bytes = new Uint8Array(str.split("").map((c) => c.charCodeAt(0)));
break;
case "hex":
bytes = new Uint8Array(str.length / 2);
for (let i = 0; i < bytes.length; i++) {
bytes[i] = parseInt(str.substr(i * 2, 2), 16);
}
break;
case "base64":
bytes = Uint8Array.from(atob(str), (c) => c.charCodeAt(0));
break;
case "rawbase64":
bytes = Uint8Array.from(atob(str.replace(/-/g, "+").replace(/_/g, "/")), (c) => c.charCodeAt(0));
break;
case "urlbase64":
bytes = Uint8Array.from(atob(str.replace(/-/g, "+").replace(/_/g, "/")), (c) => c.charCodeAt(0));
break;
case "rawurlbase64":
bytes = Uint8Array.from(atob(str.replace(/-/g, "+").replace(/_/g, "/")), (c) => c.charCodeAt(0));
break;
}
return new Reader(bytes.slice().buffer, littleEndian);
}
/* Aliases */
/* Alias for bool */
public flag(): boolean {
return this.bool();
}
/* Alias for utf8String */
public string(length: number): string {
return this.utf8String(length);
}
private checkBounds(length: number) {
if (this.offset + length > this.view.byteLength) {
throw new RangeError(
`Attempt to read beyond end of buffer: offset=${this.offset}, length=${length}, bufferLength=${this.view.byteLength}`
);
}
}
}
/**
* A utility class for writing various primitive types and strings into an ArrayBuffer,
* supporting configurable byte order (endianness).
*
* @remarks
* The `BufferWriter` provides methods to write signed and unsigned integers, floating-point numbers,
* booleans, dates, raw bytes, and strings into an internal buffer. The byte order for multi-byte
* values is determined by the provided `ByteOrder` implementation.
*
* @example
* ```typescript
* const writer = new BufferWriter(16, LittleEndian);
* writer.int32(42);
* writer.string("hello");
* ```
*/
export class Writer {
private buffer: ArrayBuffer;
private view: DataView;
private offset: number;
private littleEndian: boolean;
constructor(size: number, littleEndian: boolean = true) {
this.buffer = new ArrayBuffer(size);
this.view = new DataView(this.buffer);
this.offset = 0;
this.littleEndian = littleEndian;
}
// Methods for writing various types will go here (e.g., writeInt8, writeUInt16LE, etc.)
public bool(value: boolean): void {
this.checkBounds(1);
this.view.setUint8(this.offset, value ? 1 : 0);
this.offset += 1;
}
/**
* Write an 8-bit character to the buffer at the current offset, and advance the offset by 1 byte.
*
* @param value The character or its ASCII code to write.
*/
public char(value: string | number): void {
if (typeof value === "string") {
if (value.length !== 1) {
throw new Error("Input must be a single character");
}
this.checkBounds(1);
this.view.setUint8(this.offset, value.charCodeAt(0));
} else if (typeof value === "number") {
this.checkBounds(1);
this.view.setUint8(this.offset, value);
} else {
throw new Error("Input must be a string or number");
}
this.offset += 1;
}
/**
* Write an 8-bit signed integer to the buffer at the current offset, and advance the offset by
* 1 byte.
*
* @param value The 8-bit signed integer to write.
*/
public int8(value: number): void {
this.checkBounds(1);
this.view.setInt8(this.offset, value);
this.offset += 1;
}
/**
* Write a 16-bit signed integer to the buffer at the current offset, using the specified byte
* order, and advance the offset by 2 bytes.
*
* @param value The 16-bit signed integer to write.
*/
public int16(value: number): void {
this.checkBounds(2);
this.view.setInt16(this.offset, value, this.littleEndian);
this.offset += 2;
}
/**
* Write a 32-bit signed integer to the buffer at the current offset, using the specified byte
* order, and advance the offset by 4 bytes.
*
* @param value The 32-bit signed integer to write.
*/
public int32(value: number): void {
this.checkBounds(4);
this.view.setInt32(this.offset, value, this.littleEndian);
this.offset += 4;
}
/**
* Write a 64-bit signed integer to the buffer at the current offset, using the specified byte
* order, and advance the offset by 8 bytes.
*
* @param value The 64-bit signed integer to write.
*/
public int64(value: number | bigint): void {
this.checkBounds(8);
if (typeof value === "number") {
value = BigInt(value);
}
this.view.setBigInt64(this.offset, value, this.littleEndian);
this.offset += 8;
}
/**
* Write an 8-bit unsigned integer to the buffer at the current offset, and advance the offset by
* 1 byte.
*
* @param value The 8-bit unsigned integer to write.
*/
public uint8(value: number): void {
this.checkBounds(1);
this.view.setUint8(this.offset, value);
this.offset += 1;
}
/**
* Write a 16-bit unsigned integer to the buffer at the current offset, using the specified byte
* order, and advance the offset by 2 bytes.
*
* @param value The 16-bit unsigned integer to write.
*/
public uint16(value: number): void {
this.checkBounds(2);
this.view.setUint16(this.offset, value, this.littleEndian);
this.offset += 2;
}
/**
* Write a 32-bit unsigned integer to the buffer at the current offset, using the specified byte
* order, and advance the offset by 4 bytes.
*
* @param value The 32-bit unsigned integer to write.
*/
public uint32(value: number): void {
this.checkBounds(4);
this.view.setUint32(this.offset, value, this.littleEndian);
this.offset += 4;
}
/**
* Write a 64-bit unsigned integer to the buffer at the current offset, using the specified byte
* order, and advance the offset by 8 bytes.
*
* @param value The 64-bit unsigned integer to write.
*/
public uint64(value: number | bigint): void {
this.checkBounds(8);
if (typeof value === "number") {
value = BigInt(value);
}
this.view.setBigUint64(this.offset, value, this.littleEndian);
this.offset += 8;
}
/**
* Write a 32-bit floating point number to the buffer at the current offset, using the specified byte
* order, and advance the offset by 4 bytes.
*
* @param value The 32-bit floating point number to write.
*/
public float32(value: number): void {
this.checkBounds(4);
this.view.setFloat32(this.offset, value, this.littleEndian);
this.offset += 4;
}
/**
* Write a 64-bit floating point number to the buffer at the current offset, using the specified byte
* order, and advance the offset by 8 bytes.
*
* @param value The 64-bit floating point number to write.
*/
public float64(value: number): void {
this.checkBounds(8);
this.view.setFloat64(this.offset, value, this.littleEndian);
this.offset += 8;
}
/**
* Write a variable-length unsigned integer to the buffer using LEB128 encoding. The method encodes the
* value in one or more bytes, where each byte has the most significant bit (MSB) set to 1 if there
* are more bytes to follow, and 0 if it is the last byte. The lower 7 bits of each byte contain
* the data, and the value is constructed by concatenating these bits and shifting them according to
* their position.
*
* @param value The unsigned integer to encode as a varint.
*/
public varint(value: number): void {
this.checkBounds(Writer.varintSize(value));
// Calculate the number of bytes needed to encode the varint
// (does not actually advance the offset or write)
// Useful for pre-sizing buffers.
let remaining = value >>> 0; // Ensure unsigned
while (remaining >= 0x80) {
this.view.setUint8(this.offset++, (remaining & 0x7f) | 0x80);
remaining >>>= 7;
}
this.view.setUint8(this.offset++, remaining);
}
/**
* Write a variable-length signed integer to the buffer using LEB128 encoding. The method encodes the
* value in one or more bytes, where each byte has the most significant bit (MSB) set to 1 if there
* are more bytes to follow, and 0 if it is the last byte. The lower 7 bits of each byte contain
* the data, and the value is constructed by concatenating these bits and shifting them according to
* their position. If the sign bit (the highest bit of the last byte) is set, the result is
* sign-extended to produce a negative number.
*
* @param value The signed integer to encode as a varint.
*/
public varsint(value: number): void {
this.checkBounds(Writer.varintSize(value));
let remaining = value >>> 0; // Ensure unsigned
const isNegative = value < 0;
while (remaining >= 0x80 || (isNegative && remaining < 0x80)) {
this.view.setUint8(this.offset++, (remaining & 0x7f) | 0x80);
remaining >>>= 7;
}
this.view.setUint8(this.offset++, remaining);
}
private static varintSize(value: number): number {
let size = 1;
let v = value >>> 0;
while (v >= 0x80) {
v >>>= 7;
size++;
}
return size;
}
/**
* Write a 32-bit date (stored as seconds since epoch) to the buffer at the current offset, using the
* specified byte order, and advance the offset by 4 bytes.
*
* @param value The Date object to write as a 32-bit timestamp.
*/
public date32(value: Date): void {
const timestamp = Math.floor(value.getTime() / 1000); // Convert ms to seconds
this.checkBounds(4);
this.view.setUint32(this.offset, timestamp, this.littleEndian);
this.offset += 4;
}
/**
* Write a 64-bit date (stored as milliseconds since epoch) to the buffer at the current offset,
* using the specified byte order, and advance the offset by 8 bytes.
*
* @param value The Date object to write as a 64-bit timestamp.
*/
public date64(value: Date): void {
const timestamp = BigInt(value.getTime()); // Get time in ms as bigint
this.checkBounds(8);
this.view.setBigUint64(this.offset, timestamp, this.littleEndian);
this.offset += 8;
}
/**
* Write a sequence of bytes to the buffer at the current offset, and advance the offset by the
* length of the data.
*
* @param data The sequence of bytes to write.
*/
public bytes(data: Uint8Array): void {
this.checkBounds(data.length);
new Uint8Array(this.buffer, this.offset, data.length).set(data);
this.offset += data.length;
}
/**
* Write a null-terminated C-style string to the buffer at the current offset, and advance the
* offset by the length of the string plus one byte for the null terminator.
*
* @param value The string to write as a null-terminated C-style string.
*/
public cString(value: string): void {
const encoder = new TextEncoder();
const bytes = encoder.encode(value);
this.checkBounds(bytes.length + 1); // +1 for null terminator
new Uint8Array(this.buffer, this.offset, bytes.length).set(bytes);
this.view.setUint8(this.offset + bytes.length, 0); // Null terminator
this.offset += bytes.length + 1;
}
/**
* Write a UTF-8 encoded string to the buffer at the current offset, and advance the offset by the
* length of the encoded string.
*
* @param value The string to write as a UTF-8 encoded string.
*/
public utf8String(value: string): void {
const encoder = new TextEncoder();
const bytes = encoder.encode(value);
this.checkBounds(bytes.length);
new Uint8Array(this.buffer, this.offset, bytes.length).set(bytes);
this.offset += bytes.length;
}
/**
* Convert the internal buffer to a Uint8Array containing the bytes that have been written so far.
* The returned Uint8Array shares the same underlying ArrayBuffer, but is sliced to include only
* the bytes up to the current offset.
*
* @returns A Uint8Array containing the bytes that have been written so far.
*/
public toBytes(): Uint8Array {
return new Uint8Array(this.buffer, 0, this.offset);
}
/**
* Convert the internal buffer to a string using the specified encoding. The method first converts
* the buffer to a Uint8Array containing the bytes that have been written so far, and then encodes
* it according to the specified encoding.
*
* The supported encodings are:
* - 'utf-8': Decodes the bytes as a UTF-8 string.
* - 'hex': Encodes the bytes as a hexadecimal string.
* - 'base64': Encodes the bytes as a Base64 string.
* - 'rawbase64': Encodes the bytes as a URL-safe Base64 string without padding.
* - 'urlbase64': Encodes the bytes as a URL-safe Base64 string with padding.
* - 'rawurlbase64': Encodes the bytes as a URL-safe Base64 string without padding.
*
* @param encoding The encoding to use for the string conversion.
* @returns The encoded string.
*/
public toString(encoding: "utf-8" | "hex" | "base64" | "rawbase64" | "urlbase64" | "rawurlbase64" = "utf-8"): string {
const bytes = this.toBytes();
switch (encoding) {
case "utf-8":
return new TextDecoder().decode(bytes);
case "hex":
return Array.from(bytes)
.map((b) => b.toString(16).padStart(2, "0"))
.join("");
case "base64":
return btoa(String.fromCharCode(...bytes));
case "rawbase64":
return btoa(String.fromCharCode(...bytes))
.replace(/\+/g, "-")
.replace(/\//g, "_")
.replace(/=+$/, "");
case "urlbase64":
return btoa(String.fromCharCode(...bytes))
.replace(/\+/g, "-")
.replace(/\//g, "_");
case "rawurlbase64":
return btoa(String.fromCharCode(...bytes))
.replace(/\+/g, "-")
.replace(/\//g, "_")
.replace(/=+$/, "");
default:
throw new Error(`Unsupported encoding: ${encoding}`);
}
}
public static fromString(
value: string,
encoding: "utf-8" | "hex" | "base64" | "rawbase64" | "urlbase64" | "rawurlbase64" = "utf-8",
littleEndian: boolean = true
): Writer {
let bytes: Uint8Array;
switch (encoding) {
case "utf-8":
bytes = new TextEncoder().encode(value);
break;
case "hex":
bytes = new Uint8Array(value.match(/.{1,2}/g)!.map((byte) => parseInt(byte, 16)));
break;
case "base64":
bytes = Uint8Array.from(atob(value), (c) => c.charCodeAt(0));
break;
case "rawbase64":
bytes = Uint8Array.from(atob(value.replace(/-/g, "+").replace(/_/g, "/")), (c) => c.charCodeAt(0));
break;
case "urlbase64":
bytes = Uint8Array.from(atob(value.replace(/-/g, "+").replace(/_/g, "/")), (c) => c.charCodeAt(0));
break;
case "rawurlbase64":
bytes = Uint8Array.from(atob(value.replace(/-/g, "+").replace(/_/g, "/")), (c) => c.charCodeAt(0));
break;
default:
throw new Error(`Unsupported encoding: ${encoding}`);
}
const writer = new Writer(bytes.length, littleEndian);
writer.bytes(bytes);
return writer;
}
/* Aliases */
/* Alias for bool */
public flag(value: boolean): void {
this.bool(value);
}
/* Alias for utf8String */
public string(value: string): void {
this.utf8String(value);
}
private checkBounds(length: number) {
if (this.offset + length > this.view.byteLength) {
throw new RangeError(
`Attempt to write beyond end of buffer: offset=${this.offset}, length=${length}, bufferLength=${this.view.byteLength}`
);
}
}
}
// Exporting types and utilities for external use:
export * from "./types";
export {
FieldType,
type Packet,
type Protocol,
type Dissected,
type Segment,
type Field,
type BitField
} from "./types";
export {
I8,
I16,
I32,
U8,
U16,
U32,
F32,
F64,
isBytes,
assertBytes,
equalBytes,
constantTimeEqualBytes,
base64ToBytes,
bytesToBase64,
hexToBytes,
bytesToHex,
decodeBytes,
encodeBytes,
type TypedArray,
type HexEncoding,
type Base64Encoding,
type Base64RawEncoding,
type Base64URLEncoding,
type Base64RawURLEncoding,
type Encoding
} from "./utils";