in plugin/src/com/microsoft/alm/plugin/versioncontrol/path/ServerPath.java [122:261]
public final static String canonicalize(String serverPath, boolean checkForIllegalDollar) throws ServerPathFormatException {
ArgumentHelper.checkNotNull(serverPath, "serverPath");
int serverPathLength = serverPath.length();
// empty string is not valid
if (serverPathLength == 0) {
logger.warn("Server path is empty");
throw new ServerPathFormatException(serverPath);
}
/*
* Do a quicker check up front to see if the path is OK. If it's not,
* we'll try to fix it up and/or throw the appropriate exception.
*
* This is a huge win, since almost all of the server paths we ever
* encounter in the program (and especially at large scale, like
* translating hundreds of thousands of server paths to local paths) are
* already canonicalized.
*/
if (isCanonicalizedPath(serverPath, true)) {
return serverPath;
}
final List<String> newComponents = new ArrayList<String>();
final StringBuilder currentComponent = new StringBuilder(serverPathLength);
int position = 0;
// A simple conversion for $ to $/
if (serverPath.equals(ServerPath.ROOT_NAME_ONLY)) {
serverPath = ServerPath.ROOT;
serverPathLength = 2;
}
// prepend a $ if necessary (next check will take care of the following /)
if (serverPath.charAt(0) == '$') {
position++;
}
newComponents.add("$");
// the path must begin with one of: /, $/, \, $\
if (position >= serverPathLength || ServerPath.isSeparator(serverPath.charAt(position)) == false) {
logger.warn("The server path is not absolute: " + serverPath);
throw new ServerPathFormatException(serverPath);
}
boolean illegalDollarInPath = false;
// walk the rest of the given path
for (; position <= serverPathLength; position++) {
// end of the string or directory separators, append the current
// component to the list
if (position == serverPathLength || ServerPath.isSeparator(serverPath.charAt(position))) {
// squash multiple concurrent separators
if (currentComponent.length() == 0) {
// Ignore
}
// single dot components are thrown away
else if (currentComponent.toString().equals(".")) {
// Ignore
}
// double dot components mean to pop the last off the stack
else if (currentComponent.toString().equals("..")) {
if (newComponents.size() <= 1) {
logger.warn(String.format("Server path %s refers to invalid path outside %s", serverPath, ROOT));
throw new ServerPathFormatException(serverPath);
}
newComponents.remove(newComponents.size() - 1);
}
// otherwise, pop this bad boy on the directory stack
else {
final String cleaned = ServerPath.cleanupComponent(currentComponent).toString();
/*
* Match Visual Studio behavior of ignoring directories that
* contain nothing but spaces and dots.
*/
if (cleaned.length() == 0) {
// Ignore
} else if (cleaned.length() > MAXIMUM_COMPONENT_LENGTH) {
logger.warn(String.format("Server path component %s is longer than the maximum character length %s", cleaned, MAXIMUM_COMPONENT_LENGTH));
throw new ServerPathFormatException(cleaned);
} else if (FileHelper.isReservedName(cleaned)) {
logger.warn(String.format("Server path %s contains an invalid directory component: %s", serverPath, cleaned));
throw new ServerPathFormatException(cleaned);
} else {
if (cleaned.charAt(0) == '$') {
illegalDollarInPath = true;
}
// Good component, just add.
newComponents.add(cleaned);
}
}
currentComponent.setLength(0);
}
// a non-directory separator, non-dot, but valid in NTFS filenames
else if (ServerPath.isValidPathCharacter(serverPath.charAt(position)) == true) {
currentComponent.append(serverPath.charAt(position));
}
// invalid character
else {
char c = serverPath.charAt(position);
char c_safe = c < ' ' ? '?' : c;
logger.warn(String.format("The character (%s) is not permitted in server paths %s.",
c_safe, serverPath.replace(c, c_safe)));
throw new ServerPathFormatException(serverPath.replace(c, c_safe));
}
}
if (newComponents.size() == 1) {
return ServerPath.ROOT;
}
// join components with a slash
final StringBuilder newPath = new StringBuilder();
for (int i = 0; i < newComponents.size(); i++) {
if (i > 0) {
newPath.append(ServerPath.PREFERRED_SEPARATOR_CHARACTER);
}
newPath.append(newComponents.get(i));
}
/*
* We were checking for illegal dollar in the path during the loop
* through the string. Throw the same exception as checkForIllegalDollar
* would, if the flag was raised stating we had an illegal dollar
* somewhere.
*/
if (illegalDollarInPath && checkForIllegalDollar) {
logger.warn(String.format("TF10122: The path %s contains a $ at the beginning of a path component.", newPath.toString()));
throw new ServerPathFormatException(newPath.toString());
}
return newPath.toString();
}