blob: 28c01edc3c7e23035ba57e89f1091dd01c049ecc [file] [log] [blame]
package org.apache.maven.shared.utils;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Date;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import org.apache.maven.shared.utils.io.FileUtils;
import org.apache.maven.shared.utils.io.IOUtil;
/**
* Expand will unpack the given zip archive.
*
* @author <a href="mailto:struberg@yahoo.de">Mark Struberg</a>
*/
class Expand
{
/**
* Source file which should get expanded
*/
private File source;
/**
* destination directory
*/
private File dest;
/**
* if the unpackaging should get performed if the destination already exists.
*/
private boolean overwrite = false;
private static final int BUFFER_SIZE = 2 ^ 16;
/**
* The zip archive which should get expanded.
*
* @param sourceArchive
*/
public void setSrc( File sourceArchive )
{
this.source = sourceArchive;
}
/**
* Set the destination directory into which the archive should get expanded.
* The directory will get created if it doesn't yet exist
* while executing the expand.
*
* @param destinationDirectory
*/
public void setDest( File destinationDirectory )
{
this.dest = destinationDirectory;
}
/**
* If the destination directory should get overwritten if the content
* already exists. If <code>false</code> we will only overwrite if the local
* file or directory is older than the one in the archive.
*
* @param overwrite
*/
public void setOverwrite( boolean overwrite )
{
this.overwrite = overwrite;
}
/**
* Actually perform the unpacking of the source archive
* into the destination directory.
*
* @throws Exception
*/
public void execute()
throws Exception
{
expandFile( source, dest );
}
/**
* <p>It is intended to be overwritten when implementing an own unarchiver</p>
* <p/>
* <p><b>Note:</b> we kept this protected method for the sake of backward compatibility!</p>
*
* @param srcFile The source file.
* @param destination The destination.
* @throws Exception In case of failure.
*/
void expandFile( File srcFile, File destination )
throws Exception
{
if ( source == null )
{
throw new NullPointerException( "Source Archive must not be null!" );
}
File destDir = destination;
if ( destDir == null )
{
destDir = new File( System.getProperty( "user.dir" ) );
}
ZipInputStream in = null;
try
{
in = new ZipInputStream( new FileInputStream( srcFile ) );
for ( ZipEntry zipEntry = in.getNextEntry(); zipEntry != null; zipEntry = in.getNextEntry() )
{
String zipEntryName = zipEntry.getName();
Date zipEntryDate = new Date( zipEntry.getTime() );
extractFile( source, destDir, in, zipEntryName, zipEntryDate, zipEntry.isDirectory() );
}
in.close();
in = null;
}
finally
{
IOUtil.close( in );
}
}
/**
* Extract a single ZipEntry.
* <p/>
* <p><b>Note:</b> we kept this protected method for the sake of backward compatibility!</p>
*
* @param archive the archive to unpack
* @param destDir the destination dirctory
* @param compressedInputStream
* @param entryName
* @param entryDate
* @param isDirectory
* @throws Exception
*/
void extractFile( File archive, File destDir, InputStream compressedInputStream, String entryName,
Date entryDate, boolean isDirectory )
throws Exception
{
File targetFile = new File( destDir, entryName );
if ( !targetFile.getAbsolutePath().startsWith( destDir.getAbsolutePath() ) )
{
throw new IOException( "Entry '" + entryName + "' outside the target directory." );
}
// if overwrite is specified and the file type
// of the existing file does not match, then delete it
if ( overwrite && targetFile.exists() && targetFile.isDirectory() != isDirectory )
{
deleteFileOrDir( targetFile );
}
if ( !targetFile.exists() || overwrite || targetFile.lastModified() <= entryDate.getTime() )
{
if ( isDirectory )
{
targetFile.mkdirs();
}
else
{
byte[] buffer = new byte[BUFFER_SIZE];
OutputStream out = null;
try
{
out = new FileOutputStream( targetFile );
int len;
while ( ( len = compressedInputStream.read( buffer ) ) >= 0 )
{
out.write( buffer, 0, len );
}
out.close();
out = null;
}
finally
{
IOUtil.close( out );
}
targetFile.setLastModified( entryDate.getTime() );
}
}
}
/**
* small helper method who deletes the given directory or file.
*
* @param targetFile
* @throws IOException
*/
private void deleteFileOrDir( File targetFile )
throws IOException
{
if ( targetFile.isDirectory() )
{
FileUtils.deleteDirectory( targetFile );
}
else
{
FileUtils.delete( targetFile );
}
}
}