001/*
002 * Copyright 2018 Nils Hoffmann <nils.hoffmann@isas.de>.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package de.isas.mztab2.test.utils;
017
018import java.io.BufferedInputStream;
019import java.io.BufferedOutputStream;
020import java.io.File;
021import java.io.FileNotFoundException;
022import java.io.FileOutputStream;
023import java.io.IOException;
024import java.io.InputStream;
025import java.net.URL;
026import java.util.logging.Level;
027import java.util.logging.Logger;
028import java.util.zip.GZIPInputStream;
029import java.util.zip.ZipEntry;
030import java.util.zip.ZipInputStream;
031
032/**
033 * <p>
034 * ZipResourceExtractor class.</p>
035 *
036 * @author nilshoffmann
037 *
038 */
039public class ZipResourceExtractor {
040
041    private ZipResourceExtractor() {
042        
043    }
044    
045    /**
046     * <p>
047     * Extract a JAR resource into the provided destination directory and return
048     * that extracted resource's location as a file.</p>
049     *
050     * @param resourcePath a {@link java.lang.String} object.
051     * @param destDir a {@link java.io.File} object.
052     * @return a {@link java.io.File} object.
053     */
054    public static File extract(String resourcePath, File destDir) {
055        if (!destDir.exists()) {
056            destDir.mkdirs();
057        }
058        URL resourceURL = ZipResourceExtractor.class.getResource(resourcePath);
059        if (resourceURL == null) {
060            throw new NullPointerException(
061                "Could not retrieve resource for path: " + resourcePath);
062        }
063        File outputFile = null;
064        try (InputStream resourceInputStream = resourceURL.openStream()) {
065
066            String outname = new File(resourceURL.getPath()).getName();
067            outname = outname.replaceAll("%20", " ");
068            if (resourcePath.endsWith("zip")) {
069                outname = outname.substring(0, outname.lastIndexOf(
070                    '.'));
071                return extractZipArchive(resourceInputStream, destDir);
072            } else if (resourcePath.endsWith("gz")) {
073                try (InputStream in = new GZIPInputStream(
074                    new BufferedInputStream(
075                        resourceInputStream))) {
076
077                    outname = outname.substring(0, outname.lastIndexOf(
078                        '.'));
079                    return writeTo(destDir, outname, in);
080                }
081            } else {
082                try (InputStream in = new BufferedInputStream(
083                    resourceInputStream)) {
084                    return writeTo(destDir, outname, in);
085                }
086            }
087
088        } catch (IOException ex) {
089            Logger.getLogger(ZipResourceExtractor.class.getName()).
090                log(Level.SEVERE, null, ex);
091        }
092
093        return outputFile;
094    }
095
096    private static File writeTo(File destDir, String outname, InputStream in) throws FileNotFoundException, IOException {
097        File outputFile = new File(destDir, outname);
098        try (BufferedOutputStream out = new BufferedOutputStream(
099            new FileOutputStream(outputFile))) {
100
101            // Transfer bytes from in to out
102            byte[] buf = new byte[1024];
103            int len;
104            while ((len = in.read(buf)) > 0) {
105                out.write(buf, 0, len);
106            }
107        }
108        return outputFile;
109    }
110
111    /**
112     * <p>
113     * extractZipArchive.</p>
114     *
115     * @param istream a {@link java.io.InputStream} object.
116     * @param outputDir a {@link java.io.File} object.
117     * @return a {@link java.io.File} object.
118     */
119    public static File extractZipArchive(InputStream istream, File outputDir) {
120        try {
121            File outDir;
122            try (ZipInputStream zis = new ZipInputStream(
123                new BufferedInputStream(istream))) {
124                ZipEntry entry;
125                outDir = null;
126                while ((entry = zis.getNextEntry()) != null) {
127                    int size;
128                    byte[] buffer = new byte[2048];
129                    File outFile = new File(outputDir, entry.getName());
130                    if (entry.isDirectory()) {
131                        outFile.mkdirs();
132                        if (outDir == null) {
133                            outDir = outFile;
134                        }
135                    } else {
136                        try (FileOutputStream fos = new FileOutputStream(outFile)) {
137                            BufferedOutputStream bos = new BufferedOutputStream(
138                                fos, buffer.length);
139                            while ((size = zis.read(buffer, 0, buffer.length)) != -1) {
140                                bos.write(buffer, 0, size);
141                            }
142                            bos.flush();
143                            bos.close();
144                        }
145                    }
146                }
147                if (outDir == null) {
148                    outDir = outputDir;
149                }
150            }
151            istream.close();
152            return outDir;
153        } catch (IOException e) {
154            throw new ZipResourceExtractionException(e);
155        }
156    }
157}