All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.day.text.GlobPattern Maven / Gradle / Ivy

/*************************************************************************
 *
 * ADOBE CONFIDENTIAL
 * __________________
 *
 *  Copyright 2012 Adobe Systems Incorporated
 *  All Rights Reserved.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of Adobe Systems Incorporated and its suppliers,
 * if any.  The intellectual and technical concepts contained
 * herein are proprietary to Adobe Systems Incorporated and its
 * suppliers and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from Adobe Systems Incorporated.
 **************************************************************************/
package com.day.text;

/**
 * The GlobPattern implements matching operations that do a
 * pattern globbing.
 */
public class GlobPattern {

    /** Pattern strings should be compared to.  */
    private final String pattern;

    /** if this is present, use for handle comparison (acl) */
    private final String handlePattern;

    /**
     * Class constructor that create a GlobPattern with the given
     * pattern. If the ishandle flag is true this
     * will construct a hierarchy matcher.
     *
     * @param pattern  pattern string
     * @param ishandle if true and the pattern contains no
     *                 wildcards, the {@link #matches(String)} returns true, if
     *                 the compared string is equal or starts with the
     *                 pattern+"/" (i.e. is a child page)
     */
    public GlobPattern(String pattern, boolean ishandle) {
	this.pattern = pattern;
        if (ishandle && !containsWildcards(pattern)) {
            handlePattern = (pattern.equals("/")) ? "/" : pattern + '/';
        } else {
	    handlePattern = null;
	}
    }

    /**
     * Class constructor that create a GlobPattern with the given
     * pattern.
     *
     * @param pattern  pattern string
     */
    public GlobPattern(String pattern) {
        this(pattern, false);
    }

    /**
     * Returns a flag indicating whether a string matches this pattern.
     *
     * @param s string to be checked
     * @return  true if s matches this pattern, else
     *          false.
     */
    public final boolean matches(String s) {
        if (handlePattern != null) {
            // do handle comparison
            if (pattern.equals(s)) return true;
            return s.startsWith(handlePattern);
        }
	return recurseMatchPattern(pattern, s, 0, 0);
    }

    /**
     * Returns a flag indicating whether a string matches a pattern.
     *
     * @param pattern pattern used for comparison
     * @param s       string to be checked
     * @return        true if s matches pattern,
     *                else false.
     */
    public static final boolean matches(String pattern, String s) {
	return recurseMatchPattern(pattern, s, 0, 0);
    }

    /**
     * Returns a flag indicating whether a string matches a pattern. if the
     * ishandle is true and the pattern contains
     * no wildcards, the method returns true, if the pattern is a hierarchical
     * father of the string.
     *
     * @param pattern  pattern used for comparison
     * @param s        string to be checked
     * @param ishandle flag, indicating, if a handle comparison has to be
     *                 performed
     * @return         true if s matches pattern,
     *                 else false.
     */
    public static final boolean matches(String pattern, String s,
        boolean ishandle) {

        if (ishandle && !containsWildcards(pattern)) {
            if (pattern.equals(s)) {
                return true;
            }
            return s.startsWith(pattern + '/');
        }
        return GlobPattern.matches(pattern, s);
    }

    /**
     * Returns a flag indicating whether a string matches a pattern. unlike the
     * matches methods, this matching is done shell-like.
     *
     * @param s string to be checked
     *
     * @return true if the string matches shell-like;
     *         false otherwise.
     */
    public boolean shellMatches(String s) {
        return shellMatches(s, '/');
    }

    /**
     * Returns a flag indicating whether a string matches a pattern. unlike the
     * matches methods, this matching is done shell-like.
     *
     * @param s string to be checked
     * @param c character to be used as path delimiter
     *
     * @return true if the string matches shell-like;
     *         false otherwise.
     */
    public boolean shellMatches(String s, char c) {
        if (pattern.equals("*")) return true;
        int sc = 0;
        for (int len = s.length() - 1; len >= 0; len--)
            if (s.charAt(len) == c) sc++;
        for (int len = pattern.length() - 1; len >= 0; len--)
            if (pattern.charAt(len) == c) sc--;
        if (sc != 0) return false;
        return matches(s);
    }

    /**
     * Returns true if the string contains wildcards.
     *
     * @param s string to be checked
     * @return  true if s contains wildcards, else
     *          false.
     */
    public static final boolean containsWildcards(String s) {
        return indexOfWildcard(s) >= 0;
    }

