1 /* 2 * Copyright 2002-2005 the original author or authors. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.badlogic.gdx.jnigen; 18 19 import java.util.ArrayList; 20 import java.util.List; 21 import java.util.StringTokenizer; 22 23 /** PathMatcher implementation for Ant-style path patterns. Examples are provided below. 24 * 25 * <p> 26 * Part of this mapping code has been kindly borrowed from <a href="http://ant.apache.org">Apache Ant</a>. 27 * 28 * <p> 29 * The mapping matches URLs using the following rules:<br> 30 * <ul> 31 * <li>? matches one character</li> 32 * <li>* matches zero or more characters</li> 33 * <li>** matches zero or more 'directories' in a path</li> 34 * </ul> 35 * 36 * <p> 37 * Some examples:<br> 38 * <ul> 39 * <li>com/t?st.jsp - matches test.jsp but also tast.jsp or txst.jsp</li> 40 * <li>com/*.jsp - matches all .jsp files in the com directory</li> 41 * <li>com/**/test.jsp - matches all test.jsp path underneath the com path</li> 42 * <li>org/springframework/**/*.jsp - matches all .jsp files underneath the org/springframework path</li> 43 * <li>org/**/servlet/bla.jsp - matches org/springframework/servlet/bla.jsp but also 44 * org/springframework/testing/servlet/bla.jsp and com/servlet/bla.jsp</li> 45 * </ul> 46 * 47 * @author Alef Arendsen 48 * @author Juergen Hoeller 49 * @since 16.07.2003 */ 50 public class AntPathMatcher { 51 isPattern(String str)52 public boolean isPattern (String str) { 53 return (str.indexOf('*') != -1 || str.indexOf('?') != -1); 54 } 55 tokenizeToStringArray(String str, String delimiters, boolean trimTokens, boolean ignoreEmptyTokens)56 public static String[] tokenizeToStringArray (String str, String delimiters, boolean trimTokens, boolean ignoreEmptyTokens) { 57 if (str == null) { 58 return null; 59 } 60 StringTokenizer st = new StringTokenizer(str, delimiters); 61 List<String> tokens = new ArrayList<String>(); 62 while (st.hasMoreTokens()) { 63 String token = st.nextToken(); 64 if (trimTokens) { 65 token = token.trim(); 66 } 67 if (!ignoreEmptyTokens || token.length() > 0) { 68 tokens.add(token); 69 } 70 } 71 return tokens.toArray(new String[tokens.size()]); 72 } 73 match(String file, String[] patterns)74 public boolean match (String file, String[] patterns) { 75 if (patterns == null || patterns.length == 0) return true; 76 for (String pattern : patterns) { 77 if (match(pattern, file)) { 78 return true; 79 } 80 } 81 return false; 82 } 83 match(String pattern, String str)84 public boolean match (String pattern, String str) { 85 if (str.startsWith("/") != pattern.startsWith("/")) { 86 return false; 87 } 88 89 String[] patDirs = tokenizeToStringArray(pattern, "/", true, true); 90 String[] strDirs = tokenizeToStringArray(str, "/", true, true); 91 92 int patIdxStart = 0; 93 int patIdxEnd = patDirs.length - 1; 94 int strIdxStart = 0; 95 int strIdxEnd = strDirs.length - 1; 96 97 // Match all elements up to the first ** 98 while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) { 99 String patDir = (String)patDirs[patIdxStart]; 100 if (patDir.equals("**")) { 101 break; 102 } 103 if (!matchStrings(patDir, (String)strDirs[strIdxStart])) { 104 return false; 105 } 106 patIdxStart++; 107 strIdxStart++; 108 } 109 110 if (strIdxStart > strIdxEnd) { 111 // String is exhausted, only match if rest of pattern is **'s 112 for (int i = patIdxStart; i <= patIdxEnd; i++) { 113 if (!patDirs[i].equals("**")) { 114 return false; 115 } 116 } 117 return true; 118 } else { 119 if (patIdxStart > patIdxEnd) { 120 // String not exhausted, but pattern is. Failure. 121 return false; 122 } 123 } 124 125 // up to last '**' 126 while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) { 127 String patDir = (String)patDirs[patIdxEnd]; 128 if (patDir.equals("**")) { 129 break; 130 } 131 if (!matchStrings(patDir, (String)strDirs[strIdxEnd])) { 132 return false; 133 } 134 patIdxEnd--; 135 strIdxEnd--; 136 } 137 if (strIdxStart > strIdxEnd) { 138 // String is exhausted 139 for (int i = patIdxStart; i <= patIdxEnd; i++) { 140 if (!patDirs[i].equals("**")) { 141 return false; 142 } 143 } 144 return true; 145 } 146 147 while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd) { 148 int patIdxTmp = -1; 149 for (int i = patIdxStart + 1; i <= patIdxEnd; i++) { 150 if (patDirs[i].equals("**")) { 151 patIdxTmp = i; 152 break; 153 } 154 } 155 if (patIdxTmp == patIdxStart + 1) { 156 // '**/**' situation, so skip one 157 patIdxStart++; 158 continue; 159 } 160 // Find the pattern between padIdxStart & padIdxTmp in str between 161 // strIdxStart & strIdxEnd 162 int patLength = (patIdxTmp - patIdxStart - 1); 163 int strLength = (strIdxEnd - strIdxStart + 1); 164 int foundIdx = -1; 165 strLoop: 166 for (int i = 0; i <= strLength - patLength; i++) { 167 for (int j = 0; j < patLength; j++) { 168 String subPat = (String)patDirs[patIdxStart + j + 1]; 169 String subStr = (String)strDirs[strIdxStart + i + j]; 170 if (!matchStrings(subPat, subStr)) { 171 continue strLoop; 172 } 173 } 174 175 foundIdx = strIdxStart + i; 176 break; 177 } 178 179 if (foundIdx == -1) { 180 return false; 181 } 182 183 patIdxStart = patIdxTmp; 184 strIdxStart = foundIdx + patLength; 185 } 186 187 for (int i = patIdxStart; i <= patIdxEnd; i++) { 188 if (!patDirs[i].equals("**")) { 189 return false; 190 } 191 } 192 193 return true; 194 } 195 196 /** Tests whether or not a string matches against a pattern. The pattern may contain two special characters:<br> 197 * '*' means zero or more characters<br> 198 * '?' means one and only one character 199 * 200 * @param pattern pattern to match against. Must not be <code>null</code>. 201 * @param str string which must be matched against the pattern. Must not be <code>null</code>. 202 * @return <code>true</code> if the string matches against the pattern, or <code>false</code> otherwise. */ matchStrings(String pattern, String str)203 private boolean matchStrings (String pattern, String str) { 204 char[] patArr = pattern.toCharArray(); 205 char[] strArr = str.toCharArray(); 206 int patIdxStart = 0; 207 int patIdxEnd = patArr.length - 1; 208 int strIdxStart = 0; 209 int strIdxEnd = strArr.length - 1; 210 char ch; 211 212 boolean containsStar = false; 213 for (int i = 0; i < patArr.length; i++) { 214 if (patArr[i] == '*') { 215 containsStar = true; 216 break; 217 } 218 } 219 220 if (!containsStar) { 221 // No '*'s, so we make a shortcut 222 if (patIdxEnd != strIdxEnd) { 223 return false; // Pattern and string do not have the same size 224 } 225 for (int i = 0; i <= patIdxEnd; i++) { 226 ch = patArr[i]; 227 if (ch != '?') { 228 if (ch != strArr[i]) { 229 return false;// Character mismatch 230 } 231 } 232 } 233 return true; // String matches against pattern 234 } 235 236 if (patIdxEnd == 0) { 237 return true; // Pattern contains only '*', which matches anything 238 } 239 240 // Process characters before first star 241 while ((ch = patArr[patIdxStart]) != '*' && strIdxStart <= strIdxEnd) { 242 if (ch != '?') { 243 if (ch != strArr[strIdxStart]) { 244 return false;// Character mismatch 245 } 246 } 247 patIdxStart++; 248 strIdxStart++; 249 } 250 if (strIdxStart > strIdxEnd) { 251 // All characters in the string are used. Check if only '*'s are 252 // left in the pattern. If so, we succeeded. Otherwise failure. 253 for (int i = patIdxStart; i <= patIdxEnd; i++) { 254 if (patArr[i] != '*') { 255 return false; 256 } 257 } 258 return true; 259 } 260 261 // Process characters after last star 262 while ((ch = patArr[patIdxEnd]) != '*' && strIdxStart <= strIdxEnd) { 263 if (ch != '?') { 264 if (ch != strArr[strIdxEnd]) { 265 return false;// Character mismatch 266 } 267 } 268 patIdxEnd--; 269 strIdxEnd--; 270 } 271 if (strIdxStart > strIdxEnd) { 272 // All characters in the string are used. Check if only '*'s are 273 // left in the pattern. If so, we succeeded. Otherwise failure. 274 for (int i = patIdxStart; i <= patIdxEnd; i++) { 275 if (patArr[i] != '*') { 276 return false; 277 } 278 } 279 return true; 280 } 281 282 // process pattern between stars. padIdxStart and patIdxEnd point 283 // always to a '*'. 284 while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd) { 285 int patIdxTmp = -1; 286 for (int i = patIdxStart + 1; i <= patIdxEnd; i++) { 287 if (patArr[i] == '*') { 288 patIdxTmp = i; 289 break; 290 } 291 } 292 if (patIdxTmp == patIdxStart + 1) { 293 // Two stars next to each other, skip the first one. 294 patIdxStart++; 295 continue; 296 } 297 // Find the pattern between padIdxStart & padIdxTmp in str between 298 // strIdxStart & strIdxEnd 299 int patLength = (patIdxTmp - patIdxStart - 1); 300 int strLength = (strIdxEnd - strIdxStart + 1); 301 int foundIdx = -1; 302 strLoop: 303 for (int i = 0; i <= strLength - patLength; i++) { 304 for (int j = 0; j < patLength; j++) { 305 ch = patArr[patIdxStart + j + 1]; 306 if (ch != '?') { 307 if (ch != strArr[strIdxStart + i + j]) { 308 continue strLoop; 309 } 310 } 311 } 312 313 foundIdx = strIdxStart + i; 314 break; 315 } 316 317 if (foundIdx == -1) { 318 return false; 319 } 320 321 patIdxStart = patIdxTmp; 322 strIdxStart = foundIdx + patLength; 323 } 324 325 // All characters in the string are used. Check if only '*'s are left 326 // in the pattern. If so, we succeeded. Otherwise failure. 327 for (int i = patIdxStart; i <= patIdxEnd; i++) { 328 if (patArr[i] != '*') { 329 return false; 330 } 331 } 332 333 return true; 334 } 335 336 } 337