1b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato/*
2b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * ProGuard -- shrinking, optimization, obfuscation, and preverification
3b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato *             of Java bytecode.
4b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato *
5b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * 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;
22b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
23b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport java.io.*;
24b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport java.util.*;
25b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
26b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato/**
27b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * This class checks and prints out information about the GPL.
28b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato *
29b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * @author Eric Lafortune
30b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato */
31b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratopublic class GPL
32b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato{
33b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    /**
34b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * Prints out a note about the GPL if ProGuard is linked against unknown
35b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * code.
36b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     */
37b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    public static void check()
38b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
39b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        ByteArrayOutputStream out = new ByteArrayOutputStream();
40b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        new Exception().printStackTrace(new PrintStream(out));
41b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        LineNumberReader reader = new LineNumberReader(
42b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                                  new InputStreamReader(
43b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                                  new ByteArrayInputStream(out.toByteArray())));
44b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
45b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        Set unknownPackageNames = unknownPackageNames(reader);
46b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
47b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        if (unknownPackageNames.size() > 0)
48b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
49b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            String uniquePackageNames = uniquePackageNames(unknownPackageNames);
50b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
51b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            System.out.println("ProGuard is released under the GNU General Public License. The authors of all");
52b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            System.out.println("programs or plugins that link to it ("+uniquePackageNames+"...) therefore");
53b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            System.out.println("must ensure that these programs carry the GNU General Public License as well.");
54b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
55b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
56b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
57b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
58b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    /**
59b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * Returns a set of package names from the given stack trace.
60b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     */
61b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    private static Set unknownPackageNames(LineNumberReader reader)
62b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
63b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        Set packageNames = new HashSet();
64b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
65b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        try
66b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
67b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            while (true)
68b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            {
69b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                String line = reader.readLine();
70b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                if (line == null)
71b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                {
72b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                    break;
73b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                }
74b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
75b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                line = line.trim();
76b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                if (line.startsWith("at "))
77b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                {
78b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                    line = line.substring(2).trim();
79b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                    line = trimSuffix(line, '(');
80b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                    line = trimSuffix(line, '.');
81b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                    line = trimSuffix(line, '.');
82b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
83b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                    if (line.length() > 0 && !isKnown(line))
84b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                    {
85b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                        packageNames.add(line);
86b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                    }
87b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                }
88b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            }
89b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
90b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        catch (IOException ex)
91b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
92b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            // We'll just stop looking for more names.
93b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
94b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
95b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        return packageNames;
96b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
97b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
98b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
99b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    /**
100b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * Returns a comma-separated list of package names from the set, excluding
101b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * any subpackages of packages in the set.
102b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     */
103b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    private static String uniquePackageNames(Set packageNames)
104b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
105b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        StringBuffer buffer = new StringBuffer();
106b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
107b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        Iterator iterator = packageNames.iterator();
108b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        while (iterator.hasNext())
109b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
110b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            String packageName = (String)iterator.next();
111b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            if (!containsPrefix(packageNames, packageName))
112b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            {
113b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                buffer.append(packageName).append(", ");
114b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            }
115b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
116b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
117b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        return buffer.toString();
118b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
119b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
120b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
121b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    /**
122b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * Returns a given string without the suffix, as defined by the given
123b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * separator.
124b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     */
125b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    private static String trimSuffix(String string, char separator)
126b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
127b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        int index = string.lastIndexOf(separator);
128b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        return index < 0 ? "" : string.substring(0, index);
129b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
130b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
131b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
132b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    /**
133b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * Returns whether the given set contains a prefix of the given name.
134b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     */
135b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    private static boolean containsPrefix(Set set, String name)
136b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
137b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        int index = 0;
138b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
139b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        while (!set.contains(name.substring(0, index)))
140b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
141b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            index = name.indexOf('.', index + 1);
142b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            if (index < 0)
143b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            {
144b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                return false;
145b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            }
146b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
147b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
148b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        return true;
149b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
150b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
151b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
152b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    /**
153b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * Returns whether the given package name has been granted an exception
154b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * against the GPL linking clause, by the copyright holder of ProGuard.
155b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * This method is not legally binding, but of course the actual license is.
156b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * Please contact the copyright holder if you would like an exception for
157b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * your code as well.
158b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     */
159b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    private static boolean isKnown(String packageName)
160b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
161b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        return packageName.startsWith("java")                   ||
162b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato               packageName.startsWith("sun.reflect")            ||
163b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato               packageName.startsWith("proguard")               ||
164b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato               packageName.startsWith("org.apache.tools.ant")   ||
165b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato               packageName.startsWith("org.apache.tools.maven") ||
166b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato               packageName.startsWith("org.eclipse")            ||
167b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato               packageName.startsWith("org.netbeans")           ||
168b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato               packageName.startsWith("com.sun.kvem")           ||
169b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato               packageName.startsWith("net.certiv.proguarddt")  ||
170b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato               packageName.startsWith("eclipseme")              ||
171b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato               packageName.startsWith("jg.j2me")                ||
172b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato               packageName.startsWith("jg.common")              ||
173b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato               packageName.startsWith("jg.buildengine");
174b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
175b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
176b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
177b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    public static void main(String[] args)
178b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
179b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        LineNumberReader reader = new LineNumberReader(
180b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                                  new InputStreamReader(System.in));
181b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
182b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        Set unknownPackageNames = unknownPackageNames(reader);
183b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
184b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        if (unknownPackageNames.size() > 0)
185b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
186b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            String uniquePackageNames = uniquePackageNames(unknownPackageNames);
187b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
188b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            System.out.println(uniquePackageNames);
189b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
190b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
191b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato}
192