View Javadoc

1   /**
2    * Copyright 2008 Google Inc.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package com.tonicsystems.jarjar.util;
18  
19  import java.io.*;
20  import java.util.ArrayList;
21  import java.util.Collections;
22  import java.util.Comparator;
23  import java.util.Enumeration;
24  import java.util.zip.ZipEntry;
25  import java.util.zip.ZipFile;
26  import java.util.zip.ZipOutputStream;
27  
28  class IoUtil {
29      private IoUtil() {}
30  
31      public static void pipe(InputStream is, OutputStream out, byte[] buf) throws IOException {
32          for (;;) {
33              int amt = is.read(buf);
34              if (amt < 0)
35                  break;
36              out.write(buf, 0, amt);
37          }
38      }
39  
40      public static void copy(File from, File to, byte[] buf) throws IOException {
41          InputStream in = new FileInputStream(from);
42          try {
43              OutputStream out = new FileOutputStream(to);
44              try {
45                  pipe(in, out, buf);
46              } finally {
47                  out.close();
48              }
49          } finally {
50              in.close();
51          }
52      }
53  
54      /**
55       * Create a copy of an zip file without its empty directories.
56       * @param inputFile
57       * @param outputFile
58       * @throws IOException
59       */
60      public static void copyZipWithoutEmptyDirectories(final File inputFile, final File outputFile) throws IOException
61      {
62          final byte[] buf = new byte[0x2000];
63  
64          final ZipFile inputZip = new ZipFile(inputFile);
65          final ZipOutputStream outputStream = new ZipOutputStream(new FileOutputStream(outputFile));
66          try
67          {
68              // read a the entries of the input zip file and sort them
69              final Enumeration<? extends ZipEntry> e = inputZip.entries();
70              final ArrayList<ZipEntry> sortedList = new ArrayList<ZipEntry>();
71              while (e.hasMoreElements()) {
72                  final ZipEntry entry = e.nextElement();
73                  // META-INF/ doesn't need a directory entry
74                  if (!"META-INF/".equals(entry.getName())) {
75                      sortedList.add(entry);
76                  }
77              }
78  
79              Collections.sort(sortedList, new Comparator<ZipEntry>()
80              {
81                  public int compare(ZipEntry o1, ZipEntry o2)
82                  {
83                      String n1 = o1.getName(), n2 = o2.getName();
84                      if (metaOverride(n1, n2)) {
85                          return -1;
86                      }
87                      if (metaOverride(n2, n1)) {
88                          return 1;
89                      }
90                      return n1.compareTo(n2);
91                  }
92  
93                  // make sure that META-INF/MANIFEST.MF is always the very first entry
94                  private boolean metaOverride(String n1, String n2) {
95                      return (n1.startsWith("META-INF/") && !n2.startsWith("META-INF/"))
96                          || (n1.equals("META-INF/MANIFEST.MF") && !n2.equals(n1));
97                  }
98              });
99  
100             // treat them again and write them in output, wenn they not are empty directories
101             for (int i = sortedList.size()-1; i>=0; i--)
102             {
103                 final ZipEntry inputEntry = sortedList.get(i);
104                 final String name = inputEntry.getName();
105                 final boolean isEmptyDirectory;
106                 if (inputEntry.isDirectory())
107                 {
108                     if (i == sortedList.size()-1)
109                     {
110                         // no item afterwards; it was an empty directory
111                         isEmptyDirectory = true;
112                     }
113                     else
114                     {
115                         final String nextName = sortedList.get(i+1).getName();
116                         isEmptyDirectory  = !nextName.startsWith(name);
117                     }
118                 }
119                 else
120                 {
121                     isEmptyDirectory = false;
122                 }
123 
124                 if (isEmptyDirectory)
125                 {
126                     sortedList.remove(i);
127                 }
128             }
129 
130             // finally write entries in normal order
131             for (int i = 0; i < sortedList.size(); i++)
132             {
133                 final ZipEntry inputEntry = sortedList.get(i);
134                 final ZipEntry outputEntry = new ZipEntry(inputEntry);
135                 outputStream.putNextEntry(outputEntry);
136                 ByteArrayOutputStream baos = new ByteArrayOutputStream();
137                 final InputStream is = inputZip.getInputStream(inputEntry);
138                 IoUtil.pipe(is, baos, buf);
139                 is.close();
140                 outputStream.write(baos.toByteArray());
141             }
142         } finally {
143             outputStream.close();
144             inputZip.close();
145         }
146 
147     }
148 
149 }