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