package com.google.gwt.dist.util;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.Adler32;
import java.util.zip.CheckedOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
/**
* Used to archive and compress folders using standard zip algorithm.
*/
public class ZipCompressor {
private Pattern excludeDirPattern;
static final int BUFFER = 2048;
static final Logger logger = Logger
.getLogger(ZipCompressor.class.getName());
public ByteArrayOutputStream archiveAndCompressDir(File directory) {
return archiveAndCompressDir(directory, false, null);
}
public ByteArrayOutputStream archiveAndCompressDir(File directory,
boolean preserveParentFolderName) {
return archiveAndCompressDir(directory, preserveParentFolderName, null);
}
/**
* Method compresses files in the directory.
*
* @param directory
* Directory to compress.
* @param preserveParentFolderName
* true if folder which is being compressed should be parent in
* the archive also.
* @return Compressed output stream as byte array.
*/
public ByteArrayOutputStream archiveAndCompressDir(File directory,
boolean preserveParentFolderName, Pattern fileFilter) {
ByteArrayOutputStream destination = new ByteArrayOutputStream();
CheckedOutputStream checksum = new CheckedOutputStream(destination,
new Adler32());
ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(
checksum));
out.setMethod(ZipOutputStream.DEFLATED);
try {
if (preserveParentFolderName) {
addFilesToPackage(directory, directory.getName()
+ Util.getFolderSeparatorInZipArchive(), out, fileFilter);
} else {
addFilesToPackage(directory, "", out, fileFilter);
}
out.close();
} catch (IOException e) {
logger.log(Level.SEVERE,
"There was a problem while adding files into Zip stream.");
}
return destination;
}
/**
* Archives and Compresses the Directory, but includes only files that match
* the regular expression pattern.
*
* @param directory
* @param fileFilter
* @return
* @throws IOException
*/
public ByteArrayOutputStream archiveAndCompressDir(File directory,
Pattern fileFilter) throws IOException {
ByteArrayOutputStream destination = new ByteArrayOutputStream();
CheckedOutputStream checksum = new CheckedOutputStream(destination,
new Adler32());
ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(
checksum));
out.setMethod(ZipOutputStream.DEFLATED);
addFilesToPackage(directory, "", out, fileFilter);
out.close();
return destination;
}
/**
* Add files found in a directory to output stream, preserving path
*
* @param dir
* Directory to add to output stream.
* @param pathPrefix
* Prefix to use for path (preserves folder structure).
* @param includeFilePattern
* Regular expression which acts as a filter. All the files that
* do not match that regular expression are not added to the
* stream.
* @param out
* Output stream to which data is written.
* @throws IOException
*/
private void addFilesToPackage(File dir, String pathPrefix,
ZipOutputStream out, Pattern includeFilePattern) throws IOException {
File[] list = dir.listFiles();
List<File> filteredList = new ArrayList<File>();
if (getExcludePattern() != null) {
for (File f : list) {
Matcher m = excludeDirPattern.matcher(f.getName());
if (!m.matches()) {
filteredList.add(f);
}
}
} else {
for (File f : list) {
filteredList.add(f);
}
}
for (File f : filteredList) {
if (f.getName().startsWith(".")) {
continue;
}
if (f.isDirectory()) {
addFilesToPackage(f, pathPrefix + f.getName()
+ Util.getFolderSeparatorInZipArchive(), out,
includeFilePattern);
} else {
if (includeFilePattern != null
&& !includeFilePattern.matcher(f.getName()).matches()) {
continue;
}
ZipEntry ze = new ZipEntry(pathPrefix + f.getName());
out.putNextEntry(ze);
InputStream in = new FileInputStream(f);
byte[] buff = new byte[2048];
int bytesRead = 0;
while ((bytesRead = in.read(buff)) > -1) {
out.write(buff, 0, bytesRead);
}
out.closeEntry();
in.close();
}
}
}
public Pattern getExcludePattern() {
return this.excludeDirPattern;
}
public ZipInputStream mergeZippedStreams(ZipInputStream... z) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
CheckedOutputStream checksum = new CheckedOutputStream(baos,
new Adler32());
ZipOutputStream mergedStream = new ZipOutputStream(checksum);
mergedStream.setMethod(ZipOutputStream.DEFLATED);
try {
for (ZipInputStream zis : z) {
ZipEntry zipEntry = null;
while ((zipEntry = zis.getNextEntry()) != null) {
mergedStream.putNextEntry(zipEntry);
byte[] buff = new byte[2048];
int bytesRead = 0;
while ((bytesRead = zis.read(buff)) > -1) {
mergedStream.write(buff, 0, bytesRead);
}
mergedStream.flush();
mergedStream.closeEntry();
zis.closeEntry();
}
}
mergedStream.close();
} catch (IOException e) {
e.printStackTrace();
}
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ZipInputStream zisNew = new ZipInputStream(bais);
return zisNew;
}
public void setExcludePattern(Pattern excludePattern) {
this.excludeDirPattern = excludePattern;
}
}