proguard.util.ClassNameParser Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of proguard-core Show documentation
Show all versions of proguard-core Show documentation
ProGuardCORE is a free library to read, analyze, modify, and write Java class files.
/*
* ProGuardCORE -- library to process Java bytecode.
*
* Copyright (c) 2002-2020 Guardsquare NV
*
* Licensed 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.
*/
package proguard.util;
import proguard.classfile.TypeConstants;
/**
* This {@link StringParser} can create {@link StringMatcher} instances for regular expressions
* matching internal class names (or descriptors containing class names).
* The regular expressions can contain the following wildcards:
* '%' for a single internal primitive type character (V, Z, B, C, S, I, F,
* J, or D),
* '?' for a single regular class name character,
* '*' for any number of regular class name characters,
* '**' for any number of regular class name characters or package separator
* characters ('/'),
* 'L***;' for a single internal type (class name or primitive type,
* array or non-array),
* 'L///;' for any number of internal types (class names and primitive
* types), and
* '' for a reference to an earlier wildcard (n = 1, 2, ...)
*
* @author Eric Lafortune
*/
public class ClassNameParser implements StringParser
{
private static final char[] PRIMITIVE_TYPES = new char[]
{
TypeConstants.VOID,
TypeConstants.BOOLEAN,
TypeConstants.BYTE,
TypeConstants.CHAR,
TypeConstants.SHORT,
TypeConstants.INT,
TypeConstants.LONG,
TypeConstants.FLOAT,
TypeConstants.DOUBLE,
};
private final WildcardManager wildcardManager;
/**
* Creates a new ClassNameParser.
*/
public ClassNameParser()
{
this(null);
}
/**
* Creates a new ClassNameParser that supports references to earlier
* wildcards.
*
* @param wildcardManager an optional scope for StringMatcher instances
* that match wildcards.
*/
public ClassNameParser(WildcardManager wildcardManager)
{
this.wildcardManager = wildcardManager;
}
// Implementations for StringParser.
public StringMatcher parse(String regularExpression)
{
int index;
StringMatcher nextMatcher = new EmptyStringMatcher();
// Look for wildcards.
for (index = 0; index < regularExpression.length(); index++)
{
// Is there an 'L///;' wildcard?
if (regularExpression.regionMatches(index, "L///;", 0, 5))
{
// Create a settable matcher so we can parse wildcards from
// left to right.
SettableMatcher settableMatcher = new SettableMatcher();
// Create a matcher for the wildcard.
VariableStringMatcher variableStringMatcher =
new VariableStringMatcher(null,
new char[] { TypeConstants.METHOD_ARGUMENTS_CLOSE },
0,
Integer.MAX_VALUE,
settableMatcher);
// Remember it so it can be referenced back.
if (wildcardManager != null)
{
wildcardManager.rememberVariableStringMatcher(variableStringMatcher);
}
// Recursively create a matcher for the rest of the string.
settableMatcher.setMatcher(parse(regularExpression.substring(index + 5)));
nextMatcher = variableStringMatcher;
break;
}
// Is there an 'L***;' wildcard?
else if (regularExpression.regionMatches(index, "L***;", 0, 5))
{
// Create a settable matcher so we can parse wildcards from
// left to right.
SettableMatcher settableMatcher = new SettableMatcher();
// Create a matcher for the wildcard.
// TODO: The returned variable matcher is actually a composite that doesn't return the entire matched string.
VariableStringMatcher variableStringMatcher =
createAnyTypeMatcher(settableMatcher);
// Remember it so it can be referenced back.
if (wildcardManager != null)
{
wildcardManager.rememberVariableStringMatcher(variableStringMatcher);
}
// Recursively create a matcher for the rest of the string.
settableMatcher.setMatcher(parse(regularExpression.substring(index + 5)));
nextMatcher = variableStringMatcher;
break;
}
// Is there a '**' wildcard?
else if (regularExpression.regionMatches(index, "**", 0, 2))
{
// Handle the end of the regular expression more efficiently,
// without any next matcher for the variable string matcher.
SettableMatcher settableMatcher =
index + 2 == regularExpression.length() ? null :
new SettableMatcher();
// Create a matcher for the wildcard.
VariableStringMatcher variableStringMatcher =
new VariableStringMatcher(null,
new char[] { TypeConstants.CLASS_END },
0,
Integer.MAX_VALUE,
settableMatcher);
// Remember it so it can be referenced back.
if (wildcardManager != null)
{
wildcardManager.rememberVariableStringMatcher(variableStringMatcher);
}
// Recursively create a matcher for the rest of the string.
if (settableMatcher != null)
{
settableMatcher.setMatcher(parse(regularExpression.substring(index + 2)));
}
nextMatcher = variableStringMatcher;
break;
}
// Is there a '*' wildcard?
else if (regularExpression.charAt(index) == '*')
{
// Create a settable matcher so we can parse wildcards from
// left to right.
SettableMatcher settableMatcher = new SettableMatcher();
// Create a matcher for the wildcard.
VariableStringMatcher variableStringMatcher =
new VariableStringMatcher(null,
new char[] { TypeConstants.CLASS_END, TypeConstants.PACKAGE_SEPARATOR },
0,
Integer.MAX_VALUE,
settableMatcher);
// Remember it so it can be referenced back.
if (wildcardManager != null)
{
wildcardManager.rememberVariableStringMatcher(variableStringMatcher);
}
// Recursively create a matcher for the rest of the string.
settableMatcher.setMatcher(parse(regularExpression.substring(index + 1)));
nextMatcher = variableStringMatcher;
break;
}
// Is there a '?' wildcard?
else if (regularExpression.charAt(index) == '?')
{
// Create a settable matcher so we can parse wildcards from
// left to right.
SettableMatcher settableMatcher = new SettableMatcher();
// Create a matcher for the wildcard.
VariableStringMatcher variableStringMatcher =
new VariableStringMatcher(null,
new char[] { TypeConstants.CLASS_END, TypeConstants.PACKAGE_SEPARATOR },
1,
1,
settableMatcher);
// Remember it so it can be referenced back.
if (wildcardManager != null)
{
wildcardManager.rememberVariableStringMatcher(variableStringMatcher);
}
// Recursively create a matcher for the rest of the string.
settableMatcher.setMatcher(parse(regularExpression.substring(index + 1)));
nextMatcher = variableStringMatcher;
break;
}
// Is there a '%' wildcard?
else if (regularExpression.charAt(index) == '%')
{
// Create a settable matcher so we can parse wildcards from
// left to right.
SettableMatcher settableMatcher = new SettableMatcher();
// Create a matcher for the wildcard.
VariableStringMatcher variableStringMatcher =
new VariableStringMatcher(PRIMITIVE_TYPES,
null,
1,
1,
settableMatcher);
// Remember it so it can be referenced back.
if (wildcardManager != null)
{
wildcardManager.rememberVariableStringMatcher(variableStringMatcher);
}
// Recursively create a matcher for the rest of the string.
settableMatcher.setMatcher(parse(regularExpression.substring(index + 1)));
nextMatcher = variableStringMatcher;
break;
}
// Is there a '' wildcard?
else if (wildcardManager != null)
{
int wildCardIndex = wildcardManager.wildCardIndex(regularExpression, index);
if (wildCardIndex >= 0)
{
// Find the index of the closing bracket again.
int closingIndex = regularExpression.indexOf('>', index + 1);
// Retrieve the specified variable string matcher and
// recursively create a matcher for the rest of the string.
nextMatcher = wildcardManager.createMatchedStringMatcher(
wildCardIndex,
parse(regularExpression.substring(closingIndex + 1)));
break;
}
}
}
// Return a matcher for the fixed first part of the regular expression,
// if any, and the remainder.
return index != 0 ?
new FixedStringMatcher(regularExpression.substring(0, index), nextMatcher) :
nextMatcher;
}
// Small utility methods.
/**
* Creates a StringMatcher that matches any type (class or primitive type,
* array or non-array) and then the given matcher.
*/
private VariableStringMatcher createAnyTypeMatcher(StringMatcher nextMatcher)
{
return
// Any number of '['.
new VariableStringMatcher(new char[] { TypeConstants.ARRAY },
null,
0,
255,
// Followed by:
new OrMatcher(
// A primitive type.
new VariableStringMatcher(PRIMITIVE_TYPES,
null,
1,
1,
nextMatcher),
// Or a class type.
new VariableStringMatcher(new char[] { TypeConstants.CLASS_START },
null,
1,
1,
new VariableStringMatcher(null,
new char[] { TypeConstants.CLASS_END },
0,
Integer.MAX_VALUE,
new VariableStringMatcher(new char[] { TypeConstants.CLASS_END },
null,
1,
1,
nextMatcher)))));
}
/**
* A main method for testing class name matching.
*/
public static void main(String[] args)
{
try
{
System.out.println("Regular expression ["+args[0]+"]");
ClassNameParser parser = new ClassNameParser();
StringMatcher matcher = parser.parse(args[0]);
for (int index = 1; index < args.length; index++)
{
String string = args[index];
System.out.print("String ["+string+"]");
System.out.println(" -> match = "+matcher.matches(args[index]));
}
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy