Home | History | Annotate | Download | only in proguard
      1 /*
      2  * ProGuard -- shrinking, optimization, obfuscation, and preverification
      3  *             of Java bytecode.
      4  *
      5  * Copyright (c) 2002-2009 Eric Lafortune (eric (at) 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      */
     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