com.yworks.yguard.ObfuscatorTask Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of yguard Show documentation
Show all versions of yguard Show documentation
The open-source Java obfuscation tool working with Ant and Gradle by yWorks - the diagramming experts
/*
* ObfuscatorTask.java
*
* Created on October 10, 2002, 5:30 PM
*/
package com.yworks.yguard;
import com.yworks.util.CollectionFilter;
import com.yworks.util.ant.ZipScannerTool;
import com.yworks.yguard.common.ant.*;
import com.yworks.yguard.common.ant.AttributesSection;
import com.yworks.yguard.common.ShrinkBag;
import com.yworks.yguard.obf.Cl;
import com.yworks.yguard.obf.Cl.ClassResolver;
import com.yworks.yguard.obf.ClassTree;
import com.yworks.yguard.obf.Filter;
import com.yworks.yguard.obf.GuardDB;
import com.yworks.yguard.obf.LineNumberTableMapper;
import com.yworks.yguard.obf.NameMaker;
import com.yworks.yguard.obf.NameMakerFactory;
import com.yworks.yguard.obf.NoSuchMappingException;
import com.yworks.yguard.obf.ResourceHandler;
import com.yworks.yguard.obf.Version;
import com.yworks.yguard.obf.YGuardRule;
import com.yworks.yguard.obf.classfile.LineNumberInfo;
import com.yworks.yguard.obf.classfile.LineNumberTableAttrInfo;
import com.yworks.yguard.obf.classfile.Logger;
import com.yworks.yguard.ant.*;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.DirectoryScanner;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.Task;
import org.apache.tools.ant.types.EnumeratedAttribute;
import org.apache.tools.ant.types.Path;
import org.apache.tools.ant.types.ZipFileSet;
import org.apache.tools.ant.types.PatternSet;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.Writer;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
/**
* The main obfuscation Ant Task
* @author Sebastian Mueller, yWorks GmbH ([email protected])
*/
public class ObfuscatorTask extends YGuardBaseTask
{
//private List pairs = new ArrayList();
private String mainClass;
private boolean conserveManifest = false;
private File logFile = new File("yguardlog.xml");
private ExposeSection expose = null;
private List adjustSections = new ArrayList();
private MapSection map = null;
private PatchSection patch = null;
//private Path resourceClassPath;
// shrinking attributes
private boolean doShrink = false;
private EntryPointsSection entryPoints = null;
private File shrinkLog = null;
private boolean useExposeAsEntryPoints = true;
private static final String LOG_TITLE_PRE_VERSION = " yGuard Bytecode Obfuscator, v";
private static final String LOG_TITLE_POST_VERSION = ", a Product of yWorks GmbH - http://www.yworks.com";
private static final String LOG_CREATED = " Logfile created on ";
private static final String LOG_INPUT_FILE = " Jar file to be obfuscated: ";
private static final String LOG_OUTPUT_FILE = " Target Jar file for obfuscated code: ";
private static final String NO_SHRINKING_SUPPORT = "No shrinking support found.";
private static final String DEPRECATED = "The obfuscate task is deprecated. Please use the new com.yworks.yguard.YGuardTask instead.";
/** Holds value of property replaceClassNameStrings. */
private boolean replaceClassNameStrings = true;
private File[] tempJars;
private boolean needYShrinkModel;
private YShrinkModel yShrinkModel;
public ObfuscatorTask() {
super();
}
public ObfuscatorTask( boolean mode ) {
super( mode );
}
private static String toNativePattern(String pattern){
if (pattern.endsWith(".class")){
return pattern;
} else {
if (pattern.endsWith("**")){
return pattern.replace('.','/')+"/*.class";
} else if (pattern.endsWith("*")){
return pattern.replace('.','/')+".class";
} else if ( pattern.endsWith( "." ) ) {
return pattern.replace( '.', '/' ) + "**/*.class";
} else {
return pattern.replace( '.', '/' ) + ".class";
}
}
}
public static String[] toNativePattern(String[] patterns){
if (patterns == null){
return new String[0];
} else {
String[] res = new String[patterns.length];
for (int i = 0; i < patterns.length; i++){
res[i] = toNativePattern(patterns[i]);
}
return res;
}
}
public static final String toNativeClass(String className){
return className.replace('.','/');
}
public static final String[] toNativeMethod(String javaMethod){
StringTokenizer tokenizer = new StringTokenizer(javaMethod, "(,[]) ", true);
String tmp = tokenizer.nextToken();;
while (tmp.trim().length() == 0){
tmp = tokenizer.nextToken();
}
String returnType = tmp;
tmp = tokenizer.nextToken();
int retarraydim = 0;
while (tmp.equals("[")){
tmp = tokenizer.nextToken();
if (!tmp.equals("]")) throw new IllegalArgumentException("']' expected but found "+tmp);
retarraydim++;
tmp = tokenizer.nextToken();
}
if ( tmp.trim().length() != 0 ) {
throw new IllegalArgumentException( "space expected but found " + tmp );
}
tmp = tokenizer.nextToken();
while (tmp.trim().length() == 0){
tmp = tokenizer.nextToken();
}
String name = tmp;
StringBuffer nativeMethod = new StringBuffer(30);
nativeMethod.append('(');
tmp = tokenizer.nextToken();
while (tmp.trim().length() == 0){
tmp = tokenizer.nextToken();
}
if (!tmp.equals("(")) throw new IllegalArgumentException("'(' expected but found "+tmp);
tmp = tokenizer.nextToken();
while (!tmp.equals(")")){
while (tmp.trim().length() == 0){
tmp = tokenizer.nextToken();
}
String type = tmp;
tmp = tokenizer.nextToken();
while (tmp.trim().length() == 0){
tmp = tokenizer.nextToken();
}
int arraydim = 0;
while (tmp.equals("[")){
tmp = tokenizer.nextToken();
if (!tmp.equals("]")) throw new IllegalArgumentException("']' expected but found "+tmp);
arraydim++;
tmp = tokenizer.nextToken();
}
while (tmp.trim().length() == 0){
tmp = tokenizer.nextToken();
}
nativeMethod.append(toNativeType(type, arraydim));
if (tmp.equals(",")){
tmp = tokenizer.nextToken();
while (tmp.trim().length() == 0){
tmp = tokenizer.nextToken();
}
continue;
}
}
nativeMethod.append(')');
nativeMethod.append(toNativeType(returnType, retarraydim));
String[] result = new String[]{name, nativeMethod.toString()};
return result;
}
private static final String toNativeType(String type, int arraydim){
StringBuffer nat = new StringBuffer(30);
for (int i = 0; i < arraydim; i++){
nat.append('[');
}
if ("byte".equals(type)){
nat.append('B');
} else if ("char".equals(type)){
nat.append('C');
} else if ("double".equals(type)){
nat.append('D');
} else if ("float".equals(type)){
nat.append('F');
} else if ("int".equals(type)){
nat.append('I');
} else if ("long".equals(type)){
nat.append('J');
} else if ("short".equals(type)){
nat.append('S');
} else if ("boolean".equals(type)){
nat.append('Z');
} else if ("void".equals(type)){
nat.append('V');
} else { //Lclassname;
nat.append('L');
nat.append(type.replace('.','/'));
nat.append(';');
}
return nat.toString();
}
public void setNeedYShrinkModel( boolean b ) {
this.needYShrinkModel = b;
}
/** Used by ant to handle the patch
element.
*/
public final class PatchSection {
private List patches = new ArrayList();
public void addConfiguredClass(ClassSection cs){
patches.add(cs);
}
Collection createEntries(Collection srcJars) throws IOException{
Collection entries = new ArrayList(20);
for (Iterator it = srcJars.iterator(); it.hasNext();)
{
File file = (File) it.next();
ZipFileSet zipFile = new ZipFileSet();
zipFile.setProject(getProject());
zipFile.setSrc(file);
for (Iterator it2 = patches.iterator(); it2.hasNext();){
ClassSection cs = (ClassSection) it2.next();
if (cs.getName() == null){
cs.addEntries(entries, zipFile);
} else {
cs.addEntries(entries, cs.getName());
}
}
}
return entries;
}
}
/** Used by ant to handle the inoutpair
element.
*/
// public static final class InOutPair{
// private File inFile;
// private File outFile;
// public void setIn(File file){
// this.inFile = file;
// }
// public void setOut(File file){
// this.outFile = file;
// }
//
// public String toString(){
// return "in: "+inFile+"; out: "+outFile;
// }
// }
/** Used by ant to handle the classes
,
* methods
and fields
attributes.
*/
public static final class Modifiers extends EnumeratedAttribute {
public String[] getValues() {
return new String[] {"public", "protected", "friendly", "private","none"};
}
private int myGetIndex(){
String[] values = getValues();
for (int i = 0; i < values.length; i++){
if (getValue().equals(values[i])){
return i;
}
}
return -1;
}
public int getModifierValue(){
switch (myGetIndex()){
default:
return YGuardRule.LEVEL_NONE;
case 0:
return YGuardRule.LEVEL_PUBLIC;
case 1:
return YGuardRule.LEVEL_PROTECTED;
case 2:
return YGuardRule.LEVEL_FRIENDLY;
case 3:
return YGuardRule.LEVEL_PRIVATE;
case 4:
return YGuardRule.LEVEL_NONE;
}
}
}
/** Used by ant to handle the map
element.
*/
public final class MapSection{
private File logFile;
private List mappables = new ArrayList();
public void addConfiguredPackage( PackageSection ps){
mappables.add(ps);
}
// public ClassSection createClass() {
// ClassSection cs = new ClassSection( );
// mappables.add( cs );
// return cs;
// }
public void addConfiguredClass(ClassSection ps){
mappables.add(ps);
}
public void addConfiguredField( FieldSection ps){
mappables.add(ps);
}
public void addConfiguredMethod(MethodSection ps){
mappables.add(ps);
}
public void setLogFile(File logFile){
this.logFile = logFile;
}
Collection createEntries(Project antproject, PrintWriter log) throws BuildException{
Collection res;
if (logFile != null){
try{
SAXParserFactory f = SAXParserFactory.newInstance();
f.setValidating(false);
SAXParser parser = f.newSAXParser();
XMLReader r = parser.getXMLReader();
MapParser mp = new MapParser( ObfuscatorTask.this );
r.setContentHandler(mp);
Reader reader;
if (logFile.getName().endsWith(".gz")){
reader = new InputStreamReader(new GZIPInputStream(new FileInputStream(logFile)));
} else {
reader = new FileReader(logFile);
}
InputSource source = new InputSource(reader);
antproject.log("Parsing logfile's "+logFile.getName()+" map elements...", Project.MSG_INFO);
r.parse(source);
reader.close();
r = null;
f = null;
parser = null;
res = mp.getEntries();
} catch (ParserConfigurationException pxe){
throw new BuildException("Could configure xml parser!",pxe);
} catch (SAXException pxe){
throw new BuildException("Error parsing xml logfile!"+pxe,pxe);
} catch (IOException ioe){
throw new BuildException("Could not parse map from logfile!",ioe);
}
} else {
res = new ArrayList(mappables.size());
}
for (Iterator it = mappables.iterator(); it.hasNext();){
Mappable m = (Mappable)it.next();
m.addMapEntries(res);
}
return res;
}
}
/**
* Used by ant to handle the adjust
element.
*/
public class AdjustSection extends ZipFileSet {
private boolean replaceName = false;
private boolean replaceContent = false;
private boolean replacePath = true;
private Set entries;
public AdjustSection()
{
setProject(ObfuscatorTask.this.getProject());
}
public boolean contains(String name)
{
return entries.contains(name);
}
public void setReplaceContent(boolean rc){
this.replaceContent = rc;
}
public boolean getReplaceContent()
{
return replaceContent;
}
public void setReplacePath(boolean rp){
this.replacePath = rp;
}
public boolean getReplacePath()
{
return replacePath;
}
public boolean getReplaceName()
{
return replaceName;
}
public void setReplaceName(boolean rn){
this.replaceName = rn;
}
public void createEntries(Collection srcJars) throws IOException
{
entries = new HashSet();
for(Iterator iter = srcJars.iterator(); iter.hasNext();)
{
File file = (File) iter.next();
setSrc(file);
DirectoryScanner scanner = getDirectoryScanner(getProject());
String[] includedFiles = ZipScannerTool.getMatches(this, scanner);
for(int i = 0; i < includedFiles.length; i++)
{
entries.add(includedFiles[i]);
}
}
}
}
// public Path createExternalClasses(){
// if (this.resourceClassPath != null){
// throw new IllegalArgumentException("Only one externalclasses element allowed!");
// }
// this.resourceClassPath = new Path(getProject());
// return this.resourceClassPath;
// }
/** Used by ant to handle the nested expose
element.
* @return an ExposeSection instance
*/
public ExposeSection createExpose(){
if (this.expose != null){
throw new IllegalArgumentException("Only one expose element allowed!");
}
this.expose = new ExposeSection( this );
return expose;
}
public void addExcludes( EntryPointsSection entryPoints ) {
if ( null == this.expose ) {
createExpose();
}
}
public Exclude createKeep() {
return createExpose();
}
public void addAttributesSections( List attributesSections ) {
if ( null != expose ) {
List attributes = expose.getAttributes();
for ( AttributesSection attributesSection : attributesSections ) {
com.yworks.yguard.ant.AttributesSection asYGuard = new com.yworks.yguard.ant.AttributesSection( this );
PatternSet patternSet = attributesSection.getPatternSet(TypePatternSet.Type.NAME);
if (patternSet != null) {
asYGuard.addConfiguredPatternSet( patternSet );
}
asYGuard.setName( attributesSection.getAttributesStr() );
attributes.add( asYGuard );
}
}
}
/** Used by ant to handle the nested adjust
element.
* @return an AdjustSection instance
*/
public AdjustSection createAdjust(){
AdjustSection adjust = new AdjustSection();
adjust.setProject(this.getProject());
adjustSections.add(adjust);
return adjust;
}
/** Used by ant to handle the nested expose
element.
*/
public void addConfiguredExpose(ExposeSection ex){
if (this.expose != null){
throw new IllegalArgumentException("Only one expose element allowed!");
}
this.expose = ex;
}
public EntryPointsSection createEntryPoints() {
return new EntryPointsSection( this );
}
/**
* Used by ant to handle the nested entrypoints
element.
*/
public void addConfiguredEntryPoints( EntryPointsSection eps ) {
if ( this.entryPoints != null ) {
throw new IllegalArgumentException( "Only one entrypoints element allowed!" );
}
this.entryPoints = eps;
}
/** Used by ant to handle the nested map
element.
* @return an instance of MapSection
*/
public MapSection createMap(){
if (this.map != null){
throw new IllegalArgumentException("Only one map element allowed!");
}
this.map = new MapSection();
return map;
}
/** Used by ant to handle the nested map
element.
*/
public void addConfiguredMap(MapSection map){
if (this.map != null){
throw new IllegalArgumentException("Only one map element allowed!");
}
this.map = map;
}
/** Used by ant to handle the nested patch
element.
* @return an instance of PatchSection
*/
public PatchSection createPatch(){
if (this.patch != null){
throw new IllegalArgumentException("Only one patch element allowed!");
}
this.patch = new PatchSection();
return patch;
}
/** Used by ant to handle the nested patch
element.
*/
public void addConfiguredPatch(PatchSection patch){
if (this.patch != null){
throw new IllegalArgumentException("Only one patch element allowed!");
}
this.patch = patch;
}
// /** Used by ant to handle the nested adjust
element.
// */
// public void addConfiguredAdjust(AdjustSection adjust){
// adjustSections.add(adjust);
// System.out.println("addConfiguredAdjust");
// }
/** Used by ant to handle the logfile
attribute.
* @param file
*/
public void setLogFile(File file){
this.logFile = file;
}
/** Used by ant to handle the conservemanifest
attribute.
*/
public void setConserveManifest(boolean c){
this.conserveManifest = c;
}
/** Used by ant to handle the mainclass
attribute.
*/
public void setMainClass(String mainClass){
this.mainClass = mainClass;
}
/** Used by ant to handle the start the obfuscation process.
*/
public void execute() throws BuildException
{
getProject().log(this,"yGuard Obfuscator v" + Version.getVersion() + " - http://www.yworks.com/products/yguard", Project.MSG_INFO);
if ( mode == MODE_STANDALONE ) {
getProject().log( this, DEPRECATED, Project.MSG_WARN );
}
TaskLogger taskLogger = new TaskLogger();
if ( ! ( mode == MODE_STANDALONE ) ) {
doShrink = false;
}
if( doShrink ) doShrink();
ResourceCpResolver resolver = null;
if (resourceClassPath != null){
resolver = new ResourceCpResolver(resourceClassPath, this);
Cl.setClassResolver(resolver);
}
YGuardNameFactory nameFactory = null;
if (properties.containsKey("naming-scheme")
|| properties.containsKey("language-conformity")
|| properties.containsKey("overload-enabled")){
String ns = (String) properties.get("naming-scheme");
String lc = (String) properties.get("language-conformity");
int ilc = YGuardNameFactory.LEGAL;
int ins = YGuardNameFactory.SMALL;
if ("compatible".equalsIgnoreCase(lc)){
ilc = YGuardNameFactory.COMPATIBLE;
} else if ("illegal".equalsIgnoreCase(lc)){
ilc = YGuardNameFactory.ILLEGAL;
}
if ("mix".equalsIgnoreCase(ns)){
ins = YGuardNameFactory.MIX;
}
if ("best".equalsIgnoreCase(ns)){
ins = YGuardNameFactory.BEST;
}
nameFactory = new YGuardNameFactory(ilc|ins);
nameFactory.setPackagePrefix((String) properties.get("obfuscation-prefix"));
} else {
nameFactory = new YGuardNameFactory(YGuardNameFactory.LEGAL|YGuardNameFactory.SMALL);
nameFactory.setPackagePrefix((String) properties.get("obfuscation-prefix"));
}
if (properties.containsKey("overload-enabled")) {
String overload = (String) properties.get("overload-enabled");
boolean overloadEnabled = true;
if( "false".equalsIgnoreCase(overload) || "no".equalsIgnoreCase("overload")) {
overloadEnabled = false;
}
nameFactory.setOverloadEnabled(overloadEnabled);
}
boolean pedantic = false;
if (properties.containsKey("error-checking")){
String ed = (String) properties.get("error-checking");
if ("pedantic".equalsIgnoreCase(ed)){
pedantic = true;
}
}
getProject().log(this,"Using NameMakerFactory: "+NameMakerFactory.getInstance(), Project.MSG_VERBOSE);
if (pairs == null){
throw new BuildException("No in out pairs specified!");
}
Collection inFilesList = new ArrayList(pairs.size());
File[] inFiles = new File[pairs.size()];
File[] outFiles = new File[pairs.size()];
for (int i = 0; i < pairs.size();i++)
{
InOutPair pair = (InOutPair) pairs.get(i);
if (pair.getIn() == null || !pair.getIn().isFile() || !pair.getIn().canRead()){
throw new BuildException("Cannot open inoutpair.in "+pair.getIn());
}
inFiles[i] = pair.getIn();
inFilesList.add(pair.getIn());
if (pair.getOut() == null){
throw new BuildException("Must specify inoutpair.out!");
}
outFiles[i] = pair.getOut();
}
PrintWriter log = null;
if(logFile != null)
{
try{
if (logFile.getName().endsWith(".gz")){
log = new PrintWriter(
new BufferedWriter(
new OutputStreamWriter(
new GZIPOutputStream(
new FileOutputStream(logFile)
)
)
)
);
} else {
log = new PrintWriter(new BufferedWriter(new FileWriter(logFile)));
}
taskLogger.setWriter( log );
} catch (IOException ioe){
getProject().log(this, "Could not create logfile: "+ioe, Project.MSG_ERR);
log = new PrintWriter(System.out);
}
} else {
log = new PrintWriter(System.out);
}
writeLogHeader(log, inFiles, outFiles);
try{
Collection rules = null;
if (expose != null){
rules = expose.createEntries(inFilesList);
} else {
rules = new ArrayList(20);
}
if (mainClass!= null)
{
String cn = toNativeClass(mainClass);
rules.add(new YGuardRule(YGuardRule.TYPE_CLASS, cn));
rules.add(new YGuardRule(YGuardRule.TYPE_METHOD, cn+"/main","([Ljava/lang/String;)V"));
}
if (map != null){
Collection mapEntries = map.createEntries(getProject(), log);
rules.addAll(mapEntries);
}
for(Iterator iter = adjustSections.iterator(); iter.hasNext(); )
{
AdjustSection as = (AdjustSection)iter.next();
as.createEntries(inFilesList);
}
if (properties.containsKey("expose-attributes")){
StringTokenizer st = new StringTokenizer((String)properties.get("expose-attributes"),",",false);
while (st.hasMoreTokens()){
String attribute = st.nextToken().trim();
rules.add(new YGuardRule(YGuardRule.TYPE_ATTR, attribute));
getProject().log(this, "Exposing attribute '"+attribute+"'", Project.MSG_VERBOSE);
}
}
try
{
ObfuscatorTask.LogListener listener = new ObfuscatorTask.LogListener(getProject());
Filter filter = null;
if (patch != null){
getProject().log(this, "Patching...", Project.MSG_INFO);
Collection patchfiles = patch.createEntries(inFilesList);
//generate namelist of classes....
Set names = new HashSet();
for (Iterator it = patchfiles.iterator(); it.hasNext();){
YGuardRule entry = (YGuardRule) it.next();
if (entry.type == YGuardRule.TYPE_CLASS){
names.add(entry.name+".class");
}
}
filter = new ClassFileFilter(new CollectionFilter(names));
}
GuardDB db = new GuardDB(inFiles);
if (properties.containsKey("digests")) {
String digests = (String) properties.get("digests");
if (digests.trim().equalsIgnoreCase("none")){
db.setDigests(new String[0]);
} else {
db.setDigests(digests.split("\\s*,\\s*"));
}
}
if (annotationClass != null) db.setAnnotationClass(toNativeClass(annotationClass));
db.setResourceHandler(new ResourceAdjuster(db));
db.setPedantic(pedantic);
db.setReplaceClassNameStrings(replaceClassNameStrings);
db.addListener(listener);
db.retain(rules, log);
db.remapTo(outFiles, filter, log, conserveManifest);
for (Iterator it = rules.iterator(); it.hasNext();){
((YGuardRule)it.next()).logProperties(log);
}
db.close();
Cl.setClassResolver(null);
if( doShrink ) {
for ( int i = 0; i < tempJars.length; i++ ) {
if ( null != tempJars[ i ] ) {
tempJars[ i ].delete();
}
}
}
if ( !Logger.getInstance().isAllResolved() ) {
Logger.getInstance().warning( "Not all dependencies could be resolved. Please see the logfile for details." );
}
} catch (NoSuchMappingException nsm){
throw new BuildException("yGuard was unable to determine the mapped name for "+nsm.getKey()+".\n Probably broken code. Try recompiling from source!",nsm);
} catch (ClassNotFoundException cnfe){
throw new BuildException("yGuard was unable to resolve a class ("+cnfe+").\n Probably a missing external dependency.",cnfe);
} catch (IOException ioe){
if (ioe.getMessage() != null){
getProject().log(this, ioe.getMessage(), Project.MSG_ERR);
}
throw new BuildException("yGuard encountered an IO problem!", ioe);
} catch (ParseException pe){
throw new BuildException("yGuard encountered problems during parsing!", pe);
} catch (RuntimeException rte){
if (rte.getMessage() != null){
getProject().log(this, rte.getMessage(), Project.MSG_ERR);
}
rte.printStackTrace();
throw new BuildException("yGuard encountered an unknown problem!", rte);
} finally{
writeLogFooter(log);
log.flush();
log.close();
}
} catch (IOException ioe){
throw new BuildException("yGuard encountered an IO problem!", ioe);
} finally {
try {
if (resolver != null) {
resolver.close();
}
} catch (Exception e) {
// can't do nothing about it
}
}
}
private void doShrink() {
YShrinkInvoker yShrinkInvoker = null;
try {
yShrinkInvoker = (YShrinkInvoker) Class.forName( "com.yworks.yguard.yshrink.YShrinkInvokerImpl" ).newInstance();
} catch ( InstantiationException e ) {
throw new BuildException( NO_SHRINKING_SUPPORT, e );
} catch ( IllegalAccessException e ) {
throw new BuildException( NO_SHRINKING_SUPPORT, e );
} catch ( ClassNotFoundException e ) {
throw new BuildException( NO_SHRINKING_SUPPORT, e );
}
if ( null == yShrinkInvoker ) return;
yShrinkInvoker.setContext( (Task)this );
tempJars = new File[ pairs.size() ];
File[] outJars = new File[ pairs.size() ];
for ( int i = 0; i < tempJars.length; i++ ) {
try {
tempJars[ i ] = File.createTempFile( "tempJar_", "_shrinked.jar", new File(((InOutPair) pairs.get( i )).getOut().getParent()));
} catch ( IOException e ) {
getProject().log( "Could not create tempfile for shrinking " + tempJars[ i ] + ".", Project.MSG_ERR );
tempJars[ i ] = null;
}
if ( null != tempJars[ i ] ) {
System.out.println( "temp-jar: " + tempJars[ i ] );
ShrinkBag pair = ((ShrinkBag) pairs.get( i ));
outJars[ i ] = pair.getOut();
pair.setOut( tempJars[ i ] );
yShrinkInvoker.addPair( pair );
}
}
yShrinkInvoker.setResourceClassPath( resourceClassPath );
if ( shrinkLog != null ) {
yShrinkInvoker.setLogFile( shrinkLog );
}
if ( null != entryPoints ) {
yShrinkInvoker.setEntyPoints( entryPoints );
}
if ( null != expose && useExposeAsEntryPoints ) {
for ( ClassSection cs : (List) expose.getClasses()) {
yShrinkInvoker.addClassSection( cs );
}
for ( MethodSection ms : (List) expose.getMethods()) {
yShrinkInvoker.addMethodSection( ms );
}
for ( FieldSection fs : (List) expose.getFields() ) {
yShrinkInvoker.addFieldSection( fs );
}
}
yShrinkInvoker.execute();
for ( int i = 0; i < tempJars.length; i++ ) {
if( null != tempJars[ i ] ) {
InOutPair pair = ((InOutPair) pairs.get( i ));
pair.setIn( tempJars[ i ] );
pair.setOut( outJars[ i ] );
}
}
}
public void addInheritanceEntries( Collection entries ) throws IOException {
if ( ! needYShrinkModel || expose == null ) return;
yShrinkModel = null;
try {
yShrinkModel = (YShrinkModel) Class.forName( "com.yworks.yguard.yshrink.YShrinkModelImpl" ).newInstance();
} catch ( InstantiationException e ) {
throw new BuildException( NO_SHRINKING_SUPPORT, e );
} catch ( IllegalAccessException e ) {
throw new BuildException( NO_SHRINKING_SUPPORT, e );
} catch ( ClassNotFoundException e ) {
throw new BuildException( NO_SHRINKING_SUPPORT, e );
}
if ( null == yShrinkModel ) return;
if (this.resourceClassPath != null) {
yShrinkModel.setResourceClassPath(this.resourceClassPath,this);
}
yShrinkModel.createSimpleModel( (List) pairs );
for ( String className : yShrinkModel.getAllClassNames() ) {
Set allAncestorClasses = yShrinkModel.getAllAncestorClasses( className );
Set allInterfaces = yShrinkModel.getAllImplementedInterfaces( className );
for ( ClassSection cs : (List) expose.getClasses() ) {
if ( null != cs.getExtends() ) {
String extendsName = cs.getExtends();
if ( extendsName.equals( className ) ) {
//System.out.println( extendsName + " equals "+className );
cs.addEntries( entries, className );
} else {
if ( allAncestorClasses.contains( extendsName ) ) {
cs.addEntries( entries, className );
//System.out.println( extendsName + " extends "+className );
}
}
}
if ( null != cs.getImplements() ) {
String interfaceName = cs.getImplements();
if ( interfaceName.equals( className ) ) {
//System.out.println( interfaceName + " equals "+className );
cs.addEntries( entries, className );
} else {
if ( allInterfaces.contains( interfaceName ) ) {
cs.addEntries( entries, className );
//System.out.println( interfaceName + " implements "+className );
}
}
}
}
}
}
public void setShrink( boolean doShrink ) {
if ( mode == MODE_STANDALONE ) {
this.doShrink = doShrink;
} else {
throw new BuildException(
"The shrink attribute is not supported when the obfuscate task is nested inside a yguard task.\n Use a separate nested shrink task instead." );
}
}
public void setShrinkLog( File shrinkLog ) {
this.shrinkLog = shrinkLog;
}
public void setUseExposeAsEntryPoints( boolean useExposeAsEntryPoints ) {
this.useExposeAsEntryPoints = useExposeAsEntryPoints;
}
class ResourceAdjuster implements ResourceHandler
{
GuardDB db;
Map map;
StringReplacer contentReplacer = null;
ResourceAdjuster(final GuardDB db)
{
this.db = db;
map = new HashMap() {
public Object get(Object key)
{
return db.translateJavaClass(key.toString());
}
};
}
public boolean filterName(String inName, StringBuffer outName)
{
boolean rp = true;
boolean rn = false;
for(Iterator iter = adjustSections.iterator(); iter.hasNext();)
{
AdjustSection as = (AdjustSection)iter.next();
if(as.contains(inName))
{
if(as.getReplaceName()) rn = true;
if(!as.getReplacePath()) rp = false;
}
}
if(rn)
{
outName.setLength(0);
final String servicesPrefix = "META-INF/services/";
if (inName.startsWith(servicesPrefix)) {
// the file name of a service is a fully qualified class name
final String cn = inName.substring(servicesPrefix.length());
outName.append(servicesPrefix);
// translateJavaFile returns a path name, replacing file separators
// with dots converts that path name back into a qualified class
// name (which is the required file name for a service)
outName.append(db.translateJavaFile(cn).replace('/', '.'));
} else {
int index = 0;
if (inName.endsWith(".properties")) {
index = inName.indexOf('_');
}
if (index <= 0) {
index = inName.indexOf('.');
}
String prefix = inName.substring(0, index);
prefix = db.translateJavaFile(prefix);
outName.append(prefix);
outName.append(inName.substring(index));
}
}
else
{
outName.append(inName);
}
if(!rp)
{
String outPath = inName.substring(0,inName.lastIndexOf('/')+1);
String outFile = outName.toString();
outFile = outFile.substring(outFile.lastIndexOf('/')+1);
outName.setLength(0);
outName.append(outPath);
outName.append(outFile);
}
return rn || !rp;
}
public boolean filterContent(InputStream in, OutputStream out, String resourceName) throws IOException
{
for(Iterator iter = adjustSections.iterator(); iter.hasNext();)
{
AdjustSection as = (AdjustSection)iter.next();
if(as.contains(resourceName) && as.getReplaceContent())
{
Writer writer = new OutputStreamWriter(out);
getContentReplacer().replace(new InputStreamReader(in), writer, map);
writer.flush();
return true;
}
}
return false;
}
public String filterString(String in, String resourceName) throws IOException {
StringBuffer result =new StringBuffer(in.length());
getContentReplacer().replace(in, result, map);
return result.toString();
}
StringReplacer getContentReplacer()
{
if(contentReplacer == null)
{
contentReplacer = new StringReplacer("(?:\\w|[$])+(\\.(?:\\w|[$])+)+");
}
return contentReplacer;
}
};
//accepts classes and their inner classes
private static final class ClassFileFilter implements Filter{
private com.yworks.util.Filter parent;
ClassFileFilter(com.yworks.util.Filter parent){
this.parent = parent;
}
public boolean accepts(Object o)
{
String s= (String) o;
if (s.endsWith(".class") && s.indexOf('$') != -1)
{
s = s.substring(0, s.indexOf('$')) + ".class";
}
return parent.accepts(s);
}
}
private final class TaskLogger extends Logger {
private PrintWriter writer;
TaskLogger(){
super();
}
void setWriter( PrintWriter writer ) {
this.writer = writer;
}
public void warning(String message)
{
getProject().log(ObfuscatorTask.this, "WARNING: "+message, Project.MSG_WARN);
}
public void warningToLogfile( String message ) {
if ( null != writer ) {
writer.println("");
}
}
public void log(String message)
{
getProject().log(ObfuscatorTask.this, message, Project.MSG_INFO);
}
public void error(String message)
{
getProject().log(ObfuscatorTask.this, "ERROR: "+message, Project.MSG_ERR);
}
}
// Write a header out to the log file
private void writeLogHeader(PrintWriter log, File[] inFile, File[] outFile)
{
log.println("");
log.println("");
log.println("");
}
private static final class LogListener implements ObfuscationListener {
private Project p;
LogListener(Project p){
this.p = p;
}
public void obfuscatingClass(String className)
{
p.log("Obfuscating class "+className, Project.MSG_VERBOSE);
}
public void obfuscatingJar(String inJar, String outJar)
{
p.log("Obfuscating Jar "+inJar+" to "+outJar);
}
public void parsingClass(String className)
{
p.log("Parsing class "+className, Project.MSG_VERBOSE);
}
public void parsingJar(String jar)
{
p.log("Parsing jar "+jar);
}
}
private void writeLogFooter(PrintWriter log){
log.println(" ");
}
private static final class YGuardNameFactory extends NameMakerFactory.DefaultNameMakerFactory {
private static String legalFirstChars;
private static String legalChars;
private static String crazylegalFirstChars;
private static String crazylegalChars;
private static String asciiFirstChars;
private static String asciiChars;
private static String asciiLowerChars;
private static AtomicBoolean scrambled = new AtomicBoolean(false);
private String packagePrefix;
static{
StringBuffer legalC = new StringBuffer(500);
StringBuffer illegalC = new StringBuffer(500);
StringBuffer crazyLegalC = new StringBuffer(500);
StringBuffer asciiC = new StringBuffer(500);
StringBuffer asciiLC = new StringBuffer(100);
StringBuffer asciiUC = new StringBuffer(100);
BitSet[] bs = null;
try {
ObjectInputStream ois = new ObjectInputStream(new GZIPInputStream(ObfuscatorTask.class.getResourceAsStream("jdks.bits")));
bs = (BitSet[]) ois.readObject();
ois.close();
} catch (IOException ioe){
throw new InternalError("Could not load valid character bitset!" + ioe.getMessage());
} catch (ClassNotFoundException cnfe){
throw new InternalError("Could not load valid character bitset!" + cnfe.getMessage());
}
for (char i = 0; i < Character.MAX_VALUE; i++){
if (!bs[0].get((int)i)) {
illegalC.append(i);
} else {
legalC.append(i);
if (i>255){
crazyLegalC.append(i);
} else if (i < 128){
asciiC.append(i);
if (Character.isLowerCase(i)){
asciiLC.append(i);
} else {
asciiUC.append(i);
}
}
}
}
legalFirstChars = legalC.toString();
crazylegalFirstChars = crazyLegalC.toString();
asciiLowerChars = asciiLC.toString();
asciiFirstChars = asciiC.toString();
legalC.setLength(0);
illegalC.setLength(0);
crazyLegalC.setLength(0);
for (char i = 0; i < Character.MAX_VALUE; i++){
if (!bs[1].get((int)i)){
illegalC.append(i);
} else {
legalC.append(i);
if (i>255){
crazyLegalC.append(i);
} else if (i < 128){
asciiC.append(i);
}
}
}
legalChars = legalC.toString();
crazylegalChars = crazyLegalC.toString();
asciiChars = asciiC.toString();
}
int mode;
static final int LEGAL = 0;
static final int COMPATIBLE = 1;
static final int ILLEGAL = 2;
static final int SMALL = 4;
static final int MIX = 12;
static final int BEST = 8;
boolean overloadEnabled = true;
YGuardNameFactory(){
this(LEGAL|SMALL);
}
YGuardNameFactory(int mode){
super.setInstance(this);
this.mode = mode;
}
private static void scramble() {
if (scrambled.compareAndSet(false, true)) {
asciiChars = scrambleChars(asciiChars);
asciiFirstChars = scrambleChars(asciiFirstChars);
legalChars = scrambleChars(legalChars);
legalFirstChars = scrambleChars(legalFirstChars);
crazylegalChars = scrambleChars(crazylegalChars);
crazylegalFirstChars = scrambleChars(crazylegalFirstChars);
}
}
private static String scrambleChars(String string) {
char[] chars = string.toCharArray();
Random r = new Random(); // Random number generator
for (int c = 0; c < chars.length; c++) {
int randomPosition = r.nextInt(chars.length);
char original = chars[c];
char random = chars[randomPosition];
chars[c] = random;
chars[randomPosition] = original;
}
StringBuilder sb = new StringBuilder();
for (char c : chars) {
sb.append(c);
}
return sb.toString();
}
public boolean isOverloadEnabled() {
return overloadEnabled;
}
public void setOverloadEnabled(boolean overloadEnabled) {
this.overloadEnabled = overloadEnabled;
}
void setPackagePrefix(String prefix){
this.packagePrefix = prefix;
if (packagePrefix != null){
packagePrefix = packagePrefix.replace('.', '/')+'/';
}
}
protected NameMaker createFieldNameMaker(String[] reservedNames, String fqClassName)
{
switch (mode){
default:
case COMPATIBLE+SMALL:
LongNameMaker longNameMaker1 = new LongNameMaker(reservedNames,
asciiLowerChars, asciiLowerChars, 1);
longNameMaker1.setOverloadEnabled(overloadEnabled);
return longNameMaker1;
case LEGAL+SMALL:
LongNameMaker longNameMaker2 = new LongNameMaker(reservedNames,
legalFirstChars, legalChars, 1);
longNameMaker2.setOverloadEnabled(overloadEnabled);
return longNameMaker2;
case COMPATIBLE+MIX:
case LEGAL+MIX:
AbstractNameMaker nm1 = new LongNameMaker(reservedNames, false, 6);
AbstractNameMaker nm2 = new ObfuscatorTask.KeywordNameMaker(reservedNames);
MixNameMaker mixNameMaker1 = new MixNameMaker(null, reservedNames, nm1,
3);
MixNameMaker mnm = mixNameMaker1;
mnm.add(nm2, 1);
mnm.setOverloadEnabled(overloadEnabled);
return mnm;
case COMPATIBLE+BEST:
case LEGAL+BEST:
LongNameMaker longNameMaker4 = new LongNameMaker(reservedNames, false,
256);
KeywordNameMaker keywordNameMaker1 = new KeywordNameMaker(reservedNames);
CompoundNameMaker compoundNameMaker1 = new CompoundNameMaker(
longNameMaker4,
keywordNameMaker1);
longNameMaker4.setOverloadEnabled(overloadEnabled);
keywordNameMaker1.setOverloadEnabled(overloadEnabled);
return compoundNameMaker1;
case ILLEGAL+SMALL:
LongNameMaker longNameMaker3 = new LongNameMaker(reservedNames,
crazylegalFirstChars, crazylegalChars, 1);
longNameMaker3.setOverloadEnabled(overloadEnabled);
return longNameMaker3;
case ILLEGAL+MIX:
nm1 = new LongNameMaker(reservedNames, false, 6);
nm2 = new ObfuscatorTask.KeywordNameMaker(reservedNames,
KeywordNameMaker.KEYWORDS,
KeywordNameMaker.SPACER);
MixNameMaker mixNameMaker2 = new MixNameMaker(null, reservedNames, nm1,
2);
mixNameMaker2.add(nm2, 1);
mixNameMaker2.setOverloadEnabled(overloadEnabled);
return mixNameMaker2;
case ILLEGAL+BEST:
nm1 = new ObfuscatorTask.KeywordNameMaker(reservedNames,
KeywordNameMaker.KEYWORDS,
KeywordNameMaker.SPACER);
nm2 = new LongNameMaker(reservedNames,false, 256);
mnm = new MixNameMaker(null, reservedNames, nm1,
1);
mnm.add(nm2,1);
mnm.setOverloadEnabled(overloadEnabled);
return mnm;
}
}
protected NameMaker createMethodNameMaker(String[] reservedNames, String fqClassName)
{
return createFieldNameMaker(reservedNames, fqClassName);
}
protected NameMaker createPackageNameMaker(String[] reservedNames, String packageName)
{
boolean topLevel = packageName.length() < 1;
switch (mode){
default:
case COMPATIBLE+SMALL:
case COMPATIBLE+MIX:
case COMPATIBLE+BEST:
if (topLevel && packagePrefix != null){
return new PrefixNameMaker(packagePrefix, reservedNames, new LongNameMaker(null, asciiLowerChars, asciiLowerChars, 1));
} else {
return new LongNameMaker(reservedNames,
asciiLowerChars, asciiLowerChars, 1);
}
case LEGAL+SMALL:
case ILLEGAL+SMALL:
if (topLevel && packagePrefix != null){
return new PrefixNameMaker(packagePrefix, reservedNames, new LongNameMaker(null, asciiFirstChars, asciiChars, 1));
} else {
return new LongNameMaker(reservedNames,
asciiFirstChars, asciiChars, 1);
}
case LEGAL+MIX:
case ILLEGAL+MIX:
AbstractNameMaker nm1 = new LongNameMaker(reservedNames,
asciiFirstChars, asciiChars, 1);
AbstractNameMaker nm3 = new LongNameMaker(reservedNames,true, 256);
AbstractNameMaker nm4 = new LongNameMaker(reservedNames,true, 4);
AbstractNameMaker nm2 = new ObfuscatorTask.KeywordNameMaker(reservedNames);
MixNameMaker mnm = new MixNameMaker(topLevel ? packagePrefix : null, reservedNames, nm1, 8);
mnm.add(nm4, 4);
mnm.add(nm2, 4);
mnm.add(nm3, 1);
return mnm;
case LEGAL+BEST:
case ILLEGAL+BEST:
if (topLevel && packagePrefix != null){
return new PrefixNameMaker(packagePrefix, reservedNames, new LongNameMaker(null, true, 256));
} else {
return new LongNameMaker(reservedNames, true, 256);
}
}
}
protected NameMaker createClassNameMaker(String[] reservedNames, String fqClassName)
{
return createPackageNameMaker(reservedNames, fqClassName);
}
protected NameMaker createInnerClassNameMaker(String[] reservedNames, String fqInnerClassName)
{
switch (mode){
default:
case COMPATIBLE+SMALL:
case COMPATIBLE+MIX:
case COMPATIBLE+BEST:
return new PrefixNameMaker("_", reservedNames, new LongNameMaker(null, asciiLowerChars, asciiLowerChars, 1));
case LEGAL+SMALL:
return new PrefixNameMaker("_", reservedNames, new LongNameMaker(null, asciiFirstChars, asciiChars, 1));
case LEGAL+MIX:
return new PrefixNameMaker("_", reservedNames, new LongNameMaker(null,true, 1));
case LEGAL+BEST:
return new PrefixNameMaker("_", reservedNames, new LongNameMaker(null,true, 4));
case ILLEGAL+SMALL:
return new LongNameMaker(reservedNames, asciiFirstChars, asciiChars, 1);
case ILLEGAL+MIX:
return new LongNameMaker(reservedNames,true, 1);
case ILLEGAL+BEST:
return new LongNameMaker(reservedNames,true, 10);
}
}
public String toString(){
switch (mode){
default:
return "yGuardNameFactory [naming-scheme: default; language-conformity: default]";
case COMPATIBLE+SMALL:
return "yGuardNameFactory [naming-scheme: small; language-conformity: compatible]";
case COMPATIBLE+MIX:
return "yGuardNameFactory [naming-scheme: mix; language-conformity: compatible]";
case COMPATIBLE+BEST:
return "yGuardNameFactory [naming-scheme: best; language-conformity: compatible]";
case LEGAL+SMALL:
return "yGuardNameFactory [naming-scheme: small; language-conformity: legal]";
case LEGAL+MIX:
return "yGuardNameFactory [naming-scheme: mix; language-conformity: legal]";
case LEGAL+BEST:
return "yGuardNameFactory [naming-scheme: best; language-conformity: legal]";
case ILLEGAL+SMALL:
return "yGuardNameFactory [naming-scheme: small; language-conformity: illegal]";
case ILLEGAL+MIX:
return "yGuardNameFactory [naming-scheme: mix; language-conformity: illegal]";
case ILLEGAL+BEST:
return "yGuardNameFactory [naming-scheme: best; language-conformity: illegal]";
}
}
}
static class CompoundNameMaker implements NameMaker{
private NameMaker nm1,nm2;
CompoundNameMaker(NameMaker nm1, NameMaker nm2){
this.nm1 = nm1;
this.nm2 = nm2;
}
public String nextName(String descriptor)
{
return nm1.nextName(descriptor)+nm2.nextName(descriptor);
}
}
static class MixNameMaker extends AbstractNameMaker {
List nameMakers = new ArrayList();
final String prefix;
MixNameMaker(String prefix, String[] reservedNames, AbstractNameMaker delegate, int count){
super(reservedNames, "O0", 1);
add(delegate, count);
this.prefix = prefix;
}
void add(AbstractNameMaker delegate, int count){
count = count < 1 ? 1 : count;
for (int i = 0; i < count; i++){
nameMakers.add(delegate);
}
Collections.shuffle(nameMakers);
}
String generateName(int i)
{
if (prefix != null){
return prefix + ((AbstractNameMaker)nameMakers.get(i % nameMakers.size())).generateName(i);
} else {
return ((AbstractNameMaker)nameMakers.get(i % nameMakers.size())).generateName(i);
}
}
}
static final class LongNameMaker extends AbstractNameMaker{
String chars;
String firstChars;
LongNameMaker(String[] reservedNames){
this(reservedNames, false, 256);
}
LongNameMaker(String[] reservedNames, boolean ascii, int length){
this(reservedNames, ascii?"Oo":"Oo\u00D2\u00D3\u00D4\u00D5\u00D6\u00D8\u00F4\u00F5\u00F6\u00F8",
ascii?"Oo0":"0Oo\u00D2\u00D3\u00D4\u00D5\u00D6\u00D8\u00F4\u00F5\u00F6\u00F8",length);
}
LongNameMaker(String[] reservedNames, String firstChars, String chars, int minLength){
super(reservedNames, null, minLength);
this.chars = chars;
if ( chars == null || chars.length() < 1 ) {
throw new IllegalArgumentException( "must specify at least one character!" );
}
this.firstChars = firstChars;
if (firstChars != null && firstChars.length()<1) this.firstChars = null;
}
String generateName(int i)
{
StringBuffer sb = new StringBuffer(20);
int tmp = i;
if (firstChars != null){
sb.append(firstChars.charAt(tmp % firstChars.length()));
if (firstChars.length() > 1){
tmp = tmp / firstChars.length();
} else {
tmp--;
}
}
while (tmp > 0){
sb.append(chars.charAt(tmp % chars.length()));
if (chars.length()>1){
tmp = tmp / chars.length();
} else {
tmp--;
}
}
if (chars.length()>1){
while (sb.length()< minLength){
sb.append(chars.charAt(0));
}
}
return sb.toString();
}
}
static final class KeywordNameMaker extends AbstractNameMaker{
static final String[] KEYWORDS = new String[]{
"this","super","new","Object","String","class","return","void","null","int",
"if","float","for","do","while","public","private","interface",};
static final String[] SPACER = new String[]{
".","$"," ","_",
};
static final String[] NOSPACER = new String[]{""};
String chars;
String[] keyWords;
String spacer[];
KeywordNameMaker(String[] reservedNames){
this(reservedNames, KEYWORDS, NOSPACER);
}
KeywordNameMaker(String[] reservedNames, String[] keyWords, String[] spacer){
super(reservedNames, "Oo0",0);
this.keyWords = keyWords;
this.spacer = spacer;
}
String generateName(int i)
{
StringBuffer sb = new StringBuffer(30);
int tmp = i;
int sc = 0;
while (tmp > 0){
sb.append(keyWords[tmp % keyWords.length]);
tmp = tmp / keyWords.length;
if (tmp>0){
sb.append(spacer[sc % spacer.length]);
sc++;
}
}
return sb.toString();
}
}
static final class PrefixNameMaker extends AbstractNameMaker {
private String prefix;
private AbstractNameMaker delegate;
PrefixNameMaker(String prefix, String[] reservedNames, AbstractNameMaker delegate){
super(reservedNames, "O0", 1);
this.prefix = prefix;
this.delegate = delegate;
}
String generateName(int i)
{
return prefix + delegate.generateName(i);
}
}
static abstract class AbstractNameMaker implements NameMaker{
Set reservedNames;
Map countMap = new HashMap();
String fillChars;
int minLength;
private static final String DUMMY = "(com.dummy.Dummy)";
protected boolean overloadEnabled = true;
private int counter = 1;
public boolean isOverloadEnabled() {
return overloadEnabled;
}
public void setOverloadEnabled(boolean overloadEnabled) {
this.overloadEnabled = overloadEnabled;
}
AbstractNameMaker(String[] reservedNames){
this(reservedNames, "0o", 256);
}
AbstractNameMaker(String[] reservedNames, String fillChars, int minLength){
if (reservedNames!= null && reservedNames.length>0){
this.reservedNames = new HashSet(Arrays.asList(reservedNames));
} else {
this.reservedNames = Collections.EMPTY_SET;
}
this.minLength = minLength;
this.fillChars = fillChars != null ? fillChars: "0O";
}
/** Return the next unique name for this namespace, differing only for identical arg-lists. */
public String nextName(String descriptor)
{
if (descriptor == null){
descriptor = DUMMY;
}
int j;
if (overloadEnabled){
descriptor = descriptor.substring(0, descriptor.lastIndexOf(')'));
Integer i = (Integer) countMap.get(descriptor);
if (i == null){
i = new Integer(1);
}
j = i.intValue();
} else {
j = counter;
}
String result = null;
StringBuffer sb = new StringBuffer(minLength>10?minLength+20:20);
do {
sb.setLength(0);
String name = generateName(j);
sb.append(name);
if (sb.length() < minLength){
while (sb.length() ");
}
classNames.clear();
}
}
}
public static final class LineNumberSqueezer implements LineNumberTableMapper {
private List squeezedNumbers = new ArrayList();
public boolean mapLineNumberTable(String className, String methodName, String methodSignature, LineNumberTableAttrInfo lineNumberTable) {
final LineNumberInfo[] table = lineNumberTable.getLineNumberTable();
if (table.length > 0){
final LineNumberInfo lineNumberInfo = new LineNumberInfo(table[0].getStartPC(), table[0].getLineNumber());
lineNumberTable.setLineNumberTable(new LineNumberInfo[]{lineNumberInfo});
squeezedNumbers.add(new Object[]{className, methodName, methodSignature, lineNumberInfo});
return true;
}
return false;
}
public void logProperties(PrintWriter pw) {
if (!squeezedNumbers.isEmpty()){
for (Iterator it = squeezedNumbers.iterator(); it.hasNext();){
Object[] ar = (Object[]) it.next();
String className = ar[0].toString();
String methodName = ar[1].toString();
String methodSignature = ar[2].toString();
int line = ((LineNumberInfo)ar[3]).getLineNumber();
pw.println(" ");
}
squeezedNumbers.clear();
}
}
}
public static final class LineNumberScrambler {
private int[] scrambled;
private int[] unscrambled;
public LineNumberScrambler(int size, long seed){
this.scrambled = new int[size];
this.unscrambled = new int[size];
for (int i = 0; i < size; i++){
this.scrambled[i] = i;
this.unscrambled[i] = i;
}
Random r = new Random(seed);
for (int i = 0; i < 10; i++){
for (int j = 0; j < size; j++){
int otherIndex = r.nextInt(size);
if (otherIndex != j){
int pos1 = this.scrambled[j];
int pos2 = this.scrambled[otherIndex];
int p1 = this.unscrambled[pos1];
int p2 = this.unscrambled[pos2];
this.unscrambled[pos1] = p2;
this.unscrambled[pos2] = p1;
this.scrambled[j] = pos2;
this.scrambled[otherIndex] = pos1;
}
}
}
// for (int i = 0; i < 10000; i++) {
// System.out.println("scramble " + i + " " + scramble(i));
// if (unscramble(scramble(i)) != i){
// throw new RuntimeException();
// }
// }
// System.out.println("all is well");
}
public int scramble(int i){
if (i >= scrambled.length){
return scrambled[i % scrambled.length] + (i / scrambled.length) * scrambled.length;
} else {
return scrambled[i];
}
}
public int unscramble(int i){
if (i >= scrambled.length){
return unscrambled[i % scrambled.length] + (i / scrambled.length) * scrambled.length;
} else {
return unscrambled[i];
}
}
}
public static void main(String[] args){
new LineNumberScrambler(2000, 234432);
}
// public static void main(String[] args) throws Exception{
// Project project = new Project();
// File base =new File("/home/muellese/job/localcvs/yguard/deploy");
// project.setBaseDir(base);
// project.init();
// ObfuscatorTask os = new ObfuscatorTask();
// os.setProject(project);
// ObfuscatorTask.InOutPair iop = new ObfuscatorTask.InOutPair();
// iop.setIn(new File(base, "test.jar"));
// iop.setOut(new File(base, "testobf.jar"));
// os.setLogFile(new File(base,"testobflog.xml.gz"));
// ObfuscatorTask.Property pop = new ObfuscatorTask.Property();
// pop.setName("expose-attributes");
// pop.setValue("Deprecated");
// os.addConfiguredProperty(pop);
// ObfuscatorTask.ExposeSection eps = os.createExpose();
// ObfuscatorTask.ClassSection sec = new ObfuscatorTask.ClassSection();
// PatternSet patternSet = new PatternSet();
// patternSet.setProject(project);
// patternSet.setIncludes("com.yworks.yguard.ObfuscatorTask*");
// sec.addConfiguredPatternSet(patternSet);
// ObfuscatorTask.Modifiers mm = new ObfuscatorTask.Modifiers();
// mm.setValue("protected");
// sec.setClasses(mm);
// eps.addConfiguredClass(sec);
// os.addConfiguredInOutPair(iop);
// os.execute();
// }
private String annotationClass;
public String getAnnotationClass() {
return annotationClass;
}
public void setAnnotationClass(String annotationClass) {
this.annotationClass = annotationClass;
}
}