KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > oddjob > io > WildcardSpec


1 /*
2  * Copyright (c) 2005, Rob Gordon.
3  */

4 package org.oddjob.io;
5
6 import java.io.File JavaDoc;
7 import java.io.FileFilter JavaDoc;
8 import java.util.Arrays JavaDoc;
9 import java.util.HashSet JavaDoc;
10 import java.util.LinkedList JavaDoc;
11 import java.util.Set JavaDoc;
12
13 import org.apache.commons.io.FilenameUtils;
14
15 /**
16  */

17 public class WildcardSpec {
18
19     private File JavaDoc file;
20     
21     public WildcardSpec(String JavaDoc spec) {
22         this(new File JavaDoc(spec));
23     }
24     
25     public WildcardSpec(File JavaDoc file) {
26         this.file = file;
27     }
28     
29     public File JavaDoc[] findFiles() {
30         DirectorySplit split = new DirectorySplit(file);
31         return findFiles(split);
32     }
33     
34     public File JavaDoc[] findFiles(final DirectorySplit split) {
35         Set JavaDoc results = new HashSet JavaDoc();
36         if (split.getParentFile() == null) {
37             // should only happen with the "/" spec.
38
results.add(new File JavaDoc(split.getName()));
39         }
40         else {
41             File JavaDoc[] matching = split.getParentFile().listFiles(new FileFilter JavaDoc() {
42                 public boolean accept(File JavaDoc pathname) {
43                     return FilenameUtils.wildcardMatchOnSystem(pathname.getName(), split.getName());
44                 }
45             });
46             for (int i = 0; matching != null && i < matching.length; ++i) {
47                 if (!split.isBottom()) {
48                     if (matching[i].isDirectory()) {
49                         File JavaDoc[] more = findFiles(split.next(matching[i].getName()));
50                         results.addAll(Arrays.asList(more));
51                     }
52                 }
53                 else {
54                     results.add(matching[i]);
55                 }
56             }
57         }
58         return (File JavaDoc[]) results.toArray(new File JavaDoc[0]);
59     }
60
61     static class DirectorySplit {
62         LinkedList JavaDoc split = new LinkedList JavaDoc();
63
64         private DirectorySplit() { }
65         
66         DirectorySplit(File JavaDoc file) {
67             for (AboveAndBelow ab = new AboveAndBelow(file);
68                     true; ab = new AboveAndBelow(ab)) {
69                 split.add(ab);
70                 if (ab.top) {
71                     break;
72                 }
73                 if (ab.parent.getPath().indexOf('*') < 0 &&
74                         ab.parent.getPath().indexOf('?') < 0) {
75                     break;
76                 }
77             }
78         }
79        
80         File JavaDoc getParentFile() {
81             File JavaDoc parent = ((AboveAndBelow) split.getLast()).parent;
82             return parent;
83         }
84         
85         String JavaDoc getName() {
86             return ((AboveAndBelow) split.getLast()).name;
87         }
88         
89         boolean isBottom() {
90             return ((AboveAndBelow) split.getLast()).below == null;
91         }
92         
93         int getSize() {
94             return split.size();
95         }
96         
97         DirectorySplit next(String JavaDoc name) {
98             if (split.size() == 1) {
99                 return null;
100             }
101             
102             DirectorySplit next = new DirectorySplit();
103             next.split = new LinkedList JavaDoc(split);
104             next.split.removeLast();
105             ((AboveAndBelow) next.split.getLast()).parent = new File JavaDoc(getParentFile(), name);
106             return next;
107         }
108     }
109         
110     static class AboveAndBelow {
111         File JavaDoc parent;
112         String JavaDoc name;
113         File JavaDoc below;
114         boolean top;
115         
116         AboveAndBelow(AboveAndBelow previous) {
117             if (previous.top) {
118                 throw new IllegalStateException JavaDoc("Previous was top.");
119             }
120             if (previous.parent == null) {
121                 throw new IllegalStateException JavaDoc("Previous should have been top.");
122             }
123             
124             parent = previous.parent.getParentFile();
125             if (parent == null) {
126                 if (previous.parent.isAbsolute()) {
127                     throw new IllegalStateException JavaDoc("Previous should have been top.");
128                 }
129                 parent = previous.parent.getAbsoluteFile().getParentFile();
130                 top = true;
131             }
132             else {
133                 if (parent.getAbsoluteFile().getParentFile() == null) {
134                     // path must be "/"
135
top = true;
136                 }
137             }
138             
139             name = previous.parent.getName();
140
141             if (previous.below == null) {
142                 below = new File JavaDoc(previous.name);
143             }
144             else {
145                 below = new File JavaDoc(previous.name, previous.below.getPath());
146             }
147         }
148         
149         AboveAndBelow(File JavaDoc first) {
150             parent = first.getParentFile();
151             if (parent == null) {
152                 // parent will be null for "/" situation.
153
parent = first.getAbsoluteFile().getParentFile();
154                 top = true;
155             }
156             name = first.getName();
157             below = null;
158         }
159     }
160     
161     // taken as is from ant...
162

163     /**
164      * Tests whether or not a string matches against a pattern.
165      * The pattern may contain two special characters:<br>
166      * '*' means zero or more characters<br>
167      * '?' means one and only one character
168      *
169      * @param pattern The pattern to match against.
170      * Must not be <code>null</code>.
171      * @param str The string which must be matched against the pattern.
172      * Must not be <code>null</code>.
173      * @param isCaseSensitive Whether or not matching should be performed
174      * case sensitively.
175      *
176      *
177      * @return <code>true</code> if the string matches against the pattern,
178      * or <code>false</code> otherwise.
179      */

180     public static boolean match(String JavaDoc pattern, String JavaDoc str,
181                                 boolean isCaseSensitive) {
182         char[] patArr = pattern.toCharArray();
183         char[] strArr = str.toCharArray();
184         int patIdxStart = 0;
185         int patIdxEnd = patArr.length - 1;
186         int strIdxStart = 0;
187         int strIdxEnd = strArr.length - 1;
188         char ch;
189
190         boolean containsStar = false;
191         for (int i = 0; i < patArr.length; i++) {
192             if (patArr[i] == '*') {
193                 containsStar = true;
194                 break;
195             }
196         }
197
198         if (!containsStar) {
199             // No '*'s, so we make a shortcut
200
if (patIdxEnd != strIdxEnd) {
201                 return false; // Pattern and string do not have the same size
202
}
203             for (int i = 0; i <= patIdxEnd; i++) {
204                 ch = patArr[i];
205                 if (ch != '?') {
206                     if (isCaseSensitive && ch != strArr[i]) {
207                         return false; // Character mismatch
208
}
209                     if (!isCaseSensitive && Character.toUpperCase(ch)
210                             != Character.toUpperCase(strArr[i])) {
211                         return false; // Character mismatch
212
}
213                 }
214             }
215             return true; // String matches against pattern
216
}
217
218         if (patIdxEnd == 0) {
219             return true; // Pattern contains only '*', which matches anything
220
}
221
222         // Process characters before first star
223
while ((ch = patArr[patIdxStart]) != '*' && strIdxStart <= strIdxEnd) {
224             if (ch != '?') {
225                 if (isCaseSensitive && ch != strArr[strIdxStart]) {
226                     return false; // Character mismatch
227
}
228                 if (!isCaseSensitive && Character.toUpperCase(ch)
229                         != Character.toUpperCase(strArr[strIdxStart])) {
230                     return false; // Character mismatch
231
}
232             }
233             patIdxStart++;
234             strIdxStart++;
235         }
236         if (strIdxStart > strIdxEnd) {
237             // All characters in the string are used. Check if only '*'s are
238
// left in the pattern. If so, we succeeded. Otherwise failure.
239
for (int i = patIdxStart; i <= patIdxEnd; i++) {
240                 if (patArr[i] != '*') {
241                     return false;
242                 }
243             }
244             return true;
245         }
246
247         // Process characters after last star
248
while ((ch = patArr[patIdxEnd]) != '*' && strIdxStart <= strIdxEnd) {
249             if (ch != '?') {
250                 if (isCaseSensitive && ch != strArr[strIdxEnd]) {
251                     return false; // Character mismatch
252
}
253                 if (!isCaseSensitive && Character.toUpperCase(ch)
254                         != Character.toUpperCase(strArr[strIdxEnd])) {
255                     return false; // Character mismatch
256
}
257             }
258             patIdxEnd--;
259             strIdxEnd--;
260         }
261         if (strIdxStart > strIdxEnd) {
262             // All characters in the string are used. Check if only '*'s are
263
// left in the pattern. If so, we succeeded. Otherwise failure.
264
for (int i = patIdxStart; i <= patIdxEnd; i++) {
265                 if (patArr[i] != '*') {
266                     return false;
267                 }
268             }
269             return true;
270         }
271
272         // process pattern between stars. padIdxStart and patIdxEnd point
273
// always to a '*'.
274
while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd) {
275             int patIdxTmp = -1;
276             for (int i = patIdxStart + 1; i <= patIdxEnd; i++) {
277                 if (patArr[i] == '*') {
278                     patIdxTmp = i;
279                     break;
280                 }
281             }
282             if (patIdxTmp == patIdxStart + 1) {
283                 // Two stars next to each other, skip the first one.
284
patIdxStart++;
285                 continue;
286             }
287             // Find the pattern between padIdxStart & padIdxTmp in str between
288
// strIdxStart & strIdxEnd
289
int patLength = (patIdxTmp - patIdxStart - 1);
290             int strLength = (strIdxEnd - strIdxStart + 1);
291             int foundIdx = -1;
292             strLoop:
293             for (int i = 0; i <= strLength - patLength; i++) {
294                 for (int j = 0; j < patLength; j++) {
295                     ch = patArr[patIdxStart + j + 1];
296                     if (ch != '?') {
297                         if (isCaseSensitive && ch != strArr[strIdxStart + i
298                                 + j]) {
299                             continue strLoop;
300                         }
301                         if (!isCaseSensitive
302                             && Character.toUpperCase(ch)
303                                 != Character.toUpperCase(strArr[strIdxStart + i + j])) {
304                             continue strLoop;
305                         }
306                     }
307                 }
308
309                 foundIdx = strIdxStart + i;
310                 break;
311             }
312
313             if (foundIdx == -1) {
314                 return false;
315             }
316
317             patIdxStart = patIdxTmp;
318             strIdxStart = foundIdx + patLength;
319         }
320
321         // All characters in the string are used. Check if only '*'s are left
322
// in the pattern. If so, we succeeded. Otherwise failure.
323
for (int i = patIdxStart; i <= patIdxEnd; i++) {
324             if (patArr[i] != '*') {
325                 return false;
326             }
327         }
328         return true;
329     }
330
331 }
332
Popular Tags