blob: b3ec74e397cbb06d354a664a55a1248648751d63 [file] [log] [blame]
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* 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 org.jetbrains.idea.svn.properties;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.idea.svn.commandLine.SvnBindException;
import java.util.HashMap;
import java.util.Map;
/**
* @author Konstantin Kolosovsky.
*/
public class ExternalsDefinitionParser {
/**
* Parses "svn:externals" property in format starting from svn 1.5.
*
* @return map of externals definitions: key - relative directory, value - corresponding complete externals definition.
*/
@NotNull
public static Map<String, String> parseExternalsProperty(@NotNull String externals) throws SvnBindException {
HashMap<String, String> map = ContainerUtil.newHashMap();
for (String external : StringUtil.splitByLines(externals, true)) {
map.put(parseRelativeDirectory(external), external);
}
return map;
}
/**
* Parses relative directory from externals definition (in format starting from svn 1.5). Restrictions for relative directory:
* - is at the end of externals definition separated from other parameters by ' ' char
* - could be quoted with '"' char
* - certain chars could be escaped with '\' char
*/
@NotNull
public static String parseRelativeDirectory(@NotNull String s) throws SvnBindException {
s = s.trim();
int length = s.length();
String result;
if (isUnescapedQuote(s, length - 1)) {
int index = lastUnescapedIndexOf(s, length - 1, '"');
assertIndex(s, index, "Could not find start quote");
result = s.substring(index + 1, length - 1);
}
else {
int index = lastUnescapedIndexOf(s, length, ' ');
assertIndex(s, index, "Could not find separating space");
result = s.substring(index + 1);
}
return unescape(result);
}
private static void assertIndex(@NotNull String s, int index, @NotNull String message) throws SvnBindException {
if (index < 0) {
throw new SvnBindException(message + " - " + s);
}
}
@NotNull
private static String unescape(@NotNull String s) {
return s.replace("\\", "");
}
/**
* "from" index is excluded.
*/
private static int lastUnescapedIndexOf(@NotNull String s, int from, char c) {
int result = from;
do {
result = s.lastIndexOf(c, result - 1);
}
while (result != -1 && !isUnescaped(s, result, c));
return result;
}
private static boolean isUnescapedQuote(@NotNull String s, int index) {
return isUnescaped(s, index, '"');
}
private static boolean isUnescaped(@NotNull String s, int index, char c) {
return StringUtil.isChar(s, index, c) && !StringUtil.isChar(s, index - 1, '\\');
}
}