diff options
Diffstat (limited to 'third_party/jarjar/java/com/tonicsystems/jarjar/Wildcard.java')
-rw-r--r-- | third_party/jarjar/java/com/tonicsystems/jarjar/Wildcard.java | 160 |
1 files changed, 160 insertions, 0 deletions
diff --git a/third_party/jarjar/java/com/tonicsystems/jarjar/Wildcard.java b/third_party/jarjar/java/com/tonicsystems/jarjar/Wildcard.java new file mode 100644 index 0000000000..8deb3518d0 --- /dev/null +++ b/third_party/jarjar/java/com/tonicsystems/jarjar/Wildcard.java @@ -0,0 +1,160 @@ +/* + * Copyright 2007 Google Inc. + * + * 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 com.tonicsystems.jarjar; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +class Wildcard { + private static Pattern dstar = Pattern.compile("\\*\\*"); + private static Pattern star = Pattern.compile("\\*"); + private static Pattern estar = Pattern.compile("\\+\\??\\)\\Z"); + + private final Pattern pattern; + private final int count; + private final ArrayList<Object> parts = new ArrayList<Object>(16); // kept for debugging + private final String[] strings; + private final int[] refs; + + public Wildcard(String pattern, String result) { + if (pattern.equals("**")) { + throw new IllegalArgumentException("'**' is not a valid pattern"); + } + if (!checkIdentifierChars(pattern, "/*-")) { + throw new IllegalArgumentException("Not a valid package pattern: " + pattern); + } + if (pattern.indexOf("***") >= 0) { + throw new IllegalArgumentException("The sequence '***' is invalid in a package pattern"); + } + + String regex = pattern; + regex = replaceAllLiteral(dstar, regex, "(.+?)"); + regex = replaceAllLiteral(star, regex, "([^/]+)"); + regex = replaceAllLiteral(estar, regex, "*)"); + this.pattern = Pattern.compile("\\A" + regex + "\\Z"); + this.count = this.pattern.matcher("foo").groupCount(); + + // TODO: check for illegal characters + char[] chars = result.toCharArray(); + int max = 0; + for (int i = 0, mark = 0, state = 0, len = chars.length; i < len + 1; i++) { + char ch = (i == len) ? '@' : chars[i]; + if (state == 0) { + if (ch == '@') { + parts.add(new String(chars, mark, i - mark)); + mark = i + 1; + state = 1; + } + } else { + switch (ch) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + break; + default: + if (i == mark) { + throw new IllegalArgumentException("Backslash not followed by a digit"); + } + int n = Integer.parseInt(new String(chars, mark, i - mark)); + if (n > max) { + max = n; + } + parts.add(new Integer(n)); + mark = i--; + state = 0; + } + } + } + int size = parts.size(); + strings = new String[size]; + refs = new int[size]; + Arrays.fill(refs, -1); + for (int i = 0; i < size; i++) { + Object v = parts.get(i); + if (v instanceof String) { + strings[i] = ((String) v).replace('.', '/'); + } else { + refs[i] = ((Integer) v).intValue(); + } + } + if (count < max) { + throw new IllegalArgumentException( + "Result includes impossible placeholder \"@" + max + "\": " + result); + } + // System.err.println(this); + } + + public boolean matches(String value) { + return getMatcher(value) != null; + } + + public String replace(String value) { + Matcher matcher = getMatcher(value); + if (matcher != null) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < strings.length; i++) + sb.append((refs[i] >= 0) ? matcher.group(refs[i]) : strings[i]); + return sb.toString(); + } + return null; + } + + private Matcher getMatcher(String value) { + Matcher matcher = pattern.matcher(value); + if (matcher.matches() && checkIdentifierChars(value, "/-")) { + return matcher; + } + return null; + } + + private static boolean checkIdentifierChars(String expr, String extra) { + // package-info violates the spec for Java Identifiers. + // Nevertheless, expressions that end with this string are still legal. + // See 7.4.1.1 of the Java language spec for discussion. + if (expr.endsWith("package-info")) { + expr = expr.substring(0, expr.length() - "package-info".length()); + } + for (int i = 0, len = expr.length(); i < len; i++) { + char c = expr.charAt(i); + if (extra.indexOf(c) >= 0) { + continue; + } + if (!Character.isJavaIdentifierPart(c)) { + return false; + } + } + return true; + } + + private static String replaceAllLiteral(Pattern pattern, String value, String replace) { + replace = replace.replaceAll("([$\\\\])", "\\\\$0"); + return pattern.matcher(value).replaceAll(replace); + } + + public String toString() { + return "Wildcard{pattern=" + pattern + ",parts=" + parts + "}"; + } +} |