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 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.Enumeration;
13  import java.util.zip.ZipEntry;
14  import java.util.zip.ZipFile;
15  import java.util.zip.ZipOutputStream;
16  
17  public class ZipUtils {
18  
19      public static void unzip(final File zipFile, final String destDir) throws IOException
20      {
21          unzip(zipFile, destDir, 0);
22      }
23  
24      public static void unzip(final File zipFile, final String destDir, int leadingPathSegmentsToTrim) throws IOException
25      {
26          final ZipFile zip = new ZipFile(zipFile);
27          try {
28              final Enumeration<? extends ZipEntry> entries = zip.entries();
29              while (entries.hasMoreElements())
30              {
31                  final ZipEntry zipEntry = entries.nextElement();
32                  String zipPath = trimPathSegments(zipEntry.getName(), leadingPathSegmentsToTrim);
33                  final File file = new File(destDir + "/" + zipPath);
34                  if (zipEntry.isDirectory())
35                  {
36                      file.mkdirs();
37                      continue;
38                  }
39                  //make sure our parent exists in case zipentries are out of order
40                  if (!file.getParentFile().exists())
41                  {
42                      file.getParentFile().mkdirs();
43                  }
44  
45                  InputStream is = null;
46                  OutputStream fos = null;
47                  try
48                  {
49                      is = zip.getInputStream(zipEntry);
50                      fos = new FileOutputStream(file);
51                      IOUtils.copy(is, fos);
52                  }
53                  finally
54                  {
55                      IOUtils.closeQuietly(is);
56                      IOUtils.closeQuietly(fos);
57                  }
58                  file.setLastModified(zipEntry.getTime());
59              }
60          } finally {
61              try {
62                  zip.close();
63              } catch (IOException e) {
64                  // ignore
65              }
66          }
67      }
68  
69       public static void zipDir(final File zipFile, final File srcDir, final String prefix) throws IOException
70       {
71           ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipFile));
72           try {
73               addZipPrefixes(srcDir, out, prefix);
74               addZipDir(srcDir, out, prefix);
75           } finally {
76               // Complete the ZIP file
77               IOUtils.closeQuietly(out);
78           }
79       }
80  
81       private static void addZipPrefixes(File dirObj, ZipOutputStream out, String prefix) throws IOException {
82           //need to manually add the prefix folders
83           String entryPrefix = ensurePrefixWithSlash(dirObj, prefix);
84  
85           String[] prefixes = entryPrefix.split("/");
86           String lastPrefix = "";
87           for (int i = 0; i < prefixes.length; i++) {
88               ZipEntry entry = new ZipEntry(lastPrefix + prefixes[i] + "/");
89               out.putNextEntry(entry);
90               out.closeEntry();
91  
92               lastPrefix = prefixes[i] + "/";
93           }
94       }
95  
96       private static void addZipDir(File dirObj, ZipOutputStream out, String prefix) throws IOException
97       {
98           File[] files = dirObj.listFiles();
99           byte[] tmpBuf = new byte[1024];
100          File currentFile;
101          String entryPrefix = ensurePrefixWithSlash(dirObj, prefix);
102          String entryName = "";
103 
104          for (int i = 0; i < files.length; i++)
105          {
106              currentFile = files[i];
107              if (currentFile.isDirectory())
108              {
109                  entryName = entryPrefix + currentFile.getName() + "/";
110 
111                  //need to manually add folders so entries are in order
112                  ZipEntry entry = new ZipEntry(entryName);
113                  out.putNextEntry(entry);
114                  out.closeEntry();
115 
116                  //add the files in the folder
117                  addZipDir(currentFile, out, entryName);
118              } else if (currentFile.isFile())
119              {
120 
121                  entryName = entryPrefix + currentFile.getName();
122                  FileInputStream in = new FileInputStream(currentFile.getAbsolutePath());
123                  try {
124                      out.putNextEntry(new ZipEntry(entryName));
125                      // Transfer from the file to the ZIP file
126                      int len;
127                      while ((len = in.read(tmpBuf)) > 0)
128                      {
129                          out.write(tmpBuf, 0, len);
130                      }
131 
132                      // Complete the entry
133                      out.closeEntry();
134                  } finally {
135                      IOUtils.closeQuietly(in);
136                  }
137              }
138          }
139      }
140 
141      private static String ensurePrefixWithSlash(File rootDir, String prefix) {
142          String entryPrefix = prefix;
143 
144          if (StringUtils.isNotBlank(entryPrefix) && !entryPrefix.equals("/"))
145          {
146              // strip leading '/'
147              if (entryPrefix.charAt(0) == '/')
148              {
149                  entryPrefix = entryPrefix.substring(1);
150              }
151              // ensure trailing '/'
152              if (entryPrefix.charAt(entryPrefix.length() - 1) != '/')
153              {
154                  entryPrefix = entryPrefix + "/";
155              }
156          } else
157          {
158              entryPrefix = rootDir.getName() + "/";
159          }
160 
161          return entryPrefix;
162      }
163 
164       private static String trimPathSegments(String zipPath, final int trimLeadingPathSegments)
165       {
166          int startIndex = 0;
167           for (int i = 0; i < trimLeadingPathSegments; i++)
168           {
169              int nextSlash = zipPath.indexOf("/", startIndex);
170               if (nextSlash == -1) {
171                   break;
172              } else {
173                  startIndex = nextSlash+1;
174               }
175           }
176 
177          return zipPath.substring(startIndex);
178       }
179 
180 }