    /**
     * Returns the index of the first wildcard character in the string or
     * -1 if the string does not contain a wild card character.
     *
     * @param s string to be checked
     */
    public static final int indexOfWildcard(String s) {
        for (int i = 0; i < s.length(); i++) {
            if ("*?[]".indexOf(s.charAt(i)) != -1) {
                return i;
            }
        }

        // not found, return -1
        return -1;
    }

    /**
     * An internal routine to implement expression matching.
     * This routine is based on a self-recursive algorithm.
     *
     * @param pattern The pattern
     * @param s    The string to be compared.
     * @param sIdx The index of where we are in string.
     * @param pIdx The index of where we are in pattern.
     * @return     True if string matched pattern, else false.
     */
    private static boolean recurseMatchPattern(String pattern, String s,
            int sIdx, int pIdx) {
	int pLen = pattern.length();
	int sLen = s.length();

	for (;;) {
	    if (pIdx >= pLen) {
		return (sIdx >= sLen);
	    }
	    if (sIdx >= sLen && pattern.charAt(pIdx) != '*') {
		return false;
	    }

	    // Check for a '*' as the next pattern char.
	    // This is handled by a recursive call for
	    // each postfix of the name.
	    if (pattern.charAt(pIdx) == '*') {
		if (++pIdx >= pLen) {
		    return true;
		}

		for (;;) {
		    if (recurseMatchPattern(pattern, s, sIdx, pIdx)) {
			return true;
		    }
		    if (sIdx >= sLen) {
			return false;
		    }
		    ++sIdx;
		}
	    }

	    // Check for '?' as the next pattern char.
	    // This matches the current character.
	    if (pattern.charAt(pIdx) == '?') {
		++pIdx;
		++sIdx;
		continue;
	    }

	    // Check for '[' as the next pattern char.
	    // This is a list of acceptable characters,
	    // which can include character ranges.
	    if (pattern.charAt(pIdx) == '[') {
		for (++pIdx ; ; ++pIdx) {
		    if (pIdx >= pLen || pattern.charAt(pIdx) == ']') {
			return false;
		    }
		    if (pattern.charAt(pIdx) == s.charAt(sIdx) ) {
			break;
		    }

		    if (pIdx < (pLen - 1)
			    && pattern.charAt(pIdx + 1) == '-') {
			if (pIdx >= (pLen - 2)) {
			    return false;
			}

			char chStr  = s.charAt(sIdx);
			char chPtn  = pattern.charAt(pIdx);
			char chPtn2 = pattern.charAt(pIdx+2);

			if ((chPtn <= chStr) && (chPtn2 >= chStr)) {
			    break;
			}
			if ((chPtn >= chStr) && (chPtn2 <= chStr)) {
			    break;
			}
			pIdx += 2;
		    }
		}

		for ( ; pattern.charAt(pIdx) != ']'; ++pIdx) {
		    if (pIdx >= pLen) {
			--pIdx;
			break;
		    }
		}

		++pIdx;
		++sIdx;
		continue;
	    }

	    // Check for backslash escapes
	    // We just skip over them to match the next char.
	    if (pattern.charAt(pIdx) == '\\' ) {
		if (++pIdx >= pLen) {
		    return false;
		}
	    }

	    if (pIdx < pLen && sIdx < sLen) {
		if (pattern.charAt(pIdx) != s.charAt(sIdx)) {
		    return false;
		}
	    }
	    ++pIdx;
	    ++sIdx;
	}
    }

    /**
     * Returns the pattern of this GlobPattern
     * @return the pattern.
     */
    public String toString() {
	return pattern;
    }

    /**
     * Returns true if this GlobPattern
     * is equal to object obj.
     *
     * @param obj the object to compare for equality.
     * @return true if this GlobPattern
     *   is equal to object obj.
     */
    public boolean equals(Object obj) {
	if (this == obj) {
	    return true;
	}
	if (obj instanceof GlobPattern) {
	    GlobPattern other = (GlobPattern)obj;
	    return (this.pattern.equals(other.pattern)
		    && this.isHandlePattern() == other.isHandlePattern());
	}
	return false;
    }

    /**
     * Returns the hashCode for this GlobPattern.
     * @return the hashCode for this GlobPattern.
     */
    public int hashCode() {
	return this.pattern.hashCode() + ((isHandlePattern()) ? 1 : 0);
    }

    /**
     * Returns true if this GlobPattern is a handle pattern.
     * @return true if this GlobPattern is a handle pattern;
     *   false otherwise.
     */
    private boolean isHandlePattern() {
	return handlePattern != null;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy