UNPKG

@gmod/bgzf-filehandle

Version:

read from a compressed bgzip file (with .gzi) as if it were uncompressed

75 lines 2.52 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const long_ts_1 = require("./long.js"); const ENTRY_SIZE = 16; function parseEntries(buf, numEntries) { const entries = new Array(numEntries + 1); entries[0] = [0, 0]; const view = new DataView(buf.buffer, buf.byteOffset, buf.byteLength); for (let i = 0; i < numEntries; i += 1) { const offset = i * ENTRY_SIZE; entries[i + 1] = [(0, long_ts_1.readUint64LE)(view, offset), (0, long_ts_1.readUint64LE)(view, offset + 8)]; } return entries; } // lower-bound binary search: first index whose uncompressed start > position function findUpperBound(entries, position) { let lo = 0; let hi = entries.length; while (lo < hi) { const mid = (lo + hi) >>> 1; if (entries[mid][1] <= position) { lo = mid + 1; } else { hi = mid; } } return lo; } class GziIndex { filehandle; index; constructor({ filehandle }) { this.filehandle = filehandle; } _getIndex() { if (!this.index) { this.index = this._readIndex().catch((error) => { this.index = undefined; throw error; }); } return this.index; } async _readIndex() { const header = await this.filehandle.read(8, 0); const numEntries = (0, long_ts_1.readUint64LE)(new DataView(header.buffer, header.byteOffset, header.byteLength)); if (numEntries === 0) { return [[0, 0]]; } if (numEntries > Number.MAX_SAFE_INTEGER / ENTRY_SIZE) { throw new TypeError('integer overflow'); } const body = await this.filehandle.read(ENTRY_SIZE * numEntries, 8); return parseEntries(body, numEntries); } async getRelevantBlocksForRead(length, position) { if (length === 0) { return { blocks: [], nextCompressedPosition: undefined }; } const entries = await this._getIndex(); const readEnd = position + length; const startBlock = findUpperBound(entries, position) - 1; let endBlock = startBlock + 1; while (endBlock < entries.length && entries[endBlock][1] < readEnd) { endBlock += 1; } return { blocks: entries.slice(startBlock, endBlock), nextCompressedPosition: entries[endBlock]?.[0], }; } } exports.default = GziIndex; //# sourceMappingURL=gziIndex.js.map