byte-rw
Version:
Byte reader/writer for buffers and streams in typescript/javascript
127 lines (126 loc) • 4.17 kB
JavaScript
import { copy, textEncoder } from "../utils/index.js";
export class DataViewByteWriter {
get _bytesRemaining() {
return this._dataview.byteLength - this._byteOffset;
}
get dataview() {
return this._dataview;
}
set dataview(dataview) {
this._dataview = dataview;
}
isComplete() {
return this._isComplete || (this._isComplete = this.updateIsComplete());
}
constructor(dataview, littleEndian = true) {
this.littleEndian = littleEndian;
this._isComplete = false;
this._byteOffset = 0;
this._dataview = dataview;
}
updateIsComplete() {
return this.tryEnsureAvailable(1) > 0;
}
complete() {
this._isComplete = true;
}
/**
* Attempts to ensure that a specified number of bytes are available in the
* current dataview.
*
* @param bytes the number of bytes to request available in the current
* dataview
* @returns the number of bytes at least made available in the current
* dataview, up to the requested number of bytes
*/
tryEnsureAvailable(bytes) {
if (this._isComplete)
return 0;
if (this._bytesRemaining < bytes)
return this._bytesRemaining;
else
return bytes;
}
ensureAvailable(bytes) {
const available = this.tryEnsureAvailable(bytes);
if (available !== bytes)
throw new Error(`Not all bytes could be available (${bytes} bytes requested, ${available} bytes available)`);
}
writeFloat32(value) {
const bytes = 4;
this.ensureAvailable(bytes);
this._dataview.setFloat32(this._byteOffset, value, this.littleEndian);
this._byteOffset += bytes;
}
writeFloat64(value) {
const bytes = 8;
this.ensureAvailable(bytes);
this._dataview.setFloat64(this._byteOffset, value, this.littleEndian);
this._byteOffset += bytes;
}
writeInt8(value) {
const bytes = 1;
this.ensureAvailable(bytes);
this._dataview.setInt8(this._byteOffset, value);
this._byteOffset += bytes;
}
writeInt16(value) {
const bytes = 2;
this.ensureAvailable(bytes);
this._dataview.setInt16(this._byteOffset, value, this.littleEndian);
this._byteOffset += bytes;
}
writeInt32(value) {
const bytes = 4;
this.ensureAvailable(bytes);
this._dataview.setInt32(this._byteOffset, value, this.littleEndian);
this._byteOffset += bytes;
}
writeUint8(value) {
const bytes = 1;
this.ensureAvailable(bytes);
this._dataview.setUint8(this._byteOffset, value);
this._byteOffset += bytes;
}
writeUint16(value) {
const bytes = 2;
this.ensureAvailable(bytes);
this._dataview.setUint16(this._byteOffset, value, this.littleEndian);
this._byteOffset += bytes;
}
writeUint32(value) {
const bytes = 4;
this.ensureAvailable(bytes);
this._dataview.setUint32(this._byteOffset, value, this.littleEndian);
this._byteOffset += bytes;
}
tryWriteBytes(view) {
const bytes = view.byteLength;
const write = this.tryEnsureAvailable(bytes);
const dst = this._dataview.buffer;
const src = view.buffer;
const dstOffset = this._dataview.byteOffset + this._byteOffset;
const srcOffset = view.byteOffset;
copy({
buffer: src,
byteOffset: srcOffset,
byteLength: write,
}, {
buffer: dst,
byteOffset: dstOffset,
byteLength: write,
});
this._byteOffset += write;
return write;
}
writeBytes(view) {
const written = this.tryWriteBytes(view);
if (written !== view.byteLength)
throw new Error(`Not all bytes could be written (${view.byteLength} bytes requested, ${written} bytes written)`);
}
writeString(value) {
const encoded = textEncoder.encode(value);
this.writeUint32(encoded.byteLength);
this.writeBytes(encoded);
}
}