@chickenjdk/byteutils
Version:
Some utilitys for working with binary data
387 lines (386 loc) • 17 kB
JavaScript
"use strict";
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
if (kind === "m") throw new TypeError("Private method is not writable");
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
};
var _readableBufferBase_isLe, _readableBuffer_buffer, _readableBuffer_index;
Object.defineProperty(exports, "__esModule", { value: true });
exports.readableBufferLe = exports.readableBuffer = exports.readableBufferBaseAsync = exports.readableBufferBase = void 0;
const utf8tools_1 = require("./utf8tools");
const common_1 = require("./common");
const constants = {
// 11111111111111111111111111111111
allOnes: 0xffffffff,
// 10000000000000000000000000000000
oneThen31Zeros: 0x80000000,
// 11111111111111111111111100000000
allOnesButLastByte: 0xffffff00,
};
class readableBufferBase {
constructor() {
/**
* Read a array OR Uint8Array from the start of the buffer
* @param bytes How many bytes to read
*/
this.read = this.readUint8Array;
/**
* Read a array OR Uint8Array from the start of the buffer backwards
* @param bytes How many bytes to read
*/
this.readBackwards = this.readUint8ArrayBackwards;
// "real" code
// Little-endian support: <-
/**
* Read a Uint8Array from the start of the buffer (endian-dependent)
*/
this.readUint8ArrayEndian = this.readUint8Array;
/**
* Read a Uint8Array from the start of the buffer backwards (endian-dependent)
*/
this.readUint8ArrayBackwardsEndian = this.readUint8ArrayBackwards;
/**
* Read a number array (0-255) from the start of the buffer (endian-dependent)
* @param bytes How many bytes to read
*/
this.readArrayEndian = this.readArray;
/**
* Read a number array (0-255) from the start of the buffer backwards (endian-dependent)
* @param bytes How many bytes to read
*/
this.readArrayBackwardsEndian = this.readArrayBackwards;
/**
* Read a array-like (May be a array or uint8array but don't count on it) from the start of the buffer (endian-dependent)
* @param value The data to write
*/
this.readEndian = this.read;
/**
* Read a array-like (May be a array or uint8array but don't count on it) from the start of the buffer backwards (endian-dependent)
*/
this.readBackwardsEndian = this.readBackwards;
_readableBufferBase_isLe.set(this, false);
}
/**
* Read a ReadableBuffer from the start of the buffer
* @param bytes How many bytes to read
*/
readReadableBuffer(bytes) {
return (0, common_1.maybePromiseThen)(this.readUint8Array(bytes), (read) => new readableBuffer(read));
}
/**
* If the buffer is little endian
*/
get isLe() {
return __classPrivateFieldGet(this, _readableBufferBase_isLe, "f");
}
/**
* If the buffer is little endian
*/
set isLe(isLe) {
if (isLe) {
this.readEndian = this.readBackwards;
this.readBackwardsEndian = this.read;
this.readUint8ArrayEndian = this.readUint8ArrayBackwards;
}
else {
this.readEndian = this.read;
this.readBackwardsEndian = this.readBackwards;
this.readUint8ArrayEndian = this.readUint8Array;
}
__classPrivateFieldSet(this, _readableBufferBase_isLe, isLe, "f");
}
// ->
/**
* Read a unsigned integer
* @param bytes How many bytes the data is
* @returns The parsed unsigned integer
*/
readUnsignedInt(bytes) {
return (0, common_1.maybePromiseThen)(this.readEndian(bytes), (read) => {
let output = 0;
let index = 0;
for (const byte of read.reverse()) {
output |= byte << (index++ * 8);
}
return output >>> 0; // Force unsigned
});
}
/**
* Read a unsigned integer as a bigint
* @param bytes How many bytes the data is
* @returns The parsed unsigned integer (as a bigint)
*/
readUnsignedIntBigint(bytes) {
return (0, common_1.maybePromiseThen)(this.readEndian(bytes), (read) => {
let output = 0n;
for (let index = 0; index < bytes; index++) {
output <<= 8n;
output |= BigInt(read[index]);
}
return output;
});
}
/**
* Parse a two's complement
* @param bytes How many bytes it is
* @returns The parsed twos complement
*/
readTwosComplement(bytes) {
return (0, common_1.maybePromiseThen)(this.readUnsignedInt(bytes), (read) => {
// No padding is needed with a full 4 bytes, and in fact, the padding messes it up! What a world. (not needed for bigint because there is no size limit)
if (bytes === 4) {
return read >> 0;
}
const bits = bytes * 8;
// Just pad the value with 1s
return (read & (1 << (bits - 1))) !== 0
? (constants.allOnes << bits) | read
: read;
});
}
/**
* Parse a two's complement as a bigint
* @param bytes How many bytes it is
* @returns The parsed twos complement (as a bigint)
*/
readTwosComplementBigint(bytes) {
return (0, common_1.maybePromiseThen)(this.readUnsignedIntBigint(bytes), (read) => {
const bits = BigInt(bytes * 8);
// Just pad the value with 1s
return (read & (1n << (bits - 1n))) !== 0n ? (-1n << bits) | read : read;
});
}
/**
* Parse a two's complement from a single byte
* @returns The parsed twos complement
*/
readTwosComplementByte() {
return (0, common_1.maybePromiseThen)(this.shift(), (byte) => byte & 0b10000000 ? byte | constants.allOnesButLastByte : byte);
}
/**
* Parse a two's complements from single bytes
* @param bytes How many two's complements to parse
* @returns The parsed twos complements
*/
readTwosComplementByteArray(bytes) {
return (0, common_1.maybeAsyncCallArr)(this.readTwosComplementByte.bind(this), Array(bytes).fill([]));
}
/**
* Parse a float
* @returns The parsed float
*/
readFloat() {
if (common_1.isBigEndian) {
return (0, common_1.maybePromiseThen)(this.readEndian(4), (read) => {
common_1.uint8Float32ArrayView.set(read);
return common_1.float32Array[0];
});
}
else {
return (0, common_1.maybePromiseThen)(this.readBackwardsEndian(4), (read) => {
common_1.uint8Float32ArrayView.set(read);
return common_1.float32Array[0];
});
}
}
/**
* Parse a double
* @returns The parsed float
*/
readDouble() {
if (common_1.isBigEndian) {
return (0, common_1.maybePromiseThen)(this.readEndian(4), (read) => {
common_1.uint8Float64ArrayView.set(read);
return common_1.float64Array[0];
});
}
else {
return (0, common_1.maybePromiseThen)(this.readBackwardsEndian(4), (read) => {
common_1.uint8Float64ArrayView.set(read);
return common_1.float64Array[0];
});
}
}
/**
* Parse a string
* @param bytes How many bytes long the string is
* @param [mutf8=false] If the string is mutf8
* @returns The parsed string
*/
readString(bytes, mutf8 = false) {
if (mutf8 === true) {
return (0, common_1.maybePromiseThen)(this.readUint8ArrayEndian(bytes), (read) => (0, utf8tools_1.decodeMutf8)(read));
}
return (0, common_1.maybePromiseThen)(this.readUint8ArrayEndian(bytes), (read) => (0, utf8tools_1.decodeUtf8)(read));
}
/**
* Parse a signed one's complement
* @param bytes How long the signed one's complement is
* @returns The parsed signed ones compement
*/
readSignedOnesComplement(bytes) {
return (0, common_1.maybePromiseThen)(this.readUnsignedInt(bytes), (read) => {
// No padding is needed with a full 4 bytes, and in fact, the padding messes it up! What a world. (not needed for bigint because there is no size limit)
if (bytes === 4) {
return read >> 0;
}
const bits = bytes * 8;
return (read & (1 << (bits - 1))) !== 0
? -(~read & (constants.allOnes >>> (33 - bits)))
: read;
});
}
/**
* Parse a signed one's complement as a bigint
* @param bytes How long the signed one's complement is
* @returns The parsed signed ones compement (as a bigint)
*/
readSignedOnesComplementBigint(bytes) {
const bits = BigInt(bytes * 8);
return (0, common_1.maybePromiseThen)(this.readUnsignedIntBigint(bytes), (read) => (read & (1n << (bits - 1n))) !== 0n
? -(~read & ~(-1n << (bits - 1n)))
: read);
}
/**
* Parse a signed one's complement from a byte
* @returns The parsed signed one's compement
*/
readSignedOnesComplementByte() {
// Possible: We invert the bits then 0 the first bit if the origional has the first bit as one, so the removal of the first bit is kind of useless. (By first bit I mean 0b10000000)
return (0, common_1.maybePromiseThen)(this.shift(), (byte) => byte & 0b10000000 ? -(~byte & 0b01111111) : byte);
}
/**
* Parse signed one's complements (one byte each) from bytes
* @param bytes How many one's complements to read
* @returns The parsed signed one's compements
*/
readSignedOnesComplementByteArray(bytes) {
return (0, common_1.maybeAsyncCallArr)(this.readSignedOnesComplementByte.bind(this), Array(bytes).fill([]));
}
/**
* Parse a signed integer
* @param bytes How many bytes long the signed integer is
* @returns The parsed signed integer
*/
readSignedInteger(bytes) {
const bits = bytes * 8;
return (0, common_1.maybePromiseThen)(this.readUnsignedInt(bytes), (read) => {
const sign = read & (1 << (bits - 1));
return sign === 0 ? read ^ sign : -(read ^ sign);
});
}
/**
* Parse a signed integer as a bigint
* @param bytes How many bytes long the signed integer is
* @returns The parsed signed integer (as a bigint)
*/
readSignedIntegerBigint(bytes) {
const bits = BigInt(bytes * 8);
return (0, common_1.maybePromiseThen)(this.readUnsignedIntBigint(bytes), (read) => {
const sign = read & (1n << (bits - 1n));
return sign === 0n ? read ^ sign : -(read ^ sign);
});
}
/**
* Parse a signed integer from a byte
* @returns The parsed signed integer
*/
readSignedIntegerByte() {
return (0, common_1.maybePromiseThen)(this.shift(), (byte) => byte & 0b10000000 ? -(byte & 0b01111111) : byte & 0b01111111);
}
/**
* Parse a signed integer from a byte
* @returns The parsed signed integers
*/
readSignedIntegerByteArray(bytes) {
return (0, common_1.maybeAsyncCallArr)(this.readSignedIntegerByte.bind(this), Array(bytes).fill([]));
}
}
exports.readableBufferBase = readableBufferBase;
_readableBufferBase_isLe = new WeakMap();
exports.readableBufferBaseAsync = (readableBufferBase);
class readableBuffer extends readableBufferBase {
constructor(data) {
super();
_readableBuffer_buffer.set(this, void 0);
_readableBuffer_index.set(this, 0);
if (data instanceof readableBuffer) {
__classPrivateFieldSet(this, _readableBuffer_buffer, __classPrivateFieldGet(data, _readableBuffer_buffer, "f"), "f");
__classPrivateFieldSet(this, _readableBuffer_index, __classPrivateFieldGet(data, _readableBuffer_index, "f"), "f");
}
else {
__classPrivateFieldSet(this, _readableBuffer_buffer, data, "f");
}
}
get buffer() {
return __classPrivateFieldGet(this, _readableBuffer_buffer, "f").slice(__classPrivateFieldGet(this, _readableBuffer_index, "f"));
}
set buffer(newValue) {
if (newValue instanceof readableBuffer) {
__classPrivateFieldSet(this, _readableBuffer_buffer, __classPrivateFieldGet(newValue, _readableBuffer_buffer, "f"), "f");
__classPrivateFieldSet(this, _readableBuffer_index, __classPrivateFieldGet(newValue, _readableBuffer_index, "f"), "f");
}
else {
__classPrivateFieldSet(this, _readableBuffer_buffer, newValue, "f");
__classPrivateFieldSet(this, _readableBuffer_index, 0, "f");
}
}
/**
* The current offset in the buffer
* @returns The current offset in the buffer
*/
get _offset() {
return __classPrivateFieldGet(this, _readableBuffer_index, "f");
}
/**
* The remaining length of the buffer
* @returns The length of the buffer
*/
get length() {
return __classPrivateFieldGet(this, _readableBuffer_buffer, "f").length - __classPrivateFieldGet(this, _readableBuffer_index, "f");
}
shift() {
var _a, _b;
// If the index is the same or bigger than the length, the buffer will be out of bounds be out of bounds because the length is always one bigger then the highest index
if (__classPrivateFieldGet(this, _readableBuffer_buffer, "f").length <= __classPrivateFieldGet(this, _readableBuffer_index, "f")) {
throw new RangeError("readableBuffer out of bounds");
}
return __classPrivateFieldGet(this, _readableBuffer_buffer, "f")[__classPrivateFieldSet(this, _readableBuffer_index, (_b = __classPrivateFieldGet(this, _readableBuffer_index, "f"), _a = _b++, _b), "f"), _a];
}
readUint8Array(bytes) {
if (__classPrivateFieldGet(this, _readableBuffer_buffer, "f").length < __classPrivateFieldGet(this, _readableBuffer_index, "f") + bytes) {
throw new RangeError("readableBuffer out of bounds");
}
return __classPrivateFieldGet(this, _readableBuffer_buffer, "f").subarray(__classPrivateFieldGet(this, _readableBuffer_index, "f"), (__classPrivateFieldSet(this, _readableBuffer_index, __classPrivateFieldGet(this, _readableBuffer_index, "f") + bytes, "f")));
}
readUint8ArrayBackwards(bytes) {
return this.readUint8Array(bytes).reverse();
}
readReadableBuffer(bytes) {
if (__classPrivateFieldGet(this, _readableBuffer_buffer, "f").length < __classPrivateFieldGet(this, _readableBuffer_index, "f") + bytes) {
throw new RangeError("readableBuffer out of bounds");
}
// This uses the same memory for the new readableBuffer
return new readableBuffer(__classPrivateFieldGet(this, _readableBuffer_buffer, "f").subarray(__classPrivateFieldGet(this, _readableBuffer_index, "f"), (__classPrivateFieldSet(this, _readableBuffer_index, __classPrivateFieldGet(this, _readableBuffer_index, "f") + bytes, "f"))));
}
readArray(bytes) {
const output = Array.prototype.slice.call(__classPrivateFieldGet(this, _readableBuffer_buffer, "f"), __classPrivateFieldGet(this, _readableBuffer_index, "f"), (__classPrivateFieldSet(this, _readableBuffer_index, __classPrivateFieldGet(this, _readableBuffer_index, "f") + bytes, "f")));
if (output.length !== bytes) {
throw new RangeError("readableBuffer out of bounds");
}
return output;
}
// This is a bit more usefull in writableBuffer
readArrayBackwards(bytes) {
return this.readArray(bytes).reverse();
}
}
exports.readableBuffer = readableBuffer;
_readableBuffer_buffer = new WeakMap(), _readableBuffer_index = new WeakMap();
exports.readableBufferLe = (0, common_1.addDefaultEndianness)(readableBuffer, true);