|
|
|
import { BitstreamReader as br, BitstreamWriter as bw } from '@astronautlabs/bitstream';
|
|
|
|
|
|
|
|
export const revbyte = (n: number, len = 8) => {
|
|
|
|
let acc = 0;
|
|
|
|
let n2 = n;
|
|
|
|
let len2 = len;
|
|
|
|
while (len2) {
|
|
|
|
// can't use bitshifts or binray ops or else becomes negative
|
|
|
|
acc = (acc * 2) + (n2 & 1);
|
|
|
|
n2 >>= 1;
|
|
|
|
len2--;
|
|
|
|
}
|
|
|
|
return acc;
|
|
|
|
};
|
|
|
|
|
|
|
|
export class BitstreamReader {
|
|
|
|
private buffers: Uint8Array[] = [];
|
|
|
|
|
|
|
|
private bufferedLength = 0;
|
|
|
|
|
|
|
|
private _offsetIntoBuffer = 0;
|
|
|
|
|
|
|
|
private _bufferIndex = 0;
|
|
|
|
|
|
|
|
private _offset = 0;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the index of the buffer currently being read. This will always be zero unless retainBuffers=true
|
|
|
|
*/
|
|
|
|
get bufferIndex() {
|
|
|
|
return this._bufferIndex;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the current offset in bits, starting from the very first bit read by this reader (across all
|
|
|
|
* buffers added)
|
|
|
|
*/
|
|
|
|
get offset() {
|
|
|
|
return this._offset;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The number of bits that are currently available.
|
|
|
|
*/
|
|
|
|
get available() {
|
|
|
|
return this.bufferedLength - this.skippedLength;
|
|
|
|
}
|
|
|
|
|
|
|
|
private skippedLength = 0;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Read an unsigned integer of the given bit length synchronously. If there are not enough
|
|
|
|
* bits available, an error is thrown.
|
|
|
|
*
|
|
|
|
* @param length The number of bits to read
|
|
|
|
* @returns The unsigned integer that was read
|
|
|
|
*/
|
|
|
|
|
|
|
|
getBit(offset: number) {
|
|
|
|
const byte = this.buffers[0][offset >> 3];
|
|
|
|
return +!!(byte & (1 << (offset & 7)));
|
|
|
|
}
|
|
|
|
|
|
|
|
readSync(length: number): number {
|
|
|
|
let value = 0;
|
|
|
|
//console.log(this.buffers[0])
|
|
|
|
if (this._offset >> 3 > this.buffers[0].byteLength) {
|
|
|
|
throw "Out of data";
|
|
|
|
}
|
|
|
|
//const byte = this.buffers[0][this._offset >> 3];
|
|
|
|
for (let i = length - 1; i >= 0; --i) {
|
|
|
|
value = value * 2 + this.getBit(this._offset + i);
|
|
|
|
}
|
|
|
|
this._offset += length;
|
|
|
|
this.bufferedLength -= length;
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Add a buffer onto the end of the bitstream.
|
|
|
|
* @param buffer The buffer to add to the bitstream
|
|
|
|
*/
|
|
|
|
addBuffer(buffer: Uint8Array) {
|
|
|
|
this.buffers.push(buffer);
|
|
|
|
this.bufferedLength += buffer.length * 8;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export type Writable = {
|
|
|
|
write: (chunk: Uint8Array) => void;
|
|
|
|
};
|
|
|
|
|
|
|
|
export class BitstreamWriter {
|
|
|
|
/**
|
|
|
|
* Create a new writer
|
|
|
|
* @param stream The writable stream to write to
|
|
|
|
* @param bufferSize The number of bytes to buffer before flushing onto the writable
|
|
|
|
*/
|
|
|
|
constructor(public stream: Writable, bufferSize = 1) {
|
|
|
|
bufferSize = 1;
|
|
|
|
this.buffer = new Uint8Array(bufferSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
private pendingBits = 0;
|
|
|
|
|
|
|
|
private buffer: Uint8Array;
|
|
|
|
|
|
|
|
bufferoffset = 0;
|
|
|
|
|
|
|
|
private _offset = 0;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* How many bits have been written via this writer in total
|
|
|
|
*/
|
|
|
|
get offset() {
|
|
|
|
return this._offset;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* How many bits into the current byte is the write cursor.
|
|
|
|
* If this value is zero, then we are currently byte-aligned.
|
|
|
|
* A value of 7 means we are 1 bit away from the byte boundary.
|
|
|
|
*/
|
|
|
|
get byteOffset() {
|
|
|
|
return this.pendingBits;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Finish the current byte (assuming zeros for the remaining bits, if necessary)
|
|
|
|
* and flushes the output.
|
|
|
|
*/
|
|
|
|
end() {
|
|
|
|
//this.finishByte();
|
|
|
|
this.flush();
|
|
|
|
}
|
|
|
|
|
|
|
|
flush() {
|
|
|
|
this.stream.write(new Uint8Array(this.buffer));
|
|
|
|
this.bufferoffset = 0;
|
|
|
|
this.buffer.fill(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
setBit(b: number) {
|
|
|
|
if (b)
|
|
|
|
debugger;
|
|
|
|
let byte = this.buffer[0];
|
|
|
|
byte |= b << (this._offset & 7);
|
|
|
|
this.buffer[0] = byte;
|
|
|
|
this._offset += 1;
|
|
|
|
if (++this.bufferoffset == this.buffer.length * 8) {
|
|
|
|
this.flush();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Write the given number to the bitstream with the given bitlength. If the number is too large for the
|
|
|
|
* number of bits specified, the lower-order bits are written and the higher-order bits are ignored.
|
|
|
|
* @param length The number of bits to write
|
|
|
|
* @param value The number to write
|
|
|
|
*/
|
|
|
|
write(length: number, value: number) {
|
|
|
|
while (length--) {
|
|
|
|
this.setBit(value & 1);
|
|
|
|
value >>= 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|