/* | |
* Copyright 2002-2005 the original author or authors. | |
* | |
* 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.badlogic.gdx.jnigen; | |
import java.util.ArrayList; | |
import java.util.List; | |
import java.util.StringTokenizer; | |
/** PathMatcher implementation for Ant-style path patterns. Examples are provided below. | |
* | |
* <p> | |
* Part of this mapping code has been kindly borrowed from <a href="http://ant.apache.org">Apache Ant</a>. | |
* | |
* <p> | |
* The mapping matches URLs using the following rules:<br> | |
* <ul> | |
* <li>? matches one character</li> | |
* <li>* matches zero or more characters</li> | |
* <li>** matches zero or more 'directories' in a path</li> | |
* </ul> | |
* | |
* <p> | |
* Some examples:<br> | |
* <ul> | |
* <li>com/t?st.jsp - matches test.jsp but also tast.jsp or txst.jsp</li> | |
* <li>com/*.jsp - matches all .jsp files in the com directory</li> | |
* <li>com/**/test.jsp - matches all test.jsp path underneath the com path</li> | |
* <li>org/springframework/**/*.jsp - matches all .jsp files underneath the org/springframework path</li> | |
* <li>org/**/servlet/bla.jsp - matches org/springframework/servlet/bla.jsp but also | |
* org/springframework/testing/servlet/bla.jsp and com/servlet/bla.jsp</li> | |
* </ul> | |
* | |
* @author Alef Arendsen | |
* @author Juergen Hoeller | |
* @since 16.07.2003 */ | |
public class AntPathMatcher { | |
public boolean isPattern (String str) { | |
return (str.indexOf('*') != -1 || str.indexOf('?') != -1); | |
} | |
public static String[] tokenizeToStringArray (String str, String delimiters, boolean trimTokens, boolean ignoreEmptyTokens) { | |
if (str == null) { | |
return null; | |
} | |
StringTokenizer st = new StringTokenizer(str, delimiters); | |
List<String> tokens = new ArrayList<String>(); | |
while (st.hasMoreTokens()) { | |
String token = st.nextToken(); | |
if (trimTokens) { | |
token = token.trim(); | |
} | |
if (!ignoreEmptyTokens || token.length() > 0) { | |
tokens.add(token); | |
} | |
} | |
return tokens.toArray(new String[tokens.size()]); | |
} | |
public boolean match (String file, String[] patterns) { | |
if (patterns == null || patterns.length == 0) return true; | |
for (String pattern : patterns) { | |
if (match(pattern, file)) { | |
return true; | |
} | |
} | |
return false; | |
} | |
public boolean match (String pattern, String str) { | |
if (str.startsWith("/") != pattern.startsWith("/")) { | |
return false; | |
} | |
String[] patDirs = tokenizeToStringArray(pattern, "/", true, true); | |
String[] strDirs = tokenizeToStringArray(str, "/", true, true); | |
int patIdxStart = 0; | |
int patIdxEnd = patDirs.length - 1; | |
int strIdxStart = 0; | |
int strIdxEnd = strDirs.length - 1; | |
// Match all elements up to the first ** | |
while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) { | |
String patDir = (String)patDirs[patIdxStart]; | |
if (patDir.equals("**")) { | |
break; | |
} | |
if (!matchStrings(patDir, (String)strDirs[strIdxStart])) { | |
return false; | |
} | |
patIdxStart++; | |
strIdxStart++; | |
} | |
if (strIdxStart > strIdxEnd) { | |
// String is exhausted, only match if rest of pattern is **'s | |
for (int i = patIdxStart; i <= patIdxEnd; i++) { | |
if (!patDirs[i].equals("**")) { | |
return false; | |
} | |
} | |
return true; | |
} else { | |
if (patIdxStart > patIdxEnd) { | |
// String not exhausted, but pattern is. Failure. | |
return false; | |
} | |
} | |
// up to last '**' | |
while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) { | |
String patDir = (String)patDirs[patIdxEnd]; | |
if (patDir.equals("**")) { | |
break; | |
} | |
if (!matchStrings(patDir, (String)strDirs[strIdxEnd])) { | |
return false; | |
} | |
patIdxEnd--; | |
strIdxEnd--; | |
} | |
if (strIdxStart > strIdxEnd) { | |
// String is exhausted | |
for (int i = patIdxStart; i <= patIdxEnd; i++) { | |
if (!patDirs[i].equals("**")) { | |
return false; | |
} | |
} | |
return true; | |
} | |
while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd) { | |
int patIdxTmp = -1; | |
for (int i = patIdxStart + 1; i <= patIdxEnd; i++) { | |
if (patDirs[i].equals("**")) { | |
patIdxTmp = i; | |
break; | |
} | |
} | |
if (patIdxTmp == patIdxStart + 1) { | |
// '**/**' situation, so skip one | |
patIdxStart++; | |
continue; | |
} | |
// Find the pattern between padIdxStart & padIdxTmp in str between | |
// strIdxStart & strIdxEnd | |
int patLength = (patIdxTmp - patIdxStart - 1); | |
int strLength = (strIdxEnd - strIdxStart + 1); | |
int foundIdx = -1; | |
strLoop: | |
for (int i = 0; i <= strLength - patLength; i++) { | |
for (int j = 0; j < patLength; j++) { | |
String subPat = (String)patDirs[patIdxStart + j + 1]; | |
String subStr = (String)strDirs[strIdxStart + i + j]; | |
if (!matchStrings(subPat, subStr)) { | |
continue strLoop; | |
} | |
} | |
foundIdx = strIdxStart + i; | |
break; | |
} | |
if (foundIdx == -1) { | |
return false; | |
} | |
patIdxStart = patIdxTmp; | |
strIdxStart = foundIdx + patLength; | |
} | |
for (int i = patIdxStart; i <= patIdxEnd; i++) { | |
if (!patDirs[i].equals("**")) { | |
return false; | |
} | |
} | |
return true; | |
} | |
/** Tests whether or not a string matches against a pattern. The pattern may contain two special characters:<br> | |
* '*' means zero or more characters<br> | |
* '?' means one and only one character | |
* | |
* @param pattern pattern to match against. Must not be <code>null</code>. | |
* @param str string which must be matched against the pattern. Must not be <code>null</code>. | |
* @return <code>true</code> if the string matches against the pattern, or <code>false</code> otherwise. */ | |
private boolean matchStrings (String pattern, String str) { | |
char[] patArr = pattern.toCharArray(); | |
char[] strArr = str.toCharArray(); | |
int patIdxStart = 0; | |
int patIdxEnd = patArr.length - 1; | |
int strIdxStart = 0; | |
int strIdxEnd = strArr.length - 1; | |
char ch; | |
boolean containsStar = false; | |
for (int i = 0; i < patArr.length; i++) { | |
if (patArr[i] == '*') { | |
containsStar = true; | |
break; | |
} | |
} | |
if (!containsStar) { | |
// No '*'s, so we make a shortcut | |
if (patIdxEnd != strIdxEnd) { | |
return false; // Pattern and string do not have the same size | |
} | |
for (int i = 0; i <= patIdxEnd; i++) { | |
ch = patArr[i]; | |
if (ch != '?') { | |
if (ch != strArr[i]) { | |
return false;// Character mismatch | |
} | |
} | |
} | |
return true; // String matches against pattern | |
} | |
if (patIdxEnd == 0) { | |
return true; // Pattern contains only '*', which matches anything | |
} | |
// Process characters before first star | |
while ((ch = patArr[patIdxStart]) != '*' && strIdxStart <= strIdxEnd) { | |
if (ch != '?') { | |
if (ch != strArr[strIdxStart]) { | |
return false;// Character mismatch | |
} | |
} | |
patIdxStart++; | |
strIdxStart++; | |
} | |
if (strIdxStart > strIdxEnd) { | |
// All characters in the string are used. Check if only '*'s are | |
// left in the pattern. If so, we succeeded. Otherwise failure. | |
for (int i = patIdxStart; i <= patIdxEnd; i++) { | |
if (patArr[i] != '*') { | |
return false; | |
} | |
} | |
return true; | |
} | |
// Process characters after last star | |
while ((ch = patArr[patIdxEnd]) != '*' && strIdxStart <= strIdxEnd) { | |
if (ch != '?') { | |
if (ch != strArr[strIdxEnd]) { | |
return false;// Character mismatch | |
} | |
} | |
patIdxEnd--; | |
strIdxEnd--; | |
} | |
if (strIdxStart > strIdxEnd) { | |
// All characters in the string are used. Check if only '*'s are | |
// left in the pattern. If so, we succeeded. Otherwise failure. | |
for (int i = patIdxStart; i <= patIdxEnd; i++) { | |
if (patArr[i] != '*') { | |
return false; | |
} | |
} | |
return true; | |
} | |
// process pattern between stars. padIdxStart and patIdxEnd point | |
// always to a '*'. | |
while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd) { | |
int patIdxTmp = -1; | |
for (int i = patIdxStart + 1; i <= patIdxEnd; i++) { | |
if (patArr[i] == '*') { | |
patIdxTmp = i; | |
break; | |
} | |
} | |
if (patIdxTmp == patIdxStart + 1) { | |
// Two stars next to each other, skip the first one. | |
patIdxStart++; | |
continue; | |
} | |
// Find the pattern between padIdxStart & padIdxTmp in str between | |
// strIdxStart & strIdxEnd | |
int patLength = (patIdxTmp - patIdxStart - 1); | |
int strLength = (strIdxEnd - strIdxStart + 1); | |
int foundIdx = -1; | |
strLoop: | |
for (int i = 0; i <= strLength - patLength; i++) { | |
for (int j = 0; j < patLength; j++) { | |
ch = patArr[patIdxStart + j + 1]; | |
if (ch != '?') { | |
if (ch != strArr[strIdxStart + i + j]) { | |
continue strLoop; | |
} | |
} | |
} | |
foundIdx = strIdxStart + i; | |
break; | |
} | |
if (foundIdx == -1) { | |
return false; | |
} | |
patIdxStart = patIdxTmp; | |
strIdxStart = foundIdx + patLength; | |
} | |
// All characters in the string are used. Check if only '*'s are left | |
// in the pattern. If so, we succeeded. Otherwise failure. | |
for (int i = patIdxStart; i <= patIdxEnd; i++) { | |
if (patArr[i] != '*') { | |
return false; | |
} | |
} | |
return true; | |
} | |
} |