UNPKG

@phi-ag/rvt

Version:

Parse Revit file format

54 lines (53 loc) 1.8 kB
import { Cfb } from "./cfb/index.js"; export class DenoSource { #file; size; constructor(file, size) { this.#file = file; this.size = size; } [Symbol.dispose]() { this.#file.close(); } static async open(path) { const file = await Deno.open(path); const fileInfo = await file.stat(); return new DenoSource(file, fileInfo.size); } async sliceBytes(start, end) { if (start > end) throw Error(`Invalid slice arguments (start: ${start}, end ${end})`); const position = await this.#file.seek(start, Deno.SeekMode.Start); if (position !== start) throw Error(`Failed to seek to position ${start} (received ${position})`); const size = end - start; const buffer = new Uint8Array(size); const bytesRead = await this.#file.read(buffer); if (bytesRead !== size) throw Error(`Failed to read ${size} bytes from file (received ${bytesRead})`); return buffer; } async sliceView(start, end) { const buffer = await this.sliceBytes(start, end); return new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength); } } const noop = () => { }; export const openPath = async (path) => { const source = await DenoSource.open(path); return { data: await Cfb.initialize(source), [Symbol.dispose]: () => source[Symbol.dispose]() }; }; export const tryOpenPath = async (path) => { try { const cfb = await openPath(path); return { ok: true, data: cfb.data, [Symbol.dispose]: () => cfb[Symbol.dispose]() }; } catch (e) { if (e instanceof Error) return { ok: false, error: e.message, [Symbol.dispose]: noop }; throw e; } };