libnexa-ts
Version:
A pure and powerful Nexa SDK library.
201 lines (176 loc) • 5.29 kB
text/typescript
import ValidationUtils from "../utils/validation.utils";
import BN from "../crypto/bn.extension";
import BufferUtils from "../utils/buffer.utils";
import type { BufferParams } from "../common/interfaces";
export default class BufferReader {
public buf: Uint8Array;
public pos: number;
constructor(buf?: Uint8Array | string | BufferParams) {
this.buf = new Uint8Array();
this.pos = 0;
if (buf == null) {
return;
}
if (BufferUtils.isBuffer(buf)) {
this.set({ buf: buf });
} else if (typeof buf === 'string') {
let b = BufferUtils.hexToBuffer(buf);
if (b.length * 2 != buf.length) {
throw new TypeError('Invalid hex string');
}
this.set({ buf: b });
} else if (typeof buf === 'object') {
let obj = buf;
this.set(obj);
} else {
throw new TypeError('Unrecognized argument for BufferReader');
}
}
public set(obj: BufferParams): this {
this.buf = obj.buf || this.buf;
this.pos = obj.pos || this.pos || 0;
return this;
}
public eof(): boolean {
return this.pos >= this.buf.length;
}
public finished = this.eof;
public read(len: number): Uint8Array {
ValidationUtils.validateArgument(len != null, 'Must specify a length');
let buf = this.buf.subarray(this.pos, this.pos + len);
this.pos = this.pos + len;
return buf;
}
public readAll(): Uint8Array {
let buf = this.buf.subarray(this.pos, this.buf.length);
this.pos = this.buf.length;
return buf;
}
public readUInt8(): number {
const view = new DataView(this.buf.buffer, this.buf.byteOffset, this.buf.byteLength);
const val = view.getUint8(this.pos);
this.pos += 1;
return val;
}
public readUInt16BE(): number {
const view = new DataView(this.buf.buffer, this.buf.byteOffset, this.buf.byteLength);
const val = view.getUint16(this.pos);
this.pos += 2;
return val;
}
public readUInt16LE(): number {
const view = new DataView(this.buf.buffer, this.buf.byteOffset, this.buf.byteLength);
const val = view.getUint16(this.pos, true);
this.pos += 2;
return val;
}
public readUInt32BE(): number {
const view = new DataView(this.buf.buffer, this.buf.byteOffset, this.buf.byteLength);
const val = view.getUint32(this.pos);
this.pos += 4;
return val;
}
public readUInt32LE(): number {
const view = new DataView(this.buf.buffer, this.buf.byteOffset, this.buf.byteLength);
const val = view.getUint32(this.pos, true);
this.pos += 4;
return val;
}
public readInt32LE(): number {
const view = new DataView(this.buf.buffer, this.buf.byteOffset, this.buf.byteLength);
const val = view.getInt32(this.pos, true);
this.pos += 4;
return val;
}
public readUInt64BEBN(): BN {
const view = new DataView(this.buf.buffer, this.buf.byteOffset, this.buf.byteLength);
const val = view.getBigUint64(this.pos);
this.pos += 8;
return BN.fromBigInt(val);
}
public readUInt64LEBN(): BN {
const view = new DataView(this.buf.buffer, this.buf.byteOffset, this.buf.byteLength);
const val = view.getBigUint64(this.pos, true);
this.pos += 8;
return BN.fromBigInt(val);
}
public readVarintNum(): number {
let first = this.readUInt8();
switch (first) {
case 0xFD:
return this.readUInt16LE();
case 0xFE:
return this.readUInt32LE();
case 0xFF:
let bn = this.readUInt64LEBN();
let n = bn.toNumber();
if (n <= Math.pow(2, 53)) {
return n;
} else {
throw new Error('number too large to retain precision - use readVarintBN');
}
}
return first;
}
/**
* reads a length prepended buffer
*/
public readVarLengthBuffer(): Uint8Array {
let len = this.readVarintNum();
let buf = this.read(len);
ValidationUtils.validateState(buf.length === len, 'Invalid length while reading varlength buffer. ' +
'Expected to read: ' + len + ' and read ' + buf.length);
return buf;
}
public readVarintBuf(): Uint8Array {
let first = this.buf[this.pos];
switch (first) {
case 0xFD:
return this.read(1 + 2);
case 0xFE:
return this.read(1 + 4);
case 0xFF:
return this.read(1 + 8);
default:
return this.read(1);
}
}
public readVarintBN(): BN {
let first = this.readUInt8();
switch (first) {
case 0xFD:
return new BN(this.readUInt16LE());
case 0xFE:
return new BN(this.readUInt32LE());
case 0xFF:
return this.readUInt64LEBN();
default:
return new BN(first);
}
}
public reverse(): this {
let buf = BufferUtils.reverse(this.buf);
this.buf = buf;
return this;
}
public readReverse(len?: number): Uint8Array {
if (len == null) {
len = this.buf.length;
}
let buf = this.buf.subarray(this.pos, this.pos + len);
this.pos = this.pos + len;
return BufferUtils.reverse(buf);
};
public readCoreVarintNum(): number {
let n = 0;
while (true) {
let chData = this.readUInt8();
n = (n << 7) | (chData & 0x7F);
if (chData & 0x80) {
n++;
} else {
return n;
}
}
}
}