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

com.aspectran.utils.PathUtils Maven / Gradle / Ivy

There is a newer version: 8.1.3
Show newest version
/*
 * Copyright (c) 2008-2024 The Aspectran Project
 *
 * 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.aspectran.utils;

import java.util.ArrayDeque;
import java.util.Deque;

public abstract class PathUtils {

    public static final String REGULAR_FILE_SEPARATOR = "/";

    public static final char REGULAR_FILE_SEPARATOR_CHAR = '/';

    public static final String WINDOWS_FILE_SEPARATOR = "\\";

    private static final String TOP_PATH = "..";

    private static final String CURRENT_PATH = ".";

    /**
     * Apply the given relative path to the given Java resource path,
     * assuming standard Java folder separation (i.e. "/" separators).
     * @param path         the path to start from (usually a full file path)
     * @param relativePath the relative path to apply
     *                     (relative to the full file path above)
     * @return the full file path that results from applying the relative path
     */
    public static String applyRelativePath(String path, String relativePath) {
        Assert.notNull(path, "path must not be null");
        Assert.notNull(relativePath, "relativePath must not be null");
        int separatorIndex = path.lastIndexOf(REGULAR_FILE_SEPARATOR_CHAR);
        if (separatorIndex != -1) {
            String newPath = path.substring(0, separatorIndex);
            if (!relativePath.startsWith(REGULAR_FILE_SEPARATOR)) {
                newPath += REGULAR_FILE_SEPARATOR_CHAR;
            }
            return newPath + relativePath;
        } else {
            return relativePath;
        }
    }

    /**
     * Normalize the path by suppressing sequences like "path/.." and
     * inner simple dots.
     * 

The result is convenient for path comparison. For other uses, * notice that Windows separators ("\") are replaced by simple slashes. *

NOTE that {@code cleanPath} should not be depended * upon in a security context. Other mechanisms should be used to prevent * path-traversal issues. * @param path the original path * @return the normalized path */ public static String cleanPath(String path) { if (!StringUtils.hasLength(path)) { return path; } String normalizedPath = StringUtils.replace(path, WINDOWS_FILE_SEPARATOR, REGULAR_FILE_SEPARATOR); String pathToUse = normalizedPath; // Shortcut if there is no work to do if (pathToUse.indexOf('.') == -1) { return pathToUse; } // Strip prefix from path to analyze, to not treat it as part of the // first path element. This is necessary to correctly parse paths like // "file:core/../core/io/Resource.class", where the ".." should just // strip the first "core" directory while keeping the "file:" prefix. int prefixIndex = pathToUse.indexOf(':'); String prefix = ""; if (prefixIndex != -1) { prefix = pathToUse.substring(0, prefixIndex + 1); if (prefix.contains(REGULAR_FILE_SEPARATOR)) { prefix = ""; } else { pathToUse = pathToUse.substring(prefixIndex + 1); } } if (pathToUse.startsWith(REGULAR_FILE_SEPARATOR)) { prefix = prefix + REGULAR_FILE_SEPARATOR; pathToUse = pathToUse.substring(1); } String[] pathArray = StringUtils.split(pathToUse, REGULAR_FILE_SEPARATOR); // we never require more elements than pathArray and in the common case the same number Deque pathElements = new ArrayDeque<>(pathArray.length); int tops = 0; for (int i = pathArray.length - 1; i >= 0; i--) { String element = pathArray[i]; if (CURRENT_PATH.equals(element)) { // Points to current directory - drop it. } else if (TOP_PATH.equals(element)) { // Registering top path found. tops++; } else { if (tops > 0) { // Merging path element with element corresponding to top path. tops--; } else { // Normal path element found. pathElements.addFirst(element); } } } // All path elements stayed the same - shortcut if (pathArray.length == pathElements.size()) { return normalizedPath; } // Remaining top paths need to be retained. for (int i = 0; i < tops; i++) { pathElements.addFirst(TOP_PATH); } // If nothing else left, at least explicitly point to current path. if (pathElements.size() == 1 && pathElements.getLast().isEmpty() && !prefix.endsWith(REGULAR_FILE_SEPARATOR)) { pathElements.addFirst(CURRENT_PATH); } final String joined = StringUtils.toDelimitedString(pathElements, REGULAR_FILE_SEPARATOR); // avoid string concatenation with empty prefix return prefix.isEmpty() ? joined : prefix + joined; } /** * Compare two paths after normalization of them. * @param path1 first path for comparison * @param path2 second path for comparison * @return whether the two paths are equivalent after normalization */ public static boolean pathEquals(String path1, String path2) { return cleanPath(path1).equals(cleanPath(path2)); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy