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