• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/&#42;&#42;/test.jsp - matches all test.jsp path underneath the com path</li>
42  * <li>org/springframework/&#42;&#42;/*.jsp - matches all .jsp files underneath the org/springframework path</li>
43  * <li>org/&#42;&#42;/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