mc-anvil
Version:
A Typescript library for reading Minecraft Anvil format files and Minecraft NBT format files in the browser.
89 lines (74 loc) • 2.65 kB
text/typescript
const MASK: Map<number, number> = new Map([
[ 0, 0 ],
[ 1, 1 ],
[ 2, 3 ],
[ 3, 7 ],
[ 4, 15 ],
[ 5, 31 ],
[ 6, 63 ],
[ 7, 127 ],
[ 8, 255 ]
]);
export class BitParser {
protected partial: number;
protected partialCount: number;
protected view: DataView;
protected position: number;
protected length: number;
static inverseMask(start: number, n: number): number {
return 0xFF - ((MASK.get(n)! << (8 - start - n)) % 0xFF);
}
constructor(data: ArrayBuffer) {
this.view = new DataView(data);
this.position = 0;
this.length = this.view.byteLength;
this.partial = 0;
this.partialCount = 0;
}
currentPosition() {
return this.position;
}
remainingLength() {
return this.length - this.position;
}
getBits(n: number): number {
if (n <= this.partialCount) {
const r = this.partial >> (this.partialCount - n);
this.partial &= MASK.get(this.partialCount - n)!;
this.partialCount -= n;
return r;
}
let needed = n - this.partialCount;
let r = this.partial << (n - this.partialCount);
this.partialCount = 8 - (needed % 8);
if (this.partialCount === 8) this.partialCount = 0;
while (needed > 8) {
r |= this.view.getUint8(this.position++) << (needed - 8);
needed -= 8;
}
const b = this.view.getUint8(this.position++);
r |= (b >> this.partialCount) & MASK.get(needed)!;
this.partial = b & MASK.get(this.partialCount)!;
return r;
}
setBits(n: number, value: number) {
let needed = n;
if (n > 8 - this.partialCount) {
const x = 8 - this.partialCount;
const l = this.view.getUint8(this.position) & (MASK.get(this.partialCount)! << (8 - this.partialCount));
this.view.setUint8(this.position++, l + (value >> (n - x)));
this.partialCount = 0;
needed -= x;
}
const sm = needed % 8;
for (let i = Math.floor(needed / 8) - 1; i >= 0; --i)
this.view.setUint8(this.position++, (value >> (sm + (8 * i))) % 256);
const existing = this.view.getUint8(this.position) & (MASK.get(this.partialCount)! << (8 - this.partialCount));
this.view.setUint8(this.position, existing + ((value & MASK.get(sm)!) << (8 - sm - this.partialCount)));
this.partialCount += sm;
}
seek(position: number, partialCount?: number) {
this.position = position;
this.partialCount = partialCount || 0;
}
}