lucee.commons.io.compress.CompressUtil.java Source code

Java tutorial

Introduction

Here is the source code for lucee.commons.io.compress.CompressUtil.java

Source

/**
 * Copyright (c) 2015, Lucee Assosication Switzerland. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either 
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library 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
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public 
 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
 * 
 */
package lucee.commons.io.compress;

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 lucee.aprint;
import lucee.commons.io.IOUtil;
import lucee.commons.io.SystemUtil;
import lucee.commons.io.res.Resource;
import lucee.commons.io.res.ResourceProvider;
import lucee.commons.io.res.ResourcesImpl;
import lucee.commons.io.res.filter.ExtensionResourceFilter;
import lucee.commons.io.res.filter.OrResourceFilter;
import lucee.commons.io.res.filter.ResourceFilter;
import lucee.commons.lang.StringUtil;
import lucee.runtime.op.Caster;

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;

/**
 * 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);

    }
}