byte-rw
Version:
Byte reader/writer for buffers and streams in typescript/javascript
196 lines (195 loc) • 7.02 kB
JavaScript
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { copy, textDecoder } from "../utils/index.js";
export class DataViewByteReaderAsync {
get _bytesRemaining() {
return this._dataview.byteLength - this._byteOffset;
}
get dataview() {
return this._dataview;
}
set dataview(dataview) {
this._dataview = dataview;
}
isComplete() {
return __awaiter(this, void 0, void 0, function* () {
return this._isComplete || (this._isComplete = yield this.updateIsComplete());
});
}
constructor(dataview, littleEndian = true) {
this.littleEndian = littleEndian;
this._isComplete = false;
this._byteOffset = 0;
this._dataview = dataview;
}
updateIsComplete() {
return __awaiter(this, void 0, void 0, function* () {
return (yield this.tryEnsureAvailable(1)) > 0;
});
}
/**
* Attempts to ensure that a specified number of bytes are available in the
* current chunk.
*
* @param bytes the number of bytes to request in the current chunk
* @returns the number of bytes at least made available in the current
* chunk, up to the requested number of bytes
*/
tryEnsureAvailable(bytes) {
return __awaiter(this, void 0, void 0, function* () {
if (this._isComplete)
return 0;
if (this._bytesRemaining < bytes)
return this._bytesRemaining;
else
return bytes;
});
}
ensureAvailable(bytes) {
return __awaiter(this, void 0, void 0, function* () {
const available = yield this.tryEnsureAvailable(bytes);
if (available !== bytes)
throw new Error(`Not all bytes could be available (${bytes} bytes request, ${available} bytes available)`);
});
}
/**
* Gets the next Float32 value
*/
readFloat32() {
return __awaiter(this, void 0, void 0, function* () {
const bytes = 4;
yield this.ensureAvailable(bytes);
const value = this._dataview.getFloat32(this._byteOffset, this.littleEndian);
this._byteOffset += bytes;
return value;
});
}
/**
* Gets the next Float64 value
*/
readFloat64() {
return __awaiter(this, void 0, void 0, function* () {
const bytes = 8;
yield this.ensureAvailable(bytes);
const value = this._dataview.getFloat64(this._byteOffset, this.littleEndian);
this._byteOffset += bytes;
return value;
});
}
/**
* Gets the next Int8 value
*/
readInt8() {
return __awaiter(this, void 0, void 0, function* () {
const bytes = 1;
yield this.ensureAvailable(bytes);
const value = this._dataview.getInt8(this._byteOffset);
this._byteOffset += bytes;
return value;
});
}
/**
* Gets the next Int16 value
*/
readInt16() {
return __awaiter(this, void 0, void 0, function* () {
const bytes = 2;
yield this.ensureAvailable(bytes);
const value = this._dataview.getInt16(this._byteOffset, this.littleEndian);
this._byteOffset += bytes;
return value;
});
}
/**
* Gets the next Int32 value
*/
readInt32() {
return __awaiter(this, void 0, void 0, function* () {
const bytes = 4;
yield this.ensureAvailable(bytes);
const value = this._dataview.getInt32(this._byteOffset, this.littleEndian);
this._byteOffset += bytes;
return value;
});
}
/**
* Gets the next Uint8 value
*/
readUint8() {
return __awaiter(this, void 0, void 0, function* () {
const bytes = 1;
yield this.ensureAvailable(bytes);
const value = this._dataview.getUint8(this._byteOffset);
this._byteOffset += bytes;
return value;
});
}
/**
* Gets the next Uint16 value
*/
readUint16() {
return __awaiter(this, void 0, void 0, function* () {
const bytes = 2;
yield this.ensureAvailable(bytes);
const value = this._dataview.getUint16(this._byteOffset, this.littleEndian);
this._byteOffset += bytes;
return value;
});
}
/**
* Gets the next Uint32 value
*/
readUint32() {
return __awaiter(this, void 0, void 0, function* () {
const bytes = 4;
yield this.ensureAvailable(bytes);
const value = this._dataview.getUint32(this._byteOffset, this.littleEndian);
this._byteOffset += bytes;
return value;
});
}
tryReadBytes(view) {
return __awaiter(this, void 0, void 0, function* () {
const bytes = view.byteLength;
const read = yield this.tryEnsureAvailable(bytes);
const dst = view.buffer;
const src = this._dataview.buffer;
const dstOffset = view.byteOffset;
const srcOffset = this._dataview.byteOffset + this._byteOffset;
copy({
buffer: src,
byteOffset: srcOffset,
byteLength: read,
}, {
buffer: dst,
byteOffset: dstOffset,
byteLength: read,
});
return read;
});
}
readBytes(view) {
return __awaiter(this, void 0, void 0, function* () {
const read = yield this.tryReadBytes(view);
if (read !== view.byteLength)
throw new Error(`Not all bytes could be read (${view.byteLength} bytes request, ${read} bytes read)`);
});
}
readString(encoding) {
return __awaiter(this, void 0, void 0, function* () {
const length = yield this.readUint32();
yield this.ensureAvailable(length);
const available = this._dataview.byteLength - this._byteOffset;
console.assert(available >= length);
const view = new DataView(this._dataview.buffer, this._dataview.byteOffset + this._byteOffset, length);
return textDecoder.decode(view);
});
}
}