1 /* 2 * ProGuard -- shrinking, optimization, obfuscation, and preverification 3 * of Java bytecode. 4 * 5 * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu) 6 * 7 * This program is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License as published by the Free 9 * Software Foundation; either version 2 of the License, or (at your option) 10 * any later version. 11 * 12 * This program is distributed in the hope that it will be useful, but WITHOUT 13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 15 * more details. 16 * 17 * You should have received a copy of the GNU General Public License along 18 * with this program; if not, write to the Free Software Foundation, Inc., 19 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 */ 21 package proguard.classfile.util; 22 23 import proguard.classfile.*; 24 25 import java.util.List; 26 27 /** 28 * Utility methods for converting between internal and external representations 29 * of names and descriptions. 30 * 31 * @author Eric Lafortune 32 */ 33 public class ClassUtil 34 { 35 private static final String EMPTY_STRING = ""; 36 37 38 /** 39 * Checks whether the given class magic number is correct. 40 * @param magicNumber the magic number. 41 * @throws UnsupportedOperationException when the magic number is incorrect. 42 */ checkMagicNumber(int magicNumber)43 public static void checkMagicNumber(int magicNumber) throws UnsupportedOperationException 44 { 45 if (magicNumber != ClassConstants.MAGIC) 46 { 47 throw new UnsupportedOperationException("Invalid magic number ["+Integer.toHexString(magicNumber)+"] in class"); 48 } 49 } 50 51 52 /** 53 * Returns the combined class version number. 54 * @param majorVersion the major part of the class version number. 55 * @param minorVersion the minor part of the class version number. 56 * @return the combined class version number. 57 */ internalClassVersion(int majorVersion, int minorVersion)58 public static int internalClassVersion(int majorVersion, int minorVersion) 59 { 60 return (majorVersion << 16) | minorVersion; 61 } 62 63 64 /** 65 * Returns the major part of the given class version number. 66 * @param classVersion the combined class version number. 67 * @return the major part of the class version number. 68 */ internalMajorClassVersion(int classVersion)69 public static int internalMajorClassVersion(int classVersion) 70 { 71 return classVersion >>> 16; 72 } 73 74 75 /** 76 * Returns the internal class version number. 77 * @param classVersion the external class version number. 78 * @return the internal class version number. 79 */ internalMinorClassVersion(int classVersion)80 public static int internalMinorClassVersion(int classVersion) 81 { 82 return classVersion & 0xffff; 83 } 84 85 86 /** 87 * Returns the internal class version number. 88 * @param classVersion the external class version number. 89 * @return the internal class version number. 90 */ internalClassVersion(String classVersion)91 public static int internalClassVersion(String classVersion) 92 { 93 return 94 classVersion.equals(JavaConstants.CLASS_VERSION_1_0) || 95 classVersion.equals(JavaConstants.CLASS_VERSION_1_1) ? ClassConstants.CLASS_VERSION_1_0 : 96 classVersion.equals(JavaConstants.CLASS_VERSION_1_2) ? ClassConstants.CLASS_VERSION_1_2 : 97 classVersion.equals(JavaConstants.CLASS_VERSION_1_3) ? ClassConstants.CLASS_VERSION_1_3 : 98 classVersion.equals(JavaConstants.CLASS_VERSION_1_4) ? ClassConstants.CLASS_VERSION_1_4 : 99 classVersion.equals(JavaConstants.CLASS_VERSION_1_5_ALIAS) || 100 classVersion.equals(JavaConstants.CLASS_VERSION_1_5) ? ClassConstants.CLASS_VERSION_1_5 : 101 classVersion.equals(JavaConstants.CLASS_VERSION_1_6_ALIAS) || 102 classVersion.equals(JavaConstants.CLASS_VERSION_1_6) ? ClassConstants.CLASS_VERSION_1_6 : 103 classVersion.equals(JavaConstants.CLASS_VERSION_1_7_ALIAS) || 104 classVersion.equals(JavaConstants.CLASS_VERSION_1_7) ? ClassConstants.CLASS_VERSION_1_7 : 105 classVersion.equals(JavaConstants.CLASS_VERSION_1_8_ALIAS) || 106 classVersion.equals(JavaConstants.CLASS_VERSION_1_8) ? ClassConstants.CLASS_VERSION_1_8 : 107 0; 108 } 109 110 111 /** 112 * Returns the minor part of the given class version number. 113 * @param classVersion the combined class version number. 114 * @return the minor part of the class version number. 115 */ externalClassVersion(int classVersion)116 public static String externalClassVersion(int classVersion) 117 { 118 switch (classVersion) 119 { 120 case ClassConstants.CLASS_VERSION_1_0: return JavaConstants.CLASS_VERSION_1_0; 121 case ClassConstants.CLASS_VERSION_1_2: return JavaConstants.CLASS_VERSION_1_2; 122 case ClassConstants.CLASS_VERSION_1_3: return JavaConstants.CLASS_VERSION_1_3; 123 case ClassConstants.CLASS_VERSION_1_4: return JavaConstants.CLASS_VERSION_1_4; 124 case ClassConstants.CLASS_VERSION_1_5: return JavaConstants.CLASS_VERSION_1_5; 125 case ClassConstants.CLASS_VERSION_1_6: return JavaConstants.CLASS_VERSION_1_6; 126 case ClassConstants.CLASS_VERSION_1_7: return JavaConstants.CLASS_VERSION_1_7; 127 case ClassConstants.CLASS_VERSION_1_8: return JavaConstants.CLASS_VERSION_1_8; 128 default: return null; 129 } 130 } 131 132 133 /** 134 * Checks whether the given class version number is supported. 135 * @param classVersion the combined class version number. 136 * @throws UnsupportedOperationException when the version is not supported. 137 */ checkVersionNumbers(int classVersion)138 public static void checkVersionNumbers(int classVersion) throws UnsupportedOperationException 139 { 140 if (classVersion < ClassConstants.CLASS_VERSION_1_0 || 141 classVersion > ClassConstants.CLASS_VERSION_1_8) 142 { 143 throw new UnsupportedOperationException("Unsupported class version number ["+ 144 internalMajorClassVersion(classVersion)+"."+ 145 internalMinorClassVersion(classVersion)+"] (maximum "+ 146 ClassConstants.CLASS_VERSION_1_8_MAJOR+"."+ 147 ClassConstants.CLASS_VERSION_1_8_MINOR+", Java "+ 148 JavaConstants.CLASS_VERSION_1_8+")"); 149 } 150 } 151 152 153 /** 154 * Converts an external class name into an internal class name. 155 * @param externalClassName the external class name, 156 * e.g. "<code>java.lang.Object</code>" 157 * @return the internal class name, 158 * e.g. "<code>java/lang/Object</code>". 159 */ internalClassName(String externalClassName)160 public static String internalClassName(String externalClassName) 161 { 162 return externalClassName.replace(JavaConstants.PACKAGE_SEPARATOR, 163 ClassConstants.PACKAGE_SEPARATOR); 164 } 165 166 167 /** 168 * Converts an internal class description into an external class description. 169 * @param accessFlags the access flags of the class. 170 * @param internalClassName the internal class name, 171 * e.g. "<code>java/lang/Object</code>". 172 * @return the external class description, 173 * e.g. "<code>public java.lang.Object</code>". 174 */ externalFullClassDescription(int accessFlags, String internalClassName)175 public static String externalFullClassDescription(int accessFlags, 176 String internalClassName) 177 { 178 return externalClassAccessFlags(accessFlags) + 179 externalClassName(internalClassName); 180 } 181 182 183 /** 184 * Converts an internal class name into an external class name. 185 * @param internalClassName the internal class name, 186 * e.g. "<code>java/lang/Object</code>". 187 * @return the external class name, 188 * e.g. "<code>java.lang.Object</code>". 189 */ externalClassName(String internalClassName)190 public static String externalClassName(String internalClassName) 191 { 192 return //internalClassName.startsWith(ClassConstants.PACKAGE_JAVA_LANG) && 193 //internalClassName.indexOf(ClassConstants.PACKAGE_SEPARATOR, ClassConstants.PACKAGE_JAVA_LANG.length() + 1) < 0 ? 194 //internalClassName.substring(ClassConstants.PACKAGE_JAVA_LANG.length()) : 195 internalClassName.replace(ClassConstants.PACKAGE_SEPARATOR, 196 JavaConstants.PACKAGE_SEPARATOR); 197 } 198 199 200 /** 201 * Returns the external base type of an external array type, dropping any 202 * array brackets. 203 * @param externalArrayType the external array type, 204 * e.g. "<code>java.lang.Object[][]</code>" 205 * @return the external base type, 206 * e.g. "<code>java.lang.Object</code>". 207 */ externalBaseType(String externalArrayType)208 public static String externalBaseType(String externalArrayType) 209 { 210 int index = externalArrayType.indexOf(JavaConstants.TYPE_ARRAY); 211 return index >= 0 ? 212 externalArrayType.substring(0, index) : 213 externalArrayType; 214 } 215 216 217 /** 218 * Returns the external short class name of an external class name, dropping 219 * the package specification. 220 * @param externalClassName the external class name, 221 * e.g. "<code>java.lang.Object</code>" 222 * @return the external short class name, 223 * e.g. "<code>Object</code>". 224 */ externalShortClassName(String externalClassName)225 public static String externalShortClassName(String externalClassName) 226 { 227 int index = externalClassName.lastIndexOf(JavaConstants.PACKAGE_SEPARATOR); 228 return externalClassName.substring(index+1); 229 } 230 231 232 /** 233 * Returns whether the given internal type is an array type. 234 * @param internalType the internal type, 235 * e.g. "<code>[[Ljava/lang/Object;</code>". 236 * @return <code>true</code> if the given type is an array type, 237 * <code>false</code> otherwise. 238 */ isInternalArrayType(String internalType)239 public static boolean isInternalArrayType(String internalType) 240 { 241 return internalType.length() > 1 && 242 internalType.charAt(0) == ClassConstants.TYPE_ARRAY; 243 } 244 245 246 /** 247 * Returns the number of dimensions of the given internal type. 248 * @param internalType the internal type, 249 * e.g. "<code>[[Ljava/lang/Object;</code>". 250 * @return the number of dimensions, e.g. 2. 251 */ internalArrayTypeDimensionCount(String internalType)252 public static int internalArrayTypeDimensionCount(String internalType) 253 { 254 int dimensions = 0; 255 while (internalType.charAt(dimensions) == ClassConstants.TYPE_ARRAY) 256 { 257 dimensions++; 258 } 259 260 return dimensions; 261 } 262 263 264 /** 265 * Returns whether the given internal class name is one of the interfaces 266 * that is implemented by all array types. These class names are 267 * "<code>java/lang/Object</code>", "<code>java/lang/Cloneable</code>", and 268 * "<code>java/io/Serializable</code>" 269 * @param internalClassName the internal class name, 270 * e.g. "<code>java/lang/Object</code>". 271 * @return <code>true</code> if the given type is an array interface name, 272 * <code>false</code> otherwise. 273 */ isInternalArrayInterfaceName(String internalClassName)274 public static boolean isInternalArrayInterfaceName(String internalClassName) 275 { 276 return ClassConstants.NAME_JAVA_LANG_OBJECT.equals(internalClassName) || 277 ClassConstants.NAME_JAVA_LANG_CLONEABLE.equals(internalClassName) || 278 ClassConstants.NAME_JAVA_IO_SERIALIZABLE.equals(internalClassName); 279 } 280 281 282 /** 283 * Returns whether the given internal type is a plain primitive type 284 * (not void). 285 * @param internalType the internal type, 286 * e.g. "<code>I</code>". 287 * @return <code>true</code> if the given type is a class type, 288 * <code>false</code> otherwise. 289 */ isInternalPrimitiveType(char internalType)290 public static boolean isInternalPrimitiveType(char internalType) 291 { 292 return internalType == ClassConstants.TYPE_BOOLEAN || 293 internalType == ClassConstants.TYPE_BYTE || 294 internalType == ClassConstants.TYPE_CHAR || 295 internalType == ClassConstants.TYPE_SHORT || 296 internalType == ClassConstants.TYPE_INT || 297 internalType == ClassConstants.TYPE_FLOAT || 298 internalType == ClassConstants.TYPE_LONG || 299 internalType == ClassConstants.TYPE_DOUBLE; 300 } 301 302 303 /** 304 * Returns whether the given internal type is a primitive Category 2 type. 305 * @param internalType the internal type, 306 * e.g. "<code>L</code>". 307 * @return <code>true</code> if the given type is a Category 2 type, 308 * <code>false</code> otherwise. 309 */ isInternalCategory2Type(String internalType)310 public static boolean isInternalCategory2Type(String internalType) 311 { 312 return internalType.length() == 1 && 313 (internalType.charAt(0) == ClassConstants.TYPE_LONG || 314 internalType.charAt(0) == ClassConstants.TYPE_DOUBLE); 315 } 316 317 318 /** 319 * Returns whether the given internal type is a plain class type 320 * (including an array type of a plain class type). 321 * @param internalType the internal type, 322 * e.g. "<code>Ljava/lang/Object;</code>". 323 * @return <code>true</code> if the given type is a class type, 324 * <code>false</code> otherwise. 325 */ isInternalClassType(String internalType)326 public static boolean isInternalClassType(String internalType) 327 { 328 int length = internalType.length(); 329 return length > 1 && 330 // internalType.charAt(0) == ClassConstants.TYPE_CLASS_START && 331 internalType.charAt(length-1) == ClassConstants.TYPE_CLASS_END; 332 } 333 334 335 /** 336 * Returns the internal type of a given class name. 337 * @param internalClassName the internal class name, 338 * e.g. "<code>java/lang/Object</code>". 339 * @return the internal type, 340 * e.g. "<code>Ljava/lang/Object;</code>". 341 */ internalTypeFromClassName(String internalClassName)342 public static String internalTypeFromClassName(String internalClassName) 343 { 344 return internalArrayTypeFromClassName(internalClassName, 0); 345 } 346 347 348 /** 349 * Returns the internal array type of a given class name with a given number 350 * of dimensions. If the number of dimensions is 0, the class name itself is 351 * returned. 352 * @param internalClassName the internal class name, 353 * e.g. "<code>java/lang/Object</code>". 354 * @param dimensionCount the number of array dimensions. 355 * @return the internal array type of the array elements, 356 * e.g. "<code>Ljava/lang/Object;</code>". 357 */ internalArrayTypeFromClassName(String internalClassName, int dimensionCount)358 public static String internalArrayTypeFromClassName(String internalClassName, 359 int dimensionCount) 360 { 361 StringBuffer buffer = new StringBuffer(internalClassName.length() + dimensionCount + 2); 362 363 for (int dimension = 0; dimension < dimensionCount; dimension++) 364 { 365 buffer.append(ClassConstants.TYPE_ARRAY); 366 } 367 368 return buffer.append(ClassConstants.TYPE_CLASS_START) 369 .append(internalClassName) 370 .append(ClassConstants.TYPE_CLASS_END) 371 .toString(); 372 } 373 374 375 /** 376 * Returns the internal element type of a given internal array type. 377 * @param internalArrayType the internal array type, 378 * e.g. "<code>[[Ljava/lang/Object;</code>" or 379 * "<code>[I</code>". 380 * @return the internal type of the array elements, 381 * e.g. "<code>Ljava/lang/Object;</code>" or 382 * "<code>I</code>". 383 */ internalTypeFromArrayType(String internalArrayType)384 public static String internalTypeFromArrayType(String internalArrayType) 385 { 386 int index = internalArrayType.lastIndexOf(ClassConstants.TYPE_ARRAY); 387 return internalArrayType.substring(index+1); 388 } 389 390 391 /** 392 * Returns the internal class name of a given internal class type 393 * (including an array type). Types involving primitive types are returned 394 * unchanged. 395 * @param internalClassType the internal class type, 396 * e.g. "<code>[Ljava/lang/Object;</code>", 397 * "<code>Ljava/lang/Object;</code>", or 398 * "<code>java/lang/Object</code>". 399 * @return the internal class name, 400 * e.g. "<code>java/lang/Object</code>". 401 */ internalClassNameFromClassType(String internalClassType)402 public static String internalClassNameFromClassType(String internalClassType) 403 { 404 return isInternalClassType(internalClassType) ? 405 internalClassType.substring(internalClassType.indexOf(ClassConstants.TYPE_CLASS_START)+1, 406 internalClassType.length()-1) : 407 internalClassType; 408 } 409 410 411 /** 412 * Returns the internal class name of any given internal descriptor type, 413 * disregarding array prefixes. 414 * @param internalClassType the internal class type, 415 * e.g. "<code>Ljava/lang/Object;</code>" or 416 * "<code>[[I</code>". 417 * @return the internal class name, 418 * e.g. "<code>java/lang/Object</code>" or 419 * <code>null</code>. 420 */ internalClassNameFromType(String internalClassType)421 public static String internalClassNameFromType(String internalClassType) 422 { 423 if (!isInternalClassType(internalClassType)) 424 { 425 return null; 426 } 427 428 // Is it an array type? 429 if (isInternalArrayType(internalClassType)) 430 { 431 internalClassType = internalTypeFromArrayType(internalClassType); 432 } 433 434 return internalClassNameFromClassType(internalClassType); 435 } 436 437 438 /** 439 * Returns whether the given method name refers to a class initializer or 440 * an instance initializer. 441 * @param internalMethodName the internal method name, 442 * e.g. "<code><clinit></code>". 443 * @return whether the method name refers to an initializer, 444 * e.g. <code>true</code>. 445 */ isInitializer(String internalMethodName)446 public static boolean isInitializer(String internalMethodName) 447 { 448 return internalMethodName.equals(ClassConstants.METHOD_NAME_CLINIT) || 449 internalMethodName.equals(ClassConstants.METHOD_NAME_INIT); 450 } 451 452 453 /** 454 * Returns the internal type of the given internal method descriptor. 455 * @param internalMethodDescriptor the internal method descriptor, 456 * e.g. "<code>(II)Z</code>". 457 * @return the internal return type, 458 * e.g. "<code>Z</code>". 459 */ internalMethodReturnType(String internalMethodDescriptor)460 public static String internalMethodReturnType(String internalMethodDescriptor) 461 { 462 int index = internalMethodDescriptor.indexOf(ClassConstants.METHOD_ARGUMENTS_CLOSE); 463 return internalMethodDescriptor.substring(index + 1); 464 } 465 466 467 /** 468 * Returns the number of parameters of the given internal method descriptor. 469 * @param internalMethodDescriptor the internal method descriptor, 470 * e.g. "<code>(ID)Z</code>". 471 * @return the number of parameters, 472 * e.g. 2. 473 */ internalMethodParameterCount(String internalMethodDescriptor)474 public static int internalMethodParameterCount(String internalMethodDescriptor) 475 { 476 int counter = 0; 477 int index = 1; 478 479 while (true) 480 { 481 char c = internalMethodDescriptor.charAt(index++); 482 switch (c) 483 { 484 case ClassConstants.TYPE_ARRAY: 485 { 486 // Just ignore all array characters. 487 break; 488 } 489 case ClassConstants.TYPE_CLASS_START: 490 { 491 counter++; 492 493 // Skip the class name. 494 index = internalMethodDescriptor.indexOf(ClassConstants.TYPE_CLASS_END, index) + 1; 495 break; 496 } 497 default: 498 { 499 counter++; 500 break; 501 } 502 case ClassConstants.METHOD_ARGUMENTS_CLOSE: 503 { 504 return counter; 505 } 506 } 507 } 508 } 509 510 511 /** 512 * Returns the size taken up on the stack by the parameters of the given 513 * internal method descriptor. This accounts for long and double parameters 514 * taking up two entries. 515 * @param internalMethodDescriptor the internal method descriptor, 516 * e.g. "<code>(ID)Z</code>". 517 * @return the size taken up on the stack, 518 * e.g. 3. 519 */ internalMethodParameterSize(String internalMethodDescriptor)520 public static int internalMethodParameterSize(String internalMethodDescriptor) 521 { 522 return internalMethodParameterSize(internalMethodDescriptor, true); 523 } 524 525 526 /** 527 * Returns the size taken up on the stack by the parameters of the given 528 * internal method descriptor. This accounts for long and double parameters 529 * taking up two entries, and a non-static method taking up an additional 530 * entry. 531 * @param internalMethodDescriptor the internal method descriptor, 532 * e.g. "<code>(ID)Z</code>". 533 * @param accessFlags the access flags of the method, 534 * e.g. 0. 535 * @return the size taken up on the stack, 536 * e.g. 4. 537 */ internalMethodParameterSize(String internalMethodDescriptor, int accessFlags)538 public static int internalMethodParameterSize(String internalMethodDescriptor, 539 int accessFlags) 540 { 541 return internalMethodParameterSize(internalMethodDescriptor, 542 (accessFlags & ClassConstants.ACC_STATIC) != 0); 543 } 544 545 546 /** 547 * Returns the size taken up on the stack by the parameters of the given 548 * internal method descriptor. This accounts for long and double parameters 549 * taking up two spaces, and a non-static method taking up an additional 550 * entry. 551 * @param internalMethodDescriptor the internal method descriptor, 552 * e.g. "<code>(ID)Z</code>". 553 * @param isStatic specifies whether the method is static, 554 * e.g. false. 555 * @return the size taken up on the stack, 556 * e.g. 4. 557 */ internalMethodParameterSize(String internalMethodDescriptor, boolean isStatic)558 public static int internalMethodParameterSize(String internalMethodDescriptor, 559 boolean isStatic) 560 { 561 int size = isStatic ? 0 : 1; 562 int index = 1; 563 564 while (true) 565 { 566 char c = internalMethodDescriptor.charAt(index++); 567 switch (c) 568 { 569 case ClassConstants.TYPE_LONG: 570 case ClassConstants.TYPE_DOUBLE: 571 { 572 size += 2; 573 break; 574 } 575 case ClassConstants.TYPE_CLASS_START: 576 { 577 size++; 578 579 // Skip the class name. 580 index = internalMethodDescriptor.indexOf(ClassConstants.TYPE_CLASS_END, index) + 1; 581 break; 582 } 583 case ClassConstants.TYPE_ARRAY: 584 { 585 size++; 586 587 // Skip all array characters. 588 while ((c = internalMethodDescriptor.charAt(index++)) == ClassConstants.TYPE_ARRAY) {} 589 590 if (c == ClassConstants.TYPE_CLASS_START) 591 { 592 // Skip the class type. 593 index = internalMethodDescriptor.indexOf(ClassConstants.TYPE_CLASS_END, index) + 1; 594 } 595 break; 596 } 597 default: 598 { 599 size++; 600 break; 601 } 602 case ClassConstants.METHOD_ARGUMENTS_CLOSE: 603 { 604 return size; 605 } 606 } 607 } 608 } 609 610 611 /** 612 * Returns the size taken up on the stack by the given internal type. 613 * The size is 1, except for long and double types, for which it is 2, 614 * and for the void type, for which 0 is returned. 615 * @param internalType the internal type, 616 * e.g. "<code>I</code>". 617 * @return the size taken up on the stack, 618 * e.g. 1. 619 */ internalTypeSize(String internalType)620 public static int internalTypeSize(String internalType) 621 { 622 if (internalType.length() == 1) 623 { 624 char internalPrimitiveType = internalType.charAt(0); 625 if (internalPrimitiveType == ClassConstants.TYPE_LONG || 626 internalPrimitiveType == ClassConstants.TYPE_DOUBLE) 627 { 628 return 2; 629 } 630 else if (internalPrimitiveType == ClassConstants.TYPE_VOID) 631 { 632 return 0; 633 } 634 } 635 636 return 1; 637 } 638 639 640 /** 641 * Converts an external type into an internal type. 642 * @param externalType the external type, 643 * e.g. "<code>java.lang.Object[][]</code>" or 644 * "<code>int[]</code>". 645 * @return the internal type, 646 * e.g. "<code>[[Ljava/lang/Object;</code>" or 647 * "<code>[I</code>". 648 */ internalType(String externalType)649 public static String internalType(String externalType) 650 { 651 // Strip the array part, if any. 652 int dimensionCount = externalArrayTypeDimensionCount(externalType); 653 if (dimensionCount > 0) 654 { 655 externalType = externalType.substring(0, externalType.length() - dimensionCount * JavaConstants.TYPE_ARRAY.length()); 656 } 657 658 // Analyze the actual type part. 659 char internalTypeChar = 660 externalType.equals(JavaConstants.TYPE_VOID ) ? ClassConstants.TYPE_VOID : 661 externalType.equals(JavaConstants.TYPE_BOOLEAN) ? ClassConstants.TYPE_BOOLEAN : 662 externalType.equals(JavaConstants.TYPE_BYTE ) ? ClassConstants.TYPE_BYTE : 663 externalType.equals(JavaConstants.TYPE_CHAR ) ? ClassConstants.TYPE_CHAR : 664 externalType.equals(JavaConstants.TYPE_SHORT ) ? ClassConstants.TYPE_SHORT : 665 externalType.equals(JavaConstants.TYPE_INT ) ? ClassConstants.TYPE_INT : 666 externalType.equals(JavaConstants.TYPE_FLOAT ) ? ClassConstants.TYPE_FLOAT : 667 externalType.equals(JavaConstants.TYPE_LONG ) ? ClassConstants.TYPE_LONG : 668 externalType.equals(JavaConstants.TYPE_DOUBLE ) ? ClassConstants.TYPE_DOUBLE : 669 externalType.equals("%" ) ? '%' : 670 (char)0; 671 672 String internalType = 673 internalTypeChar != 0 ? String.valueOf(internalTypeChar) : 674 ClassConstants.TYPE_CLASS_START + 675 internalClassName(externalType) + 676 ClassConstants.TYPE_CLASS_END; 677 678 // Prepend the array part, if any. 679 for (int count = 0; count < dimensionCount; count++) 680 { 681 internalType = ClassConstants.TYPE_ARRAY + internalType; 682 } 683 684 return internalType; 685 } 686 687 688 /** 689 * Returns the number of dimensions of the given external type. 690 * @param externalType the external type, 691 * e.g. "<code>[[Ljava/lang/Object;</code>". 692 * @return the number of dimensions, e.g. 2. 693 */ externalArrayTypeDimensionCount(String externalType)694 public static int externalArrayTypeDimensionCount(String externalType) 695 { 696 int dimensions = 0; 697 int length = JavaConstants.TYPE_ARRAY.length(); 698 int offset = externalType.length() - length; 699 while (externalType.regionMatches(offset, 700 JavaConstants.TYPE_ARRAY, 701 0, 702 length)) 703 { 704 dimensions++; 705 offset -= length; 706 } 707 708 return dimensions; 709 } 710 711 712 /** 713 * Converts an internal type into an external type. 714 * @param internalType the internal type, 715 * e.g. "<code>[[Ljava/lang/Object;</code>" or 716 * "<code>[I</code>". 717 * @return the external type, 718 * e.g. "<code>java.lang.Object[][]</code>" or 719 * "<code>int[]</code>". 720 */ externalType(String internalType)721 public static String externalType(String internalType) 722 { 723 // Strip the array part, if any. 724 int dimensionCount = internalArrayTypeDimensionCount(internalType); 725 if (dimensionCount > 0) 726 { 727 internalType = internalType.substring(dimensionCount); 728 } 729 730 // Analyze the actual type part. 731 char internalTypeChar = internalType.charAt(0); 732 733 String externalType = 734 internalTypeChar == ClassConstants.TYPE_VOID ? JavaConstants.TYPE_VOID : 735 internalTypeChar == ClassConstants.TYPE_BOOLEAN ? JavaConstants.TYPE_BOOLEAN : 736 internalTypeChar == ClassConstants.TYPE_BYTE ? JavaConstants.TYPE_BYTE : 737 internalTypeChar == ClassConstants.TYPE_CHAR ? JavaConstants.TYPE_CHAR : 738 internalTypeChar == ClassConstants.TYPE_SHORT ? JavaConstants.TYPE_SHORT : 739 internalTypeChar == ClassConstants.TYPE_INT ? JavaConstants.TYPE_INT : 740 internalTypeChar == ClassConstants.TYPE_FLOAT ? JavaConstants.TYPE_FLOAT : 741 internalTypeChar == ClassConstants.TYPE_LONG ? JavaConstants.TYPE_LONG : 742 internalTypeChar == ClassConstants.TYPE_DOUBLE ? JavaConstants.TYPE_DOUBLE : 743 internalTypeChar == '%' ? "%" : 744 internalTypeChar == ClassConstants.TYPE_CLASS_START ? externalClassName(internalType.substring(1, internalType.indexOf(ClassConstants.TYPE_CLASS_END))) : 745 null; 746 747 if (externalType == null) 748 { 749 throw new IllegalArgumentException("Unknown type ["+internalType+"]"); 750 } 751 752 // Append the array part, if any. 753 for (int count = 0; count < dimensionCount; count++) 754 { 755 externalType += JavaConstants.TYPE_ARRAY; 756 } 757 758 return externalType; 759 } 760 761 762 /** 763 * Returns whether the given internal descriptor String represents a method 764 * descriptor. 765 * @param internalDescriptor the internal descriptor String, 766 * e.g. "<code>(II)Z</code>". 767 * @return <code>true</code> if the given String is a method descriptor, 768 * <code>false</code> otherwise. 769 */ isInternalMethodDescriptor(String internalDescriptor)770 public static boolean isInternalMethodDescriptor(String internalDescriptor) 771 { 772 return internalDescriptor.charAt(0) == ClassConstants.METHOD_ARGUMENTS_OPEN; 773 } 774 775 776 /** 777 * Returns whether the given member String represents an external method 778 * name with arguments. 779 * @param externalMemberNameAndArguments the external member String, 780 * e.g. "<code>myField</code>" or 781 * e.g. "<code>myMethod(int,int)</code>". 782 * @return <code>true</code> if the given String refers to a method, 783 * <code>false</code> otherwise. 784 */ isExternalMethodNameAndArguments(String externalMemberNameAndArguments)785 public static boolean isExternalMethodNameAndArguments(String externalMemberNameAndArguments) 786 { 787 return externalMemberNameAndArguments.indexOf(JavaConstants.METHOD_ARGUMENTS_OPEN) > 0; 788 } 789 790 791 /** 792 * Returns the name part of the given external method name and arguments. 793 * @param externalMethodNameAndArguments the external method name and arguments, 794 * e.g. "<code>myMethod(int,int)</code>". 795 * @return the name part of the String, e.g. "<code>myMethod</code>". 796 */ externalMethodName(String externalMethodNameAndArguments)797 public static String externalMethodName(String externalMethodNameAndArguments) 798 { 799 ExternalTypeEnumeration externalTypeEnumeration = 800 new ExternalTypeEnumeration(externalMethodNameAndArguments); 801 802 return externalTypeEnumeration.methodName(); 803 } 804 805 806 /** 807 * Converts the given external method return type and name and arguments to 808 * an internal method descriptor. 809 * @param externalReturnType the external method return type, 810 * e.g. "<code>boolean</code>". 811 * @param externalMethodNameAndArguments the external method name and arguments, 812 * e.g. "<code>myMethod(int,int)</code>". 813 * @return the internal method descriptor, 814 * e.g. "<code>(II)Z</code>". 815 */ internalMethodDescriptor(String externalReturnType, String externalMethodNameAndArguments)816 public static String internalMethodDescriptor(String externalReturnType, 817 String externalMethodNameAndArguments) 818 { 819 StringBuffer internalMethodDescriptor = new StringBuffer(); 820 internalMethodDescriptor.append(ClassConstants.METHOD_ARGUMENTS_OPEN); 821 822 ExternalTypeEnumeration externalTypeEnumeration = 823 new ExternalTypeEnumeration(externalMethodNameAndArguments); 824 825 while (externalTypeEnumeration.hasMoreTypes()) 826 { 827 internalMethodDescriptor.append(internalType(externalTypeEnumeration.nextType())); 828 } 829 830 internalMethodDescriptor.append(ClassConstants.METHOD_ARGUMENTS_CLOSE); 831 internalMethodDescriptor.append(internalType(externalReturnType)); 832 833 return internalMethodDescriptor.toString(); 834 } 835 836 837 /** 838 * Converts the given external method return type and List of arguments to 839 * an internal method descriptor. 840 * @param externalReturnType the external method return type, 841 * e.g. "<code>boolean</code>". 842 * @param externalArguments the external method arguments, 843 * e.g. <code>{ "int", "int" }</code>. 844 * @return the internal method descriptor, 845 * e.g. "<code>(II)Z</code>". 846 */ internalMethodDescriptor(String externalReturnType, List externalArguments)847 public static String internalMethodDescriptor(String externalReturnType, 848 List externalArguments) 849 { 850 StringBuffer internalMethodDescriptor = new StringBuffer(); 851 internalMethodDescriptor.append(ClassConstants.METHOD_ARGUMENTS_OPEN); 852 853 for (int index = 0; index < externalArguments.size(); index++) 854 { 855 internalMethodDescriptor.append(internalType((String)externalArguments.get(index))); 856 } 857 858 internalMethodDescriptor.append(ClassConstants.METHOD_ARGUMENTS_CLOSE); 859 internalMethodDescriptor.append(internalType(externalReturnType)); 860 861 return internalMethodDescriptor.toString(); 862 } 863 864 865 /** 866 * Converts an internal field description into an external full field description. 867 * @param accessFlags the access flags of the field. 868 * @param fieldName the field name, 869 * e.g. "<code>myField</code>". 870 * @param internalFieldDescriptor the internal field descriptor, 871 * e.g. "<code>Z</code>". 872 * @return the external full field description, 873 * e.g. "<code>public boolean myField</code>". 874 */ externalFullFieldDescription(int accessFlags, String fieldName, String internalFieldDescriptor)875 public static String externalFullFieldDescription(int accessFlags, 876 String fieldName, 877 String internalFieldDescriptor) 878 { 879 return externalFieldAccessFlags(accessFlags) + 880 externalType(internalFieldDescriptor) + 881 ' ' + 882 fieldName; 883 } 884 885 886 /** 887 * Converts an internal method description into an external full method description. 888 * @param internalClassName the internal name of the class of the method, 889 * e.g. "<code>mypackage/MyClass</code>". 890 * @param accessFlags the access flags of the method. 891 * @param internalMethodName the internal method name, 892 * e.g. "<code>myMethod</code>" or 893 * "<code><init></code>". 894 * @param internalMethodDescriptor the internal method descriptor, 895 * e.g. "<code>(II)Z</code>". 896 * @return the external full method description, 897 * e.g. "<code>public boolean myMethod(int,int)</code>" or 898 * "<code>public MyClass(int,int)</code>". 899 */ externalFullMethodDescription(String internalClassName, int accessFlags, String internalMethodName, String internalMethodDescriptor)900 public static String externalFullMethodDescription(String internalClassName, 901 int accessFlags, 902 String internalMethodName, 903 String internalMethodDescriptor) 904 { 905 return externalMethodAccessFlags(accessFlags) + 906 externalMethodReturnTypeAndName(internalClassName, 907 internalMethodName, 908 internalMethodDescriptor) + 909 JavaConstants.METHOD_ARGUMENTS_OPEN + 910 externalMethodArguments(internalMethodDescriptor) + 911 JavaConstants.METHOD_ARGUMENTS_CLOSE; 912 } 913 914 915 /** 916 * Converts internal class access flags into an external access description. 917 * @param accessFlags the class access flags. 918 * @return the external class access description, 919 * e.g. "<code>public final </code>". 920 */ externalClassAccessFlags(int accessFlags)921 public static String externalClassAccessFlags(int accessFlags) 922 { 923 return externalClassAccessFlags(accessFlags, ""); 924 } 925 926 927 /** 928 * Converts internal class access flags into an external access description. 929 * @param accessFlags the class access flags. 930 * @param prefix a prefix that is added to each access modifier. 931 * @return the external class access description, 932 * e.g. "<code>public final </code>". 933 */ externalClassAccessFlags(int accessFlags, String prefix)934 public static String externalClassAccessFlags(int accessFlags, String prefix) 935 { 936 if (accessFlags == 0) 937 { 938 return EMPTY_STRING; 939 } 940 941 StringBuffer string = new StringBuffer(50); 942 943 if ((accessFlags & ClassConstants.ACC_PUBLIC) != 0) 944 { 945 string.append(prefix).append(JavaConstants.ACC_PUBLIC).append(' '); 946 } 947 if ((accessFlags & ClassConstants.ACC_PRIVATE) != 0) 948 { 949 // Only in InnerClasses attributes. 950 string.append(prefix).append(JavaConstants.ACC_PRIVATE).append(' '); 951 } 952 if ((accessFlags & ClassConstants.ACC_PROTECTED) != 0) 953 { 954 // Only in InnerClasses attributes. 955 string.append(prefix).append(JavaConstants.ACC_PROTECTED).append(' '); 956 } 957 if ((accessFlags & ClassConstants.ACC_STATIC) != 0) 958 { 959 // Only in InnerClasses attributes. 960 string.append(prefix).append(JavaConstants.ACC_STATIC).append(' '); 961 } 962 if ((accessFlags & ClassConstants.ACC_FINAL) != 0) 963 { 964 string.append(prefix).append(JavaConstants.ACC_FINAL).append(' '); 965 } 966 if ((accessFlags & ClassConstants.ACC_ANNOTATTION) != 0) 967 { 968 string.append(prefix).append(JavaConstants.ACC_ANNOTATION); 969 } 970 if ((accessFlags & ClassConstants.ACC_INTERFACE) != 0) 971 { 972 string.append(prefix).append(JavaConstants.ACC_INTERFACE).append(' '); 973 } 974 else if ((accessFlags & ClassConstants.ACC_ENUM) != 0) 975 { 976 string.append(prefix).append(JavaConstants.ACC_ENUM).append(' '); 977 } 978 else if ((accessFlags & ClassConstants.ACC_ABSTRACT) != 0) 979 { 980 string.append(prefix).append(JavaConstants.ACC_ABSTRACT).append(' '); 981 } 982 else if ((accessFlags & ClassConstants.ACC_SYNTHETIC) != 0) 983 { 984 string.append(prefix).append(JavaConstants.ACC_SYNTHETIC).append(' '); 985 } 986 987 return string.toString(); 988 } 989 990 991 /** 992 * Converts internal field access flags into an external access description. 993 * @param accessFlags the field access flags. 994 * @return the external field access description, 995 * e.g. "<code>public volatile </code>". 996 */ externalFieldAccessFlags(int accessFlags)997 public static String externalFieldAccessFlags(int accessFlags) 998 { 999 return externalFieldAccessFlags(accessFlags, ""); 1000 } 1001 1002 1003 /** 1004 * Converts internal field access flags into an external access description. 1005 * @param accessFlags the field access flags. 1006 * @param prefix a prefix that is added to each access modifier. 1007 * @return the external field access description, 1008 * e.g. "<code>public volatile </code>". 1009 */ externalFieldAccessFlags(int accessFlags, String prefix)1010 public static String externalFieldAccessFlags(int accessFlags, String prefix) 1011 { 1012 if (accessFlags == 0) 1013 { 1014 return EMPTY_STRING; 1015 } 1016 1017 StringBuffer string = new StringBuffer(50); 1018 1019 if ((accessFlags & ClassConstants.ACC_PUBLIC) != 0) 1020 { 1021 string.append(prefix).append(JavaConstants.ACC_PUBLIC).append(' '); 1022 } 1023 if ((accessFlags & ClassConstants.ACC_PRIVATE) != 0) 1024 { 1025 string.append(prefix).append(JavaConstants.ACC_PRIVATE).append(' '); 1026 } 1027 if ((accessFlags & ClassConstants.ACC_PROTECTED) != 0) 1028 { 1029 string.append(prefix).append(JavaConstants.ACC_PROTECTED).append(' '); 1030 } 1031 if ((accessFlags & ClassConstants.ACC_STATIC) != 0) 1032 { 1033 string.append(prefix).append(JavaConstants.ACC_STATIC).append(' '); 1034 } 1035 if ((accessFlags & ClassConstants.ACC_FINAL) != 0) 1036 { 1037 string.append(prefix).append(JavaConstants.ACC_FINAL).append(' '); 1038 } 1039 if ((accessFlags & ClassConstants.ACC_VOLATILE) != 0) 1040 { 1041 string.append(prefix).append(JavaConstants.ACC_VOLATILE).append(' '); 1042 } 1043 if ((accessFlags & ClassConstants.ACC_TRANSIENT) != 0) 1044 { 1045 string.append(prefix).append(JavaConstants.ACC_TRANSIENT).append(' '); 1046 } 1047 if ((accessFlags & ClassConstants.ACC_SYNTHETIC) != 0) 1048 { 1049 string.append(prefix).append(JavaConstants.ACC_SYNTHETIC).append(' '); 1050 } 1051 1052 return string.toString(); 1053 } 1054 1055 1056 /** 1057 * Converts internal method access flags into an external access description. 1058 * @param accessFlags the method access flags. 1059 * @return the external method access description, 1060 * e.g. "<code>public synchronized </code>". 1061 */ externalMethodAccessFlags(int accessFlags)1062 public static String externalMethodAccessFlags(int accessFlags) 1063 { 1064 return externalMethodAccessFlags(accessFlags, ""); 1065 } 1066 1067 1068 /** 1069 * Converts internal method access flags into an external access description. 1070 * @param accessFlags the method access flags. 1071 * @param prefix a prefix that is added to each access modifier. 1072 * @return the external method access description, 1073 * e.g. "public synchronized ". 1074 */ externalMethodAccessFlags(int accessFlags, String prefix)1075 public static String externalMethodAccessFlags(int accessFlags, String prefix) 1076 { 1077 if (accessFlags == 0) 1078 { 1079 return EMPTY_STRING; 1080 } 1081 1082 StringBuffer string = new StringBuffer(50); 1083 1084 if ((accessFlags & ClassConstants.ACC_PUBLIC) != 0) 1085 { 1086 string.append(prefix).append(JavaConstants.ACC_PUBLIC).append(' '); 1087 } 1088 if ((accessFlags & ClassConstants.ACC_PRIVATE) != 0) 1089 { 1090 string.append(prefix).append(JavaConstants.ACC_PRIVATE).append(' '); 1091 } 1092 if ((accessFlags & ClassConstants.ACC_PROTECTED) != 0) 1093 { 1094 string.append(prefix).append(JavaConstants.ACC_PROTECTED).append(' '); 1095 } 1096 if ((accessFlags & ClassConstants.ACC_STATIC) != 0) 1097 { 1098 string.append(prefix).append(JavaConstants.ACC_STATIC).append(' '); 1099 } 1100 if ((accessFlags & ClassConstants.ACC_FINAL) != 0) 1101 { 1102 string.append(prefix).append(JavaConstants.ACC_FINAL).append(' '); 1103 } 1104 if ((accessFlags & ClassConstants.ACC_SYNCHRONIZED) != 0) 1105 { 1106 string.append(prefix).append(JavaConstants.ACC_SYNCHRONIZED).append(' '); 1107 } 1108 if ((accessFlags & ClassConstants.ACC_BRIDGE) != 0) 1109 { 1110 string.append(prefix).append(JavaConstants.ACC_BRIDGE).append(' '); 1111 } 1112 if ((accessFlags & ClassConstants.ACC_VARARGS) != 0) 1113 { 1114 string.append(prefix).append(JavaConstants.ACC_VARARGS).append(' '); 1115 } 1116 if ((accessFlags & ClassConstants.ACC_NATIVE) != 0) 1117 { 1118 string.append(prefix).append(JavaConstants.ACC_NATIVE).append(' '); 1119 } 1120 if ((accessFlags & ClassConstants.ACC_ABSTRACT) != 0) 1121 { 1122 string.append(prefix).append(JavaConstants.ACC_ABSTRACT).append(' '); 1123 } 1124 if ((accessFlags & ClassConstants.ACC_STRICT) != 0) 1125 { 1126 string.append(prefix).append(JavaConstants.ACC_STRICT).append(' '); 1127 } 1128 if ((accessFlags & ClassConstants.ACC_SYNTHETIC) != 0) 1129 { 1130 string.append(prefix).append(JavaConstants.ACC_SYNTHETIC).append(' '); 1131 } 1132 1133 return string.toString(); 1134 } 1135 1136 1137 /** 1138 * Converts internal method parameter access flags into an external access 1139 * description. 1140 * @param accessFlags the method parameter access flags. 1141 * @return the external method parameter access description, 1142 * e.g. "<code>final mandated </code>". 1143 */ externalParameterAccessFlags(int accessFlags)1144 public static String externalParameterAccessFlags(int accessFlags) 1145 { 1146 return externalParameterAccessFlags(accessFlags, ""); 1147 } 1148 1149 1150 /** 1151 * Converts internal method parameter access flags into an external access 1152 * description. 1153 * @param accessFlags the method parameter access flags. 1154 * @param prefix a prefix that is added to each access modifier. 1155 * @return the external method parameter access description, 1156 * e.g. "final mandated ". 1157 */ externalParameterAccessFlags(int accessFlags, String prefix)1158 public static String externalParameterAccessFlags(int accessFlags, String prefix) 1159 { 1160 if (accessFlags == 0) 1161 { 1162 return EMPTY_STRING; 1163 } 1164 1165 StringBuffer string = new StringBuffer(50); 1166 1167 if ((accessFlags & ClassConstants.ACC_FINAL) != 0) 1168 { 1169 string.append(prefix).append(JavaConstants.ACC_FINAL).append(' '); 1170 } 1171 if ((accessFlags & ClassConstants.ACC_SYNTHETIC) != 0) 1172 { 1173 string.append(prefix).append(JavaConstants.ACC_SYNTHETIC).append(' '); 1174 } 1175 if ((accessFlags & ClassConstants.ACC_MANDATED) != 0) 1176 { 1177 string.append(prefix).append(JavaConstants.ACC_MANDATED).append(' '); 1178 } 1179 1180 return string.toString(); 1181 } 1182 1183 1184 /** 1185 * Converts an internal method descriptor into an external method return type. 1186 * @param internalMethodDescriptor the internal method descriptor, 1187 * e.g. "<code>(II)Z</code>". 1188 * @return the external method return type, 1189 * e.g. "<code>boolean</code>". 1190 */ externalMethodReturnType(String internalMethodDescriptor)1191 public static String externalMethodReturnType(String internalMethodDescriptor) 1192 { 1193 return externalType(internalMethodReturnType(internalMethodDescriptor)); 1194 } 1195 1196 1197 /** 1198 * Converts an internal class name, method name, and method descriptor to 1199 * an external method return type and name. 1200 * @param internalClassName the internal name of the class of the method, 1201 * e.g. "<code>mypackage/MyClass</code>". 1202 * @param internalMethodName the internal method name, 1203 * e.g. "<code>myMethod</code>" or 1204 * "<code><init></code>". 1205 * @param internalMethodDescriptor the internal method descriptor, 1206 * e.g. "<code>(II)Z</code>". 1207 * @return the external method return type and name, 1208 * e.g. "<code>boolean myMethod</code>" or 1209 * "<code>MyClass</code>". 1210 */ externalMethodReturnTypeAndName(String internalClassName, String internalMethodName, String internalMethodDescriptor)1211 private static String externalMethodReturnTypeAndName(String internalClassName, 1212 String internalMethodName, 1213 String internalMethodDescriptor) 1214 { 1215 return internalMethodName.equals(ClassConstants.METHOD_NAME_INIT) ? 1216 externalShortClassName(externalClassName(internalClassName)) : 1217 (externalMethodReturnType(internalMethodDescriptor) + 1218 ' ' + 1219 internalMethodName); 1220 } 1221 1222 1223 /** 1224 * Converts an internal method descriptor into an external method argument 1225 * description. 1226 * @param internalMethodDescriptor the internal method descriptor, 1227 * e.g. "<code>(II)Z</code>". 1228 * @return the external method argument description, 1229 * e.g. "<code>int,int</code>". 1230 */ externalMethodArguments(String internalMethodDescriptor)1231 public static String externalMethodArguments(String internalMethodDescriptor) 1232 { 1233 StringBuffer externalMethodNameAndArguments = new StringBuffer(); 1234 1235 InternalTypeEnumeration internalTypeEnumeration = 1236 new InternalTypeEnumeration(internalMethodDescriptor); 1237 1238 while (internalTypeEnumeration.hasMoreTypes()) 1239 { 1240 externalMethodNameAndArguments.append(externalType(internalTypeEnumeration.nextType())); 1241 if (internalTypeEnumeration.hasMoreTypes()) 1242 { 1243 externalMethodNameAndArguments.append(JavaConstants.METHOD_ARGUMENTS_SEPARATOR); 1244 } 1245 } 1246 1247 return externalMethodNameAndArguments.toString(); 1248 } 1249 1250 1251 /** 1252 * Returns the internal package name of the given internal class name. 1253 * @param internalClassName the internal class name, 1254 * e.g. "<code>java/lang/Object</code>". 1255 * @return the internal package name, 1256 * e.g. "<code>java/lang</code>". 1257 */ internalPackageName(String internalClassName)1258 public static String internalPackageName(String internalClassName) 1259 { 1260 String internalPackagePrefix = internalPackagePrefix(internalClassName); 1261 int length = internalPackagePrefix.length(); 1262 return length > 0 ? 1263 internalPackagePrefix.substring(0, length - 1) : 1264 ""; 1265 } 1266 1267 1268 /** 1269 * Returns the internal package prefix of the given internal class name. 1270 * @param internalClassName the internal class name, 1271 * e.g. "<code>java/lang/Object</code>". 1272 * @return the internal package prefix, 1273 * e.g. "<code>java/lang/</code>". 1274 */ internalPackagePrefix(String internalClassName)1275 public static String internalPackagePrefix(String internalClassName) 1276 { 1277 return internalClassName.substring(0, internalClassName.lastIndexOf(ClassConstants.PACKAGE_SEPARATOR, 1278 internalClassName.length() - 2) + 1); 1279 } 1280 1281 1282 /** 1283 * Returns the external package name of the given external class name. 1284 * @param externalClassName the external class name, 1285 * e.g. "<code>java.lang.Object</code>". 1286 * @return the external package name, 1287 * e.g. "<code>java.lang</code>". 1288 */ externalPackageName(String externalClassName)1289 public static String externalPackageName(String externalClassName) 1290 { 1291 String externalPackagePrefix = externalPackagePrefix(externalClassName); 1292 int length = externalPackagePrefix.length(); 1293 return length > 0 ? 1294 externalPackagePrefix.substring(0, length - 1) : 1295 ""; 1296 } 1297 1298 1299 /** 1300 * Returns the external package prefix of the given external class name. 1301 * @param externalClassName the external class name, 1302 * e.g. "<code>java.lang.Object</code>". 1303 * @return the external package prefix, 1304 * e.g. "<code>java.lang.</code>". 1305 */ externalPackagePrefix(String externalClassName)1306 public static String externalPackagePrefix(String externalClassName) 1307 { 1308 return externalClassName.substring(0, externalClassName.lastIndexOf(JavaConstants.PACKAGE_SEPARATOR, 1309 externalClassName.length() - 2) + 1); 1310 } 1311 } 1312