forked from DustinBrett/daedalOS
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathzipFunctions.ts
More file actions
151 lines (129 loc) · 3.86 KB
/
zipFunctions.ts
File metadata and controls
151 lines (129 loc) · 3.86 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
import { basename, extname, join } from "path";
import {
type AsyncZipOptions,
type AsyncZippable,
type AsyncZippableFile,
type Unzipped,
} from "fflate";
import type SevenZip from "7z-wasm";
import { loadFiles } from "utils/functions";
import { BASE_ZIP_CONFIG } from "utils/constants";
export const createZippable = (path: string, file: Buffer): AsyncZippable =>
path
.split("/")
.reduceRight<AsyncZippable>((value, key) => ({ [key]: value }), [
file,
BASE_ZIP_CONFIG,
] as AsyncZippableFile as AsyncZippable);
export const addEntryToZippable = (
oldZippable: AsyncZippable,
newZippable: AsyncZippable
): AsyncZippable => {
const [[key, value]] = Object.entries(newZippable);
// eslint-disable-next-line no-param-reassign
oldZippable[key] =
key in oldZippable
? addEntryToZippable(
oldZippable[key] as AsyncZippable,
newZippable[key] as AsyncZippable
)
: value;
return oldZippable;
};
const unzipAsync = (zipFile: Buffer): Promise<Unzipped> =>
new Promise((resolve, reject) => {
import("fflate").then(({ unzip }) =>
unzip(zipFile, (error, data) => (error ? reject(error) : resolve(data)))
);
});
export const zipAsync = (
data: AsyncZippable,
opts: AsyncZipOptions = BASE_ZIP_CONFIG
): Promise<Uint8Array> =>
new Promise((resolve, reject) => {
import("fflate").then(({ zip }) =>
zip(data, opts, (error, zipData) =>
error ? reject(error) : resolve(zipData)
)
);
});
export const addFileToZip = async (
buffer: Buffer,
filePath: string,
zipFilePath: string,
readFile: (path: string) => Promise<Buffer>
): Promise<Buffer> =>
Buffer.from(
await zipAsync(
addEntryToZippable(
(buffer.length > 0 && (await unzipAsync(buffer))) || {},
createZippable(zipFilePath, await readFile(filePath))
)
)
);
export const isFileInZip = (
buffer: Buffer,
zipFilePath: string
): Promise<boolean> =>
new Promise((resolve, reject) => {
import("fflate").then(({ unzip }) =>
unzip(buffer, (unzipError, zipData) =>
unzipError
? reject(unzipError)
: resolve(Object.keys(zipData).includes(zipFilePath))
)
);
});
export { unzipAsync as unzip };
declare global {
interface Window {
SevenZip: typeof SevenZip;
}
}
export const unarchive = async (
path: string,
data: Buffer
): Promise<Unzipped> => {
if (!window.SevenZip) {
await loadFiles(["System/7zip/7zz.es6.js"]);
}
if (!window.SevenZip) return {};
const sevenZip = await window.SevenZip();
const fileName = basename(path);
const extractFolder = join("/", basename(path, extname(path)));
sevenZip.FS.mkdir(extractFolder);
sevenZip.FS.chdir(extractFolder);
const stream = sevenZip.FS.open(fileName, "w+");
sevenZip.FS.write(stream, data, 0, data.length);
sevenZip.FS.close(stream);
sevenZip.callMain(["-y", "x", fileName]);
const extractedFiles = sevenZip.FS.readdir(extractFolder);
const reduceFiles =
(currentPath: string) =>
(accFiles: Unzipped, file: string): Unzipped => {
if ([".", "..", fileName].includes(file)) return accFiles;
const filePath = join(currentPath, file);
const extractPath = filePath.replace(extractFolder, "");
try {
sevenZip.FS.chmod(filePath, 0o777);
} catch {
// Ignore failure to change permissions
}
Object.assign(
accFiles,
sevenZip.FS.isDir(sevenZip.FS.stat(filePath).mode)
? {
[join(extractPath, "/")]: Buffer.from(""),
...sevenZip.FS.readdir(filePath).reduce(
reduceFiles(filePath),
{}
),
}
: {
[extractPath]: sevenZip.FS.readFile(filePath, { flags: "r" }),
}
);
return accFiles;
};
return extractedFiles.reduce(reduceFiles(extractFolder), {});
};