All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.unkrig.commons.file.CompressUtil Maven / Gradle / Ivy

Go to download

A versatile Java(TM) library that implements many useful container and utility classes.

There is a newer version: 1.1.12
Show newest version

/*
 * de.unkrig.commons - A general-purpose Java class library
 *
 * Copyright (c) 2014, Arno Unkrig
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
 * following conditions are met:
 *
 *    1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
 *       following disclaimer.
 *    2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
 *       following disclaimer in the documentation and/or other materials provided with the distribution.
 *    3. The name of the author may not be used to endorse or promote products derived from this software without
 *       specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
 * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

package de.unkrig.commons.file;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.apache.commons.compress.archivers.ArchiveException;
import org.apache.commons.compress.archivers.ArchiveInputStream;
import org.apache.commons.compress.compressors.CompressorInputStream;

import de.unkrig.commons.file.org.apache.commons.compress.archivers.ArchiveFormat;
import de.unkrig.commons.file.org.apache.commons.compress.archivers.ArchiveFormatFactory;
import de.unkrig.commons.file.org.apache.commons.compress.compressors.CompressionFormat;
import de.unkrig.commons.file.org.apache.commons.compress.compressors.CompressionFormatFactory;
import de.unkrig.commons.io.IoUtil;
import de.unkrig.commons.io.MarkableFileInputStream;
import de.unkrig.commons.lang.AssertionUtil;
import de.unkrig.commons.lang.ExceptionUtil;
import de.unkrig.commons.lang.protocol.Predicate;
import de.unkrig.commons.nullanalysis.Nullable;

/** Utility class which implements functionality that is related to {@code org.apache.commons.compress}. */
public final
class CompressUtil {

    static { AssertionUtil.enableAssertionsForThisClass(); }

    private static final Logger LOGGER = Logger.getLogger(CompressUtil.class.getName());

    private CompressUtil() {}

    /**
     * @param                                              {@link #handleArchive(ArchiveInputStream, ArchiveFormat)}
     *                                                        returns a value of this type, which is, in turn, returned
     *                                                        by the {@code processStream()} and {@code processValue()}
     *                                                        methods
     * @see #handleArchive(ArchiveInputStream, ArchiveFormat)
     */
    public
    interface ArchiveHandler {

        /**
         * May or may not read entries and data from the {@code archiveInputStream}, and may or may not close it.
         *
         * @see #processFile(File, Predicate, ArchiveHandler, Predicate, CompressorHandler, NormalContentsHandler)
         * @see #processStream(InputStream, Predicate, ArchiveHandler, Predicate, CompressorHandler,
         *      NormalContentsHandler)
         */
        @Nullable T
        handleArchive(ArchiveInputStream archiveInputStream, ArchiveFormat archiveFormat) throws IOException;
    }

    /**
     * @param                                                        {@link #handleCompressor(CompressorInputStream,
     *                                                                  CompressionFormat)} returns a value of this
     *                                                                  type, which is, in turn, returned by the {@code
     *                                                                  processStream()} and {@code processValue()}
     *                                                                  methods
     * @see #handleCompressor(CompressorInputStream, CompressionFormat)
     */
    public
    interface CompressorHandler {

        /**
         * May or may not read from the {@code compressorInputStream}.
         *
         * @see #processFile(File, Predicate, ArchiveHandler, Predicate, CompressorHandler, NormalContentsHandler)
         * @see #processStream(InputStream, Predicate, ArchiveHandler, Predicate, CompressorHandler,
         *      NormalContentsHandler)
         */
        @Nullable T
        handleCompressor(CompressorInputStream compressorInputStream, CompressionFormat compressionFormat)
        throws IOException;
    }

    /**
     * @param                              {@link #handleNormalContents(InputStream)} returns a value of this type,
     *                                        which is, in turn, returned by the {@code processStream()} and {@code
     *                                        processValue()} methods
     * @see #handleNormalContents(InputStream)
     */
    public
    interface NormalContentsHandler {

        /**
         * May or may not read from the {@code inputStream}, and may or may not close it.
         *
         * @see #processFile(File, Predicate, ArchiveHandler, Predicate, CompressorHandler, NormalContentsHandler)
         * @see CompressUtil#processStream(InputStream, Predicate, ArchiveHandler, Predicate, CompressorHandler,
         *      NormalContentsHandler)
         */
        @Nullable T
        handleNormalContents(InputStream inputStream) throws IOException;
    }

