package railo.commons.io;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
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.Enumeration;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
import org.apache.commons.compress.compressors.bzip2.BZip2CompressorOutputStream;
import railo.aprint;
import railo.commons.io.res.Resource;
import railo.commons.io.res.ResourceProvider;
import railo.commons.io.res.ResourcesImpl;
import railo.commons.io.res.filter.ExtensionResourceFilter;
import railo.commons.io.res.filter.OrResourceFilter;
import railo.commons.io.res.filter.ResourceFilter;
import railo.commons.lang.StringUtil;
import railo.runtime.op.Caster;
/**
* Util to manipulate zip files
*/
public final class CompressUtil {
/**
* Field <code>FORMAT_ZIP</code>
*/
public static final int FORMAT_ZIP=0;
/**
* Field <code>FORMAT_TAR</code>
*/
public static final int FORMAT_TAR=1;
/**
* Field <code>FORMAT_TGZ</code>
*/
public static final int FORMAT_TGZ=2;
/**
* Field <code>FORMAT_GZIP</code>
*/
public static final int FORMAT_GZIP=3;
/**
* Field <code>FORMAT_BZIP</code>
*/
public static final int FORMAT_BZIP=4;
/**
* Field <code>FORMAT_BZIP</code>
*/
public static final int FORMAT_BZIP2=4;
/**
* Field <code>FORMAT_TBZ</code>
*/
public static final int FORMAT_TBZ=5;
/**
* Field <code>FORMAT_TBZ2</code>
*/
public static final int FORMAT_TBZ2=5;
/**
* Constructor of the class
*/
private CompressUtil(){}
/**
* extract a zip file to a directory
* @param format
* @param source
* @param target
* @throws IOException
*/
public static void extract(int format,Resource source, Resource target) throws IOException {
if(format==FORMAT_ZIP) extractZip(source,target);
else if(format==FORMAT_TAR) extractTar(source,target);
else if(format==FORMAT_GZIP)extractGZip(source,target);
else if(format==FORMAT_TGZ) extractTGZ(source,target);
else throw new IOException("can't extract in given format");
}
public static void list(int format,Resource source) throws IOException {
if(format==FORMAT_ZIP) listZip(source);
//else if(format==FORMAT_TAR) listar(source);
//else if(format==FORMAT_GZIP)listGZip(source);
//else if(format==FORMAT_TGZ) listTGZ(source);
else throw new IOException("can't list in given format, atm only zip files are supported");
}
private static void extractTGZ(Resource source, Resource target) throws IOException {
//File tmpTarget = File.createTempFile("_temp","tmp");
Resource tmp = SystemUtil.getTempDirectory().getRealResource(System.currentTimeMillis()+".tmp");
try {
// read Gzip
extractGZip(source, tmp);
// read Tar
extractTar(tmp, target);
}
finally {
tmp.delete();
}
}
private static void extractGZip(Resource source, Resource target) throws IOException {
InputStream is=null;
OutputStream os=null;
try {
is = new GZIPInputStream(IOUtil.toBufferedInputStream(source.getInputStream()));
os = IOUtil.toBufferedOutputStream(target.getOutputStream());
IOUtil.copy(is,os,false,false);
}
finally {
IOUtil.closeEL(is, os);
}
}
/**
* extract a zip file to a directory
* @param format
* @param sources
* @param target
* @throws IOException
*/
public static void extract(int format,Resource[] sources, Resource target) throws IOException {
if(format==FORMAT_ZIP || format==FORMAT_TAR) {
for(int i=0;i<sources.length;i++) {
extract(format,sources[i],target);
}
}
else throw new IOException("can't extract in given format");
}
private static void extractTar(Resource tarFile, Resource targetDir) throws IOException {
if(!targetDir.exists() || !targetDir.isDirectory())
throw new IOException(targetDir+" is not a existing directory");
if(!tarFile.exists())
throw new IOException(tarFile+" is not a existing file");
if(tarFile.isDirectory()) {
Resource[] files = tarFile.listResources(new ExtensionResourceFilter("tar"));
if(files==null)
throw new IOException("directory "+tarFile+" is empty");
extract(FORMAT_TAR,files,targetDir);
return;
}
// read the zip file and build a query from its contents
TarArchiveInputStream tis=null;
try {
tis = new TarArchiveInputStream( IOUtil.toBufferedInputStream(tarFile.getInputStream()) ) ;
TarArchiveEntry entry;
int mode;
while ( ( entry = tis.getNextTarEntry()) != null ) {
//print.ln(entry);
Resource target=targetDir.getRealResource(entry.getName());
if(entry.isDirectory()) {
target.mkdirs();
}
else {
Resource parent=target.getParentResource();
if(!parent.exists())parent.mkdirs();
IOUtil.copy(tis,target,false);
}
target.setLastModified(entry.getModTime().getTime());
mode=entry.getMode();
if(mode>0)target.setMode(mode);
//tis.closeEntry() ;
}
}
finally {
IOUtil.closeEL(tis);
}
}
private static void extractZip(Resource zipFile, Resource targetDir) throws IOException {
if(!targetDir.exists() || !targetDir.isDirectory())
throw new IOException(targetDir+" is not a existing directory");
if(!zipFile.exists())
throw new IOException(zipFile+" is not a existing file");
if(zipFile.isDirectory()) {
Resource[] files = zipFile.listResources(
new OrResourceFilter(new ResourceFilter[]{
new ExtensionResourceFilter("zip"),
new ExtensionResourceFilter("jar"),
new ExtensionResourceFilter("war"),
new ExtensionResourceFilter("tar"),
new ExtensionResourceFilter("ear")
})
);
if(files==null)
throw new IOException("directory "+zipFile+" is empty");
extract(FORMAT_ZIP,files,targetDir);
return;
}
// read the zip file and build a query from its contents
unzip(zipFile,targetDir);
/*ZipInputStream zis=null;
try {
zis = new ZipInputStream( IOUtil.toBufferedInputStream(zipFile.getInputStream()) ) ;
ZipEntry entry;
while ( ( entry = zis.getNextEntry()) != null ) {
Resource target=targetDir.getRealResource(entry.getName());
if(entry.isDirectory()) {
target.mkdirs();
}
else {
Resource parent=target.getParentResource();
if(!parent.exists())parent.mkdirs();
IOUtil.copy(zis,target,false);
}
target.setLastModified(entry.getTime());
zis.closeEntry() ;
}
}
finally {
IOUtil.closeEL(zis);
}*/
}
private static void unzip(Resource zipFile,Resource targetDir) throws IOException {
/*if(zipFile instanceof File){
unzip((File)zipFile, targetDir);
return;
}*/
ZipInputStream zis=null;
try {
zis = new ZipInputStream( IOUtil.toBufferedInputStream(zipFile.getInputStream()) ) ;
ZipEntry entry;
while ( ( entry = zis.getNextEntry()) != null ) {
Resource target=targetDir.getRealResource(entry.getName());
if(entry.isDirectory()) {
target.mkdirs();
}
else {
Resource parent=target.getParentResource();
if(!parent.exists())parent.mkdirs();
IOUtil.copy(zis,target,false);
}
target.setLastModified(entry.getTime());
zis.closeEntry() ;
}
}
finally {
IOUtil.closeEL(zis);
}
}
private static void listZip(Resource zipFile) throws IOException {
if(!zipFile.exists())
throw new IOException(zipFile+" is not a existing file");
if(zipFile.isDirectory()) {
throw new IOException(zipFile+" is a directory");
}
ZipInputStream zis=null;
try {
zis = new ZipInputStream( IOUtil.toBufferedInputStream(zipFile.getInputStream()) ) ;
ZipEntry entry;
while ( ( entry = zis.getNextEntry()) != null ) {
if(!entry.isDirectory()){
ByteArrayOutputStream baos=new ByteArrayOutputStream();
IOUtil.copy(zis,baos,false,false);
byte[] barr = baos.toByteArray();
aprint.o(entry.getName()+":"+barr.length);
}
}
}
finally {
IOUtil.closeEL(zis);
}
}
private static void unzip2(File zipFile,Resource targetDir) throws IOException {
ZipFile zf=null;
try {
zf = new ZipFile(zipFile);
ZipEntry entry;
Enumeration en = zf.entries();
while(en.hasMoreElements()){
entry = (ZipEntry) en.nextElement();
Resource target=targetDir.getRealResource(entry.getName());
if(entry.isDirectory()) {
target.mkdirs();
}
else {
Resource parent=target.getParentResource();
if(!parent.exists())parent.mkdirs();
InputStream is = zf.getInputStream(entry);
IOUtil.copy(is,target,true);
}
target.setLastModified(entry.getTime());
}
}
finally {
IOUtil.closeEL(zf);
}
}
/**
* compress data to a zip file
* @param format format it that should by compressed usally is CompressUtil.FORMAT_XYZ
* @param source
* @param target
* @param includeBaseFolder
* @param mode
* @throws IOException
*/
public static void compress(int format, Resource source, Resource target, boolean includeBaseFolder, int mode) throws IOException {
if( format==FORMAT_GZIP) compressGZip(source,target);
else if(format==FORMAT_BZIP2) compressBZip2(source,target);
else {
Resource[] sources=(!includeBaseFolder && source.isDirectory())?source.listResources():new Resource[]{source};
compress(format, sources, target,mode);
}
}
/**
* compress data to a zip file
* @param format format it that should by compressed usally is CompressUtil.FORMAT_XYZ
* @param sources
* @param target
* @param mode
* @throws IOException
*/
public static void compress(int format, Resource[] sources, Resource target, int mode) throws IOException {
if( format==FORMAT_ZIP) compressZip(sources,target,null);
else if(format==FORMAT_TAR) compressTar(sources,target,mode);
else if(format==FORMAT_TGZ) compressTGZ(sources,target,mode);
else if(format==FORMAT_TBZ2) compressTBZ2(sources,target,mode);
else throw new IOException("can't compress in given format");
}
/**
* compress a source file/directory to a tar/gzip file
* @param sources
* @param target
* @param mode
* @throws IOException
*/
public static void compressTGZ(Resource[] sources, Resource target,int mode) throws IOException {
File tmpTarget = File.createTempFile("_temp","tmp");
try {
// write Tar
OutputStream tmpOs=new FileOutputStream(tmpTarget);
try {
compressTar(sources,tmpOs,mode);
}
finally {
IOUtil.closeEL(tmpOs);
}
// write Gzip
InputStream is = null;
OutputStream os = null;
try {
is = new FileInputStream(tmpTarget);
os = target.getOutputStream();
compressGZip(is, os);
}
finally {
IOUtil.closeEL(is,os);
}
}
finally {
tmpTarget.delete();
}
}
/**
* compress a source file/directory to a tar/bzip2 file
* @param sources
* @param target
* @param mode
* @throws IOException
*/
private static void compressTBZ2(Resource[] sources, Resource target, int mode) throws IOException {
//File tmpTarget = File.createTempFile("_temp","tmp");
ByteArrayOutputStream baos=new ByteArrayOutputStream();
compressTar(sources,baos,mode);
_compressBZip2(new ByteArrayInputStream(baos.toByteArray()), target.getOutputStream());
//tmpTarget.delete();
}
/**
* compress a source file to a gzip file
* @param source
* @param target
* @throws IOException
* @throws IOException
*/
private static void compressGZip(Resource source, Resource target) throws IOException {
if(source.isDirectory()) {
throw new IOException("you can only create a GZIP File from a single source file, use TGZ (TAR-GZIP) to first TAR multiple files");
}
InputStream is=null;
OutputStream os=null;
try {
is = source.getInputStream();
os = target.getOutputStream();
} catch(IOException ioe) {
IOUtil.closeEL(is, os);
throw ioe;
}
compressGZip(is,os);
}
public static void compressGZip(InputStream source, OutputStream target) throws IOException {
InputStream is = IOUtil.toBufferedInputStream(source);
if(!(target instanceof GZIPOutputStream)) target = new GZIPOutputStream(IOUtil.toBufferedOutputStream(target));
IOUtil.copy(is,target,true,true);
}
/**
* compress a source file to a bzip2 file
* @param source
* @param target
* @throws IOException
*/
private static void compressBZip2(Resource source, Resource target) throws IOException {
if(source.isDirectory()) {
throw new IOException("you can only create a BZIP File from a single source file, use TBZ (TAR-BZIP2) to first TAR multiple files");
}
InputStream is=null;
OutputStream os=null;
try {
is=source.getInputStream();
os=target.getOutputStream();
}
catch(IOException ioe) {
IOUtil.closeEL(is, os);
throw ioe;
}
_compressBZip2(is, os);
}
/**
* compress a source file to a bzip2 file
* @param source
* @param target
* @throws IOException
*/
private static void _compressBZip2(InputStream source, OutputStream target) throws IOException {
InputStream is = IOUtil.toBufferedInputStream(source);
OutputStream os = new BZip2CompressorOutputStream(IOUtil.toBufferedOutputStream(target));
IOUtil.copy(is,os,true,true);
}
/**
* compress a source file/directory to a zip file
* @param sources
* @param target
* @param filter
* @throws IOException
*/
public static void compressZip(Resource[] sources, Resource target, ResourceFilter filter) throws IOException {
ZipOutputStream zos = null;
try {
zos = new ZipOutputStream(IOUtil.toBufferedOutputStream(target.getOutputStream()));
compressZip("",sources, zos, filter);
}
finally {
IOUtil.closeEL(zos);
}
}
public static void compressZip( Resource[] sources, ZipOutputStream zos, ResourceFilter filter) throws IOException {
compressZip("",sources, zos, filter);
}
private static void compressZip(String parent, Resource[] sources, ZipOutputStream zos, ResourceFilter filter) throws IOException {
if(parent.length()>0)parent+="/";
for(int i=0;i<sources.length;i++) {
compressZip(parent+sources[i].getName(),sources[i],zos,filter);
}
}
private static void compressZip(String parent, Resource source, ZipOutputStream zos, ResourceFilter filter) throws IOException {
if(source.isFile()) {
//if(filter.accept(source)) {
ZipEntry ze=new ZipEntry(parent);
ze.setTime(source.lastModified());
zos.putNextEntry(ze);
try {
IOUtil.copy(source,zos,false);
}
finally {
zos.closeEntry();
}
//}
}
else if(source.isDirectory()) {
if(!StringUtil.isEmpty(parent)) {
ZipEntry ze=new ZipEntry(parent+"/");
ze.setTime(source.lastModified());
try {
zos.putNextEntry(ze);
}
catch(IOException ioe) {
if(Caster.toString(ioe.getMessage()).indexOf("duplicate")==-1)throw ioe;
}
zos.closeEntry();
}
compressZip(parent, filter==null?source.listResources():source.listResources(filter),zos,filter);
}
}
/**
* compress a source file/directory to a tar file
* @param sources
* @param target
* @param mode
* @throws IOException
*/
public static void compressTar(Resource[] sources,Resource target, int mode) throws IOException {
compressTar(sources, IOUtil.toBufferedOutputStream(target.getOutputStream()), mode);
}
public static void compressTar(Resource[] sources,OutputStream target, int mode) throws IOException {
if(target instanceof TarArchiveOutputStream){
compressTar("",sources,(TarArchiveOutputStream)target,mode);
return;
}
TarArchiveOutputStream tos=new TarArchiveOutputStream(target);
tos.setLongFileMode(TarArchiveOutputStream.LONGFILE_GNU);
try {
compressTar("",sources, tos,mode);
}
finally {
IOUtil.closeEL(tos);
}
}
public static void compressTar(String parent, Resource[] sources, TarArchiveOutputStream tos, int mode) throws IOException {
if(parent.length()>0)parent+="/";
for(int i=0;i<sources.length;i++) {
compressTar(parent+sources[i].getName(),sources[i],tos,mode);
}
}
private static void compressTar(String parent, Resource source,TarArchiveOutputStream tos, int mode) throws IOException {
if(source.isFile()) {
//TarEntry entry = (source instanceof FileResource)?new TarEntry((FileResource)source):new TarEntry(parent);
TarArchiveEntry entry = new TarArchiveEntry(parent);
entry.setName(parent);
// mode
//100777 TODO ist das so ok?
if(mode>0) entry.setMode(mode);
else if((mode=source.getMode())>0) entry.setMode(mode);
entry.setSize(source.length());
entry.setModTime(source.lastModified());
tos.putArchiveEntry(entry);
try {
IOUtil.copy(source,tos,false);
}
finally {
tos.closeArchiveEntry();
}
}
else if(source.isDirectory()) {
compressTar(parent, source.listResources(),tos,mode);
}
}
public static void main(String[] args) throws IOException {
ResourceProvider frp = ResourcesImpl.getFileResourceProvider();
Resource src = frp.getResource("/Users/mic/temp/a");
Resource tgz = frp.getResource("/Users/mic/temp/b/a.tgz");
tgz.getParentResource().mkdirs();
Resource tar = frp.getResource("/Users/mic/temp/b/a.tar");
tar.getParentResource().mkdirs();
Resource zip = frp.getResource("/Users/mic/temp/b/a.zip");
zip.getParentResource().mkdirs();
Resource tgz1 = frp.getResource("/Users/mic/temp/b/tgz");
tgz1.mkdirs();
Resource tar1 = frp.getResource("/Users/mic/temp/b/tar");
tar1.mkdirs();
Resource zip1 = frp.getResource("/Users/mic/temp/b/zip");
zip1.mkdirs();
compressTGZ(new Resource[]{src}, tgz, -1);
compressTar(new Resource[]{src}, tar, -1);
compressZip(new Resource[]{src}, zip, null);
extractTGZ(tgz, tgz1);
extractTar(tar, tar1);
extractZip(src, zip1);
}
}