/** * Copyright (C) 2009 STMicroelectronics * * This file is part of "Mind Compiler" is free software: you can redistribute * it and/or modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * Contact: mind@ow2.org * * Authors: Matthieu Leclercq * Contributors: */ package org.ow2.mind; import static org.ow2.mind.NameHelper.getPackageName; import static org.ow2.mind.NameHelper.toValidName; import java.util.regex.Pattern; /** * Utility class that provides methods to manipulate path-like strings. */ public final class PathHelper { private PathHelper() { } /** The regular expression of a path. */ public static final String PATH_REGEXP = "((\\./)?(\\.\\./)*|/)\\w+(/\\w+)*(\\.\\w+)?"; private static final Pattern PATH_PATTERN = Pattern.compile(PATH_REGEXP); /** * Checks if the given string matches the {@link #PATH_REGEXP} regular * expression. * * @param path the string to check * @return <code>true</code> if and only if the given string matches the * {@link #PATH_REGEXP} regular expression. */ public static boolean isValid(final String path) { return PATH_PATTERN.matcher(path).matches(); } /** * Returns <code>true</code> if the given path is a relative path (i.e. do not * starts with <code>"/"</code>) * * @param path a valid path (see {@link #isValid(String)}). * @return <code>true</code> if the given path is a relative path (i.e. do not * starts with <code>"/"</code>) */ public static boolean isRelative(final String path) { return !path.startsWith("/"); } public static String getParent(final String path) { final int i = path.lastIndexOf('/'); if (i == -1) return ""; if (i == 0) return "/"; return path.substring(0, i); } public static String getFileName(final String path) { final int i = path.lastIndexOf('/'); if (i == -1) return path; return path.substring(i + 1); } /** * Returns the extension of the file denoted by the given path. * * @param path a valid path (see {@link #isValid(String)}). * @return the extension of the file denoted by the given path (without the * <code>'.'<code>) or <code>null</code> if the given path do not have * an extension. */ public static String getExtension(final String path) { final int i = path.lastIndexOf('.'); final int j = path.lastIndexOf('/'); if (i == -1 || j > i) return null; return path.substring(i + 1); } /** * Returns the given path without its file extension. * * @param path a valid path (see {@link #isValid(String)}). * @return the given path without its file extension. */ public static String removeExtension(final String path) { final int i = path.lastIndexOf('.'); final int j = path.lastIndexOf('/'); if (i == -1 || j > i) return path; return path.substring(0, i); } /** * Replaces the file extension of the given path by the given extension * * @param path a valid path (see {@link #isValid(String)}). * @param extension the extension to set. If <code>extension</code> does not * starts with ".", it is automatically added. * @return the given path in which the file extension has been replaced by the * given one. */ public static String replaceExtension(final String path, String extension) { if (!extension.startsWith(".")) extension = "." + extension; return removeExtension(path) + extension; } /** * Returns the absolute path that is denoted by the given <code>path</code> * relatively to the given <code>dirName</code>. If the given path is not a * relative path (see {@link #isRelative(String)}), this method returns the * given <code>path</code>. * * @param dirName the directory that is the starting point of the given * <code>path</code>. * @param path a valid path (see {@link #isValid(String)}). * @return the absolute path that is denoted by the given * <code>path<code> relatively to the given <code>dirName</code>. * @throws InvalidRelativPathException if the given path does not designate a * file inside the source tree. For instance if <code>dirName</code> * is <code>"foo/"</code> and <code>path</code> is * <code>"../../bar"</code>. */ public static String toAbsolute(String dirName, String path) throws InvalidRelativPathException { if (!isRelative(path)) return path; // remove '/' at the end of dirName if any if (dirName.endsWith("/")) dirName = dirName.substring(0, dirName.length() - 1); if (!path.startsWith("../")) { if (path.startsWith("./")) path = path.substring(2); if (!path.startsWith("../")) { // path is a relative path that do not starts by "./" or "../" return dirName + "/" + path; } } assert path.startsWith("../"); final int lastSlash = dirName.lastIndexOf('/'); if (lastSlash <= 0) { if (path.startsWith("../../") || dirName.length() == 0) { throw new InvalidRelativPathException("Invalid relative path \"" + path + "\" for directory \"" + dirName + "\"."); } return (dirName.startsWith("/")) ? "/" + path.substring(3) : path .substring(3); } return toAbsolute(dirName.substring(0, lastSlash), "./" + path.substring(3)); } /** * Returns the directory name that correspond to the package name of the given * fully qualified name. * * @param fullyQualifiedName a fully qualified name * @return the directory name that correspond to the package name of the given * fully qualified name. */ public static String fullyQualifiedNameToDirName( final String fullyQualifiedName) { final String packageName = getPackageName(toValidName(fullyQualifiedName)); if (packageName == null) return "/"; return packageNameToDirName(packageName); } /** * Returns the directory name that correspond to the given package name * * @param packageName a package name * @return the directory name that correspond to the given package name */ public static String packageNameToDirName(final String packageName) { return "/" + packageName.replace('.', '/'); } /** * Returns the absolute path that is denoted by the given <code>path</code> * relatively to the directory that correspond to the package name of the * given fully-qualified name. If the given path is not a relative path (see * {@link #isRelative(String)}), this method returns the given * <code>path</code>. * * @param fullyQualifiedName a fully qualified name * @param path a valid path (see {@link #isValid(String)}). * @return the absolute path that is denoted by the given <code>path</code> * relatively to the directory that correspond to the package name of * the given fully-qualified name. * @throws InvalidRelativPathException if the given path does not designate a * file inside the source tree. For instance if * <code>fullyQualifiedName</code> is <code>"foo.bar"</code> and * <code>path</code> is <code>"../../bar"</code>. * @see #fullyQualifiedNameToDirName(String) * @see #toAbsolute(String, String) */ public static String fullyQualifiedNameToAbsolute( final String fullyQualifiedName, final String path) throws InvalidRelativPathException { return toAbsolute(fullyQualifiedNameToDirName(fullyQualifiedName), path); } /** * Returns the absolute path that is denoted by the given <code>path</code> * relatively to the directory that correspond to the given package name. If * the given path is not a relative path (see {@link #isRelative(String)}), * this method returns the given <code>path</code>. * * @param packageName a package name * @param path a valid path (see {@link #isValid(String)}). * @return the absolute path that is denoted by the given <code>path</code> * relatively to the directory that correspond to the given package * name. * @throws InvalidRelativPathException if the given path does not designate a * file inside the source tree. For instance if * <code>packageName</code> is <code>"foo"</code> and * <code>path</code> is <code>"../../bar"</code>. * @see #packageNameToDirName(String) * @see #toAbsolute(String, String) */ public static String packageNameToAbsolute(final String packageName, final String path) throws InvalidRelativPathException { return toAbsolute(packageNameToDirName(packageName), path); } /** * Returns the absolute path corresponding to the given fully qualified name. * * @param fullyQualifiedName a fully qualified name * @param extension the file extension to add at the end of the returned path. * May be <code>null</code> * @return the absolute path corresponding to the given fully qualified name. */ public static String fullyQualifiedNameToPath( final String fullyQualifiedName, final String extension) { return fullyQualifiedNameToPath(fullyQualifiedName, null, extension); } /** * Returns the absolute path corresponding to the given fully qualified name * followed by the given suffix. * * @param fullyQualifiedName a fully qualified name * @param suffix a suffix to add to the fully qualified name.May be * <code>null</code> * @param extension the file extension to add at the end of the returned path. * May be <code>null</code> * @return the absolute path corresponding to the given fully qualified name. */ public static String fullyQualifiedNameToPath( final String fullyQualifiedName, final String suffix, final String extension) { String path = "/" + toValidName(fullyQualifiedName).replace('.', '/'); if (suffix != null) { path += suffix; } if (extension != null) { if (!extension.startsWith(".")) path += "."; path += extension; } return path; } /** * Exception thrown by {@link PathHelper#toAbsolute(String, String)}. */ public static class InvalidRelativPathException extends Exception { /** * @see Exception#Exception(String) */ public InvalidRelativPathException(final String message) { super(message); } } }