Coverage Report - org.crosswire.common.util.IOUtil
 
Classes in this File Line Coverage Branch Coverage Complexity
IOUtil
0%
0/65
0%
0/32
4.8
 
 1  
 /**
 2  
  * Distribution License:
 3  
  * JSword is free software; you can redistribute it and/or modify it under
 4  
  * the terms of the GNU Lesser General Public License, version 2.1 or later
 5  
  * as published by the Free Software Foundation. This program is distributed
 6  
  * in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
 7  
  * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 8  
  * See the GNU Lesser General Public License for more details.
 9  
  *
 10  
  * The License is available on the internet at:
 11  
  *      http://www.gnu.org/copyleft/lgpl.html
 12  
  * or by writing to:
 13  
  *      Free Software Foundation, Inc.
 14  
  *      59 Temple Place - Suite 330
 15  
  *      Boston, MA 02111-1307, USA
 16  
  *
 17  
  * © CrossWire Bible Society, 2005 - 2016
 18  
  *
 19  
  */
 20  
 package org.crosswire.common.util;
 21  
 
 22  
 import java.io.Closeable;
 23  
 import java.io.File;
 24  
 import java.io.IOException;
 25  
 import java.io.InputStream;
 26  
 import java.io.OutputStream;
 27  
 import java.net.MalformedURLException;
 28  
 import java.net.URI;
 29  
 import java.util.Enumeration;
 30  
 
 31  
 import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
 32  
 import org.apache.commons.compress.archivers.zip.ZipFile;
 33  
 import org.crosswire.jsword.JSMsg;
 34  
 import org.slf4j.LoggerFactory;
 35  
 
 36  
 /**
 37  
  * .
 38  
  * 
 39  
  * @see gnu.lgpl.License The GNU Lesser General Public License for details.
 40  
  * @author Joe Walker
 41  
  */
 42  
 public final class IOUtil {
 43  
     /**
 44  
      * Prevent instantiation
 45  
      */
 46  0
     private IOUtil() {
 47  0
     }
 48  
 
 49  
     /**
 50  
      * Unpack a zip file to a given directory. Honor the paths as given in the
 51  
      * zip file.
 52  
      *
 53  
      * @param file
 54  
      *            The zip file to download
 55  
      * @param destdir
 56  
      *            The directory to unpack up
 57  
      * @throws IOException
 58  
      *             If there is an file error
 59  
      */
 60  
     public static void unpackZip(File file, File destdir) throws IOException {
 61  0
         unpackZip(file, destdir, true);
 62  0
     }
 63  
 
 64  
     /**
 65  
      * Unpack a zip file to a given directory. Honor the paths as given in the
 66  
      * zip file.
 67  
      *
 68  
      * @param file
 69  
      *            The zip file to download
 70  
      * @param destdir
 71  
      *            The directory to unpack up
 72  
      * @param include
 73  
      *            true to indicate the next arguments will be a filter that only includes what is specified.
 74  
      * @param includeExcludes
 75  
      *            a list of case insensitive patterns that will act as an inclusion or exclusion prefix
 76  
      * @throws IOException
 77  
      *            If there is an file error
 78  
      */
 79  
     public static void unpackZip(File file, File destdir, boolean include, String... includeExcludes) throws IOException {
 80  
         // unpack the zip.
 81  0
         byte[] dbuf = new byte[4096];
 82  0
         ZipFile zf = null;
 83  
         try {
 84  0
             zf = new ZipFile(file);
 85  0
             Enumeration<ZipArchiveEntry> entries = zf.getEntries();
 86  0
             while (entries.hasMoreElements()) {
 87  0
                 ZipArchiveEntry entry = entries.nextElement();
 88  0
                 String entrypath = entry.getName();
 89  
 
 90  
                 //check filters
 91  0
                 if (includeExcludes != null && includeExcludes.length > 0) {
 92  
                         //if include, then we attempt to match ANY path
 93  
                         //if exclude, then we ensure that we match NO path
 94  0
                     boolean skip = include;
 95  0
                     for (String filter : includeExcludes) {
 96  0
                         final boolean matchesPath = entrypath.toLowerCase().startsWith(filter);
 97  
                         //for includes, ANY match counts, so we override the default of true to false to say 'not skip'
 98  0
                         if (include && matchesPath) {
 99  0
                             skip = false;
 100  
                         }
 101  
 
 102  
                         //for excludes, the default of skip is false
 103  0
                         if (!include && matchesPath) {
 104  0
                             skip = true;
 105  
                         }
 106  
                     }
 107  
 
 108  0
                     if (skip) {
 109  0
                         continue;
 110  
                     }
 111  
                 }
 112  
 
 113  0
                 File entryFile = new File(destdir, entrypath);
 114  0
                 File parentDir = entryFile.getParentFile();
 115  
                 // Is it already a directory ?
 116  0
                 if (!parentDir.isDirectory()) {
 117  
                     // Create the directory and make sure it worked.
 118  0
                     if (!parentDir.mkdirs()) {
 119  
                         // TRANSLATOR: Error condition: A directory could not be created. {0} is a placeholder for the directory
 120  0
                         throw new MalformedURLException(JSMsg.gettext("The URL {0} could not be created as a directory.", parentDir.toString()));
 121  
                     }
 122  
                 }
 123  
 
 124  
                 // write entryFile from zip to filesystem but avoid writing dir entries out as files
 125  0
                 if (!entry.isDirectory()) {
 126  
 
 127  0
                     URI child = NetUtil.getURI(entryFile);
 128  
 
 129  0
                     OutputStream dataOut = NetUtil.getOutputStream(child);
 130  0
                     InputStream dataIn = zf.getInputStream(entry);
 131  
 
 132  
                     while (true) {
 133  0
                         int count = dataIn.read(dbuf);
 134  0
                         if (count == -1) {
 135  0
                             break;
 136  
                         }
 137  0
                         dataOut.write(dbuf, 0, count);
 138  0
                     }
 139  
 
 140  0
                     dataOut.close();
 141  
                 }
 142  0
             }
 143  
         } finally {
 144  0
             IOUtil.close(zf);
 145  0
         }
 146  0
     }
 147  
 
 148  
     /**
 149  
      * Get a zip entry by specification, returning a buffer of the contents.
 150  
      * If there is an error, return a zero length buffer.
 151  
      * 
 152  
      * @param entrySpec This is of the form /path/to/zip!entryName
 153  
      * @return the contents as a buffer
 154  
      * @throws IOException 
 155  
      */
 156  
     public static byte[] getZipEntry(String entrySpec) throws IOException {
 157  
         // Get the buffer
 158  0
         byte[] buffer = new byte[0];
 159  0
         String[] parts = StringUtil.split(entrySpec, '!');
 160  0
         ZipFile zipFile = null;
 161  0
         InputStream zin = null;
 162  
         try {
 163  0
             zipFile = new ZipFile(parts[0]);
 164  0
             ZipArchiveEntry entry = zipFile.getEntry(parts[1]);
 165  0
             zin = zipFile.getInputStream(entry);
 166  0
             int size = (int) entry.getSize();
 167  0
             buffer = new byte[size];
 168  
             // Repeatedly read until all has been read
 169  0
             int offset = 0;
 170  0
             while (offset < size) {
 171  0
                 offset += zin.read(buffer, offset, size - offset);
 172  
             }
 173  
 
 174  0
             if (offset != size) {
 175  0
                 log.error("Error: Could not read {} bytes, instead {}, for {} from {}", Integer.toString(size), Integer.toString(offset), parts[1], parts[0]);
 176  
             }
 177  
         } finally {
 178  0
             IOUtil.close(zin);
 179  0
             IOUtil.close(zipFile);
 180  0
         }
 181  0
         return buffer;
 182  
     }
 183  
 
 184  
     /**
 185  
      * Closes any {@link Closeable} object
 186  
      *
 187  
      * @param closeable
 188  
      *            The zip file to close
 189  
      */
 190  
     public static void close(Closeable closeable) {
 191  0
         if (null != closeable) {
 192  
             try {
 193  0
                 closeable.close();
 194  0
             } catch (IOException ex) {
 195  0
                 log.error("close", ex);
 196  0
             }
 197  
         }
 198  0
     }
 199  
 
 200  
     /**
 201  
      * The log stream
 202  
      */
 203  0
     private static final org.slf4j.Logger log = LoggerFactory.getLogger(IOUtil.class);
 204  
 }