1 package com.atlassian.maven.plugins.amps.util;
2
3 import org.apache.commons.io.IOUtils;
4 import org.apache.commons.lang.StringUtils;
5
6 import com.google.common.collect.Lists;
7
8
9 import java.io.File;
10 import java.io.FileInputStream;
11 import java.io.FileOutputStream;
12 import java.io.IOException;
13 import java.io.InputStream;
14 import java.io.OutputStream;
15 import java.util.Enumeration;
16 import java.util.List;
17 import java.util.zip.ZipEntry;
18 import java.util.zip.ZipException;
19 import java.util.zip.ZipFile;
20 import java.util.zip.ZipOutputStream;
21
22 public class ZipUtils
23 {
24 public static void unzip(final File zipFile, final String destDir) throws IOException
25 {
26 unzip(zipFile, destDir, 0);
27 }
28
29
30
31
32
33
34
35
36
37
38
39
40
41 public static void unzip(final File zipFile, final String destDir, int leadingPathSegmentsToTrim) throws IOException
42 {
43 final ZipFile zip = new ZipFile(zipFile);
44 try
45 {
46 final Enumeration<? extends ZipEntry> entries = zip.entries();
47 while (entries.hasMoreElements())
48 {
49 final ZipEntry zipEntry = entries.nextElement();
50 String zipPath = trimPathSegments(zipEntry.getName(), leadingPathSegmentsToTrim);
51 final File file = new File(destDir + "/" + zipPath);
52 if (zipEntry.isDirectory())
53 {
54 file.mkdirs();
55 continue;
56 }
57
58 if (!file.getParentFile().exists())
59 {
60 file.getParentFile().mkdirs();
61 }
62
63 InputStream is = null;
64 OutputStream fos = null;
65 try
66 {
67 is = zip.getInputStream(zipEntry);
68 fos = new FileOutputStream(file);
69 IOUtils.copy(is, fos);
70 }
71 finally
72 {
73 IOUtils.closeQuietly(is);
74 IOUtils.closeQuietly(fos);
75 }
76 file.setLastModified(zipEntry.getTime());
77 }
78 }
79 finally
80 {
81 try
82 {
83 zip.close();
84 }
85 catch (IOException e)
86 {
87
88 }
89 }
90 }
91
92
93
94
95
96
97
98
99
100 public static int countNestingLevel(File zip) throws ZipException, IOException
101 {
102 List<String> filenames = toList(new ZipFile(zip).entries());
103 return countNestingLevel(filenames);
104 }
105
106
107
108
109
110
111
112
113 static int countNestingLevel(List<String> filenames)
114 {
115 String prefix = StringUtils.getCommonPrefix(filenames.toArray(new String[filenames.size()]));
116 if (!prefix.endsWith("/"))
117 {
118 prefix = prefix.substring(0, prefix.lastIndexOf("/") + 1);
119 }
120
121
122
123
124
125
126 if (filenames.remove(prefix))
127 {
128 return countNestingLevel(filenames);
129 }
130
131
132 filenames.clear();
133 return StringUtils.countMatches(prefix, "/");
134 }
135
136 private static List<String> toList(final Enumeration<? extends ZipEntry> entries)
137 {
138 List<String> filenamesList = Lists.newArrayList();
139 while (entries.hasMoreElements())
140 {
141 final ZipEntry zipEntry = entries.nextElement();
142 filenamesList.add(zipEntry.getName());
143 }
144 return filenamesList;
145 }
146
147
148
149
150
151 public static void zipDir(final File zipFile, final File srcDir, final String prefix) throws IOException
152 {
153 ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipFile));
154 try
155 {
156 addZipPrefixes(srcDir, out, prefix);
157 addZipDir(srcDir, out, prefix);
158 }
159 finally
160 {
161
162 IOUtils.closeQuietly(out);
163 }
164 }
165
166 private static void addZipPrefixes(File dirObj, ZipOutputStream out, String prefix) throws IOException
167 {
168
169 String entryPrefix = ensurePrefixWithSlash(dirObj, prefix);
170
171 String[] prefixes = entryPrefix.split("/");
172 String lastPrefix = "";
173 for (int i = 0; i < prefixes.length; i++)
174 {
175 ZipEntry entry = new ZipEntry(lastPrefix + prefixes[i] + "/");
176 out.putNextEntry(entry);
177 out.closeEntry();
178
179 lastPrefix = prefixes[i] + "/";
180 }
181 }
182
183 private static void addZipDir(File dirObj, ZipOutputStream out, String prefix) throws IOException
184 {
185 File[] files = dirObj.listFiles();
186 byte[] tmpBuf = new byte[1024];
187 File currentFile;
188 String entryPrefix = ensurePrefixWithSlash(dirObj, prefix);
189 String entryName = "";
190
191 for (int i = 0; i < files.length; i++)
192 {
193 currentFile = files[i];
194 if (currentFile.isDirectory())
195 {
196 entryName = entryPrefix + currentFile.getName() + "/";
197
198
199 ZipEntry entry = new ZipEntry(entryName);
200 out.putNextEntry(entry);
201 out.closeEntry();
202
203
204 addZipDir(currentFile, out, entryName);
205 }
206 else if (currentFile.isFile())
207 {
208
209 entryName = entryPrefix + currentFile.getName();
210 FileInputStream in = new FileInputStream(currentFile.getAbsolutePath());
211 try
212 {
213 out.putNextEntry(new ZipEntry(entryName));
214
215 int len;
216 while ((len = in.read(tmpBuf)) > 0)
217 {
218 out.write(tmpBuf, 0, len);
219 }
220
221
222 out.closeEntry();
223 }
224 finally
225 {
226 IOUtils.closeQuietly(in);
227 }
228 }
229 }
230 }
231
232
233
234
235
236 private static String ensurePrefixWithSlash(File rootDir, String prefix)
237 {
238 String entryPrefix = prefix;
239
240 if (StringUtils.isNotBlank(entryPrefix) && !entryPrefix.equals("/"))
241 {
242
243 if (entryPrefix.charAt(0) == '/')
244 {
245 entryPrefix = entryPrefix.substring(1);
246 }
247
248 if (entryPrefix.charAt(entryPrefix.length() - 1) != '/')
249 {
250 entryPrefix = entryPrefix + "/";
251 }
252 }
253 else
254 {
255 entryPrefix = rootDir.getName() + "/";
256 }
257
258 return entryPrefix;
259 }
260
261 private static String trimPathSegments(String zipPath, final int trimLeadingPathSegments)
262 {
263 int startIndex = 0;
264 for (int i = 0; i < trimLeadingPathSegments; i++)
265 {
266 int nextSlash = zipPath.indexOf("/", startIndex);
267 if (nextSlash == -1)
268 {
269 break;
270 }
271 else
272 {
273 startIndex = nextSlash + 1;
274 }
275 }
276
277 return zipPath.substring(startIndex);
278 }
279
280 }