@phi-ag/rvt
Version:
Parse Revit file format
54 lines (53 loc) • 1.8 kB
JavaScript
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;
}
};