diff --git a/src/cjs/browser.cjs b/src/cjs/browser.cjs index 607fe23..24ce7e8 100644 --- a/src/cjs/browser.cjs +++ b/src/cjs/browser.cjs @@ -1,6 +1,6 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -exports.compare = exports.fromHex = exports.toHex = exports.toUtf8 = void 0; +exports.readUInt64 = exports.readUInt32 = exports.readUInt16 = exports.readUInt8 = exports.writeUInt64 = exports.writeUInt32 = exports.writeUInt16 = exports.writeUInt8 = exports.compare = exports.fromHex = exports.toHex = exports.toUtf8 = void 0; const HEX_STRINGS = "0123456789abcdefABCDEF"; const HEX_CODES = HEX_STRINGS.split("").map((c) => c.codePointAt(0)); const HEX_CODEPOINTS = Array(256) @@ -71,3 +71,163 @@ function compare(v1, v2) { return v1.length === v2.length ? 0 : v1.length > v2.length ? 1 : -1; } exports.compare = compare; +function writeUInt8(buffer, offset, value) { + if (offset + 1 > buffer.length) { + throw new Error("Offset is outside the bounds of Uint8Array"); + } + if (value > 0xff) { + throw new Error(`The value of "value" is out of range. It must be >= 0 and <= ${0xff}. Received ${value}`); + } + buffer[offset] = value; +} +exports.writeUInt8 = writeUInt8; +function writeUInt16(buffer, offset, value, littleEndian) { + if (offset + 2 > buffer.length) { + throw new Error("Offset is outside the bounds of Uint8Array"); + } + littleEndian = littleEndian.toUpperCase(); + if (value > 0xffff) { + throw new Error(`The value of "value" is out of range. It must be >= 0 and <= ${0xffff}. Received ${value}`); + } + if (littleEndian === "LE") { + buffer[offset] = value & 0xff; + buffer[offset + 1] = (value >> 8) & 0xff; + } + else { + buffer[offset] = (value >> 8) & 0xff; + buffer[offset + 1] = value & 0xff; + } +} +exports.writeUInt16 = writeUInt16; +function writeUInt32(buffer, offset, value, littleEndian) { + if (offset + 4 > buffer.length) { + throw new Error("Offset is outside the bounds of Uint8Array"); + } + littleEndian = littleEndian.toUpperCase(); + if (value > 0xffffffff) { + throw new Error(`The value of "value" is out of range. It must be >= 0 and <= ${0xffffffff}. Received ${value}`); + } + if (littleEndian === "LE") { + buffer[offset] = value & 0xff; + buffer[offset + 1] = (value >> 8) & 0xff; + buffer[offset + 2] = (value >> 16) & 0xff; + buffer[offset + 3] = (value >> 24) & 0xff; + } + else { + buffer[offset] = (value >> 24) & 0xff; + buffer[offset + 1] = (value >> 16) & 0xff; + buffer[offset + 2] = (value >> 8) & 0xff; + buffer[offset + 3] = value & 0xff; + } +} +exports.writeUInt32 = writeUInt32; +function writeUInt64(buffer, offset, value, littleEndian) { + if (offset + 8 > buffer.length) { + throw new Error("Offset is outside the bounds of Uint8Array"); + } + littleEndian = littleEndian.toUpperCase(); + if (value > 0xffffffffffffffffn) { + throw new Error(`The value of "value" is out of range. It must be >= 0 and <= ${0xffffffffffffffffn}. Received ${value}`); + } + if (littleEndian === "LE") { + buffer[offset] = Number(value & 0xffn); + buffer[offset + 1] = Number((value >> 8n) & 0xffn); + buffer[offset + 2] = Number((value >> 16n) & 0xffn); + buffer[offset + 3] = Number((value >> 24n) & 0xffn); + buffer[offset + 4] = Number((value >> 32n) & 0xffn); + buffer[offset + 5] = Number((value >> 40n) & 0xffn); + buffer[offset + 6] = Number((value >> 48n) & 0xffn); + buffer[offset + 7] = Number((value >> 56n) & 0xffn); + } + else { + buffer[offset] = Number((value >> 56n) & 0xffn); + buffer[offset + 1] = Number((value >> 48n) & 0xffn); + buffer[offset + 2] = Number((value >> 40n) & 0xffn); + buffer[offset + 3] = Number((value >> 32n) & 0xffn); + buffer[offset + 4] = Number((value >> 24n) & 0xffn); + buffer[offset + 5] = Number((value >> 16n) & 0xffn); + buffer[offset + 6] = Number((value >> 8n) & 0xffn); + buffer[offset + 7] = Number(value & 0xffn); + } +} +exports.writeUInt64 = writeUInt64; +function readUInt8(buffer, offset) { + if (offset + 1 > buffer.length) { + throw new Error("Offset is outside the bounds of Uint8Array"); + } + return buffer[offset]; +} +exports.readUInt8 = readUInt8; +function readUInt16(buffer, offset, littleEndian) { + if (offset + 2 > buffer.length) { + throw new Error("Offset is outside the bounds of Uint8Array"); + } + littleEndian = littleEndian.toUpperCase(); + if (littleEndian === "LE") { + let num = 0; + num = (num << 8) + buffer[offset + 1]; + num = (num << 8) + buffer[offset]; + return num; + } + else { + let num = 0; + num = (num << 8) + buffer[offset]; + num = (num << 8) + buffer[offset + 1]; + return num; + } +} +exports.readUInt16 = readUInt16; +function readUInt32(buffer, offset, littleEndian) { + if (offset + 4 > buffer.length) { + throw new Error("Offset is outside the bounds of Uint8Array"); + } + littleEndian = littleEndian.toUpperCase(); + if (littleEndian === "LE") { + let num = 0; + num = ((num << 8) + buffer[offset + 3]) >>> 0; + num = ((num << 8) + buffer[offset + 2]) >>> 0; + num = ((num << 8) + buffer[offset + 1]) >>> 0; + num = ((num << 8) + buffer[offset]) >>> 0; + return num; + } + else { + let num = 0; + num = ((num << 8) + buffer[offset]) >>> 0; + num = ((num << 8) + buffer[offset + 1]) >>> 0; + num = ((num << 8) + buffer[offset + 2]) >>> 0; + num = ((num << 8) + buffer[offset + 3]) >>> 0; + return num; + } +} +exports.readUInt32 = readUInt32; +function readUInt64(buffer, offset, littleEndian) { + if (offset + 8 > buffer.length) { + throw new Error("Offset is outside the bounds of Uint8Array"); + } + littleEndian = littleEndian.toUpperCase(); + if (littleEndian === "LE") { + let num = 0n; + num = (num << 8n) + BigInt(buffer[offset + 7]); + num = (num << 8n) + BigInt(buffer[offset + 6]); + num = (num << 8n) + BigInt(buffer[offset + 5]); + num = (num << 8n) + BigInt(buffer[offset + 4]); + num = (num << 8n) + BigInt(buffer[offset + 3]); + num = (num << 8n) + BigInt(buffer[offset + 2]); + num = (num << 8n) + BigInt(buffer[offset + 1]); + num = (num << 8n) + BigInt(buffer[offset]); + return num; + } + else { + let num = 0n; + num = (num << 8n) + BigInt(buffer[offset]); + num = (num << 8n) + BigInt(buffer[offset + 1]); + num = (num << 8n) + BigInt(buffer[offset + 2]); + num = (num << 8n) + BigInt(buffer[offset + 3]); + num = (num << 8n) + BigInt(buffer[offset + 4]); + num = (num << 8n) + BigInt(buffer[offset + 5]); + num = (num << 8n) + BigInt(buffer[offset + 6]); + num = (num << 8n) + BigInt(buffer[offset + 7]); + return num; + } +} +exports.readUInt64 = readUInt64; diff --git a/src/cjs/index.cjs b/src/cjs/index.cjs index 473f705..597469a 100644 --- a/src/cjs/index.cjs +++ b/src/cjs/index.cjs @@ -1,6 +1,6 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -exports.compare = exports.fromHex = exports.toHex = exports.toUtf8 = void 0; +exports.readUInt64 = exports.readUInt32 = exports.readUInt16 = exports.readUInt8 = exports.writeUInt64 = exports.writeUInt32 = exports.writeUInt16 = exports.writeUInt8 = exports.compare = exports.fromHex = exports.toHex = exports.toUtf8 = void 0; function toUtf8(bytes) { return Buffer.from(bytes || []).toString(); } @@ -17,3 +17,110 @@ function compare(v1, v2) { return Buffer.from(v1).compare(Buffer.from(v2)); } exports.compare = compare; +function writeUInt8(buffer, offset, value) { + if (offset + 1 > buffer.length) { + throw new Error("Offset is outside the bounds of Uint8Array"); + } + const buf = Buffer.alloc(1); + buf.writeUInt8(value, 0); + buffer.set(Uint8Array.from(buf), offset); +} +exports.writeUInt8 = writeUInt8; +function writeUInt16(buffer, offset, value, littleEndian) { + if (offset + 2 > buffer.length) { + throw new Error("Offset is outside the bounds of Uint8Array"); + } + littleEndian = littleEndian.toUpperCase(); + const buf = Buffer.alloc(2); + if (littleEndian === "LE") { + buf.writeUInt16LE(value, 0); + } + else { + buf.writeUInt16BE(value, 0); + } + buffer.set(Uint8Array.from(buf), offset); +} +exports.writeUInt16 = writeUInt16; +function writeUInt32(buffer, offset, value, littleEndian) { + if (offset + 4 > buffer.length) { + throw new Error("Offset is outside the bounds of Uint8Array"); + } + littleEndian = littleEndian.toUpperCase(); + const buf = Buffer.alloc(4); + if (littleEndian === "LE") { + buf.writeUInt32LE(value, 0); + } + else { + buf.writeUInt32BE(value, 0); + } + buffer.set(Uint8Array.from(buf), offset); +} +exports.writeUInt32 = writeUInt32; +function writeUInt64(buffer, offset, value, littleEndian) { + if (offset + 8 > buffer.length) { + throw new Error("Offset is outside the bounds of Uint8Array"); + } + littleEndian = littleEndian.toUpperCase(); + const buf = Buffer.alloc(8); + if (value > 0xffffffffffffffffn) { + throw new Error(`The value of "value" is out of range. It must be >= 0 and <= ${0xffffffffffffffffn}. Received ${value}`); + } + if (littleEndian === "LE") { + buf.writeBigUInt64LE(value, 0); + } + else { + buf.writeBigUInt64BE(value, 0); + } + buffer.set(Uint8Array.from(buf), offset); +} +exports.writeUInt64 = writeUInt64; +function readUInt8(buffer, offset) { + if (offset + 1 > buffer.length) { + throw new Error("Offset is outside the bounds of Uint8Array"); + } + const buf = Buffer.from(buffer); + return buf.readUInt8(offset); +} +exports.readUInt8 = readUInt8; +function readUInt16(buffer, offset, littleEndian) { + if (offset + 2 > buffer.length) { + throw new Error("Offset is outside the bounds of Uint8Array"); + } + littleEndian = littleEndian.toUpperCase(); + const buf = Buffer.from(buffer); + if (littleEndian === "LE") { + return buf.readUInt16LE(offset); + } + else { + return buf.readUInt16BE(offset); + } +} +exports.readUInt16 = readUInt16; +function readUInt32(buffer, offset, littleEndian) { + if (offset + 4 > buffer.length) { + throw new Error("Offset is outside the bounds of Uint8Array"); + } + littleEndian = littleEndian.toUpperCase(); + const buf = Buffer.from(buffer); + if (littleEndian === "LE") { + return buf.readUInt32LE(offset); + } + else { + return buf.readUInt32BE(offset); + } +} +exports.readUInt32 = readUInt32; +function readUInt64(buffer, offset, littleEndian) { + if (offset + 8 > buffer.length) { + throw new Error("Offset is outside the bounds of Uint8Array"); + } + littleEndian = littleEndian.toUpperCase(); + const buf = Buffer.from(buffer); + if (littleEndian === "LE") { + return buf.readBigUInt64LE(offset); + } + else { + return buf.readBigUInt64BE(offset); + } +} +exports.readUInt64 = readUInt64; diff --git a/src/cjs/index.d.ts b/src/cjs/index.d.ts index 2a1717a..d618b5b 100644 --- a/src/cjs/index.d.ts +++ b/src/cjs/index.d.ts @@ -3,3 +3,12 @@ export declare function toHex(bytes: Uint8Array): string; export declare function fromHex(hexString: string): Uint8Array; export declare type CompareResult = -1 | 0 | 1; export declare function compare(v1: Uint8Array, v2: Uint8Array): CompareResult; +export declare type endian = "LE" | "BE" | "le" | "be"; +export declare function writeUInt8(buffer: Uint8Array, offset: number, value: number): void; +export declare function writeUInt16(buffer: Uint8Array, offset: number, value: number, littleEndian: endian): void; +export declare function writeUInt32(buffer: Uint8Array, offset: number, value: number, littleEndian: endian): void; +export declare function writeUInt64(buffer: Uint8Array, offset: number, value: bigint, littleEndian: endian): void; +export declare function readUInt8(buffer: Uint8Array, offset: number): number; +export declare function readUInt16(buffer: Uint8Array, offset: number, littleEndian: endian): number; +export declare function readUInt32(buffer: Uint8Array, offset: number, littleEndian: endian): number; +export declare function readUInt64(buffer: Uint8Array, offset: number, littleEndian: endian): bigint; diff --git a/src/mjs/browser.js b/src/mjs/browser.js index 89379f0..171ab80 100644 --- a/src/mjs/browser.js +++ b/src/mjs/browser.js @@ -64,3 +64,155 @@ export function compare(v1, v2) { } return v1.length === v2.length ? 0 : v1.length > v2.length ? 1 : -1; } +export function writeUInt8(buffer, offset, value) { + if (offset + 1 > buffer.length) { + throw new Error("Offset is outside the bounds of Uint8Array"); + } + if (value > 0xff) { + throw new Error(`The value of "value" is out of range. It must be >= 0 and <= ${0xff}. Received ${value}`); + } + buffer[offset] = value; +} +export function writeUInt16(buffer, offset, value, littleEndian) { + if (offset + 2 > buffer.length) { + throw new Error("Offset is outside the bounds of Uint8Array"); + } + littleEndian = littleEndian.toUpperCase(); + if (value > 0xffff) { + throw new Error(`The value of "value" is out of range. It must be >= 0 and <= ${0xffff}. Received ${value}`); + } + if (littleEndian === "LE") { + buffer[offset] = value & 0xff; + buffer[offset + 1] = (value >> 8) & 0xff; + } + else { + buffer[offset] = (value >> 8) & 0xff; + buffer[offset + 1] = value & 0xff; + } +} +export function writeUInt32(buffer, offset, value, littleEndian) { + if (offset + 4 > buffer.length) { + throw new Error("Offset is outside the bounds of Uint8Array"); + } + littleEndian = littleEndian.toUpperCase(); + if (value > 0xffffffff) { + throw new Error(`The value of "value" is out of range. It must be >= 0 and <= ${0xffffffff}. Received ${value}`); + } + if (littleEndian === "LE") { + buffer[offset] = value & 0xff; + buffer[offset + 1] = (value >> 8) & 0xff; + buffer[offset + 2] = (value >> 16) & 0xff; + buffer[offset + 3] = (value >> 24) & 0xff; + } + else { + buffer[offset] = (value >> 24) & 0xff; + buffer[offset + 1] = (value >> 16) & 0xff; + buffer[offset + 2] = (value >> 8) & 0xff; + buffer[offset + 3] = value & 0xff; + } +} +export function writeUInt64(buffer, offset, value, littleEndian) { + if (offset + 8 > buffer.length) { + throw new Error("Offset is outside the bounds of Uint8Array"); + } + littleEndian = littleEndian.toUpperCase(); + if (value > 0xffffffffffffffffn) { + throw new Error(`The value of "value" is out of range. It must be >= 0 and <= ${0xffffffffffffffffn}. Received ${value}`); + } + if (littleEndian === "LE") { + buffer[offset] = Number(value & 0xffn); + buffer[offset + 1] = Number((value >> 8n) & 0xffn); + buffer[offset + 2] = Number((value >> 16n) & 0xffn); + buffer[offset + 3] = Number((value >> 24n) & 0xffn); + buffer[offset + 4] = Number((value >> 32n) & 0xffn); + buffer[offset + 5] = Number((value >> 40n) & 0xffn); + buffer[offset + 6] = Number((value >> 48n) & 0xffn); + buffer[offset + 7] = Number((value >> 56n) & 0xffn); + } + else { + buffer[offset] = Number((value >> 56n) & 0xffn); + buffer[offset + 1] = Number((value >> 48n) & 0xffn); + buffer[offset + 2] = Number((value >> 40n) & 0xffn); + buffer[offset + 3] = Number((value >> 32n) & 0xffn); + buffer[offset + 4] = Number((value >> 24n) & 0xffn); + buffer[offset + 5] = Number((value >> 16n) & 0xffn); + buffer[offset + 6] = Number((value >> 8n) & 0xffn); + buffer[offset + 7] = Number(value & 0xffn); + } +} +export function readUInt8(buffer, offset) { + if (offset + 1 > buffer.length) { + throw new Error("Offset is outside the bounds of Uint8Array"); + } + return buffer[offset]; +} +export function readUInt16(buffer, offset, littleEndian) { + if (offset + 2 > buffer.length) { + throw new Error("Offset is outside the bounds of Uint8Array"); + } + littleEndian = littleEndian.toUpperCase(); + if (littleEndian === "LE") { + let num = 0; + num = (num << 8) + buffer[offset + 1]; + num = (num << 8) + buffer[offset]; + return num; + } + else { + let num = 0; + num = (num << 8) + buffer[offset]; + num = (num << 8) + buffer[offset + 1]; + return num; + } +} +export function readUInt32(buffer, offset, littleEndian) { + if (offset + 4 > buffer.length) { + throw new Error("Offset is outside the bounds of Uint8Array"); + } + littleEndian = littleEndian.toUpperCase(); + if (littleEndian === "LE") { + let num = 0; + num = ((num << 8) + buffer[offset + 3]) >>> 0; + num = ((num << 8) + buffer[offset + 2]) >>> 0; + num = ((num << 8) + buffer[offset + 1]) >>> 0; + num = ((num << 8) + buffer[offset]) >>> 0; + return num; + } + else { + let num = 0; + num = ((num << 8) + buffer[offset]) >>> 0; + num = ((num << 8) + buffer[offset + 1]) >>> 0; + num = ((num << 8) + buffer[offset + 2]) >>> 0; + num = ((num << 8) + buffer[offset + 3]) >>> 0; + return num; + } +} +export function readUInt64(buffer, offset, littleEndian) { + if (offset + 8 > buffer.length) { + throw new Error("Offset is outside the bounds of Uint8Array"); + } + littleEndian = littleEndian.toUpperCase(); + if (littleEndian === "LE") { + let num = 0n; + num = (num << 8n) + BigInt(buffer[offset + 7]); + num = (num << 8n) + BigInt(buffer[offset + 6]); + num = (num << 8n) + BigInt(buffer[offset + 5]); + num = (num << 8n) + BigInt(buffer[offset + 4]); + num = (num << 8n) + BigInt(buffer[offset + 3]); + num = (num << 8n) + BigInt(buffer[offset + 2]); + num = (num << 8n) + BigInt(buffer[offset + 1]); + num = (num << 8n) + BigInt(buffer[offset]); + return num; + } + else { + let num = 0n; + num = (num << 8n) + BigInt(buffer[offset]); + num = (num << 8n) + BigInt(buffer[offset + 1]); + num = (num << 8n) + BigInt(buffer[offset + 2]); + num = (num << 8n) + BigInt(buffer[offset + 3]); + num = (num << 8n) + BigInt(buffer[offset + 4]); + num = (num << 8n) + BigInt(buffer[offset + 5]); + num = (num << 8n) + BigInt(buffer[offset + 6]); + num = (num << 8n) + BigInt(buffer[offset + 7]); + return num; + } +} diff --git a/src/mjs/index.js b/src/mjs/index.js index 8d35bf4..53004d5 100644 --- a/src/mjs/index.js +++ b/src/mjs/index.js @@ -10,3 +10,102 @@ export function fromHex(hexString) { export function compare(v1, v2) { return Buffer.from(v1).compare(Buffer.from(v2)); } +export function writeUInt8(buffer, offset, value) { + if (offset + 1 > buffer.length) { + throw new Error("Offset is outside the bounds of Uint8Array"); + } + const buf = Buffer.alloc(1); + buf.writeUInt8(value, 0); + buffer.set(Uint8Array.from(buf), offset); +} +export function writeUInt16(buffer, offset, value, littleEndian) { + if (offset + 2 > buffer.length) { + throw new Error("Offset is outside the bounds of Uint8Array"); + } + littleEndian = littleEndian.toUpperCase(); + const buf = Buffer.alloc(2); + if (littleEndian === "LE") { + buf.writeUInt16LE(value, 0); + } + else { + buf.writeUInt16BE(value, 0); + } + buffer.set(Uint8Array.from(buf), offset); +} +export function writeUInt32(buffer, offset, value, littleEndian) { + if (offset + 4 > buffer.length) { + throw new Error("Offset is outside the bounds of Uint8Array"); + } + littleEndian = littleEndian.toUpperCase(); + const buf = Buffer.alloc(4); + if (littleEndian === "LE") { + buf.writeUInt32LE(value, 0); + } + else { + buf.writeUInt32BE(value, 0); + } + buffer.set(Uint8Array.from(buf), offset); +} +export function writeUInt64(buffer, offset, value, littleEndian) { + if (offset + 8 > buffer.length) { + throw new Error("Offset is outside the bounds of Uint8Array"); + } + littleEndian = littleEndian.toUpperCase(); + const buf = Buffer.alloc(8); + if (value > 0xffffffffffffffffn) { + throw new Error(`The value of "value" is out of range. It must be >= 0 and <= ${0xffffffffffffffffn}. Received ${value}`); + } + if (littleEndian === "LE") { + buf.writeBigUInt64LE(value, 0); + } + else { + buf.writeBigUInt64BE(value, 0); + } + buffer.set(Uint8Array.from(buf), offset); +} +export function readUInt8(buffer, offset) { + if (offset + 1 > buffer.length) { + throw new Error("Offset is outside the bounds of Uint8Array"); + } + const buf = Buffer.from(buffer); + return buf.readUInt8(offset); +} +export function readUInt16(buffer, offset, littleEndian) { + if (offset + 2 > buffer.length) { + throw new Error("Offset is outside the bounds of Uint8Array"); + } + littleEndian = littleEndian.toUpperCase(); + const buf = Buffer.from(buffer); + if (littleEndian === "LE") { + return buf.readUInt16LE(offset); + } + else { + return buf.readUInt16BE(offset); + } +} +export function readUInt32(buffer, offset, littleEndian) { + if (offset + 4 > buffer.length) { + throw new Error("Offset is outside the bounds of Uint8Array"); + } + littleEndian = littleEndian.toUpperCase(); + const buf = Buffer.from(buffer); + if (littleEndian === "LE") { + return buf.readUInt32LE(offset); + } + else { + return buf.readUInt32BE(offset); + } +} +export function readUInt64(buffer, offset, littleEndian) { + if (offset + 8 > buffer.length) { + throw new Error("Offset is outside the bounds of Uint8Array"); + } + littleEndian = littleEndian.toUpperCase(); + const buf = Buffer.from(buffer); + if (littleEndian === "LE") { + return buf.readBigUInt64LE(offset); + } + else { + return buf.readBigUInt64BE(offset); + } +} diff --git a/ts_src/browser.ts b/ts_src/browser.ts index 57f5a5f..f8b6c7f 100644 --- a/ts_src/browser.ts +++ b/ts_src/browser.ts @@ -69,3 +69,212 @@ export function compare(v1: Uint8Array, v2: Uint8Array): CompareResult { } return v1.length === v2.length ? 0 : v1.length > v2.length ? 1 : -1; } + +export type endian = "LE" | "BE" | "le" | "be"; + +export function writeUInt8( + buffer: Uint8Array, + offset: number, + value: number +): void { + if (offset + 1 > buffer.length) { + throw new Error("Offset is outside the bounds of Uint8Array"); + } + + if (value > 0xff) { + throw new Error( + `The value of "value" is out of range. It must be >= 0 and <= ${0xff}. Received ${value}` + ); + } + + buffer[offset] = value; +} + +export function writeUInt16( + buffer: Uint8Array, + offset: number, + value: number, + littleEndian: endian +): void { + if (offset + 2 > buffer.length) { + throw new Error("Offset is outside the bounds of Uint8Array"); + } + littleEndian = littleEndian.toUpperCase() as endian; + if (value > 0xffff) { + throw new Error( + `The value of "value" is out of range. It must be >= 0 and <= ${0xffff}. Received ${value}` + ); + } + + if (littleEndian === "LE") { + buffer[offset] = value & 0xff; + buffer[offset + 1] = (value >> 8) & 0xff; + } else { + buffer[offset] = (value >> 8) & 0xff; + buffer[offset + 1] = value & 0xff; + } +} + +export function writeUInt32( + buffer: Uint8Array, + offset: number, + value: number, + littleEndian: endian +): void { + if (offset + 4 > buffer.length) { + throw new Error("Offset is outside the bounds of Uint8Array"); + } + + littleEndian = littleEndian.toUpperCase() as endian; + + if (value > 0xffffffff) { + throw new Error( + `The value of "value" is out of range. It must be >= 0 and <= ${0xffffffff}. Received ${value}` + ); + } + + if (littleEndian === "LE") { + buffer[offset] = value & 0xff; + buffer[offset + 1] = (value >> 8) & 0xff; + buffer[offset + 2] = (value >> 16) & 0xff; + buffer[offset + 3] = (value >> 24) & 0xff; + } else { + buffer[offset] = (value >> 24) & 0xff; + buffer[offset + 1] = (value >> 16) & 0xff; + buffer[offset + 2] = (value >> 8) & 0xff; + buffer[offset + 3] = value & 0xff; + } +} + +export function writeUInt64( + buffer: Uint8Array, + offset: number, + value: bigint, + littleEndian: endian +): void { + if (offset + 8 > buffer.length) { + throw new Error("Offset is outside the bounds of Uint8Array"); + } + littleEndian = littleEndian.toUpperCase() as endian; + + if (value > 0xffffffffffffffffn) { + throw new Error( + `The value of "value" is out of range. It must be >= 0 and <= ${0xffffffffffffffffn}. Received ${value}` + ); + } + + if (littleEndian === "LE") { + buffer[offset] = Number(value & 0xffn); + buffer[offset + 1] = Number((value >> 8n) & 0xffn); + buffer[offset + 2] = Number((value >> 16n) & 0xffn); + buffer[offset + 3] = Number((value >> 24n) & 0xffn); + buffer[offset + 4] = Number((value >> 32n) & 0xffn); + buffer[offset + 5] = Number((value >> 40n) & 0xffn); + buffer[offset + 6] = Number((value >> 48n) & 0xffn); + buffer[offset + 7] = Number((value >> 56n) & 0xffn); + } else { + buffer[offset] = Number((value >> 56n) & 0xffn); + buffer[offset + 1] = Number((value >> 48n) & 0xffn); + buffer[offset + 2] = Number((value >> 40n) & 0xffn); + buffer[offset + 3] = Number((value >> 32n) & 0xffn); + buffer[offset + 4] = Number((value >> 24n) & 0xffn); + buffer[offset + 5] = Number((value >> 16n) & 0xffn); + buffer[offset + 6] = Number((value >> 8n) & 0xffn); + buffer[offset + 7] = Number(value & 0xffn); + } +} + +export function readUInt8(buffer: Uint8Array, offset: number): number { + if (offset + 1 > buffer.length) { + throw new Error("Offset is outside the bounds of Uint8Array"); + } + + return buffer[offset]; +} + +export function readUInt16( + buffer: Uint8Array, + offset: number, + littleEndian: endian +): number { + if (offset + 2 > buffer.length) { + throw new Error("Offset is outside the bounds of Uint8Array"); + } + + littleEndian = littleEndian.toUpperCase() as endian; + if (littleEndian === "LE") { + let num = 0; + num = (num << 8) + buffer[offset + 1]; + num = (num << 8) + buffer[offset]; + return num; + } else { + let num = 0; + num = (num << 8) + buffer[offset]; + num = (num << 8) + buffer[offset + 1]; + return num; + } +} + +export function readUInt32( + buffer: Uint8Array, + offset: number, + littleEndian: endian +): number { + if (offset + 4 > buffer.length) { + throw new Error("Offset is outside the bounds of Uint8Array"); + } + + littleEndian = littleEndian.toUpperCase() as endian; + + if (littleEndian === "LE") { + let num = 0; + num = ((num << 8) + buffer[offset + 3]) >>> 0; + num = ((num << 8) + buffer[offset + 2]) >>> 0; + num = ((num << 8) + buffer[offset + 1]) >>> 0; + num = ((num << 8) + buffer[offset]) >>> 0; + return num; + } else { + let num = 0; + num = ((num << 8) + buffer[offset]) >>> 0; + num = ((num << 8) + buffer[offset + 1]) >>> 0; + num = ((num << 8) + buffer[offset + 2]) >>> 0; + num = ((num << 8) + buffer[offset + 3]) >>> 0; + return num; + } +} + +export function readUInt64( + buffer: Uint8Array, + offset: number, + littleEndian: endian +): bigint { + if (offset + 8 > buffer.length) { + throw new Error("Offset is outside the bounds of Uint8Array"); + } + + littleEndian = littleEndian.toUpperCase() as endian; + + if (littleEndian === "LE") { + let num = 0n; + num = (num << 8n) + BigInt(buffer[offset + 7]); + num = (num << 8n) + BigInt(buffer[offset + 6]); + num = (num << 8n) + BigInt(buffer[offset + 5]); + num = (num << 8n) + BigInt(buffer[offset + 4]); + num = (num << 8n) + BigInt(buffer[offset + 3]); + num = (num << 8n) + BigInt(buffer[offset + 2]); + num = (num << 8n) + BigInt(buffer[offset + 1]); + num = (num << 8n) + BigInt(buffer[offset]); + return num; + } else { + let num = 0n; + num = (num << 8n) + BigInt(buffer[offset]); + num = (num << 8n) + BigInt(buffer[offset + 1]); + num = (num << 8n) + BigInt(buffer[offset + 2]); + num = (num << 8n) + BigInt(buffer[offset + 3]); + num = (num << 8n) + BigInt(buffer[offset + 4]); + num = (num << 8n) + BigInt(buffer[offset + 5]); + num = (num << 8n) + BigInt(buffer[offset + 6]); + num = (num << 8n) + BigInt(buffer[offset + 7]); + return num; + } +} diff --git a/ts_src/index.ts b/ts_src/index.ts index deb373b..cd5cbeb 100644 --- a/ts_src/index.ts +++ b/ts_src/index.ts @@ -14,3 +14,160 @@ export type CompareResult = -1 | 0 | 1; export function compare(v1: Uint8Array, v2: Uint8Array): CompareResult { return Buffer.from(v1).compare(Buffer.from(v2)) as CompareResult; } + +export type endian = "LE" | "BE" | "le" | "be"; + +export function writeUInt8( + buffer: Uint8Array, + offset: number, + value: number +): void { + if (offset + 1 > buffer.length) { + throw new Error("Offset is outside the bounds of Uint8Array"); + } + + const buf = Buffer.alloc(1); + buf.writeUInt8(value, 0); + buffer.set(Uint8Array.from(buf), offset); +} + +export function writeUInt16( + buffer: Uint8Array, + offset: number, + value: number, + littleEndian: endian +): void { + if (offset + 2 > buffer.length) { + throw new Error("Offset is outside the bounds of Uint8Array"); + } + + littleEndian = littleEndian.toUpperCase() as endian; + + const buf = Buffer.alloc(2); + + if (littleEndian === "LE") { + buf.writeUInt16LE(value, 0); + } else { + buf.writeUInt16BE(value, 0); + } + buffer.set(Uint8Array.from(buf), offset); +} + +export function writeUInt32( + buffer: Uint8Array, + offset: number, + value: number, + littleEndian: endian +): void { + if (offset + 4 > buffer.length) { + throw new Error("Offset is outside the bounds of Uint8Array"); + } + + littleEndian = littleEndian.toUpperCase() as endian; + + const buf = Buffer.alloc(4); + + if (littleEndian === "LE") { + buf.writeUInt32LE(value, 0); + } else { + buf.writeUInt32BE(value, 0); + } + buffer.set(Uint8Array.from(buf), offset); +} + +export function writeUInt64( + buffer: Uint8Array, + offset: number, + value: bigint, + littleEndian: endian +): void { + if (offset + 8 > buffer.length) { + throw new Error("Offset is outside the bounds of Uint8Array"); + } + + littleEndian = littleEndian.toUpperCase() as endian; + + const buf = Buffer.alloc(8); + + if (value > 0xffffffffffffffffn) { + throw new Error( + `The value of "value" is out of range. It must be >= 0 and <= ${0xffffffffffffffffn}. Received ${value}` + ); + } + + if (littleEndian === "LE") { + buf.writeBigUInt64LE(value, 0); + } else { + buf.writeBigUInt64BE(value, 0); + } + buffer.set(Uint8Array.from(buf), offset); +} + +export function readUInt8(buffer: Uint8Array, offset: number): number { + if (offset + 1 > buffer.length) { + throw new Error("Offset is outside the bounds of Uint8Array"); + } + + const buf = Buffer.from(buffer); + return buf.readUInt8(offset); +} + +export function readUInt16( + buffer: Uint8Array, + offset: number, + littleEndian: endian +): number { + if (offset + 2 > buffer.length) { + throw new Error("Offset is outside the bounds of Uint8Array"); + } + + littleEndian = littleEndian.toUpperCase() as endian; + + const buf = Buffer.from(buffer); + + if (littleEndian === "LE") { + return buf.readUInt16LE(offset); + } else { + return buf.readUInt16BE(offset); + } +} + +export function readUInt32( + buffer: Uint8Array, + offset: number, + littleEndian: endian +): number { + if (offset + 4 > buffer.length) { + throw new Error("Offset is outside the bounds of Uint8Array"); + } + + littleEndian = littleEndian.toUpperCase() as endian; + + const buf = Buffer.from(buffer); + + if (littleEndian === "LE") { + return buf.readUInt32LE(offset); + } else { + return buf.readUInt32BE(offset); + } +} + +export function readUInt64( + buffer: Uint8Array, + offset: number, + littleEndian: endian +): bigint { + if (offset + 8 > buffer.length) { + throw new Error("Offset is outside the bounds of Uint8Array"); + } + + littleEndian = littleEndian.toUpperCase() as endian; + + const buf = Buffer.from(buffer); + + if (littleEndian === "LE") { + return buf.readBigUInt64LE(offset); + } else { + return buf.readBigUInt64BE(offset); + } +} diff --git a/ts_src/tests.spec.ts b/ts_src/tests.spec.ts index 427da31..ef95876 100644 --- a/ts_src/tests.spec.ts +++ b/ts_src/tests.spec.ts @@ -62,6 +62,284 @@ describe(`Uint8Array tools`, () => { expect(tools.compare(bytes2, bytes2LargerLeft)).toBe(1); expect(tools.compare(bytes2LargerLeft, bytes2)).toBe(-1); }); + it("should writeUint8", () => { + const hexs = ["03", "fd"]; + + for (const hex of hexs) { + const actualArray = new Uint8Array(1); + const expectedArray = Buffer.alloc(1); + + tools.writeUInt8(actualArray, 0, Number.parseInt(hex, 16)); + expectedArray.writeUInt8(Number.parseInt(hex, 16), 0); + + expect(expectedArray.toString("hex")).toEqual( + tools.toHex(actualArray) + ); + } + }); + + it("should writeUint16", () => { + const hexs = ["0300", "0003", "fdff", "fffd"]; + + for (const hex of hexs) { + const actualArray = new Uint8Array(2); + const expectedArray = Buffer.alloc(2); + + for (const endian of ["BE", "LE"]) { + tools.writeUInt16( + actualArray, + 0, + Number.parseInt(hex, 16), + endian as browser.endian + ); + expectedArray[ + ("writeUInt16" + endian) as "writeUInt16LE" | "writeUInt16BE" + ](Number.parseInt(hex, 16), 0); + + expect(expectedArray.toString("hex")).toEqual( + tools.toHex(actualArray) + ); + } + } + }); + + it("should writeUint32", () => { + const hexs = ["03000000", "00000003", "fdffffff", "fffffffd"]; + + for (const hex of hexs) { + const actualArray = new Uint8Array(4); + const expectedArray = Buffer.alloc(4); + + for (const endian of ["BE", "LE"]) { + tools.writeUInt32( + actualArray, + 0, + Number.parseInt(hex, 16), + endian as browser.endian + ); + expectedArray[ + ("writeUInt32" + endian) as "writeUInt32LE" | "writeUInt32BE" + ](Number.parseInt(hex, 16), 0); + + expect(expectedArray.toString("hex")).toEqual( + tools.toHex(actualArray) + ); + } + } + }); + + it("should writeUint64", () => { + const hexs = [ + "0300000000000000", + "0000000000000003", + "fdffffffffffffff", + "fffffffffffffffd", + ]; + + for (const hex of hexs) { + const actualArray = new Uint8Array(8); + const expectedArray = Buffer.alloc(8); + + for (const endian of ["BE", "LE"]) { + tools.writeUInt64( + actualArray, + 0, + BigInt("0x" + hex), + endian as browser.endian + ); + expectedArray[ + ("writeBigUInt64" + endian) as + | "writeBigUInt64LE" + | "writeBigUInt64BE" + ](BigInt("0x" + hex), 0); + + expect(expectedArray.toString("hex")).toEqual( + tools.toHex(actualArray) + ); + } + } + }); + + it("should throw an error when offset is out of bounds", () => { + const bytes = new Uint8Array(100); + + expect(() => + tools.writeUInt8(bytes, bytes.length - 1 + 1, 1) + ).toThrowError(new Error("Offset is outside the bounds of Uint8Array")); + + expect(() => + tools.writeUInt16(bytes, bytes.length - 2 + 1, 1, "LE") + ).toThrowError(new Error("Offset is outside the bounds of Uint8Array")); + + expect(() => + tools.writeUInt32(bytes, bytes.length - 4 + 1, 1, "LE") + ).toThrowError(new Error("Offset is outside the bounds of Uint8Array")); + + expect(() => + tools.writeUInt64(bytes, bytes.length - 8 + 1, 1n, "LE") + ).toThrowError(new Error("Offset is outside the bounds of Uint8Array")); + }); + + it("should write at the correct offset", () => { + const actualArray = new Uint8Array(100); + const expectedArray = Buffer.alloc(100); + let hex = "03"; + const offset = 50; + + tools.writeUInt8(actualArray, offset, Number.parseInt(hex, 16)); + expectedArray.writeUInt8(Number.parseInt(hex, 16), offset); + + expect(expectedArray.toString("hex")).toEqual(tools.toHex(actualArray)); + + hex = "0300"; + + tools.writeUInt16(actualArray, offset, Number.parseInt(hex, 16), "LE"); + expectedArray.writeUInt16LE(Number.parseInt(hex, 16), offset); + + expect(expectedArray.toString("hex")).toEqual(tools.toHex(actualArray)); + + tools.writeUInt16(actualArray, offset, Number.parseInt(hex, 16), "BE"); + expectedArray.writeUInt16BE(Number.parseInt(hex, 16), offset); + + expect(expectedArray.toString("hex")).toEqual(tools.toHex(actualArray)); + + hex = "03000000"; + + tools.writeUInt32(actualArray, offset, Number.parseInt(hex, 16), "LE"); + expectedArray.writeUInt32LE(Number.parseInt(hex, 16), offset); + + expect(expectedArray.toString("hex")).toEqual(tools.toHex(actualArray)); + + tools.writeUInt32(actualArray, offset, Number.parseInt(hex, 16), "BE"); + expectedArray.writeUInt32BE(Number.parseInt(hex, 16), offset); + + expect(expectedArray.toString("hex")).toEqual(tools.toHex(actualArray)); + + hex = "0300000000000000"; + + tools.writeUInt64(actualArray, offset, BigInt("0x" + hex), "LE"); + expectedArray.writeBigUInt64LE(BigInt("0x" + hex), offset); + + expect(expectedArray.toString("hex")).toEqual(tools.toHex(actualArray)); + + tools.writeUInt64(actualArray, offset, BigInt("0x" + hex), "BE"); + expectedArray.writeBigUInt64BE(BigInt("0x" + hex), offset); + + expect(expectedArray.toString("hex")).toEqual(tools.toHex(actualArray)); + }); + it("should throw an error on overflow", () => { + let bytes = new Uint8Array(1); + + let overflowVal = 0xffn + 1n; + expect(() => tools.writeUInt8(bytes, 0, 0xff + 1)).toThrowError( + `The value of "value" is out of range. It must be >= 0 and <= ${0xffn}. Received ${overflowVal}` + ); + + bytes = new Uint8Array(2); + overflowVal = 0xffffn + 1n; + + expect(() => + tools.writeUInt16(bytes, 0, 0xffff + 1, "LE") + ).toThrowError( + `The value of "value" is out of range. It must be >= 0 and <= ${0xffffn}. Received ${overflowVal}` + ); + + bytes = new Uint8Array(4); + overflowVal = 0xffffffffn + 1n; + + expect(() => + tools.writeUInt32(bytes, 0, 0xffffffff + 1, "LE") + ).toThrowError( + `The value of "value" is out of range. It must be >= 0 and <= ${0xffffffffn}. Received ${overflowVal}` + ); + + bytes = new Uint8Array(8); + overflowVal = 0xffffffffffffffffn + 1n; + + expect(() => + tools.writeUInt64(bytes, 0, 0xffffffffffffffffn + 1n, "LE") + ).toThrowError( + `The value of "value" is out of range. It must be >= 0 and <= ${0xffffffffffffffffn.toString()}. Received ${overflowVal}` + ); + }); + + it("should read bytes at the correct offset", () => { + const actualArray = new Uint8Array(200); + const expectedArray = Buffer.alloc(200); + + let hex = "ff"; + tools.writeUInt8(actualArray, 0, Number.parseInt(hex, 16)); + expectedArray.writeUInt8(Number.parseInt(hex, 16), 0); + + expect(expectedArray.readUInt8(0)).toEqual( + tools.readUInt8(actualArray, 0) + ); + + hex = "abcd"; + tools.writeUInt16(actualArray, 10, Number.parseInt(hex, 16), "LE"); + expectedArray.writeUInt16LE(Number.parseInt(hex, 16), 10); + + expect(expectedArray.readUInt16LE(10)).toEqual( + tools.readUInt16(actualArray, 10, "LE") + ); + + tools.writeUInt16(actualArray, 20, Number.parseInt(hex, 16), "BE"); + expectedArray.writeUInt16BE(Number.parseInt(hex, 16), 20); + + expect(expectedArray.readUInt16BE(20)).toEqual( + tools.readUInt16(actualArray, 20, "BE") + ); + + hex = "ffffabff"; + tools.writeUInt32(actualArray, 30, Number.parseInt(hex, 16), "LE"); + expectedArray.writeUInt32LE(Number.parseInt(hex, 16), 30); + + expect(expectedArray.readUInt32LE(30)).toEqual( + tools.readUInt32(actualArray, 30, "LE") + ); + + tools.writeUInt32(actualArray, 50, Number.parseInt(hex, 16), "BE"); + expectedArray.writeUInt32BE(Number.parseInt(hex, 16), 50); + + expect(expectedArray.readUInt32BE(50)).toEqual( + tools.readUInt32(actualArray, 50, "BE") + ); + + hex = "ffffffffffffabff"; + tools.writeUInt64(actualArray, 70, BigInt("0x" + hex), "LE"); + expectedArray.writeBigUInt64LE(BigInt("0x" + hex), 70); + + expect(expectedArray.readBigUInt64LE(70)).toEqual( + tools.readUInt64(actualArray, 70, "LE") + ); + + tools.writeUInt64(actualArray, 110, BigInt("0x" + hex), "BE"); + expectedArray.writeBigUInt64BE(BigInt("0x" + hex), 110); + + expect(expectedArray.readBigUInt64BE(110)).toEqual( + tools.readUInt64(actualArray, 110, "BE") + ); + }); + + it("should throw an error if the offset is out of bounds", () => { + const arr = new Uint8Array(10); + + expect(() => tools.readUInt8(arr, 10)).toThrowError( + new Error("Offset is outside the bounds of Uint8Array") + ); + + const fns = [tools.readUInt16, tools.readUInt32, tools.readUInt64]; + + for (const fn of fns) { + expect(() => fn(arr, 10, "LE")).toThrowError( + new Error("Offset is outside the bounds of Uint8Array") + ); + + expect(() => fn(arr, 10, "BE")).toThrowError( + new Error("Offset is outside the bounds of Uint8Array") + ); + } + }); }); } }); diff --git a/tsconfig-cjs.json b/tsconfig-cjs.json index bcb355b..a57f605 100644 --- a/tsconfig-cjs.json +++ b/tsconfig-cjs.json @@ -3,7 +3,7 @@ "compilerOptions": { "module": "commonjs", "outDir": "src/cjs", - "target": "es2015", + "target": "es2020", "declaration": true } -} \ No newline at end of file +}