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