Files
noctis/src/lib/buffer.ts

197 lines
5.7 KiB
TypeScript

// nodejs like buffer class for browser
export class WebBuffer {
private data: Uint8Array<ArrayBuffer>;
// the number of bytes read from the buffer, this allows for you to read the buffer without having to specify the offset every time
private count = 0;
private dataView: DataView;
constructor(data: ArrayBuffer) {
this.data = new Uint8Array(data);
this.dataView = new DataView(data);
return new Proxy(this, {
get(target, prop, receiver) {
// Check if the property is a string that represents a valid number (array index)
if (typeof prop === 'string' && /^\d+$/.test(prop)) {
const index = parseInt(prop, 10);
// Delegate array-like access to the underlying Uint8Array
return target.data[index];
}
// For all other properties (methods like slice, getters like length, etc.),
// use the default property access behavior on the target object.
return Reflect.get(target, prop, receiver);
},
set(target, prop, value, receiver) {
// Check if the property is a string that represents a valid number (array index)
if (typeof prop === 'string' && /^\d+$/.test(prop)) {
const index = parseInt(prop, 10);
// Delegate array-like assignment to the underlying Uint8Array
target.data[index] = value;
return true; // Indicate success
}
// For all other properties, use the default property assignment behavior.
return Reflect.set(target, prop, value, receiver);
}
});
}
[index: number]: number;
get length(): number {
return this.data.length;
}
get buffer(): ArrayBuffer {
return this.data.buffer;
}
slice(start: number, end?: number): WebBuffer {
return new WebBuffer(this.data.slice(start, end).buffer);
}
set(data: number, offset: number) {
this.dataView.setUint8(offset, data);
// this.data.set(data, offset);
}
read(length?: number, offset?: number): Uint8Array {
if (length === undefined) {
length = this.length - this.count;
}
if (offset === undefined) {
offset = this.count;
this.count += length;
}
return this.data.slice(offset, offset + length);
}
write(data: Uint8Array, offset?: number) {
if (offset === undefined) {
offset = this.count;
this.count += data.byteLength;
}
for (let i = 0; i < data.byteLength; i++) {
this.dataView.setUint8(offset + i, data[i]);
}
}
readInt8(offset?: number): number {
if (offset === undefined) {
offset = this.count;
this.count += 1;
}
return this.dataView.getUint8(offset);
}
writeInt8(value: number, offset?: number) {
if (offset === undefined) {
offset = this.count;
this.count += 1;
}
this.dataView.setUint8(offset, value);
}
readInt16LE(offset?: number): number {
if (offset === undefined) {
offset = this.count;
this.count += 2;
}
return this.dataView.getInt16(offset, true);
}
writeInt16LE(value: number, offset?: number) {
if (offset === undefined) {
offset = this.count;
this.count += 2;
}
this.dataView.setInt16(offset, value, true);
}
readInt32LE(offset?: number): number {
if (offset === undefined) {
offset = this.count;
this.count += 4;
}
return this.dataView.getInt32(offset, true);
}
writeInt32LE(value: number, offset?: number) {
if (offset === undefined) {
offset = this.count;
this.count += 4;
}
this.dataView.setInt32(offset, value, true);
}
readBigInt64LE(offset?: number): bigint {
if (offset === undefined) {
offset = this.count;
this.count += 8;
}
return this.dataView.getBigInt64(offset, true);
}
writeBigInt64LE(value: bigint, offset?: number) {
if (offset === undefined) {
offset = this.count;
this.count += 8;
}
this.dataView.setBigInt64(offset, value, true);
}
// if no length is specified, reads until the end of the buffer
readString(length?: number, offset?: number): string {
if (length === undefined) {
length = this.length - this.count;
}
if (offset === undefined) {
offset = this.count;
this.count += length;
}
let textDeccoder = new TextDecoder();
let readTextBuf = this.data.slice(offset, offset + length);
let value = textDeccoder.decode(readTextBuf);
return value;
}
writeString(value: string, offset?: number) {
if (offset === undefined) {
offset = this.count;
this.count += value.length;
}
let textEncoder = new TextEncoder();
let textBuf = textEncoder.encode(value);
this.data.set(textBuf, offset);
}
// lets you peek at the next byte without advancing the read pointer
peek(): number {
return this.data[this.count];
}
[Symbol.iterator]() {
// Return an iterator over the values of the underlying Uint8Array
return this.data.values();
}
// Optional: Add Symbol.toStringTag for better console output
get [Symbol.toStringTag]() {
return 'WebBuffer';
}
}