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