com.izforge.izpack.util.IoHelper.java Source code

Java tutorial

Introduction

Here is the source code for com.izforge.izpack.util.IoHelper.java

Source

/*
 * Copyright 2016 Julien Ponge, Ren Krell and the IzPack team.
 *
 * 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.izforge.izpack.util;

import com.izforge.izpack.api.data.Variables;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.zip.ZipEntry;

/**
 * I/O-related utility methods.
 */
public class IoHelper {
    // This class uses the same values for family and flavor as
    // TargetFactory. But this class should not depends on TargetFactory,
    // because it is possible that TargetFactory is not bound. Therefore
    // the definition here again.

    /**
     * Placeholder during translatePath computing
     */
    private static final String MASKED_SLASH_PLACEHOLDER = "~&_&~";

    private static Properties envVars = null;

    /**
     * Creates a temp file with delete on exit rule. The extension is extracted from the template if
     * possible, else the default extension is used. The contents of template will be copied into
     * the temporary file.
     *
     * @param template         file path to copy from and define file extension
     * @param defaultExtension file extension if no is contained in template
     * @return newly created and filled temporary file
     * @throws IOException if an I/O error occurred
     */
    public static File copyToTempFile(String template, String defaultExtension) throws IOException {
        return copyToTempFile(new File(template), defaultExtension);
    }

    /**
     * Creates a temp file with delete on exit rule. The extension is extracted from the template if
     * possible, else the default extension is used. The contents of template will be copied into
     * the temporary file.
     *
     * @param templateFile         file to copy from and define file extension
     * @param defaultExtension file extension if no is contained in template
     * @return newly created and filled temporary file
     * @throws IOException if an I/O error occurred
     */
    public static File copyToTempFile(File templateFile, String defaultExtension) throws IOException {
        String path = templateFile.getCanonicalPath();
        int pos = path.lastIndexOf('.');
        String ext = path.substring(pos);
        if (ext.isEmpty()) {
            ext = defaultExtension;
        }
        File tmpFile = File.createTempFile("izpack_io", ext);
        tmpFile.deleteOnExit();
        FileUtils.copyFile(templateFile, tmpFile);
        return tmpFile;
    }

    /**
     * Returns the free (disk) space for the given path. If it is not ascertainable -1 returns.
     *
     * @param path path for which the free space should be detected
     * @return the free space for the given path
     */
    public static long getFreeSpace(String path) {
        long ret = -1;
        if (OsVersion.IS_WINDOWS) {
            String command = "cmd.exe";
            if (System.getProperty("os.name").toLowerCase().contains("windows 9")) {
                return (-1);
            }
            String[] params = { command, "/C", "\"dir /D /-C \"" + path + "\"\"" };
            String[] output = new String[2];
            FileExecutor fe = new FileExecutor();
            fe.executeCommand(params, output);
            ret = extractLong(output[0], -3);
        } else if (OsVersion.IS_SUNOS) {
            String[] params = { "df", "-k", path };
            String[] output = new String[2];
            FileExecutor fe = new FileExecutor();
            fe.executeCommand(params, output);
            ret = extractLong(output[0], -3) * 1024;
        } else if (OsVersion.IS_HPUX) {
            String[] params = { "bdf", path };
            String[] output = new String[2];
            FileExecutor fe = new FileExecutor();
            fe.executeCommand(params, output);
            ret = extractLong(output[0], -3) * 1024;
        } else if (OsVersion.IS_UNIX) {
            String[] params = { "df", "-Pk", path };
            String[] output = new String[2];
            FileExecutor fe = new FileExecutor();
            fe.executeCommand(params, output);
            ret = extractLong(output[0], -3) * 1024;
        }
        return ret;
    }

