1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.ximtec.igesture.util;
18
19 import java.io.File;
20 import java.io.FileNotFoundException;
21 import java.io.FileOutputStream;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.util.ArrayList;
25 import java.util.Enumeration;
26 import java.util.HashMap;
27 import java.util.HashSet;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.Set;
31 import java.util.zip.ZipEntry;
32 import java.util.zip.ZipFile;
33 import java.util.zip.ZipOutputStream;
34
35 import org.apache.commons.io.FileUtils;
36 import org.apache.commons.io.IOUtils;
37 import org.sigtec.util.Constant;
38
39
40
41
42
43
44
45
46
47
48
49
50 public class ZipFS {
51
52 public final static String SEPERATOR = "/";
53
54 private ZipFile zipFile;
55 private File originalZipFile;
56 private File tmpZipFile;
57 private ZipOutputStream zipOutput;
58 private Map<String, Map<String, ZipEntry>> fileIndex;
59 private Set<String> toIgnore;
60
61 public ZipFS(File file) throws IOException {
62 this.originalZipFile = file;
63
64 if (this.originalZipFile.exists()) {
65 zipFile = new ZipFile(this.originalZipFile);
66 fileIndex = indexFile(zipFile);
67 } else {
68 fileIndex = new HashMap<String, Map<String, ZipEntry>>();
69 }
70
71 tmpZipFile = File.createTempFile(Long.toHexString(System.currentTimeMillis()), ".tmp");
72 zipOutput = new ZipOutputStream(new FileOutputStream(tmpZipFile));
73
74 toIgnore = new HashSet<String>();
75 }
76
77
78
79
80
81
82
83
84
85 private synchronized Map<String, Map<String, ZipEntry>> indexFile(ZipFile file) throws IOException {
86 Map<String, Map<String, ZipEntry>> fileIndex = new HashMap<String, Map<String, ZipEntry>>();
87
88 Enumeration<? extends ZipEntry> enumerator = file.entries();
89 fileIndex.put(Constant.EMPTY_STRING, new HashMap<String, ZipEntry>());
90 while (enumerator.hasMoreElements()) {
91 ZipEntry entry = enumerator.nextElement();
92 addEntryToIndex(fileIndex, entry);
93 }
94
95 return fileIndex;
96 }
97
98
99
100
101
102
103 private void addEntryToIndex(Map<String, Map<String, ZipEntry>> index, ZipEntry zipEntry) {
104 String parentPath = getParentPath(zipEntry);
105 createDirectoryEntry(index, parentPath);
106
107 if (zipEntry.isDirectory()) {
108 index.get(parentPath).put(getName(zipEntry), zipEntry);
109 } else {
110 index.get(parentPath).put(getName(zipEntry), zipEntry);
111 }
112 }
113
114
115
116
117
118
119
120 private void createDirectoryEntry(Map<String, Map<String, ZipEntry>> index, String path) {
121 path = normalizePath(path);
122 if (path.contains(SEPERATOR)) {
123 createDirectoryEntry(index, path.substring(0, path.lastIndexOf(SEPERATOR)));
124 }
125 if (!index.containsKey(path)) {
126 index.put(path, new HashMap<String, ZipEntry>());
127 String parentPath = getParentPath(path);
128 index.get(parentPath).put(getName(path), new ZipEntry(path + SEPERATOR));
129 }
130 }
131
132
133
134
135
136
137
138 public static String getName(ZipEntry zipEntry) {
139 return getName(zipEntry.getName());
140 }
141
142
143
144
145
146
147
148
149 public static String getName(String path) {
150 path = normalizePath(path);
151 int index = path.lastIndexOf(SEPERATOR) + 1;
152 if (index == 0) {
153 return path;
154 } else {
155 return path.substring(index);
156 }
157 }
158
159
160
161
162
163
164
165
166
167 private static String normalizePath(String path) {
168 while (path.endsWith(SEPERATOR)) {
169 path = path.substring(0, path.length() - 1);
170 }
171
172 while (path.startsWith(SEPERATOR)) {
173 path = path.substring(1);
174 }
175
176 return path;
177 }
178
179
180
181
182
183
184
185
186
187 public static String getParentPath(ZipEntry zipEntry) {
188 return getParentPath(zipEntry.getName());
189 }
190
191
192
193
194
195
196
197
198 public static String getParentPath(String path) {
199 if (path == null) {
200 return null;
201 }
202
203 path = normalizePath(path);
204
205 int lastIndex = path.lastIndexOf(SEPERATOR);
206
207 if (lastIndex == -1) {
208 return Constant.EMPTY_STRING;
209 } else {
210 return path.substring(0, lastIndex);
211 }
212 }
213
214
215
216
217
218
219
220 public List<ZipEntry> listFiles(String path) {
221 path = normalizePath(path);
222 if (fileIndex.containsKey(path)) {
223 return new ArrayList<ZipEntry>(fileIndex.get(path).values());
224 }
225 return new ArrayList<ZipEntry>();
226 }
227
228
229
230
231
232
233
234
235 public InputStream getInputStream(String path) throws IOException {
236 return zipFile.getInputStream(getEntry(path));
237 }
238
239
240
241
242
243
244
245
246 public InputStream getInputStream(ZipEntry entry) throws IOException {
247 return getInputStream(entry.getName());
248 }
249
250
251
252
253
254
255
256
257 public ZipEntry getEntry(String path) throws IOException {
258 String parentPath = getParentPath(path);
259 String name = getName(path);
260 Map<String, ZipEntry> entries = fileIndex.get(parentPath);
261 ZipEntry entry = null;
262
263 if (entries != null) {
264 entry = entries.get(name);
265 }
266
267 if (entry == null || entry.isDirectory()) {
268 throw new FileNotFoundException(path);
269 }
270
271 return entry;
272 }
273
274 public ZipFS(String fileName) throws IOException {
275 this(new File(fileName));
276 }
277
278
279
280
281
282
283 public void delete(String path) {
284 toIgnore.add(normalizePath(path));
285 }
286
287
288
289
290
291
292
293
294 public void store(String path, InputStream stream) throws IOException {
295 toIgnore.add(normalizePath(path));
296 ZipEntry entry = new ZipEntry(path);
297 zipOutput.putNextEntry(entry);
298 IOUtils.copy(stream, zipOutput);
299 zipOutput.closeEntry();
300 }
301
302
303
304
305 private void copyEntries() {
306 if (zipFile != null) {
307 Enumeration<? extends ZipEntry> enumerator = zipFile.entries();
308 while (enumerator.hasMoreElements()) {
309 ZipEntry entry = enumerator.nextElement();
310 if (!entry.isDirectory() && !toIgnore.contains(normalizePath(entry.getName()))) {
311 ZipEntry originalEntry = new ZipEntry(entry.getName());
312 try {
313 zipOutput.putNextEntry(originalEntry);
314 IOUtils.copy(getInputStream(entry.getName()), zipOutput);
315 zipOutput.closeEntry();
316 } catch (IOException e) {
317 e.printStackTrace();
318 }
319 }
320 }
321 }
322 }
323
324
325
326
327
328
329 public void close() throws IOException {
330
331 if (zipFile != null) {
332 copyEntries();
333 zipOutput.close();
334 zipFile.close();
335 originalZipFile.delete();
336 if (!originalZipFile.exists()) {
337 FileUtils.moveFile(tmpZipFile, originalZipFile);
338 }
339 } else {
340 store("readme", IOUtils.toInputStream("see http://www.igesture.org"));
341 zipOutput.flush();
342 zipOutput.close();
343 if (!originalZipFile.exists()) {
344 FileUtils.moveFile(tmpZipFile, originalZipFile);
345 }
346 }
347
348 }
349 }