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 }