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); } }