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
16package javassist.bytecode;
17
18import java.io.DataInputStream;
19import java.io.DataOutputStream;
20import java.io.ByteArrayOutputStream;
21import java.io.PrintWriter;
22import java.io.IOException;
23import java.util.HashMap;
24import java.util.HashSet;
25import java.util.Map;
26import java.util.Set;
27
28import javassist.CtClass;
29
30/**
31 * Constant pool table.
32 */
33public 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
1128abstract 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 */
1154class 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
1168class 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
1241class 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
1296abstract 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
1336class 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
1356class 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
1376class 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
1396class 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
1425class 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
1454class 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
1483class 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
1512class 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
1541class 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