UNPKG

byte-rw

Version:

Byte reader/writer for buffers and streams in typescript/javascript

182 lines (181 loc) 7.85 kB
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 } from "../utils/copy.js"; import { DataViewByteReaderAsync } from "./reader-async.js"; export class DataViewByteReaderAsyncChunked extends DataViewByteReaderAsync { get currentChunk() { return this._currentChunk; } set currentChunk(currentChunk) { this._currentChunk = currentChunk; this._dataview = currentChunk.view instanceof DataView ? currentChunk.view : new DataView(currentChunk.view.buffer, currentChunk.view.byteOffset, currentChunk.view.byteLength); } get _bytesRemaining() { let remaining = this._bytesRemaining_currentChunk; for (const pendingChunk of this.pendingChunks) remaining += pendingChunk.bytesWritten; return remaining; } get _bytesRemaining_currentChunk() { return this.currentChunk.bytesWritten - this._byteOffset; } constructor(littleEndian, defaultChunkSize = 4096) { super(new DataView(new ArrayBuffer(defaultChunkSize)), littleEndian); this.defaultChunkSize = defaultChunkSize; this.pendingChunks = []; this._currentChunk = { view: this._dataview, bytesWritten: 0 }; } pendChunk(chunk) { chunk !== null && chunk !== void 0 ? chunk : (chunk = { view: { buffer: new ArrayBuffer(this.defaultChunkSize), byteOffset: 0, byteLength: this.defaultChunkSize }, bytesWritten: 0 }); this.pendingChunks.push(chunk); return chunk; } /** * Attempts to ensure that a specified number of bytes are available in the * current chunk. * * @param bytes the number of bytes to fill (total bytesWritten should * increase by this amount at least) * @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 (bytes <= this._bytesRemaining_currentChunk) return bytes; function resizeCurrentChunk(size) { const currentChunk_length = this._bytesRemaining_currentChunk; if (currentChunk_length >= size) return size; const tmpChunk_buffer = new ArrayBuffer(size); let tmpChunk_bytesWritten = 0; copy({ buffer: this.currentChunk.view.buffer, byteOffset: this.currentChunk.view.byteOffset + this._byteOffset, byteLength: currentChunk_length }, { buffer: tmpChunk_buffer, byteOffset: 0, byteLength: currentChunk_length }); tmpChunk_bytesWritten += currentChunk_length; while (tmpChunk_bytesWritten < size) { const pendingChunk = this.pendingChunks.shift(); if (!pendingChunk) break; const toCopy = Math.min(pendingChunk.bytesWritten, size - tmpChunk_bytesWritten); copy({ buffer: pendingChunk.view.buffer, byteOffset: pendingChunk.view.byteOffset, byteLength: toCopy }, { buffer: tmpChunk_buffer, byteOffset: tmpChunk_bytesWritten, byteLength: toCopy }); if (toCopy < pendingChunk.bytesWritten) { this.pendingChunks.unshift({ view: { buffer: pendingChunk.view.buffer, byteOffset: pendingChunk.view.byteOffset + toCopy, byteLength: pendingChunk.view.byteLength + toCopy }, bytesWritten: pendingChunk.bytesWritten + toCopy, }); } tmpChunk_bytesWritten += toCopy; } this.currentChunk = { view: { buffer: tmpChunk_buffer, byteOffset: 0, byteLength: size }, bytesWritten: tmpChunk_bytesWritten }; this._byteOffset = 0; return tmpChunk_bytesWritten; } if (this._bytesRemaining_currentChunk === 0) { const pendingChunk = this.pendingChunks.shift(); if (pendingChunk) { if (pendingChunk.bytesWritten < bytes) this.pendingChunks.unshift(pendingChunk); else { this.currentChunk = pendingChunk; this._byteOffset = 0; return bytes; } } yield this.fill(bytes - this._bytesRemaining); return resizeCurrentChunk.call(this, bytes); } else { const toFill = bytes - this._bytesRemaining; yield this.fill(toFill); return resizeCurrentChunk.call(this, bytes); } }); } tryReadBytes(view) { return __awaiter(this, void 0, void 0, function* () { let read = 0; function copyFromCurrentChunk() { const toCopy_remaining = view.byteLength - read; const toCopy = Math.min(this._bytesRemaining_currentChunk, toCopy_remaining); copy({ buffer: this.currentChunk.view.buffer, byteOffset: this.currentChunk.view.byteOffset + this._byteOffset, byteLength: toCopy }, { buffer: view.buffer, byteOffset: view.byteOffset, byteLength: toCopy }); read += toCopy; this._byteOffset += toCopy; } if (this._bytesRemaining_currentChunk > 0) copyFromCurrentChunk.call(this); while (read < view.byteLength && this.pendingChunks.length > 0) { this.currentChunk = this.pendingChunks.shift(); this._byteOffset = 0; copyFromCurrentChunk.call(this); } if (read < view.byteLength) { this.currentChunk = { view, bytesWritten: read }; const toFill = view.byteLength - read; const filled = yield this.fill(toFill); read += Math.min(toFill, filled); if (this.pendingChunks.length === 0) this.pendChunk(); this.currentChunk = this.pendingChunks.shift(); this._byteOffset = 0; } return read; }); } }