Files
eh-downloader/utils/readonly_zip.ts

93 lines
2.4 KiB
TypeScript

import * as lz from "@lifegpc/libzip/raw";
function get_err(err: number) {
const e = lz.ZipErrorT.new();
lz.zip_error_init_with_code(e, err);
const s = lz.zip_error_strerror(e);
lz.zip_error_fini(e);
return s;
}
class ZipFile {
#file: lz.ZipFileT;
#closed = false;
constructor(f: lz.ZipFileT) {
this.#file = f;
}
#check_close() {
if (this.#closed) throw Error("Already closed.");
}
close() {
if (this.#closed) return;
this.#closed = true;
const er = lz.zip_fclose(this.#file);
if (er) {
throw Error(`Failed to close file: ${get_err(er)}`);
}
}
read(buf: Uint8Array) {
this.#check_close();
const num = lz.zip_fread(this.#file, buf);
if (num == -1) {
throw Error(
`Failed to read file: ${lz.zip_file_strerror(this.#file)}`,
);
}
return num;
}
}
export class ReadonlyZip {
#zip: lz.ZipT;
#discarded = false;
#opened_file_list: ZipFile[] = [];
constructor(path: string) {
const ep = lz.IntPointer.new();
const z = lz.zip_open(path, lz.ZipOpenFlag.RDONLY, ep);
if (!z) {
throw Error(`Failed to open archive: ${get_err(ep.int)}.`);
}
this.#zip = z;
}
close() {
if (this.#discarded) return;
for (const f of this.#opened_file_list) {
f.close();
}
this.#discarded = true;
lz.zip_discard(this.#zip);
}
get count() {
return lz.zip_get_num_entries(this.#zip, 0);
}
get_index(name: string) {
return lz.zip_name_locate(this.#zip, name, lz.ZipFlags.ENC_UTF_8);
}
get_name(index: number | bigint) {
return lz.zip_get_name(this.#zip, index, 0);
}
open(name: string) {
const z = lz.zip_fopen(this.#zip, name, lz.ZipFlags.ENC_UTF_8);
if (!z) {
const errmsg = lz.zip_strerror(this.#zip);
return errmsg;
}
const f = new ZipFile(z);
this.#opened_file_list.push(f);
return f;
}
open_index(index: number | bigint) {
const z = lz.zip_fopen_index(this.#zip, index, 0);
if (!z) {
const errmsg = lz.zip_strerror(this.#zip);
return errmsg;
}
const f = new ZipFile(z);
this.#opened_file_list.push(f);
return f;
}
}