1 package org.codehaus.plexus.util;
2
3 /*
4 * The Apache Software License, Version 1.1
5 *
6 * Copyright (c) 2000-2002 The Apache Software Foundation. All rights
7 * reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 *
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in
18 * the documentation and/or other materials provided with the
19 * distribution.
20 *
21 * 3. The end-user documentation included with the redistribution, if
22 * any, must include the following acknowledgement:
23 * "This product includes software developed by the
24 * Apache Software Foundation (http://www.codehaus.org/)."
25 * Alternately, this acknowledgement may appear in the software itself,
26 * if and wherever such third-party acknowledgements normally appear.
27 *
28 * 4. The names "The Jakarta Project", "Ant", and "Apache Software
29 * Foundation" must not be used to endorse or promote products derived
30 * from this software without prior written permission. For written
31 * permission, please contact codehaus@codehaus.org.
32 *
33 * 5. Products derived from this software may not be called "Apache"
34 * nor may "Apache" appear in their names without prior written
35 * permission of the Apache Group.
36 *
37 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
38 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
39 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
41 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
43 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
44 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
45 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
46 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
47 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48 * SUCH DAMAGE.
49 * ====================================================================
50 *
51 * This software consists of voluntary contributions made by many
52 * individuals on behalf of the Apache Software Foundation. For more
53 * information on the Apache Software Foundation, please see
54 * <http://www.codehaus.org/>.
55 */
56
57 import java.io.File;
58 import java.io.FileNotFoundException;
59 import java.io.IOException;
60 import java.io.InputStream;
61 import java.io.OutputStream;
62 import java.nio.file.Files;
63 import java.util.Date;
64 import java.util.zip.ZipEntry;
65 import java.util.zip.ZipInputStream;
66
67 /**
68 * Unzip a file.
69 *
70 * @author costin@dnt.ro
71 * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a>
72 * @author <a href="mailto:umagesh@codehaus.org">Magesh Umasankar</a>
73 * @since Ant 1.1 @ant.task category="packaging" name="unzip" name="unjar" name="unwar"
74 *
75 */
76 public class Expand
77 {
78
79 private File dest;// req
80
81 private File source;// req
82
83 private boolean overwrite = true;
84
85 /**
86 * Do the work.
87 *
88 * @exception Exception Thrown in unrecoverable error.
89 */
90 public void execute()
91 throws Exception
92 {
93 expandFile( source, dest );
94 }
95
96 protected void expandFile( final File srcF, final File dir )
97 throws Exception
98 {
99 // code from WarExpand
100 try ( ZipInputStream zis = new ZipInputStream( Files.newInputStream( srcF.toPath() ) ) )
101 {
102 for ( ZipEntry ze = zis.getNextEntry(); ze != null; ze = zis.getNextEntry() )
103 {
104 extractFile( srcF, dir, zis, ze.getName(), new Date( ze.getTime() ), ze.isDirectory() );
105 }
106 }
107 catch ( IOException ioe )
108 {
109 throw new Exception( "Error while expanding " + srcF.getPath(), ioe );
110 }
111 }
112
113 protected void extractFile( File srcF, File dir, InputStream compressedInputStream, String entryName,
114 Date entryDate, boolean isDirectory )
115 throws Exception
116 {
117 File f = FileUtils.resolveFile( dir, entryName );
118
119 if ( !f.getAbsolutePath().startsWith( dir.getAbsolutePath() ) )
120 {
121 throw new IOException( "Entry '" + entryName + "' outside the target directory." );
122 }
123
124 try
125 {
126 if ( !overwrite && f.exists() && f.lastModified() >= entryDate.getTime() )
127 {
128 return;
129 }
130
131 // create intermediary directories - sometimes zip don't add them
132 File dirF = f.getParentFile();
133 dirF.mkdirs();
134
135 if ( isDirectory )
136 {
137 f.mkdirs();
138 }
139 else
140 {
141 byte[] buffer = new byte[65536];
142
143 try ( OutputStream fos = Files.newOutputStream( f.toPath() ) )
144 {
145 for ( int length = compressedInputStream.read( buffer );
146 length >= 0;
147 fos.write( buffer, 0, length ), length = compressedInputStream.read( buffer ) )
148 ;
149 }
150 }
151
152 f.setLastModified( entryDate.getTime() );
153 }
154 catch ( FileNotFoundException ex )
155 {
156 throw new Exception( "Can't extract file " + srcF.getPath(), ex );
157 }
158
159 }
160
161 /**
162 * Set the destination directory. File will be unzipped into the destination directory.
163 *
164 * @param d Path to the directory.
165 */
166 public void setDest( File d )
167 {
168 this.dest = d;
169 }
170
171 /**
172 * Set the path to zip-file.
173 *
174 * @param s Path to zip-file.
175 */
176 public void setSrc( File s )
177 {
178 this.source = s;
179 }
180
181 /**
182 * @param b Should we overwrite files in dest, even if they are newer than the corresponding entries in the archive?
183 */
184 public void setOverwrite( boolean b )
185 {
186 overwrite = b;
187 }
188
189 }