1b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato/*
2b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * ProGuard -- shrinking, optimization, obfuscation, and preverification
3b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato *             of Java bytecode.
4b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato *
5b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang * Copyright (c) 2002-2013 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
51b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            System.out.println("ProGuard is released under the GNU General Public License. You therefore");
52b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            System.out.println("must ensure that programs that link to it ("+uniquePackageNames+"...)");
53b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            System.out.println("carry the GNU General Public License as well. Alternatively, you can");
54b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang            System.out.println("apply for an exception with the author of ProGuard.");
55b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
56b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
57b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
58b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
59b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    /**
60b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * Returns a set of package names from the given stack trace.
61b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     */
62b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    private static Set unknownPackageNames(LineNumberReader reader)
63b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
64b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        Set packageNames = new HashSet();
65b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
66b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        try
67b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
68b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            while (true)
69b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            {
70b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                String line = reader.readLine();
71b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                if (line == null)
72b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                {
73b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                    break;
74b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                }
75b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
76b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                line = line.trim();
77b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                if (line.startsWith("at "))
78b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                {
79b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                    line = line.substring(2).trim();
80b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                    line = trimSuffix(line, '(');
81b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                    line = trimSuffix(line, '.');
82b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                    line = trimSuffix(line, '.');
83b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
84b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                    if (line.length() > 0 && !isKnown(line))
85b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                    {
86b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                        packageNames.add(line);
87b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                    }
88b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                }
89b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            }
90b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
91b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        catch (IOException ex)
92b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
93b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            // We'll just stop looking for more names.
94b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
95b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
96b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        return packageNames;
97b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
98b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
99b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
100b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    /**
101b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * Returns a comma-separated list of package names from the set, excluding
102b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * any subpackages of packages in the set.
103b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     */
104b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    private static String uniquePackageNames(Set packageNames)
105b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
106b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        StringBuffer buffer = new StringBuffer();
107b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
108b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        Iterator iterator = packageNames.iterator();
109b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        while (iterator.hasNext())
110b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
111b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            String packageName = (String)iterator.next();
112b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            if (!containsPrefix(packageNames, packageName))
113b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            {
114b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                buffer.append(packageName).append(", ");
115b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            }
116b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
117b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
118b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        return buffer.toString();
119b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
120b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
121b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
122b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    /**
123b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * Returns a given string without the suffix, as defined by the given
124b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * separator.
125b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     */
126b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    private static String trimSuffix(String string, char separator)
127b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
128b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        int index = string.lastIndexOf(separator);
129b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        return index < 0 ? "" : string.substring(0, index);
130b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
131b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
132b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
133b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    /**
134b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * Returns whether the given set contains a prefix of the given name.
135b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     */
136b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    private static boolean containsPrefix(Set set, String name)
137b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
138b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        int index = 0;
139b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
140b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        while (!set.contains(name.substring(0, index)))
141b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
142b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            index = name.indexOf('.', index + 1);
143b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            if (index < 0)
144b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            {
145b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                return false;
146b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            }
147b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
148b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
149b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        return true;
150b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
151b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
152b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
153b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    /**
154b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * Returns whether the given package name has been granted an exception
155b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * against the GPL linking clause, by the copyright holder of ProGuard.
156b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * This method is not legally binding, but of course the actual license is.
157b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * Please contact the copyright holder if you would like an exception for
158b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     * your code as well.
159b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato     */
160b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    private static boolean isKnown(String packageName)
161b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
162b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        return packageName.startsWith("java")                   ||
163b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato               packageName.startsWith("sun.reflect")            ||
164b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato               packageName.startsWith("proguard")               ||
165b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato               packageName.startsWith("org.apache.tools.ant")   ||
166b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato               packageName.startsWith("org.apache.tools.maven") ||
167b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang               packageName.startsWith("org.gradle")             ||
168b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang               packageName.startsWith("org.codehaus.groovy")    ||
169b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato               packageName.startsWith("org.eclipse")            ||
170b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato               packageName.startsWith("org.netbeans")           ||
171b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang               packageName.startsWith("com.android")            ||
172b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato               packageName.startsWith("com.sun.kvem")           ||
173b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang               packageName.startsWith("com.intel")              ||
174b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato               packageName.startsWith("net.certiv.proguarddt")  ||
175b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang               packageName.startsWith("groovy")                 ||
176b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang               packageName.startsWith("scala")                  ||
177b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang               packageName.startsWith("sbt")                    ||
178b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang               packageName.startsWith("xsbt")                   ||
179b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato               packageName.startsWith("eclipseme")              ||
180b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang               packageName.startsWith("com.neomades")           ||
181b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato               packageName.startsWith("jg.j2me")                ||
182b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato               packageName.startsWith("jg.common")              ||
183b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato               packageName.startsWith("jg.buildengine");
184b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
185b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
186b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
187b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    public static void main(String[] args)
188b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    {
189b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        LineNumberReader reader = new LineNumberReader(
190b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato                                  new InputStreamReader(System.in));
191b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
192b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        Set unknownPackageNames = unknownPackageNames(reader);
193b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
194b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        if (unknownPackageNames.size() > 0)
195b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        {
196b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            String uniquePackageNames = uniquePackageNames(unknownPackageNames);
197b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato
198b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato            System.out.println(uniquePackageNames);
199b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato        }
200b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato    }
201b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato}
202