UNPKG

@thi.ng/bitstream

Version:

ES6 iterator based read/write bit streams with support for variable word widths

109 lines (108 loc) 2.73 kB
import { illegalArgs } from "@thi.ng/errors/illegal-arguments"; import { BitInputStream } from "./input.js"; const DEFAULT_BUF_SIZE = 16; const U32 = 4294967296; class BitOutputStream { buffer; start; pos; bit; bitPos; constructor(buffer, offset = 0) { this.buffer = typeof buffer === "undefined" ? new Uint8Array(DEFAULT_BUF_SIZE) : typeof buffer === "number" ? new Uint8Array(buffer) : buffer; this.start = offset; this.seek(offset); this.buffer[this.pos] &= ~((1 << this.bit) - 1); } get position() { return this.bitPos; } seek(pos) { if (pos < this.start || pos >= this.buffer.length << 3) { illegalArgs(`seek pos out of bounds: ${pos}`); } this.pos = pos >>> 3; this.bit = 8 - (pos & 7); this.bitPos = pos; return this; } bytes() { return this.buffer.slice(0, this.pos + (this.bit & 7 ? 1 : 0)); } reader(from = 0) { return new BitInputStream(this.buffer, from, this.position); } write(x, wordSize = 1) { if (wordSize > 32) { let hi = Math.floor(x / U32); this.write(hi, wordSize - 32); this.write(x - hi * U32, 32); } else if (wordSize > 8) { let n = wordSize & -8; let msb = wordSize - n; if (msb > 0) { this._write(x >>> n, msb); } n -= 8; while (n >= 0) { this._write(x >>> n, 8); n -= 8; } } else { this._write(x, wordSize); } return this; } writeWords(input, wordSize = 8) { let iter = input[Symbol.iterator](); let v; while (v = iter.next(), !v.done) { this.write(v.value, wordSize); } } writeBit(x) { this.bit--; this.buffer[this.pos] = this.buffer[this.pos] & ~(1 << this.bit) | x << this.bit; if (this.bit === 0) { this.ensureSize(); this.bit = 8; } this.bitPos++; return this; } _write(x, wordSize) { x &= (1 << wordSize) - 1; let buf = this.buffer; let pos = this.pos; let bit = this.bit; let b = bit - wordSize; let m = bit < 8 ? ~((1 << bit) - 1) : 0; if (b >= 0) { m |= (1 << b) - 1; buf[pos] = buf[pos] & m | x << b & ~m; if (b === 0) { this.ensureSize(); this.bit = 8; } else { this.bit = b; } } else { this.bit = bit = 8 + b; buf[pos] = buf[pos] & m | x >>> -b & ~m; this.ensureSize(); this.buffer[this.pos] = this.buffer[this.pos] & (1 << bit) - 1 | x << bit & 255; } this.bitPos += wordSize; return this; } ensureSize() { if (++this.pos === this.buffer.length) { let b = new Uint8Array(this.buffer.length << 1); b.set(this.buffer); this.buffer = b; } } } export { BitOutputStream };