• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * ProGuard -- shrinking, optimization, obfuscation, and preverification
3  *             of Java bytecode.
4  *
5  * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published by the Free
9  * Software Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * This program is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15  * more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20  */
21 package proguard;
22 
23 import java.io.*;
24 import java.util.*;
25 
26 /**
27  * This class checks and prints out information about the GPL.
28  *
29  * @author Eric Lafortune
30  */
31 public class GPL
32 {
33     /**
34      * Prints out a note about the GPL if ProGuard is linked against unknown
35      * code.
36      */
check()37     public static void check()
38     {
39         ByteArrayOutputStream out = new ByteArrayOutputStream();
40         new Exception().printStackTrace(new PrintStream(out));
41         LineNumberReader reader = new LineNumberReader(
42                                   new InputStreamReader(
43                                   new ByteArrayInputStream(out.toByteArray())));
44 
45         Set unknownPackageNames = unknownPackageNames(reader);
46 
47         if (unknownPackageNames.size() > 0)
48         {
49             String uniquePackageNames = uniquePackageNames(unknownPackageNames);
50 
51             System.out.println("ProGuard is released under the GNU General Public License. You therefore");
52             System.out.println("must ensure that programs that link to it ("+uniquePackageNames+"...)");
53             System.out.println("carry the GNU General Public License as well. Alternatively, you can");
54             System.out.println("apply for an exception with the author of ProGuard.");
55         }
56     }
57 
58 
59     /**
60      * Returns a set of package names from the given stack trace.
61      */
unknownPackageNames(LineNumberReader reader)62     private static Set unknownPackageNames(LineNumberReader reader)
63     {
64         Set packageNames = new HashSet();
65 
66         try
67         {
68             while (true)
69             {
70                 String line = reader.readLine();
71                 if (line == null)
72                 {
73                     break;
74                 }
75 
76                 line = line.trim();
77                 if (line.startsWith("at "))
78                 {
79                     line = line.substring(2).trim();
80                     line = trimSuffix(line, '(');
81                     line = trimSuffix(line, '.');
82                     line = trimSuffix(line, '.');
83 
84                     if (line.length() > 0 && !isKnown(line))
85                     {
86                         packageNames.add(line);
87                     }
88                 }
89             }
90         }
91         catch (IOException ex)
92         {
93             // We'll just stop looking for more names.
94         }
95 
96         return packageNames;
97     }
98 
99 
100     /**
101      * Returns a comma-separated list of package names from the set, excluding
102      * any subpackages of packages in the set.
103      */
uniquePackageNames(Set packageNames)104     private static String uniquePackageNames(Set packageNames)
105     {
106         StringBuffer buffer = new StringBuffer();
107 
108         Iterator iterator = packageNames.iterator();
109         while (iterator.hasNext())
110         {
111             String packageName = (String)iterator.next();
112             if (!containsPrefix(packageNames, packageName))
113             {
114                 buffer.append(packageName).append(", ");
115             }
116         }
117 
118         return buffer.toString();
119     }
120 
121 
122     /**
123      * Returns a given string without the suffix, as defined by the given
124      * separator.
125      */
trimSuffix(String string, char separator)126     private static String trimSuffix(String string, char separator)
127     {
128         int index = string.lastIndexOf(separator);
129         return index < 0 ? "" : string.substring(0, index);
130     }
131 
132 
133     /**
134      * Returns whether the given set contains a prefix of the given name.
135      */
containsPrefix(Set set, String name)136     private static boolean containsPrefix(Set set, String name)
137     {
138         int index = 0;
139 
140         while (!set.contains(name.substring(0, index)))
141         {
142             index = name.indexOf('.', index + 1);
143             if (index < 0)
144             {
145                 return false;
146             }
147         }
148 
149         return true;
150     }
151 
152 
153     /**
154      * Returns whether the given package name has been granted an exception
155      * against the GPL linking clause, by the copyright holder of ProGuard.
156      * This method is not legally binding, but of course the actual license is.
157      * Please contact the copyright holder if you would like an exception for
158      * your code as well.
159      */
isKnown(String packageName)160     private static boolean isKnown(String packageName)
161     {
162         return packageName.startsWith("java")                   ||
163                packageName.startsWith("sun.reflect")            ||
164                packageName.startsWith("proguard")               ||
165                packageName.startsWith("org.apache.tools.ant")   ||
166                packageName.startsWith("org.apache.tools.maven") ||
167                packageName.startsWith("org.gradle")             ||
168                packageName.startsWith("org.codehaus.groovy")    ||
169                packageName.startsWith("org.eclipse")            ||
170                packageName.startsWith("org.netbeans")           ||
171                packageName.startsWith("com.android")            ||
172                packageName.startsWith("com.sun.kvem")           ||
173                packageName.startsWith("net.certiv.proguarddt")  ||
174                packageName.startsWith("groovy")                 ||
175                packageName.startsWith("scala")                  ||
176                packageName.startsWith("sbt")                    ||
177                packageName.startsWith("xsbt")                   ||
178                packageName.startsWith("eclipseme");
179     }
180 
181 
main(String[] args)182     public static void main(String[] args)
183     {
184         LineNumberReader reader = new LineNumberReader(
185                                   new InputStreamReader(System.in));
186 
187         Set unknownPackageNames = unknownPackageNames(reader);
188 
189         if (unknownPackageNames.size() > 0)
190         {
191             String uniquePackageNames = uniquePackageNames(unknownPackageNames);
192 
193             System.out.println(uniquePackageNames);
194         }
195     }
196 }
197