/**
* ZipSnap 2.1
* Copyright 2007 Zach Scrivena
* 2007-08-26
* zachscrivena@gmail.com
* http://zipsnap.sourceforge.net/
*
* ZipSnap is a simple command-line incremental backup tool for directories.
*
* TERMS AND CONDITIONS:
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package zipsnap;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;
/**
* Simple class for performing common compression input/output operations.
*/
public class CompressionIO
{
/**
* Add a given list of files/directories to a specified ZIP volume.
*
* @param zipFile
* ZIP volume to be created
* @param files
* The files/directories to be added to the ZIP volume
* @param addedFiles
* The files/directories that were successfully added to the ZIP volume
* @return
* Number of files/directories successfully added to the ZIP volume
*/
public static int zipFiles(
final File zipFile,
final List<FileUnit> files,
final List<FileUnit> addedFiles)
{
final String zipFileName = zipFile.getName();
if (ZipSnap.simulateOnly)
{
return simulateProcessFiles(
"\n\nSimulating addition of " + files.size() + " files/directories to new ZIP volume \"" + zipFileName + "\":",
"",
"No. of files/directories added:",
true,
files,
addedFiles);
}
System.out.print("\n\nAdding " + files.size() + " files/directories to new ZIP volume \"" + zipFileName + "\":");
final File parentDir = zipFile.getParentFile();
/* create parent directories if necessary */
if (!parentDir.exists())
parentDir.mkdirs();
/* check that the parent directory of the ZIP volume exists */
if (!parentDir.isDirectory())
ErrorWarningHandler.reportErrorAndExit("Unable to create ZIP volume \"" + zipFileName + "\":\nThe parent directory \"" +
parentDir.getPath() + "\" does not exist, and cannot be created.");
/* check if the ZIP volume already exists */
if (zipFile.exists())
ErrorWarningHandler.reportErrorAndExit("Unable to create ZIP volume \"" + zipFileName + "\":\nA " +
(zipFile.isDirectory() ? "directory" : "file") + " of the same name already exists.");
/* return value */
int numAddedFiles = 0;
/* sum of uncompressed file/directory sizes */
long totalUncompressedSize = 0;
if (files.isEmpty())
{
/* create an empty file */
try
{
final FileOutputStream fos = new FileOutputStream(zipFile);
fos.flush();
fos.close();
}
catch (Exception e)
{
ErrorWarningHandler.reportErrorAndExit("Unable to create ZIP volume \"" + zipFileName + "\":\n" +
ErrorWarningHandler.getExceptionMessage(e));
}
}
else
{
/* at least one file/directory to be added */
ZipOutputStream zos = null;
try
{
zos = new ZipOutputStream(new FileOutputStream(zipFile));
}
catch (Exception e)
{
ErrorWarningHandler.reportErrorAndExit("Unable to create ZIP volume \"" + zipFileName + "\":\n" +
ErrorWarningHandler.getExceptionMessage(e));
}
/* set compression level (0-9) */
zos.setLevel(ZipSnap.compressionLevel);
final byte byteBuffer[] = new byte[ZipSnap.bufferSize];
int i = 0;
AddNextFile:
for (FileUnit u : files)
{
i++;
/* populate ZipEntry properties */
final ZipEntry ze = new ZipEntry(u.name);
ze.setTime(u.time);
/* decide on compression method */
final boolean useDeflate =
(u.size < ZipSnap.minSizeForCompression) ?
false : true;
if (useDeflate)
{
/* DEFLATE the file */
/* (size,CRC) fields of ZipEntry are automatically set */
System.out.print("\n [" + i + "] \"" + u.nativeName + "\"");
/* set properties of ZipEntry */
ze.setMethod(ZipEntry.DEFLATED);
}
else
{
/* STORE the file */
/* (size,CRC) fields of ZipEntry must be explicitly set */
System.out.print("\n [" + i + "] \"" + u.nativeName + "\"");
/* set properties of ZipEntry */
ze.setCrc(u.getCrc());
ze.setSize(u.size);
ze.setMethod(ZipEntry.STORED);
}
System.out.flush();
try
{
/* commit Zip Entry to the ZIP volume */
zos.putNextEntry(ze);
/* read the file and compress the data if it is a file */
if (!u.isDirectory)
{
final FileInputStream fis = new FileInputStream(u.file);
while (true)
{
final int byteCount = fis.read(byteBuffer, 0, ZipSnap.bufferSize);
if (byteCount == -1)
break; /* reached EOF */
zos.write(byteBuffer, 0, byteCount);
}
fis.close();
}
/* close the zip stream and prepare for next entry */
zos.closeEntry();
}
catch (Exception e)
{
if (u.isDirectory)
{
ErrorWarningHandler.reportWarning("Unable to add directory \"" + u.nativeName +
"\" to ZIP volume \"" + zipFileName + "\":\n" +
ErrorWarningHandler.getExceptionMessage(e) + "\nThis directory will be ignored.");
}
else
{
ErrorWarningHandler.reportWarning("Unable to add file \"" + u.nativeName +
"\" to ZIP volume \"" + zipFileName + "\":\n" +
ErrorWarningHandler.getExceptionMessage(e) + "\nThis file will be ignored.");
}
continue AddNextFile;
}
if (useDeflate)
{
u.setCrc(ze.getCrc());
System.out.print(" (" + (int) (100.0 * (ze.getSize() - ze.getCompressedSize()) /
ze.getSize()) + "%)");
}
/* file/directory successfully added to ZIP volume */
addedFiles.add(u);
totalUncompressedSize += u.size;
numAddedFiles++;
}
/* close the ZIP stream */
try
{
zos.flush();
zos.close();
}
catch (Exception e)
{
ErrorWarningHandler.reportWarning("Unable to close ZIP volume \"" + zipFileName +
"\"\n(ZIP volume may not be written successfully):\n" +
ErrorWarningHandler.getExceptionMessage(e));
}
}
/* print summary */
System.out.print(
"\n -------------------------------" +
"\n No. of files/directories added: " +
numAddedFiles + " out of " + files.size() +
"\n Uncompressed size : " +
StringManipulator.formattedLong(totalUncompressedSize) + " bytes" +
"\n Compressed size (ratio) : " +
StringManipulator.formattedLong(zipFile.length()) + " bytes (" +
((totalUncompressedSize > 0) ?
(int) (100.0 * (totalUncompressedSize - zipFile.length()) /
totalUncompressedSize) :
"-") +
"%)");
System.out.flush();
/* set timestamp of ZIP volume */
final FileIO.FileIOResult result = FileIO.setFileTime(zipFile, ZipSnap.currentTime.getTime());
if (!result.success)
ErrorWarningHandler.reportWarning("Unable to set last-modified time of ZIP volume \"" + zipFileName + "\".");
return numAddedFiles;
}
/**
* Add a given list of files/directories to a specified JAR volume.
*
* @param jarFile
* JAR volume to be created
* @param files
* The files/directories to be added to the JAR volume
* @param addedFiles
* The files/directories that were successfully added to the JAR volume
* @return
* Number of files/directories successfully added to the JAR volume
*/
public static int jarFiles(
final File jarFile,
final List<FileUnit> files,
final List<FileUnit> addedFiles)
{
final String jarFileName = jarFile.getName();
if (ZipSnap.simulateOnly)
{
return simulateProcessFiles(
"\n\nSimulating addition of " + files.size() + " files/directories to new JAR volume \"" + jarFileName + "\":",
"",
"No. of files/directories added:",
true,
files,
addedFiles);
}
System.out.print("\n\nAdding " + files.size() + " files/directories to new JAR volume \"" + jarFileName + "\":");
final File parentDir = jarFile.getParentFile();
/* create parent directories if necessary */
if (!parentDir.exists())
parentDir.mkdirs();
/* check that the parent directory of the JAR volume exists */
if (!parentDir.isDirectory())
ErrorWarningHandler.reportErrorAndExit("Unable to create JAR volume \"" + jarFileName + "\":\nThe parent directory \"" +
parentDir.getPath() + "\" does not exist, and cannot be created.");
/* check if the JAR volume already exists */
if (jarFile.exists())
ErrorWarningHandler.reportErrorAndExit("Unable to create JAR volume \"" + jarFileName + "\":\nA " +
(jarFile.isDirectory() ? "directory" : "file") + " of the same name already exists.");
/* return value */
int numAddedFiles = 0;
/* sum of uncompressed file/directory sizes */
long totalUncompressedSize = 0;
if (files.isEmpty())
{
/* create an empty file and return */
try
{
final FileOutputStream fos = new FileOutputStream(jarFile);
fos.flush();
fos.close();
}
catch (Exception e)
{
ErrorWarningHandler.reportErrorAndExit("Unable to create JAR volume \"" + jarFileName + "\":\n" +
ErrorWarningHandler.getExceptionMessage(e));
}
}
else
{
/* at least one file/directory to be added */
JarOutputStream jos = null;
try
{
jos = new JarOutputStream(new FileOutputStream(jarFile));
}
catch (Exception e)
{
ErrorWarningHandler.reportErrorAndExit("Unable to create JAR volume \"" + jarFileName + "\":\n" +
ErrorWarningHandler.getExceptionMessage(e));
}
/* set compression level (0-9) */
jos.setLevel(ZipSnap.compressionLevel);
final byte byteBuffer[] = new byte[ZipSnap.bufferSize];
int i = 0;
AddNextFile:
for (FileUnit u : files)
{
i++;
/* populate JarEntry properties */
final JarEntry je = new JarEntry(u.name);
je.setTime(u.time);
/* decide on compression method */
final boolean useDeflate =
(u.size < ZipSnap.minSizeForCompression) ?
false : true;
if (useDeflate)
{
/* DEFLATE the file */
/* (size,CRC) fields of JarEntry are automatically set */
System.out.print("\n [" + i + "] \"" + u.nativeName + "\"");
/* set properties of JarEntry */
je.setMethod(JarEntry.DEFLATED);
}
else
{
/* STORE the file */
/* (size,CRC) fields of JarEntry must be explicitly set */
System.out.print("\n [" + i + "] \"" + u.nativeName + "\"");
/* set properties of JarEntry */
je.setCrc(u.getCrc());
je.setSize(u.size);
je.setMethod(JarEntry.STORED);
}
System.out.flush();
try
{
/* commit Jar Entry to the JAR volume */
jos.putNextEntry(je);
/* read the file and compress the data if it is a file */
if (!u.isDirectory)
{
final FileInputStream fis = new FileInputStream(u.file);
while (true)
{
final int byteCount = fis.read(byteBuffer, 0, ZipSnap.bufferSize);
if (byteCount == -1)
break; /* reached EOF */
jos.write(byteBuffer, 0, byteCount);
}
fis.close();
}
/* close the JAR stream and prepare for next entry */
jos.closeEntry();
}
catch (Exception e)
{
if (u.isDirectory)
{
ErrorWarningHandler.reportWarning("Unable to add directory \"" + u.nativeName +
"\" to JAR volume \"" + jarFileName + "\":\n" +
ErrorWarningHandler.getExceptionMessage(e) + "\nThis directory will be ignored.");
}
else
{
ErrorWarningHandler.reportWarning("Unable to add file \"" + u.nativeName +
"\" to JAR volume \"" + jarFileName + "\":\n" +
ErrorWarningHandler.getExceptionMessage(e) + "\nThis file will be ignored.");
}
continue AddNextFile;
}
if (useDeflate)
{
u.setCrc(je.getCrc());
System.out.print(" (" + (int) (100.0 * (je.getSize() - je.getCompressedSize()) /
je.getSize()) + "%)");
}
/* file/directory successfully added to JAR volume */
addedFiles.add(u);
totalUncompressedSize += u.size;
numAddedFiles++;
}
/* close the JAR stream */
try
{
jos.flush();
jos.close();
}
catch (Exception e)
{
ErrorWarningHandler.reportWarning("Unable to close JAR volume \"" + jarFileName +
"\"\n(JAR volume may not be written successfully):\n" +
ErrorWarningHandler.getExceptionMessage(e));
}
}
/* print summary */
System.out.print(
"\n -------------------------------" +
"\n No. of files/directories added: " +
numAddedFiles + " out of " + files.size() +
"\n Uncompressed size : " +
StringManipulator.formattedLong(totalUncompressedSize) + " bytes" +
"\n Compressed size (ratio) : " +
StringManipulator.formattedLong(jarFile.length()) + " bytes (" +
((totalUncompressedSize > 0) ?
(int) (100.0 * (totalUncompressedSize - jarFile.length()) /
totalUncompressedSize) :
"-") +
"%)");
System.out.flush();
/* set timestamp of JAR volume */
final FileIO.FileIOResult result = FileIO.setFileTime(jarFile, ZipSnap.currentTime.getTime());
if (!result.success)
ErrorWarningHandler.reportWarning("Unable to set last-modified time of JAR volume \"" + jarFileName + "\".");
return numAddedFiles;
}
/**
* Extract a given list of files/directories from a specified ZIP volume.
*
* @param zipFile
* ZIP volume from which files/directories are to be extracted
* @param files
* The files/directories to be extracted from the ZIP volume
* @param extractedFiles
* The files/directories that were successfully extracted from the ZIP volume
* @return
* Number of files/directories successfully extracted from the ZIP volume
*/
public static int unZipFiles(
final File zipFile,
final List<FileUnit> files,
final List<FileUnit> extractedFiles)
{
final String zipFileName = (ZipSnap.searchPaths.size() == 1) ? zipFile.getName() : zipFile.getPath();
if (ZipSnap.simulateOnly)
{
return simulateProcessFiles(
"\n\nSimulating extraction of " + files.size() + " files/directories from ZIP volume \"" + zipFileName + "\":",
"",
"No. of files/directories extracted:",
true,
files,
extractedFiles);
}
System.out.print("\n\nExtracting " + files.size() + " files/directories from ZIP volume \"" + zipFileName + "\":");
/* return value */
int numExtractedFiles = 0;
if (!files.isEmpty())
{
/* at least one file to extract */
/* check if the ZIP volume exists */
if (!zipFile.exists())
ErrorWarningHandler.reportWarning("ZIP volume \"" + zipFileName + "\" does not exist;\nthe " +
files.size() + " files/directories from this volume will not be extracted.");
ZipFile zf = null;
try
{
zf = new ZipFile(zipFile);
}
catch (Exception e)
{
ErrorWarningHandler.reportWarning("Unable to open ZIP volume \"" + zipFileName + "\":\n" +
ErrorWarningHandler.getExceptionMessage(e) + "\nThe " + files.size() +
" files/directories from this volume will not be extracted.");
}
final byte byteBuffer[] = new byte[ZipSnap.bufferSize];
int i = 0;
ExtractNextFile:
for (FileUnit u : files)
{
++i;
boolean extractFile = false;
if (u.file.exists())
{
/* a file/directory of the same name already exists */
if (u.isDirectory == u.file.isDirectory())
{
/* overwrite existing file/directory? */
if (ZipSnap.defaultActionOnOverwrite == 'Y')
{
System.out.print("\n [" + i + "] Overwriting \"" + u.nativeName + "\"");
extractFile = true;
}
else if (ZipSnap.defaultActionOnOverwrite == 'N')
{
System.out.print("\n [" + i + "] Skipping existing \"" + u.nativeName + "\"");
}
else if (ZipSnap.defaultActionOnOverwrite == '\0')
{
System.out.print("\n [" + i + "] Overwrite \"" + u.nativeName + "\"?\n ");
final char choice = UserIO.userCharPrompt(
"(Y)es/(N)o/(A)lways/Neve(R): ",
"YNAR");
if (choice == 'Y')
{
extractFile = true;
}
else if (choice == 'A')
{
ZipSnap.defaultActionOnOverwrite = 'Y';
extractFile = true;
}
else if (choice == 'R')
{
ZipSnap.defaultActionOnOverwrite = 'N';
}
}
}
else
{
System.out.print("\n [" + i + "] \"" + u.nativeName + "\"");
ErrorWarningHandler.reportWarning("Unable to extract " + (u.isDirectory ? "directory" : "file") +
" \"" + u.nativeName + "\" from ZIP volume \"" + zipFileName + "\":\nA " +
(u.file.isDirectory() ? "directory" : "file") +
" of the same name already exists.");
}
}
else
{
/* file/directory does not exist yet */
System.out.print("\n [" + i + "] \"" + u.nativeName + "\"");
extractFile = true;
}
System.out.flush();
if (extractFile)
{
if (u.isDirectory)
{
/* extract a directory */
u.file.mkdirs();
if (!u.file.exists() || !u.file.isDirectory())
{
ErrorWarningHandler.reportWarning("Unable to extract directory \"" + u.nativeName +
"\" from ZIP volume \"" + zipFileName + "\".");
continue ExtractNextFile;
}
/* check pathname of extracted directory */
String pathname = null;
try
{
pathname = u.file.getCanonicalPath();
}
catch (Exception e)
{
pathname = null;
}
if ((pathname != null) &&
!pathname.equals(u.file.getPath()))
{
/* rename extracted directory */
File s = new File(pathname);
File t = u.file;
while ((s != null) && (t != null) &&
!s.equals(ZipSnap.currentDir) &&
!t.equals(ZipSnap.currentDir) &&
!s.getPath().equals(t.getPath()))
{
/* pathnames are different; proceed to rename */
s.renameTo(t);
/* check parent pathnames next */
s = s.getParentFile();
t = t.getParentFile();
}
}
/* set timestamp of extracted directory */
final FileIO.FileIOResult result = FileIO.setDirTime(u.file, u.time);
if (!result.success)
ErrorWarningHandler.reportWarning("Unable to set last-modified time of extracted directory \"" + u.nativeName + "\".");
}
else
{
/* extract a file */
final ZipEntry ze = zf.getEntry(u.name);
if (ze == null)
{
ErrorWarningHandler.reportWarning("Unable to extract file \"" +
u.nativeName + "\" from ZIP volume \"" + zipFileName +
"\":\nCannot find the corresponding entry in the ZIP volume.");
continue ExtractNextFile;
}
final File parentDir = u.file.getParentFile();
if ((parentDir != null) && !parentDir.exists())
parentDir.mkdirs();
if ((parentDir == null) || !parentDir.isDirectory())
{
ErrorWarningHandler.reportWarning("Unable to extract file \"" +
u.nativeName + "\" from ZIP volume \"" + zipFileName +
"\":\nThe parent directory of the file does not exist and cannot be created.");
continue ExtractNextFile;
}
/* write uncompressed data to file */
InputStream zis = null;
FileOutputStream fos = null;
try
{
zis = zf.getInputStream(ze);
fos = new FileOutputStream(u.file);
while (true)
{
final int byteCount = zis.read(byteBuffer, 0, ZipSnap.bufferSize);
if (byteCount == -1)
break; /* reached EOF */
fos.write(byteBuffer, 0, byteCount);
}
}
catch (Exception e)
{
ErrorWarningHandler.reportWarning("Unable to extract file \"" +
u.nativeName + "\" from ZIP volume \"" + zipFileName +
"\":\n" + ErrorWarningHandler.getExceptionMessage(e));
continue ExtractNextFile;
}
try
{
fos.flush();
fos.close();
}
catch (Exception e)
{
ErrorWarningHandler.reportWarning("Unable to close extracted file \"" +
u.nativeName + "\"\n(file may not be written successfully):\n" +
ErrorWarningHandler.getExceptionMessage(e));
}
try
{
zis.close();
}
catch (Exception e)
{
ErrorWarningHandler.reportWarning("Unable to close ZIP volume entry \"" + u.nativeName +
"\"\n(extracted file may not be written successfully):\n" +
ErrorWarningHandler.getExceptionMessage(e));
}
/* check pathname of extracted file */
String pathname = null;
try
{
pathname = u.file.getCanonicalPath();
}
catch (Exception e)
{
pathname = null;
}
if ((pathname != null) &&
!pathname.equals(u.file.getPath()))
{
/* rename extracted file */
File s = new File(pathname);
File t = u.file;
while ((s != null) && (t != null) &&
!s.equals(ZipSnap.currentDir) &&
!t.equals(ZipSnap.currentDir) &&
!s.getPath().equals(t.getPath()))
{
/* pathnames are different; proceed to rename */
s.renameTo(t);
/* check parent pathnames next */
s = s.getParentFile();
t = t.getParentFile();
}
}
/* set timestamp of extracted file */
final FileIO.FileIOResult result = FileIO.setFileTime(u.file, u.time);
if (!result.success)
ErrorWarningHandler.reportWarning("Unable to set last-modified time of extracted file \"" + u.nativeName + "\".");
}
/* file/directory successfully extracted from the ZIP volume */
extractedFiles.add(u);
numExtractedFiles++;
}
}
/* close the ZIP volume */
try
{
zf.close();
}
catch (Exception e)
{
ErrorWarningHandler.reportWarning("Unable to close ZIP volume \"" + zipFileName +
"\"\n(file may not be read successfully):\n" +
ErrorWarningHandler.getExceptionMessage(e));
}
}
/* print summary */
System.out.print(
"\n -----------------------------------" +
"\n No. of files/directories extracted: " +
numExtractedFiles + " out of " + files.size());
System.out.flush();
return numExtractedFiles;
}
/**
* Extract a given list of files/directories from a specified JAR volume.
*
* @param jarFile
* JAR volume from which files/directories are to be extracted
* @param files
* The files/directories to be extracted from the JAR volume
* @param extractedFiles
* The files/directories that were successfully extracted from the JAR volume
* @return
* Number of files/directories successfully extracted from the JAR volume
*/
public static int unJarFiles(
final File jarFile,
final List<FileUnit> files,
final List<FileUnit> extractedFiles)
{
final String jarFileName = (ZipSnap.searchPaths.size() == 1) ? jarFile.getName() : jarFile.getPath();
if (ZipSnap.simulateOnly)
{
return simulateProcessFiles(
"\n\nSimulating extraction of " + files.size() + " files/directories from JAR volume \"" + jarFileName + "\":",
"",
"No. of files/directories extracted:",
true,
files,
extractedFiles);
}
System.out.print("\n\nExtracting " + files.size() + " files/directories from JAR volume \"" + jarFileName + "\":");
/* return value */
int numExtractedFiles = 0;
if (!files.isEmpty())
{
/* at least one file to extract */
/* check if the JAR volume exists */
if (!jarFile.exists())
ErrorWarningHandler.reportWarning("JAR volume \"" + jarFileName + "\" does not exist;\nthe " +
files.size() + " files/directories from this volume will not be extracted.");
JarFile jf = null;
try
{
jf = new JarFile(jarFile);
}
catch (Exception e)
{
ErrorWarningHandler.reportWarning("Unable to open JAR volume \"" + jarFileName + "\":\n" +
ErrorWarningHandler.getExceptionMessage(e) + "\nThe " + files.size() +
" files/directories from this volume will not be extracted.");
}
final byte byteBuffer[] = new byte[ZipSnap.bufferSize];
int i = 0;
ExtractNextFile:
for (FileUnit u : files)
{
++i;
boolean extractFile = false;
if (u.file.exists())
{
/* a file/directory of the same name already exists */
if (u.isDirectory == u.file.isDirectory())
{
/* overwrite existing file/directory? */
if (ZipSnap.defaultActionOnOverwrite == 'Y')
{
System.out.print("\n [" + i + "] Overwriting \"" + u.nativeName + "\"");
extractFile = true;
}
else if (ZipSnap.defaultActionOnOverwrite == 'N')
{
System.out.print("\n [" + i + "] Skipping existing \"" + u.nativeName + "\"");
}
else if (ZipSnap.defaultActionOnOverwrite == '\0')
{
System.out.print("\n [" + i + "] Overwrite \"" + u.nativeName + "\"?\n ");
final char choice = UserIO.userCharPrompt(
"(Y)es/(N)o/(A)lways/Neve(R): ",
"YNAR");
if (choice == 'Y')
{
extractFile = true;
}
else if (choice == 'A')
{
ZipSnap.defaultActionOnOverwrite = 'Y';
extractFile = true;
}
else if (choice == 'R')
{
ZipSnap.defaultActionOnOverwrite = 'N';
}
}
}
else
{
System.out.print("\n [" + i + "] \"" +
u.nativeName + "\"");
ErrorWarningHandler.reportWarning("Unable to extract " + (u.isDirectory ? "directory" : "file") +
" \"" + u.nativeName + "\" from JAR volume \"" + jarFileName + "\":\nA " +
(u.file.isDirectory() ? "directory" : "file") +
" of the same name already exists.");
}
}
else
{
/* file/directory does not exist yet */
System.out.print("\n [" + i + "] \"" + u.nativeName + "\"");
extractFile = true;
}
System.out.flush();
if (extractFile)
{
if (u.isDirectory)
{
/* extract a directory */
u.file.mkdirs();
if (!u.file.exists() || !u.file.isDirectory())
{
ErrorWarningHandler.reportWarning("Unable to extract directory \"" + u.nativeName +
"\" from JAR volume \"" + jarFileName + "\".");
continue ExtractNextFile;
}
/* check pathname of extracted directory */
String pathname = null;
try
{
pathname = u.file.getCanonicalPath();
}
catch (Exception e)
{
pathname = null;
}
if ((pathname != null) &&
!pathname.equals(u.file.getPath()))
{
/* rename extracted directory */
File s = new File(pathname);
File t = u.file;
while ((s != null) && (t != null) &&
!s.equals(ZipSnap.currentDir) &&
!t.equals(ZipSnap.currentDir) &&
!s.getPath().equals(t.getPath()))
{
/* pathnames are different; proceed to rename */
s.renameTo(t);
/* check parent pathnames next */
s = s.getParentFile();
t = t.getParentFile();
}
}
/* set timestamp of extracted directory */
final FileIO.FileIOResult result = FileIO.setDirTime(u.file, u.time);
if (!result.success)
ErrorWarningHandler.reportWarning("Unable to set last-modified time of extracted directory \"" + u.nativeName + "\".");
}
else
{
/* extract a file */
final ZipEntry ze = jf.getEntry(u.name);
if (ze == null)
{
ErrorWarningHandler.reportWarning("Unable to extract file \"" +
u.nativeName + "\" from JAR volume \"" + jarFileName +
"\":\nCannot find the corresponding entry in the JAR volume.");
continue ExtractNextFile;
}
final File parentDir = u.file.getParentFile();
if ((parentDir != null) && !parentDir.exists())
parentDir.mkdirs();
if ((parentDir == null) || !parentDir.isDirectory())
{
ErrorWarningHandler.reportWarning("Unable to extract file \"" +
u.nativeName + "\" from JAR volume \"" + jarFileName +
"\":\nThe parent directory of the file does not exist and cannot be created.");
continue ExtractNextFile;
}
/* write uncompressed data to file */
InputStream jis = null;
FileOutputStream fos = null;
try
{
jis = jf.getInputStream(ze);
fos = new FileOutputStream(u.file);
while (true)
{
final int byteCount = jis.read(byteBuffer, 0, ZipSnap.bufferSize);
if (byteCount == -1)
break; /* reached EOF */
fos.write(byteBuffer, 0, byteCount);
}
}
catch (Exception e)
{
ErrorWarningHandler.reportWarning("Unable to extract file \"" +
u.nativeName + "\" from JAR volume \"" + jarFileName +
"\":\n" + ErrorWarningHandler.getExceptionMessage(e));
continue ExtractNextFile;
}
try
{
fos.flush();
fos.close();
}
catch (Exception e)
{
ErrorWarningHandler.reportWarning("Unable to close extracted file \"" +
u.nativeName + "\"\n(file may not be written successfully):\n" +
ErrorWarningHandler.getExceptionMessage(e));
}
try
{
jis.close();
}
catch (Exception e)
{
ErrorWarningHandler.reportWarning("Unable to close JAR volume entry \"" + u.nativeName +
"\"\n(extracted file may not be written successfully):\n" +
ErrorWarningHandler.getExceptionMessage(e));
}
/* check pathname of extracted file */
String pathname = null;
try
{
pathname = u.file.getCanonicalPath();
}
catch (Exception e)
{
pathname = null;
}
if ((pathname != null) &&
!pathname.equals(u.file.getPath()))
{
/* rename extracted file */
File s = new File(pathname);
File t = u.file;
while ((s != null) && (t != null) &&
!s.equals(ZipSnap.currentDir) &&
!t.equals(ZipSnap.currentDir) &&
!s.getPath().equals(t.getPath()))
{
/* pathnames are different; proceed to rename */
s.renameTo(t);
/* check parent pathnames next */
s = s.getParentFile();
t = t.getParentFile();
}
}
/* set timestamp of extracted file */
final FileIO.FileIOResult result = FileIO.setFileTime(u.file, u.time);
if (!result.success)
ErrorWarningHandler.reportWarning("Unable to set last-modified time of extracted file \"" + u.nativeName + "\".");
}
/* file/directory successfully extracted from the JAR volume */
extractedFiles.add(u);
numExtractedFiles++;
}
}
/* close the JAR volume */
try
{
jf.close();
}
catch (Exception e)
{
ErrorWarningHandler.reportWarning("Unable to close JAR volume \"" + jarFileName +
"\"\n(file may not be read successfully):\n" +
ErrorWarningHandler.getExceptionMessage(e));
}
}
/* print summary */
System.out.print(
"\n -----------------------------------" +
"\n No. of files/directories extracted: " +
numExtractedFiles + " out of " + files.size());
System.out.flush();
return numExtractedFiles;
}
/**
* Simulate processing of specified files/directories.
*
* @param headerString
* String to be displayed before processing files/directories
* @param perFileString
* String to be displayed for each file/directory processed
* @param footerString
* String to be displayed after processing files/directories
* @param success
* If true, all files/directories will be successfully processed;
* otherwise, all files/directories will not be successfully processed
* @param files
* The files/directories to be processed
* @param processedFiles
* The files/directories successfully processed
* @return
* Number of files/directories successfully processed
*/
public static int simulateProcessFiles(
final String headerString,
final String perFileString,
final String footerString,
final boolean success,
final List<FileUnit> files,
final List<FileUnit> processedFiles)
{
System.out.print(headerString);
/* return value */
int numProcessedFiles = 0;
int i = 0;
for (FileUnit u : files)
{
i++;
System.out.print("\n [" + i + "] " + perFileString + "\"" + u.nativeName + "\"");
System.out.flush();
if (success)
{
processedFiles.add(u);
numProcessedFiles++;
}
}
/* print summary */
System.out.print(
"\n " + StringManipulator.repeat("-", footerString.length()) +
"\n " + footerString + " " +
numProcessedFiles + " out of " + files.size());
System.out.flush();
return numProcessedFiles;
}
}