1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.shared.utils.io;
20
21 import javax.annotation.Nonnull;
22
23 import java.io.File;
24 import java.util.ArrayList;
25 import java.util.List;
26 import java.util.StringTokenizer;
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43 @Deprecated
44 public final class SelectorUtils {
45
46
47
48
49 private static final String PATTERN_HANDLER_PREFIX = "[";
50
51
52
53
54 public static final String PATTERN_HANDLER_SUFFIX = "]";
55
56
57
58
59 public static final String REGEX_HANDLER_PREFIX = "%regex" + PATTERN_HANDLER_PREFIX;
60
61
62
63
64 public static final String ANT_HANDLER_PREFIX = "%ant" + PATTERN_HANDLER_PREFIX;
65
66
67
68
69 private SelectorUtils() {}
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86 public static boolean matchPatternStart(String pattern, String str) {
87 return matchPatternStart(pattern, str, true);
88 }
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106 public static boolean matchPatternStart(String pattern, String str, boolean isCaseSensitive) {
107 if (isRegexPrefixedPattern(pattern)) {
108
109
110 return true;
111 } else {
112 if (isAntPrefixedPattern(pattern)) {
113 pattern = pattern.substring(
114 ANT_HANDLER_PREFIX.length(), pattern.length() - PATTERN_HANDLER_SUFFIX.length());
115 }
116
117 String altPattern = pattern.replace('\\', '/');
118 String altStr = str.replace('\\', '/');
119
120 return matchAntPathPatternStart(altPattern, altStr, "/", isCaseSensitive);
121 }
122 }
123
124 private static boolean matchAntPathPatternStart(
125 String pattern, String str, String separator, boolean isCaseSensitive) {
126
127
128
129
130 if (separatorPatternStartSlashMismatch(pattern, str, separator)) {
131 return false;
132 }
133
134 List<String> patDirs = tokenizePath(pattern, separator);
135 List<String> strDirs = tokenizePath(str, separator);
136
137 int patIdxStart = 0;
138 int patIdxEnd = patDirs.size() - 1;
139 int strIdxStart = 0;
140 int strIdxEnd = strDirs.size() - 1;
141
142
143 while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) {
144 String patDir = patDirs.get(patIdxStart);
145 if ("**".equals(patDir)) {
146 break;
147 }
148 if (!match(patDir, strDirs.get(strIdxStart), isCaseSensitive)) {
149 return false;
150 }
151 patIdxStart++;
152 strIdxStart++;
153 }
154
155 return strIdxStart > strIdxEnd || patIdxStart <= patIdxEnd;
156 }
157
158
159
160
161
162
163
164
165
166
167
168 public static boolean matchPath(String pattern, String str) {
169 return matchPath(pattern, str, true);
170 }
171
172
173
174
175
176
177
178
179
180
181
182
183
184 public static boolean matchPath(String pattern, String str, boolean isCaseSensitive) {
185 if (pattern.length() > (REGEX_HANDLER_PREFIX.length() + PATTERN_HANDLER_SUFFIX.length() + 1)
186 && pattern.startsWith(REGEX_HANDLER_PREFIX)
187 && pattern.endsWith(PATTERN_HANDLER_SUFFIX)) {
188 pattern = pattern.substring(
189 REGEX_HANDLER_PREFIX.length(), pattern.length() - PATTERN_HANDLER_SUFFIX.length());
190
191 return str.matches(pattern);
192 } else {
193 if (pattern.length() > (ANT_HANDLER_PREFIX.length() + PATTERN_HANDLER_SUFFIX.length() + 1)
194 && pattern.startsWith(ANT_HANDLER_PREFIX)
195 && pattern.endsWith(PATTERN_HANDLER_SUFFIX)) {
196 pattern = pattern.substring(
197 ANT_HANDLER_PREFIX.length(), pattern.length() - PATTERN_HANDLER_SUFFIX.length());
198 }
199
200 return matchAntPathPattern(pattern, str, isCaseSensitive);
201 }
202 }
203
204 private static boolean matchAntPathPattern(String pattern, String str, boolean isCaseSensitive) {
205
206
207
208
209 if (str.startsWith(File.separator) != pattern.startsWith(File.separator)) {
210 return false;
211 }
212
213 List<String> patDirs = tokenizePath(pattern, File.separator);
214 List<String> strDirs = tokenizePath(str, File.separator);
215
216 int patIdxStart = 0;
217 int patIdxEnd = patDirs.size() - 1;
218 int strIdxStart = 0;
219 int strIdxEnd = strDirs.size() - 1;
220
221
222 while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) {
223 String patDir = patDirs.get(patIdxStart);
224 if ("**".equals(patDir)) {
225 break;
226 }
227 if (!match(patDir, strDirs.get(strIdxStart), isCaseSensitive)) {
228 return false;
229 }
230 patIdxStart++;
231 strIdxStart++;
232 }
233 if (strIdxStart > strIdxEnd) {
234
235 for (int i = patIdxStart; i <= patIdxEnd; i++) {
236 if (!"**".equals(patDirs.get(i))) {
237 return false;
238 }
239 }
240 return true;
241 } else {
242 if (patIdxStart > patIdxEnd) {
243
244 return false;
245 }
246 }
247
248
249 while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) {
250 String patDir = patDirs.get(patIdxEnd);
251 if ("**".equals(patDir)) {
252 break;
253 }
254 if (!match(patDir, strDirs.get(strIdxEnd), isCaseSensitive)) {
255 return false;
256 }
257 patIdxEnd--;
258 strIdxEnd--;
259 }
260 if (strIdxStart > strIdxEnd) {
261
262 for (int i = patIdxStart; i <= patIdxEnd; i++) {
263 if (!"**".equals(patDirs.get(i))) {
264 return false;
265 }
266 }
267 return true;
268 }
269
270 while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd) {
271 int patIdxTmp = -1;
272 for (int i = patIdxStart + 1; i <= patIdxEnd; i++) {
273 if ("**".equals(patDirs.get(i))) {
274 patIdxTmp = i;
275 break;
276 }
277 }
278 if (patIdxTmp == patIdxStart + 1) {
279
280 patIdxStart++;
281 continue;
282 }
283
284
285 int patLength = (patIdxTmp - patIdxStart - 1);
286 int strLength = (strIdxEnd - strIdxStart + 1);
287 int foundIdx = -1;
288 strLoop:
289 for (int i = 0; i <= strLength - patLength; i++) {
290 for (int j = 0; j < patLength; j++) {
291 String subPat = patDirs.get(patIdxStart + j + 1);
292 String subStr = strDirs.get(strIdxStart + i + j);
293 if (!match(subPat, subStr, isCaseSensitive)) {
294 continue strLoop;
295 }
296 }
297
298 foundIdx = strIdxStart + i;
299 break;
300 }
301
302 if (foundIdx == -1) {
303 return false;
304 }
305
306 patIdxStart = patIdxTmp;
307 strIdxStart = foundIdx + patLength;
308 }
309
310 for (int i = patIdxStart; i <= patIdxEnd; i++) {
311 if (!"**".equals(patDirs.get(i))) {
312 return false;
313 }
314 }
315
316 return true;
317 }
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332 public static boolean match(String pattern, String str) {
333 return match(pattern, str, true);
334 }
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351 public static boolean match(String pattern, String str, boolean isCaseSensitive) {
352 char[] patArr = pattern.toCharArray();
353 char[] strArr = str.toCharArray();
354 int patIdxStart = 0;
355 int patIdxEnd = patArr.length - 1;
356 int strIdxStart = 0;
357 int strIdxEnd = strArr.length - 1;
358 char ch;
359
360 boolean containsStar = false;
361 for (char aPatArr : patArr) {
362 if (aPatArr == '*') {
363 containsStar = true;
364 break;
365 }
366 }
367
368 if (!containsStar) {
369
370 if (patIdxEnd != strIdxEnd) {
371 return false;
372 }
373 for (int i = 0; i <= patIdxEnd; i++) {
374 ch = patArr[i];
375 if (ch != '?' && !equals(ch, strArr[i], isCaseSensitive)) {
376 return false;
377 }
378 }
379 return true;
380 }
381
382 if (patIdxEnd == 0) {
383 return true;
384 }
385
386
387
388 while ((ch = patArr[patIdxStart]) != '*' && strIdxStart <= strIdxEnd)
389
390 {
391 if (ch != '?' && !equals(ch, strArr[strIdxStart], isCaseSensitive)) {
392 return false;
393 }
394 patIdxStart++;
395 strIdxStart++;
396 }
397 if (strIdxStart > strIdxEnd) {
398
399
400 for (int i = patIdxStart; i <= patIdxEnd; i++) {
401 if (patArr[i] != '*') {
402 return false;
403 }
404 }
405 return true;
406 }
407
408
409
410 while ((ch = patArr[patIdxEnd]) != '*' && strIdxStart <= strIdxEnd)
411
412 {
413 if (ch != '?' && !equals(ch, strArr[strIdxEnd], isCaseSensitive)) {
414 return false;
415 }
416 patIdxEnd--;
417 strIdxEnd--;
418 }
419 if (strIdxStart > strIdxEnd) {
420
421
422 for (int i = patIdxStart; i <= patIdxEnd; i++) {
423 if (patArr[i] != '*') {
424 return false;
425 }
426 }
427 return true;
428 }
429
430
431
432 while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd) {
433 int patIdxTmp = -1;
434 for (int i = patIdxStart + 1; i <= patIdxEnd; i++) {
435 if (patArr[i] == '*') {
436 patIdxTmp = i;
437 break;
438 }
439 }
440 if (patIdxTmp == patIdxStart + 1) {
441
442 patIdxStart++;
443 continue;
444 }
445
446
447 int patLength = (patIdxTmp - patIdxStart - 1);
448 int strLength = (strIdxEnd - strIdxStart + 1);
449 int foundIdx = -1;
450 strLoop:
451 for (int i = 0; i <= strLength - patLength; i++) {
452 for (int j = 0; j < patLength; j++) {
453 ch = patArr[patIdxStart + j + 1];
454 if (ch != '?' && !equals(ch, strArr[strIdxStart + i + j], isCaseSensitive)) {
455 continue strLoop;
456 }
457 }
458
459 foundIdx = strIdxStart + i;
460 break;
461 }
462
463 if (foundIdx == -1) {
464 return false;
465 }
466
467 patIdxStart = patIdxTmp;
468 strIdxStart = foundIdx + patLength;
469 }
470
471
472
473 for (int i = patIdxStart; i <= patIdxEnd; i++) {
474 if (patArr[i] != '*') {
475 return false;
476 }
477 }
478 return true;
479 }
480
481
482
483
484 private static boolean equals(char c1, char c2, boolean isCaseSensitive) {
485 if (c1 == c2) {
486 return true;
487 }
488 if (!isCaseSensitive) {
489
490 if (Character.toUpperCase(c1) == Character.toUpperCase(c2)
491 || Character.toLowerCase(c1) == Character.toLowerCase(c2)) {
492 return true;
493 }
494 }
495 return false;
496 }
497
498
499
500
501
502
503
504
505
506 private static List<String> tokenizePath(String path, String separator) {
507 List<String> ret = new ArrayList<String>();
508 StringTokenizer st = new StringTokenizer(path, separator);
509 while (st.hasMoreTokens()) {
510 ret.add(st.nextToken());
511 }
512 return ret;
513 }
514
515 static boolean matchAntPathPatternStart(
516 @Nonnull MatchPattern pattern, @Nonnull String str, @Nonnull String separator, boolean isCaseSensitive) {
517 return !separatorPatternStartSlashMismatch(pattern, str, separator)
518 && matchAntPathPatternStart(pattern.getTokenizedPathString(), str, separator, isCaseSensitive);
519 }
520
521 private static String[] tokenizePathToString(@Nonnull String path, @Nonnull String separator) {
522 List<String> ret = new ArrayList<String>();
523 StringTokenizer st = new StringTokenizer(path, separator);
524 while (st.hasMoreTokens()) {
525 ret.add(st.nextToken());
526 }
527 return ret.toArray(new String[ret.size()]);
528 }
529
530 private static boolean matchAntPathPatternStart(
531 @Nonnull String[] patDirs, @Nonnull String str, @Nonnull String separator, boolean isCaseSensitive) {
532 String[] strDirs = tokenizePathToString(str, separator);
533 return matchAntPathPatternStart(patDirs, strDirs, isCaseSensitive);
534 }
535
536 private static boolean matchAntPathPatternStart(
537 @Nonnull String[] patDirs, @Nonnull String[] tokenizedFileName, boolean isCaseSensitive) {
538
539 int patIdxStart = 0;
540 int patIdxEnd = patDirs.length - 1;
541 int strIdxStart = 0;
542 int strIdxEnd = tokenizedFileName.length - 1;
543
544
545 while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) {
546 String patDir = patDirs[patIdxStart];
547 if (patDir.equals("**")) {
548 break;
549 }
550 if (!match(patDir, tokenizedFileName[strIdxStart], isCaseSensitive)) {
551 return false;
552 }
553 patIdxStart++;
554 strIdxStart++;
555 }
556
557 return strIdxStart > strIdxEnd || patIdxStart <= patIdxEnd;
558 }
559
560 private static boolean separatorPatternStartSlashMismatch(
561 @Nonnull MatchPattern matchPattern, @Nonnull String str, @Nonnull String separator) {
562 return str.startsWith(separator) != matchPattern.startsWith(separator);
563 }
564
565 private static boolean separatorPatternStartSlashMismatch(String pattern, String str, String separator) {
566 return str.startsWith(separator) != pattern.startsWith(separator);
567 }
568
569 static boolean matchAntPathPattern(String[] patDirs, String[] strDirs, boolean isCaseSensitive) {
570 int patIdxStart = 0;
571 int patIdxEnd = patDirs.length - 1;
572 int strIdxStart = 0;
573 int strIdxEnd = strDirs.length - 1;
574
575
576 while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) {
577 String patDir = patDirs[patIdxStart];
578 if (patDir.equals("**")) {
579 break;
580 }
581 if (!match(patDir, strDirs[strIdxStart], isCaseSensitive)) {
582 return false;
583 }
584 patIdxStart++;
585 strIdxStart++;
586 }
587 if (strIdxStart > strIdxEnd) {
588
589 for (int i = patIdxStart; i <= patIdxEnd; i++) {
590 if (!patDirs[i].equals("**")) {
591 return false;
592 }
593 }
594 return true;
595 } else {
596 if (patIdxStart > patIdxEnd) {
597
598 return false;
599 }
600 }
601
602
603 while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) {
604 String patDir = patDirs[patIdxEnd];
605 if (patDir.equals("**")) {
606 break;
607 }
608 if (!match(patDir, strDirs[strIdxEnd], isCaseSensitive)) {
609 return false;
610 }
611 patIdxEnd--;
612 strIdxEnd--;
613 }
614 if (strIdxStart > strIdxEnd) {
615
616 for (int i = patIdxStart; i <= patIdxEnd; i++) {
617 if (!patDirs[i].equals("**")) {
618 return false;
619 }
620 }
621 return true;
622 }
623
624 while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd) {
625 int patIdxTmp = -1;
626 for (int i = patIdxStart + 1; i <= patIdxEnd; i++) {
627 if (patDirs[i].equals("**")) {
628 patIdxTmp = i;
629 break;
630 }
631 }
632 if (patIdxTmp == patIdxStart + 1) {
633
634 patIdxStart++;
635 continue;
636 }
637
638
639 int patLength = (patIdxTmp - patIdxStart - 1);
640 int strLength = (strIdxEnd - strIdxStart + 1);
641 int foundIdx = -1;
642 strLoop:
643 for (int i = 0; i <= strLength - patLength; i++) {
644 for (int j = 0; j < patLength; j++) {
645 String subPat = patDirs[patIdxStart + j + 1];
646 String subStr = strDirs[strIdxStart + i + j];
647 if (!match(subPat, subStr, isCaseSensitive)) {
648 continue strLoop;
649 }
650 }
651
652 foundIdx = strIdxStart + i;
653 break;
654 }
655
656 if (foundIdx == -1) {
657 return false;
658 }
659
660 patIdxStart = patIdxTmp;
661 strIdxStart = foundIdx + patLength;
662 }
663
664 for (int i = patIdxStart; i <= patIdxEnd; i++) {
665 if (!patDirs[i].equals("**")) {
666 return false;
667 }
668 }
669
670 return true;
671 }
672
673 static boolean isRegexPrefixedPattern(String pattern) {
674 return pattern.length() > (REGEX_HANDLER_PREFIX.length() + PATTERN_HANDLER_SUFFIX.length() + 1)
675 && pattern.startsWith(REGEX_HANDLER_PREFIX)
676 && pattern.endsWith(PATTERN_HANDLER_SUFFIX);
677 }
678
679 static boolean isAntPrefixedPattern(String pattern) {
680 return pattern.length() > (ANT_HANDLER_PREFIX.length() + PATTERN_HANDLER_SUFFIX.length() + 1)
681 && pattern.startsWith(ANT_HANDLER_PREFIX)
682 && pattern.endsWith(PATTERN_HANDLER_SUFFIX);
683 }
684
685 static boolean matchAntPathPattern(
686 @Nonnull MatchPattern matchPattern,
687 @Nonnull String str,
688 @Nonnull String separator,
689 boolean isCaseSensitive) {
690 if (separatorPatternStartSlashMismatch(matchPattern, str, separator)) {
691 return false;
692 }
693 String[] patDirs = matchPattern.getTokenizedPathString();
694 String[] strDirs = tokenizePathToString(str, separator);
695 return matchAntPathPattern(patDirs, strDirs, isCaseSensitive);
696 }
697 }