1b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato/*
2b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * ProGuard -- shrinking, optimization, obfuscation, and preverification
3b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato *             of Java bytecode.
4b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato *
59f606f95f03a75961498803e24bee6799a7c0885Ying Wang * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
6b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato *
7b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * This program is free software; you can redistribute it and/or modify it
8b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * under the terms of the GNU General Public License as published by the Free
9b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * Software Foundation; either version 2 of the License, or (at your option)
10b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * any later version.
11b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato *
12b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * This program is distributed in the hope that it will be useful, but WITHOUT
13b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * more details.
16b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato *
17b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * You should have received a copy of the GNU General Public License along
18b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * with this program; if not, write to the Free Software Foundation, Inc.,
19b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato */
21b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratopackage proguard.util;
22b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
23b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport java.util.List;
24b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
25b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato/**
26b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * This StringParser can create StringMatcher instances for regular expressions.
27b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * The regular expressions are either presented as a list, or they are
28b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * interpreted as comma-separated lists, optionally prefixed with '!' negators.
29b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * If an entry with a negator matches, a negative match is returned, without
30b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * considering any subsequent entries in the list. The creation of StringMatcher
31b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * instances  for the entries is delegated to the given StringParser.
32b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato *
33b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * @author Eric Lafortune
34b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato */
35b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratopublic class ListParser implements StringParser
36b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato{
37b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    private final StringParser stringParser;
38b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
39b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
40b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    /**
41b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * Creates a new ListParser that parses individual elements in the
42b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * comma-separated list with the given StringParser.
43b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     */
44b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    public ListParser(StringParser stringParser)
45b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
46b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        this.stringParser = stringParser;
47b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
48b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
49b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
50b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    // Implementations for StringParser.
51b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
52b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    public StringMatcher parse(String regularExpression)
53b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
54b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // Does the regular expression contain a ',' list separator?
55b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        return parse(ListUtil.commaSeparatedList(regularExpression));
56b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
57b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
58b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
59b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    /**
60b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * Creates a StringMatcher for the given regular expression, which can
61b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * be a list of optionally negated simple entries.
62b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * <p>
63b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * An empty list results in a StringMatcher that matches any string.
64b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     */
65b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    public StringMatcher parse(List regularExpressions)
66b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
67b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        StringMatcher listMatcher = null;
68b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
69b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // Loop over all simple regular expressions, backward, creating a
70b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // linked list of matchers.
71b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        for (int index = regularExpressions.size()-1; index >=0; index--)
72b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
73b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            String regularExpression = (String)regularExpressions.get(index);
74b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
75b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            StringMatcher entryMatcher = parseEntry(regularExpression);
76b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
77b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            // Prepend the entry matcher.
78b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            listMatcher =
79b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                listMatcher == null ?
80b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                    (StringMatcher)entryMatcher :
81b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                isNegated(regularExpression) ?
82b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                    (StringMatcher)new AndMatcher(entryMatcher, listMatcher) :
83b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                    (StringMatcher)new OrMatcher(entryMatcher, listMatcher);
84b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
85b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
86b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        return listMatcher != null ? listMatcher : new ConstantMatcher(true);
87b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
88b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
89b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
90b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    // Small utility methods.
91b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
92b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    /**
93b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * Creates a StringMatcher for the given regular expression, which is a
94b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * an optionally negated simple expression.
95b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     */
96b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    private StringMatcher parseEntry(String regularExpression)
97b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
98b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        // Wrap the matcher if the regular expression starts with a '!' negator.
99b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        return isNegated(regularExpression) ?
100b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato          new NotMatcher(stringParser.parse(regularExpression.substring(1))) :
101b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato          stringParser.parse(regularExpression);
102b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
103b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
104b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
105b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    /**
106b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * Returns whether the given simple regular expression is negated.
107b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     */
108b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    private boolean isNegated(String regularExpression)
109b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
110b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        return regularExpression.length() > 0 &&
111b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato               regularExpression.charAt(0) == '!';
112b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
113b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
114b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
115b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    /**
116b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * A main method for testing name matching.
117b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     */
118b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    public static void main(String[] args)
119b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
120b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        try
121b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
122b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            System.out.println("Regular expression ["+args[0]+"]");
123b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            ListParser parser  = new ListParser(new NameParser());
124b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            StringMatcher  matcher = parser.parse(args[0]);
125b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            for (int index = 1; index < args.length; index++)
126b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            {
127b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                String string = args[index];
128b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                System.out.print("String             ["+string+"]");
129b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                System.out.println(" -> match = "+matcher.matches(args[index]));
130b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            }
131b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
132b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        catch (Exception ex)
133b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
134b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            ex.printStackTrace();
135b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
136b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
137b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato}
138