Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright (c) 2011-2013 The original author or authors
* ------------------------------------------------------
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Apache License v2.0 which accompanies this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* The Apache License v2.0 is available at
* http://www.opensource.org/licenses/apache2.0.php
*
* You may elect to redistribute this code under either of these licenses.
*/
package io.vertx.core.impl.launcher.commands;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
/**
* Utility methods to test path matching. This is used by the {@link Watcher} to determine whether or not a file
* triggers a redeployment.
*
* @author Clement Escoffier
*/
public final class FileSelector {
/**
* When the pattern starts with a {@link File#separator}, {@code str} has to start with a {@link File#separator}.
*
* @return {@code true} when @{code str} starts with a {@link File#separator}, and {@code pattern} starts with a
* {@link File#separator}.
*/
private static boolean separatorPatternStartSlashMismatch(String pattern, String str, String separator) {
return str.startsWith(separator) != pattern.startsWith(separator);
}
/**
* Tests whether or not a given path matches a given pattern.
*
* @param pattern The pattern to match against. Must not be
* {@code null}.
* @param str The path to match, as a String. Must not be
* {@code null}.
* @return {@code true} if the pattern matches against the string,
* or {@code false} otherwise.
*/
public static boolean matchPath(String pattern, String str) {
return matchPath(pattern, str, true);
}
/**
* Tests whether or not a given path matches a given pattern.
*
* @param pattern The pattern to match against. Must not be
* {@code null}.
* @param str The path to match, as a String. Must not be
* {@code null}.
* @param isCaseSensitive Whether or not matching should be performed
* case sensitively.
* @return {@code true} if the pattern matches against the string,
* or {@code false} otherwise.
*/
public static boolean matchPath(String pattern, String str, boolean isCaseSensitive) {
return matchPath(pattern, str, File.separator, isCaseSensitive);
}
protected static boolean matchPath(String pattern, String str, String separator, boolean isCaseSensitive) {
return matchPathPattern(pattern, str, separator, isCaseSensitive);
}
private static boolean matchPathPattern(String pattern, String str, String separator, boolean isCaseSensitive) {
if (separatorPatternStartSlashMismatch(pattern, str, separator)) {
return false;
}
String[] patDirs = tokenizePathToString(pattern, separator);
String[] strDirs = tokenizePathToString(str, separator);
return matchPathPattern(patDirs, strDirs, isCaseSensitive);
}
private static boolean matchPathPattern(String[] patDirs, String[] strDirs, boolean isCaseSensitive) {
int patIdxStart = 0;
int patIdxEnd = patDirs.length - 1;
int strIdxStart = 0;
int strIdxEnd = strDirs.length - 1;
// up to first '**'
while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) {
String patDir = patDirs[patIdxStart];
if (patDir.equals("**")) {
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 (!patDirs[i].equals("**")) {
return false;
}
}
return true;
} else {
if (patIdxStart > patIdxEnd) {
// String not exhausted, but pattern is. Failure.
return false;
}
}
// up to last '**'
while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) {
String patDir = patDirs[patIdxEnd];
if (patDir.equals("**")) {
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 (!patDirs[i].equals("**")) {
return false;
}
}
return true;
}
while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd) {
int patIdxTmp = -1;
for (int i = patIdxStart + 1; i <= patIdxEnd; i++) {
if (patDirs[i].equals("**")) {
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 = patDirs[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 (!patDirs[i].equals("**")) {
return false;
}
}
return true;
}
/**
* Tests whether or not a string matches against a pattern.
* The pattern may contain two special characters:
* '*' means zero or more characters
* '?' means one and only one character
*
* @param pattern The pattern to match against.
* Must not be{@code null}.
* @param str The string which must be matched against the pattern.
* Must not be{@code null}.
* @return {@code true} if the string matches against the pattern,
* or {@code false} 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:
* '*' means zero or more characters
* '?' means one and only one character
*
* @param pattern The pattern to match against.
* Must not be{@code null}.
* @param str The string which must be matched against the pattern.
* Must not be{@code null}.
* @param isCaseSensitive Whether or not matching should be performed
* case sensitively.
* @return {@code true} if the string matches against the pattern,
* or {@code false} otherwise.
*/
public static boolean match(String pattern, String str, boolean isCaseSensitive) {
char[] patArr = pattern.toCharArray();
char[] strArr = str.toCharArray();
return match(patArr, strArr, isCaseSensitive);
}
private static boolean match(char[] patArr, char[] strArr, boolean isCaseSensitive) {
int patIdxStart = 0;
int patIdxEnd = patArr.length - 1;
int strIdxStart = 0;
int strIdxEnd = strArr.length - 1;
char ch;
boolean containsStar = false;
for (char aPatArr : patArr) {
if (aPatArr == '*') {
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++) {
ch = patArr[i];
if (ch != '?' && !equals(ch, strArr[i], isCaseSensitive)) {
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 ((ch = patArr[patIdxStart]) != '*' && strIdxStart <= strIdxEnd) {
if (ch != '?' && !equals(ch, strArr[strIdxStart], isCaseSensitive)) {
return false; // Character mismatch
}
patIdxStart++;
strIdxStart++;
}
if (strIdxStart > strIdxEnd) {
return checkOnlyStartsLeft(patArr, patIdxStart, patIdxEnd);
}
// Process characters after last star
while ((ch = patArr[patIdxEnd]) != '*' && strIdxStart <= strIdxEnd) {
if (ch != '?' && !equals(ch, strArr[strIdxEnd], isCaseSensitive)) {
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 checkOnlyStartsLeft(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++) {
ch = patArr[patIdxStart + j + 1];
if (ch != '?' && !equals(ch, strArr[strIdxStart + i + j], isCaseSensitive)) {
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 checkOnlyStartsLeft(patArr, patIdxStart, patIdxEnd);
}
private static boolean checkOnlyStartsLeft(char[] patArr, int patIdxStart, int patIdxEnd) {
// All characters in the string are used. Check if only '*'s are
// left in the pattern. If so, we succeeded. Otherwise failure.
for (int i = patIdxStart; i <= patIdxEnd; i++) {
if (patArr[i] != '*') {
return false;
}
}
return true;
}
/**
* Tests whether two characters are equal.
*/
private static boolean equals(char c1, char c2, boolean isCaseSensitive) {
if (c1 == c2) {
return true;
}
if (!isCaseSensitive) {
// NOTE: Try both upper case and lower case as done by String.equalsIgnoreCase()
if (Character.toUpperCase(c1) == Character.toUpperCase(c2)
|| Character.toLowerCase(c1) == Character.toLowerCase(c2)) {
return true;
}
}
return false;
}
private static String[] tokenizePathToString(String path, String separator) {
List ret = new ArrayList<>();
StringTokenizer st = new StringTokenizer(path, separator);
while (st.hasMoreTokens()) {
ret.add(st.nextToken());
}
return ret.toArray(new String[ret.size()]);
}
}