| // Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file | |
| // for details. All rights reserved. Use of this source code is governed by a | |
| // BSD-style license that can be found in the LICENSE file. | |
| package com.android.tools.r8.shaking; | |
| public class ProguardPackageMatcher { | |
| private final String pattern; | |
| public ProguardPackageMatcher(String pattern) { | |
| this.pattern = pattern; | |
| } | |
| public boolean matches(String packageName) { | |
| return matchPackageNameImpl(pattern, 0, packageName, 0); | |
| } | |
| private static boolean matchPackageNameImpl( | |
| String pattern, int patternIndex, String name, int nameIndex) { | |
| for (int i = patternIndex; i < pattern.length(); i++) { | |
| char patternChar = pattern.charAt(i); | |
| switch (patternChar) { | |
| case '*': | |
| int nextPatternIndex = i + 1; | |
| // Check for **. | |
| boolean includeSeparators = | |
| pattern.length() > (nextPatternIndex) && pattern.charAt(nextPatternIndex) == '*'; | |
| if (includeSeparators) { | |
| nextPatternIndex += 1; | |
| } | |
| // Fast cases for the common case where a pattern ends with '*' or '**'. | |
| if (nextPatternIndex == pattern.length()) { | |
| if (includeSeparators) { | |
| return true; | |
| } | |
| boolean hasSeparators = containsSeparatorsStartingAt(name, nameIndex); | |
| return !hasSeparators; | |
| } | |
| // Match the rest of the pattern against the (non-empty) rest of the class name. | |
| for (int nextNameIndex = nameIndex; nextNameIndex < name.length(); nextNameIndex++) { | |
| if (!includeSeparators) { | |
| // Stop at the first separator for just *. | |
| if (name.charAt(nextNameIndex) == '.') { | |
| return matchPackageNameImpl(pattern, nextPatternIndex, name, nextNameIndex); | |
| } | |
| } | |
| if (matchPackageNameImpl(pattern, nextPatternIndex, name, nextNameIndex)) { | |
| return true; | |
| } | |
| } | |
| // Finally, check the case where the '*' or '**' eats all of the package name. | |
| return matchPackageNameImpl(pattern, nextPatternIndex, name, name.length()); | |
| case '?': | |
| if (nameIndex == name.length() || name.charAt(nameIndex) == '.') { | |
| return false; | |
| } | |
| nameIndex++; | |
| break; | |
| default: | |
| if (nameIndex == name.length() || patternChar != name.charAt(nameIndex++)) { | |
| return false; | |
| } | |
| break; | |
| } | |
| } | |
| return nameIndex == name.length(); | |
| } | |
| private static boolean containsSeparatorsStartingAt(String className, int nameIndex) { | |
| return className.indexOf('.', nameIndex) != -1; | |
| } | |
| @Override | |
| public boolean equals(Object o) { | |
| if (this == o) { | |
| return true; | |
| } | |
| if (!(o instanceof ProguardPackageMatcher)) { | |
| return false; | |
| } | |
| ProguardPackageMatcher other = (ProguardPackageMatcher) o; | |
| return pattern.equals(other.pattern); | |
| } | |
| @Override | |
| public int hashCode() { | |
| return pattern.hashCode(); | |
| } | |
| } |