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