/******************************************************************************* * Copyright (c) 2006-2013 The RCP Company and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * The RCP Company - initial API and implementation *******************************************************************************/ package com.rcpcompany.uibindings.internal.utils; import java.util.HashMap; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import com.rcpcompany.uibindings.utils.IPathMatcher; /** * Implementation of {@link IPathMatcher}. * * @author Tonny Madsen, The RCP Company */ public class PathMatcher implements IPathMatcher { /** * Map with all matchers index by pattern. */ private static final Map<String, IPathMatcher> MATCHERS = new HashMap<String, IPathMatcher>(); /** * Returns an {@link IPathMatcher} for the specified pattern. * * @param pattern the pattern for the matcher * @return the matcher */ public static IPathMatcher getPathMatcher(String pattern) { IPathMatcher matcher = MATCHERS.get(pattern); if (matcher == null) { matcher = new PathMatcher(pattern); MATCHERS.put(pattern, matcher); } return matcher; } /** * Constructs and returns a new {@link IPathMatcher} for the specified pattern. * * @param pattern the pattern of this matcher */ public PathMatcher(String pattern) { String regexp = null; if (pattern.startsWith("glob:")) { regexp = translateGlob(pattern.substring("glob:".length())); } else if (pattern.startsWith("regex:")) { regexp = pattern.substring("regex:".length()); } else throw new IllegalArgumentException("Pattern must start with 'glob:' or 'regex:'. Was: '" + pattern + "'"); // LogUtils.debug(null, pattern + " -> " + regexp); myPattern = Pattern.compile(regexp, Pattern.CASE_INSENSITIVE); } /** * Translates a Glob pattern into a corresponding regexp. * * @param pattern the global pattern * @return the regexp pattern */ private String translateGlob(String pattern) { String p = pattern; // final char separator = File.separatorChar; /* * Translate all "\\" into "/", to make the rest easier */ p = p.replaceAll("\\\\", "/"); /* * "." -> "\." to get a verbatim match */ p = p.replaceAll("\\.", "\\\\."); /* * "?" -> "[^/]" */ p = p.replaceAll("[?]", "[^/]"); /* * "[!...]" -> "[^...]" */ p = p.replaceAll("^\\[!", "[^"); p = p.replaceAll("(?<!\\\\)\\[!", "[^"); /* * "*" -> "[^/]*" */ p = p.replaceAll("[*]", "[^/]*"); /* * "**" -> "[^/]*(/[^/]*)*" */ final String dss = "[^/]*(/[^/]*)*"; p = p.replace("[^/]*[^/]*", dss); /* * "/**" at the end of the string -> "([^/]*(/[^/]*)*)?" */ if (p.endsWith("/" + dss)) { p = p.substring(0, p.length() - dss.length() - 1) + "(" + dss + ")?"; } /* * "{...,...}" -> "(...|...)" - not suported yet */ // if (pattern.matches(pattern)) // pattern.replaceAll("\\*", ".*"); /* * No start separator: then we match both a file name and a path name with a matching last * part */ if (p.charAt(0) != '/') { p = "((/[^/]*)*/)?" + p; } /* * Translate all '/' to the native separator (if different from '/') */ // if (separator == '\\') { // For unknown reasons replaceAll does not do the trick for (int i = p.indexOf('/'); i >= 0; i = p.indexOf('/', i + 4)) { p = p.substring(0, i) + "[/\\\\]" + p.substring(i + 1); } for (int i = p.indexOf("[^[/\\\\]]"); i >= 0; i = p.indexOf("[^[/\\\\]]")) { p = p.substring(0, i) + "[^/\\\\]" + p.substring(i + 8); } // } else if (separator != '/') { // p = p.replace('/', separator); // } /* * For Windows (separator == '\'), add drive letter and network drive support */ // if (separator == '\\') { p = "([a-z]:|[/\\\\][^/\\\\]+)?" + p; // } // LogUtils.debug(this, "translate '" + pattern + "' -> '" + p + "'"); return p; } private final Pattern myPattern; @Override public boolean matches(String path) { return myPattern.matcher(path).matches(); } @Override public boolean partiallyMatches(String path) { final Matcher matcher = myPattern.matcher(path); return matcher.matches() || matcher.hitEnd(); } }