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

org.jumpmind.symmetric.fs.util.Utils Maven / Gradle / Ivy

There is a newer version: 3.4.9
Show newest version
/*
 * Licensed to JumpMind Inc under one or more contributor 
 * license agreements.  See the NOTICE file distributed
 * with this work for additional information regarding 
 * copyright ownership.  JumpMind Inc licenses this file
 * to you under the GNU Lesser General Public License (the
 * "License"); you may not use this file except in compliance
 * with the License. 
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, see           
 * .
 * 
 * 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 org.jumpmind.symmetric.fs.util;

import java.io.File;
import java.util.regex.Pattern;

import org.apache.commons.io.FilenameUtils;

final public class Utils {

    private Utils() {
    }
    
    public static String getRelativePath(File target, File base) {
        return getRelativePath(target.getAbsolutePath(), base.getAbsolutePath());        
    }

    public static String getRelativePath(String targetPath, String basePath) {
        return getRelativePath(targetPath, basePath, System.getProperty("file.separator"));
    }

    /**
     * Get the relative path from one file to another, specifying the directory
     * separator. If one of the provided resources does not exist, it is assumed
     * to be a file unless it ends with '/' or '\'.
     * 
     * @param targetPath
     *            targetPath is calculated to this file
     * @param basePath
     *            basePath is calculated from this file
     * @param pathSeparator
     *            directory separator. The platform default is not assumed so
     *            that we can test Unix behaviour when running on Windows (for
     *            example)
     */
    public static String getRelativePath(String targetPath, String basePath, String pathSeparator) {

        // Normalize the paths
        String normalizedTargetPath = FilenameUtils.normalizeNoEndSeparator(targetPath);
        String normalizedBasePath = FilenameUtils.normalizeNoEndSeparator(basePath);

        // Undo the changes to the separators made by normalization
        if (pathSeparator.equals("/")) {
            normalizedTargetPath = FilenameUtils.separatorsToUnix(normalizedTargetPath);
            normalizedBasePath = FilenameUtils.separatorsToUnix(normalizedBasePath);

        } else if (pathSeparator.equals("\\")) {
            normalizedTargetPath = FilenameUtils.separatorsToWindows(normalizedTargetPath);
            normalizedBasePath = FilenameUtils.separatorsToWindows(normalizedBasePath);

        } else {
            throw new IllegalArgumentException("Unrecognised dir separator '" + pathSeparator + "'");
        }

        String[] base = normalizedBasePath.split(Pattern.quote(pathSeparator));
        String[] target = normalizedTargetPath.split(Pattern.quote(pathSeparator));

        // First get all the common elements. Store them as a string,
        // and also count how many of them there are.
        StringBuffer common = new StringBuffer();

        int commonIndex = 0;
        while (commonIndex < target.length && commonIndex < base.length
                && target[commonIndex].equals(base[commonIndex])) {
            common.append(target[commonIndex] + pathSeparator);
            commonIndex++;
        }

        if (commonIndex == 0) {
            // No single common path element. This most
            // likely indicates differing drive letters, like C: and D:.
            // These paths cannot be relativized.
            throw new PathResolutionException("No common path element found for '"
                    + normalizedTargetPath + "' and '" + normalizedBasePath + "'");
        }

        /*
         * The number of directories we have to backtrack depends on whether the
         * base is a file or a dir For example, the relative path from
         * 
         * /foo/bar/baz/gg/ff to /foo/bar/baz
         * 
         * ".." if ff is a file "../.." if ff is a directory
         * 
         * The following is a heuristic to figure out if the base refers to a
         * file or dir. It's not perfect, because the resource referred to by
         * this path may not actually exist, but it's the best I can do
         */
        boolean baseIsFile = true;

        File baseResource = new File(normalizedBasePath);

        if (baseResource.exists()) {
            baseIsFile = baseResource.isFile();

        } else if (basePath.endsWith(pathSeparator)) {
            baseIsFile = false;
        }

        StringBuffer relative = new StringBuffer();

        if (base.length != commonIndex) {
            int numDirsUp = baseIsFile ? base.length - commonIndex - 1 : base.length - commonIndex;

            for (int i = 0; i < numDirsUp; i++) {
                relative.append(".." + pathSeparator);
            }
        }
        relative.append(normalizedTargetPath.substring(common.length()));
        return relative.toString();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy