1 package alt.jiapi.file; 2 3 import java.io.ByteArrayInputStream ; 4 import java.io.ByteArrayOutputStream ; 5 import java.io.DataInputStream ; 6 import java.io.DataOutputStream ; 7 import java.io.FileInputStream ; 8 import java.io.InputStream ; 9 import java.io.IOException ; 10 import java.io.EOFException ; 11 12 import java.util.Iterator ; 13 import java.util.LinkedList ; 14 import java.util.List ; 15 16 21 public class ClassFile { 22 private static Configuration config = new Configuration(); 23 24 private ConstantPool constantPool; 25 private List interfaces = new LinkedList (); 26 private List fields = new LinkedList (); 27 private List methods = new LinkedList (); 28 private List attributes = new LinkedList (); 29 30 34 public static final int ACC_PUBLIC = 0x0001; 35 38 public static final int ACC_FINAL = 0x0010; 39 42 public static final int ACC_SUPER = 0x0020; 43 46 public static final int ACC_INTERFACE = 0x0200; 47 50 public static final int ACC_ABSTRACT = 0x0400; 51 52 private int magic_number; 56 private short minor_version; 57 private short major_version; 58 private short access_flags; 59 private short this_class; 60 private short super_class; 61 62 67 public static void main(String [] args) throws Exception { 68 ClassFile cf = ClassFile.parse(args[0]); 69 70 System.out.println(cf.getMagicNumber()); 71 System.out.println(cf.getMajorVersion() + " " + cf.getMinorVersion()); 72 System.out.println(cf.getAccessFlags()); 73 74 System.out.println(cf.getConstantPool()); 75 } 76 77 82 public ClassFile(String className) { 83 String name = className.replace('.', '/'); 84 this.magic_number = 0xcafebabe; 85 this.minor_version = 0; this.major_version = 46; this.access_flags = ACC_PUBLIC; 88 89 this.constantPool = new ConstantPool(); 90 this.this_class = constantPool.addClassInfo(name).getEntryIndex(); 91 this.super_class = constantPool.addClassInfo("java.lang.Object").getEntryIndex(); 92 93 this.interfaces = new LinkedList (); 94 this.methods = new LinkedList (); 95 this.fields = new LinkedList (); 96 this.attributes = new LinkedList (); 97 } 98 99 102 private ClassFile() { 103 } 104 105 106 117 public static ClassFile parse(String fileName) throws ParseException, IOException { 118 return parse(new FileInputStream (fileName)); 119 } 120 121 122 133 public static ClassFile parse(InputStream is) throws ParseException, IOException { 134 InputStream input = null; 135 136 141 if (config.getBoolean("alt.jiapi.file.use-ZipFileInputStream-bug-workaround")) { ByteArrayOutputStream bos = new 144 ByteArrayOutputStream (is.available()); 145 146 int i = 0; 147 while((i = is.read()) != -1) { 148 bos.write(i); 149 } 150 151 input = new ByteArrayInputStream (bos.toByteArray()); 152 } 153 else { 154 input = is; 155 } 156 157 158 159 DataInputStream dis = new DataInputStream (input); 160 ClassFile cf = null; 161 try { 162 cf = new ClassFile(); 163 cf.parseClassFile(dis); 164 165 if (dis.available() != 0) { 166 System.out.println(is.available() + ":::" + dis.available() + ":" + is); 167 System.out.println("" + dis.readByte()); 168 if (false) { 169 throw new ParseException("Could not fully read class file. " + dis.available() + " bytes remain to be read", cf); 173 } 174 } 175 } 176 catch(EOFException eof) { 177 System.out.println(">>Got EOFException: " + eof + ","+is.available()+ 179 ", " + cf.getClassName()); 180 } 181 catch(IOException ioe) { 182 System.out.println("Got IOException: " + ioe + "," +is.available()+ 183 ", " + cf.getClassName()); 184 throw new ParseException(ioe.getMessage(), cf); 185 } 186 finally { 187 dis.close(); 188 } 189 190 return cf; 191 } 192 193 194 199 public List getAttributes() { 200 return attributes; 201 } 202 203 204 209 public ConstantPool getConstantPool() { 210 return constantPool; 211 } 212 213 214 220 public void addInterface(String name) { 221 String iType = name.replace('.', '/'); 222 short nameIndex = constantPool.addUtf8Info(iType).getEntryIndex(); 223 224 short cInfo = constantPool.addClassInfo(nameIndex); 226 227 interfaces.add(new Interface(constantPool, cInfo)); 228 } 229 230 231 232 237 public int getMagicNumber() { 238 return magic_number; } 240 241 246 public short getMinorVersion() { 247 return minor_version; } 249 250 255 public short getMajorVersion() { 256 return major_version; } 258 259 264 public List getFields() { 265 return fields; 266 } 267 268 273 public List getInterfaces() { 274 return interfaces; 275 } 276 277 282 public List getMethods() { 283 return methods; 284 } 285 286 287 292 public String getClassName() { 293 return constantPool.getClassName(this_class); 294 } 295 296 303 public String getSuperclassName() { 304 if (super_class != 0) { 305 return constantPool.getClassName(super_class); 306 } 307 308 return null; 309 } 310 311 312 322 public short getAccessFlags() { 323 return access_flags; } 325 326 public void setAccessFlags(short access_flags) { 327 this.access_flags = access_flags; 328 } 329 330 331 339 public short getSuperClassIndex() { 340 return super_class; 341 } 342 343 349 public short getThisClassIndex() { 350 return this_class; 351 } 352 353 354 361 public byte[] toBytes() { 362 ByteArrayOutputStream baos = new ByteArrayOutputStream (); 363 DataOutputStream dos = new DataOutputStream (baos); 364 try { 365 dos.writeInt(magic_number); 366 dos.writeShort(minor_version); 367 dos.writeShort(major_version); 368 369 writeConstantPool(dos); 370 371 dos.writeShort(access_flags); 372 dos.writeShort(this_class); 373 dos.writeShort(super_class); 374 375 writeInterfaces(dos); 376 writeFields(dos); 377 writeMethods(dos); 378 379 writeAttributes(dos, attributes); 380 } 381 catch(IOException ioe) { 382 throw new ParseException(ioe.getMessage(), this); } 384 385 return baos.toByteArray(); 386 } 387 388 389 private void parseClassFile(DataInputStream dis) throws ParseException, IOException { 390 this.magic_number = dis.readInt(); 391 this.minor_version = dis.readShort(); this.major_version = dis.readShort(); 394 400 parseConstantPool(dis); 401 402 this.access_flags = dis.readShort(); 404 this.this_class = dis.readShort(); 405 this.super_class = dis.readShort(); 406 407 411 readInterfaces(dis); 412 readFields(dis); 413 readMethods(dis); 414 415 this.attributes = readAttributes(dis); 416 } 417 418 419 void addInterface(short constantClassIndex) { 420 interfaces.add(new Interface(constantPool, constantClassIndex)); 421 } 422 423 void addField(short access_flags, short name_index, 424 short descriptor_index, List attributes) { 425 fields.add(new Field(constantPool, access_flags, name_index, 426 descriptor_index, attributes)); 427 } 428 429 void addMethod(short access_flags, short name_index, 430 short descriptor_index, List attributes) { 431 methods.add(new Method(constantPool, access_flags, name_index, 432 descriptor_index, attributes)); 433 } 434 435 436 private void readInterfaces(DataInputStream dis) throws IOException { 437 short iCount = dis.readShort(); 438 Interface[] interfaces = new Interface[iCount]; 439 440 for (int i = 0; i < iCount; i++) { 442 short constantClassIndex = dis.readShort(); 443 addInterface(constantClassIndex); 444 } 445 } 446 447 private void readFields(DataInputStream dis) throws IOException { 448 short fCount = dis.readShort(); 449 Field[] fields = new Field[fCount]; 450 451 for (int i = 0; i < fCount; i++) { 452 short access_flags = dis.readShort(); 453 short name_index = dis.readShort(); 454 short descriptor_index = dis.readShort(); 455 456 List attributes = readAttributes(dis); 457 458 addField(access_flags, name_index, descriptor_index, attributes); 459 } 460 } 461 462 463 private void readMethods(DataInputStream dis) throws IOException { 464 short mCount = dis.readShort(); 465 Method[] methods = new Method[mCount]; 466 467 for (int i = 0; i < mCount; i++) { 468 short access_flags = dis.readShort(); 469 short name_index = dis.readShort(); 470 short descriptor_index = dis.readShort(); 471 472 List attributes = readAttributes(dis); 473 474 addMethod(access_flags, name_index, descriptor_index, attributes); 475 } 476 } 477 478 479 482 List readAttributes(DataInputStream dis) throws IOException { 483 short attr_count = dis.readShort(); 484 LinkedList attrs = new LinkedList (); 485 486 for (int i = 0; i < attr_count; i++) { 488 short attribute_name_index = dis.readShort(); 489 int attribute_length = dis.readInt(); 490 491 String attrName = getUtf8(attribute_name_index); 492 Attribute a = null; 493 494 if ("Code".equals(attrName)) { 495 a = new CodeAttribute(constantPool, attribute_name_index, dis); 496 } 497 else if ("Exceptions".equals(attrName)) { 498 a = new ExceptionsAttribute(attribute_name_index, dis); 499 } 500 else if ("ConstantValue".equals(attrName)) { 501 a = new ConstantValueAttribute(attribute_name_index, dis); 502 } 503 else if ("InnerClasses".equals(attrName)) { 504 a = new InnerClassesAttribute(attribute_name_index, dis); 505 } 506 else if ("Synthetic".equals(attrName)) { 507 a = new SyntheticAttribute(attribute_name_index, dis); 508 } 509 else if ("SourceFile".equals(attrName)) { 510 a = new SourceFileAttribute(attribute_name_index, dis); 511 } 512 else if ("Deprecated".equals(attrName)) { 513 a = new DeprecatedAttribute(attribute_name_index, dis); 514 } 515 else { 516 a = new Attribute(attribute_name_index, attribute_length, dis); 518 } 519 520 a.setConstantPool(constantPool); 521 522 attrs.add(a); 523 } 524 525 return attrs; 526 } 527 528 529 530 private void parseConstantPool(DataInputStream dis) throws IOException { 531 short constantPoolCount = dis.readShort(); 532 constantPool = new ConstantPool(constantPoolCount - 1); 533 534 for (int i = 0; i < constantPoolCount - 1; i++) { 535 byte tag = dis.readByte(); 536 537 switch(tag) { 538 case ConstantPool.CONSTANT_Class: 539 constantPool.addClassInfo(dis.readShort()); 540 break; 541 case ConstantPool.CONSTANT_Fieldref: 542 constantPool.addFieldRefInfo(dis.readShort(), dis.readShort()); 543 break; 544 case ConstantPool.CONSTANT_Methodref: 545 constantPool.addMethodRefInfo(dis.readShort(),dis.readShort()); 546 break; 547 case ConstantPool.CONSTANT_InterfaceMethodref: 548 constantPool.addInterfaceMethodRefInfo(dis.readShort(), 549 dis.readShort()); 550 break; 551 case ConstantPool.CONSTANT_String: 552 constantPool.addString_info(dis.readShort()); 553 break; 554 case ConstantPool.CONSTANT_Integer: 555 constantPool.addInteger_info(dis.readInt()); 556 break; 557 case ConstantPool.CONSTANT_Float: 558 constantPool.addFloat_info(dis.readInt()); 559 break; 560 case ConstantPool.CONSTANT_Long: 561 constantPool.addLong_info(dis.readInt(), dis.readInt()); 562 i++; break; 564 case ConstantPool.CONSTANT_Double: 565 constantPool.addDouble_info(dis.readInt(), dis.readInt()); 566 i++; break; 568 case ConstantPool.CONSTANT_NameAndType: 569 575 constantPool.addNameAndTypeInfo(dis.readShort(), 576 dis.readShort()); 577 break; 578 case ConstantPool.CONSTANT_Utf8: 579 short length = dis.readShort(); 580 byte[] byteArray = new byte[length]; 581 for(int j = 0; j < byteArray.length; j++) { 582 byteArray[j] = dis.readByte(); 583 if (byteArray[j] == 0 || byteArray[j] >= 0xf0) { 584 System.out.println(" " + Integer.toHexString(byteArray[j])); 586 } 587 } 588 589 constantPool.addUtf8_info(byteArray); 590 break; 591 default: 592 throw new ParseException(constantPool + 593 "\nInvalid constant pool tag: " +tag, 594 this); 595 } 596 } 597 } 598 599 600 private void writeConstantPool(DataOutputStream dos) throws IOException { 601 List cp = constantPool.getList(); 602 603 dos.writeShort(cp.size() + 1); 605 Iterator i = cp.iterator(); 606 while(i.hasNext()) { 607 ConstantPool.Entry e = (ConstantPool.Entry)i.next(); 608 609 if (e instanceof ConstantPool.NullEntry) { 610 continue; 611 } 612 613 if (e.getTag() == 0) { 614 System.out.println("ERROR: invalid constant pool tag: 0"); 615 } 616 617 dos.writeByte(e.getTag()); 618 e.writeData(dos); 619 } 620 } 621 622 private void writeInterfaces(DataOutputStream dos) throws IOException { 623 dos.writeShort(interfaces.size()); 624 625 Iterator i = interfaces.iterator(); 626 while(i.hasNext()) { 627 Interface iFace = (Interface)i.next(); 628 dos.writeShort(iFace.getConstantClassIndex()); 630 } 631 } 632 633 private void writeFields(DataOutputStream dos) throws IOException { 634 dos.writeShort(fields.size()); 636 Iterator i = fields.iterator(); 637 while(i.hasNext()) { 638 Field f = (Field)i.next(); 639 dos.writeShort(f.getAccessFlags()); 641 dos.writeShort(f.getNameIndex()); 642 dos.writeShort(f.getDescriptorIndex()); 643 644 writeAttributes(dos, f.getAttributes()); 645 } 646 } 647 648 private void writeMethods(DataOutputStream dos) throws IOException { 649 dos.writeShort(methods.size()); 651 Iterator i = methods.iterator(); 652 while(i.hasNext()) { 653 Method m = (Method)i.next(); 654 dos.writeShort(m.getAccessFlags()); 656 dos.writeShort(m.getNameIndex()); 657 dos.writeShort(m.getDescriptorIndex()); 658 659 writeAttributes(dos, m.getAttributes()); 660 } 661 } 662 663 private void writeAttributes(DataOutputStream dos, List attrs) throws IOException { 664 dos.writeShort(attrs.size()); 665 666 Iterator i = attrs.iterator(); 667 while(i.hasNext()) { 668 Attribute a = (Attribute)i.next(); 669 670 dos.writeShort(a.getAttributeNameIndex()); 671 672 byte[] info = a.getBytes(); 673 674 dos.writeInt(info.length); 675 for (int j = 0; j < info.length; j++) { 676 dos.writeByte(info[j]); 677 } 678 } 679 } 680 681 682 private String getUtf8(short index) { 683 ConstantPool.Utf8Info utf8 = 684 (ConstantPool.Utf8Info)constantPool.get(index); 685 686 String s = new String (utf8.getBytes()); 687 688 return s; 689 } 690 } 691 | Popular Tags |