1 /* 2 * Javassist, a Java-bytecode translator toolkit. 3 * Copyright (C) 1999-2007 Shigeru Chiba. All Rights Reserved. 4 * 5 * The contents of this file are subject to the Mozilla Public License Version 6 * 1.1 (the "License"); you may not use this file except in compliance with 7 * the License. Alternatively, the contents of this file may be used under 8 * the terms of the GNU Lesser General Public License Version 2.1 or later. 9 * 10 * Software distributed under the License is distributed on an "AS IS" basis, 11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 12 * for the specific language governing rights and limitations under the 13 * License. 14 */ 15 16 package javassist.bytecode; 17 18 import java.io.DataInputStream; 19 import java.io.DataOutputStream; 20 import java.io.ByteArrayOutputStream; 21 import java.io.PrintWriter; 22 import java.io.IOException; 23 import java.util.HashMap; 24 import java.util.HashSet; 25 import java.util.Map; 26 import java.util.Set; 27 28 import javassist.CtClass; 29 30 /** 31 * Constant pool table. 32 */ 33 public final class ConstPool { 34 LongVector items; 35 int numOfItems; 36 HashMap classes; 37 HashMap strings; 38 ConstInfo[] constInfoCache; 39 int[] constInfoIndexCache; 40 int thisClassInfo; 41 42 private static final int CACHE_SIZE = 32; 43 44 /** 45 * A hash function for CACHE_SIZE 46 */ 47 private static int hashFunc(int a, int b) { 48 int h = -2128831035; 49 final int prime = 16777619; 50 h = (h ^ (a & 0xff)) * prime; 51 h = (h ^ (b & 0xff)) * prime; 52 53 // changing the hash key size from 32bit to 5bit 54 h = (h >> 5) ^ (h & 0x1f); 55 return h & 0x1f; // 0..31 56 } 57 58 /** 59 * <code>CONSTANT_Class</code> 60 */ 61 public static final int CONST_Class = ClassInfo.tag; 62 63 /** 64 * <code>CONSTANT_Fieldref</code> 65 */ 66 public static final int CONST_Fieldref = FieldrefInfo.tag; 67 68 /** 69 * <code>CONSTANT_Methodref</code> 70 */ 71 public static final int CONST_Methodref = MethodrefInfo.tag; 72 73 /** 74 * <code>CONSTANT_InterfaceMethodref</code> 75 */ 76 public static final int CONST_InterfaceMethodref 77 = InterfaceMethodrefInfo.tag; 78 79 /** 80 * <code>CONSTANT_String</code> 81 */ 82 public static final int CONST_String = StringInfo.tag; 83 84 /** 85 * <code>CONSTANT_Integer</code> 86 */ 87 public static final int CONST_Integer = IntegerInfo.tag; 88 89 /** 90 * <code>CONSTANT_Float</code> 91 */ 92 public static final int CONST_Float = FloatInfo.tag; 93 94 /** 95 * <code>CONSTANT_Long</code> 96 */ 97 public static final int CONST_Long = LongInfo.tag; 98 99 /** 100 * <code>CONSTANT_Double</code> 101 */ 102 public static final int CONST_Double = DoubleInfo.tag; 103 104 /** 105 * <code>CONSTANT_NameAndType</code> 106 */ 107 public static final int CONST_NameAndType = NameAndTypeInfo.tag; 108 109 /** 110 * <code>CONSTANT_Utf8</code> 111 */ 112 public static final int CONST_Utf8 = Utf8Info.tag; 113 114 /** 115 * Represents the class using this constant pool table. 116 */ 117 public static final CtClass THIS = null; 118 119 /** 120 * Constructs a constant pool table. 121 * 122 * @param thisclass the name of the class using this constant 123 * pool table 124 */ 125 public ConstPool(String thisclass) { 126 items = new LongVector(); 127 numOfItems = 0; 128 addItem(null); // index 0 is reserved by the JVM. 129 classes = new HashMap(); 130 strings = new HashMap(); 131 constInfoCache = new ConstInfo[CACHE_SIZE]; 132 constInfoIndexCache = new int[CACHE_SIZE]; 133 thisClassInfo = addClassInfo(thisclass); 134 } 135 136 /** 137 * Constructs a constant pool table from the given byte stream. 138 * 139 * @param in byte stream. 140 */ 141 public ConstPool(DataInputStream in) throws IOException { 142 classes = new HashMap(); 143 strings = new HashMap(); 144 constInfoCache = new ConstInfo[CACHE_SIZE]; 145 constInfoIndexCache = new int[CACHE_SIZE]; 146 thisClassInfo = 0; 147 /* read() initializes items and numOfItems, and do addItem(null). 148 */ 149 read(in); 150 } 151 152 void prune() { 153 classes = new HashMap(); 154 strings = new HashMap(); 155 constInfoCache = new ConstInfo[CACHE_SIZE]; 156 constInfoIndexCache = new int[CACHE_SIZE]; 157 } 158 159 /** 160 * Returns the number of entries in this table. 161 */ 162 public int getSize() { 163 return numOfItems; 164 } 165 166 /** 167 * Returns the name of the class using this constant pool table. 168 */ 169 public String getClassName() { 170 return getClassInfo(thisClassInfo); 171 } 172 173 /** 174 * Returns the index of <code>CONSTANT_Class_info</code> structure 175 * specifying the class using this constant pool table. 176 */ 177 public int getThisClassInfo() { 178 return thisClassInfo; 179 } 180 181 void setThisClassInfo(int i) { 182 thisClassInfo = i; 183 } 184 185 ConstInfo getItem(int n) { 186 return items.elementAt(n); 187 } 188 189 /** 190 * Returns the <code>tag</code> field of the constant pool table 191 * entry at the given index. 192 */ 193 public int getTag(int index) { 194 return getItem(index).getTag(); 195 } 196 197 /** 198 * Reads <code>CONSTANT_Class_info</code> structure 199 * at the given index. 200 * 201 * @return a fully-qualified class or interface name specified 202 * by <code>name_index</code>. If the type is an array 203 * type, this method returns an encoded name like 204 * <code>[java.lang.Object;</code> (note that the separators 205 * are not slashes but dots). 206 * @see javassist.ClassPool#getCtClass(String) 207 */ 208 public String getClassInfo(int index) { 209 ClassInfo c = (ClassInfo)getItem(index); 210 if (c == null) 211 return null; 212 else 213 return Descriptor.toJavaName(getUtf8Info(c.name)); 214 } 215 216 /** 217 * Reads the <code>name_index</code> field of the 218 * <code>CONSTANT_NameAndType_info</code> structure 219 * at the given index. 220 */ 221 public int getNameAndTypeName(int index) { 222 NameAndTypeInfo ntinfo = (NameAndTypeInfo)getItem(index); 223 return ntinfo.memberName; 224 } 225 226 /** 227 * Reads the <code>descriptor_index</code> field of the 228 * <code>CONSTANT_NameAndType_info</code> structure 229 * at the given index. 230 */ 231 public int getNameAndTypeDescriptor(int index) { 232 NameAndTypeInfo ntinfo = (NameAndTypeInfo)getItem(index); 233 return ntinfo.typeDescriptor; 234 } 235 236 /** 237 * Reads the <code>class_index</code> field of the 238 * <code>CONSTANT_Fieldref_info</code>, 239 * <code>CONSTANT_Methodref_info</code>, 240 * or <code>CONSTANT_Interfaceref_info</code>, 241 * structure at the given index. 242 * 243 * @since 3.6 244 */ 245 public int getMemberClass(int index) { 246 MemberrefInfo minfo = (MemberrefInfo)getItem(index); 247 return minfo.classIndex; 248 } 249 250 /** 251 * Reads the <code>name_and_type_index</code> field of the 252 * <code>CONSTANT_Fieldref_info</code>, 253 * <code>CONSTANT_Methodref_info</code>, 254 * or <code>CONSTANT_Interfaceref_info</code>, 255 * structure at the given index. 256 * 257 * @since 3.6 258 */ 259 public int getMemberNameAndType(int index) { 260 MemberrefInfo minfo = (MemberrefInfo)getItem(index); 261 return minfo.nameAndTypeIndex; 262 } 263 264 /** 265 * Reads the <code>class_index</code> field of the 266 * <code>CONSTANT_Fieldref_info</code> structure 267 * at the given index. 268 */ 269 public int getFieldrefClass(int index) { 270 FieldrefInfo finfo = (FieldrefInfo)getItem(index); 271 return finfo.classIndex; 272 } 273 274 /** 275 * Reads the <code>class_index</code> field of the 276 * <code>CONSTANT_Fieldref_info</code> structure 277 * at the given index. 278 * 279 * @return the name of the class at that <code>class_index</code>. 280 */ 281 public String getFieldrefClassName(int index) { 282 FieldrefInfo f = (FieldrefInfo)getItem(index); 283 if (f == null) 284 return null; 285 else 286 return getClassInfo(f.classIndex); 287 } 288 289 /** 290 * Reads the <code>name_and_type_index</code> field of the 291 * <code>CONSTANT_Fieldref_info</code> structure 292 * at the given index. 293 */ 294 public int getFieldrefNameAndType(int index) { 295 FieldrefInfo finfo = (FieldrefInfo)getItem(index); 296 return finfo.nameAndTypeIndex; 297 } 298 299 /** 300 * Reads the <code>name_index</code> field of the 301 * <code>CONSTANT_NameAndType_info</code> structure 302 * indirectly specified by the given index. 303 * 304 * @param index an index to a <code>CONSTANT_Fieldref_info</code>. 305 * @return the name of the field. 306 */ 307 public String getFieldrefName(int index) { 308 FieldrefInfo f = (FieldrefInfo)getItem(index); 309 if (f == null) 310 return null; 311 else { 312 NameAndTypeInfo n = (NameAndTypeInfo)getItem(f.nameAndTypeIndex); 313 if(n == null) 314 return null; 315 else 316 return getUtf8Info(n.memberName); 317 } 318 } 319 320 /** 321 * Reads the <code>descriptor_index</code> field of the 322 * <code>CONSTANT_NameAndType_info</code> structure 323 * indirectly specified by the given index. 324 * 325 * @param index an index to a <code>CONSTANT_Fieldref_info</code>. 326 * @return the type descriptor of the field. 327 */ 328 public String getFieldrefType(int index) { 329 FieldrefInfo f = (FieldrefInfo)getItem(index); 330 if (f == null) 331 return null; 332 else { 333 NameAndTypeInfo n = (NameAndTypeInfo)getItem(f.nameAndTypeIndex); 334 if(n == null) 335 return null; 336 else 337 return getUtf8Info(n.typeDescriptor); 338 } 339 } 340 341 /** 342 * Reads the <code>class_index</code> field of the 343 * <code>CONSTANT_Methodref_info</code> structure 344 * at the given index. 345 */ 346 public int getMethodrefClass(int index) { 347 MethodrefInfo minfo = (MethodrefInfo)getItem(index); 348 return minfo.classIndex; 349 } 350 351 /** 352 * Reads the <code>class_index</code> field of the 353 * <code>CONSTANT_Methodref_info</code> structure 354 * at the given index. 355 * 356 * @return the name of the class at that <code>class_index</code>. 357 */ 358 public String getMethodrefClassName(int index) { 359 MethodrefInfo minfo = (MethodrefInfo)getItem(index); 360 if (minfo == null) 361 return null; 362 else 363 return getClassInfo(minfo.classIndex); 364 } 365 366 /** 367 * Reads the <code>name_and_type_index</code> field of the 368 * <code>CONSTANT_Methodref_info</code> structure 369 * at the given index. 370 */ 371 public int getMethodrefNameAndType(int index) { 372 MethodrefInfo minfo = (MethodrefInfo)getItem(index); 373 return minfo.nameAndTypeIndex; 374 } 375 376 /** 377 * Reads the <code>name_index</code> field of the 378 * <code>CONSTANT_NameAndType_info</code> structure 379 * indirectly specified by the given index. 380 * 381 * @param index an index to a <code>CONSTANT_Methodref_info</code>. 382 * @return the name of the method. 383 */ 384 public String getMethodrefName(int index) { 385 MethodrefInfo minfo = (MethodrefInfo)getItem(index); 386 if (minfo == null) 387 return null; 388 else { 389 NameAndTypeInfo n 390 = (NameAndTypeInfo)getItem(minfo.nameAndTypeIndex); 391 if(n == null) 392 return null; 393 else 394 return getUtf8Info(n.memberName); 395 } 396 } 397 398 /** 399 * Reads the <code>descriptor_index</code> field of the 400 * <code>CONSTANT_NameAndType_info</code> structure 401 * indirectly specified by the given index. 402 * 403 * @param index an index to a <code>CONSTANT_Methodref_info</code>. 404 * @return the descriptor of the method. 405 */ 406 public String getMethodrefType(int index) { 407 MethodrefInfo minfo = (MethodrefInfo)getItem(index); 408 if (minfo == null) 409 return null; 410 else { 411 NameAndTypeInfo n 412 = (NameAndTypeInfo)getItem(minfo.nameAndTypeIndex); 413 if(n == null) 414 return null; 415 else 416 return getUtf8Info(n.typeDescriptor); 417 } 418 } 419 420 /** 421 * Reads the <code>class_index</code> field of the 422 * <code>CONSTANT_InterfaceMethodref_info</code> structure 423 * at the given index. 424 */ 425 public int getInterfaceMethodrefClass(int index) { 426 InterfaceMethodrefInfo minfo 427 = (InterfaceMethodrefInfo)getItem(index); 428 return minfo.classIndex; 429 } 430 431 /** 432 * Reads the <code>class_index</code> field of the 433 * <code>CONSTANT_InterfaceMethodref_info</code> structure 434 * at the given index. 435 * 436 * @return the name of the class at that <code>class_index</code>. 437 */ 438 public String getInterfaceMethodrefClassName(int index) { 439 InterfaceMethodrefInfo minfo 440 = (InterfaceMethodrefInfo)getItem(index); 441 return getClassInfo(minfo.classIndex); 442 } 443 444 /** 445 * Reads the <code>name_and_type_index</code> field of the 446 * <code>CONSTANT_InterfaceMethodref_info</code> structure 447 * at the given index. 448 */ 449 public int getInterfaceMethodrefNameAndType(int index) { 450 InterfaceMethodrefInfo minfo 451 = (InterfaceMethodrefInfo)getItem(index); 452 return minfo.nameAndTypeIndex; 453 } 454 455 /** 456 * Reads the <code>name_index</code> field of the 457 * <code>CONSTANT_NameAndType_info</code> structure 458 * indirectly specified by the given index. 459 * 460 * @param index an index to 461 * a <code>CONSTANT_InterfaceMethodref_info</code>. 462 * @return the name of the method. 463 */ 464 public String getInterfaceMethodrefName(int index) { 465 InterfaceMethodrefInfo minfo 466 = (InterfaceMethodrefInfo)getItem(index); 467 if (minfo == null) 468 return null; 469 else { 470 NameAndTypeInfo n 471 = (NameAndTypeInfo)getItem(minfo.nameAndTypeIndex); 472 if(n == null) 473 return null; 474 else 475 return getUtf8Info(n.memberName); 476 } 477 } 478 479 /** 480 * Reads the <code>descriptor_index</code> field of the 481 * <code>CONSTANT_NameAndType_info</code> structure 482 * indirectly specified by the given index. 483 * 484 * @param index an index to 485 * a <code>CONSTANT_InterfaceMethodref_info</code>. 486 * @return the descriptor of the method. 487 */ 488 public String getInterfaceMethodrefType(int index) { 489 InterfaceMethodrefInfo minfo 490 = (InterfaceMethodrefInfo)getItem(index); 491 if (minfo == null) 492 return null; 493 else { 494 NameAndTypeInfo n 495 = (NameAndTypeInfo)getItem(minfo.nameAndTypeIndex); 496 if(n == null) 497 return null; 498 else 499 return getUtf8Info(n.typeDescriptor); 500 } 501 } 502 /** 503 * Reads <code>CONSTANT_Integer_info</code>, <code>_Float_info</code>, 504 * <code>_Long_info</code>, <code>_Double_info</code>, or 505 * <code>_String_info</code> structure. 506 * These are used with the LDC instruction. 507 * 508 * @return a <code>String</code> value or a wrapped primitive-type 509 * value. 510 */ 511 public Object getLdcValue(int index) { 512 ConstInfo constInfo = this.getItem(index); 513 Object value = null; 514 if (constInfo instanceof StringInfo) 515 value = this.getStringInfo(index); 516 else if (constInfo instanceof FloatInfo) 517 value = new Float(getFloatInfo(index)); 518 else if (constInfo instanceof IntegerInfo) 519 value = new Integer(getIntegerInfo(index)); 520 else if (constInfo instanceof LongInfo) 521 value = new Long(getLongInfo(index)); 522 else if (constInfo instanceof DoubleInfo) 523 value = new Double(getDoubleInfo(index)); 524 else 525 value = null; 526 527 return value; 528 } 529 530 /** 531 * Reads <code>CONSTANT_Integer_info</code> structure 532 * at the given index. 533 * 534 * @return the value specified by this entry. 535 */ 536 public int getIntegerInfo(int index) { 537 IntegerInfo i = (IntegerInfo)getItem(index); 538 return i.value; 539 } 540 541 /** 542 * Reads <code>CONSTANT_Float_info</code> structure 543 * at the given index. 544 * 545 * @return the value specified by this entry. 546 */ 547 public float getFloatInfo(int index) { 548 FloatInfo i = (FloatInfo)getItem(index); 549 return i.value; 550 } 551 552 /** 553 * Reads <code>CONSTANT_Long_info</code> structure 554 * at the given index. 555 * 556 * @return the value specified by this entry. 557 */ 558 public long getLongInfo(int index) { 559 LongInfo i = (LongInfo)getItem(index); 560 return i.value; 561 } 562 563 /** 564 * Reads <code>CONSTANT_Double_info</code> structure 565 * at the given index. 566 * 567 * @return the value specified by this entry. 568 */ 569 public double getDoubleInfo(int index) { 570 DoubleInfo i = (DoubleInfo)getItem(index); 571 return i.value; 572 } 573 574 /** 575 * Reads <code>CONSTANT_String_info</code> structure 576 * at the given index. 577 * 578 * @return the string specified by <code>string_index</code>. 579 */ 580 public String getStringInfo(int index) { 581 StringInfo si = (StringInfo)getItem(index); 582 return getUtf8Info(si.string); 583 } 584 585 /** 586 * Reads <code>CONSTANT_utf8_info</code> structure 587 * at the given index. 588 * 589 * @return the string specified by this entry. 590 */ 591 public String getUtf8Info(int index) { 592 Utf8Info utf = (Utf8Info)getItem(index); 593 return utf.string; 594 } 595 596 /** 597 * Determines whether <code>CONSTANT_Methodref_info</code> 598 * structure at the given index represents the constructor 599 * of the given class. 600 * 601 * @return the <code>descriptor_index</code> specifying 602 * the type descriptor of the that constructor. 603 * If it is not that constructor, 604 * <code>isConstructor()</code> returns 0. 605 */ 606 public int isConstructor(String classname, int index) { 607 return isMember(classname, MethodInfo.nameInit, index); 608 } 609 610 /** 611 * Determines whether <code>CONSTANT_Methodref_info</code>, 612 * <code>CONSTANT_Fieldref_info</code>, or 613 * <code>CONSTANT_InterfaceMethodref_info</code> structure 614 * at the given index represents the member with the specified 615 * name and declaring class. 616 * 617 * @param classname the class declaring the member 618 * @param membername the member name 619 * @param index the index into the constant pool table 620 * 621 * @return the <code>descriptor_index</code> specifying 622 * the type descriptor of that member. 623 * If it is not that member, 624 * <code>isMember()</code> returns 0. 625 */ 626 public int isMember(String classname, String membername, int index) { 627 MemberrefInfo minfo = (MemberrefInfo)getItem(index); 628 if (getClassInfo(minfo.classIndex).equals(classname)) { 629 NameAndTypeInfo ntinfo 630 = (NameAndTypeInfo)getItem(minfo.nameAndTypeIndex); 631 if (getUtf8Info(ntinfo.memberName).equals(membername)) 632 return ntinfo.typeDescriptor; 633 } 634 635 return 0; // false 636 } 637 638 /** 639 * Determines whether <code>CONSTANT_Methodref_info</code>, 640 * <code>CONSTANT_Fieldref_info</code>, or 641 * <code>CONSTANT_InterfaceMethodref_info</code> structure 642 * at the given index has the name and the descriptor 643 * given as the arguments. 644 * 645 * @param membername the member name 646 * @param desc the descriptor of the member. 647 * @param index the index into the constant pool table 648 * 649 * @return the name of the target class specified by 650 * the <code>..._info</code> structure 651 * at <code>index</code>. 652 * Otherwise, null if that structure does not 653 * match the given member name and descriptor. 654 */ 655 public String eqMember(String membername, String desc, int index) { 656 MemberrefInfo minfo = (MemberrefInfo)getItem(index); 657 NameAndTypeInfo ntinfo 658 = (NameAndTypeInfo)getItem(minfo.nameAndTypeIndex); 659 if (getUtf8Info(ntinfo.memberName).equals(membername) 660 && getUtf8Info(ntinfo.typeDescriptor).equals(desc)) 661 return getClassInfo(minfo.classIndex); 662 else 663 return null; // false 664 } 665 666 private int addItem(ConstInfo info) { 667 items.addElement(info); 668 return numOfItems++; 669 } 670 671 /** 672 * Copies the n-th item in this ConstPool object into the destination 673 * ConstPool object. 674 * The class names that the item refers to are renamed according 675 * to the given map. 676 * 677 * @param n the <i>n</i>-th item 678 * @param dest destination constant pool table 679 * @param classnames the map or null. 680 * @return the index of the copied item into the destination ClassPool. 681 */ 682 public int copy(int n, ConstPool dest, Map classnames) { 683 if (n == 0) 684 return 0; 685 686 ConstInfo info = getItem(n); 687 return info.copy(this, dest, classnames); 688 } 689 690 int addConstInfoPadding() { 691 return addItem(new ConstInfoPadding()); 692 } 693 694 /** 695 * Adds a new <code>CONSTANT_Class_info</code> structure. 696 * 697 * <p>This also adds a <code>CONSTANT_Utf8_info</code> structure 698 * for storing the class name. 699 * 700 * @return the index of the added entry. 701 */ 702 public int addClassInfo(CtClass c) { 703 if (c == THIS) 704 return thisClassInfo; 705 else if (!c.isArray()) 706 return addClassInfo(c.getName()); 707 else { 708 // an array type is recorded in the hashtable with 709 // the key "[L<classname>;" instead of "<classname>". 710 // 711 // note: toJvmName(toJvmName(c)) is equal to toJvmName(c). 712 713 return addClassInfo(Descriptor.toJvmName(c)); 714 } 715 } 716 717 /** 718 * Adds a new <code>CONSTANT_Class_info</code> structure. 719 * 720 * <p>This also adds a <code>CONSTANT_Utf8_info</code> structure 721 * for storing the class name. 722 * 723 * @param qname a fully-qualified class name 724 * (or the JVM-internal representation of that name). 725 * @return the index of the added entry. 726 */ 727 public int addClassInfo(String qname) { 728 ClassInfo info = (ClassInfo)classes.get(qname); 729 if (info != null) 730 return info.index; 731 else { 732 int utf8 = addUtf8Info(Descriptor.toJvmName(qname)); 733 info = new ClassInfo(utf8, numOfItems); 734 classes.put(qname, info); 735 return addItem(info); 736 } 737 } 738 739 /** 740 * Adds a new <code>CONSTANT_NameAndType_info</code> structure. 741 * 742 * <p>This also adds <code>CONSTANT_Utf8_info</code> structures. 743 * 744 * @param name <code>name_index</code> 745 * @param type <code>descriptor_index</code> 746 * @return the index of the added entry. 747 */ 748 public int addNameAndTypeInfo(String name, String type) { 749 return addNameAndTypeInfo(addUtf8Info(name), addUtf8Info(type)); 750 } 751 752 /** 753 * Adds a new <code>CONSTANT_NameAndType_info</code> structure. 754 * 755 * @param name <code>name_index</code> 756 * @param type <code>descriptor_index</code> 757 * @return the index of the added entry. 758 */ 759 public int addNameAndTypeInfo(int name, int type) { 760 int h = hashFunc(name, type); 761 ConstInfo ci = constInfoCache[h]; 762 if (ci != null && ci instanceof NameAndTypeInfo && ci.hashCheck(name, type)) 763 return constInfoIndexCache[h]; 764 else { 765 NameAndTypeInfo item = new NameAndTypeInfo(name, type); 766 constInfoCache[h] = item; 767 int i = addItem(item); 768 constInfoIndexCache[h] = i; 769 return i; 770 } 771 } 772 773 /** 774 * Adds a new <code>CONSTANT_Fieldref_info</code> structure. 775 * 776 * <p>This also adds a new <code>CONSTANT_NameAndType_info</code> 777 * structure. 778 * 779 * @param classInfo <code>class_index</code> 780 * @param name <code>name_index</code> 781 * of <code>CONSTANT_NameAndType_info</code>. 782 * @param type <code>descriptor_index</code> 783 * of <code>CONSTANT_NameAndType_info</code>. 784 * @return the index of the added entry. 785 */ 786 public int addFieldrefInfo(int classInfo, String name, String type) { 787 int nt = addNameAndTypeInfo(name, type); 788 return addFieldrefInfo(classInfo, nt); 789 } 790 791 /** 792 * Adds a new <code>CONSTANT_Fieldref_info</code> structure. 793 * 794 * @param classInfo <code>class_index</code> 795 * @param nameAndTypeInfo <code>name_and_type_index</code>. 796 * @return the index of the added entry. 797 */ 798 public int addFieldrefInfo(int classInfo, int nameAndTypeInfo) { 799 int h = hashFunc(classInfo, nameAndTypeInfo); 800 ConstInfo ci = constInfoCache[h]; 801 if (ci != null && ci instanceof FieldrefInfo && ci.hashCheck(classInfo, nameAndTypeInfo)) 802 return constInfoIndexCache[h]; 803 else { 804 FieldrefInfo item = new FieldrefInfo(classInfo, nameAndTypeInfo); 805 constInfoCache[h] = item; 806 int i = addItem(item); 807 constInfoIndexCache[h] = i; 808 return i; 809 } 810 } 811 812 /** 813 * Adds a new <code>CONSTANT_Methodref_info</code> structure. 814 * 815 * <p>This also adds a new <code>CONSTANT_NameAndType_info</code> 816 * structure. 817 * 818 * @param classInfo <code>class_index</code> 819 * @param name <code>name_index</code> 820 * of <code>CONSTANT_NameAndType_info</code>. 821 * @param type <code>descriptor_index</code> 822 * of <code>CONSTANT_NameAndType_info</code>. 823 * @return the index of the added entry. 824 */ 825 public int addMethodrefInfo(int classInfo, String name, String type) { 826 int nt = addNameAndTypeInfo(name, type); 827 return addMethodrefInfo(classInfo, nt); 828 } 829 830 /** 831 * Adds a new <code>CONSTANT_Methodref_info</code> structure. 832 * 833 * @param classInfo <code>class_index</code> 834 * @param nameAndTypeInfo <code>name_and_type_index</code>. 835 * @return the index of the added entry. 836 */ 837 public int addMethodrefInfo(int classInfo, int nameAndTypeInfo) { 838 int h = hashFunc(classInfo, nameAndTypeInfo); 839 ConstInfo ci = constInfoCache[h]; 840 if (ci != null && ci instanceof MethodrefInfo && ci.hashCheck(classInfo, nameAndTypeInfo)) 841 return constInfoIndexCache[h]; 842 else { 843 MethodrefInfo item = new MethodrefInfo(classInfo, nameAndTypeInfo); 844 constInfoCache[h] = item; 845 int i = addItem(item); 846 constInfoIndexCache[h] = i; 847 return i; 848 } 849 } 850 851 /** 852 * Adds a new <code>CONSTANT_InterfaceMethodref_info</code> 853 * structure. 854 * 855 * <p>This also adds a new <code>CONSTANT_NameAndType_info</code> 856 * structure. 857 * 858 * @param classInfo <code>class_index</code> 859 * @param name <code>name_index</code> 860 * of <code>CONSTANT_NameAndType_info</code>. 861 * @param type <code>descriptor_index</code> 862 * of <code>CONSTANT_NameAndType_info</code>. 863 * @return the index of the added entry. 864 */ 865 public int addInterfaceMethodrefInfo(int classInfo, String name, 866 String type) { 867 int nt = addNameAndTypeInfo(name, type); 868 return addInterfaceMethodrefInfo(classInfo, nt); 869 } 870 871 /** 872 * Adds a new <code>CONSTANT_InterfaceMethodref_info</code> 873 * structure. 874 * 875 * @param classInfo <code>class_index</code> 876 * @param nameAndTypeInfo <code>name_and_type_index</code>. 877 * @return the index of the added entry. 878 */ 879 public int addInterfaceMethodrefInfo(int classInfo, 880 int nameAndTypeInfo) { 881 int h = hashFunc(classInfo, nameAndTypeInfo); 882 ConstInfo ci = constInfoCache[h]; 883 if (ci != null && ci instanceof InterfaceMethodrefInfo && ci.hashCheck(classInfo, nameAndTypeInfo)) 884 return constInfoIndexCache[h]; 885 else { 886 InterfaceMethodrefInfo item =new InterfaceMethodrefInfo(classInfo, nameAndTypeInfo); 887 constInfoCache[h] = item; 888 int i = addItem(item); 889 constInfoIndexCache[h] = i; 890 return i; 891 } 892 } 893 894 /** 895 * Adds a new <code>CONSTANT_String_info</code> 896 * structure. 897 * 898 * <p>This also adds a new <code>CONSTANT_Utf8_info</code> 899 * structure. 900 * 901 * @return the index of the added entry. 902 */ 903 public int addStringInfo(String str) { 904 return addItem(new StringInfo(addUtf8Info(str))); 905 } 906 907 /** 908 * Adds a new <code>CONSTANT_Integer_info</code> 909 * structure. 910 * 911 * @return the index of the added entry. 912 */ 913 public int addIntegerInfo(int i) { 914 return addItem(new IntegerInfo(i)); 915 } 916 917 /** 918 * Adds a new <code>CONSTANT_Float_info</code> 919 * structure. 920 * 921 * @return the index of the added entry. 922 */ 923 public int addFloatInfo(float f) { 924 return addItem(new FloatInfo(f)); 925 } 926 927 /** 928 * Adds a new <code>CONSTANT_Long_info</code> 929 * structure. 930 * 931 * @return the index of the added entry. 932 */ 933 public int addLongInfo(long l) { 934 int i = addItem(new LongInfo(l)); 935 addItem(new ConstInfoPadding()); 936 return i; 937 } 938 939 /** 940 * Adds a new <code>CONSTANT_Double_info</code> 941 * structure. 942 * 943 * @return the index of the added entry. 944 */ 945 public int addDoubleInfo(double d) { 946 int i = addItem(new DoubleInfo(d)); 947 addItem(new ConstInfoPadding()); 948 return i; 949 } 950 951 /** 952 * Adds a new <code>CONSTANT_Utf8_info</code> 953 * structure. 954 * 955 * <p>If the given utf8 string has been already recorded in the 956 * table, then this method does not add a new entry to avoid adding 957 * a duplicated entry. 958 * Instead, it returns the index of the entry already recorded. 959 * 960 * @return the index of the added entry. 961 */ 962 public int addUtf8Info(String utf8) { 963 Utf8Info info = (Utf8Info)strings.get(utf8); 964 if (info != null) 965 return info.index; 966 else { 967 info = new Utf8Info(utf8, numOfItems); 968 strings.put(utf8, info); 969 return addItem(info); 970 } 971 } 972 973 /** 974 * Get all the class names. 975 * 976 * @return a set of class names 977 */ 978 public Set getClassNames() 979 { 980 HashSet result = new HashSet(); 981 LongVector v = items; 982 int size = numOfItems; 983 for (int i = 1; i < size; ++i) { 984 String className = v.elementAt(i).getClassName(this); 985 if (className != null) 986 result.add(className); 987 } 988 return result; 989 } 990 991 /** 992 * Replaces all occurrences of a class name. 993 * 994 * @param oldName the replaced name (JVM-internal representation). 995 * @param newName the substituted name (JVM-internal representation). 996 */ 997 public void renameClass(String oldName, String newName) { 998 LongVector v = items; 999 int size = numOfItems; 1000 classes = new HashMap(classes.size() * 2); 1001 for (int i = 1; i < size; ++i) { 1002 ConstInfo ci = v.elementAt(i); 1003 ci.renameClass(this, oldName, newName); 1004 ci.makeHashtable(this); 1005 } 1006 } 1007 1008 /** 1009 * Replaces all occurrences of class names. 1010 * 1011 * @param classnames specifies pairs of replaced and substituted 1012 * name. 1013 */ 1014 public void renameClass(Map classnames) { 1015 LongVector v = items; 1016 int size = numOfItems; 1017 classes = new HashMap(classes.size() * 2); 1018 for (int i = 1; i < size; ++i) { 1019 ConstInfo ci = v.elementAt(i); 1020 ci.renameClass(this, classnames); 1021 ci.makeHashtable(this); 1022 } 1023 } 1024 1025 private void read(DataInputStream in) throws IOException { 1026 int n = in.readUnsignedShort(); 1027 1028 items = new LongVector(n); 1029 numOfItems = 0; 1030 addItem(null); // index 0 is reserved by the JVM. 1031 1032 while (--n > 0) { // index 0 is reserved by JVM 1033 int tag = readOne(in); 1034 if ((tag == LongInfo.tag) || (tag == DoubleInfo.tag)) { 1035 addItem(new ConstInfoPadding()); 1036 --n; 1037 } 1038 } 1039 1040 int i = 1; 1041 while (true) { 1042 ConstInfo info = items.elementAt(i++); 1043 if (info == null) 1044 break; 1045 else 1046 info.makeHashtable(this); 1047 } 1048 } 1049 1050 private int readOne(DataInputStream in) throws IOException { 1051 ConstInfo info; 1052 int tag = in.readUnsignedByte(); 1053 switch (tag) { 1054 case Utf8Info.tag : // 1 1055 info = new Utf8Info(in, numOfItems); 1056 strings.put(((Utf8Info)info).string, info); 1057 break; 1058 case IntegerInfo.tag : // 3 1059 info = new IntegerInfo(in); 1060 break; 1061 case FloatInfo.tag : // 4 1062 info = new FloatInfo(in); 1063 break; 1064 case LongInfo.tag : // 5 1065 info = new LongInfo(in); 1066 break; 1067 case DoubleInfo.tag : // 6 1068 info = new DoubleInfo(in); 1069 break; 1070 case ClassInfo.tag : // 7 1071 info = new ClassInfo(in, numOfItems); 1072 // classes.put(<classname>, info); 1073 break; 1074 case StringInfo.tag : // 8 1075 info = new StringInfo(in); 1076 break; 1077 case FieldrefInfo.tag : // 9 1078 info = new FieldrefInfo(in); 1079 break; 1080 case MethodrefInfo.tag : // 10 1081 info = new MethodrefInfo(in); 1082 break; 1083 case InterfaceMethodrefInfo.tag : // 11 1084 info = new InterfaceMethodrefInfo(in); 1085 break; 1086 case NameAndTypeInfo.tag : // 12 1087 info = new NameAndTypeInfo(in); 1088 break; 1089 default : 1090 throw new IOException("invalid constant type: " + tag); 1091 } 1092 1093 addItem(info); 1094 return tag; 1095 } 1096 1097 /** 1098 * Writes the contents of the constant pool table. 1099 */ 1100 public void write(DataOutputStream out) throws IOException { 1101 out.writeShort(numOfItems); 1102 LongVector v = items; 1103 int size = numOfItems; 1104 for (int i = 1; i < size; ++i) 1105 v.elementAt(i).write(out); 1106 } 1107 1108 /** 1109 * Prints the contents of the constant pool table. 1110 */ 1111 public void print() { 1112 print(new PrintWriter(System.out, true)); 1113 } 1114 1115 /** 1116 * Prints the contents of the constant pool table. 1117 */ 1118 public void print(PrintWriter out) { 1119 int size = numOfItems; 1120 for (int i = 1; i < size; ++i) { 1121 out.print(i); 1122 out.print(" "); 1123 items.elementAt(i).print(out); 1124 } 1125 } 1126 } 1127 1128 abstract class ConstInfo { 1129 public abstract int getTag(); 1130 1131 public String getClassName(ConstPool cp) { return null; } 1132 public void renameClass(ConstPool cp, String oldName, String newName) {} 1133 public void renameClass(ConstPool cp, Map classnames) {} 1134 public abstract int copy(ConstPool src, ConstPool dest, Map classnames); 1135 // ** classnames is a mapping between JVM names. 1136 1137 public abstract void write(DataOutputStream out) throws IOException; 1138 public abstract void print(PrintWriter out); 1139 1140 void makeHashtable(ConstPool cp) {} // called after read() finishes in ConstPool. 1141 1142 boolean hashCheck(int a, int b) { return false; } 1143 1144 public String toString() { 1145 ByteArrayOutputStream bout = new ByteArrayOutputStream(); 1146 PrintWriter out = new PrintWriter(bout); 1147 print(out); 1148 return bout.toString(); 1149 } 1150 } 1151 1152 /* padding following DoubleInfo or LongInfo. 1153 */ 1154 class ConstInfoPadding extends ConstInfo { 1155 public int getTag() { return 0; } 1156 1157 public int copy(ConstPool src, ConstPool dest, Map map) { 1158 return dest.addConstInfoPadding(); 1159 } 1160 1161 public void write(DataOutputStream out) throws IOException {} 1162 1163 public void print(PrintWriter out) { 1164 out.println("padding"); 1165 } 1166 } 1167 1168 class ClassInfo extends ConstInfo { 1169 static final int tag = 7; 1170 int name; 1171 int index; 1172 1173 public ClassInfo(int className, int i) { 1174 name = className; 1175 index = i; 1176 } 1177 1178 public ClassInfo(DataInputStream in, int i) throws IOException { 1179 name = in.readUnsignedShort(); 1180 index = i; 1181 } 1182 1183 public int getTag() { return tag; } 1184 1185 public String getClassName(ConstPool cp) { 1186 return cp.getUtf8Info(name); 1187 }; 1188 1189 public void renameClass(ConstPool cp, String oldName, String newName) { 1190 String nameStr = cp.getUtf8Info(name); 1191 if (nameStr.equals(oldName)) 1192 name = cp.addUtf8Info(newName); 1193 else if (nameStr.charAt(0) == '[') { 1194 String nameStr2 = Descriptor.rename(nameStr, oldName, newName); 1195 if (nameStr != nameStr2) 1196 name = cp.addUtf8Info(nameStr2); 1197 } 1198 } 1199 1200 public void renameClass(ConstPool cp, Map map) { 1201 String oldName = cp.getUtf8Info(name); 1202 if (oldName.charAt(0) == '[') { 1203 String newName = Descriptor.rename(oldName, map); 1204 if (oldName != newName) 1205 name = cp.addUtf8Info(newName); 1206 } 1207 else { 1208 String newName = (String)map.get(oldName); 1209 if (newName != null && !newName.equals(oldName)) 1210 name = cp.addUtf8Info(newName); 1211 } 1212 } 1213 1214 public int copy(ConstPool src, ConstPool dest, Map map) { 1215 String classname = src.getUtf8Info(name); 1216 if (map != null) { 1217 String newname = (String)map.get(classname); 1218 if (newname != null) 1219 classname = newname; 1220 } 1221 1222 return dest.addClassInfo(classname); 1223 } 1224 1225 public void write(DataOutputStream out) throws IOException { 1226 out.writeByte(tag); 1227 out.writeShort(name); 1228 } 1229 1230 public void print(PrintWriter out) { 1231 out.print("Class #"); 1232 out.println(name); 1233 } 1234 1235 void makeHashtable(ConstPool cp) { 1236 String name = Descriptor.toJavaName(getClassName(cp)); 1237 cp.classes.put(name, this); 1238 } 1239 } 1240 1241 class NameAndTypeInfo extends ConstInfo { 1242 static final int tag = 12; 1243 int memberName; 1244 int typeDescriptor; 1245 1246 public NameAndTypeInfo(int name, int type) { 1247 memberName = name; 1248 typeDescriptor = type; 1249 } 1250 1251 public NameAndTypeInfo(DataInputStream in) throws IOException { 1252 memberName = in.readUnsignedShort(); 1253 typeDescriptor = in.readUnsignedShort(); 1254 } 1255 1256 boolean hashCheck(int a, int b) { return a == memberName && b == typeDescriptor; } 1257 1258 public int getTag() { return tag; } 1259 1260 public void renameClass(ConstPool cp, String oldName, String newName) { 1261 String type = cp.getUtf8Info(typeDescriptor); 1262 String type2 = Descriptor.rename(type, oldName, newName); 1263 if (type != type2) 1264 typeDescriptor = cp.addUtf8Info(type2); 1265 } 1266 1267 public void renameClass(ConstPool cp, Map map) { 1268 String type = cp.getUtf8Info(typeDescriptor); 1269 String type2 = Descriptor.rename(type, map); 1270 if (type != type2) 1271 typeDescriptor = cp.addUtf8Info(type2); 1272 } 1273 1274 public int copy(ConstPool src, ConstPool dest, Map map) { 1275 String mname = src.getUtf8Info(memberName); 1276 String tdesc = src.getUtf8Info(typeDescriptor); 1277 tdesc = Descriptor.rename(tdesc, map); 1278 return dest.addNameAndTypeInfo(dest.addUtf8Info(mname), 1279 dest.addUtf8Info(tdesc)); 1280 } 1281 1282 public void write(DataOutputStream out) throws IOException { 1283 out.writeByte(tag); 1284 out.writeShort(memberName); 1285 out.writeShort(typeDescriptor); 1286 } 1287 1288 public void print(PrintWriter out) { 1289 out.print("NameAndType #"); 1290 out.print(memberName); 1291 out.print(", type #"); 1292 out.println(typeDescriptor); 1293 } 1294 } 1295 1296 abstract class MemberrefInfo extends ConstInfo { 1297 int classIndex; 1298 int nameAndTypeIndex; 1299 1300 public MemberrefInfo(int cindex, int ntindex) { 1301 classIndex = cindex; 1302 nameAndTypeIndex = ntindex; 1303 } 1304 1305 public MemberrefInfo(DataInputStream in) throws IOException { 1306 classIndex = in.readUnsignedShort(); 1307 nameAndTypeIndex = in.readUnsignedShort(); 1308 } 1309 1310 public int copy(ConstPool src, ConstPool dest, Map map) { 1311 int classIndex2 = src.getItem(classIndex).copy(src, dest, map); 1312 int ntIndex2 = src.getItem(nameAndTypeIndex).copy(src, dest, map); 1313 return copy2(dest, classIndex2, ntIndex2); 1314 } 1315 1316 boolean hashCheck(int a, int b) { return a == classIndex && b == nameAndTypeIndex; } 1317 1318 abstract protected int copy2(ConstPool dest, int cindex, int ntindex); 1319 1320 public void write(DataOutputStream out) throws IOException { 1321 out.writeByte(getTag()); 1322 out.writeShort(classIndex); 1323 out.writeShort(nameAndTypeIndex); 1324 } 1325 1326 public void print(PrintWriter out) { 1327 out.print(getTagName() + " #"); 1328 out.print(classIndex); 1329 out.print(", name&type #"); 1330 out.println(nameAndTypeIndex); 1331 } 1332 1333 public abstract String getTagName(); 1334 } 1335 1336 class FieldrefInfo extends MemberrefInfo { 1337 static final int tag = 9; 1338 1339 public FieldrefInfo(int cindex, int ntindex) { 1340 super(cindex, ntindex); 1341 } 1342 1343 public FieldrefInfo(DataInputStream in) throws IOException { 1344 super(in); 1345 } 1346 1347 public int getTag() { return tag; } 1348 1349 public String getTagName() { return "Field"; } 1350 1351 protected int copy2(ConstPool dest, int cindex, int ntindex) { 1352 return dest.addFieldrefInfo(cindex, ntindex); 1353 } 1354 } 1355 1356 class MethodrefInfo extends MemberrefInfo { 1357 static final int tag = 10; 1358 1359 public MethodrefInfo(int cindex, int ntindex) { 1360 super(cindex, ntindex); 1361 } 1362 1363 public MethodrefInfo(DataInputStream in) throws IOException { 1364 super(in); 1365 } 1366 1367 public int getTag() { return tag; } 1368 1369 public String getTagName() { return "Method"; } 1370 1371 protected int copy2(ConstPool dest, int cindex, int ntindex) { 1372 return dest.addMethodrefInfo(cindex, ntindex); 1373 } 1374 } 1375 1376 class InterfaceMethodrefInfo extends MemberrefInfo { 1377 static final int tag = 11; 1378 1379 public InterfaceMethodrefInfo(int cindex, int ntindex) { 1380 super(cindex, ntindex); 1381 } 1382 1383 public InterfaceMethodrefInfo(DataInputStream in) throws IOException { 1384 super(in); 1385 } 1386 1387 public int getTag() { return tag; } 1388 1389 public String getTagName() { return "Interface"; } 1390 1391 protected int copy2(ConstPool dest, int cindex, int ntindex) { 1392 return dest.addInterfaceMethodrefInfo(cindex, ntindex); 1393 } 1394 } 1395 1396 class StringInfo extends ConstInfo { 1397 static final int tag = 8; 1398 int string; 1399 1400 public StringInfo(int str) { 1401 string = str; 1402 } 1403 1404 public StringInfo(DataInputStream in) throws IOException { 1405 string = in.readUnsignedShort(); 1406 } 1407 1408 public int getTag() { return tag; } 1409 1410 public int copy(ConstPool src, ConstPool dest, Map map) { 1411 return dest.addStringInfo(src.getUtf8Info(string)); 1412 } 1413 1414 public void write(DataOutputStream out) throws IOException { 1415 out.writeByte(tag); 1416 out.writeShort(string); 1417 } 1418 1419 public void print(PrintWriter out) { 1420 out.print("String #"); 1421 out.println(string); 1422 } 1423 } 1424 1425 class IntegerInfo extends ConstInfo { 1426 static final int tag = 3; 1427 int value; 1428 1429 public IntegerInfo(int i) { 1430 value = i; 1431 } 1432 1433 public IntegerInfo(DataInputStream in) throws IOException { 1434 value = in.readInt(); 1435 } 1436 1437 public int getTag() { return tag; } 1438 1439 public int copy(ConstPool src, ConstPool dest, Map map) { 1440 return dest.addIntegerInfo(value); 1441 } 1442 1443 public void write(DataOutputStream out) throws IOException { 1444 out.writeByte(tag); 1445 out.writeInt(value); 1446 } 1447 1448 public void print(PrintWriter out) { 1449 out.print("Integer "); 1450 out.println(value); 1451 } 1452 } 1453 1454 class FloatInfo extends ConstInfo { 1455 static final int tag = 4; 1456 float value; 1457 1458 public FloatInfo(float f) { 1459 value = f; 1460 } 1461 1462 public FloatInfo(DataInputStream in) throws IOException { 1463 value = in.readFloat(); 1464 } 1465 1466 public int getTag() { return tag; } 1467 1468 public int copy(ConstPool src, ConstPool dest, Map map) { 1469 return dest.addFloatInfo(value); 1470 } 1471 1472 public void write(DataOutputStream out) throws IOException { 1473 out.writeByte(tag); 1474 out.writeFloat(value); 1475 } 1476 1477 public void print(PrintWriter out) { 1478 out.print("Float "); 1479 out.println(value); 1480 } 1481 } 1482 1483 class LongInfo extends ConstInfo { 1484 static final int tag = 5; 1485 long value; 1486 1487 public LongInfo(long l) { 1488 value = l; 1489 } 1490 1491 public LongInfo(DataInputStream in) throws IOException { 1492 value = in.readLong(); 1493 } 1494 1495 public int getTag() { return tag; } 1496 1497 public int copy(ConstPool src, ConstPool dest, Map map) { 1498 return dest.addLongInfo(value); 1499 } 1500 1501 public void write(DataOutputStream out) throws IOException { 1502 out.writeByte(tag); 1503 out.writeLong(value); 1504 } 1505 1506 public void print(PrintWriter out) { 1507 out.print("Long "); 1508 out.println(value); 1509 } 1510 } 1511 1512 class DoubleInfo extends ConstInfo { 1513 static final int tag = 6; 1514 double value; 1515 1516 public DoubleInfo(double d) { 1517 value = d; 1518 } 1519 1520 public DoubleInfo(DataInputStream in) throws IOException { 1521 value = in.readDouble(); 1522 } 1523 1524 public int getTag() { return tag; } 1525 1526 public int copy(ConstPool src, ConstPool dest, Map map) { 1527 return dest.addDoubleInfo(value); 1528 } 1529 1530 public void write(DataOutputStream out) throws IOException { 1531 out.writeByte(tag); 1532 out.writeDouble(value); 1533 } 1534 1535 public void print(PrintWriter out) { 1536 out.print("Double "); 1537 out.println(value); 1538 } 1539 } 1540 1541 class Utf8Info extends ConstInfo { 1542 static final int tag = 1; 1543 String string; 1544 int index; 1545 1546 public Utf8Info(String utf8, int i) { 1547 string = utf8; 1548 index = i; 1549 } 1550 1551 public Utf8Info(DataInputStream in, int i) throws IOException { 1552 string = in.readUTF(); 1553 index = i; 1554 } 1555 1556 public int getTag() { return tag; } 1557 1558 public int copy(ConstPool src, ConstPool dest, Map map) { 1559 return dest.addUtf8Info(string); 1560 } 1561 1562 public void write(DataOutputStream out) throws IOException { 1563 out.writeByte(tag); 1564 out.writeUTF(string); 1565 } 1566 1567 public void print(PrintWriter out) { 1568 out.print("UTF8 \""); 1569 out.print(string); 1570 out.println("\""); 1571 } 1572 } 1573