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

com.artnaseef.minecraft.localmaptool.zip.impl.ZipUtilImpl Maven / Gradle / Ivy

Go to download

Tool for locating and managing local minecraft maps for multiple environments (Windows, Mac, Linux, etc).

The newest version!
/*
 * Copyright 2019 Arthur Naseef
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.artnaseef.minecraft.localmaptool.zip.impl;

import com.artnaseef.minecraft.localmaptool.zip.ZipParameters;
import com.artnaseef.minecraft.localmaptool.zip.ZipUtil;

import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

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.Collections;
import java.util.List;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import java.util.stream.Stream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;

/**
 * Created by art on 7/1/19.
 */
public class ZipUtilImpl implements ZipUtil {

    private static final Logger DEFAULT_LOGGER = LoggerFactory.getLogger(ZipUtilImpl.class);

    private Logger log = DEFAULT_LOGGER;

//========================================
// Getter and Setter
//----------------------------------------

    public Logger getLog() {
        return log;
    }

    public void setLog(Logger log) {
        this.log = log;
    }

//========================================
// Processing Interface
//----------------------------------------

    public void extractZip(File zipFile, File destination, ZipParameters zipParameters) throws IOException {
        ZipFile inputZipFile = new ZipFile(zipFile);

        Stream inputStream = inputZipFile.stream();

        Predicate inclusionPredicate = zipParameters.getIncludeEntryPredicate();
        if (inclusionPredicate != null) {
            inputStream = inputStream.filter(inclusionPredicate);
        }

        try {
        inputStream.forEach((entry) -> this.UnzipEntry(inputZipFile, destination, entry, zipParameters));
        } catch (InternalException intExc) {
            if (intExc.getCause() instanceof IOException) {
                throw (IOException) intExc.getCause();
            }

            throw new IOException(intExc.getMessage(), intExc.getCause());
        }
    }

    @Override
    public void createZip(File zipFile, File source) throws IOException {
        try (OutputStream outputStream = new FileOutputStream(zipFile)) {
            try (ZipOutputStream zipOutputStream = new ZipOutputStream(outputStream)) {
                this.addToZip(zipOutputStream, source, source);
            }
        }
    }

    @Override
    public List readZipEntryList(File zipFile) throws IOException {
        ZipFile reader = new ZipFile(zipFile);
        List result = Collections.list(reader.entries());
        reader.close();

        return result;
    }

//========================================
// Internals
//----------------------------------------

    private void UnzipEntry(ZipFile inputZipFile, File destination, ZipEntry entry, ZipParameters zipParameters) {
        File finalLocation = this.resolveEntryLocation(destination, entry, zipParameters);

        this.log.debug("unzip entry: entry-name={}; destination={}; final-location={}", entry.getName(), destination,
                       finalLocation);

        if (finalLocation != null) {
            //entry.getLastAccessTime();
            //entry.getLastModifiedTime();

            if (entry.isDirectory()) {
                if (! finalLocation.exists()) {
                    boolean created = finalLocation.mkdirs();
                    if (!created) {
                        throw new InternalException("failed to create directory " + finalLocation);
                    }
                }
            } else {
                this.checkParentDirectory(finalLocation);

                try (InputStream entryInputStream = inputZipFile.getInputStream(entry)) {
                    try (OutputStream outputStream = new FileOutputStream(finalLocation)) {
                        IOUtils.copy(entryInputStream, outputStream);

                        boolean updated = finalLocation.setLastModified(entry.getLastModifiedTime().toMillis());
                        if (!updated) {
                            this.log.warn("failed to update last modified time on : entry-name={}; location={}",
                                          entry.getName(), finalLocation);
                        }
                    }
                } catch (IOException ioExc) {
                    throw new InternalException(ioExc);
                }
            }
        }
    }

    private void addToZip(ZipOutputStream zipOutputStream, File zipSourceRoot, File fileToZip)
        throws IOException {

        String pathInZip =
            fileToZip
                .getPath()
                .replaceFirst(Pattern.quote(zipSourceRoot.getPath()), "")
            ;

        // Remove leading slashes (yes, this could be done more efficiently - please feel free to provide a patch)
        while (pathInZip.startsWith("/") || pathInZip.startsWith("\\")) {
            pathInZip = pathInZip.substring(1);
        }

        this.log.debug("ZIP file naming: root={}; file-to-zip={}; path-in-zip={}", zipSourceRoot, fileToZip, pathInZip);

        if (fileToZip.isDirectory()) {
            // Don't add the source root directory to the zip
            if (!fileToZip.equals(zipSourceRoot)) {
                // The trailing slash makes this a directory entry, by definition
                ZipEntry dirEntry = new ZipEntry(pathInZip + "/");
                zipOutputStream.putNextEntry(dirEntry);
                zipOutputStream.closeEntry();
            }

            // Recursively add the directory contents
            File[] contents = fileToZip.listFiles();
            if (contents != null) {
                for (File oneDirContent : contents) {
                    this.addToZip(zipOutputStream, zipSourceRoot, oneDirContent);
                }
            }
        } else {
            ZipEntry fileEntry = new ZipEntry(pathInZip);
            zipOutputStream.putNextEntry(fileEntry);
            try (InputStream inputStream = new FileInputStream(fileToZip)) {
                IOUtils.copy(inputStream, zipOutputStream);
            }
            zipOutputStream.closeEntry();
        }
    }

    private void checkParentDirectory(File file) {
        File parent = file.getParentFile();
        if (parent != null) {
            if (!parent.exists()) {
                boolean created = parent.mkdirs();
                if (! created) {
                    throw new InternalException("failed to create directory " + parent);
                }
            }
        }
    }

    private File resolveEntryLocation(File destination, ZipEntry entry, ZipParameters zipParameters) {
        File entryLocation = new File(entry.getName());
        Function mapDestinationFunction = zipParameters.getMapDestinationFunction();

        File mappedLocation = entryLocation;
        if (mapDestinationFunction != null) {
            mappedLocation = mapDestinationFunction.apply(entryLocation);
            if (mappedLocation == null) {
                this.log.debug("ignoring entry {}; map destination function returned null", entryLocation);
                return null;
            }
        }

        File finalLocation = new File(destination, mappedLocation.getPath());
        return finalLocation;
    }

//========================================
// Internal Classes
//----------------------------------------

    private static final class InternalException extends RuntimeException {
        public InternalException(String message) {
            super(message);
        }

        public InternalException(Throwable cause) {
            super(cause);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy