Files
onenote-tools/src/onenote/onepkg/binary-reader.ts

87 lines
2.3 KiB
TypeScript

import { fail } from './errors.js';
export class BinaryReader {
readonly bytes: Uint8Array;
readonly end: number;
offset: number;
private readonly view: DataView;
constructor(bytes: Uint8Array, offset = 0, end = bytes.byteLength) {
if (offset < 0 || end < offset || end > bytes.byteLength) {
throw new RangeError('Invalid BinaryReader range');
}
this.bytes = bytes;
this.offset = offset;
this.end = end;
this.view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
}
ensure(length: number, structure: string): void {
if (
!Number.isSafeInteger(length) ||
length < 0 ||
this.offset > this.end - length
) {
fail(
'cab-unexpected-eof',
`Unexpected end of cabinet while reading ${structure}.`,
{ offset: this.offset, structure }
);
}
}
readU8(structure: string): number {
this.ensure(1, structure);
return this.bytes[this.offset++]!;
}
readU16(structure: string): number {
this.ensure(2, structure);
const value = this.view.getUint16(this.offset, true);
this.offset += 2;
return value;
}
readU32(structure: string): number {
this.ensure(4, structure);
const value = this.view.getUint32(this.offset, true);
this.offset += 4;
return value;
}
readBytes(length: number, structure: string): Uint8Array {
this.ensure(length, structure);
const result = this.bytes.subarray(this.offset, this.offset + length);
this.offset += length;
return result;
}
skip(length: number, structure: string): void {
this.ensure(length, structure);
this.offset += length;
}
readNullTerminatedBytes(maxBytes: number, structure: string): Uint8Array {
const start = this.offset;
while (this.offset < this.end && this.bytes[this.offset] !== 0) {
if (this.offset - start >= maxBytes) {
fail(
'cab-name-too-long',
`Cabinet string exceeds the configured ${maxBytes}-byte limit.`,
{ offset: start, structure }
);
}
this.offset += 1;
}
if (this.offset >= this.end) {
fail('cab-unterminated-string', 'Cabinet string is not NUL-terminated.', {
offset: start,
structure,
});
}
const value = this.bytes.subarray(start, this.offset);
this.offset += 1;
return value;
}
}