summaryrefslogtreecommitdiffstats
path: root/src/main/com/tonicsystems/jarjar/Wildcard.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/com/tonicsystems/jarjar/Wildcard.java')
-rw-r--r--src/main/com/tonicsystems/jarjar/Wildcard.java143
1 files changed, 143 insertions, 0 deletions
diff --git a/src/main/com/tonicsystems/jarjar/Wildcard.java b/src/main/com/tonicsystems/jarjar/Wildcard.java
new file mode 100644
index 0000000..723c6f5
--- /dev/null
+++ b/src/main/com/tonicsystems/jarjar/Wildcard.java
@@ -0,0 +1,143 @@
+/**
+ * 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.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+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 + "}";
+ }
+}