/**
* 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);
}
}
}