    /**
     * Invokes exactly one of {@code archiveHandler}, {@code compressorHandler} or {@code
     * normalContentsHandler}.
     * 

* An archive file is introspected iff {@code lookIntoFormat} evaluates to {@code true} for {@code * "archive-format-name:path"}. *

* A compressed file is introspected iff {@code lookIntoFormat} evaluates to {@code true} for {@code * "compression-format-name:path"}. * * @see ArchiveFormatFactory#allFormats() * @see CompressionFormatFactory#allFormats() */ @Nullable public static T processStream( String path, InputStream inputStream, Predicate lookIntoFormat, ArchiveHandler archiveHandler, CompressorHandler compressorHandler, NormalContentsHandler normalContentsHandler ) throws IOException { return CompressUtil.processStream( inputStream, // inputStream CompressUtil.lookIntoArchive(path, lookIntoFormat), // lookIntoArchive archiveHandler, // archiveHandler CompressUtil.lookIntoCompressed(path, lookIntoFormat), // lookIntoCompressed compressorHandler, // compressorHandler normalContentsHandler // normalContentsHandler ); } /** * Invokes exactly one of {@code archiveHandler}, {@code compressorHandler} or {@code * normalContentsHandler}. * * @param lookIntoArchive An archive stream is introspected iff {@code lookIntoArchive} evaluates to {@code true} * for the archive format * @param lookIntoCompressed A compressed stream is introspected iff {@code lookIntoCompressed} evaluates to {@code * true} for the compression format * @see CompressionFormatFactory#allFormats() */ @Nullable public static T processStream( InputStream inputStream, Predicate lookIntoArchive, ArchiveHandler archiveHandler, Predicate lookIntoCompressed, CompressorHandler compressorHandler, NormalContentsHandler normalContentsHandler ) throws IOException { if (!inputStream.markSupported()) inputStream = new BufferedInputStream(inputStream); ARCHIVE: { final ArchiveFormat archiveFormat = ArchiveFormatFactory.forContents(inputStream); if (archiveFormat == null) break ARCHIVE; if (!lookIntoArchive.evaluate(archiveFormat)) { return normalContentsHandler.handleNormalContents(inputStream); } ArchiveInputStream ais; try { ais = archiveFormat.archiveInputStream(IoUtil.unclosableInputStream(inputStream)); } catch (ArchiveException ae) { throw new IOException(archiveFormat.getName(), ae); } return archiveHandler.handleArchive(ais, archiveFormat); } COMPRESSED: { final CompressionFormat compressionFormat = CompressionFormatFactory.forContents(inputStream); if (compressionFormat == null) break COMPRESSED; if (!lookIntoCompressed.evaluate(compressionFormat)) { return normalContentsHandler.handleNormalContents(inputStream); } return compressorHandler.handleCompressor( compressionFormat.compressorInputStream(IoUtil.unclosableInputStream(inputStream)), compressionFormat ); } return normalContentsHandler.handleNormalContents(inputStream); } /** * Invokes exactly one of {@code archiveHandler}, {@code compressorHandler} or {@code * normalContentsHandler}. *

* An archive file is introspected iff {@code lookIntoFormat} evaluates to {@code true} for * "{@code archive-format-name}{@code :}{@code path}". *

* A compressed file is introspected iff {@code lookIntoFormat} evaluates to {@code true} for "{@code * compression-format-name}{@code :}{@code path}". * * @see ArchiveFormatFactory#allFormats() * @see CompressionFormatFactory#allFormats() */ @Nullable public static T processFile( String path, File file, Predicate lookIntoFormat, ArchiveHandler archiveHandler, CompressorHandler compressorHandler, NormalContentsHandler normalContentsHandler ) throws IOException { return CompressUtil.processFile( file, CompressUtil.lookIntoArchive(path, lookIntoFormat), archiveHandler, CompressUtil.lookIntoCompressed(path, lookIntoFormat), compressorHandler, normalContentsHandler ); } /** * Invokes exactly one of {@code archiveHandler}, {@code compressorHandler} or {@code * normalContentsHandler}. * * @param lookIntoArchive An archive file is introspected iff {@code lookIntoArchive} evaluates to {@code true} * for the archive format * @param lookIntoCompressed A compressed file is introspected iff {@code lookIntoCompressed} evaluates to {@code * true} for the compression format * @see CompressionFormatFactory#allFormats() */ @Nullable public static T processFile( final File file, Predicate lookIntoArchive, ArchiveHandler archiveHandler, Predicate lookIntoCompressed, CompressorHandler compressorHandler, NormalContentsHandler normalContentsHandler ) throws IOException { InputStream is = new MarkableFileInputStream(file); try { ArchiveFormat archiveFormat = ArchiveFormatFactory.forContents(is); if (archiveFormat != null) { if (!lookIntoArchive.evaluate(archiveFormat)) { return normalContentsHandler.handleNormalContents(is); } is.close(); ArchiveInputStream ais = archiveFormat.open(file); is = ais; T result = archiveHandler.handleArchive(ais, archiveFormat); ais.close(); return result; } CompressionFormat compressionFormat = CompressionFormatFactory.forContents(is); if (compressionFormat != null) { if (!lookIntoCompressed.evaluate(compressionFormat)) { return normalContentsHandler.handleNormalContents(is); } CompressorInputStream cis = compressionFormat.compressorInputStream(is); T result = compressorHandler.handleCompressor(cis, compressionFormat); cis.close(); return result; } CompressUtil.LOGGER.log(Level.FINER, "Processing normal file \"{0}\"", file); T result = normalContentsHandler.handleNormalContents(is); is.close(); return result; } catch (ArchiveException ae) { throw ExceptionUtil.wrap(file.toString(), ae, IOException.class); } catch (IOException ioe) { throw ExceptionUtil.wrap(file.toString(), ioe); } finally { try { is.close(); } catch (Exception e) {} } } private static Predicate lookIntoArchive(final String path, final Predicate lookIntoFormat) { return new Predicate() { @Override public boolean evaluate(ArchiveFormat af) { boolean result = lookIntoFormat.evaluate(af.getName() + ':' + path); CompressUtil.LOGGER.log( Level.FINER, "Look into archive \"{0}\"? => {1}", new Object[] { path, result } ); return result; } }; } private static Predicate lookIntoCompressed(final String path, final Predicate lookIntoFormat) { return new Predicate() { @Override public boolean evaluate(CompressionFormat cf) { boolean result = lookIntoFormat.evaluate(cf.getName() + ':' + path); CompressUtil.LOGGER.log( Level.FINER, "Look into compressed \"{0}\"? => {1}", new Object[] { path, result } ); return result; } }; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy