1 20 21 package com.tonicsystems.jarjar; 22 23 import com.tonicsystems.jarjar.regex.*; 24 import java.util.ArrayList ; 25 import java.util.Arrays ; 26 27 class Wildcard 28 { 29 private static RegexEngine REGEX = MyRegexEngine.getInstance(); 30 31 public static final int STYLE_DESC = 0; 32 public static final int STYLE_IDENTIFIER = 1; 33 34 private static Pattern dots = REGEX.compile("\\."); 35 private static Pattern tilde = REGEX.compile("~"); 36 private static Pattern dstar = REGEX.compile("\\*\\*"); 37 private static Pattern star = REGEX.compile("\\*"); 38 39 private Pattern descPattern; 40 private Pattern identifierPattern; 41 private int count; 42 43 private ArrayList parts = new ArrayList (16); private String [] strings; 45 private int[] refs; 46 47 public Wildcard(String pattern, String result) { 48 compilePattern(pattern); 49 compileResult(result); 50 } 52 53 public boolean matches(String value, int style) { 54 return getPattern(style).matches(value); 55 } 56 57 public String replace(String value, int style) { 58 Matcher matcher = getPattern(style).getMatcher(value); 59 if (matcher.matches()) { 60 if (style == STYLE_IDENTIFIER && !checkIdentifierChars(value, false)) 61 return null; 62 return replace(value, style, matcher); 63 } 64 return null; 65 } 66 67 private Pattern getPattern(int style) { 68 switch (style) { 69 case STYLE_DESC: 70 return descPattern; 71 case STYLE_IDENTIFIER: 72 return identifierPattern; 73 default: 74 throw new IllegalArgumentException ("Unknown style " + style); 75 } 76 } 77 78 private String replace(String value, int style, Matcher match) { 79 StringBuffer sb = new StringBuffer (); 80 sb.append(value.substring(0, match.start())); 81 sb.append(match.group(1)); 82 for (int i = 0; i < strings.length; i++) { 83 int ref = refs[i]; 84 if (ref == 0) { 85 String s = match.group(0); 86 s = s.substring(match.group(1).length(), 87 s.length() - match.group(count).length()); 88 sb.append(postProcess(s, style)); 89 } else if (ref > 0) { 90 sb.append(postProcess(match.group(ref + 1), style)); 91 } else { 92 sb.append(postProcess(strings[i], style)); 93 } 94 } 95 sb.append(match.group(count)); 96 sb.append(value.substring(match.end())); 97 return sb.toString(); 98 } 99 100 private String postProcess(String value, int style) { 101 if (style == STYLE_IDENTIFIER) { 102 value = value.replace('/', '.'); 103 } else { 104 value = value.replace('.', '/'); 105 } 106 return value; 107 } 108 109 private void compilePattern(String expr) { 110 if (expr.equals("**")) 111 throw new IllegalArgumentException ("'**' is not a valid pattern"); 112 if (!checkIdentifierChars(expr, true)) 113 throw new IllegalArgumentException ("Not a valid package pattern: " + expr); 114 if (expr.indexOf("***") >= 0) 115 throw new IllegalArgumentException ("The sequence '***' is invalid in a package pattern"); 116 117 String p1 = expr; 118 p1 = dots.replaceAll(p1, "~"); 119 p1 = dstar.replaceAll(p1, "(.+?)"); 120 p1 = star.replaceAll(p1, "([^/]+?)"); 121 if (p1.endsWith("+?)")) 122 p1 = p1.substring(0, p1.length() - 3) + "*)"; 124 String p2 = p1; 125 p2 = tilde.replaceAll(p2, "\\."); 126 p1 = tilde.replaceAll(p1, "/"); 127 p1 = "(\\[*L)" + p1 + "(;)"; 129 p1 = "\\A" + p1 + "\\Z"; 130 p2 = "\\A()" + p2 + "()\\Z"; 131 134 descPattern = REGEX.compile(p1); 135 identifierPattern = REGEX.compile(p2); 136 137 count = descPattern.groupCount(); 138 } 139 140 private static boolean checkIdentifierChars(String expr, boolean allowStars) { 142 for (int i = 0, len = expr.length(); i < len; i++) { 143 char ch = expr.charAt(i); 144 switch (ch) { 145 case '*': 146 if (!allowStars) 147 return false; 148 case '.': 149 break; 150 default: 151 if (!Character.isJavaIdentifierPart(ch)) 152 return false; 153 } 154 } 155 return true; 156 } 157 158 private void compileResult(String value) { 159 char[] chars = value.toCharArray(); 161 int max = 0; 162 for (int i = 0, mark = 0, state = 0, len = chars.length; i < len + 1; i++) { 163 char ch = (i == len) ? '@' : chars[i]; 164 if (state == 0) { 165 if (ch == '@') { 166 parts.add(new String (chars, mark, i - mark)); 167 mark = i + 1; 168 state = 1; 169 } 170 } else { 171 switch (ch) { 172 case '0': 173 case '1': 174 case '2': 175 case '3': 176 case '4': 177 case '5': 178 case '6': 179 case '7': 180 case '8': 181 case '9': 182 break; 183 default: 184 if (i == mark) 185 throw new IllegalArgumentException ("Backslash not followed by a digit"); 186 int n = Integer.parseInt(new String (chars, mark, i - mark)); 187 if (n > max) 188 max = n; 189 parts.add(new Integer (n)); 190 mark = i--; 191 state = 0; 192 } 193 } 194 } 195 int size = parts.size(); 196 strings = new String [size]; 197 refs = new int[size]; 198 Arrays.fill(refs, -1); 199 for (int i = 0; i < size; i++) { 200 Object v = parts.get(i); 201 if (v instanceof String ) { 202 strings[i] = (String )v; 203 } else { 204 refs[i] = ((Integer )v).intValue(); 205 } 206 } 207 if (count < max) 208 throw new IllegalArgumentException ("Result includes impossible placeholder \"@" + max + "\": " + value); 209 } 210 211 public String toString() { 212 return "Wildcard{descPattern=" + descPattern + 213 ",identifierPattern=" + identifierPattern + 214 ",parts=" + parts + "}"; 215 } 216 } 217 | Popular Tags |