View Javadoc
1   /**
2    *
3    * Copyright 2004 The Apache Software Foundation
4    *
5    * Licensed under the Apache License, Version 2.0 (the "License");
6    * you may not use this file except in compliance with the License.
7    * You may obtain a copy of the License at
8    *
9    * http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.codehaus.plexus.archiver.zip;
18  
19  import java.io.File;
20  import java.io.IOException;
21  import java.io.InputStream;
22  import java.io.UnsupportedEncodingException;
23  import java.net.URL;
24  import java.util.Date;
25  import java.util.Enumeration;
26  import javax.annotation.Nonnull;
27  import org.apache.commons.compress.archivers.zip.UnicodePathExtraField;
28  import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
29  import org.apache.commons.compress.archivers.zip.ZipFile;
30  import org.apache.commons.compress.utils.IOUtils;
31  import org.codehaus.plexus.archiver.AbstractUnArchiver;
32  import org.codehaus.plexus.archiver.ArchiverException;
33  import org.codehaus.plexus.components.io.filemappers.FileMapper;
34  import org.codehaus.plexus.components.io.resources.PlexusIoResource;
35  
36  /**
37   * @author <a href="mailto:evenisse@codehaus.org">Emmanuel Venisse</a>
38   */
39  public abstract class AbstractZipUnArchiver
40      extends AbstractUnArchiver
41  {
42  
43      private static final String NATIVE_ENCODING = "native-encoding";
44  
45      private String encoding = "UTF8";
46  
47      public AbstractZipUnArchiver()
48      {
49      }
50  
51      public AbstractZipUnArchiver( final File sourceFile )
52      {
53          super( sourceFile );
54      }
55  
56      /**
57       * Sets the encoding to assume for file names and comments.
58       * <p>
59       * Set to <code>native-encoding</code> if you want your platform's native encoding, defaults to UTF8.
60       * </p>
61       */
62      public void setEncoding( String encoding )
63      {
64          if ( NATIVE_ENCODING.equals( encoding ) )
65          {
66              encoding = null;
67          }
68          this.encoding = encoding;
69      }
70  
71      private static class ZipEntryFileInfo
72          implements PlexusIoResource
73      {
74  
75          private final org.apache.commons.compress.archivers.zip.ZipFile zipFile;
76  
77          private final ZipArchiveEntry zipEntry;
78  
79          ZipEntryFileInfo( final org.apache.commons.compress.archivers.zip.ZipFile zipFile,
80                            final ZipArchiveEntry zipEntry )
81          {
82              this.zipFile = zipFile;
83              this.zipEntry = zipEntry;
84          }
85  
86          public String getName()
87          {
88              try
89              {
90                  final UnicodePathExtraField unicodePath =
91                      (UnicodePathExtraField) zipEntry.getExtraField( UnicodePathExtraField.UPATH_ID );
92  
93                  return unicodePath != null
94                             ? new String( unicodePath.getUnicodeName(), "UTF-8" )
95                             : zipEntry.getName();
96  
97              }
98              catch ( final UnsupportedEncodingException e )
99              {
100                 throw new AssertionError( e );
101             }
102         }
103 
104         @Override
105         public boolean isDirectory()
106         {
107             return zipEntry.isDirectory();
108         }
109 
110         @Override
111         public boolean isFile()
112         {
113             return !zipEntry.isDirectory() && !zipEntry.isUnixSymlink();
114         }
115 
116         @Override
117         public boolean isSymbolicLink()
118         {
119             return zipEntry.isUnixSymlink();
120         }
121 
122         @Nonnull
123         @Override
124         public InputStream getContents()
125             throws IOException
126         {
127             return zipFile.getInputStream( zipEntry );
128         }
129 
130         @Override
131         public long getLastModified()
132         {
133             final long l = zipEntry.getTime();
134             return l == 0 ? PlexusIoResource.UNKNOWN_MODIFICATION_DATE : l;
135         }
136 
137         @Override
138         public long getSize()
139         {
140             final long l = zipEntry.getSize();
141             return l == -1 ? PlexusIoResource.UNKNOWN_RESOURCE_SIZE : l;
142         }
143 
144         @Override
145         public URL getURL()
146             throws IOException
147         {
148             return null;
149         }
150 
151         @Override
152         public boolean isExisting()
153         {
154             return true;
155         }
156 
157     }
158 
159     @Override
160     protected void execute()
161         throws ArchiverException
162     {
163         getLogger().debug( "Expanding: " + getSourceFile() + " into " + getDestDirectory() );
164         org.apache.commons.compress.archivers.zip.ZipFile zf = null;
165         InputStream in = null;
166         try
167         {
168             zf = new org.apache.commons.compress.archivers.zip.ZipFile( getSourceFile(), encoding, true );
169             final Enumeration e = zf.getEntriesInPhysicalOrder();
170             while ( e.hasMoreElements() )
171             {
172                 final ZipArchiveEntry ze = (ZipArchiveEntry) e.nextElement();
173                 final ZipEntryFileInfo fileInfo = new ZipEntryFileInfo( zf, ze );
174                 if ( isSelected( fileInfo.getName(), fileInfo ) )
175                 {
176                     in = zf.getInputStream( ze );
177 
178                     extractFileIfIncluded( getSourceFile(), getDestDirectory(), in, fileInfo.getName(),
179                                            new Date( ze.getTime() ), ze.isDirectory(),
180                                            ze.getUnixMode() != 0 ? ze.getUnixMode() : null,
181                                            resolveSymlink( zf, ze ), getFileMappers() );
182 
183                     in.close();
184                     in = null;
185                 }
186             }
187 
188             zf.close();
189             zf = null;
190 
191             getLogger().debug( "expand complete" );
192         }
193         catch ( final IOException ioe )
194         {
195             throw new ArchiverException( "Error while expanding " + getSourceFile().getAbsolutePath(), ioe );
196         }
197         finally
198         {
199             IOUtils.closeQuietly( in );
200             IOUtils.closeQuietly( zf );
201         }
202     }
203 
204     private String resolveSymlink( ZipFile zf, ZipArchiveEntry ze )
205         throws IOException
206     {
207         if ( ze.isUnixSymlink() )
208         {
209             return zf.getUnixSymlink( ze );
210         }
211         else
212         {
213             return null;
214         }
215     }
216 
217     private void extractFileIfIncluded( final File sourceFile, final File destDirectory, final InputStream inputStream,
218                                         final String name, final Date time, final boolean isDirectory,
219                                         final Integer mode, String symlinkDestination, final FileMapper[] fileMappers )
220         throws IOException, ArchiverException
221     {
222         extractFile( sourceFile, destDirectory, inputStream, name, time, isDirectory, mode, symlinkDestination, fileMappers );
223     }
224 
225     @Override
226     protected void execute( final String path, final File outputDirectory )
227         throws ArchiverException
228     {
229         org.apache.commons.compress.archivers.zip.ZipFile zipFile = null;
230         InputStream in = null;
231         try
232         {
233             zipFile = new org.apache.commons.compress.archivers.zip.ZipFile( getSourceFile(), encoding, true );
234 
235             final Enumeration e = zipFile.getEntriesInPhysicalOrder();
236 
237             while ( e.hasMoreElements() )
238             {
239                 final ZipArchiveEntry ze = (ZipArchiveEntry) e.nextElement();
240                 final ZipEntryFileInfo fileInfo = new ZipEntryFileInfo( zipFile, ze );
241                 if ( !isSelected( ze.getName(), fileInfo ) )
242                 {
243                     continue;
244                 }
245 
246                 if ( ze.getName().startsWith( path ) )
247                 {
248                     in = zipFile.getInputStream( ze );
249 
250                     extractFileIfIncluded( getSourceFile(), outputDirectory, in,
251                                            ze.getName(), new Date( ze.getTime() ), ze.isDirectory(),
252                                            ze.getUnixMode() != 0 ? ze.getUnixMode() : null,
253                                            resolveSymlink( zipFile, ze ), getFileMappers() );
254 
255                     in.close();
256                     in = null;
257                 }
258             }
259 
260             zipFile.close();
261             zipFile = null;
262         }
263         catch ( final IOException ioe )
264         {
265             throw new ArchiverException( "Error while expanding " + getSourceFile().getAbsolutePath(), ioe );
266         }
267         finally
268         {
269             IOUtils.closeQuietly( in );
270             IOUtils.closeQuietly( zipFile );
271         }
272     }
273 
274 }