15716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet/* 25716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * Licensed to the Apache Software Foundation (ASF) under one or more 35716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * contributor license agreements. See the NOTICE file distributed with 45716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * this work for additional information regarding copyright ownership. 55716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * The ASF licenses this file to You under the Apache License, Version 2.0 65716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * (the "License"); you may not use this file except in compliance with 75716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * the License. You may obtain a copy of the License at 85716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * 95716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * http://www.apache.org/licenses/LICENSE-2.0 105716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * 115716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * Unless required by applicable law or agreed to in writing, software 125716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * distributed under the License is distributed on an "AS IS" BASIS, 135716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 145716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * See the License for the specific language governing permissions and 155716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * limitations under the License. 165716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * 175716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet */ 185716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet 195716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohetpackage org.apache.tools.ant.types.selectors; 205716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet 215716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohetimport org.apache.tools.ant.util.FileUtils; 225716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet 235716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohetimport java.io.File; 245716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohetimport java.util.StringTokenizer; 255716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohetimport java.util.Vector; 265716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet 275716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet/** 285716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * <p>This is a utility class used by selectors and DirectoryScanner. The 295716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * functionality more properly belongs just to selectors, but unfortunately 305716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * DirectoryScanner exposed these as protected methods. Thus we have to 315716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * support any subclasses of DirectoryScanner that may access these methods. 325716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * </p> 335716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * <p>This is a Singleton.</p> 345716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * 355716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * @since 1.5 365716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet */ 375716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohetpublic final class SelectorUtils { 385716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet 395716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet /** 405716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * The pattern that matches an arbitrary number of directories. 415716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * @since Ant 1.8.0 425716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet */ 435716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet public static final String DEEP_TREE_MATCH = "**"; 445716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet 455716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet private static final SelectorUtils instance = new SelectorUtils(); 465716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet private static final FileUtils FILE_UTILS = FileUtils.getFileUtils(); 475716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet 485716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet /** 495716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * Private Constructor 505716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet */ 515716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet private SelectorUtils() { 525716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 535716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet 545716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet /** 555716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * Retrieves the instance of the Singleton. 565716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * @return singleton instance 575716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet */ 585716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet public static SelectorUtils getInstance() { 595716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet return instance; 605716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 615716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet 625716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet /** 635716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * Tests whether or not a given path matches the start of a given 645716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * pattern up to the first "**". 655716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * <p> 665716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * This is not a general purpose test and should only be used if you 675716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * can live with false positives. For example, <code>pattern=**\a</code> 685716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * and <code>str=b</code> will yield <code>true</code>. 695716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * 705716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * @param pattern The pattern to match against. Must not be 715716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * <code>null</code>. 725716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * @param str The path to match, as a String. Must not be 735716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * <code>null</code>. 745716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * 755716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * @return whether or not a given path matches the start of a given 765716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * pattern up to the first "**". 775716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet */ 785716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet public static boolean matchPatternStart(String pattern, String str) { 795716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet return matchPatternStart(pattern, str, true); 805716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 815716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet 825716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet /** 835716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * Tests whether or not a given path matches the start of a given 845716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * pattern up to the first "**". 855716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * <p> 865716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * This is not a general purpose test and should only be used if you 875716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * can live with false positives. For example, <code>pattern=**\a</code> 885716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * and <code>str=b</code> will yield <code>true</code>. 895716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * 905716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * @param pattern The pattern to match against. Must not be 915716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * <code>null</code>. 925716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * @param str The path to match, as a String. Must not be 935716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * <code>null</code>. 945716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * @param isCaseSensitive Whether or not matching should be performed 955716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * case sensitively. 965716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * 975716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * @return whether or not a given path matches the start of a given 985716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * pattern up to the first "**". 995716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet */ 1005716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet public static boolean matchPatternStart(String pattern, String str, 1015716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet boolean isCaseSensitive) { 1025716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet // When str starts with a File.separator, pattern has to start with a 1035716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet // File.separator. 1045716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet // When pattern starts with a File.separator, str has to start with a 1055716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet // File.separator. 1065716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet if (str.startsWith(File.separator) 1075716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet != pattern.startsWith(File.separator)) { 1085716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet return false; 1095716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 1105716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet 1115716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet String[] patDirs = tokenizePathAsArray(pattern); 1125716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet String[] strDirs = tokenizePathAsArray(str); 1135716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet return matchPatternStart(patDirs, strDirs, isCaseSensitive); 1145716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 1155716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet 1165716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet 1175716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet /** 1185716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * Tests whether or not a given path matches the start of a given 1195716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * pattern up to the first "**". 1205716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * <p> 1215716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * This is not a general purpose test and should only be used if you 1225716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * can live with false positives. For example, <code>pattern=**\a</code> 1235716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * and <code>str=b</code> will yield <code>true</code>. 1245716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * 1255716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * @param patDirs The tokenized pattern to match against. Must not be 1265716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * <code>null</code>. 1275716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * @param strDirs The tokenized path to match. Must not be 1285716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * <code>null</code>. 1295716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * @param isCaseSensitive Whether or not matching should be performed 1305716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * case sensitively. 1315716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * 1325716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * @return whether or not a given path matches the start of a given 1335716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * pattern up to the first "**". 1345716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet */ 1355716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet static boolean matchPatternStart(String[] patDirs, String[] strDirs, 1365716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet boolean isCaseSensitive) { 1375716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet int patIdxStart = 0; 1385716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet int patIdxEnd = patDirs.length - 1; 1395716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet int strIdxStart = 0; 1405716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet int strIdxEnd = strDirs.length - 1; 1415716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet 1425716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet // up to first '**' 1435716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) { 1445716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet String patDir = patDirs[patIdxStart]; 1455716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet if (patDir.equals(DEEP_TREE_MATCH)) { 1465716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet break; 1475716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 1485716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet if (!match(patDir, strDirs[strIdxStart], isCaseSensitive)) { 1495716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet return false; 1505716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 1515716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet patIdxStart++; 1525716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet strIdxStart++; 1535716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 1545716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet 1555716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet // CheckStyle:SimplifyBooleanReturnCheck OFF 1565716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet // Check turned off as the code needs the comments for the various 1575716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet // code paths. 1585716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet if (strIdxStart > strIdxEnd) { 1595716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet // String is exhausted 1605716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet return true; 1615716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } else if (patIdxStart > patIdxEnd) { 1625716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet // String not exhausted, but pattern is. Failure. 1635716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet return false; 1645716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } else { 1655716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet // pattern now holds ** while string is not exhausted 1665716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet // this will generate false positives but we can live with that. 1675716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet return true; 1685716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 1695716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 1705716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet 1715716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet /** 1725716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * Tests whether or not a given path matches a given pattern. 1735716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * 1745716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * If you need to call this method multiple times with the same 1755716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * pattern you should rather use TokenizedPath 1765716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * 1775716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * @see TokenizedPath 1785716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * 1795716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * @param pattern The pattern to match against. Must not be 1805716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * <code>null</code>. 1815716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * @param str The path to match, as a String. Must not be 1825716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * <code>null</code>. 1835716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * 1845716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * @return <code>true</code> if the pattern matches against the string, 1855716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * or <code>false</code> otherwise. 1865716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet */ 1875716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet public static boolean matchPath(String pattern, String str) { 1885716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet String[] patDirs = tokenizePathAsArray(pattern); 1895716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet return matchPath(patDirs, tokenizePathAsArray(str), true); 1905716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 1915716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet 1925716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet /** 1935716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * Tests whether or not a given path matches a given pattern. 1945716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * 1955716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * If you need to call this method multiple times with the same 1965716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * pattern you should rather use TokenizedPattern 1975716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * 1985716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * @see TokenizedPattern 1995716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * 2005716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * @param pattern The pattern to match against. Must not be 2015716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * <code>null</code>. 2025716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * @param str The path to match, as a String. Must not be 2035716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * <code>null</code>. 2045716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * @param isCaseSensitive Whether or not matching should be performed 2055716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * case sensitively. 2065716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * 2075716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * @return <code>true</code> if the pattern matches against the string, 2085716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * or <code>false</code> otherwise. 2095716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet */ 2105716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet public static boolean matchPath(String pattern, String str, 2115716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet boolean isCaseSensitive) { 2125716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet String[] patDirs = tokenizePathAsArray(pattern); 2135716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet return matchPath(patDirs, tokenizePathAsArray(str), isCaseSensitive); 2145716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 2155716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet 2165716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet /** 2175716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * Core implementation of matchPath. It is isolated so that it 2185716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * can be called from TokenizedPattern. 2195716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet */ 2205716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet static boolean matchPath(String[] tokenizedPattern, String[] strDirs, 2215716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet boolean isCaseSensitive) { 2225716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet int patIdxStart = 0; 2235716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet int patIdxEnd = tokenizedPattern.length - 1; 2245716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet int strIdxStart = 0; 2255716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet int strIdxEnd = strDirs.length - 1; 2265716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet 2275716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet // up to first '**' 2285716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) { 2295716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet String patDir = tokenizedPattern[patIdxStart]; 2305716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet if (patDir.equals(DEEP_TREE_MATCH)) { 2315716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet break; 2325716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 2335716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet if (!match(patDir, strDirs[strIdxStart], isCaseSensitive)) { 2345716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet return false; 2355716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 2365716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet patIdxStart++; 2375716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet strIdxStart++; 2385716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 2395716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet if (strIdxStart > strIdxEnd) { 2405716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet // String is exhausted 2415716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet for (int i = patIdxStart; i <= patIdxEnd; i++) { 2425716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet if (!tokenizedPattern[i].equals(DEEP_TREE_MATCH)) { 2435716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet return false; 2445716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 2455716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 2465716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet return true; 2475716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } else { 2485716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet if (patIdxStart > patIdxEnd) { 2495716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet // String not exhausted, but pattern is. Failure. 2505716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet return false; 2515716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 2525716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 2535716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet 2545716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet // up to last '**' 2555716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) { 2565716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet String patDir = tokenizedPattern[patIdxEnd]; 2575716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet if (patDir.equals(DEEP_TREE_MATCH)) { 2585716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet break; 2595716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 2605716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet if (!match(patDir, strDirs[strIdxEnd], isCaseSensitive)) { 2615716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet return false; 2625716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 2635716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet patIdxEnd--; 2645716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet strIdxEnd--; 2655716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 2665716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet if (strIdxStart > strIdxEnd) { 2675716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet // String is exhausted 2685716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet for (int i = patIdxStart; i <= patIdxEnd; i++) { 2695716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet if (!tokenizedPattern[i].equals(DEEP_TREE_MATCH)) { 2705716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet return false; 2715716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 2725716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 2735716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet return true; 2745716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 2755716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet 2765716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd) { 2775716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet int patIdxTmp = -1; 2785716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet for (int i = patIdxStart + 1; i <= patIdxEnd; i++) { 2795716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet if (tokenizedPattern[i].equals(DEEP_TREE_MATCH)) { 2805716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet patIdxTmp = i; 2815716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet break; 2825716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 2835716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 2845716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet if (patIdxTmp == patIdxStart + 1) { 2855716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet // '**/**' situation, so skip one 2865716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet patIdxStart++; 2875716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet continue; 2885716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 2895716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet // Find the pattern between padIdxStart & padIdxTmp in str between 2905716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet // strIdxStart & strIdxEnd 2915716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet int patLength = (patIdxTmp - patIdxStart - 1); 2925716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet int strLength = (strIdxEnd - strIdxStart + 1); 2935716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet int foundIdx = -1; 2945716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet strLoop: 2955716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet for (int i = 0; i <= strLength - patLength; i++) { 2965716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet for (int j = 0; j < patLength; j++) { 2975716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet String subPat = tokenizedPattern[patIdxStart + j + 1]; 2985716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet String subStr = strDirs[strIdxStart + i + j]; 2995716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet if (!match(subPat, subStr, isCaseSensitive)) { 3005716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet continue strLoop; 3015716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 3025716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 3035716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet 3045716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet foundIdx = strIdxStart + i; 3055716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet break; 3065716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 3075716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet 3085716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet if (foundIdx == -1) { 3095716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet return false; 3105716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 3115716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet 3125716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet patIdxStart = patIdxTmp; 3135716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet strIdxStart = foundIdx + patLength; 3145716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 3155716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet 3165716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet for (int i = patIdxStart; i <= patIdxEnd; i++) { 3175716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet if (!tokenizedPattern[i].equals(DEEP_TREE_MATCH)) { 3185716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet return false; 3195716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 3205716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 3215716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet 3225716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet return true; 3235716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 3245716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet 3255716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet /** 3265716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * Tests whether or not a string matches against a pattern. 3275716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * The pattern may contain two special characters:<br> 3285716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * '*' means zero or more characters<br> 3295716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * '?' means one and only one character 3305716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * 3315716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * @param pattern The pattern to match against. 3325716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * Must not be <code>null</code>. 3335716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * @param str The string which must be matched against the pattern. 3345716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * Must not be <code>null</code>. 3355716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * 3365716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * @return <code>true</code> if the string matches against the pattern, 3375716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * or <code>false</code> otherwise. 3385716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet */ 3395716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet public static boolean match(String pattern, String str) { 3405716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet return match(pattern, str, true); 3415716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 3425716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet 3435716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet /** 3445716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * Tests whether or not a string matches against a pattern. 3455716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * The pattern may contain two special characters:<br> 3465716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * '*' means zero or more characters<br> 3475716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * '?' means one and only one character 3485716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * 3495716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * @param pattern The pattern to match against. 3505716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * Must not be <code>null</code>. 3515716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * @param str The string which must be matched against the pattern. 3525716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * Must not be <code>null</code>. 3535716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * @param caseSensitive Whether or not matching should be performed 3545716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * case sensitively. 3555716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * 3565716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * 3575716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * @return <code>true</code> if the string matches against the pattern, 3585716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * or <code>false</code> otherwise. 3595716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet */ 3605716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet public static boolean match(String pattern, String str, 3615716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet boolean caseSensitive) { 3625716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet char[] patArr = pattern.toCharArray(); 3635716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet char[] strArr = str.toCharArray(); 3645716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet int patIdxStart = 0; 3655716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet int patIdxEnd = patArr.length - 1; 3665716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet int strIdxStart = 0; 3675716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet int strIdxEnd = strArr.length - 1; 3685716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet char ch; 3695716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet 3705716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet boolean containsStar = false; 3715716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet for (int i = 0; i < patArr.length; i++) { 3725716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet if (patArr[i] == '*') { 3735716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet containsStar = true; 3745716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet break; 3755716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 3765716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 3775716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet 3785716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet if (!containsStar) { 3795716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet // No '*'s, so we make a shortcut 3805716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet if (patIdxEnd != strIdxEnd) { 3815716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet return false; // Pattern and string do not have the same size 3825716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 3835716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet for (int i = 0; i <= patIdxEnd; i++) { 3845716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet ch = patArr[i]; 3855716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet if (ch != '?') { 3865716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet if (different(caseSensitive, ch, strArr[i])) { 3875716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet return false; // Character mismatch 3885716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 3895716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 3905716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 3915716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet return true; // String matches against pattern 3925716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 3935716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet 3945716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet if (patIdxEnd == 0) { 3955716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet return true; // Pattern contains only '*', which matches anything 3965716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 3975716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet 3985716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet // Process characters before first star 3995716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet while (true) { 4005716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet ch = patArr[patIdxStart]; 4015716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet if (ch == '*' || strIdxStart > strIdxEnd) { 4025716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet break; 4035716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 4045716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet if (ch != '?') { 4055716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet if (different(caseSensitive, ch, strArr[strIdxStart])) { 4065716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet return false; // Character mismatch 4075716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 4085716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 4095716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet patIdxStart++; 4105716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet strIdxStart++; 4115716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 4125716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet if (strIdxStart > strIdxEnd) { 4135716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet // All characters in the string are used. Check if only '*'s are 4145716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet // left in the pattern. If so, we succeeded. Otherwise failure. 4155716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet return allStars(patArr, patIdxStart, patIdxEnd); 4165716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 4175716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet 4185716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet // Process characters after last star 4195716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet while (true) { 4205716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet ch = patArr[patIdxEnd]; 4215716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet if (ch == '*' || strIdxStart > strIdxEnd) { 4225716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet break; 4235716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 4245716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet if (ch != '?') { 4255716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet if (different(caseSensitive, ch, strArr[strIdxEnd])) { 4265716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet return false; // Character mismatch 4275716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 4285716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 4295716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet patIdxEnd--; 4305716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet strIdxEnd--; 4315716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 4325716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet if (strIdxStart > strIdxEnd) { 4335716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet // All characters in the string are used. Check if only '*'s are 4345716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet // left in the pattern. If so, we succeeded. Otherwise failure. 4355716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet return allStars(patArr, patIdxStart, patIdxEnd); 4365716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 4375716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet 4385716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet // process pattern between stars. padIdxStart and patIdxEnd point 4395716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet // always to a '*'. 4405716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd) { 4415716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet int patIdxTmp = -1; 4425716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet for (int i = patIdxStart + 1; i <= patIdxEnd; i++) { 4435716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet if (patArr[i] == '*') { 4445716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet patIdxTmp = i; 4455716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet break; 4465716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 4475716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 4485716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet if (patIdxTmp == patIdxStart + 1) { 4495716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet // Two stars next to each other, skip the first one. 4505716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet patIdxStart++; 4515716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet continue; 4525716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 4535716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet // Find the pattern between padIdxStart & padIdxTmp in str between 4545716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet // strIdxStart & strIdxEnd 4555716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet int patLength = (patIdxTmp - patIdxStart - 1); 4565716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet int strLength = (strIdxEnd - strIdxStart + 1); 4575716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet int foundIdx = -1; 4585716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet strLoop: 4595716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet for (int i = 0; i <= strLength - patLength; i++) { 4605716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet for (int j = 0; j < patLength; j++) { 4615716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet ch = patArr[patIdxStart + j + 1]; 4625716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet if (ch != '?') { 4635716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet if (different(caseSensitive, ch, 4645716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet strArr[strIdxStart + i + j])) { 4655716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet continue strLoop; 4665716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 4675716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 4685716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 4695716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet 4705716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet foundIdx = strIdxStart + i; 4715716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet break; 4725716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 4735716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet 4745716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet if (foundIdx == -1) { 4755716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet return false; 4765716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 4775716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet 4785716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet patIdxStart = patIdxTmp; 4795716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet strIdxStart = foundIdx + patLength; 4805716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 4815716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet 4825716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet // All characters in the string are used. Check if only '*'s are left 4835716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet // in the pattern. If so, we succeeded. Otherwise failure. 4845716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet return allStars(patArr, patIdxStart, patIdxEnd); 4855716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 4865716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet 4875716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet private static boolean allStars(char[] chars, int start, int end) { 4885716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet for (int i = start; i <= end; ++i) { 4895716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet if (chars[i] != '*') { 4905716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet return false; 4915716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 4925716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 4935716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet return true; 4945716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 4955716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet 4965716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet private static boolean different( 4975716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet boolean caseSensitive, char ch, char other) { 4985716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet return caseSensitive 4995716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet ? ch != other 5005716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet : Character.toUpperCase(ch) != Character.toUpperCase(other); 5015716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 5025716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet 5035716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet /** 5045716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * Breaks a path up into a Vector of path elements, tokenizing on 5055716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * <code>File.separator</code>. 5065716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * 5075716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * @param path Path to tokenize. Must not be <code>null</code>. 5085716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * 5095716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * @return a Vector of path elements from the tokenized path 5105716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet */ 5115716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet @SuppressWarnings("rawtypes") 5125716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet public static Vector tokenizePath (String path) { 5135716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet return tokenizePath(path, File.separator); 5145716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 5155716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet 5165716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet /** 5175716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * Breaks a path up into a Vector of path elements, tokenizing on 5185716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * 5195716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * @param path Path to tokenize. Must not be <code>null</code>. 5205716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * @param separator the separator against which to tokenize. 5215716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * 5225716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * @return a Vector of path elements from the tokenized path 5235716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * @since Ant 1.6 5245716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet */ 5255716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet @SuppressWarnings({ 5265716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet "rawtypes", "unchecked" 5275716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet }) 5285716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet public static Vector tokenizePath (String path, String separator) { 5295716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet Vector ret = new Vector(); 5305716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet if (FileUtils.isAbsolutePath(path)) { 5315716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet String[] s = FILE_UTILS.dissect(path); 5325716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet ret.add(s[0]); 5335716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet path = s[1]; 5345716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 5355716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet StringTokenizer st = new StringTokenizer(path, separator); 5365716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet while (st.hasMoreTokens()) { 5375716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet ret.addElement(st.nextToken()); 5385716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 5395716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet return ret; 5405716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 5415716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet 5425716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet /** 5435716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * Same as {@link #tokenizePath tokenizePath} but hopefully faster. 5445716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet */ 5455716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet /*package*/ static String[] tokenizePathAsArray(String path) { 5465716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet String root = null; 5475716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet if (FileUtils.isAbsolutePath(path)) { 5485716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet String[] s = FILE_UTILS.dissect(path); 5495716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet root = s[0]; 5505716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet path = s[1]; 5515716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 5525716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet char sep = File.separatorChar; 5535716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet int start = 0; 5545716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet int len = path.length(); 5555716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet int count = 0; 5565716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet for (int pos = 0; pos < len; pos++) { 5575716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet if (path.charAt(pos) == sep) { 5585716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet if (pos != start) { 5595716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet count++; 5605716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 5615716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet start = pos + 1; 5625716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 5635716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 5645716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet if (len != start) { 5655716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet count++; 5665716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 5675716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet String[] l = new String[count + ((root == null) ? 0 : 1)]; 5685716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet 5695716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet if (root != null) { 5705716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet l[0] = root; 5715716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet count = 1; 5725716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } else { 5735716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet count = 0; 5745716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 5755716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet start = 0; 5765716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet for (int pos = 0; pos < len; pos++) { 5775716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet if (path.charAt(pos) == sep) { 5785716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet if (pos != start) { 5795716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet String tok = path.substring(start, pos); 5805716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet l[count++] = tok; 5815716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 5825716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet start = pos + 1; 5835716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 5845716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 5855716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet if (len != start) { 5865716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet String tok = path.substring(start); 5875716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet l[count/*++*/] = tok; 5885716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 5895716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet return l; 5905716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 5915716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet 5925716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet /** 5935716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * Returns dependency information on these two files. If src has been 5945716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * modified later than target, it returns true. If target doesn't exist, 5955716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * it likewise returns true. Otherwise, target is newer than src and 5965716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * is not out of date, thus the method returns false. It also returns 5975716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * false if the src file doesn't even exist, since how could the 5985716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * target then be out of date. 5995716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * 6005716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * @param src the original file 6015716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * @param target the file being compared against 6025716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * @param granularity the amount in seconds of slack we will give in 6035716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * determining out of dateness 6045716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * @return whether the target is out of date 6055716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet */ 6065716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet public static boolean isOutOfDate(File src, File target, int granularity) { 6075716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet if (!src.exists()) { 6085716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet return false; 6095716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 6105716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet if (!target.exists()) { 6115716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet return true; 6125716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 6135716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet if ((src.lastModified() - granularity) > target.lastModified()) { 6145716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet return true; 6155716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 6165716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet return false; 6175716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 6185716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet 6195716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet /** 6205716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * "Flattens" a string by removing all whitespace (space, tab, linefeed, 6215716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * carriage return, and formfeed). This uses StringTokenizer and the 6225716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * default set of tokens as documented in the single arguement constructor. 6235716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * 6245716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * @param input a String to remove all whitespace. 6255716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * @return a String that has had all whitespace removed. 6265716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet */ 6275716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet public static String removeWhitespace(String input) { 6285716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet StringBuffer result = new StringBuffer(); 6295716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet if (input != null) { 6305716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet StringTokenizer st = new StringTokenizer(input); 6315716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet while (st.hasMoreTokens()) { 6325716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet result.append(st.nextToken()); 6335716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 6345716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 6355716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet return result.toString(); 6365716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 6375716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet 6385716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet /** 6395716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * Tests if a string contains stars or question marks 6405716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * @param input a String which one wants to test for containing wildcard 6415716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet * @return true if the string contains at least a star or a question mark 6425716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet */ 6435716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet public static boolean hasWildcards(String input) { 6445716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet return (input.indexOf('*') != -1 || input.indexOf('?') != -1); 6455716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet } 6465716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet} 6475716c15248acdb7dba42d951cf8273ee87cc6846Xavier Ducrohet 648