| 1 26 package com.yworks.yguard.obf; 27 28 import com.yworks.yguard.Conversion; 29 import com.yworks.yguard.ParseException; 30 import com.yworks.yguard.obf.classfile.ClassConstants; 31 import com.yworks.yguard.obf.classfile.ClassFile; 32 import com.yworks.yguard.obf.classfile.LineNumberTableAttrInfo; 33 import com.yworks.yguard.obf.classfile.Logger; 34 import com.yworks.yguard.obf.classfile.NameMapper; 35 36 import java.io.PrintWriter ; 37 import java.lang.reflect.Modifier ; 38 import java.util.ArrayList ; 39 import java.util.Enumeration ; 40 import java.util.HashSet ; 41 import java.util.List ; 42 import java.util.Set ; 43 import java.util.StringTokenizer ; 44 import java.util.Vector ; 45 46 51 public class ClassTree implements NameMapper 52 { 53 public static final char PACKAGE_LEVEL = '/'; 55 public static final char CLASS_LEVEL = '$'; 56 public static final char METHOD_FIELD_LEVEL = '/'; 57 58 private Vector retainAttrs = new Vector (); private Pk root = null; 62 64 public static Enumeration getNameEnum(String name) 65 { 66 Vector vec = new Vector (); 67 String nameOrig = name; 68 while (!name.equals("")) 69 { 70 int posP = name.indexOf(PACKAGE_LEVEL); 71 int posC = name.indexOf(CLASS_LEVEL); 72 Cons cons = null; 73 if (posP == -1 && posC == -1) 74 { 75 cons = new Cons(new Character (CLASS_LEVEL), name); 76 name = ""; 77 } 78 if (posP == -1 && posC != -1) 79 { 80 cons = new Cons(new Character (CLASS_LEVEL), name.substring(0, posC)); 81 while ((posC+1 < name.length()) && (name.charAt(posC+1) == CLASS_LEVEL)) posC++; 84 name = name.substring(posC + 1, name.length()); 85 } 86 if (posP != -1 && posC == -1) 87 { 88 cons = new Cons(new Character (PACKAGE_LEVEL), name.substring(0, posP)); 89 name = name.substring(posP + 1, name.length()); 90 } 91 if (posP != -1 && posC != -1) 92 { 93 if (posP < posC) 94 { 95 cons = new Cons(new Character (PACKAGE_LEVEL), name.substring(0, posP)); 96 name = name.substring(posP + 1, name.length()); 97 } 98 else 99 { 100 throw new IllegalArgumentException ("Invalid fully qualified name (a): " + 101 nameOrig); 102 } 103 } 104 if (((String )cons.cdr).equals("")) 105 { 106 throw new IllegalArgumentException ("Invalid fully qualified name (b): " + 107 nameOrig); 108 } 109 vec.addElement(cons); 110 } 111 return vec.elements(); 112 } 113 114 115 117 public ClassTree() 118 { 119 root = Pk.createRoot(this); 120 } 121 122 123 public Pk getRoot() {return root;} 124 125 128 public TreeItem findTreeItem(String [] nameParts){ 129 TreeItem tmp = root; 130 for (int i = 0; tmp != null && i < nameParts.length; i++){ 131 String name = nameParts[i]; 132 tmp = findSubItem(tmp, name); 133 } 134 return tmp; 135 } 136 137 140 public Cl findClassForName(String name){ 141 int dindex = name.indexOf('$'); 142 String innerClass = null; 143 if (dindex>0){ 144 innerClass = name.substring(dindex+1); 145 name = name.substring(0, dindex); 146 } 147 int pindex = name.lastIndexOf('.'); 148 String packageName = null; 149 if (pindex>0){ 150 packageName = name.substring(0, pindex); 151 name = name.substring(pindex+1); 152 } 153 Pk pk = root; 154 if (packageName != null){ 155 for (StringTokenizer st = new StringTokenizer (packageName, ".", false); st.hasMoreTokens();){ 156 String token = st.nextToken(); 157 pk = findPackage(pk, token); 158 if (pk == null) return null; 159 } 160 } 161 Cl cl = findClass(pk, name); 162 if (cl != null && innerClass != null){ 163 for (StringTokenizer st = new StringTokenizer (innerClass, "$", false); st.hasMoreTokens();){ 164 String token = st.nextToken(); 165 cl = findClass(cl, token); 166 if (cl == null) return null; 167 } 168 } 169 return cl; 170 } 171 172 private Pk findPackage(TreeItem parent, String pName){ 173 if (parent instanceof Pk){ 174 for (Enumeration enumeration = ((Pk)parent).getPackageEnum(); enumeration.hasMoreElements();){ 175 Pk subPk = (Pk) enumeration.nextElement(); 176 if (subPk.getInName().equals(pName)){ 177 return subPk; 178 } 179 } 180 } 181 return null; 182 } 183 184 private Cl findClass(PkCl parent, String pName){ 185 for (Enumeration enumeration = ((PkCl)parent).getClassEnum(); enumeration.hasMoreElements();){ 186 Cl cl = (Cl) enumeration.nextElement(); 187 if (cl.getInName().equals(pName)){ 188 return cl; 189 } 190 } 191 return null; 192 } 193 194 private TreeItem findSubItem(TreeItem parent, String childName){ 195 if (parent instanceof Pk){ 196 for (Enumeration enumeration = ((Pk)parent).getPackageEnum(); enumeration.hasMoreElements();){ 197 Pk subPk = (Pk) enumeration.nextElement(); 198 if (subPk.getInName().equals(childName)){ 199 return subPk; 200 } 201 } 202 for (Enumeration enumeration = ((Pk)parent).getClassEnum(); enumeration.hasMoreElements();){ 203 Cl cl = (Cl) enumeration.nextElement(); 204 if (cl.getInName().equals(childName)){ 205 return cl; 206 } 207 } 208 } 209 if (parent instanceof Cl){ 210 for (Enumeration enumeration = ((Cl)parent).getClassEnum(); enumeration.hasMoreElements();){ 211 Cl cl = (Cl) enumeration.nextElement(); 212 if (cl.getInName().equals(childName)){ 213 return cl; 214 } 215 } 216 return null; 217 } 218 return null; 219 } 220 221 222 public String getOutName(String inName) 223 { 224 try 225 { 226 TreeItem ti = root; 227 StringBuffer sb = new StringBuffer (); 228 for (Enumeration nameEnum = getNameEnum(inName); nameEnum.hasMoreElements(); ) 229 { 230 Cons nameSegment = (Cons)nameEnum.nextElement(); 231 char tag = ((Character )nameSegment.car).charValue(); 232 String name = (String )nameSegment.cdr; 233 switch (tag) 234 { 235 case PACKAGE_LEVEL: 236 if (ti != null) 237 { 238 ti = ((Pk)ti).getPackage(name); 239 if (ti != null) 240 { 241 sb.append(ti.getOutName()); 242 } 243 else 244 { 245 sb.append(name); 246 } 247 } 248 else 249 { 250 sb.append(name); 251 } 252 sb.append(PACKAGE_LEVEL); 253 break; 254 255 case CLASS_LEVEL: 256 sb.append(name); 257 return sb.toString(); 258 259 default: 260 throw new RuntimeException ("Internal error: illegal package/class name tag"); 261 } 262 } 263 } 264 catch (Exception e) 265 { 266 } 268 return inName; 269 } 270 271 272 public void addClassFile(ClassFile cf) 273 { 274 TreeItem ti = root; 276 char parentTag = PACKAGE_LEVEL; 277 for (Enumeration nameEnum = getNameEnum(cf.getName()); nameEnum.hasMoreElements(); ) 278 { 279 Cons nameSegment = (Cons)nameEnum.nextElement(); 280 char tag = ((Character )nameSegment.car).charValue(); 281 String name = (String )nameSegment.cdr; 282 switch (tag) 283 { 284 case PACKAGE_LEVEL: 285 ti = ((Pk)ti).addPackage(name); 286 break; 287 288 case CLASS_LEVEL: 289 if (nameEnum.hasMoreElements()) 291 { 292 ti = ((PkCl)ti).addPlaceholderClass(name); 293 } 294 else 295 { 296 Cl cl =((PkCl)ti).addClass(name, cf.getSuper(), cf.getInterfaces(), cf.getModifiers()); 297 cl.setInnerClassModifiers(cf.getInnerClassModifiers()); 298 cl.setClassFileAccess(cf.getClassFileAccess()); 299 ti = cl; 300 } 301 break; 302 303 default: 304 throw new ParseException("Internal error: illegal package/class name tag"); 305 } 306 parentTag = tag; 307 } 308 309 if (ti instanceof Cl) 311 { 312 Cl cl = (Cl)ti; 313 cl.access = cf.getModifiers(); 314 315 for (Enumeration enumeration = cf.getMethodEnum(); enumeration.hasMoreElements(); ) 317 { 318 Cons cons = (Cons)enumeration.nextElement(); 319 cl.addMethod(((Boolean )((Cons)cons.car).car).booleanValue(), (String )((Cons)cons.car).cdr, (String )((Cons)cons.cdr).car, ((Integer )((Cons)cons.cdr).cdr).intValue()); 320 } 321 322 for (Enumeration enumeration = cf.getFieldEnum(); enumeration.hasMoreElements(); ) 324 { 325 Cons cons = (Cons)enumeration.nextElement(); 326 cl.addField(((Boolean )((Cons)cons.car).car).booleanValue(), (String )((Cons)cons.car).cdr, (String )((Cons)cons.cdr).car, ((Integer )((Cons)cons.cdr).cdr).intValue()); 327 } 328 } 329 else 330 { 331 throw new ParseException("Inconsistent class file."); 332 } 333 } 334 335 336 public void retainAttribute(String name) 337 { 338 retainAttrs.addElement(name); 339 } 340 341 private boolean modifierMatch(int level, int mods){ 342 if (level == YGuardRule.LEVEL_NONE) return false; 343 if (Modifier.isPublic(mods)){ 344 return (level & YGuardRule.PUBLIC) == YGuardRule.PUBLIC; 345 } 346 if (Modifier.isProtected(mods)){ 347 return (level & YGuardRule.PROTECTED) == YGuardRule.PROTECTED; 348 } 349 if (Modifier.isPrivate(mods)){ 350 return (level & YGuardRule.PRIVATE) == YGuardRule.PRIVATE; 351 } 352 return (level & YGuardRule.FRIENDLY) == YGuardRule.FRIENDLY; 354 } 355 356 357 public void retainClass(String name, int classLevel, int methodLevel, int fieldLevel, boolean retainHierarchy) 358 { 359 360 for (Enumeration clEnum = getClEnum(name, classLevel); clEnum.hasMoreElements(); ) 362 { 363 Cl classItem = (Cl)clEnum.nextElement(); 364 if(retainHierarchy && classLevel != YGuardRule.LEVEL_NONE) retainHierarchy(classItem); 365 if (methodLevel != YGuardRule.LEVEL_NONE) 367 { 368 for (Enumeration enumeration = classItem.getMethodEnum(); enumeration.hasMoreElements(); ) 369 { 370 Md md = (Md)enumeration.nextElement(); 371 if (modifierMatch(methodLevel, md.getModifiers())) 372 { 373 md.setOutName(md.getInName()); 374 md.setFromScript(); 375 } 376 } 377 if ((methodLevel & (YGuardRule.PUBLIC | YGuardRule.PROTECTED | YGuardRule.FRIENDLY)) != 0 379 ||(fieldLevel & (YGuardRule.PUBLIC | YGuardRule.PROTECTED | YGuardRule.FRIENDLY)) != 0){ 380 int mask = YGuardRule.PRIVATE; 381 int ml = methodLevel & ~mask; 382 int fl = fieldLevel & ~mask; 383 int cl = classLevel & ~mask; 384 String [] interfaces = classItem.getInterfaces(); 385 if (interfaces != null){ 386 for (int i = 0; i < interfaces.length; i++){ 387 String interfaceClass = interfaces[i]; 388 retainClass(interfaceClass, cl, ml, fl, false); 389 } 390 } 391 String superClass = classItem.getSuperClass(); 392 if (superClass != null){ 393 if (!superClass.startsWith(classItem.getParent().getFullInName())){ 395 mask |= YGuardRule.FRIENDLY; 396 ml = methodLevel & ~mask; 397 fl = fieldLevel & ~mask; 398 cl = classLevel & ~mask; 399 } 400 retainClass(superClass, cl, ml, fl, false); 401 } 402 } 403 } 404 405 if (fieldLevel != YGuardRule.LEVEL_NONE) 407 { 408 for (Enumeration enumeration = classItem.getFieldEnum(); enumeration.hasMoreElements(); ) 409 { 410 Fd fd = (Fd)enumeration.nextElement(); 411 if (modifierMatch(fieldLevel, fd.getModifiers())) 412 { 413 fd.setOutName(fd.getInName()); 414 fd.setFromScript(); 415 } 416 } 417 } 418 } 419 } 420 421 422 public void retainMethod(String name, String descriptor) 423 { 424 for (Enumeration enumeration = getMdEnum(name, descriptor); 425 enumeration.hasMoreElements(); ) { 426 Md md = (Md)enumeration.nextElement(); 427 md.setOutName(md.getInName()); 428 md.setFromScript(); 429 } 430 } 431 432 433 public void retainField(String name) 434 { 435 for (Enumeration enumeration = getFdEnum(name); enumeration.hasMoreElements(); ) { 436 Fd fd = (Fd)enumeration.nextElement(); 437 fd.setOutName(fd.getInName()); 438 fd.setFromScript(); 439 } 440 } 441 442 443 public void retainPackageMap(String name, String obfName) 444 { 445 retainItemMap(getPk(name), obfName); 446 } 447 448 449 public void retainClassMap(String name, String obfName) 450 { 451 retainItemMap(getCl(name), obfName); 452 } 453 454 455 public void retainMethodMap(String name, String descriptor, 456 String obfName) 457 { 458 retainItemMap(getMd(name, descriptor), obfName); 459 } 460 461 462 public void retainFieldMap(String name, String obfName) 463 { 464 retainItemMap(getFd(name), obfName); 465 } 466 467 private void retainItemMap(TreeItem item, String obfName) 469 { 470 if (!item.isFixed()) 471 { 472 item.setOutName(obfName); 473 item.setFromScriptMap(); 474 } else { 475 if (!item.getOutName().equals(obfName)){ 476 item.setOutName(obfName); 477 item.setFromScriptMap(); 478 Logger.getInstance().warning("'" + item.getFullInName() + "' will be remapped to '" + obfName + "' according to mapping rule!"); 480 } 481 } 482 } 488 489 490 public void generateNames() 491 { 492 walkTree(new TreeAction() { 493 public void packageAction(Pk pk) {pk.generateNames();} 494 public void classAction(Cl cl) {cl.generateNames();} 495 }); 496 } 497 498 499 public void resolveClasses() throws ClassNotFoundException  500 { 501 walkTree(new TreeAction() { 502 public void classAction(Cl cl) {cl.resetResolve();} 503 }); 504 walkTree(new TreeAction() { 505 public void classAction(Cl cl) {cl.setupNameListDowns();} 506 }); 507 Cl.nameSpace = 0; 508 final ClassNotFoundException [] ex = new ClassNotFoundException [1]; 509 try{ 510 walkTree(new TreeAction() { 511 public void classAction(Cl cl) { 512 try{ 513 cl.resolveOptimally(); 514 } catch (ClassNotFoundException cnfe){ 515 ex[0] = cnfe; 516 throw new RuntimeException (); 517 } 518 } 519 }); 520 } catch (RuntimeException rte){ 521 if (ex[0] != null){ 522 throw ex[0]; 523 } else { 524 throw rte; 525 } 526 } 527 } 528 529 530 public String [] getAttrsToKeep() 531 { 532 String [] attrs = new String [retainAttrs.size()]; 533 for (int i = 0; i < attrs.length; i++) 534 { 535 attrs[i] = (String )retainAttrs.elementAt(i); 536 } 537 return attrs; 538 } 539 540 542 public Enumeration getClEnum(String fullName) 543 { 544 return getClEnum(fullName, YGuardRule.LEVEL_PRIVATE); 545 } 546 547 549 public Enumeration getClEnum(String fullName, final int classMode) 550 { 551 final Vector vec = new Vector (); 552 553 if (fullName.indexOf('*') != -1) { 556 if (fullName.indexOf('!') == 0) { 558 final String fName = fullName.substring(1); 559 walkTree(new TreeAction() { 560 public void classAction(Cl cl) { 561 if (cl.isWildcardMatch(fName) && modifierMatch(classMode, cl.getModifiers())) { 562 vec.addElement(cl); 563 } 564 } 565 }); 566 } 567 else 568 { 569 final String fName = fullName; 571 walkTree(new TreeAction() { 572 public void classAction(Cl cl) { 573 if (cl.isNRWildcardMatch(fName) && modifierMatch(classMode, cl.getModifiers())) { 574 vec.addElement(cl); 575 } 576 } 577 }); 578 } 579 } 580 else 581 { 582 Cl cl = getCl(fullName); 584 if (cl != null ) 585 { 586 int mods = cl.getModifiers(); 587 if (cl.isInnerClass()){ 588 Cl outer = (Cl) cl.getParent(); 589 } 590 boolean match = modifierMatch(classMode, cl.getModifiers()); 591 if (match || classMode == YGuardRule.LEVEL_NONE ){ vec.addElement(cl); 593 } 594 } 595 } 596 return vec.elements(); 597 } 598 599 601 public Enumeration getMdEnum(String fullName, 602 String descriptor) 603 { 604 final Vector vec = new Vector (); 605 final String fDesc = descriptor; 606 if (fullName.indexOf('*') != -1 || 607 descriptor.indexOf('*') != -1) { 608 if (fullName.indexOf('!') == 0) { 610 final String fName = fullName.substring(1); 611 walkTree(new TreeAction() { 613 public void methodAction(Md md) { 614 if (md.isWildcardMatch(fName, fDesc)) { 615 vec.addElement(md); 616 } 617 } 618 }); 619 } 620 else 621 { 622 final String fName = fullName; 623 walkTree(new TreeAction() { 625 public void methodAction(Md md) { 626 if (md.isNRWildcardMatch(fName, fDesc)) { 627 vec.addElement(md); 628 } 629 } 630 }); 631 } 632 } else { 633 Md md = getMd(fullName, descriptor); 634 if (md != null) { 635 vec.addElement(md); 636 } 637 } 638 return vec.elements(); 639 } 640 641 643 public Enumeration getFdEnum(String fullName) 644 { 645 final Vector vec = new Vector (); 646 if (fullName.indexOf('*') != -1) { 647 if (fullName.indexOf('!') == 0) { 649 final String fName = fullName.substring(1); 651 walkTree(new TreeAction() { 652 public void fieldAction(Fd fd) { 653 if (fd.isWildcardMatch(fName)) { 654 vec.addElement(fd); 655 } 656 } 657 }); 658 } 659 else 660 { 661 final String fName = fullName; 663 walkTree(new TreeAction() { 664 public void fieldAction(Fd fd) { 665 if (fd.isNRWildcardMatch(fName)) { 666 vec.addElement(fd); 667 } 668 } 669 }); 670 } 671 } else { 672 Fd fd = getFd(fullName); 673 if (fd != null) { 674 vec.addElement(fd); 675 } 676 } 677 return vec.elements(); 678 } 679 680 681 public Cl getCl(String fullName) 682 { 683 TreeItem ti = root; 684 for (Enumeration nameEnum = getNameEnum(fullName); nameEnum.hasMoreElements(); ) 685 { 686 Cons nameSegment = (Cons)nameEnum.nextElement(); 687 char tag = ((Character )nameSegment.car).charValue(); 688 String name = (String )nameSegment.cdr; 689 switch (tag) 690 { 691 case PACKAGE_LEVEL: 692 ti = ((Pk)ti).getPackage(name); 693 break; 694 695 case CLASS_LEVEL: 696 ti = ((PkCl)ti).getClass(name); 697 break; 698 699 default: 700 throw new ParseException("Internal error: illegal package/class name tag"); 701 } 702 703 if (ti == null) 705 { 706 return null; 707 } 708 } 709 710 if (!(ti instanceof Cl)) 712 { 713 throw new ParseException("Inconsistent class or interface name."); 714 } 715 return (Cl)ti; 716 } 717 718 719 public Pk getPk(String fullName) 720 { 721 TreeItem ti = root; 722 for (Enumeration nameEnum = getNameEnum(fullName); nameEnum.hasMoreElements(); ) 723 { 724 Cons nameSegment = (Cons)nameEnum.nextElement(); 725 String name = (String )nameSegment.cdr; 726 ti = ((Pk)ti).getPackage(name); 727 728 if (ti == null) 730 { 731 return null; 732 } 733 if (!(ti instanceof Pk)) 735 { 736 throw new ParseException("Inconsistent package."); 737 } 738 } 739 return (Pk)ti; 740 } 741 742 743 public Md getMd(String fullName, String descriptor) 744 { 745 int pos = fullName.lastIndexOf(METHOD_FIELD_LEVEL); 747 Cl cl = getCl(fullName.substring(0, pos)); 748 return cl.getMethod(fullName.substring(pos + 1), descriptor); 749 } 750 751 752 public Fd getFd(String fullName) 753 { 754 int pos = fullName.lastIndexOf(METHOD_FIELD_LEVEL); 756 Cl cl = getCl(fullName.substring(0, pos)); 757 return cl.getField(fullName.substring(pos + 1)); 758 } 759 760 public String [] getAttrsToKeep(String className) { 761 Cl cl = getCl(className); 762 if (cl != null){ 763 Set attrs = cl.getAttributesToKeep(); 764 if (attrs != null && attrs.size() > 0){ 765 String [] other = getAttrsToKeep(); 766 Set tmp = new HashSet (attrs); 767 for (int i = 0; i < other.length; i++) { 768 tmp.add(other[i]); 769 } 770 return (String []) tmp.toArray(new String [tmp.size()]); 771 } else { 772 return getAttrsToKeep(); 773 } 774 } else { 775 return getAttrsToKeep(); 776 } 777 } 778 779 public String mapLocalVariable(String thisClassName, String methodName, String descriptor, String string) { 780 return string; 781 } 782 783 785 public String mapClass(String className) 786 { 787 if (className.length() > 0 && className.charAt(0) == '[') { 790 StringBuffer newName = new StringBuffer (); 791 int i = 0; 792 while (i < className.length()) { 793 char ch = className.charAt(i++); 794 switch (ch) { 795 case '[': 796 case ';': 797 newName.append(ch); 798 break; 799 800 case 'L': 801 newName.append(ch); 802 int pos = className.indexOf(';', i); 803 if (pos < 0) { 804 throw new ParseException("Invalid class name encountered: " + className); 805 } 806 newName.append(mapClass(className.substring(i, pos))); 807 i = pos; 808 break; 809 810 default: 811 return className; 812 } 813 } 814 return newName.toString(); 815 } else { 816 Cl cl = getCl(className); 817 if (cl == null){ 818 try { 819 Class aClass = Cl.getClassResolver().resolve(Conversion.toJavaClass(className)); 820 return className; 822 } catch (ClassNotFoundException e) { 823 if (pedantic){ 824 throw new NoSuchMappingException("Class "+Conversion.toJavaClass(className)); 825 } else { 826 Logger.getInstance().warningToLogfile("Unresolved external dependency: "+Conversion.toJavaClass(className)+ 827 " not found!"); 828 Logger.getInstance().setUnresolved(); 829 return className; 830 } 831 } 832 } 833 return cl.getFullOutName(); 834 } 835 } 836 837 839 public String mapMethod(String className, String methodName, String descriptor) 840 { 841 if (className.startsWith("[") && className.endsWith(";")){ 843 int count = 0; 844 while (className.charAt(count) == '['){ 845 count++; 846 } 847 if (className.charAt(count) == 'L'){ 848 className = className.substring(count + 1, className.length() - 1); 849 } 850 } 851 Cl cl = getCl(className); 852 if (cl != null && cl.getMethod(methodName, descriptor) != null) 853 { 854 return cl.getMethod(methodName, descriptor).getOutName(); 855 } 856 else 857 { 858 if (cl == null) 859 { 860 try { 861 Class aClass = Cl.getClassResolver().resolve(Conversion.toJavaClass(className)); 862 } catch (ClassNotFoundException e) { 863 if (pedantic){ 864 throw new NoSuchMappingException("Class "+Conversion.toJavaClass(className)); 865 } else { 866 Logger.getInstance().warningToLogfile( "No mapping found: " + Conversion.toJavaClass( className ) ); 867 } 868 } 869 return methodName; 871 } 872 else 873 { 874 try 875 { 876 String result = cl.getMethodOutNameUp(methodName,descriptor); 878 if (result != null) 879 return result; 880 } 881 catch (Exception ex) 882 { 883 System.out.println(ex); 884 } 886 if ((!methodName.equals("<init>") && 887 (!methodName.equals("<clinit>")))){ 888 if (pedantic){ 889 throw new NoSuchMappingException("Method "+Conversion.toJavaClass(className)+"."+methodName); 890 } else { 891 Logger.getInstance().error("Method "+Conversion.toJavaClass(className)+"."+methodName+ 892 " could not be mapped !\n Probably broken code! Try rebuilding from source!"); 893 return methodName; 894 } 895 } 896 return methodName; 897 } 898 } 899 } 900 901 903 public String mapAnnotationField(String className, String methodName) 904 { 905 Cl cl = getCl(className); 906 if (cl != null) 907 { 908 for (Enumeration enumeration = cl.getMethodEnum(); enumeration.hasMoreElements();){ 909 Md md = (Md) enumeration.nextElement(); 910 if (md.getInName().equals(methodName)){ 911 return md.getOutName(); 912 } 913 } 914 return methodName; 916 } 917 else 918 { 919 return methodName; 921 } 922 } 923 924 926 public String mapField(String className, String fieldName) 927 { 928 Cl cl = getCl(className); 930 if ((cl != null) && (cl.getField(fieldName) != null)) 931 { 932 if (fieldName.startsWith("class$") && isReplaceClassNameStrings()){ 934 String realClassName = fieldName.substring(6); 935 List nameParts = new ArrayList (20); 936 for (StringTokenizer st = new StringTokenizer (realClassName, "$", false); st.hasMoreTokens();){ 937 nameParts.add(st.nextToken()); 938 } 939 String [] names = new String [nameParts.size()]; 940 nameParts.toArray(names); 941 TreeItem ti = findTreeItem(names); 942 if (ti instanceof Cl){ 943 Fd fd = cl.getField(fieldName); 944 String newClassName = mapClass(ti.getFullInName()); 945 String outName = "class$"+newClassName.replace('/','$'); 946 fd.setOutName(outName); 947 return outName; 948 } 949 } 950 return cl.getField(fieldName).getOutName(); 952 } 953 else 954 { 955 if (cl == null) 956 { 957 return fieldName; 960 } 961 else 962 { 963 try 966 { 967 String result = cl.getFieldOutNameUp(fieldName); 969 if (result != null) 970 return result; 971 } 972 catch (Exception ex) 973 { 974 } 976 if (!fieldName.equals("this")) { 977 if (pedantic){ 978 throw new NoSuchMappingException("Field "+className+"."+fieldName); 979 } else { 980 Logger.getInstance().error("Field "+className+"."+fieldName+ 981 " could not be mapped !\n Probably broken code! Try rebuilding from source!"); 982 } 983 } 984 return fieldName; 985 } 986 } 987 988 989 } 993 994 997 public String mapSignature(String signature){ 998 1001 1003 StringBuffer classString = new StringBuffer (); 1004 1005 StringBuffer newSignature = new StringBuffer (); 1006 int i = 0; 1007 while (i < signature.length()) 1008 { 1009 char ch = signature.charAt(i++); 1010 switch (ch) 1011 { 1012 case '[': 1013 case 'B': 1014 case 'C': 1015 case 'D': 1016 case 'F': 1017 case 'I': 1018 case 'J': 1019 case 'S': 1020 case 'Z': 1021 case 'V': 1022 case '(': 1023 case ')': 1024 case '+': 1025 case ':': 1026 case '-': 1027 case '*': 1028 newSignature.append(ch); 1029 break; 1030 case ';': 1031 newSignature.append(ch); 1032 classString.setLength( 0 ); 1033 break; 1034 case 'T': 1035 { newSignature.append(ch); 1037 int pos = signature.indexOf(';', i); 1038 if (pos < 0) 1039 { 1040 throw new ParseException("Invalid signature string encountered."); 1041 } 1042 newSignature.append(signature.substring(i, pos)); 1043 i = pos; 1044 break; 1045 } 1046 case '<': 1047 { 1048 newSignature.append(ch); 1050 while (true){ 1051 int first = i; 1052 while (signature.charAt(i) != ':'){ 1053 i++; 1054 } 1055 String templateName = signature.substring(first, i); 1056 newSignature.append(templateName); 1057 1058 while (signature.charAt(i) == ':'){ 1059 newSignature.append(':'); 1060 i++; 1061 int firstPos = i; 1062 int bracketCount = 0; 1063 while (!(bracketCount == 0 && signature.charAt(i) == ';')){ 1064 if (signature.charAt(i) == '<') { 1065 bracketCount++; 1066 } else if (signature.charAt(i) == '>'){ 1067 bracketCount--; 1068 } 1069 i++; 1070 } 1071 i++; 1072 newSignature.append(mapSignature(signature.substring(firstPos, i))); 1073 } 1074 if (signature.charAt(i) == '>'){ 1075 newSignature.append('>'); 1076 i++; 1077 break; 1078 } 1079 } 1080 break; 1081 } 1082 1083 case '^': 1084 { 1085 newSignature.append(ch); 1086 if (signature.charAt(i) == 'T'){ 1087 while (signature.charAt(i) != ';'){ 1089 newSignature.append(signature.charAt(i)); 1090 i++; 1091 } 1092 continue; 1093 } else if (signature.charAt(i) == 'L'){ 1094 int first = i; 1096 int bracketCount = 0; 1097 while (signature.charAt(i) != ';' || bracketCount != 0){ 1098 char c = signature.charAt(i); 1099 if (c == '<'){ 1100 bracketCount++; 1101 } else if (c == '>'){ 1102 bracketCount--; 1103 } 1104 i++; 1105 } 1106 i++; 1107 String classSig = signature.substring(first, i); 1108 newSignature.append(mapSignature(classSig)); 1109 } else { 1110 throw new IllegalStateException ("Could not map signature " + signature); 1111 } 1112 } 1113 break; 1114 case 'L': 1115 case '.': { 1117 newSignature.append(ch); 1118 int pos = signature.indexOf(';', i); 1119 int bracketPos = signature.indexOf('<', i); 1120 if (bracketPos >= i && bracketPos < pos){ 1121 int bracketCount = 0; 1123 int closingBracket = signature.length(); 1124 for (int walker = bracketPos + 1; walker < signature.length(); walker++){ 1125 char c = signature.charAt(walker); 1126 if (c == '<'){ 1127 bracketCount++; 1128 } else if (c == '>'){ 1129 if (bracketCount == 0){ 1130 closingBracket = walker; 1131 break; 1132 } else { 1133 bracketCount--; 1134 } 1135 } 1136 } 1137 pos = closingBracket + 1; 1139 String templateArg = signature.substring(bracketPos + 1, closingBracket); 1141 String classNamePart = signature.substring( i, bracketPos ); 1142 if (ch == '.'){ classString.append( '$' ); 1144 classString.append( classNamePart ); 1145 String className = classString.toString(); 1146 String result; 1147 1148 Cl cl = getCl(className); 1150 if (cl == null){ 1151 try { 1152 Class aClass = Cl.getClassResolver().resolve(Conversion.toJavaClass(className)); 1153 result = classNamePart; 1155 } catch (ClassNotFoundException e) { 1156 if (pedantic){ 1157 throw new NoSuchMappingException("Class "+Conversion.toJavaClass(className)); 1158 } else { 1159 Logger.getInstance().warningToLogfile("Unresolved external dependency: "+Conversion.toJavaClass(className)+ 1160 " not found!"); 1161 Logger.getInstance().setUnresolved(); 1162 result = classNamePart; 1163 } 1164 } 1165 } else { 1166 result = cl.getOutName(); 1167 } 1168 newSignature.append(result); 1169 } else { classString.append( classNamePart ); 1171 newSignature.append(mapClass( classString.toString() )); 1172 } 1173 newSignature.append('<'); 1174 newSignature.append(mapSignature(templateArg)); 1175 newSignature.append('>'); 1176 i = pos; 1177 } else { 1178 if (pos < 0) 1179 { 1180 throw new ParseException("Invalid signature string encountered: " + signature); 1181 } 1182 String classNamePart = signature.substring( i, pos ); 1183 if (ch == '.'){ classString.append( '$' ); 1185 } 1186 classString.append( classNamePart ); 1187 newSignature.append(mapClass( classString.toString() )); 1188 i = pos; 1189 } 1190 break; 1191 } 1192 default: 1193 throw new ParseException("Invalid signature string encountered: " +signature + " parsing char " + ch); 1194 } 1195 } 1196 return newSignature.toString(); 1197 } 1198 1199 public String mapSourceFile(String className, String sourceFileName){ 1200 final Cl cl = getCl(className); 1201 if (cl.isSourceFileMappingSet()){ 1202 return cl.getSourceFileMapping(); 1203 } else { 1204 return sourceFileName; 1205 } 1206 } 1207 1208 public boolean mapLineNumberTable(String className, String methodName, String methodSignature, LineNumberTableAttrInfo info) { 1209 final Cl cl = getCl(className); 1210 if (cl.getLineNumberTableMapper() != null){ 1211 return cl.getLineNumberTableMapper().mapLineNumberTable(className, methodName, methodSignature, info); 1212 } else { 1213 return true; 1214 } 1215 } 1216 1217 1219 public String mapDescriptor(String descriptor) 1220 { 1221 StringBuffer newDesc = new StringBuffer (); 1224 int i = 0; 1225 while (i < descriptor.length()) 1226 { 1227 char ch = descriptor.charAt(i++); 1228 switch (ch) 1229 { 1230 case '[': 1231 case 'B': 1232 case 'C': 1233 case 'D': 1234 case 'F': 1235 case 'I': 1236 case 'J': 1237 case 'S': 1238 case 'Z': 1239 case 'V': 1240 case '(': 1241 case ')': 1242 case ';': 1243 newDesc.append(ch); 1244 break; 1245 1246 case 'L': 1247 newDesc.append(ch); 1248 int pos = descriptor.indexOf(';', i); 1249 if (pos < 0) 1250 { 1251 throw new ParseException("Invalid descriptor string encountered."); 1252 } 1253 newDesc.append(mapClass(descriptor.substring(i, pos))); 1254 i = pos; 1255 break; 1256 1257 default: 1258 throw new ParseException("Invalid descriptor string encountered."); 1259 } 1260 } 1261 return newDesc.toString(); 1262 } 1263 1264 1265 public void dump(final PrintWriter log) 1266 { 1267 log.println("<expose>"); 1268 walkTree(new TreeAction() { 1269 public void classAction(Cl cl) { 1270 if (cl.isFromScript()) { 1271 String cla = toUtf8XmlString(Conversion.toJavaClass(cl.getFullInName())); 1272 log.println(" <class name=\"" + cla + "\"/>"); 1273 } 1274 } 1275 public void methodAction(Md md) { 1276 if (md.isFromScript()) { 1277 String cla = toUtf8XmlString(Conversion.toJavaClass(md.getParent().getFullInName())); 1278 String method = toUtf8XmlString(Conversion.toJavaMethod(md.getInName(), md.getDescriptor())); 1279 log.println(" <method class=\""+cla+"\" name=\"" + method + "\"/>"); 1280 } 1281 } 1282 public void fieldAction(Fd fd) { 1283 if (fd.isFromScript()) { 1284 String cla = toUtf8XmlString(Conversion.toJavaClass(fd.getParent().getFullInName())); 1285 log.println(" <field class=\""+cla+"\" name=\"" + toUtf8XmlString(fd.getInName()) + "\"/>"); 1286 } 1287 } 1288 public void packageAction(Pk pk) { 1289 } 1291 }); 1292 log.println("</expose>"); 1293 log.println("<map>"); 1294 walkTree(new TreeAction() { 1295 public void classAction(Cl cl) { 1296 if (!cl.isFromScript()) { 1297 String cla = toUtf8XmlString(Conversion.toJavaClass(cl.getFullInName())); 1298 log.println(" <class name=\"" + toUtf8XmlString(cla) + "\" map=\"" + toUtf8XmlString(cl.getOutName()) + "\"/>"); 1299 } 1300 } 1301 public void methodAction(Md md) { 1302 if (!md.isFromScript()) { 1303 String cla = toUtf8XmlString(Conversion.toJavaClass(md.getParent().getFullInName())); 1304 String method = toUtf8XmlString(Conversion.toJavaMethod(md.getInName(), md.getDescriptor())); 1305 log.println(" <method class=\""+cla+"\" name=\"" + method + "\" map=\"" + toUtf8XmlString(md.getOutName()) + "\"/>"); 1306 } 1307 } 1308 public void fieldAction(Fd fd) { 1309 if (!fd.isFromScript()) { 1310 String cla = toUtf8XmlString(Conversion.toJavaClass(fd.getParent().getFullInName())); 1311 log.println(" <field class=\""+cla+"\" name=\"" + toUtf8XmlString(fd.getInName()) + "\" map=\"" + toUtf8XmlString(fd.getOutName()) + "\"/>"); 1312 } 1313 } 1314 public void packageAction(Pk pk) { 1315 if (!pk.isFromScript() && pk.getFullInName().length() > 0) { 1316 String pa = toUtf8XmlString(Conversion.toJavaClass(pk.getFullInName())); 1317 log.println(" <package name=\""+pa +"\" map=\"" + toUtf8XmlString(pk.getOutName()) + "\"/>"); 1318 } 1319 } 1320 }); 1321 log.println("</map>"); 1322 } 1323 1324 public static final String toUtf8XmlString(String s){ 1325 boolean bad = false; 1326 for (int i = 0; i< s.length(); i++){ 1327 char c = s.charAt(i); 1328 if ((c >= 0x80) || (c =='"') || (c == '<')){ 1329 bad = true; 1330 break; 1331 } 1332 } 1333 if (bad){ 1334 StringBuffer buf = new StringBuffer (s.length()); 1335 for (int i = 0; i < s.length(); i++){ 1336 buf.append(toUtf8XmlChar(s.charAt(i))); 1337 } 1338 return buf.toString(); 1339 } else { 1340 return s; 1341 } 1342 } 1343 1344 private static final String toUtf8XmlChar(char c){ 1345 if (c < 0x80){ 1346 if (c == '"'){ 1347 return """; 1348 } else if (c == '<'){ 1349 return "<"; 1350 } 1351 return new String (new char[]{c}); 1352 } 1353 else if (c < 0x800) 1354 { 1355 StringBuffer buf = new StringBuffer (8); 1356 buf.append("&#x"); 1357 buf.append(hex[(c >> 8) & 0xff]); 1358 buf.append(hex[c & 0xff]); 1359 buf.append(';'); 1360 return buf.toString(); 1361 } 1362 else 1363 { 1364 StringBuffer buf = new StringBuffer (10); 1365 buf.append("&#x"); 1366 buf.append(hex[(c >> 16) & 0xff]); 1367 buf.append(hex[(c >> 8) & 0xff]); 1368 buf.append(hex[c & 0xff]); 1369 buf.append(';'); 1370 return buf.toString(); 1371 } 1372 } 1373 1374 private static final String [] hex; 1375 static { 1376 hex = new String [256]; 1377 for (int i = 0; i < 256; i++){ 1378 hex[i] = toHex(i); 1379 } 1380 } 1381 1382 private static final String hexChars = "0123456789abcdef"; 1383 1384 1385 private boolean replaceClassNameStrings; 1386 1387 1388 private boolean pedantic; 1389 1390 private static String toHex(int i){ 1391 StringBuffer buf = new StringBuffer (2); 1392 buf.append(hexChars.charAt((i/16)&15)); 1393 buf.append(hexChars.charAt(i&15)); 1394 return buf.toString(); 1395 } 1396 1397 private void retainHierarchy(TreeItem ti) 1400 { 1401 if (!ti.isFixed()) 1402 { 1403 ti.setOutName(ti.getInName()); 1404 ti.setFromScript(); 1405 } 1406 if (ti.parent != null) 1407 { 1408 retainHierarchy(ti.parent); 1409 } 1410 } 1411 1412 1413 public void walkTree(TreeAction ta) 1414 { 1415 walkTree(ta, root); 1416 } 1417 1418 private void walkTree(TreeAction ta, TreeItem ti) 1421 { 1422 if (ti instanceof Pk) 1423 { 1424 Enumeration packageEnum = ((Pk)ti).getPackageEnum(); 1425 ta.packageAction((Pk)ti); 1426 while (packageEnum.hasMoreElements()) 1427 { 1428 walkTree(ta, (TreeItem)packageEnum.nextElement()); 1429 } 1430 } 1431 if (ti instanceof PkCl) 1432 { 1433 Enumeration classEnum = ((PkCl)ti).getClassEnum(); 1434 while (classEnum.hasMoreElements()) 1435 { 1436 walkTree(ta, (TreeItem)classEnum.nextElement()); 1437 } 1438 } 1439 if (ti instanceof Cl) 1440 { 1441 Enumeration fieldEnum = ((Cl)ti).getFieldEnum(); 1442 Enumeration methodEnum = ((Cl)ti).getMethodEnum(); 1443 ta.classAction((Cl)ti); 1444 while (fieldEnum.hasMoreElements()) 1445 { 1446 ta.fieldAction((Fd)fieldEnum.nextElement()); 1447 } 1448 while (methodEnum.hasMoreElements()) 1449 { 1450 ta.methodAction((Md)methodEnum.nextElement()); 1451 } 1452 } 1453 } 1454 1455 1459 public boolean isReplaceClassNameStrings() 1460 { 1461 return this.replaceClassNameStrings; 1462 } 1463 1464 1468 public void setReplaceClassNameStrings(boolean replaceClassNameStrings) 1469 { 1470 this.replaceClassNameStrings = replaceClassNameStrings; 1471 } 1472 1473 1477 public boolean isPedantic() 1478 { 1479 return this.pedantic; 1480 } 1481 1482 1486 public void setPedantic(boolean pedantic) 1487 { 1488 this.pedantic = pedantic; 1489 } 1490 1491 public void retainSourceFileAttributeMap(String name, String obfName) { 1492 for (Enumeration clEnum = getClEnum(name); clEnum.hasMoreElements(); ) 1493 { 1494 Cl classItem = (Cl)clEnum.nextElement(); 1495 classItem.setSourceFileMapping(obfName); 1496 classItem.getAttributesToKeep().add(ClassConstants.ATTR_SourceFile); 1497 } 1498 } 1499 1500 public void retainLineNumberTable(String name, final LineNumberTableMapper lineNumberTableMapper) { 1501 for (Enumeration clEnum = getClEnum(name); clEnum.hasMoreElements(); ) 1502 { 1503 Cl classItem = (Cl)clEnum.nextElement(); 1504 classItem.setLineNumberTableMapper(lineNumberTableMapper); 1505 classItem.getAttributesToKeep().add(ClassConstants.ATTR_LineNumberTable); 1506 } 1507 } 1508 1509 public void retainAttributeForClass(String className, String attributeDescriptor) { 1510 for (Enumeration clEnum = getClEnum(className); clEnum.hasMoreElements(); ) 1511 { 1512 Cl classItem = (Cl)clEnum.nextElement(); 1513 final Set set = classItem.getAttributesToKeep(); 1514 set.add(attributeDescriptor); 1515 } 1516 } 1517 1518 public void retainPackage(String packageName) { 1519 retainHierarchy(getPk(packageName)); 1520 } 1521} 1522 1523 1524 | Popular Tags |