Skip to content

Commit 8203049

Browse files
committed
Добавлен модуль zip
1 parent 589fdbf commit 8203049

File tree

3 files changed

+263
-0
lines changed

3 files changed

+263
-0
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
/.nb-gradle/
44
/build/
55
/dist/
6+
/out/
67
/store/
78
/optimizations/
89
/nbproject/private/

build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ task sandbox(dependsOn: proguard, type: Jar) {
106106
"**/modules/socket/**", "io/**",
107107
"**/modules/aimp/**", "aimpremote/**",
108108
"**/modules/downloader/**",
109+
"**/modules/zip/**",
109110
"jline/**", "org/fusesource/**", "META-INF/native/**"
110111

111112
manifest {
Lines changed: 261 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,261 @@
1+
package com.annimon.ownlang.modules.zip;
2+
3+
import com.annimon.ownlang.exceptions.TypeException;
4+
import com.annimon.ownlang.lib.*;
5+
import com.annimon.ownlang.modules.Module;
6+
import java.io.File;
7+
import java.io.FileInputStream;
8+
import java.io.FileOutputStream;
9+
import java.io.IOException;
10+
import java.io.InputStream;
11+
import java.io.OutputStream;
12+
import java.util.ArrayList;
13+
import java.util.HashMap;
14+
import java.util.List;
15+
import java.util.Map;
16+
import java.util.zip.ZipEntry;
17+
import java.util.zip.ZipInputStream;
18+
import java.util.zip.ZipOutputStream;
19+
20+
public class zip implements Module {
21+
22+
@Override
23+
public void init() {
24+
Functions.set("zip", this::zipWithMapper);
25+
Functions.set("zipFiles", this::zipFiles);
26+
Functions.set("unzip", this::unzip);
27+
Functions.set("unzipFiles", this::unzipFiles);
28+
Functions.set("listZipEntries", this::listZipEntries);
29+
}
30+
31+
private Value zipWithMapper(Value[] args) {
32+
Arguments.checkOrOr(2, 3, args.length);
33+
final String inputPath = args[0].asString();
34+
final File input = new File(inputPath);
35+
if (!input.exists()) {
36+
return NumberValue.MINUS_ONE;
37+
}
38+
final File output = new File(args[1].asString());
39+
if (output.isDirectory()) {
40+
return NumberValue.MINUS_ONE;
41+
}
42+
final Function mapper = getMapperOrNull(args, 2);
43+
44+
final Map<File, String> mappings = new HashMap<>();
45+
final String rootPath = (input.isFile() ? input.getParent() : input.getAbsolutePath());
46+
generateFileList(mappings, rootPath, input, mapper);
47+
return zipFileList(mappings, output);
48+
}
49+
50+
private Value zipFiles(Value[] args) {
51+
Arguments.check(2, args.length);
52+
53+
final Map<File, String> mappings = new HashMap<>();
54+
switch (args[0].type()) {
55+
case Types.STRING: {
56+
final File file = new File(args[0].asString());
57+
mappings.put(file, file.getName());
58+
} break;
59+
case Types.ARRAY:
60+
for (Value value : ((ArrayValue) args[0])) {
61+
final File file = new File(value.asString());
62+
mappings.put(file, file.getName());
63+
}
64+
break;
65+
case Types.MAP:
66+
for (Map.Entry<Value, Value> entry : ((MapValue) args[0])) {
67+
final File file = new File(entry.getKey().asString());
68+
mappings.put(file, entry.getValue().asString());
69+
}
70+
break;
71+
default:
72+
throw new TypeException("Single file path, file paths array or file mappings expected at first argument");
73+
}
74+
75+
final File output = new File(args[1].asString());
76+
if (output.isDirectory()) {
77+
return NumberValue.MINUS_ONE;
78+
}
79+
return zipFileList(mappings, output);
80+
}
81+
82+
private Value zipFileList(Map<File, String> mappings, File output) {
83+
int count = 0;
84+
try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(output))) {
85+
for (Map.Entry<File, String> entry : mappings.entrySet()) {
86+
final File node = entry.getKey();
87+
final String entryName = entry.getValue();
88+
if (node.isDirectory()) {
89+
zos.putNextEntry(new ZipEntry(entryName + (entryName.endsWith("/") ? "" : "/")));
90+
} else {
91+
zipFile(zos, entry.getKey(), entry.getValue());
92+
count++;
93+
}
94+
}
95+
} catch (IOException ex) {
96+
throw new RuntimeException("zip files", ex);
97+
}
98+
return NumberValue.of(count);
99+
}
100+
101+
private void zipFile(ZipOutputStream zos, File file, String entryPath) throws IOException {
102+
final ZipEntry entry = new ZipEntry(entryPath);
103+
entry.setTime(file.lastModified());
104+
zos.putNextEntry(entry);
105+
try (FileInputStream fis = new FileInputStream(file)) {
106+
copy(fis, zos);
107+
}
108+
}
109+
110+
private Value unzip(Value[] args) {
111+
Arguments.checkOrOr(2, 3, args.length);
112+
final File input = new File(args[0].asString());
113+
if (!input.exists() || !input.canRead() || input.isDirectory()) {
114+
return NumberValue.MINUS_ONE;
115+
}
116+
final File output = new File(args[1].asString());
117+
if (!output.exists()) {
118+
output.mkdirs();
119+
}
120+
final Function mapper = getMapperOrNull(args, 2);
121+
122+
final Map<String, File> mappings = new HashMap<>();
123+
for (String entryName : listEntries(input)) {
124+
String fileName = entryName;
125+
if (mapper != null) {
126+
fileName = mapper.execute(new StringValue(entryName)).asString();
127+
}
128+
if (!fileName.isEmpty()) {
129+
mappings.put(entryName, new File(output, fileName));
130+
}
131+
}
132+
return unzipFileList(input, mappings);
133+
}
134+
135+
private Value unzipFiles(Value[] args) {
136+
Arguments.check(2, args.length);
137+
138+
final File input = new File(args[0].asString());
139+
if (!input.exists() || !input.canRead() || input.isDirectory()) {
140+
return NumberValue.MINUS_ONE;
141+
}
142+
143+
final Map<String, File> mappings = new HashMap<>();
144+
switch (args[1].type()) {
145+
case Types.STRING: {
146+
final String entryPath = args[1].asString();
147+
mappings.put(entryPath, new File(entryPath));
148+
} break;
149+
case Types.ARRAY:
150+
for (Value value : ((ArrayValue) args[1])) {
151+
final String entryPath = value.asString();
152+
mappings.put(entryPath, new File(entryPath));
153+
}
154+
break;
155+
case Types.MAP:
156+
for (Map.Entry<Value, Value> entry : ((MapValue) args[1])) {
157+
final File file = new File(entry.getValue().asString());
158+
mappings.put(entry.getKey().asString(), file);
159+
}
160+
break;
161+
default:
162+
throw new TypeException("Single entry path, entry paths array or entry mappings expected at second argument");
163+
}
164+
return unzipFileList(input, mappings);
165+
}
166+
167+
private Value unzipFileList(File input, Map<String, File> mappings) {
168+
int count = 0;
169+
try (ZipInputStream zis = new ZipInputStream(new FileInputStream(input))) {
170+
ZipEntry ze;
171+
while ((ze = zis.getNextEntry()) != null) {
172+
final String entryName = ze.getName();
173+
final File file = mappings.get(entryName);
174+
if (file == null) continue;
175+
176+
if (entryName.endsWith("/")) {
177+
safeMkdirs(file);
178+
} else {
179+
safeMkdirs(file.getParentFile());
180+
try (FileOutputStream fos = new FileOutputStream(file)) {
181+
copy(zis, fos);
182+
}
183+
if (ze.getTime() > 0) {
184+
file.setLastModified(ze.getTime());
185+
}
186+
count++;
187+
}
188+
}
189+
zis.closeEntry();
190+
} catch (IOException ex) {
191+
throw new RuntimeException("unzip files", ex);
192+
}
193+
return NumberValue.of(count);
194+
}
195+
196+
private Value listZipEntries(Value[] args) {
197+
Arguments.check(1, args.length);
198+
final File input = new File(args[0].asString());
199+
if (!input.exists() || !input.canRead() || input.isDirectory()) {
200+
return new ArrayValue(0);
201+
}
202+
return ArrayValue.of(listEntries(input));
203+
}
204+
205+
private Function getMapperOrNull(Value[] args, int index) {
206+
Function mapper;
207+
if (args.length >= (index + 1)) {
208+
mapper = ValueUtils.consumeFunction(args[index], index);
209+
} else {
210+
mapper = null;
211+
}
212+
return mapper;
213+
}
214+
215+
private void copy(InputStream is, OutputStream os) throws IOException {
216+
final byte[] buffer = new byte[8192];
217+
int read;
218+
while ((read = is.read(buffer)) != -1) {
219+
os.write(buffer, 0, read);
220+
}
221+
}
222+
223+
private void generateFileList(Map<File, String> mappings, String rootPath, File node, Function mapper) {
224+
if (!rootPath.equals(node.getAbsolutePath())) {
225+
String entryPath = node.getAbsolutePath().substring(rootPath.length() + 1);
226+
if (mapper != null) {
227+
entryPath = mapper.execute(new StringValue(entryPath)).asString();
228+
if (entryPath.isEmpty()) {
229+
return;
230+
}
231+
}
232+
mappings.put(node, entryPath);
233+
}
234+
235+
if (node.isDirectory()) {
236+
for (File file : node.listFiles()) {
237+
generateFileList(mappings, rootPath, file, mapper);
238+
}
239+
}
240+
}
241+
242+
private String[] listEntries(File input) {
243+
final List<String> entries = new ArrayList<>();
244+
try (ZipInputStream zis = new ZipInputStream(new FileInputStream(input))) {
245+
ZipEntry ze;
246+
while ((ze = zis.getNextEntry()) != null) {
247+
entries.add(ze.getName());
248+
}
249+
zis.closeEntry();
250+
} catch (IOException ex) {
251+
throw new RuntimeException("list zip entries", ex);
252+
}
253+
return entries.toArray(new String[0]);
254+
}
255+
256+
private void safeMkdirs(File file) {
257+
if (file != null) {
258+
file.mkdirs();
259+
}
260+
}
261+
}

0 commit comments

Comments
 (0)