+++ /dev/null
-package org.apache.archiva.configuration.util;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.io.File;
-import java.nio.file.InvalidPathException;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-
-/**
- *
- * This provides a path matcher like in the SelectorUtils of the ant project.
- *
- * Using code from apache ant org.apache.tools.ant.types.selectors.SelectorUtils to remove the ant dependency for code
- * compilation.
- * See https://github.com/apache/ant/blob/master/src/main/org/apache/tools/ant/types/selectors/SelectorUtils.java
- *
- * @author Martin Stockhammer <martin_s@apache.org>
- *
- *
- */
-public class PathMatcher
-{
-
- private static final String DEEP_TREE_MATCH = "**";
-
-
- /**
- * Tests whether or not a string matches against a pattern.
- * The pattern may contain two special characters:<br>
- * '*' means zero or more characters<br>
- * '?' means one and only one character
- *
- * @param pattern The pattern to match against.
- * Must not be <code>null</code>.
- * @param str The string which must be matched against the pattern.
- * Must not be <code>null</code>.
- *
- * @return <code>true</code> if the string matches against the pattern,
- * or <code>false</code> otherwise.
- */
- public static boolean match(String pattern, String str) {
- return match(pattern, str, true);
- }
-
-
- /**
- * Tests whether or not a string matches against a pattern.
- * The pattern may contain two special characters:<br>
- * '*' means zero or more characters<br>
- * '?' means one and only one character
- *
- * @param pattern The pattern to match against.
- * Must not be <code>null</code>.
- * @param str The string which must be matched against the pattern.
- * Must not be <code>null</code>.
- * @param caseSensitive Whether or not matching should be performed
- * case sensitively.
- *
- *
- * @return <code>true</code> if the string matches against the pattern,
- * or <code>false</code> otherwise.
- */
- public static boolean match(String pattern, String str,
- boolean caseSensitive) {
- char[] patArr = pattern.toCharArray();
- char[] strArr = str.toCharArray();
- int patIdxStart = 0;
- int patIdxEnd = patArr.length - 1;
- int strIdxStart = 0;
- int strIdxEnd = strArr.length - 1;
-
- boolean containsStar = false;
- for (char ch : patArr) {
- if (ch == '*') {
- containsStar = true;
- break;
- }
- }
-
- if (!containsStar) {
- // No '*'s, so we make a shortcut
- if (patIdxEnd != strIdxEnd) {
- return false; // Pattern and string do not have the same size
- }
- for (int i = 0; i <= patIdxEnd; i++) {
- char ch = patArr[i];
- if (ch != '?' && different(caseSensitive, ch, strArr[i])) {
- return false; // Character mismatch
- }
- }
- return true; // String matches against pattern
- }
-
- if (patIdxEnd == 0) {
- return true; // Pattern contains only '*', which matches anything
- }
-
- // Process characters before first star
- while (true) {
- char ch = patArr[patIdxStart];
- if (ch == '*' || strIdxStart > strIdxEnd) {
- break;
- }
- if (ch != '?'
- && different(caseSensitive, ch, strArr[strIdxStart])) {
- return false; // Character mismatch
- }
- patIdxStart++;
- strIdxStart++;
- }
- if (strIdxStart > strIdxEnd) {
- // All characters in the string are used. Check if only '*'s are
- // left in the pattern. If so, we succeeded. Otherwise failure.
- return allStars(patArr, patIdxStart, patIdxEnd);
- }
-
- // Process characters after last star
- while (true) {
- char ch = patArr[patIdxEnd];
- if (ch == '*' || strIdxStart > strIdxEnd) {
- break;
- }
- if (ch != '?' && different(caseSensitive, ch, strArr[strIdxEnd])) {
- return false; // Character mismatch
- }
- patIdxEnd--;
- strIdxEnd--;
- }
- if (strIdxStart > strIdxEnd) {
- // All characters in the string are used. Check if only '*'s are
- // left in the pattern. If so, we succeeded. Otherwise failure.
- return allStars(patArr, patIdxStart, patIdxEnd);
- }
-
- // process pattern between stars. padIdxStart and patIdxEnd point
- // always to a '*'.
- while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd) {
- int patIdxTmp = -1;
- for (int i = patIdxStart + 1; i <= patIdxEnd; i++) {
- if (patArr[i] == '*') {
- patIdxTmp = i;
- break;
- }
- }
- if (patIdxTmp == patIdxStart + 1) {
- // Two stars next to each other, skip the first one.
- patIdxStart++;
- continue;
- }
- // Find the pattern between padIdxStart & padIdxTmp in str between
- // strIdxStart & strIdxEnd
- int patLength = (patIdxTmp - patIdxStart - 1);
- int strLength = (strIdxEnd - strIdxStart + 1);
- int foundIdx = -1;
- strLoop:
- for (int i = 0; i <= strLength - patLength; i++) {
- for (int j = 0; j < patLength; j++) {
- char ch = patArr[patIdxStart + j + 1];
- if (ch != '?' && different(caseSensitive, ch,
- strArr[strIdxStart + i + j])) {
- continue strLoop;
- }
- }
- foundIdx = strIdxStart + i;
- break;
- }
-
- if (foundIdx == -1) {
- return false;
- }
- patIdxStart = patIdxTmp;
- strIdxStart = foundIdx + patLength;
- }
-
- // All characters in the string are used. Check if only '*'s are left
- // in the pattern. If so, we succeeded. Otherwise failure.
- return allStars(patArr, patIdxStart, patIdxEnd);
- }
-
- private static boolean allStars(char[] chars, int start, int end) {
- for (int i = start; i <= end; ++i) {
- if (chars[i] != '*') {
- return false;
- }
- }
- return true;
- }
-
- private static boolean different(
- boolean caseSensitive, char ch, char other) {
- return caseSensitive
- ? ch != other
- : Character.toUpperCase(ch) != Character.toUpperCase(other);
- }
-
- /**
- * Tests whether or not a given path matches a given pattern.
- *
- * If you need to call this method multiple times with the same
- * pattern you should rather use TokenizedPath
- *
- *
- * @param pattern The pattern to match against. Must not be
- * <code>null</code>.
- * @param str The path to match, as a String. Must not be
- * <code>null</code>.
- *
- * @return <code>true</code> if the pattern matches against the string,
- * or <code>false</code> otherwise.
- */
- public static boolean matchPath(String pattern, String str) {
- String[] patDirs = tokenizePathAsArray( pattern, false );
- return matchPath(patDirs, tokenizePathAsArray( str, true ), true);
- }
-
- /**
- * Tests whether or not a given path matches a given pattern.
- *
- * If you need to call this method multiple times with the same
- * pattern you should rather use TokenizedPattern
- *
- * @param pattern The pattern to match against. Must not be
- * <code>null</code>.
- * @param str The path to match, as a String. Must not be
- * <code>null</code>.
- * @param isCaseSensitive Whether or not matching should be performed
- * case sensitively.
- *
- * @return <code>true</code> if the pattern matches against the string,
- * or <code>false</code> otherwise.
- */
- public static boolean matchPath(String pattern, String str,
- boolean isCaseSensitive) {
- String[] patDirs = tokenizePathAsArray( pattern, false );
- return matchPath(patDirs, tokenizePathAsArray( str, false ), isCaseSensitive);
- }
-
- /**
- *
- * @param path
- * @param osspecific
- * @return
- */
- static String[] tokenizePathAsArray(String path, boolean osSpecific) {
- Path root = null;
- try
- {
- Path fsPath = Paths.get( path );
- if ( fsPath.isAbsolute() ) {
- root = fsPath.getRoot();
- path = root.relativize( fsPath ).toString();
- }
- } catch (InvalidPathException ipe )
- {
- // invalid path, windauze hate **/*
- }
- char sep = osSpecific ? File.separatorChar : '/';
- int start = 0;
- int len = path.length();
- int count = 0;
- for (int pos = 0; pos < len; pos++) {
- if (path.charAt(pos) == sep) {
- if (pos != start) {
- count++;
- }
- start = pos + 1;
- }
- }
- if (len != start) {
- count++;
- }
- String[] l = new String[count + ((root == null) ? 0 : 1)];
-
- if (root != null) {
- l[0] = root.toString();
- count = 1;
- } else {
- count = 0;
- }
- start = 0;
- for (int pos = 0; pos < len; pos++) {
- if (path.charAt(pos) == sep) {
- if (pos != start) {
- String tok = path.substring(start, pos);
- l[count++] = tok;
- }
- start = pos + 1;
- }
- }
- if (len != start) {
- String tok = path.substring(start);
- l[count/*++*/] = tok;
- }
- return l;
- }
-
- /**
- * Core implementation of matchPath. It is isolated so that it
- * can be called from TokenizedPattern.
- */
- public static boolean matchPath( String[] tokenizedPattern, String[] strDirs,
- boolean isCaseSensitive ) {
- int patIdxStart = 0;
- int patIdxEnd = tokenizedPattern.length - 1;
- int strIdxStart = 0;
- int strIdxEnd = strDirs.length - 1;
-
- // up to first '**'
- while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) {
- String patDir = tokenizedPattern[patIdxStart];
- if (patDir.equals(DEEP_TREE_MATCH)) {
- break;
- }
- if (!match(patDir, strDirs[strIdxStart], isCaseSensitive)) {
- return false;
- }
- patIdxStart++;
- strIdxStart++;
- }
- if (strIdxStart > strIdxEnd) {
- // String is exhausted
- for (int i = patIdxStart; i <= patIdxEnd; i++) {
- if (!tokenizedPattern[i].equals(DEEP_TREE_MATCH)) {
- return false;
- }
- }
- return true;
- }
- if (patIdxStart > patIdxEnd) {
- // String not exhausted, but pattern is. Failure.
- return false;
- }
-
- // up to last '**'
- while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) {
- String patDir = tokenizedPattern[patIdxEnd];
- if (patDir.equals(DEEP_TREE_MATCH)) {
- break;
- }
- if (!match(patDir, strDirs[strIdxEnd], isCaseSensitive)) {
- return false;
- }
- patIdxEnd--;
- strIdxEnd--;
- }
- if (strIdxStart > strIdxEnd) {
- // String is exhausted
- for (int i = patIdxStart; i <= patIdxEnd; i++) {
- if (!tokenizedPattern[i].equals(DEEP_TREE_MATCH)) {
- return false;
- }
- }
- return true;
- }
-
- while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd) {
- int patIdxTmp = -1;
- for (int i = patIdxStart + 1; i <= patIdxEnd; i++) {
- if (tokenizedPattern[i].equals(DEEP_TREE_MATCH)) {
- patIdxTmp = i;
- break;
- }
- }
- if (patIdxTmp == patIdxStart + 1) {
- // '**/**' situation, so skip one
- patIdxStart++;
- continue;
- }
- // Find the pattern between padIdxStart & padIdxTmp in str between
- // strIdxStart & strIdxEnd
- int patLength = (patIdxTmp - patIdxStart - 1);
- int strLength = (strIdxEnd - strIdxStart + 1);
- int foundIdx = -1;
- strLoop:
- for (int i = 0; i <= strLength - patLength; i++) {
- for (int j = 0; j < patLength; j++) {
- String subPat = tokenizedPattern[patIdxStart + j + 1];
- String subStr = strDirs[strIdxStart + i + j];
- if (!match(subPat, subStr, isCaseSensitive)) {
- continue strLoop;
- }
- }
- foundIdx = strIdxStart + i;
- break;
- }
- if (foundIdx == -1) {
- return false;
- }
-
- patIdxStart = patIdxTmp;
- strIdxStart = foundIdx + patLength;
- }
-
- for (int i = patIdxStart; i <= patIdxEnd; i++) {
- if (!DEEP_TREE_MATCH.equals(tokenizedPattern[i])) {
- return false;
- }
- }
- return true;
- }
-
-
-}