1 7 8 package org.gjt.jclasslib.structures; 9 10 import org.gjt.jclasslib.io.Log; 11 import org.gjt.jclasslib.structures.constants.ConstantLargeNumeric; 12 import org.gjt.jclasslib.structures.constants.ConstantUtf8Info; 13 14 import java.io.*; 15 import java.util.HashMap ; 16 17 23 public class ClassFile extends AbstractStructureWithAttributes { 24 25 30 public static final String SYSTEM_PROPERTY_SKIP_CONSTANT_POOL = "jclasslib.io.skipConstantPool"; 31 32 private static final int MAGIC_NUMBER = 0xcafebabe; 33 34 private final boolean skipConstantPool; 35 36 private int minorVersion; 37 private int majorVersion; 38 private CPInfo[] constantPool; 39 private HashMap constantPoolEntryToIndex = new HashMap (); 40 private int accessFlags; 41 private int thisClass; 42 private int superClass; 43 private int[] interfaces; 44 private FieldInfo[] fields; 45 private MethodInfo[] methods; 46 47 48 51 public ClassFile() { 52 skipConstantPool = Boolean.getBoolean(SYSTEM_PROPERTY_SKIP_CONSTANT_POOL); 53 setClassFile(this); 54 } 55 56 61 public int getMinorVersion() { 62 return minorVersion; 63 } 64 65 70 public void setMinorVersion(int minorVersion) { 71 this.minorVersion = minorVersion; 72 } 73 74 79 public int getMajorVersion() { 80 return majorVersion; 81 } 82 83 88 public void setMajorVersion(int majorVersion) { 89 this.majorVersion = majorVersion; 90 } 91 92 97 public CPInfo[] getConstantPool() { 98 return constantPool; 99 } 100 101 107 public int getConstantPoolIndex(CPInfo cpInfo) { 108 Integer index = (Integer )constantPoolEntryToIndex.get(cpInfo); 109 if (index != null) { 110 return index.intValue(); 111 } else { 112 return -1; 113 } 114 } 115 116 123 public void setConstantPool(CPInfo[] constantPool) { 124 this.constantPool = constantPool; 125 for (int i = 0; i < constantPool.length; i++) { 126 constantPoolEntryToIndex.put(constantPool[i], new Integer (i)); 127 } 128 } 129 130 137 public void enlargeConstantPool(CPInfo[] enlargedConstantPool) { 138 int startIndex = constantPool == null ? 0 : constantPool.length; 139 this.constantPool = enlargedConstantPool; 140 for (int i = startIndex; i < constantPool.length; i++) { 141 if (constantPool[i] != null) { 142 constantPoolEntryToIndex.put(constantPool[i], new Integer (i)); 143 } 144 } 145 } 146 147 153 public void registerConstantPoolEntry(int index) { 154 constantPoolEntryToIndex.put(constantPool[index], new Integer (index)); 155 } 156 157 163 public void unregisterConstantPoolEntry(int index) { 164 constantPoolEntryToIndex.remove(constantPool[index]); 165 } 166 167 172 public int getAccessFlags() { 173 return accessFlags; 174 } 175 176 181 public void setAccessFlags(int accessFlags) { 182 this.accessFlags = accessFlags; 183 } 184 185 190 public int getThisClass() { 191 return thisClass; 192 } 193 194 199 public void setThisClass(int thisClass) { 200 this.thisClass = thisClass; 201 } 202 203 209 public String getThisClassName() throws InvalidByteCodeException { 210 return getConstantPoolEntryName(getThisClass()); 211 } 212 213 218 public int getSuperClass() { 219 return superClass; 220 } 221 222 227 public void setSuperClass(int superClass) { 228 this.superClass = superClass; 229 } 230 231 237 public String getSuperClassName() throws InvalidByteCodeException { 238 return getConstantPoolEntryName(getSuperClass()); 239 } 240 241 246 public int[] getInterfaces() { 247 return interfaces; 248 } 249 250 255 public void setInterfaces(int[] interfaces) { 256 this.interfaces = interfaces; 257 } 258 259 264 public FieldInfo[] getFields() { 265 return fields; 266 } 267 268 273 public void setFields(FieldInfo[] fields) { 274 this.fields = fields; 275 } 276 277 282 public MethodInfo[] getMethods() { 283 return methods; 284 } 285 286 291 public void setMethods(MethodInfo[] methods) { 292 this.methods = methods; 293 } 294 295 300 public String getFormattedAccessFlags() { 301 return printAccessFlags(accessFlags); 302 } 303 304 309 public String getAccessFlagsVerbose() { 310 return printAccessFlagsVerbose(accessFlags); 311 } 312 313 320 public ConstantUtf8Info getConstantPoolUtf8Entry(int index) 321 throws InvalidByteCodeException { 322 323 return (ConstantUtf8Info)getConstantPoolEntry(index, ConstantUtf8Info.class); 324 } 325 326 334 public CPInfo getConstantPoolEntry(int index, Class entryClass) 335 throws InvalidByteCodeException { 336 337 if (!checkValidConstantPoolIndex(index)) { 338 return null; 339 } 340 341 CPInfo cpInfo = constantPool[index]; 342 343 if (cpInfo == null) { 344 return null; 345 } 346 347 if (entryClass.isAssignableFrom(cpInfo.getClass())) { 348 return cpInfo; 349 } else { 350 throw new InvalidByteCodeException("constant pool entry at " + index + 351 " is not assignable to " + 352 entryClass.getName()); 353 } 354 } 355 356 364 public String getConstantPoolEntryName(int index) 365 throws InvalidByteCodeException { 366 367 if (!checkValidConstantPoolIndex(index)) { 368 return null; 369 } 370 371 CPInfo cpInfo = constantPool[index]; 372 if (cpInfo == null) { 373 return "invalid constant pool index"; 374 } else { 375 return cpInfo.getVerbose(); 376 } 377 } 378 379 387 public int getFieldIndex(String name, String descriptor) throws InvalidByteCodeException { 388 389 for (int i = 0; i < fields.length; i++) { 390 FieldInfo field = fields[i]; 391 if (field.getName().equals(name) && field.getDescriptor().equals(descriptor)) { 392 return i; 393 } 394 } 395 return -1; 396 } 397 398 406 public FieldInfo getField(String name, String descriptor) throws InvalidByteCodeException { 407 408 int index = getFieldIndex(name, descriptor); 409 if (index < 0) { 410 return null; 411 } else { 412 return fields[index]; 413 } 414 } 415 416 424 public int getMethodIndex(String name, String descriptor) throws InvalidByteCodeException { 425 426 for (int i = 0; i < methods.length; i++) { 427 MethodInfo method = methods[i]; 428 if (method.getName().equals(name) && method.getDescriptor().equals(descriptor)) { 429 return i; 430 } 431 } 432 return -1; 433 } 434 435 443 public MethodInfo getMethod(String name, String descriptor) throws InvalidByteCodeException { 444 445 int index = getMethodIndex(name, descriptor); 446 if (index < 0) { 447 return null; 448 } else { 449 return methods[index]; 450 } 451 } 452 453 public void read(DataInput in) 454 throws InvalidByteCodeException, IOException { 455 456 readMagicNumber(in); 457 readVersion(in); 458 readConstantPool(in); 459 readAccessFlags(in); 460 readThisClass(in); 461 readSuperClass(in); 462 readInterfaces(in); 463 readFields(in); 464 readMethods(in); 465 readAttributes(in); 466 } 467 468 public void write(DataOutput in) 469 throws InvalidByteCodeException, IOException { 470 471 writeMagicNumber(in); 472 writeVersion(in); 473 writeConstantPool(in); 474 writeAccessFlags(in); 475 writeThisClass(in); 476 writeSuperClass(in); 477 writeInterfaces(in); 478 writeFields(in); 479 writeMethods(in); 480 writeAttributes(in); 481 482 } 483 484 private boolean checkValidConstantPoolIndex(int index) { 485 486 if (index < 1 || index >= constantPool.length) { 487 return false; 488 } 489 return true; 490 491 } 492 493 private void readMagicNumber(DataInput in) 494 throws InvalidByteCodeException, IOException { 495 496 int magicNumber = in.readInt(); 497 if (magicNumber != MAGIC_NUMBER) { 498 throw new InvalidByteCodeException("Invalid magic number 0x" + 499 Integer.toHexString(magicNumber) + 500 " instead of 0x" + 501 Integer.toHexString(MAGIC_NUMBER)); 502 } 503 504 if (debug) debug("read magic number"); 505 } 506 507 private void writeMagicNumber(DataOutput out) throws IOException { 508 509 out.writeInt(MAGIC_NUMBER); 510 if (debug) debug("wrote magic number"); 511 } 512 513 private void readVersion(DataInput in) throws IOException { 514 515 minorVersion = in.readUnsignedShort(); 516 if (debug) debug("read minor version " + minorVersion); 517 518 majorVersion = in.readUnsignedShort(); 519 if (debug) debug("read major version " + majorVersion); 520 521 checkMajorVersion(majorVersion); 522 } 523 524 private void writeVersion(DataOutput out) throws IOException { 525 526 out.writeShort(minorVersion); 527 if (debug) debug("wrote minor version " + minorVersion); 528 529 out.writeShort(majorVersion); 530 if (debug) debug("wrote major version " + majorVersion); 531 532 checkMajorVersion(majorVersion); 533 } 534 535 private void readConstantPool(DataInput in) 536 throws InvalidByteCodeException, IOException { 537 538 constantPoolEntryToIndex.clear(); 539 int constantPoolCount = in.readUnsignedShort(); 540 if (debug) debug("read constant pool count " + constantPoolCount); 541 542 constantPool = new CPInfo[constantPoolCount]; 543 544 for (int i = 1; i < constantPoolCount; i++) { 547 if (skipConstantPool) { 548 i += CPInfo.skip(in); 550 } else { 551 if (debug) debug("reading constant pool entry " + i); 554 constantPool[i] = CPInfo.create(in, this); 555 constantPoolEntryToIndex.put(constantPool[i], new Integer (i)); 556 if (constantPool[i] instanceof ConstantLargeNumeric) { 557 i++; 560 } 561 } 562 } 563 } 564 565 private void writeConstantPool(DataOutput out) 566 throws InvalidByteCodeException, IOException { 567 568 int lastFreeIndex; 569 for (lastFreeIndex = getLength(constantPool) - 1; 570 lastFreeIndex >= 0 && constantPool[lastFreeIndex] == null; 571 lastFreeIndex--) { 572 } 573 574 out.writeShort(lastFreeIndex + 1); 575 if (debug) debug("wrote constant pool count " + (lastFreeIndex + 1)); 576 577 for (int i = 1; i <= lastFreeIndex; i++) { 579 if (constantPool[i] == null) { 580 throw new InvalidByteCodeException("constant pool entry " + i + " is null"); 581 } 582 if (debug) debug("writing constant pool entry " + i); 583 constantPool[i].write(out); 584 if (constantPool[i] instanceof ConstantLargeNumeric) { 585 i++; 588 } 589 } 590 } 591 592 private void readAccessFlags(DataInput in) throws IOException { 593 594 accessFlags = in.readUnsignedShort(); 595 if (debug) debug("read access flags " + printAccessFlags(accessFlags)); 596 } 597 598 private void writeAccessFlags(DataOutput out) throws IOException { 599 600 out.writeShort(accessFlags); 601 if (debug) debug("wrote access flags " + printAccessFlags(accessFlags)); 602 } 603 604 private void readThisClass(DataInput in) throws IOException { 605 606 thisClass = in.readUnsignedShort(); 607 if (debug) debug("read this_class index " + thisClass); 608 } 609 610 private void writeThisClass(DataOutput out) throws IOException { 611 612 out.writeShort(thisClass); 613 if (debug) debug("wrote this_class index " + thisClass); 614 } 615 616 private void readSuperClass(DataInput in) throws IOException { 617 618 superClass = in.readUnsignedShort(); 619 if (debug) debug("read super_class index " + superClass); 620 } 621 622 private void writeSuperClass(DataOutput out) throws IOException { 623 624 out.writeShort(superClass); 625 if (debug) debug("wrote super_class index " + superClass); 626 } 627 628 private void readInterfaces(DataInput in) throws IOException { 629 630 int interfacesCount = in.readUnsignedShort(); 631 if (debug) debug("read interfaces count " + interfacesCount); 632 633 interfaces = new int[interfacesCount]; 634 635 for (int i = 0; i < interfacesCount; i++) { 636 interfaces[i] = in.readUnsignedShort(); 637 if (debug) debug("read interface index " + interfaces[i]); 638 } 639 640 } 641 642 private void writeInterfaces(DataOutput out) throws IOException { 643 644 int interfacesCount = getLength(interfaces); 645 646 out.writeShort(interfacesCount); 647 if (debug) debug("wrote interfaces count " + interfacesCount); 648 649 for (int i = 0; i < interfacesCount; i++) { 650 out.writeShort(interfaces[i]); 651 if (debug) debug("wrote interface index " + interfaces[i]); 652 } 653 654 } 655 656 private void readFields(DataInput in) 657 throws InvalidByteCodeException, IOException { 658 659 int fieldsCount = in.readUnsignedShort(); 660 if (debug) debug("read fields count " + fieldsCount); 661 662 fields = new FieldInfo[fieldsCount]; 663 664 for (int i = 0; i < fieldsCount; i++) { 665 fields[i] = FieldInfo.create(in, this); 666 } 667 668 } 669 670 private void writeFields(DataOutput out) 671 throws InvalidByteCodeException, IOException { 672 673 int fieldsCount = getLength(fields); 674 675 out.writeShort(fieldsCount); 676 if (debug) debug("wrote fields count " + fieldsCount); 677 678 for (int i = 0; i < fieldsCount; i++) { 679 if (fields[i] == null) { 680 throw new InvalidByteCodeException("field " + i + " is null"); 681 } 682 fields[i].write(out); 683 } 684 685 } 686 687 private void readMethods(DataInput in) 688 throws InvalidByteCodeException, IOException { 689 690 int methodsCount = in.readUnsignedShort(); 691 if (debug) debug("read methods count " + methodsCount); 692 693 methods = new MethodInfo[methodsCount]; 694 695 for (int i = 0; i < methodsCount; i++) { 696 methods[i] = MethodInfo.create(in, this); 697 } 698 699 } 700 701 private void writeMethods(DataOutput out) 702 throws InvalidByteCodeException, IOException { 703 704 int methodsCount = getLength(methods); 705 706 out.writeShort(methodsCount); 707 if (debug) debug("wrote methods count " + methodsCount); 708 709 for (int i = 0; i < methodsCount; i++) { 710 if (methods[i] == null) { 711 throw new InvalidByteCodeException("method " + i + " is null"); 712 } 713 methods[i].write(out); 714 } 715 716 } 717 718 protected void readAttributes(DataInput in) 719 throws InvalidByteCodeException, IOException { 720 721 super.readAttributes(in); 722 if (debug) debug("read " + getLength(attributes) + " attributes for the ClassFile structure"); 723 } 724 725 protected void writeAttributes(DataOutput out) 726 throws InvalidByteCodeException, IOException { 727 728 super.writeAttributes(out); 729 if (debug) debug("wrote " + getLength(attributes) + " attributes for the ClassFile structure"); 730 } 731 732 private void checkMajorVersion(int majorVersion) { 733 734 if (majorVersion < 45 || majorVersion > 49) { 735 Log.warning("major version should be between 45 and 49 for JDK <= 1.5"); 736 } 737 738 } 739 740 protected String printAccessFlagsVerbose(int accessFlags) { 741 return printAccessFlagsVerbose(AccessFlags.CLASS_ACCESS_FLAGS, AccessFlags.CLASS_ACCESS_FLAGS_VERBOSE, accessFlags); 742 } 743 } 744 | Popular Tags |