1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.vfs2.filter;
18
19 import java.io.Serializable;
20 import java.util.ArrayList;
21 import java.util.Arrays;
22 import java.util.List;
23 import java.util.Stack;
24
25 import org.apache.commons.lang3.ArrayUtils;
26 import org.apache.commons.lang3.StringUtils;
27 import org.apache.commons.vfs2.FileFilter;
28 import org.apache.commons.vfs2.FileSelectInfo;
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60 public class WildcardFileFilter implements FileFilter, Serializable {
61
62 private static final long serialVersionUID = 1L;
63
64
65 private final IOCase caseSensitivity;
66
67
68 private final List<String> wildcards;
69
70
71
72
73
74
75 public WildcardFileFilter(final List<String> wildcards) {
76 this((IOCase) null, wildcards);
77 }
78
79
80
81
82
83
84
85
86
87 public WildcardFileFilter(final IOCase caseSensitivity, final List<String> wildcards) {
88 if (wildcards == null) {
89 throw new IllegalArgumentException("The wildcard list must not be null");
90 }
91 this.wildcards = new ArrayList<>(wildcards);
92 this.caseSensitivity = caseSensitivity == null ? IOCase.SENSITIVE : caseSensitivity;
93 }
94
95
96
97
98
99
100
101
102
103 public WildcardFileFilter(final String... wildcards) {
104 this((IOCase) null, wildcards);
105 }
106
107
108
109
110
111
112
113
114
115 public WildcardFileFilter(final IOCase caseSensitivity, final String... wildcards) {
116 if (wildcards == null) {
117 throw new IllegalArgumentException("The wildcard array must not be null");
118 }
119 this.wildcards = new ArrayList<>(Arrays.asList(wildcards));
120 this.caseSensitivity = caseSensitivity == null ? IOCase.SENSITIVE : caseSensitivity;
121 }
122
123
124
125
126
127
128
129
130 @Override
131 public boolean accept(final FileSelectInfo fileSelectInfo) {
132 final String name = fileSelectInfo.getFile().getName().getBaseName();
133 for (final String wildcard : wildcards) {
134 if (wildcardMatch(name, wildcard, caseSensitivity)) {
135 return true;
136 }
137 }
138 return false;
139 }
140
141
142
143
144
145
146 @Override
147 public String toString() {
148 final StringBuilder buffer = new StringBuilder();
149 buffer.append(super.toString());
150 buffer.append("(");
151 if (wildcards != null) {
152 for (int i = 0; i < wildcards.size(); i++) {
153 if (i > 0) {
154 buffer.append(",");
155 }
156 buffer.append(wildcards.get(i));
157 }
158 }
159 buffer.append(")");
160 return buffer.toString();
161 }
162
163
164
165
166
167
168
169
170
171 static String[] splitOnTokens(final String text) {
172
173
174
175 if (text.indexOf('?') == -1 && text.indexOf('*') == -1) {
176 return new String[] { text };
177 }
178
179 final char[] array = text.toCharArray();
180 final ArrayList<String> list = new ArrayList<>();
181 final StringBuilder builder = new StringBuilder();
182 for (int i = 0; i < array.length; i++) {
183 if (array[i] == '?' || array[i] == '*') {
184 if (StringUtils.isNotEmpty(builder)) {
185 list.add(builder.toString());
186 builder.setLength(0);
187 }
188 if (array[i] == '?') {
189 list.add("?");
190 } else if (list.isEmpty() || i > 0 && !list.get(list.size() - 1).equals("*")) {
191 list.add("*");
192 }
193 } else {
194 builder.append(array[i]);
195 }
196 }
197 if (StringUtils.isNotEmpty(builder)) {
198 list.add(builder.toString());
199 }
200
201 return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
202 }
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223 static boolean wildcardMatch(final String fileName, final String wildcardMatcher, IOCase caseSensitivity) {
224 if (fileName == null && wildcardMatcher == null) {
225 return true;
226 }
227 if (fileName == null || wildcardMatcher == null) {
228 return false;
229 }
230 if (caseSensitivity == null) {
231 caseSensitivity = IOCase.SENSITIVE;
232 }
233 final String[] wcs = splitOnTokens(wildcardMatcher);
234 boolean anyChars = false;
235 int textIdx = 0;
236 int wcsIdx = 0;
237 final Stack<int[]> backtrack = new Stack<>();
238
239
240 do {
241 if (!backtrack.isEmpty()) {
242 final int[] array = backtrack.pop();
243 wcsIdx = array[0];
244 textIdx = array[1];
245 anyChars = true;
246 }
247
248
249 while (wcsIdx < wcs.length) {
250
251 if (wcs[wcsIdx].equals("?")) {
252
253 textIdx++;
254 if (textIdx > fileName.length()) {
255 break;
256 }
257 anyChars = false;
258
259 } else if (wcs[wcsIdx].equals("*")) {
260
261 anyChars = true;
262 if (wcsIdx == wcs.length - 1) {
263 textIdx = fileName.length();
264 }
265
266 } else {
267
268 if (anyChars) {
269
270 textIdx = caseSensitivity.checkIndexOf(fileName, textIdx, wcs[wcsIdx]);
271 if (textIdx == -1) {
272
273 break;
274 }
275 final int repeat = caseSensitivity.checkIndexOf(fileName, textIdx + 1, wcs[wcsIdx]);
276 if (repeat >= 0) {
277 backtrack.push(new int[] { wcsIdx, repeat });
278 }
279 } else if (!caseSensitivity.checkRegionMatches(fileName, textIdx, wcs[wcsIdx])) {
280
281
282 break;
283 }
284
285
286
287 textIdx += wcs[wcsIdx].length();
288 anyChars = false;
289 }
290
291 wcsIdx++;
292 }
293
294
295 if (wcsIdx == wcs.length && textIdx == fileName.length()) {
296 return true;
297 }
298
299 } while (!backtrack.isEmpty());
300
301 return false;
302 }
303
304
305 }