1 19 20 package jode.obfuscator; 21 import jode.GlobalOptions; 22 import jode.bytecode.SearchPath; 23 import jode.bytecode.ClassInfo; 24 import jode.bytecode.Reference; 25 import jode.obfuscator.modules.WildCard; 26 import jode.obfuscator.modules.MultiIdentifierMatcher; 27 import jode.obfuscator.modules.SimpleAnalyzer; 28 import java.io.*; 29 import java.util.zip.ZipOutputStream ; 30 31 import java.util.Collection ; 32 import java.util.Iterator ; 33 import java.util.Set ; 34 import java.util.HashSet ; 35 import java.util.Map ; 36 import java.util.HashMap ; 37 import java.util.TreeMap ; 38 import java.lang.UnsupportedOperationException ; 39 40 import java.util.WeakHashMap ; 42 44 public class ClassBundle implements OptionHandler { 45 PackageIdentifier basePackage; 46 47 50 Set toAnalyze = new HashSet (); 51 52 String classPath; 53 String destDir; 54 55 String inTableFile; 56 String outTableFile; 57 String outRevTableFile; 58 59 IdentifierMatcher loading; 60 IdentifierMatcher preserving; 61 IdentifierMatcher reaching; 62 CodeTransformer[] preTrafos; 63 CodeAnalyzer analyzer; 64 CodeTransformer[] postTrafos; 65 Renamer renamer; 66 67 68 public ClassBundle() { 69 classPath = System.getProperty("java.class.path") 70 .replace(File.pathSeparatorChar, SearchPath.altPathSeparatorChar); 71 destDir = "."; 72 basePackage = new PackageIdentifier(this, null, "", ""); 73 basePackage.setReachable(); 74 basePackage.setPreserved(); 75 } 76 77 private static final Map aliasesHash = new WeakHashMap (); 79 private static final Map clazzCache = new HashMap (); 83 private static final Map referenceCache = new HashMap (); 84 85 public static void setStripOptions(Collection stripString) { 86 } 87 public void setOption(String option, Collection values) { 88 if (option.equals("classpath")) { 89 Iterator i = values.iterator(); 90 StringBuffer sb = new StringBuffer ((String ) i.next()); 91 while (i.hasNext()) { 92 sb.append(SearchPath.altPathSeparatorChar) 93 .append((String )i.next()); 94 } 95 ClassInfo.setClassPath(sb.toString()); 96 return; 97 } 98 99 if (option.equals("dest")) { 100 if (values.size() != 1) 101 throw new IllegalArgumentException 102 ("Only one destination path allowed"); 103 destDir = (String ) values.iterator().next(); 104 return; 105 } 106 107 if (option.equals("verbose")) { 108 if (values.size() != 1) 109 throw new IllegalArgumentException 110 ("Verbose takes one int parameter"); 111 GlobalOptions.verboseLevel 112 = ((Integer ) values.iterator().next()).intValue(); 113 return; 114 } 115 116 if (option.equals("intable") || option.equals("table")) { 117 if (values.size() != 1) 118 throw new IllegalArgumentException 119 ("Only one destination path allowed"); 120 inTableFile = (String ) values.iterator().next(); 121 return; 122 } 123 124 if (option.equals("outtable")) { 125 if (values.size() != 1) 126 throw new IllegalArgumentException 127 ("Only one destination path allowed"); 128 outTableFile = (String ) values.iterator().next(); 129 return; 130 } 131 132 if (option.equals("outrevtable") || option.equals("revtable")) { 133 if (values.size() != 1) 134 throw new IllegalArgumentException 135 ("Only one destination path allowed"); 136 outRevTableFile = (String ) values.iterator().next(); 137 return; 138 } 139 140 if (option.equals("strip")) { 141 next_token: 142 for (Iterator iter = values.iterator(); iter.hasNext(); ) { 143 String token = (String ) iter.next(); 144 for (int i=0; i < Main.stripNames.length; i++) { 145 if (token.equals(Main.stripNames[i])) { 146 Main.stripping |= 1 << i; 147 continue next_token; 148 } 149 } 150 throw new IllegalArgumentException ("Unknown strip option: `" 151 +token+"'"); 152 } 153 return; 154 } 155 156 if (option.equals("load")) { 157 if (values.size() == 1) { 158 Object value = values.iterator().next(); 159 if (value instanceof String ) 160 loading = new WildCard((String )value); 161 else 162 loading = (IdentifierMatcher) value; 163 } else { 164 IdentifierMatcher[] matchers 165 = new IdentifierMatcher[values.size()]; 166 int j = 0; 167 for (Iterator i = values.iterator(); i.hasNext(); ) { 168 Object value = i.next(); 169 matchers[j++] = (value instanceof String 170 ? new WildCard((String )value) 171 : (IdentifierMatcher) value); 172 } 173 loading = new MultiIdentifierMatcher 174 (MultiIdentifierMatcher.OR, matchers); 175 } 176 return; 177 } 178 179 if (option.equals("preserve")) { 180 if (values.size() == 1) { 181 Object value = values.iterator().next(); 182 if (value instanceof String ) 183 preserving = new WildCard((String )value); 184 else 185 preserving = (IdentifierMatcher) value; 186 } else { 187 IdentifierMatcher[] matchers 188 = new IdentifierMatcher[values.size()]; 189 int j = 0; 190 for (Iterator i = values.iterator(); i.hasNext(); ) { 191 Object value = i.next(); 192 matchers[j++] = (value instanceof String 193 ? new WildCard((String )value) 194 : (IdentifierMatcher) value); 195 } 196 preserving = new MultiIdentifierMatcher 197 (MultiIdentifierMatcher.OR, matchers); 198 } 199 return; 200 } 201 202 if (option.equals("reach")) { 203 if (values.size() == 1) { 205 Object value = values.iterator().next(); 206 if (value instanceof String ) 207 reaching = new WildCard((String )value); 208 else 209 reaching = (IdentifierMatcher) value; 210 } else { 211 IdentifierMatcher[] matchers 212 = new IdentifierMatcher[values.size()]; 213 int j = 0; 214 for (Iterator i = values.iterator(); i.hasNext(); ) { 215 Object value = i.next(); 216 matchers[j++] = (value instanceof String 217 ? new WildCard((String )value) 218 : (IdentifierMatcher) value); 219 } 220 reaching = new MultiIdentifierMatcher 221 (MultiIdentifierMatcher.OR, matchers); 222 } 223 } 224 225 if (option.equals("pre")) { 226 preTrafos = (CodeTransformer[]) 227 values.toArray(new CodeTransformer[values.size()]); 228 return; 229 } 230 if (option.equals("analyzer")) { 231 if (values.size() != 1) 232 throw new IllegalArgumentException 233 ("Only one analyzer is allowed"); 234 analyzer = (CodeAnalyzer) values.iterator().next(); 235 return; 236 } 237 if (option.equals("post")) { 238 postTrafos = (CodeTransformer[]) 239 values.toArray(new CodeTransformer[values.size()]); 240 return; 241 } 242 243 if (option.equals("renamer")) { 244 if (values.size() != 1) 245 throw new IllegalArgumentException 246 ("Only one renamer allowed"); 247 renamer = (Renamer) values.iterator().next(); 248 return; 249 } 250 throw new IllegalArgumentException ("Invalid option `"+option+"'."); 251 } 252 253 public Reference getReferenceAlias(Reference ref) { 254 Reference alias = (Reference) aliasesHash.get(ref); 255 if (alias == null) { 256 Identifier ident = getIdentifier(ref); 257 String newType = getTypeAlias(ref.getType()); 258 if (ident == null) 259 alias = Reference.getReference 260 (ref.getClazz(), ref.getName(), newType); 261 else 262 alias = Reference.getReference 263 ("L"+ident.getParent().getFullAlias().replace('.','/')+';', 264 ident.getAlias(), newType); 265 aliasesHash.put(ref, alias); 266 } 267 return alias; 268 } 269 270 public String getClassAlias(String className) { 271 ClassIdentifier classIdent = getClassIdentifier(className); 272 if (classIdent == null) 273 return className; 274 return classIdent.getFullAlias(); 275 } 276 277 public String getTypeAlias(String typeSig) { 278 String alias = (String ) aliasesHash.get(typeSig); 279 if (alias == null) { 280 StringBuffer newSig = new StringBuffer (); 281 int index = 0, nextindex; 282 while ((nextindex = typeSig.indexOf('L', index)) != -1) { 283 newSig.append(typeSig.substring(index, nextindex+1)); 284 index = typeSig.indexOf(';', nextindex); 285 String typeAlias = getClassAlias 286 (typeSig.substring(nextindex+1, index).replace('/','.')); 287 newSig.append(typeAlias.replace('.', '/')); 288 } 289 alias = newSig.append(typeSig.substring(index)) 290 .toString().intern(); 291 aliasesHash.put(typeSig, alias); 292 } 293 return alias; 294 } 295 296 public void addClassIdentifier(Identifier ident) { 297 } 298 299 public ClassIdentifier getClassIdentifier(String name) { 300 if (clazzCache.containsKey(name)) 301 return (ClassIdentifier) clazzCache.get(name); 302 ClassIdentifier ident 303 = (ClassIdentifier) basePackage.getIdentifier(name); 304 clazzCache.put(name, ident); 305 return ident; 306 } 307 308 public Identifier getIdentifier(Reference ref) { 309 if (referenceCache.containsKey(ref)) 310 return (Identifier) referenceCache.get(ref); 311 312 String clName = ref.getClazz(); 313 if (clName.charAt(0) == '[') 314 315 return null; 316 ClassIdentifier clazzIdent = 317 getClassIdentifier(clName.substring(1, clName.length()-1) 318 .replace('/','.')); 319 Identifier ident = 320 clazzIdent == null ? null 321 : clazzIdent.getIdentifier(ref.getName(), ref.getType()); 322 referenceCache.put(ref, ident); 323 return ident; 324 } 325 326 public void reachableClass(String clazzName) { 327 ClassIdentifier ident = getClassIdentifier(clazzName); 328 if (ident != null) 329 ident.setReachable(); 330 } 331 332 public void reachableReference(Reference ref, boolean isVirtual) { 333 String clName = ref.getClazz(); 334 if (clName.charAt(0) == '[') 335 336 return; 337 ClassIdentifier ident = 338 getClassIdentifier(clName.substring(1, clName.length()-1) 339 .replace('/','.')); 340 if (ident != null) 341 ident.reachableReference(ref, isVirtual); 342 } 343 344 public void analyzeIdentifier(Identifier ident) { 345 if (ident == null) 346 throw new NullPointerException (); 347 toAnalyze.add(ident); 348 } 349 350 public void analyze() { 351 while(!toAnalyze.isEmpty()) { 352 Identifier ident = (Identifier) toAnalyze.iterator().next(); 353 toAnalyze.remove(ident); 354 ident.analyze(); 355 } 356 } 357 358 public IdentifierMatcher getPreserveRule() { 359 return preserving; 360 } 361 362 public CodeAnalyzer getCodeAnalyzer() { 363 return analyzer; 364 } 365 366 public CodeTransformer[] getPreTransformers() { 367 return preTrafos; 368 } 369 370 public CodeTransformer[] getPostTransformers() { 371 return postTrafos; 372 } 373 374 public void buildTable(Renamer renameRule) { 375 basePackage.buildTable(renameRule); 376 } 377 378 public void readTable() { 379 try { 380 TranslationTable table = new TranslationTable(); 381 InputStream input = new FileInputStream(inTableFile); 382 table.load(input); 383 input.close(); 384 basePackage.readTable(table); 385 } catch (java.io.IOException ex) { 386 GlobalOptions.err.println("Can't read rename table " 387 + inTableFile); 388 ex.printStackTrace(GlobalOptions.err); 389 } 390 } 391 392 public void writeTable() { 393 TranslationTable table = new TranslationTable(); 394 basePackage.writeTable(table, false); 395 try { 396 OutputStream out = new FileOutputStream(outTableFile); 397 table.store(out); 398 out.close(); 399 } catch (java.io.IOException ex) { 400 GlobalOptions.err.println("Can't write rename table " 401 + outTableFile); 402 ex.printStackTrace(GlobalOptions.err); 403 } 404 } 405 406 public void writeRevTable() { 407 TranslationTable revtable = new TranslationTable(); 408 basePackage.writeTable(revtable, true); 409 try { 410 OutputStream out = new FileOutputStream(outRevTableFile); 411 revtable.store(out); 412 out.close(); 413 } catch (java.io.IOException ex) { 414 GlobalOptions.err.println("Can't write rename table " 415 + outRevTableFile); 416 ex.printStackTrace(GlobalOptions.err); 417 } 418 } 419 420 public void doTransformations() { 421 basePackage.doTransformations(); 422 } 423 424 public void storeClasses() { 425 if (destDir.endsWith(".jar") || 426 destDir.endsWith(".zip")) { 427 try { 428 ZipOutputStream zip = new ZipOutputStream 429 (new FileOutputStream(destDir)); 430 basePackage.storeClasses(zip); 431 zip.close(); 432 } catch (IOException ex) { 433 GlobalOptions.err.println 434 ("Can't write zip file: "+destDir); 435 ex.printStackTrace(GlobalOptions.err); 436 } 437 } else { 438 File directory = new File(destDir); 439 if (!directory.exists()) { 440 GlobalOptions.err.println("Destination directory " 441 +directory.getPath() 442 +" doesn't exists."); 443 return; 444 } 445 basePackage.storeClasses(new File(destDir)); 446 } 447 } 448 449 public void run() { 450 if (analyzer == null) 451 analyzer = new SimpleAnalyzer(); 452 if (preTrafos == null) 453 preTrafos = new CodeTransformer[0]; 454 if (postTrafos == null) 455 postTrafos = new CodeTransformer[0]; 456 if (renamer == null) 457 renamer = new Renamer() { 458 public Iterator generateNames(Identifier ident) { 459 final String base = ident.getName(); 460 return new Iterator () { 461 int last = 0; 462 463 public boolean hasNext() { 464 return true; 465 } 466 467 public Object next() { 468 return (last++ == 0 ? base : base + last); 469 } 470 471 public void remove() { 472 throw new UnsupportedOperationException (); 473 } 474 }; 475 } 476 }; 477 478 479 Runtime runtime = Runtime.getRuntime(); 480 long free = runtime.freeMemory(); 481 long last; 482 do { 483 last = free; 484 runtime.gc(); 485 runtime.runFinalization(); 486 free = runtime.freeMemory(); 487 } while (free < last); 488 System.err.println("used before: "+(runtime.totalMemory()- free)); 489 490 GlobalOptions.err.println("Loading and preserving classes"); 491 492 long time = System.currentTimeMillis(); 493 basePackage.loadMatchingClasses(loading); 494 basePackage.applyPreserveRule(preserving); 495 System.err.println("Time used: "+(System.currentTimeMillis() - time)); 496 497 498 GlobalOptions.err.println("Computing reachability"); 499 time = System.currentTimeMillis(); 500 analyze(); 501 System.err.println("Time used: "+(System.currentTimeMillis() - time)); 502 503 free = runtime.freeMemory(); 504 do { 505 last = free; 506 runtime.gc(); 507 runtime.runFinalization(); 508 free = runtime.freeMemory(); 509 } while (free < last); 510 System.err.println("used after analyze: " 511 + (runtime.totalMemory() - free)); 512 513 GlobalOptions.err.println("Renaming methods"); 514 time = System.currentTimeMillis(); 515 if (inTableFile != null) 516 readTable(); 517 buildTable(renamer); 518 if (outTableFile != null) 519 writeTable(); 520 if (outRevTableFile != null) 521 writeRevTable(); 522 System.err.println("Time used: "+(System.currentTimeMillis() - time)); 523 524 GlobalOptions.err.println("Transforming the classes"); 525 time = System.currentTimeMillis(); 526 doTransformations(); 527 System.err.println("Time used: "+(System.currentTimeMillis() - time)); 528 529 free = runtime.freeMemory(); 530 do { 531 last = free; 532 runtime.gc(); 533 runtime.runFinalization(); 534 free = runtime.freeMemory(); 535 } while (free < last); 536 System.err.println("used after transform: " 537 + (runtime.totalMemory() - free)); 538 539 GlobalOptions.err.println("Writing new classes"); 540 time = System.currentTimeMillis(); 541 storeClasses(); 542 System.err.println("Time used: "+(System.currentTimeMillis() - time)); 543 } 544 } 545 | Popular Tags |