blitflash
Version:
A JavaScript implementation of the 32blit flash tools
123 lines (122 loc) • 5 kB
JavaScript
"use strict";
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());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ReadBuffer = void 0;
const INITIAL_CAPACITY = 1024;
class PendingPromise {
constructor(dataLength, resolve, reject) {
this.dataLength = dataLength;
this.resolve = resolve;
this.reject = reject;
}
}
class ReadBuffer {
constructor(initialCapacity = INITIAL_CAPACITY) {
this.pendingPromises = [];
this._size = 0;
this.decoder = new TextDecoder();
this.buffer = new Uint8Array(new ArrayBuffer(initialCapacity));
}
read(numBytes) {
return __awaiter(this, void 0, void 0, function* () {
// If we don't have any Promises pending ahead of this and have enough data we respond straight
// away.
if (this.pendingPromises.length === 0 && this.size() >= numBytes) {
return yield this.internalRead(numBytes);
}
// Otherwise, we append a Promise to our list of pending promises.
return new Promise((resolve, reject) => {
this.pendingPromises.push(new PendingPromise(numBytes, resolve, reject));
});
});
}
readUint8() {
return __awaiter(this, void 0, void 0, function* () {
const data = yield this.read(1);
return new DataView(data.buffer).getUint8(0);
});
}
readUint16(littleEndian) {
return __awaiter(this, void 0, void 0, function* () {
const data = yield this.read(2);
return new DataView(data.buffer).getUint16(0, littleEndian);
});
}
readUint32(littleEndian) {
return __awaiter(this, void 0, void 0, function* () {
const data = yield this.read(4);
return new DataView(data.buffer).getUint32(0, littleEndian);
});
}
readString(size) {
return __awaiter(this, void 0, void 0, function* () {
const data = yield this.read(size);
let end = data.findIndex((value) => value === 0);
if (end === -1) {
end = size - 1;
}
return this.decoder.decode(data.slice(0, end + 1));
});
}
append(data) {
if (this.size() + data.byteLength > this.buffer.byteLength) {
this.extendBuffer();
}
this.buffer.set(data, this.size());
this._size += data.byteLength;
this.tryResolvePendingPromises();
}
failPendingPromises(error) {
while (this.pendingPromises.length > 0) {
this.pendingPromises.shift().reject(error);
}
}
size() {
return this._size;
}
capacity() {
return this.buffer.byteLength;
}
/**
* Reads `numBytes` from the internal buffer. throws an {Error} if there's not enough data in the
* Buffer.
*
* @param numBytes number of bytes to read.
* @returns A @{Promise<Uint8Array>} which resolves if the data is successfully read and rejects
* if the buffer doesn't have enough data.
*/
internalRead(numBytes) {
return __awaiter(this, void 0, void 0, function* () {
if (this.size() < numBytes) {
throw new Error(`Internal buffer has ${this.size} bytes, but tried to read ${numBytes}.`);
}
this._size -= numBytes;
const array = new Uint8Array(this.buffer.subarray(0, numBytes));
this.buffer.copyWithin(0, numBytes, numBytes + this.size());
return array;
});
}
tryResolvePendingPromises() {
return __awaiter(this, void 0, void 0, function* () {
while (this.pendingPromises.length > 0 && this.pendingPromises[0].dataLength <= this.size()) {
const pendingPromise = this.pendingPromises.shift();
const result = yield this.internalRead(pendingPromise.dataLength);
pendingPromise.resolve(result);
}
});
}
extendBuffer() {
const newBuffer = new Uint8Array(new ArrayBuffer(this.buffer.byteLength * 2));
newBuffer.set(this.buffer);
this.buffer = newBuffer;
}
}
exports.ReadBuffer = ReadBuffer;