1 /* 2 * ProGuard -- shrinking, optimization, obfuscation, and preverification 3 * of Java bytecode. 4 * 5 * Copyright (c) 2002-2013 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.ClassConstants; 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(ClassConstants.EXTERNAL_CLASS_VERSION_1_0) || 95 classVersion.equals(ClassConstants.EXTERNAL_CLASS_VERSION_1_1) ? ClassConstants.INTERNAL_CLASS_VERSION_1_0 : 96 classVersion.equals(ClassConstants.EXTERNAL_CLASS_VERSION_1_2) ? ClassConstants.INTERNAL_CLASS_VERSION_1_2 : 97 classVersion.equals(ClassConstants.EXTERNAL_CLASS_VERSION_1_3) ? ClassConstants.INTERNAL_CLASS_VERSION_1_3 : 98 classVersion.equals(ClassConstants.EXTERNAL_CLASS_VERSION_1_4) ? ClassConstants.INTERNAL_CLASS_VERSION_1_4 : 99 classVersion.equals(ClassConstants.EXTERNAL_CLASS_VERSION_1_5_ALIAS) || 100 classVersion.equals(ClassConstants.EXTERNAL_CLASS_VERSION_1_5) ? ClassConstants.INTERNAL_CLASS_VERSION_1_5 : 101 classVersion.equals(ClassConstants.EXTERNAL_CLASS_VERSION_1_6_ALIAS) || 102 classVersion.equals(ClassConstants.EXTERNAL_CLASS_VERSION_1_6) ? ClassConstants.INTERNAL_CLASS_VERSION_1_6 : 103 classVersion.equals(ClassConstants.EXTERNAL_CLASS_VERSION_1_7_ALIAS) || 104 classVersion.equals(ClassConstants.EXTERNAL_CLASS_VERSION_1_7) ? ClassConstants.INTERNAL_CLASS_VERSION_1_7 : 105 0; 106 } 107 108 109 /** 110 * Returns the minor part of the given class version number. 111 * @param classVersion the combined class version number. 112 * @return the minor part of the class version number. 113 */ externalClassVersion(int classVersion)114 public static String externalClassVersion(int classVersion) 115 { 116 switch (classVersion) 117 { 118 case ClassConstants.INTERNAL_CLASS_VERSION_1_0: return ClassConstants.EXTERNAL_CLASS_VERSION_1_0; 119 case ClassConstants.INTERNAL_CLASS_VERSION_1_2: return ClassConstants.EXTERNAL_CLASS_VERSION_1_2; 120 case ClassConstants.INTERNAL_CLASS_VERSION_1_3: return ClassConstants.EXTERNAL_CLASS_VERSION_1_3; 121 case ClassConstants.INTERNAL_CLASS_VERSION_1_4: return ClassConstants.EXTERNAL_CLASS_VERSION_1_4; 122 case ClassConstants.INTERNAL_CLASS_VERSION_1_5: return ClassConstants.EXTERNAL_CLASS_VERSION_1_5; 123 case ClassConstants.INTERNAL_CLASS_VERSION_1_6: return ClassConstants.EXTERNAL_CLASS_VERSION_1_6; 124 case ClassConstants.INTERNAL_CLASS_VERSION_1_7: return ClassConstants.EXTERNAL_CLASS_VERSION_1_7; 125 default: return null; 126 } 127 } 128 129 130 /** 131 * Checks whether the given class version number is supported. 132 * @param classVersion the combined class version number. 133 * @throws UnsupportedOperationException when the version is not supported. 134 */ checkVersionNumbers(int classVersion)135 public static void checkVersionNumbers(int classVersion) throws UnsupportedOperationException 136 { 137 if (classVersion < ClassConstants.INTERNAL_CLASS_VERSION_1_0 || 138 classVersion > ClassConstants.INTERNAL_CLASS_VERSION_1_7) 139 { 140 throw new UnsupportedOperationException("Unsupported class version number ["+ 141 internalMajorClassVersion(classVersion)+"."+ 142 internalMinorClassVersion(classVersion)+"] (maximum "+ 143 ClassConstants.INTERNAL_CLASS_VERSION_1_7_MAJOR+"."+ 144 ClassConstants.INTERNAL_CLASS_VERSION_1_7_MINOR+", Java "+ 145 ClassConstants.EXTERNAL_CLASS_VERSION_1_7+")"); 146 } 147 } 148 149 150 /** 151 * Converts an external class name into an internal class name. 152 * @param externalClassName the external class name, 153 * e.g. "<code>java.lang.Object</code>" 154 * @return the internal class name, 155 * e.g. "<code>java/lang/Object</code>". 156 */ internalClassName(String externalClassName)157 public static String internalClassName(String externalClassName) 158 { 159 return externalClassName.replace(ClassConstants.EXTERNAL_PACKAGE_SEPARATOR, 160 ClassConstants.INTERNAL_PACKAGE_SEPARATOR); 161 } 162 163 164 /** 165 * Converts an internal class description into an external class description. 166 * @param accessFlags the access flags of the class. 167 * @param internalClassName the internal class name, 168 * e.g. "<code>java/lang/Object</code>". 169 * @return the external class description, 170 * e.g. "<code>public java.lang.Object</code>". 171 */ externalFullClassDescription(int accessFlags, String internalClassName)172 public static String externalFullClassDescription(int accessFlags, 173 String internalClassName) 174 { 175 return externalClassAccessFlags(accessFlags) + 176 externalClassName(internalClassName); 177 } 178 179 180 /** 181 * Converts an internal class name into an external class name. 182 * @param internalClassName the internal class name, 183 * e.g. "<code>java/lang/Object</code>". 184 * @return the external class name, 185 * e.g. "<code>java.lang.Object</code>". 186 */ externalClassName(String internalClassName)187 public static String externalClassName(String internalClassName) 188 { 189 return //internalClassName.startsWith(ClassConstants.INTERNAL_PACKAGE_JAVA_LANG) && 190 //internalClassName.indexOf(ClassConstants.INTERNAL_PACKAGE_SEPARATOR, ClassConstants.INTERNAL_PACKAGE_JAVA_LANG.length() + 1) < 0 ? 191 //internalClassName.substring(ClassConstants.INTERNAL_PACKAGE_JAVA_LANG.length()) : 192 internalClassName.replace(ClassConstants.INTERNAL_PACKAGE_SEPARATOR, 193 ClassConstants.EXTERNAL_PACKAGE_SEPARATOR); 194 } 195 196 197 /** 198 * Returns the external base type of an external array type, dropping any 199 * array brackets. 200 * @param externalArrayType the external array type, 201 * e.g. "<code>java.lang.Object[][]</code>" 202 * @return the external base type, 203 * e.g. "<code>java.lang.Object</code>". 204 */ externalBaseType(String externalArrayType)205 public static String externalBaseType(String externalArrayType) 206 { 207 int index = externalArrayType.indexOf(ClassConstants.EXTERNAL_TYPE_ARRAY); 208 return index >= 0 ? 209 externalArrayType.substring(0, index) : 210 externalArrayType; 211 } 212 213 214 /** 215 * Returns the external short class name of an external class name, dropping 216 * the package specification. 217 * @param externalClassName the external class name, 218 * e.g. "<code>java.lang.Object</code>" 219 * @return the external short class name, 220 * e.g. "<code>Object</code>". 221 */ externalShortClassName(String externalClassName)222 public static String externalShortClassName(String externalClassName) 223 { 224 int index = externalClassName.lastIndexOf(ClassConstants.EXTERNAL_PACKAGE_SEPARATOR); 225 return externalClassName.substring(index+1); 226 } 227 228 229 /** 230 * Returns whether the given internal type is an array type. 231 * @param internalType the internal type, 232 * e.g. "<code>[[Ljava/lang/Object;</code>". 233 * @return <code>true</code> if the given type is an array type, 234 * <code>false</code> otherwise. 235 */ isInternalArrayType(String internalType)236 public static boolean isInternalArrayType(String internalType) 237 { 238 return internalType.length() > 1 && 239 internalType.charAt(0) == ClassConstants.INTERNAL_TYPE_ARRAY; 240 } 241 242 243 /** 244 * Returns the number of dimensions of the given internal type. 245 * @param internalType the internal type, 246 * e.g. "<code>[[Ljava/lang/Object;</code>". 247 * @return the number of dimensions, e.g. 2. 248 */ internalArrayTypeDimensionCount(String internalType)249 public static int internalArrayTypeDimensionCount(String internalType) 250 { 251 int dimensions = 0; 252 while (internalType.charAt(dimensions) == ClassConstants.INTERNAL_TYPE_ARRAY) 253 { 254 dimensions++; 255 } 256 257 return dimensions; 258 } 259 260 261 /** 262 * Returns whether the given internal class name is one of the interfaces 263 * that is implemented by all array types. These class names are 264 * "<code>java/lang/Object</code>", "<code>java/lang/Cloneable</code>", and 265 * "<code>java/io/Serializable</code>" 266 * @param internalClassName the internal class name, 267 * e.g. "<code>java/lang/Object</code>". 268 * @return <code>true</code> if the given type is an array interface name, 269 * <code>false</code> otherwise. 270 */ isInternalArrayInterfaceName(String internalClassName)271 public static boolean isInternalArrayInterfaceName(String internalClassName) 272 { 273 return ClassConstants.INTERNAL_NAME_JAVA_LANG_OBJECT.equals(internalClassName) || 274 ClassConstants.INTERNAL_NAME_JAVA_LANG_CLONEABLE.equals(internalClassName) || 275 ClassConstants.INTERNAL_NAME_JAVA_IO_SERIALIZABLE.equals(internalClassName); 276 } 277 278 279 /** 280 * Returns whether the given internal type is a plain primitive type 281 * (not void). 282 * @param internalType the internal type, 283 * e.g. "<code>I</code>". 284 * @return <code>true</code> if the given type is a class type, 285 * <code>false</code> otherwise. 286 */ isInternalPrimitiveType(char internalType)287 public static boolean isInternalPrimitiveType(char internalType) 288 { 289 return internalType == ClassConstants.INTERNAL_TYPE_BOOLEAN || 290 internalType == ClassConstants.INTERNAL_TYPE_BYTE || 291 internalType == ClassConstants.INTERNAL_TYPE_CHAR || 292 internalType == ClassConstants.INTERNAL_TYPE_SHORT || 293 internalType == ClassConstants.INTERNAL_TYPE_INT || 294 internalType == ClassConstants.INTERNAL_TYPE_FLOAT || 295 internalType == ClassConstants.INTERNAL_TYPE_LONG || 296 internalType == ClassConstants.INTERNAL_TYPE_DOUBLE; 297 } 298 299 300 /** 301 * Returns whether the given internal type is a primitive Category 2 type. 302 * @param internalType the internal type, 303 * e.g. "<code>L</code>". 304 * @return <code>true</code> if the given type is a Category 2 type, 305 * <code>false</code> otherwise. 306 */ isInternalCategory2Type(String internalType)307 public static boolean isInternalCategory2Type(String internalType) 308 { 309 return internalType.length() == 1 && 310 (internalType.charAt(0) == ClassConstants.INTERNAL_TYPE_LONG || 311 internalType.charAt(0) == ClassConstants.INTERNAL_TYPE_DOUBLE); 312 } 313 314 315 /** 316 * Returns whether the given internal type is a plain class type 317 * (including an array type of a plain class type). 318 * @param internalType the internal type, 319 * e.g. "<code>Ljava/lang/Object;</code>". 320 * @return <code>true</code> if the given type is a class type, 321 * <code>false</code> otherwise. 322 */ isInternalClassType(String internalType)323 public static boolean isInternalClassType(String internalType) 324 { 325 int length = internalType.length(); 326 return length > 1 && 327 // internalType.charAt(0) == ClassConstants.INTERNAL_TYPE_CLASS_START && 328 internalType.charAt(length-1) == ClassConstants.INTERNAL_TYPE_CLASS_END; 329 } 330 331 332 /** 333 * Returns the internal type of a given class name. 334 * @param internalClassName the internal class name, 335 * e.g. "<code>java/lang/Object</code>". 336 * @return the internal type, 337 * e.g. "<code>Ljava/lang/Object;</code>". 338 */ internalTypeFromClassName(String internalClassName)339 public static String internalTypeFromClassName(String internalClassName) 340 { 341 return internalArrayTypeFromClassName(internalClassName, 0); 342 } 343 344 345 /** 346 * Returns the internal array type of a given class name with a given number 347 * of dimensions. If the number of dimensions is 0, the class name itself is 348 * returned. 349 * @param internalClassName the internal class name, 350 * e.g. "<code>java/lang/Object</code>". 351 * @param dimensionCount the number of array dimensions. 352 * @return the internal array type of the array elements, 353 * e.g. "<code>Ljava/lang/Object;</code>". 354 */ internalArrayTypeFromClassName(String internalClassName, int dimensionCount)355 public static String internalArrayTypeFromClassName(String internalClassName, 356 int dimensionCount) 357 { 358 StringBuffer buffer = new StringBuffer(internalClassName.length() + dimensionCount + 2); 359 360 for (int dimension = 0; dimension < dimensionCount; dimension++) 361 { 362 buffer.append(ClassConstants.INTERNAL_TYPE_ARRAY); 363 } 364 365 return buffer.append(ClassConstants.INTERNAL_TYPE_CLASS_START) 366 .append(internalClassName) 367 .append(ClassConstants.INTERNAL_TYPE_CLASS_END) 368 .toString(); 369 } 370 371 372 /** 373 * Returns the internal element type of a given internal array type. 374 * @param internalArrayType the internal array type, 375 * e.g. "<code>[[Ljava/lang/Object;</code>" or 376 * "<code>[I</code>". 377 * @return the internal type of the array elements, 378 * e.g. "<code>Ljava/lang/Object;</code>" or 379 * "<code>I</code>". 380 */ internalTypeFromArrayType(String internalArrayType)381 public static String internalTypeFromArrayType(String internalArrayType) 382 { 383 int index = internalArrayType.lastIndexOf(ClassConstants.INTERNAL_TYPE_ARRAY); 384 return internalArrayType.substring(index+1); 385 } 386 387 388 /** 389 * Returns the internal class name of a given internal class type 390 * (including an array type). Types involving primitive types are returned 391 * unchanged. 392 * @param internalClassType the internal class type, 393 * e.g. "<code>[Ljava/lang/Object;</code>", 394 * "<code>Ljava/lang/Object;</code>", or 395 * "<code>java/lang/Object</code>". 396 * @return the internal class name, 397 * e.g. "<code>java/lang/Object</code>". 398 */ internalClassNameFromClassType(String internalClassType)399 public static String internalClassNameFromClassType(String internalClassType) 400 { 401 return isInternalClassType(internalClassType) ? 402 internalClassType.substring(internalClassType.indexOf(ClassConstants.INTERNAL_TYPE_CLASS_START)+1, 403 internalClassType.length()-1) : 404 internalClassType; 405 } 406 407 408 /** 409 * Returns the internal class name of any given internal descriptor type, 410 * disregarding array prefixes. 411 * @param internalClassType the internal class type, 412 * e.g. "<code>Ljava/lang/Object;</code>" or 413 * "<code>[[I</code>". 414 * @return the internal class name, 415 * e.g. "<code>java/lang/Object</code>" or 416 * <code>null</code>. 417 */ internalClassNameFromType(String internalClassType)418 public static String internalClassNameFromType(String internalClassType) 419 { 420 if (!isInternalClassType(internalClassType)) 421 { 422 return null; 423 } 424 425 // Is it an array type? 426 if (isInternalArrayType(internalClassType)) 427 { 428 internalClassType = internalTypeFromArrayType(internalClassType); 429 } 430 431 return internalClassNameFromClassType(internalClassType); 432 } 433 434 435 /** 436 * Returns whether the given method name refers to a class initializer or 437 * an instance initializer. 438 * @param internalMethodName the internal method name, 439 * e.g. "<code><clinit></code>". 440 * @return whether the method name refers to an initializer, 441 * e.g. <code>true</code>. 442 */ isInitializer(String internalMethodName)443 public static boolean isInitializer(String internalMethodName) 444 { 445 return internalMethodName.equals(ClassConstants.INTERNAL_METHOD_NAME_CLINIT) || 446 internalMethodName.equals(ClassConstants.INTERNAL_METHOD_NAME_INIT); 447 } 448 449 450 /** 451 * Returns the internal type of the given internal method descriptor. 452 * @param internalMethodDescriptor the internal method descriptor, 453 * e.g. "<code>(II)Z</code>". 454 * @return the internal return type, 455 * e.g. "<code>Z</code>". 456 */ internalMethodReturnType(String internalMethodDescriptor)457 public static String internalMethodReturnType(String internalMethodDescriptor) 458 { 459 int index = internalMethodDescriptor.indexOf(ClassConstants.INTERNAL_METHOD_ARGUMENTS_CLOSE); 460 return internalMethodDescriptor.substring(index + 1); 461 } 462 463 464 /** 465 * Returns the number of parameters of the given internal method descriptor. 466 * @param internalMethodDescriptor the internal method descriptor, 467 * e.g. "<code>(ID)Z</code>". 468 * @return the number of parameters, 469 * e.g. 2. 470 */ internalMethodParameterCount(String internalMethodDescriptor)471 public static int internalMethodParameterCount(String internalMethodDescriptor) 472 { 473 InternalTypeEnumeration internalTypeEnumeration = 474 new InternalTypeEnumeration(internalMethodDescriptor); 475 476 int counter = 0; 477 while (internalTypeEnumeration.hasMoreTypes()) 478 { 479 internalTypeEnumeration.nextType(); 480 481 counter++; 482 } 483 484 return counter; 485 } 486 487 488 /** 489 * Returns the size taken up on the stack by the parameters of the given 490 * internal method descriptor. This accounts for long and double parameters 491 * taking up two entries. 492 * @param internalMethodDescriptor the internal method descriptor, 493 * e.g. "<code>(ID)Z</code>". 494 * @return the size taken up on the stack, 495 * e.g. 3. 496 */ internalMethodParameterSize(String internalMethodDescriptor)497 public static int internalMethodParameterSize(String internalMethodDescriptor) 498 { 499 return internalMethodParameterSize(internalMethodDescriptor, true); 500 } 501 502 503 /** 504 * Returns the size taken up on the stack by the parameters of the given 505 * internal method descriptor. This accounts for long and double parameters 506 * taking up two entries, and a non-static method taking up an additional 507 * entry. 508 * @param internalMethodDescriptor the internal method descriptor, 509 * e.g. "<code>(ID)Z</code>". 510 * @param accessFlags the access flags of the method, 511 * e.g. 0. 512 * @return the size taken up on the stack, 513 * e.g. 4. 514 */ internalMethodParameterSize(String internalMethodDescriptor, int accessFlags)515 public static int internalMethodParameterSize(String internalMethodDescriptor, 516 int accessFlags) 517 { 518 return internalMethodParameterSize(internalMethodDescriptor, 519 (accessFlags & ClassConstants.INTERNAL_ACC_STATIC) != 0); 520 } 521 522 523 /** 524 * Returns the size taken up on the stack by the parameters of the given 525 * internal method descriptor. This accounts for long and double parameters 526 * taking up two spaces, and a non-static method taking up an additional 527 * entry. 528 * @param internalMethodDescriptor the internal method descriptor, 529 * e.g. "<code>(ID)Z</code>". 530 * @param isStatic specifies whether the method is static, 531 * e.g. false. 532 * @return the size taken up on the stack, 533 * e.g. 4. 534 */ internalMethodParameterSize(String internalMethodDescriptor, boolean isStatic)535 public static int internalMethodParameterSize(String internalMethodDescriptor, 536 boolean isStatic) 537 { 538 InternalTypeEnumeration internalTypeEnumeration = 539 new InternalTypeEnumeration(internalMethodDescriptor); 540 541 int size = isStatic ? 0 : 1; 542 while (internalTypeEnumeration.hasMoreTypes()) 543 { 544 String internalType = internalTypeEnumeration.nextType(); 545 546 size += internalTypeSize(internalType); 547 } 548 549 return size; 550 } 551 552 553 /** 554 * Returns the size taken up on the stack by the given internal type. 555 * The size is 1, except for long and double types, for which it is 2, 556 * and for the void type, for which 0 is returned. 557 * @param internalType the internal type, 558 * e.g. "<code>I</code>". 559 * @return the size taken up on the stack, 560 * e.g. 1. 561 */ internalTypeSize(String internalType)562 public static int internalTypeSize(String internalType) 563 { 564 if (internalType.length() == 1) 565 { 566 char internalPrimitiveType = internalType.charAt(0); 567 if (internalPrimitiveType == ClassConstants.INTERNAL_TYPE_LONG || 568 internalPrimitiveType == ClassConstants.INTERNAL_TYPE_DOUBLE) 569 { 570 return 2; 571 } 572 else if (internalPrimitiveType == ClassConstants.INTERNAL_TYPE_VOID) 573 { 574 return 0; 575 } 576 } 577 578 return 1; 579 } 580 581 582 /** 583 * Converts an external type into an internal type. 584 * @param externalType the external type, 585 * e.g. "<code>java.lang.Object[][]</code>" or 586 * "<code>int[]</code>". 587 * @return the internal type, 588 * e.g. "<code>[[Ljava/lang/Object;</code>" or 589 * "<code>[I</code>". 590 */ internalType(String externalType)591 public static String internalType(String externalType) 592 { 593 // Strip the array part, if any. 594 int dimensionCount = externalArrayTypeDimensionCount(externalType); 595 if (dimensionCount > 0) 596 { 597 externalType = externalType.substring(0, externalType.length() - dimensionCount * ClassConstants.EXTERNAL_TYPE_ARRAY.length()); 598 } 599 600 // Analyze the actual type part. 601 char internalTypeChar = 602 externalType.equals(ClassConstants.EXTERNAL_TYPE_VOID ) ? 603 ClassConstants.INTERNAL_TYPE_VOID : 604 externalType.equals(ClassConstants.EXTERNAL_TYPE_BOOLEAN) ? 605 ClassConstants.INTERNAL_TYPE_BOOLEAN : 606 externalType.equals(ClassConstants.EXTERNAL_TYPE_BYTE ) ? 607 ClassConstants.INTERNAL_TYPE_BYTE : 608 externalType.equals(ClassConstants.EXTERNAL_TYPE_CHAR ) ? 609 ClassConstants.INTERNAL_TYPE_CHAR : 610 externalType.equals(ClassConstants.EXTERNAL_TYPE_SHORT ) ? 611 ClassConstants.INTERNAL_TYPE_SHORT : 612 externalType.equals(ClassConstants.EXTERNAL_TYPE_INT ) ? 613 ClassConstants.INTERNAL_TYPE_INT : 614 externalType.equals(ClassConstants.EXTERNAL_TYPE_FLOAT ) ? 615 ClassConstants.INTERNAL_TYPE_FLOAT : 616 externalType.equals(ClassConstants.EXTERNAL_TYPE_LONG ) ? 617 ClassConstants.INTERNAL_TYPE_LONG : 618 externalType.equals(ClassConstants.EXTERNAL_TYPE_DOUBLE ) ? 619 ClassConstants.INTERNAL_TYPE_DOUBLE : 620 externalType.equals("%" ) ? 621 '%' : 622 (char)0; 623 624 String internalType = 625 internalTypeChar != 0 ? String.valueOf(internalTypeChar) : 626 ClassConstants.INTERNAL_TYPE_CLASS_START + 627 internalClassName(externalType) + 628 ClassConstants.INTERNAL_TYPE_CLASS_END; 629 630 // Prepend the array part, if any. 631 for (int count = 0; count < dimensionCount; count++) 632 { 633 internalType = ClassConstants.INTERNAL_TYPE_ARRAY + internalType; 634 } 635 636 return internalType; 637 } 638 639 640 /** 641 * Returns the number of dimensions of the given external type. 642 * @param externalType the external type, 643 * e.g. "<code>[[Ljava/lang/Object;</code>". 644 * @return the number of dimensions, e.g. 2. 645 */ externalArrayTypeDimensionCount(String externalType)646 public static int externalArrayTypeDimensionCount(String externalType) 647 { 648 int dimensions = 0; 649 int length = ClassConstants.EXTERNAL_TYPE_ARRAY.length(); 650 int offset = externalType.length() - length; 651 while (externalType.regionMatches(offset, 652 ClassConstants.EXTERNAL_TYPE_ARRAY, 653 0, 654 length)) 655 { 656 dimensions++; 657 offset -= length; 658 } 659 660 return dimensions; 661 } 662 663 664 /** 665 * Converts an internal type into an external type. 666 * @param internalType the internal type, 667 * e.g. "<code>[[Ljava/lang/Object;</code>" or 668 * "<code>[I</code>". 669 * @return the external type, 670 * e.g. "<code>java.lang.Object[][]</code>" or 671 * "<code>int[]</code>". 672 */ externalType(String internalType)673 public static String externalType(String internalType) 674 { 675 // Strip the array part, if any. 676 int dimensionCount = internalArrayTypeDimensionCount(internalType); 677 if (dimensionCount > 0) 678 { 679 internalType = internalType.substring(dimensionCount); 680 } 681 682 // Analyze the actual type part. 683 char internalTypeChar = internalType.charAt(0); 684 685 String externalType = 686 internalTypeChar == ClassConstants.INTERNAL_TYPE_VOID ? 687 ClassConstants.EXTERNAL_TYPE_VOID : 688 internalTypeChar == ClassConstants.INTERNAL_TYPE_BOOLEAN ? 689 ClassConstants.EXTERNAL_TYPE_BOOLEAN : 690 internalTypeChar == ClassConstants.INTERNAL_TYPE_BYTE ? 691 ClassConstants.EXTERNAL_TYPE_BYTE : 692 internalTypeChar == ClassConstants.INTERNAL_TYPE_CHAR ? 693 ClassConstants.EXTERNAL_TYPE_CHAR : 694 internalTypeChar == ClassConstants.INTERNAL_TYPE_SHORT ? 695 ClassConstants.EXTERNAL_TYPE_SHORT : 696 internalTypeChar == ClassConstants.INTERNAL_TYPE_INT ? 697 ClassConstants.EXTERNAL_TYPE_INT : 698 internalTypeChar == ClassConstants.INTERNAL_TYPE_FLOAT ? 699 ClassConstants.EXTERNAL_TYPE_FLOAT : 700 internalTypeChar == ClassConstants.INTERNAL_TYPE_LONG ? 701 ClassConstants.EXTERNAL_TYPE_LONG : 702 internalTypeChar == ClassConstants.INTERNAL_TYPE_DOUBLE ? 703 ClassConstants.EXTERNAL_TYPE_DOUBLE : 704 internalTypeChar == '%' ? 705 "%" : 706 internalTypeChar == ClassConstants.INTERNAL_TYPE_CLASS_START ? 707 externalClassName(internalType.substring(1, internalType.indexOf(ClassConstants.INTERNAL_TYPE_CLASS_END))) : 708 null; 709 710 if (externalType == null) 711 { 712 throw new IllegalArgumentException("Unknown type ["+internalType+"]"); 713 } 714 715 // Append the array part, if any. 716 for (int count = 0; count < dimensionCount; count++) 717 { 718 externalType += ClassConstants.EXTERNAL_TYPE_ARRAY; 719 } 720 721 return externalType; 722 } 723 724 725 /** 726 * Returns whether the given internal descriptor String represents a method 727 * descriptor. 728 * @param internalDescriptor the internal descriptor String, 729 * e.g. "<code>(II)Z</code>". 730 * @return <code>true</code> if the given String is a method descriptor, 731 * <code>false</code> otherwise. 732 */ isInternalMethodDescriptor(String internalDescriptor)733 public static boolean isInternalMethodDescriptor(String internalDescriptor) 734 { 735 return internalDescriptor.charAt(0) == ClassConstants.INTERNAL_METHOD_ARGUMENTS_OPEN; 736 } 737 738 739 /** 740 * Returns whether the given member String represents an external method 741 * name with arguments. 742 * @param externalMemberNameAndArguments the external member String, 743 * e.g. "<code>myField</code>" or 744 * e.g. "<code>myMethod(int,int)</code>". 745 * @return <code>true</code> if the given String refers to a method, 746 * <code>false</code> otherwise. 747 */ isExternalMethodNameAndArguments(String externalMemberNameAndArguments)748 public static boolean isExternalMethodNameAndArguments(String externalMemberNameAndArguments) 749 { 750 return externalMemberNameAndArguments.indexOf(ClassConstants.EXTERNAL_METHOD_ARGUMENTS_OPEN) > 0; 751 } 752 753 754 /** 755 * Returns the name part of the given external method name and arguments. 756 * @param externalMethodNameAndArguments the external method name and arguments, 757 * e.g. "<code>myMethod(int,int)</code>". 758 * @return the name part of the String, e.g. "<code>myMethod</code>". 759 */ externalMethodName(String externalMethodNameAndArguments)760 public static String externalMethodName(String externalMethodNameAndArguments) 761 { 762 ExternalTypeEnumeration externalTypeEnumeration = 763 new ExternalTypeEnumeration(externalMethodNameAndArguments); 764 765 return externalTypeEnumeration.methodName(); 766 } 767 768 769 /** 770 * Converts the given external method return type and name and arguments to 771 * an internal method descriptor. 772 * @param externalReturnType the external method return type, 773 * e.g. "<code>boolean</code>". 774 * @param externalMethodNameAndArguments the external method name and arguments, 775 * e.g. "<code>myMethod(int,int)</code>". 776 * @return the internal method descriptor, 777 * e.g. "<code>(II)Z</code>". 778 */ internalMethodDescriptor(String externalReturnType, String externalMethodNameAndArguments)779 public static String internalMethodDescriptor(String externalReturnType, 780 String externalMethodNameAndArguments) 781 { 782 StringBuffer internalMethodDescriptor = new StringBuffer(); 783 internalMethodDescriptor.append(ClassConstants.INTERNAL_METHOD_ARGUMENTS_OPEN); 784 785 ExternalTypeEnumeration externalTypeEnumeration = 786 new ExternalTypeEnumeration(externalMethodNameAndArguments); 787 788 while (externalTypeEnumeration.hasMoreTypes()) 789 { 790 internalMethodDescriptor.append(internalType(externalTypeEnumeration.nextType())); 791 } 792 793 internalMethodDescriptor.append(ClassConstants.INTERNAL_METHOD_ARGUMENTS_CLOSE); 794 internalMethodDescriptor.append(internalType(externalReturnType)); 795 796 return internalMethodDescriptor.toString(); 797 } 798 799 800 /** 801 * Converts the given external method return type and List of arguments to 802 * an internal method descriptor. 803 * @param externalReturnType the external method return type, 804 * e.g. "<code>boolean</code>". 805 * @param externalArguments the external method arguments, 806 * e.g. <code>{ "int", "int" }</code>. 807 * @return the internal method descriptor, 808 * e.g. "<code>(II)Z</code>". 809 */ internalMethodDescriptor(String externalReturnType, List externalArguments)810 public static String internalMethodDescriptor(String externalReturnType, 811 List externalArguments) 812 { 813 StringBuffer internalMethodDescriptor = new StringBuffer(); 814 internalMethodDescriptor.append(ClassConstants.INTERNAL_METHOD_ARGUMENTS_OPEN); 815 816 for (int index = 0; index < externalArguments.size(); index++) 817 { 818 internalMethodDescriptor.append(internalType((String)externalArguments.get(index))); 819 } 820 821 internalMethodDescriptor.append(ClassConstants.INTERNAL_METHOD_ARGUMENTS_CLOSE); 822 internalMethodDescriptor.append(internalType(externalReturnType)); 823 824 return internalMethodDescriptor.toString(); 825 } 826 827 828 /** 829 * Converts an internal field description into an external full field description. 830 * @param accessFlags the access flags of the field. 831 * @param fieldName the field name, 832 * e.g. "<code>myField</code>". 833 * @param internalFieldDescriptor the internal field descriptor, 834 * e.g. "<code>Z</code>". 835 * @return the external full field description, 836 * e.g. "<code>public boolean myField</code>". 837 */ externalFullFieldDescription(int accessFlags, String fieldName, String internalFieldDescriptor)838 public static String externalFullFieldDescription(int accessFlags, 839 String fieldName, 840 String internalFieldDescriptor) 841 { 842 return externalFieldAccessFlags(accessFlags) + 843 externalType(internalFieldDescriptor) + 844 ' ' + 845 fieldName; 846 } 847 848 849 /** 850 * Converts an internal method description into an external full method description. 851 * @param internalClassName the internal name of the class of the method, 852 * e.g. "<code>mypackage/MyClass</code>". 853 * @param accessFlags the access flags of the method. 854 * @param internalMethodName the internal method name, 855 * e.g. "<code>myMethod</code>" or 856 * "<code><init></code>". 857 * @param internalMethodDescriptor the internal method descriptor, 858 * e.g. "<code>(II)Z</code>". 859 * @return the external full method description, 860 * e.g. "<code>public boolean myMethod(int,int)</code>" or 861 * "<code>public MyClass(int,int)</code>". 862 */ externalFullMethodDescription(String internalClassName, int accessFlags, String internalMethodName, String internalMethodDescriptor)863 public static String externalFullMethodDescription(String internalClassName, 864 int accessFlags, 865 String internalMethodName, 866 String internalMethodDescriptor) 867 { 868 return externalMethodAccessFlags(accessFlags) + 869 externalMethodReturnTypeAndName(internalClassName, 870 internalMethodName, 871 internalMethodDescriptor) + 872 ClassConstants.EXTERNAL_METHOD_ARGUMENTS_OPEN + 873 externalMethodArguments(internalMethodDescriptor) + 874 ClassConstants.EXTERNAL_METHOD_ARGUMENTS_CLOSE; 875 } 876 877 878 /** 879 * Converts internal class access flags into an external access description. 880 * @param accessFlags the class access flags. 881 * @return the external class access description, 882 * e.g. "<code>public final </code>". 883 */ externalClassAccessFlags(int accessFlags)884 public static String externalClassAccessFlags(int accessFlags) 885 { 886 return externalClassAccessFlags(accessFlags, ""); 887 } 888 889 890 /** 891 * Converts internal class access flags into an external access description. 892 * @param accessFlags the class access flags. 893 * @param prefix a prefix that is added to each access modifier. 894 * @return the external class access description, 895 * e.g. "<code>public final </code>". 896 */ externalClassAccessFlags(int accessFlags, String prefix)897 public static String externalClassAccessFlags(int accessFlags, String prefix) 898 { 899 if (accessFlags == 0) 900 { 901 return EMPTY_STRING; 902 } 903 904 StringBuffer string = new StringBuffer(50); 905 906 if ((accessFlags & ClassConstants.INTERNAL_ACC_PUBLIC) != 0) 907 { 908 string.append(prefix).append(ClassConstants.EXTERNAL_ACC_PUBLIC).append(' '); 909 } 910 if ((accessFlags & ClassConstants.INTERNAL_ACC_PRIVATE) != 0) 911 { 912 // Only in InnerClasses attributes. 913 string.append(prefix).append(ClassConstants.EXTERNAL_ACC_PRIVATE).append(' '); 914 } 915 if ((accessFlags & ClassConstants.INTERNAL_ACC_PROTECTED) != 0) 916 { 917 // Only in InnerClasses attributes. 918 string.append(prefix).append(ClassConstants.EXTERNAL_ACC_PROTECTED).append(' '); 919 } 920 if ((accessFlags & ClassConstants.INTERNAL_ACC_STATIC) != 0) 921 { 922 // Only in InnerClasses attributes. 923 string.append(prefix).append(ClassConstants.EXTERNAL_ACC_STATIC).append(' '); 924 } 925 if ((accessFlags & ClassConstants.INTERNAL_ACC_FINAL) != 0) 926 { 927 string.append(prefix).append(ClassConstants.EXTERNAL_ACC_FINAL).append(' '); 928 } 929 if ((accessFlags & ClassConstants.INTERNAL_ACC_ANNOTATTION) != 0) 930 { 931 string.append(prefix).append(ClassConstants.EXTERNAL_ACC_ANNOTATION); 932 } 933 if ((accessFlags & ClassConstants.INTERNAL_ACC_INTERFACE) != 0) 934 { 935 string.append(prefix).append(ClassConstants.EXTERNAL_ACC_INTERFACE).append(' '); 936 } 937 else if ((accessFlags & ClassConstants.INTERNAL_ACC_ENUM) != 0) 938 { 939 string.append(prefix).append(ClassConstants.EXTERNAL_ACC_ENUM).append(' '); 940 } 941 else if ((accessFlags & ClassConstants.INTERNAL_ACC_ABSTRACT) != 0) 942 { 943 string.append(prefix).append(ClassConstants.EXTERNAL_ACC_ABSTRACT).append(' '); 944 } 945 else if ((accessFlags & ClassConstants.INTERNAL_ACC_SYNTHETIC) != 0) 946 { 947 string.append(prefix).append(ClassConstants.EXTERNAL_ACC_SYNTHETIC).append(' '); 948 } 949 950 return string.toString(); 951 } 952 953 954 /** 955 * Converts internal field access flags into an external access description. 956 * @param accessFlags the field access flags. 957 * @return the external field access description, 958 * e.g. "<code>public volatile </code>". 959 */ externalFieldAccessFlags(int accessFlags)960 public static String externalFieldAccessFlags(int accessFlags) 961 { 962 return externalFieldAccessFlags(accessFlags, ""); 963 } 964 965 966 /** 967 * Converts internal field access flags into an external access description. 968 * @param accessFlags the field access flags. 969 * @param prefix a prefix that is added to each access modifier. 970 * @return the external field access description, 971 * e.g. "<code>public volatile </code>". 972 */ externalFieldAccessFlags(int accessFlags, String prefix)973 public static String externalFieldAccessFlags(int accessFlags, String prefix) 974 { 975 if (accessFlags == 0) 976 { 977 return EMPTY_STRING; 978 } 979 980 StringBuffer string = new StringBuffer(50); 981 982 if ((accessFlags & ClassConstants.INTERNAL_ACC_PUBLIC) != 0) 983 { 984 string.append(prefix).append(ClassConstants.EXTERNAL_ACC_PUBLIC).append(' '); 985 } 986 if ((accessFlags & ClassConstants.INTERNAL_ACC_PRIVATE) != 0) 987 { 988 string.append(prefix).append(ClassConstants.EXTERNAL_ACC_PRIVATE).append(' '); 989 } 990 if ((accessFlags & ClassConstants.INTERNAL_ACC_PROTECTED) != 0) 991 { 992 string.append(prefix).append(ClassConstants.EXTERNAL_ACC_PROTECTED).append(' '); 993 } 994 if ((accessFlags & ClassConstants.INTERNAL_ACC_STATIC) != 0) 995 { 996 string.append(prefix).append(ClassConstants.EXTERNAL_ACC_STATIC).append(' '); 997 } 998 if ((accessFlags & ClassConstants.INTERNAL_ACC_FINAL) != 0) 999 { 1000 string.append(prefix).append(ClassConstants.EXTERNAL_ACC_FINAL).append(' '); 1001 } 1002 if ((accessFlags & ClassConstants.INTERNAL_ACC_VOLATILE) != 0) 1003 { 1004 string.append(prefix).append(ClassConstants.EXTERNAL_ACC_VOLATILE).append(' '); 1005 } 1006 if ((accessFlags & ClassConstants.INTERNAL_ACC_TRANSIENT) != 0) 1007 { 1008 string.append(prefix).append(ClassConstants.EXTERNAL_ACC_TRANSIENT).append(' '); 1009 } 1010 if ((accessFlags & ClassConstants.INTERNAL_ACC_SYNTHETIC) != 0) 1011 { 1012 string.append(prefix).append(ClassConstants.EXTERNAL_ACC_SYNTHETIC).append(' '); 1013 } 1014 1015 return string.toString(); 1016 } 1017 1018 1019 /** 1020 * Converts internal method access flags into an external access description. 1021 * @param accessFlags the method access flags. 1022 * @return the external method access description, 1023 * e.g. "<code>public synchronized </code>". 1024 */ externalMethodAccessFlags(int accessFlags)1025 public static String externalMethodAccessFlags(int accessFlags) 1026 { 1027 return externalMethodAccessFlags(accessFlags, ""); 1028 } 1029 1030 1031 /** 1032 * Converts internal method access flags into an external access description. 1033 * @param accessFlags the method access flags. 1034 * @param prefix a prefix that is added to each access modifier. 1035 * @return the external method access description, 1036 * e.g. "public synchronized ". 1037 */ externalMethodAccessFlags(int accessFlags, String prefix)1038 public static String externalMethodAccessFlags(int accessFlags, String prefix) 1039 { 1040 if (accessFlags == 0) 1041 { 1042 return EMPTY_STRING; 1043 } 1044 1045 StringBuffer string = new StringBuffer(50); 1046 1047 if ((accessFlags & ClassConstants.INTERNAL_ACC_PUBLIC) != 0) 1048 { 1049 string.append(prefix).append(ClassConstants.EXTERNAL_ACC_PUBLIC).append(' '); 1050 } 1051 if ((accessFlags & ClassConstants.INTERNAL_ACC_PRIVATE) != 0) 1052 { 1053 string.append(prefix).append(ClassConstants.EXTERNAL_ACC_PRIVATE).append(' '); 1054 } 1055 if ((accessFlags & ClassConstants.INTERNAL_ACC_PROTECTED) != 0) 1056 { 1057 string.append(prefix).append(ClassConstants.EXTERNAL_ACC_PROTECTED).append(' '); 1058 } 1059 if ((accessFlags & ClassConstants.INTERNAL_ACC_STATIC) != 0) 1060 { 1061 string.append(prefix).append(ClassConstants.EXTERNAL_ACC_STATIC).append(' '); 1062 } 1063 if ((accessFlags & ClassConstants.INTERNAL_ACC_FINAL) != 0) 1064 { 1065 string.append(prefix).append(ClassConstants.EXTERNAL_ACC_FINAL).append(' '); 1066 } 1067 if ((accessFlags & ClassConstants.INTERNAL_ACC_SYNCHRONIZED) != 0) 1068 { 1069 string.append(prefix).append(ClassConstants.EXTERNAL_ACC_SYNCHRONIZED).append(' '); 1070 } 1071 if ((accessFlags & ClassConstants.INTERNAL_ACC_BRIDGE) != 0) 1072 { 1073 string.append(prefix).append(ClassConstants.EXTERNAL_ACC_BRIDGE).append(' '); 1074 } 1075 if ((accessFlags & ClassConstants.INTERNAL_ACC_VARARGS) != 0) 1076 { 1077 string.append(prefix).append(ClassConstants.EXTERNAL_ACC_VARARGS).append(' '); 1078 } 1079 if ((accessFlags & ClassConstants.INTERNAL_ACC_NATIVE) != 0) 1080 { 1081 string.append(prefix).append(ClassConstants.EXTERNAL_ACC_NATIVE).append(' '); 1082 } 1083 if ((accessFlags & ClassConstants.INTERNAL_ACC_ABSTRACT) != 0) 1084 { 1085 string.append(prefix).append(ClassConstants.EXTERNAL_ACC_ABSTRACT).append(' '); 1086 } 1087 if ((accessFlags & ClassConstants.INTERNAL_ACC_STRICT) != 0) 1088 { 1089 string.append(prefix).append(ClassConstants.EXTERNAL_ACC_STRICT).append(' '); 1090 } 1091 if ((accessFlags & ClassConstants.INTERNAL_ACC_SYNTHETIC) != 0) 1092 { 1093 string.append(prefix).append(ClassConstants.EXTERNAL_ACC_SYNTHETIC).append(' '); 1094 } 1095 1096 return string.toString(); 1097 } 1098 1099 1100 /** 1101 * Converts an internal method descriptor into an external method return type. 1102 * @param internalMethodDescriptor the internal method descriptor, 1103 * e.g. "<code>(II)Z</code>". 1104 * @return the external method return type, 1105 * e.g. "<code>boolean</code>". 1106 */ externalMethodReturnType(String internalMethodDescriptor)1107 public static String externalMethodReturnType(String internalMethodDescriptor) 1108 { 1109 return externalType(internalMethodReturnType(internalMethodDescriptor)); 1110 } 1111 1112 1113 /** 1114 * Converts an internal class name, method name, and method descriptor to 1115 * an external method return type and name. 1116 * @param internalClassName the internal name of the class of the method, 1117 * e.g. "<code>mypackage/MyClass</code>". 1118 * @param internalMethodName the internal method name, 1119 * e.g. "<code>myMethod</code>" or 1120 * "<code><init></code>". 1121 * @param internalMethodDescriptor the internal method descriptor, 1122 * e.g. "<code>(II)Z</code>". 1123 * @return the external method return type and name, 1124 * e.g. "<code>boolean myMethod</code>" or 1125 * "<code>MyClass</code>". 1126 */ externalMethodReturnTypeAndName(String internalClassName, String internalMethodName, String internalMethodDescriptor)1127 private static String externalMethodReturnTypeAndName(String internalClassName, 1128 String internalMethodName, 1129 String internalMethodDescriptor) 1130 { 1131 return internalMethodName.equals(ClassConstants.INTERNAL_METHOD_NAME_INIT) ? 1132 externalShortClassName(externalClassName(internalClassName)) : 1133 (externalMethodReturnType(internalMethodDescriptor) + 1134 ' ' + 1135 internalMethodName); 1136 } 1137 1138 1139 /** 1140 * Converts an internal method descriptor into an external method argument 1141 * description. 1142 * @param internalMethodDescriptor the internal method descriptor, 1143 * e.g. "<code>(II)Z</code>". 1144 * @return the external method argument description, 1145 * e.g. "<code>int,int</code>". 1146 */ externalMethodArguments(String internalMethodDescriptor)1147 public static String externalMethodArguments(String internalMethodDescriptor) 1148 { 1149 StringBuffer externalMethodNameAndArguments = new StringBuffer(); 1150 1151 InternalTypeEnumeration internalTypeEnumeration = 1152 new InternalTypeEnumeration(internalMethodDescriptor); 1153 1154 while (internalTypeEnumeration.hasMoreTypes()) 1155 { 1156 externalMethodNameAndArguments.append(externalType(internalTypeEnumeration.nextType())); 1157 if (internalTypeEnumeration.hasMoreTypes()) 1158 { 1159 externalMethodNameAndArguments.append(ClassConstants.EXTERNAL_METHOD_ARGUMENTS_SEPARATOR); 1160 } 1161 } 1162 1163 return externalMethodNameAndArguments.toString(); 1164 } 1165 1166 1167 /** 1168 * Returns the internal package name of the given internal class name. 1169 * @param internalClassName the internal class name, 1170 * e.g. "<code>java/lang/Object</code>". 1171 * @return the internal package name, 1172 * e.g. "<code>java/lang</code>". 1173 */ internalPackageName(String internalClassName)1174 public static String internalPackageName(String internalClassName) 1175 { 1176 String internalPackagePrefix = internalPackagePrefix(internalClassName); 1177 int length = internalPackagePrefix.length(); 1178 return length > 0 ? 1179 internalPackagePrefix.substring(0, length - 1) : 1180 ""; 1181 } 1182 1183 1184 /** 1185 * Returns the internal package prefix of the given internal class name. 1186 * @param internalClassName the internal class name, 1187 * e.g. "<code>java/lang/Object</code>". 1188 * @return the internal package prefix, 1189 * e.g. "<code>java/lang/</code>". 1190 */ internalPackagePrefix(String internalClassName)1191 public static String internalPackagePrefix(String internalClassName) 1192 { 1193 return internalClassName.substring(0, internalClassName.lastIndexOf(ClassConstants.INTERNAL_PACKAGE_SEPARATOR, 1194 internalClassName.length() - 2) + 1); 1195 } 1196 1197 1198 /** 1199 * Returns the external package name of the given external class name. 1200 * @param externalClassName the external class name, 1201 * e.g. "<code>java.lang.Object</code>". 1202 * @return the external package name, 1203 * e.g. "<code>java.lang</code>". 1204 */ externalPackageName(String externalClassName)1205 public static String externalPackageName(String externalClassName) 1206 { 1207 String externalPackagePrefix = externalPackagePrefix(externalClassName); 1208 int length = externalPackagePrefix.length(); 1209 return length > 0 ? 1210 externalPackagePrefix.substring(0, length - 1) : 1211 ""; 1212 } 1213 1214 1215 /** 1216 * Returns the external package prefix of the given external class name. 1217 * @param externalClassName the external class name, 1218 * e.g. "<code>java.lang.Object</code>". 1219 * @return the external package prefix, 1220 * e.g. "<code>java.lang.</code>". 1221 */ externalPackagePrefix(String externalClassName)1222 public static String externalPackagePrefix(String externalClassName) 1223 { 1224 return externalClassName.substring(0, externalClassName.lastIndexOf(ClassConstants.EXTERNAL_PACKAGE_SEPARATOR, 1225 externalClassName.length() - 2) + 1); 1226 } 1227 } 1228