|
1 | 1 | import { pathExists } from "fs-extra"; |
2 | | -import * as unzipper from "unzipper"; |
| 2 | +import { Entry as ZipEntry, ZipFile } from "yauzl"; |
3 | 3 | import * as vscode from "vscode"; |
4 | 4 | import { extLogger } from "../logging/vscode"; |
| 5 | +import { |
| 6 | + excludeDirectories, |
| 7 | + openZip, |
| 8 | + openZipBuffer, |
| 9 | + readZipEntries, |
| 10 | +} from "../unzip"; |
5 | 11 |
|
6 | 12 | // All path operations in this file must be on paths *within* the zip |
7 | 13 | // archive. |
@@ -177,20 +183,31 @@ function ensureDir(map: DirectoryHierarchyMap, dir: string) { |
177 | 183 | } |
178 | 184 |
|
179 | 185 | type Archive = { |
180 | | - unzipped: unzipper.CentralDirectory; |
| 186 | + zipFile: ZipFile; |
| 187 | + entries: ZipEntry[]; |
181 | 188 | dirMap: DirectoryHierarchyMap; |
182 | 189 | }; |
183 | 190 |
|
184 | 191 | async function parse_zip(zipPath: string): Promise<Archive> { |
185 | 192 | if (!(await pathExists(zipPath))) { |
186 | 193 | throw vscode.FileSystemError.FileNotFound(zipPath); |
187 | 194 | } |
| 195 | + const zipFile = await openZip(zipPath, { |
| 196 | + lazyEntries: true, |
| 197 | + autoClose: false, |
| 198 | + strictFileNames: true, |
| 199 | + }); |
| 200 | + |
| 201 | + const entries = excludeDirectories(await readZipEntries(zipFile)); |
| 202 | + |
188 | 203 | const archive: Archive = { |
189 | | - unzipped: await unzipper.Open.file(zipPath), |
| 204 | + zipFile, |
| 205 | + entries, |
190 | 206 | dirMap: new Map(), |
191 | 207 | }; |
192 | | - archive.unzipped.files.forEach((f) => { |
193 | | - ensureFile(archive.dirMap, path.resolve("/", f.path)); |
| 208 | + |
| 209 | + entries.forEach((f) => { |
| 210 | + ensureFile(archive.dirMap, path.resolve("/", f.fileName)); |
194 | 211 | }); |
195 | 212 | return archive; |
196 | 213 | } |
@@ -276,22 +293,16 @@ export class ArchiveFileSystemProvider implements vscode.FileSystemProvider { |
276 | 293 | // use '/' as path separator throughout |
277 | 294 | const reqPath = ref.pathWithinSourceArchive; |
278 | 295 |
|
279 | | - const file = archive.unzipped.files.find((f) => { |
280 | | - const absolutePath = path.resolve("/", f.path); |
| 296 | + const file = archive.entries.find((f) => { |
| 297 | + const absolutePath = path.resolve("/", f.fileName); |
281 | 298 | return ( |
282 | 299 | absolutePath === reqPath || |
283 | 300 | absolutePath === path.join("/src_archive", reqPath) |
284 | 301 | ); |
285 | 302 | }); |
286 | 303 | if (file !== undefined) { |
287 | | - if (file.type === "File") { |
288 | | - return new File(reqPath, await file.buffer()); |
289 | | - } else { |
290 | | - // file.type === 'Directory' |
291 | | - // I haven't observed this case in practice. Could it happen |
292 | | - // with a zip file that contains empty directories? |
293 | | - return new Directory(reqPath); |
294 | | - } |
| 304 | + const buffer = await openZipBuffer(archive.zipFile, file); |
| 305 | + return new File(reqPath, buffer); |
295 | 306 | } |
296 | 307 | if (archive.dirMap.has(reqPath)) { |
297 | 308 | return new Directory(reqPath); |
|
0 commit comments