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