Skip to content

Commit 1ead1cc

Browse files
author
Stephen Colebourne
committed
Fix bug in wildcard search for advanced repetitive matches
bug 33303, from Danival Taffarel Calegari git-svn-id: https://svn.apache.org/repos/asf/jakarta/commons/proper/io/trunk@156217 13f79535-47bb-0310-9956-ffa450edef68
1 parent 19fa455 commit 1ead1cc

2 files changed

Lines changed: 81 additions & 51 deletions

File tree

src/java/org/apache/commons/io/FilenameUtils.java

Lines changed: 62 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import java.io.File;
1919
import java.util.ArrayList;
2020
import java.util.Collection;
21+
import java.util.Stack;
2122

2223
/**
2324
* Utility class that provides methods to manipulate filenames and filepaths.
@@ -852,63 +853,69 @@ public static boolean wildcardMatch(String filename, String wildcardMatcher) {
852853
boolean anyChars = false;
853854
int textIdx = 0;
854855
int wcsIdx = 0;
855-
856-
// loop whilst tokens and text left to process
857-
while (wcsIdx < wcs.length && textIdx < filename.length()) {
858-
859-
if (wcs[wcsIdx].equals("?")) {
860-
// ? so move to next text char
861-
textIdx++;
862-
anyChars = false;
863-
864-
} else if (wcs[wcsIdx].equals("*")) {
865-
// set any chars status
856+
Stack backtrack = new Stack();
857+
858+
// loop around a backtrack stack, to handle complex * matching
859+
do {
860+
if (backtrack.size() > 0) {
861+
int[] array = (int[]) backtrack.pop();
862+
wcsIdx = array[0];
863+
textIdx = array[1];
866864
anyChars = true;
867-
868-
} else {
869-
// matching text token
870-
if (anyChars) {
871-
// any chars then try to locate text token
872-
textIdx = filename.indexOf(wcs[wcsIdx], textIdx);
873-
if (textIdx == -1) {
874-
// token not found
875-
return false;
865+
}
866+
867+
// loop whilst tokens and text left to process
868+
while (wcsIdx < wcs.length) {
869+
870+
if (wcs[wcsIdx].equals("?")) {
871+
// ? so move to next text char
872+
textIdx++;
873+
anyChars = false;
874+
875+
} else if (wcs[wcsIdx].equals("*")) {
876+
// set any chars status
877+
anyChars = true;
878+
if (wcsIdx == wcs.length - 1) {
879+
textIdx = filename.length();
876880
}
881+
877882
} else {
878-
// matching from current position
879-
if (!filename.startsWith(wcs[wcsIdx], textIdx)) {
880-
// couldnt match token
881-
return false;
883+
// matching text token
884+
if (anyChars) {
885+
// any chars then try to locate text token
886+
textIdx = filename.indexOf(wcs[wcsIdx], textIdx);
887+
if (textIdx == -1) {
888+
// token not found
889+
break;
890+
}
891+
int repeat = filename.indexOf(wcs[wcsIdx], textIdx + 1);
892+
if (repeat >= 0) {
893+
backtrack.push(new int[] {wcsIdx, repeat});
894+
}
895+
} else {
896+
// matching from current position
897+
if (!filename.startsWith(wcs[wcsIdx], textIdx)) {
898+
// couldnt match token
899+
break;
900+
}
882901
}
902+
903+
// matched text token, move text index to end of matched token
904+
textIdx += wcs[wcsIdx].length();
905+
anyChars = false;
883906
}
884-
885-
// matched text token, move text index to end of matched token
886-
textIdx += wcs[wcsIdx].length();
887-
anyChars = false;
907+
908+
wcsIdx++;
888909
}
889-
890-
wcsIdx++;
891-
}
892-
893-
// didnt match all wildcards
894-
if (wcsIdx < wcs.length) {
895-
// ok if one remaining and wildcard or empty
896-
if (wcsIdx + 1 != wcs.length || !(wcs[wcsIdx].equals("*") || wcs[wcsIdx].equals("")) ) {
897-
return false;
910+
911+
// full match
912+
if (wcsIdx == wcs.length && textIdx == filename.length()) {
913+
return true;
898914
}
899-
}
915+
916+
} while (backtrack.size() > 0);
900917

901-
// ran out of text chars
902-
if (textIdx > filename.length()) {
903-
return false;
904-
}
905-
906-
// didnt match all text chars, only ok if any chars set
907-
if (textIdx < filename.length() && !anyChars) {
908-
return false;
909-
}
910-
911-
return true;
918+
return false;
912919
}
913920

914921
// used by wildcardMatch
@@ -927,7 +934,12 @@ static String[] splitOnTokens(String text) {
927934
list.add(buffer.toString());
928935
buffer.setLength(0);
929936
}
930-
list.add(new String(new char[] { array[i] }));
937+
if (array[i] == '?') {
938+
list.add("?");
939+
} else if (list.size() == 0 ||
940+
(i > 0 && list.get(list.size() - 1).equals("*") == false)) {
941+
list.add("*");
942+
}
931943
} else {
932944
buffer.append(array[i]);
933945
}

src/test/org/apache/commons/io/FilenameUtilsWildcardTestCase.java

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ public void testSplitOnTokens() {
5353
assertArrayEquals( new String[] { "Ad", "*", "er" }, FilenameUtils.splitOnTokens("Ad*er") );
5454
assertArrayEquals( new String[] { "Ad", "?", "er" }, FilenameUtils.splitOnTokens("Ad?er") );
5555
assertArrayEquals( new String[] { "Test", "*", "?", "One" }, FilenameUtils.splitOnTokens("Test*?One") );
56-
assertArrayEquals( new String[] { "*", "*", "*", "*" }, FilenameUtils.splitOnTokens("****") );
56+
assertArrayEquals( new String[] { "*" }, FilenameUtils.splitOnTokens("****") );
5757
assertArrayEquals( new String[] { "*", "?", "?", "*" }, FilenameUtils.splitOnTokens("*??*") );
5858
assertArrayEquals( new String[] { "*", "?", "?", "*" }, FilenameUtils.splitOnTokens("*??*") );
5959
assertArrayEquals( new String[] { "h", "?", "?", "*" }, FilenameUtils.splitOnTokens("h??*") );
@@ -98,6 +98,24 @@ public void testMatch2() {
9898
assertMatch("log.txt", "log?*", true);
9999

100100
assertMatch("log.txt12", "log.txt??", true);
101+
102+
assertMatch("log.log", "log**log", true);
103+
assertMatch("log.log", "log**", true);
104+
assertMatch("log.log", "log.**", true);
105+
assertMatch("log.log", "**.log", true);
106+
assertMatch("log.log", "**log", true);
107+
108+
assertMatch("log.log", "log*log", true);
109+
assertMatch("log.log", "log*", true);
110+
assertMatch("log.log", "log.*", true);
111+
assertMatch("log.log", "*.log", true);
112+
assertMatch("log.log", "*log", true);
113+
114+
assertMatch("log.log", "*log?", false);
115+
assertMatch("log.log", "*log?*", true);
116+
assertMatch("log.log.abc", "*log?abc", true);
117+
assertMatch("log.log.abc.log.abc", "*log?abc", true);
118+
assertMatch("log.log.abc.log.abc.d", "*log?abc?d", true);
101119
}
102120

103121
}

0 commit comments

Comments
 (0)