    /**
     * Returns whether the given method will be supported with the given environment. Some methods
     * of this class are not supported on all operation systems.
     *
     * @param method name of the method
     * @return true if the method will be supported with the current environment else false
     * @throws RuntimeException if the given method name does not exist
     */
    public static boolean supported(String method) {
        if ("getFreeSpace".equals(method)) {
            if (OsVersion.IS_UNIX) {
                return true;
            }
            if (OsVersion.IS_WINDOWS) { // getFreeSpace do not work on Windows 98.
                return !System.getProperty("os.name").toLowerCase().contains("windows 9");
            }
        } else if ("chmod".equals(method)) {
            if (OsVersion.IS_UNIX) {
                return true;
            }
        } else if ("copyFile".equals(method)) {
            return true;
        } else if ("getPrimaryGroup".equals(method)) {
            if (OsVersion.IS_UNIX) {
                return true;
            }
        } else if ("getenv".equals(method)) {
            return true;
        } else {
            throw new RuntimeException("method name " + method + "not supported by this method");
        }
        return false;

    }

    /**
     * Returns the first existing parent directory in a path
     *
     * @param path path which should be scanned
     * @return the first existing parent directory in a path
     */
    public static File existingParent(File path) {
        File result = path;
        while (!result.exists()) {
            if (result.getParent() == null) {
                return result;
            }
            result = result.getParentFile();
        }
        return result;
    }

    /**
     * Extracts a long value from a string in a special manner. The string will be broken into
     * tokens with a standard StringTokenizer. Around the assumed place (with the given half range)
     * the tokens are scanned reverse for a token which represents a long. if useNotIdentifier is not
     * null, tokens which are contains this string will be ignored. The first founded long returns.
     *
     * @param in               the string which should be parsed
     * @param assumedPlace     token number which should contain the value
     * @return founded long
     */
    private static long extractLong(String in, int assumedPlace) {
        long ret = -1;
        StringTokenizer st = new StringTokenizer(in);
        int length = st.countTokens();
        int i;
        int currentRange = 0;
        String[] interestedEntries = new String[3 + 3];
        for (i = 0; i < length - 3 + assumedPlace; ++i) {
            st.nextToken(); // Forget this entries.
        }

        for (i = 0; i < 3 + 3; ++i) { // Put the interesting Strings into an intermediate array.
            if (st.hasMoreTokens()) {
                interestedEntries[i] = st.nextToken();
                currentRange++;
            }
        }

        for (i = currentRange - 1; i >= 0; --i) {
            if (interestedEntries[i].contains("%")) {
                continue;
            }
            try {
                ret = Long.parseLong(interestedEntries[i]);
            } catch (NumberFormatException nfe) {
                continue;
            }
            break;
        }
        return ret;
    }

    /**
     * Returns a string resulting from replacing all occurrences of what in this string with with.
     * In opposite to the String.replaceAll method this method do not use regular expression or
     * other methods which are only available in JRE 1.4 and later. This method was special made to
     * mask masked slashes to avert a conversion during path translation.
     *
     * @param destination string for which the replacing should be performed
     * @param what        what string should be replaced
     * @param with        with what string what should be replaced
     * @return a new String object if what was found in the given string, else the given string self
     */
    private static String replaceString(String destination, String what, String with) {
        if (destination.contains(what)) { // what found, with (placeholder) not included in destination ->
                                          // perform changing.
            StringBuilder buf = new StringBuilder();
            int last = 0;
            int current = destination.indexOf(what);
            int whatLength = what.length();
            while (current >= 0) { // Do not use Methods from JRE 1.4 and higher ...
                if (current > 0) {
                    buf.append(destination.substring(last, current));
                }
                buf.append(with);
                last = current + whatLength;
                current = destination.indexOf(what, last);
            }
            if (destination.length() > last) {
                buf.append(destination.substring(last));
            }
            return buf.toString();
        }
        return destination;
    }

    /**
     * Translates a relative path to a local system path.
     *
     * @param destination the path to translate
     * @param variables   used to replaces variables in the path
     * @return the translated path
     */
    public static String translatePath(String destination, Variables variables) {
        destination = variables.replace(destination);
        return translatePath(destination);
    }

