eu.planets_project.services.utils.ZipUtils.java Source code

Java tutorial

Introduction

Here is the source code for eu.planets_project.services.utils.ZipUtils.java

Source

/*******************************************************************************
 * Copyright (c) 2007, 2010 The Planets Project Partners.
 *
 * All rights reserved. This program and the accompanying 
 * materials are made available under the terms of the 
 * Apache License, Version 2.0 which accompanies 
 * this distribution, and is available at 
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 *******************************************************************************/
package eu.planets_project.services.utils;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.logging.Logger;
import java.util.zip.ZipException;

import org.apache.commons.io.IOUtils;

import ch.enterag.utils.zip.EntryInputStream;
import ch.enterag.utils.zip.EntryOutputStream;
import ch.enterag.utils.zip.FileEntry;
import ch.enterag.utils.zip.Zip64File;
import eu.planets_project.services.datatypes.Checksum;

public class ZipUtils {

    private static Logger log = Logger.getLogger(ZipUtils.class.getName());

    /**
     * Creates a Zip64File zip file.
     * @param srcFolder the folder containing the files to be written to the zip
     * @param destFolder the folder to write the Zip file to
     * @param zipName the name the zip file should have. If no zipName is passed, the name of the folder will be used.
     * @param compress true if the file shoukld be compressed, false if not.
     * @return a zip(64) File
     */
    public static File createZip(File srcFolder, File destFolder, String zipName, boolean compress) {
        Zip64File zipFile = null;

        if (!srcFolder.isDirectory()) {
            log.severe(
                    "[createZip] The File object you have passed is NOT a folder! Nothing has been done, sorry.");
            return null;
        }

        if (zipName == null) {
            zipName = srcFolder.getName();
            log.info("[createZip] No zipName specified, using folder name instead: " + zipName);
        }

        try {
            File newZip = new File(destFolder, zipName);
            zipFile = new Zip64File(newZip);
            List<String> listOfFiles = listAllFilesAndFolders(srcFolder, new ArrayList<String>());
            if (listOfFiles.size() == 0) {
                log.info("[createZip] Found no files to put in the zip. Created empty Zip file anyway...");
                zipFile.close();
                return new File(zipFile.getDiskFile().getFileName());
            }
            log.info("[createZip] Working on zipFile: " + zipFile.getDiskFile().getFileName());
            log.info("[createZip] Normalizing paths...");
            List<String> normalizedPaths = normalizePaths(srcFolder);

            for (int i = 0; i < normalizedPaths.size(); i++) {
                String currentZipEntryPath = normalizedPaths.get(i);
                FileEntry entry = new FileEntry(currentZipEntryPath);
                File currentFile = new File(listOfFiles.get(i));

                writeEntry(zipFile, entry, currentFile, compress);
            }
            log.info("[createZip] All Files written to zip file: " + zipFile.getDiskFile().getFileName());
            zipFile.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return new File(zipFile.getDiskFile().getFileName());
    }

    /**
     * Creates a Zip64File containing all the files in srcFolder and write it to destFolder using the passed zipName.
     * After creating the zip file, a checksum is calculated.  
     * @param srcFolder the folder containing the files to be written to the zip
     * @param destFolder the folder to write the Zip file to
     * @param zipName the name the zip file should have. If no zipName is passed, the name of the folder will be used.
     * @param compress has no effect TODO implement compression
     * @return a ZipResult, containing the zip as a file and the created checksum (MD5)
     */
    public static ZipResult createZipAndCheck(File srcFolder, File destFolder, String zipName, boolean compress) {
        if (zipName == null) {
            zipName = srcFolder.getName();
        }
        File newZipFile = createZip(srcFolder, destFolder, zipName, compress);
        log.info("[createZipAndCheck] Zip file created: " + zipName);
        ZipResult zipResult = new ZipResult();
        try {
            byte[] digest = Checksums.md5(newZipFile);
            zipResult.setZipFile(newZipFile);
            zipResult.setChecksum(new Checksum("MD5", Arrays.toString(digest)));
            log.info("[createZipAndCheck] Checksum (MD5) created: " + zipResult.getChecksum());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return zipResult;
    }

    /**
     * Unzips a zip file and writes the contained files to destFolder.
     * 
     * @param zipFile the zip file to unpack.
     * @param destFolder the folder to write the extracted files to.
     * @return a List with all extracted files.
     */
    @SuppressWarnings("unchecked")
    public static List<File> unzipTo(File zipFile, File destFolder) {
        List<File> extractedFiles = null;
        try {
            Zip64File zip64File = new Zip64File(zipFile);

            List<FileEntry> entries = zip64File.getListFileEntries();
            extractedFiles = new ArrayList<File>();
            for (FileEntry fileEntry : entries) {

                File currentFile = readEntry(zip64File, fileEntry, destFolder);
                extractedFiles.add(currentFile);

            }
            zip64File.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return extractedFiles;
    }

    private static void readFileEntry(Zip64File zip64File, FileEntry fileEntry, File destFolder) {
        FileOutputStream fileOut;
        File target = new File(destFolder, fileEntry.getName());
        File targetsParent = target.getParentFile();
        if (targetsParent != null) {
            targetsParent.mkdirs();
        }
        try {
            //         boolean madeFolder = target.createNewFile();
            fileOut = new FileOutputStream(target);
            log.info("[readFileEntry] writing entry: " + fileEntry.getName() + " to file: "
                    + target.getAbsolutePath());
            EntryInputStream entryReader = zip64File.openEntryInputStream(fileEntry.getName());
            IOUtils.copyLarge(entryReader, fileOut);
            entryReader.close();
            fileOut.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (ZipException e) {
            log.warning(
                    "ATTENTION PLEASE: Some strange, but obviously not serious ZipException occured! Extracted file '"
                            + target.getName() + "' anyway! So don't Panic!" + "\n");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static void readFolderEntry(Zip64File zip64File, FileEntry folderEntry, File dest) {
        log.info("[readFolderEntry] The target you have specified is a folder: " + folderEntry.getName());
        File currentFolder = new File(dest, folderEntry.getName());
        currentFolder.mkdirs();
        List<String> containedFiles = getFileEntryChildren(zip64File, folderEntry);

        if (containedFiles.size() > 0) {
            for (String currentFilePath : containedFiles) {
                FileEntry currentEntry = zip64File.getFileEntry(currentFilePath);
                File destination = new File(dest, currentEntry.getName());
                if (!currentEntry.isDirectory()) {
                    readFileEntry(zip64File, currentEntry, dest);
                } else {
                    destination.mkdirs();
                    log.info("[readFolderEntry] Created folder in file system: " + destination.getAbsolutePath());
                    //               readFolderEntry(zip64File, currentEntry, destination);
                }
            }
        }
    }

    /**
     * Unzips a zip file and writes the content to destFolder, checking if the checksum is correct.
     * 
     * @param zipFile the file to unpack
     * @param destFolder the folder to write the content of the zip to
     * @param checksum the checksum to check
     * @return a list containing all extracted files.
     */
    public static List<File> checkAndUnzipTo(File zipFile, File destFolder, Checksum checksum) {
        try {
            byte[] fileDigest = Checksums.md5(zipFile);
            String fileDigestString = Arrays.toString(fileDigest);
            if (!fileDigestString.equals(checksum.getValue())) {
                log.warning(
                        "[checkAndUnzipTo] WARNING: The calculated checksum of the zip file is NOT equal to the passed checksum. File might be corrupted!");
                log.warning("[checkAndUnzipTo] Checksum Algorithm: " + checksum.getAlgorithm());
                log.warning("[checkAndUnzipTo] Passed checksum: " + checksum.getValue());
                log.warning("[checkAndUnzipTo] Calculated checksum: " + fileDigestString);
            } else {
                log.info("[checkAndUnzipTo] Success!! Checksum correct!");
            }
            return unzipTo(zipFile, destFolder);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * A convenience method. It creates an array of fragments from all entries in a given zip file.
     * Fragments can be used to adress entries in a zip file.
     * 
     * @param zip the zip file to scan
     * @return an String[] containing all file entries in this zip. 
     * 
     */
    public static String[] getAllFragments(File zip) {
        //      String[] fragments = null;
        //      try {
        //         Zip64File zip64File = new Zip64File(zip);
        //         List<FileEntry> entries = zip64File.getListFileEntries();
        //         if(entries.size() > 0) {
        //            int i = 0;
        //            fragments = new String[entries.size()];
        //            for (FileEntry fileEntry : entries) {
        //               fragments[i] = new String(fileEntry.getName());
        //               i++;
        //            }
        //         }
        //         else {
        //            return new String[]{};
        //         }
        //         zip64File.close();

        List<String> entries = listZipEntries(zip);
        if (entries.size() > 0) {
            return entries.toArray(new String[] {});
        } else {
            log.severe("[ZipUtils] getAllFragments(): No file entries found! This file is not a valid ZIP file!");
            return new String[] {};
        }

        //      } catch (ZipException e) {
        //         log.severe("[ZipUtils] getAllFragments(): No file entries found! This file is not a valid ZIP file!");
        ////         e.printStackTrace();
        //         return new String[] {};
        //      } catch (FileNotFoundException e) {
        //         e.printStackTrace();
        //      } catch (IOException e) {
        //         e.printStackTrace();
        //      }
        //      return fragments;
    }

    /**
     * Extracts a file specified by targetPathInZipfile from the passed zip and writes it to destFolder.
     * If the targetPathInZipfile points to a folder, all files in the folder will be extracted as well
     * and the parent folder, containing all these files, is returned.
     * 
     * @param zip the zip to extract targetPathInZipfile from
     * @param targetPathInZipfile the file to extract
     * @param destFolder the folder to write the extrcated file to
     * @return the extracted File.
     */
    public static File getFileFrom(File zip, String targetPathInZipfile, File destFolder) {
        File target = null;
        try {
            Zip64File zip64File = new Zip64File(zip);
            FileEntry targetEntry = getFileEntry(zip64File, targetPathInZipfile);

            if (targetEntry != null) {
                target = readEntry(zip64File, targetEntry, destFolder);
            } else {
                log.severe("[getFileFrom] Sorry, the file/folder you ask for could not be found in this zip: "
                        + targetPathInZipfile);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return target;
    }

    //   private static List<String> checkFilesForDeletion(Zip64File zip64File, FileEntry parentFolderEntry, File folderToInsert) {
    //      List<String> entryChildren = getFileEntryChildren(zip64File, parentFolderEntry);
    //      List<String> filesToAdd = normalizePaths(folderToInsert);
    //      
    //      List<String> filesToDelete = new ArrayList<String>();
    //      
    //      for (String currentChild : entryChildren) {
    //         for (String currentToAdd : filesToAdd) {
    //            if(currentChild.endsWith(currentToAdd)) {
    //               filesToDelete.add(currentChild);
    //            }
    //         }
    //      }
    //      
    //      return filesToDelete;
    //   }

    /**
     * Inserts a file into a given zip at a location specified by targetPath.
     * If toInsert points to a folder, all files in this folder will be added to the zip.
     * If the zip already contains a file specified by targetPath, the existing entry (and all files contained in it) 
     * will be deleted and toInsert (and all contained files) is inserted.
     * 
     * @param zipFile the zip file where the file toInsert will be added.
     * @param toInsert the file to add to the zip 
     * @param targetPath the location the file should have in this zip
     * @return the modified zip, containing the file toInsert.
     */
    public static File insertFileInto(File zipFile, File toInsert, String targetPath) {
        Zip64File zip64File = null;
        try {
            boolean compress = false;

            zip64File = new Zip64File(zipFile);

            FileEntry testEntry = getFileEntry(zip64File, targetPath);

            if (testEntry != null && testEntry.getMethod() == FileEntry.iMETHOD_DEFLATED) {
                compress = true;
            }

            processAndCreateFolderEntries(zip64File, parseTargetPath(targetPath, toInsert), compress);

            if (testEntry != null) {
                log.info("[insertFileInto] Entry exists: " + testEntry.getName());
                log.info("[insertFileInto] Will delete this entry before inserting: " + toInsert.getName());
                if (!testEntry.isDirectory()) {
                    zip64File.delete(testEntry.getName());
                } else {
                    log.info("[insertFileInto] Entry is a directory. "
                            + "Will delete all files contained in this entry and insert " + toInsert.getName()
                            + "and all nested files.");

                    if (!targetPath.contains("/")) {
                        targetPath = targetPath + "/";
                    }
                    deleteFileEntry(zip64File, testEntry);
                    log.info("[insertFileInto] Entry successfully deleted.");
                }

                log.info("[insertFileInto] Writing new Entry: " + targetPath);
                EntryOutputStream out = null;
                if (!compress) {
                    out = zip64File.openEntryOutputStream(targetPath, FileEntry.iMETHOD_STORED,
                            new Date(toInsert.lastModified()));
                } else {
                    out = zip64File.openEntryOutputStream(targetPath, FileEntry.iMETHOD_DEFLATED,
                            new Date(toInsert.lastModified()));
                }

                if (toInsert.isDirectory()) {
                    out.flush();
                    out.close();
                    log.info("[insertFileInto] Finished writing entry: " + targetPath);

                    List<String> containedPaths = normalizePaths(toInsert);
                    List<File> containedFiles = listAllFilesAndFolders(toInsert, new ArrayList<File>());

                    log.info("[insertFileInto] Added entry is a folder.");
                    log.info("[insertFileInto] Adding all nested files: ");
                    for (int i = 0; i < containedPaths.size(); i++) {
                        File currentFile = containedFiles.get(i);
                        String currentPath = targetPath.replace("/", "") + File.separator + containedPaths.get(i);
                        EntryOutputStream loop_out = null;
                        if (!compress) {
                            loop_out = zip64File.openEntryOutputStream(currentPath, FileEntry.iMETHOD_STORED,
                                    new Date(currentFile.lastModified()));
                        } else {
                            loop_out = zip64File.openEntryOutputStream(currentPath, FileEntry.iMETHOD_DEFLATED,
                                    new Date(currentFile.lastModified()));
                        }
                        if (currentFile.isFile()) {
                            InputStream loop_in = new FileInputStream(currentFile);
                            IOUtils.copyLarge(loop_in, loop_out);
                            loop_in.close();
                        }
                        log.info("[insertFileInto] Added: " + currentPath);
                        loop_out.flush();
                        loop_out.close();
                    }
                } else {
                    InputStream in = new FileInputStream(toInsert);
                    IOUtils.copyLarge(in, out);
                    in.close();
                    out.flush();
                    out.close();
                }
            } else {
                EntryOutputStream out = null;
                if (!compress) {
                    out = zip64File.openEntryOutputStream(targetPath, FileEntry.iMETHOD_STORED,
                            new Date(toInsert.lastModified()));
                } else {
                    out = zip64File.openEntryOutputStream(targetPath, FileEntry.iMETHOD_DEFLATED,
                            new Date(toInsert.lastModified()));
                }

                if (toInsert.isDirectory()) {
                    out.flush();
                    out.close();
                    log.info("[insertFileInto] Finished writing entry: " + targetPath);

                    List<String> containedPaths = normalizePaths(toInsert);
                    List<File> containedFiles = listAllFilesAndFolders(toInsert, new ArrayList<File>());

                    log.info("[insertFileInto] Added entry is a folder.");
                    log.info("[insertFileInto] Adding all nested files: ");

                    for (int i = 0; i < containedPaths.size(); i++) {
                        File currentFile = containedFiles.get(i);
                        String currentPath = targetPath.replace("/", "") + File.separator + containedPaths.get(i);
                        EntryOutputStream loop_out = null;
                        if (!compress) {
                            loop_out = zip64File.openEntryOutputStream(currentPath, FileEntry.iMETHOD_STORED,
                                    new Date(currentFile.lastModified()));
                        } else {
                            loop_out = zip64File.openEntryOutputStream(currentPath, FileEntry.iMETHOD_DEFLATED,
                                    new Date(currentFile.lastModified()));
                        }

                        if (currentFile.isFile()) {
                            InputStream loop_in = new FileInputStream(currentFile);
                            IOUtils.copyLarge(loop_in, loop_out);
                            loop_in.close();
                        }
                        log.info("[insertFileInto] Added: " + currentPath);
                        loop_out.flush();
                        loop_out.close();
                    }
                } else {
                    InputStream in = new FileInputStream(toInsert);
                    IOUtils.copyLarge(in, out);
                    in.close();
                    out.flush();
                    out.close();
                }
            }
            log.info("[insertFileInto] Done! Added " + toInsert.getName() + " to zip.");
            zip64File.close();

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return new File(zip64File.getDiskFile().getFileName());
    }

    private static List<String> parseTargetPath(String targetPath, File toInsert) {
        List<String> cleanedParts = new ArrayList<String>();

        if (targetPath.contains("\\")) {
            targetPath = targetPath.replace("\\", "#");
            String[] parts = targetPath.split("#");
            if (parts.length > 1) {
                String accumulatedPath = "";
                for (int i = 0; i < parts.length - 1; i++) {
                    String thisPath = accumulatedPath + "\\" + parts[i] + "/";
                    cleanedParts.add(thisPath.substring(1));
                    accumulatedPath = accumulatedPath + "\\" + parts[i];
                }
            } else {
                return null;
            }
            return cleanedParts;
        } else {
            return null;
        }
    }

    private static void processAndCreateFolderEntries(Zip64File zip64File, List<String> pathParts,
            boolean compress) {
        if (pathParts == null) {
            return;
        }
        for (String string : pathParts) {
            FileEntry currentEntry = zip64File.getFileEntry(string);
            if (currentEntry != null) {
                continue;
            } else {
                currentEntry = zip64File.getFileEntry(string + "/");
                if (currentEntry != null) {
                    continue;
                } else {
                    try {
                        EntryOutputStream entryWriter = null;

                        if (!compress) {
                            entryWriter = zip64File.openEntryOutputStream(string, FileEntry.iMETHOD_STORED, null);
                        } else {
                            entryWriter = zip64File.openEntryOutputStream(string, FileEntry.iMETHOD_DEFLATED, null);
                        }

                        entryWriter.flush();
                        entryWriter.close();
                    } catch (FileNotFoundException e) {
                        e.printStackTrace();
                    } catch (ZipException e) {
                        e.printStackTrace();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    /**
     * Removes the file 'fileToRemove' from zipFile. 
     * 'fileToRemove' points to the location of the file to delete inside the zip file.
     * 
     * @param zipFile the zip file to remove fileToRemove from.
     * @param fileToRemove the path of the file to remove from zipFile.
     * @return the modified zipFile.
     */
    public static File removeFileFrom(File zipFile, String fileToRemove) {
        Zip64File zip64File = null;
        try {
            zip64File = new Zip64File(zipFile);

            FileEntry testEntry = getFileEntry(zip64File, fileToRemove);

            if (testEntry == null) {
                log.info("File not found: " + fileToRemove);
                log.info("Nothing has been deleted...");
            } else {
                if (testEntry.isDirectory()) {
                    deleteFileEntry(zip64File, testEntry);
                } else {
                    FileEntry deletedEntry = zip64File.delete(fileToRemove);
                    log.info("Deleted entry from zip: " + deletedEntry.getName());
                    zip64File.close();
                }
            }

            zip64File.close();

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return new File(zip64File.getDiskFile().getFileName());
    }

    @SuppressWarnings("unchecked")
    public static boolean isZipFile(File file) {
        try {
            Zip64File zip = new Zip64File(file);
            List<FileEntry> entries = zip.getListFileEntries();
            if (entries == null) {
                return false;
            } else {
                return true;
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (ZipException e) {
            log.info("File '" + file.getName() + "' is NOT a ZIP.");
            return false;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * Lists all entries in this zip file. Each entry is a file/folder in this zip.
     * @param zip the zip file to scan
     * @return a list with all entry paths
     */
    @SuppressWarnings("unchecked")
    public static List<String> listZipEntries(File zip) {
        List<String> entryList = new ArrayList<String>();
        try {
            Zip64File zip64File = new Zip64File(zip);
            List<FileEntry> entries = zip64File.getListFileEntries();

            //         zip64File.close();

            if (entries.size() > 0) {
                for (FileEntry fileEntry : entries) {
                    List<String> parents = getParents(fileEntry);
                    if (parents != null) {
                        for (String currentPart : parents) {
                            if (!entryList.contains(currentPart)) {
                                entryList.add(currentPart);
                            }
                        }
                    }
                    entryList.add(fileEntry.getName());
                }
            } else {
                return new ArrayList<String>();
            }

        } catch (ZipException e) {
            log.severe("[ZipUtils] listZipEntries(): " + e.getMessage());
            //         e.printStackTrace();
            return entryList;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return entryList;
    }

    private static List<String> getParents(FileEntry fileEntry) {
        List<String> parentsList = new ArrayList<String>();
        String path = fileEntry.getName();
        String[] parents = null;
        if (path.contains("/")) {
            parents = path.split("/");
            String tmp = "";
            for (int i = 0; i < parents.length - 1; i++) {
                if (tmp.equalsIgnoreCase("")) {
                    parentsList.add(tmp + parents[i] + "/");
                    tmp = tmp + parents[i];
                } else {
                    parentsList.add(tmp + "/" + parents[i] + "/");
                    tmp = tmp + "/" + parents[i];
                }
            }
            return parentsList;
        } else {
            return null;
        }
    }

    private static File readEntry(Zip64File zip64File, FileEntry toRead, File destFolder) {
        File target = new File(destFolder, toRead.getName());
        if (!toRead.isDirectory()) {
            readFileEntry(zip64File, toRead, destFolder);
        } else {
            readFolderEntry(zip64File, toRead, destFolder);
        }
        return target;
    }

    private static FileEntry writeEntry(Zip64File zip64File, FileEntry targetPath, File toWrite, boolean compress) {
        InputStream in = null;
        EntryOutputStream out = null;

        processAndCreateFolderEntries(zip64File, parseTargetPath(targetPath.getName(), toWrite), compress);

        try {

            if (!compress) {
                out = zip64File.openEntryOutputStream(targetPath.getName(), FileEntry.iMETHOD_STORED,
                        getFileDate(toWrite));
            } else {
                out = zip64File.openEntryOutputStream(targetPath.getName(), FileEntry.iMETHOD_DEFLATED,
                        getFileDate(toWrite));
            }

            if (!targetPath.isDirectory()) {
                in = new FileInputStream(toWrite);
                IOUtils.copyLarge(in, out);
                in.close();
            }
            out.flush();
            out.close();
            if (targetPath.isDirectory()) {
                log.info("[createZip] Written folder entry to zip: " + targetPath.getName());
            } else {
                log.info("[createZip] Written file entry to zip: " + targetPath.getName());
            }

        } catch (FileNotFoundException e1) {
            e1.printStackTrace();
        } catch (ZipException e1) {
            e1.printStackTrace();
        } catch (IOException e1) {
            e1.printStackTrace();
        }
        return targetPath;
    }

    private static Date getFileDate(File file) {
        Date date = new Date(file.lastModified());
        return date;
    }

    @SuppressWarnings("unused")
    private static FileEntry testFileEntry(Zip64File zip64File, String targetPath) {
        FileEntry fileEntry = zip64File.getFileEntry(targetPath);
        return fileEntry;
    }

    @SuppressWarnings("unused")
    private static FileEntry testFolderEntry(Zip64File zip64File, String targetPath) {
        FileEntry folderEntry = zip64File.getFileEntry(targetPath + "/");
        return folderEntry;
    }

    //   private static boolean containsEntry(Zip64File zip64File, String targetPath) {
    //      FileEntry result = testFileEntry(zip64File, targetPath);
    //      if(result!=null) {
    //         return true; 
    //      }
    //      else {
    //         result = testFolderEntry(zip64File, targetPath);
    //         if(result!=null) {
    //            return true;
    //         }
    //         else {
    //            return false;
    //         }
    //      }
    //   }

    /**
     * Private method to delete a FileEntry including all nested entries "below" the FileEntry toDelete.
     * @param zip the zip64File to delete the FileEntry toDelete from
     * @param toDelete the FileEntry to delete
     * @return a list with all deleted file entries.
     */
    private static List<FileEntry> deleteFileEntry(Zip64File zip, FileEntry toDelete) {
        List<FileEntry> deletedEntries = deleteEntriesRecursively(zip, toDelete, new ArrayList<FileEntry>());
        return deletedEntries;
    }

    /**
     * Helper method to delete a FileEntry (and all nested entries) recursively.
     * If toDelete is a folder, all nested entries will be deleted.
     * @param zip the zip to delete the entry from
     * @param toDelete the entry to delete
     * @param deletedEntries a list where all deleted entries will be stored.
     * @return the list of deletedEntries
     */
    private static List<FileEntry> deleteEntriesRecursively(Zip64File zip, FileEntry toDelete,
            List<FileEntry> deletedEntries) {
        try {
            if (toDelete.isDirectory()) {
                log.info(
                        "[deleteEntriesRecursively] The FileEntry to delete is a folder. Deleting all nested entries: ");
                List<String> containedFiles = getFileEntryChildren(zip, toDelete);

                if (containedFiles.size() > 0) {
                    for (String currentEntryPath : containedFiles) {
                        FileEntry current = zip.getFileEntry(currentEntryPath);
                        if (current != null) {
                            deleteEntriesRecursively(zip, current, deletedEntries);
                        }
                    }
                    log.info("[deleteEntriesRecursively] Deleted entry: " + toDelete.getName());
                    deletedEntries.add(zip.delete(toDelete.getName()));
                } else {
                    log.info("[deleteEntriesRecursively] Deleted entry: " + toDelete.getName());
                    deletedEntries.add(zip.delete(toDelete.getName()));
                }
            } else {
                FileEntry current = zip.delete(toDelete.getName());
                log.info("[deleteEntriesRecursively] Deleted entry: " + toDelete.getName());
                deletedEntries.add(current);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return deletedEntries;
    }

    /**
     * Checks if a FileEntry named by entryPath is contained in the zip.
     * 
     * @param zip the zip file to search.
     * @param entryPath the FileEntry to find
     * @return the found FileEntry or null, if entryPath is not a valid location.
     */
    private static FileEntry getFileEntry(Zip64File zip64File, String entryPath) {
        FileEntry testEntry = null;
        testEntry = zip64File.getFileEntry(entryPath);
        if (testEntry == null) {
            testEntry = zip64File.getFileEntry(entryPath + "/");
        }
        if (testEntry != null) {
            log.info("[getFileEntry] Found entry: " + testEntry.getName());
        } else {
            log.severe("[getFileEntry] Entry NOT found: " + entryPath);
        }
        return testEntry;
    }

    /**
     * Returns all nested FileEntries for a given folder-FileEntry
     * @param zip the zip file
     * @param folderEntry the folder FileEntry to scan.
     * @return all entries nested in folderEntry.
     */
    private static List<String> getFileEntryChildren(Zip64File zip, FileEntry folderEntry) {
        List<String> list = listZipEntries(zip);
        List<String> resultList = new ArrayList<String>();
        String folderEntryName = folderEntry.getName();
        String testName = folderEntryName.substring(0, folderEntryName.length() - 1);
        for (String currentPath : list) {
            if (currentPath.contains(testName)) {
                if (!currentPath.equalsIgnoreCase(folderEntry.getName())) {
                    log.info("[getFileEntryChildren] Found child: " + currentPath);
                    resultList.add(currentPath);
                }
            }
        }
        return resultList;
    }

    /**
     * Convenience method to get the file name as String from a given FileEntry.
     * This method returns the last part of the FileEntry.getName() String, starting with
     * the last index of "\". 
     * @param entry the FileEntry to get the file name for.
     * @return the file name as String
     */
    //   private static String getEntryFileName(FileEntry entry) {
    //      String entryPath = entry.getName();
    //      String name = null;
    //      if(entryPath.contains(File.separator)) {
    //         name = entryPath.substring(entryPath.lastIndexOf(File.separator)+1);
    //         return name;
    //      }
    //      else {
    //         return entryPath;
    //      }
    //   }

    /**
     * Utility method to list all entries in a zip file as a List<String> 
     * @param zip64File the zip64 file to list the entries 
     * @return all entries in this zip64File
     */
    @SuppressWarnings("unchecked")
    private static List<String> listZipEntries(Zip64File zip64File) {
        List<String> entryList = new ArrayList<String>();

        List<FileEntry> entries = zip64File.getListFileEntries();

        if (entries.size() > 0) {
            for (FileEntry fileEntry : entries) {
                entryList.add(fileEntry.getName());
            }
        }
        return entryList;
    }

    /**
      * @param dir The dir to list
      * @param list The list to add the contents of dir to
      * @return The given list, with the contents of dir added
      */
    private static ArrayList<String> listAllFilesAndFolders(final File dir, final ArrayList<String> list) {
        File[] files = dir.listFiles();
        if (files != null) {
            for (int i = 0; i < files.length; i++) {
                File currentFile = files[i];
                boolean currentFileIsDir = currentFile.isDirectory();
                if (currentFileIsDir) {
                    // Ignore hidden folders
                    if (currentFile.isHidden()) {
                        continue;
                    }
                    if (currentFile.getName().equalsIgnoreCase("CVS")) {
                        continue;
                    }
                    if (currentFile.getName().equalsIgnoreCase(".svn")) {
                        continue;
                    }
                    list.add(currentFile.getPath() + "/");
                    /*
                     * the closing "/" has to be there to tell the
                     * ZipOutputStream that this is a folder...
                     */
                    listAllFilesAndFolders(currentFile, list);
                } else {
                    list.add(currentFile.getPath());
                }
            }
        }
        return list;
    }

    /**
     * Utility method to strip the absoulte part of a files path, starting with the index of folder.getName().
     * 
     * @param folder the folder
     * @return
     */
    private static List<String> normalizePaths(File folder) {
        if (!folder.isDirectory()) {
            return null;
        }

        List<String> resultFileList = listAllFilesAndFolders(folder, new ArrayList<String>());

        if (resultFileList.size() == 0) {
            return null;
        }
        ArrayList<String> normalizedPaths = new ArrayList<String>();
        for (int i = 0; i < resultFileList.size(); i++) {
            String currentPath = resultFileList.get(i);
            // Strip the beginning of the String, except the "[FOLDER-NAME]
            // itself\"....
            int index = currentPath.indexOf(folder.getName());
            currentPath = currentPath.substring(index);
            // Delete the [FOLDER-NAME] part of the paths
            currentPath = currentPath.replace(folder.getName() + File.separator, "");
            // add the normalized path to the list
            normalizedPaths.add(currentPath);
        }
        return normalizedPaths;
    }

    /**
     * @param dir The dir to list
     * @param list The list to add the contents of dir to
     * @return The given list, with the contents of dir added, including files and folders
     */
    static List<File> listAllFilesAndFolders(final File dir, final List<File> list) {
        File[] files = dir.listFiles();
        if (files != null) {
            for (int i = 0; i < files.length; i++) {
                File currentFile = files[i];
                boolean currentFileIsDir = currentFile.isDirectory();
                if (currentFileIsDir) {
                    // Ignore hidden folders
                    if (currentFile.isHidden()) {
                        continue;
                    }
                    if (currentFile.getName().equalsIgnoreCase("CVS")) {
                        continue;
                    }
                    list.add(currentFile);
                    listAllFilesAndFolders(currentFile, list);
                } else {
                    list.add(currentFile);
                }
            }
        }
        return list;
    }

}