Skip to content

Commit 06513f7

Browse files
committed
Minor rewrite to support sources that don't use a shared buffer
Implemented `lazy`
1 parent aec6b7f commit 06513f7

File tree

4 files changed

+155
-89
lines changed

4 files changed

+155
-89
lines changed

src/zip/fs.ts

Lines changed: 46 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
// SPDX-License-Identifier: LGPL-3.0-or-later
2-
import { FileSystem, Inode, Sync, type UsageInfo } from '@zenfs/core';
2+
import { FileSystem, Inode, type UsageInfo } from '@zenfs/core';
33
import type { Backend } from '@zenfs/core/backends/backend.js';
44
import { Readonly } from '@zenfs/core/mixins/readonly.js';
55
import { parse } from '@zenfs/core/path.js';
6-
import { S_IFDIR } from '@zenfs/core/vfs/constants.js';
6+
import { S_IFDIR, S_IFREG } from '@zenfs/core/vfs/constants.js';
77
import { withErrno } from 'kerium';
88
import { err } from 'kerium/log';
99
import { _throw } from 'utilium';
@@ -63,7 +63,7 @@ export interface ZipOptions<TBuffer extends ArrayBufferLike = ArrayBuffer> {
6363
* - Stream it out to a location.
6464
* This isn't that bad, so we might do this at a later date.
6565
*/
66-
export class ZipFS<TBuffer extends ArrayBufferLike = ArrayBuffer> extends Readonly(Sync(FileSystem)) {
66+
export class ZipFS<TBuffer extends ArrayBufferLike = ArrayBuffer> extends Readonly(FileSystem) {
6767
protected files: Map<string, FileEntry<TBuffer>> = new Map();
6868
protected directories: Map<string, Set<string>> = new Map();
6969

@@ -91,8 +91,9 @@ export class ZipFS<TBuffer extends ArrayBufferLike = ArrayBuffer> extends Readon
9191
const cdEnd = ptr + this.eocd.size;
9292

9393
while (ptr < cdEnd) {
94-
const entryData = await this.data.get(ptr, FileEntry.size);
95-
const cd = new FileEntry<TBuffer>(entryData.buffer, entryData.byteOffset);
94+
const cd = await FileEntry.from<TBuffer>(this.data, ptr);
95+
96+
if (!this.lazy) await cd.loadContents();
9697
/* Paths must be absolute,
9798
yet zip file paths are always relative to the zip root.
9899
So we prepend '/' and call it a day. */
@@ -132,7 +133,8 @@ export class ZipFS<TBuffer extends ArrayBufferLike = ArrayBuffer> extends Readon
132133

133134
public constructor(
134135
public label: string,
135-
protected data: ZipDataSource<TBuffer>
136+
protected data: ZipDataSource<TBuffer>,
137+
public readonly lazy: boolean = false
136138
) {
137139
super(0x207a6970, 'zipfs');
138140
}
@@ -144,6 +146,10 @@ export class ZipFS<TBuffer extends ArrayBufferLike = ArrayBuffer> extends Readon
144146
};
145147
}
146148

149+
public async stat(path: string): Promise<Inode> {
150+
return this.statSync(path);
151+
}
152+
147153
public statSync(path: string): Inode {
148154
// The EOCD/Header does not track directories, so it does not exist in `entries`
149155
if (this.directories.has(path)) {
@@ -161,27 +167,54 @@ export class ZipFS<TBuffer extends ArrayBufferLike = ArrayBuffer> extends Readon
161167

162168
if (!entry) throw withErrno('ENOENT');
163169

164-
return entry.inode;
170+
return new Inode({
171+
mode: 0o555 | (entry.isDirectory ? S_IFDIR : S_IFREG),
172+
size: entry.uncompressedSize,
173+
mtimeMs: entry.lastModified.getTime(),
174+
});
175+
}
176+
177+
public async readdir(path: string): Promise<string[]> {
178+
const inode = await this.stat(path);
179+
if (!(inode.mode & S_IFDIR)) throw withErrno('ENOTDIR');
180+
181+
const entries = this.directories.get(path);
182+
if (!entries) throw withErrno('ENODATA');
183+
184+
return Array.from(entries);
165185
}
166186

167187
public readdirSync(path: string): string[] {
168188
const inode = this.statSync(path);
169-
170189
if (!(inode.mode & S_IFDIR)) throw withErrno('ENOTDIR');
171190

172191
const entries = this.directories.get(path);
173-
174192
if (!entries) throw withErrno('ENODATA');
175193

176194
return Array.from(entries);
177195
}
178196

197+
public async read(path: string, buffer: Uint8Array, offset: number, end: number): Promise<void> {
198+
if (this.directories.has(path)) throw withErrno('EISDIR');
199+
200+
const file = this.files.get(path) ?? _throw(withErrno('ENOENT'));
201+
202+
if (!file.contents) await file.loadContents();
203+
204+
buffer.set(file.contents.subarray(offset, end));
205+
}
206+
179207
public readSync(path: string, buffer: Uint8Array, offset: number, end: number): void {
180208
if (this.directories.has(path)) throw withErrno('EISDIR');
181209

182-
const { contents: data } = this.files.get(path) ?? _throw(withErrno('ENOENT'));
210+
const file = this.files.get(path) ?? _throw(withErrno('ENOENT'));
211+
212+
if (!file.contents) {
213+
void file.loadContents();
214+
throw withErrno('EAGAIN');
215+
}
183216

184-
buffer.set(data.subarray(offset, end));
217+
buffer.set(file.contents.subarray(offset, end));
185218
}
186219
}
187220

@@ -278,8 +311,8 @@ const _Zip = {
278311
return true;
279312
},
280313

281-
create<TBuffer extends ArrayBufferLike = ArrayBuffer>({ name, data }: ZipOptions<TBuffer>): ZipFS<TBuffer> {
282-
return new ZipFS<TBuffer>(name ?? '', getSource(data));
314+
create<TBuffer extends ArrayBufferLike = ArrayBuffer>(opt: ZipOptions<TBuffer>): ZipFS<TBuffer> {
315+
return new ZipFS<TBuffer>(opt.name ?? '', getSource(opt.data), opt.lazy);
283316
},
284317
} satisfies Backend<ZipFS, ZipOptions>;
285318
type _Zip = typeof _Zip;

src/zip/utils.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// SPDX-License-Identifier: LGPL-3.0-or-later
22
import { decodeUTF8 } from 'utilium';
3+
import type { ZipDataSource } from './fs.js';
34

45
/**
56
* Converts the input `time` and `date` in MS-DOS format into a `Date`.
@@ -163,12 +164,12 @@ export const extendedASCIIChars = [
163164
* Safely decodes the string from a buffer.
164165
* @hidden
165166
*/
166-
export function safeDecode(buffer: Uint8Array, utf8: boolean, start: number, length: number): string {
167+
export async function safeDecode(source: ZipDataSource<any>, utf8: boolean, start: number, length: number): Promise<string> {
167168
if (length === 0) {
168169
return '';
169170
}
170171

171-
const uintArray = buffer.subarray(start, start + length);
172+
const uintArray = await source.get(start, length);
172173
if (utf8) {
173174
return decodeUTF8(uintArray);
174175
} else {

0 commit comments

Comments
 (0)