    /**
     * Translates a path.
     *
     * @param destination the path to translate
     * @return the translated path
     */
    public static String translatePath(String destination) {
        // Convert the file separator characters

        // destination = destination.replace('/', File.separatorChar);
        // Undo the conversion if the slashes was masked with
        // a backslash

        // Not all occurrences of slashes are path separators. To differ
        // between it we allow to mask a slash with a leading backslash.
        // Unfortunately we cannot use String.replaceAll because it
        // handles backslashes in the replacement string in a special way
        // and the method exist only beginning with JRE 1.4.
        // Therefore the little bit crude way following ...
        if (destination.contains("\\/") && !destination.contains(MASKED_SLASH_PLACEHOLDER)) { // Masked slash found, placeholder not included in destination ->
                                                                                              // perform masking.
            destination = replaceString(destination, "\\/", MASKED_SLASH_PLACEHOLDER);
            // Masked slashes changed to MASKED_SLASH_PLACEHOLDER.
            // Replace unmasked slashes.
            destination = destination.replace('/', File.separatorChar);
            // Replace the MASKED_SLASH_PLACEHOLDER to slashes; masking
            // backslashes will
            // be removed.
            destination = replaceString(destination, MASKED_SLASH_PLACEHOLDER, "/");
        } else {
            destination = destination.replace('/', File.separatorChar);
        }
        return destination;
    }

    /**
     * Returns the value of the environment variable given by key. This method is a work around for
     * VM versions which do not support getenv in an other way. At the first call all environment
     * variables will be loaded via an exec. On Windows keys are not case sensitive.
     *
     * @param key variable name for which the value should be resolved
     * @return the value of the environment variable given by key
     */
    public static String getenv(String key) {
        if (envVars == null) {
            loadEnv();
        }
        if (envVars == null) {
            return (null);
        }
        if (OsVersion.IS_WINDOWS) {
            key = key.toUpperCase();
        }
        return (String) (envVars.get(key));
    }

    /**
     * Loads all environment variables via an exec.
     */
    private static void loadEnv() {
        String[] output = new String[2];
        String[] params;
        if (OsVersion.IS_WINDOWS) {
            String command = "cmd.exe";
            if (System.getProperty("os.name").toLowerCase().contains("windows 9")) {
                command = "command.com";
            }
            params = new String[] { command, "/C", "set" };
        } else {
            params = new String[] { "env" };
        }
        FileExecutor fe = new FileExecutor();
        fe.executeCommand(params, output);
        if (output[0].length() <= 0) {
            return;
        }
        String lineSep = System.getProperty("line.separator");
        StringTokenizer tokenizer = new StringTokenizer(output[0], lineSep);
        envVars = new Properties();
        String var = null;
        while (tokenizer.hasMoreTokens()) {
            String line = tokenizer.nextToken();
            if (line.indexOf('=') == -1) { // May be a env var with a new line in it.
                if (var == null) {
                    var = lineSep + line;
                } else {
                    var += lineSep + line;
                }
            } else { // New var, perform the previous one.
                setEnvVar(var);
                var = line;
            }
        }
        setEnvVar(var);
    }

    /**
     * Extracts key and value from the given string var. The key should be separated from the value
     * by a sign. On Windows all chars of the key are translated to upper case.
     *
     * @param var expression for setting the environment variable
     */
    private static void setEnvVar(String var) {
        if (var == null) {
            return;
        }
        int index = var.indexOf('=');
        if (index < 0) {
            return;
        }
        String key = var.substring(0, index);
        // On windows change all key chars to upper.
        if (OsVersion.IS_WINDOWS) {
            key = key.toUpperCase();
        }
        envVars.setProperty(key, var.substring(index + 1));

    }

    public static void copyStreamToJar(InputStream zin, java.util.zip.ZipOutputStream out, String currentName,
            long fileTime) throws IOException {
        // Create new entry for zip file.
        ZipEntry newEntry = new ZipEntry(currentName);
        // Make sure there is date and time set.
        if (fileTime != -1) {
            newEntry.setTime(fileTime); // If found set it into output file.
        }
        out.putNextEntry(newEntry);
        if (zin != null) {
            IOUtils.copy(zin, out);
        }
        out.closeEntry();
    }
}