1/*
2 * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package com.sun.tools.classfile;
27
28import java.io.DataOutputStream;
29import java.io.IOException;
30import java.io.OutputStream;
31import java.util.Iterator;
32
33/**
34 * See JVMS, section 4.5.
35 *
36 *  <p><b>This is NOT part of any supported API.
37 *  If you write code that depends on this, you do so at your own risk.
38 *  This code and its internal interfaces are subject to change or
39 *  deletion without notice.</b>
40 */
41public class ConstantPool {
42
43    public static class InvalidIndex extends ConstantPoolException {
44        private static final long serialVersionUID = -4350294289300939730L;
45        InvalidIndex(int index) {
46            super(index);
47        }
48
49        @Override
50        public String getMessage() {
51            // i18n
52            return "invalid index #" + index;
53        }
54    }
55
56    public static class UnexpectedEntry extends ConstantPoolException {
57        private static final long serialVersionUID = 6986335935377933211L;
58        UnexpectedEntry(int index, int expected_tag, int found_tag) {
59            super(index);
60            this.expected_tag = expected_tag;
61            this.found_tag = found_tag;
62        }
63
64        @Override
65        public String getMessage() {
66            // i18n?
67            return "unexpected entry at #" + index + " -- expected tag " + expected_tag + ", found " + found_tag;
68        }
69
70        public final int expected_tag;
71        public final int found_tag;
72    }
73
74    public static class InvalidEntry extends ConstantPoolException {
75        private static final long serialVersionUID = 1000087545585204447L;
76        InvalidEntry(int index, int tag) {
77            super(index);
78            this.tag = tag;
79        }
80
81        @Override
82        public String getMessage() {
83            // i18n?
84            return "unexpected tag at #" + index + ": " + tag;
85        }
86
87        public final int tag;
88    }
89
90    public static class EntryNotFound extends ConstantPoolException {
91        private static final long serialVersionUID = 2885537606468581850L;
92        EntryNotFound(Object value) {
93            super(-1);
94            this.value = value;
95        }
96
97        @Override
98        public String getMessage() {
99            // i18n?
100            return "value not found: " + value;
101        }
102
103        public final Object value;
104    }
105
106    public static final int CONSTANT_Utf8 = 1;
107    public static final int CONSTANT_Integer = 3;
108    public static final int CONSTANT_Float = 4;
109    public static final int CONSTANT_Long = 5;
110    public static final int CONSTANT_Double = 6;
111    public static final int CONSTANT_Class = 7;
112    public static final int CONSTANT_String = 8;
113    public static final int CONSTANT_Fieldref = 9;
114    public static final int CONSTANT_Methodref = 10;
115    public static final int CONSTANT_InterfaceMethodref = 11;
116    public static final int CONSTANT_NameAndType = 12;
117    public static final int CONSTANT_MethodHandle = 15;
118    public static final int CONSTANT_MethodType = 16;
119    public static final int CONSTANT_InvokeDynamic = 18;
120    public static final int CONSTANT_Module = 19;
121    public static final int CONSTANT_Package = 20;
122
123    public static enum RefKind {
124        REF_getField(1),
125        REF_getStatic(2),
126        REF_putField(3),
127        REF_putStatic(4),
128        REF_invokeVirtual(5),
129        REF_invokeStatic(6),
130        REF_invokeSpecial(7),
131        REF_newInvokeSpecial(8),
132        REF_invokeInterface(9);
133
134        public final int tag;
135
136        RefKind(int tag) {
137            this.tag = tag;
138        }
139
140        static RefKind getRefkind(int tag) {
141            switch(tag) {
142                case 1:
143                    return REF_getField;
144                case 2:
145                    return REF_getStatic;
146                case 3:
147                    return REF_putField;
148                case 4:
149                    return REF_putStatic;
150                case 5:
151                    return REF_invokeVirtual;
152                case 6:
153                    return REF_invokeStatic;
154                case 7:
155                    return REF_invokeSpecial;
156                case 8:
157                    return REF_newInvokeSpecial;
158                case 9:
159                    return REF_invokeInterface;
160                default:
161                    return null;
162            }
163        }
164    }
165
166    ConstantPool(ClassReader cr) throws IOException, InvalidEntry {
167        int count = cr.readUnsignedShort();
168        pool = new CPInfo[count];
169        for (int i = 1; i < count; i++) {
170            int tag = cr.readUnsignedByte();
171            switch (tag) {
172            case CONSTANT_Class:
173                pool[i] = new CONSTANT_Class_info(this, cr);
174                break;
175
176            case CONSTANT_Double:
177                pool[i] = new CONSTANT_Double_info(cr);
178                i++;
179                break;
180
181            case CONSTANT_Fieldref:
182                pool[i] = new CONSTANT_Fieldref_info(this, cr);
183                break;
184
185            case CONSTANT_Float:
186                pool[i] = new CONSTANT_Float_info(cr);
187                break;
188
189            case CONSTANT_Integer:
190                pool[i] = new CONSTANT_Integer_info(cr);
191                break;
192
193            case CONSTANT_InterfaceMethodref:
194                pool[i] = new CONSTANT_InterfaceMethodref_info(this, cr);
195                break;
196
197            case CONSTANT_InvokeDynamic:
198                pool[i] = new CONSTANT_InvokeDynamic_info(this, cr);
199                break;
200
201            case CONSTANT_Long:
202                pool[i] = new CONSTANT_Long_info(cr);
203                i++;
204                break;
205
206            case CONSTANT_MethodHandle:
207                pool[i] = new CONSTANT_MethodHandle_info(this, cr);
208                break;
209
210            case CONSTANT_MethodType:
211                pool[i] = new CONSTANT_MethodType_info(this, cr);
212                break;
213
214            case CONSTANT_Methodref:
215                pool[i] = new CONSTANT_Methodref_info(this, cr);
216                break;
217
218            case CONSTANT_Module:
219                pool[i] = new CONSTANT_Module_info(this, cr);
220                break;
221
222            case CONSTANT_NameAndType:
223                pool[i] = new CONSTANT_NameAndType_info(this, cr);
224                break;
225
226            case CONSTANT_Package:
227                pool[i] = new CONSTANT_Package_info(this, cr);
228                break;
229
230            case CONSTANT_String:
231                pool[i] = new CONSTANT_String_info(this, cr);
232                break;
233
234            case CONSTANT_Utf8:
235                pool[i] = new CONSTANT_Utf8_info(cr);
236                break;
237
238            default:
239                throw new InvalidEntry(i, tag);
240            }
241        }
242    }
243
244    public ConstantPool(CPInfo[] pool) {
245        this.pool = pool;
246    }
247
248    public int size() {
249        return pool.length;
250    }
251
252    public int byteLength() {
253        int length = 2;
254        for (int i = 1; i < size(); ) {
255            CPInfo cpInfo = pool[i];
256            length += cpInfo.byteLength();
257            i += cpInfo.size();
258        }
259        return length;
260    }
261
262    public CPInfo get(int index) throws InvalidIndex {
263        if (index <= 0 || index >= pool.length)
264            throw new InvalidIndex(index);
265        CPInfo info = pool[index];
266        if (info == null) {
267            // this occurs for indices referencing the "second half" of an
268            // 8 byte constant, such as CONSTANT_Double or CONSTANT_Long
269            throw new InvalidIndex(index);
270        }
271        return pool[index];
272    }
273
274    private CPInfo get(int index, int expected_type) throws InvalidIndex, UnexpectedEntry {
275        CPInfo info = get(index);
276        if (info.getTag() != expected_type)
277            throw new UnexpectedEntry(index, expected_type, info.getTag());
278        return info;
279    }
280
281    public CONSTANT_Utf8_info getUTF8Info(int index) throws InvalidIndex, UnexpectedEntry {
282        return ((CONSTANT_Utf8_info) get(index, CONSTANT_Utf8));
283    }
284
285    public CONSTANT_Class_info getClassInfo(int index) throws InvalidIndex, UnexpectedEntry {
286        return ((CONSTANT_Class_info) get(index, CONSTANT_Class));
287    }
288
289    public CONSTANT_Module_info getModuleInfo(int index) throws InvalidIndex, UnexpectedEntry {
290        return ((CONSTANT_Module_info) get(index, CONSTANT_Module));
291    }
292
293    public CONSTANT_NameAndType_info getNameAndTypeInfo(int index) throws InvalidIndex, UnexpectedEntry {
294        return ((CONSTANT_NameAndType_info) get(index, CONSTANT_NameAndType));
295    }
296
297    public CONSTANT_Package_info getPackageInfo(int index) throws InvalidIndex, UnexpectedEntry {
298        return ((CONSTANT_Package_info) get(index, CONSTANT_Package));
299    }
300
301    public String getUTF8Value(int index) throws InvalidIndex, UnexpectedEntry {
302        return getUTF8Info(index).value;
303    }
304
305    public int getUTF8Index(String value) throws EntryNotFound {
306        for (int i = 1; i < pool.length; i++) {
307            CPInfo info = pool[i];
308            if (info instanceof CONSTANT_Utf8_info &&
309                    ((CONSTANT_Utf8_info) info).value.equals(value))
310                return i;
311        }
312        throw new EntryNotFound(value);
313    }
314
315    public Iterable<CPInfo> entries() {
316        return () -> new Iterator<CPInfo>() {
317
318            public boolean hasNext() {
319                return next < pool.length;
320            }
321
322            public CPInfo next() {
323                current = pool[next];
324                switch (current.getTag()) {
325                    case CONSTANT_Double:
326                    case CONSTANT_Long:
327                        next += 2;
328                        break;
329                    default:
330                        next += 1;
331                }
332                return current;
333            }
334
335            public void remove() {
336                throw new UnsupportedOperationException();
337            }
338
339            private CPInfo current;
340            private int next = 1;
341
342        };
343    }
344
345    private CPInfo[] pool;
346
347    public interface Visitor<R,P> {
348        R visitClass(CONSTANT_Class_info info, P p);
349        R visitDouble(CONSTANT_Double_info info, P p);
350        R visitFieldref(CONSTANT_Fieldref_info info, P p);
351        R visitFloat(CONSTANT_Float_info info, P p);
352        R visitInteger(CONSTANT_Integer_info info, P p);
353        R visitInterfaceMethodref(CONSTANT_InterfaceMethodref_info info, P p);
354        R visitInvokeDynamic(CONSTANT_InvokeDynamic_info info, P p);
355        R visitLong(CONSTANT_Long_info info, P p);
356        R visitMethodref(CONSTANT_Methodref_info info, P p);
357        R visitMethodHandle(CONSTANT_MethodHandle_info info, P p);
358        R visitMethodType(CONSTANT_MethodType_info info, P p);
359        R visitModule(CONSTANT_Module_info info, P p);
360        R visitNameAndType(CONSTANT_NameAndType_info info, P p);
361        R visitPackage(CONSTANT_Package_info info, P p);
362        R visitString(CONSTANT_String_info info, P p);
363        R visitUtf8(CONSTANT_Utf8_info info, P p);
364    }
365
366    public static abstract class CPInfo {
367        CPInfo() {
368            this.cp = null;
369        }
370
371        CPInfo(ConstantPool cp) {
372            this.cp = cp;
373        }
374
375        public abstract int getTag();
376
377        /** The number of slots in the constant pool used by this entry.
378         * 2 for CONSTANT_Double and CONSTANT_Long; 1 for everything else. */
379        public int size() {
380            return 1;
381        }
382
383        public abstract int byteLength();
384
385        public abstract <R,D> R accept(Visitor<R,D> visitor, D data);
386
387        protected final ConstantPool cp;
388    }
389
390    public static abstract class CPRefInfo extends CPInfo {
391        protected CPRefInfo(ConstantPool cp, ClassReader cr, int tag) throws IOException {
392            super(cp);
393            this.tag = tag;
394            class_index = cr.readUnsignedShort();
395            name_and_type_index = cr.readUnsignedShort();
396        }
397
398        protected CPRefInfo(ConstantPool cp, int tag, int class_index, int name_and_type_index) {
399            super(cp);
400            this.tag = tag;
401            this.class_index = class_index;
402            this.name_and_type_index = name_and_type_index;
403        }
404
405        public int getTag() {
406            return tag;
407        }
408
409        public int byteLength() {
410            return 5;
411        }
412
413        public CONSTANT_Class_info getClassInfo() throws ConstantPoolException {
414            return cp.getClassInfo(class_index);
415        }
416
417        public String getClassName() throws ConstantPoolException {
418            return cp.getClassInfo(class_index).getName();
419        }
420
421        public CONSTANT_NameAndType_info getNameAndTypeInfo() throws ConstantPoolException {
422            return cp.getNameAndTypeInfo(name_and_type_index);
423        }
424
425        public final int tag;
426        public final int class_index;
427        public final int name_and_type_index;
428    }
429
430    public static class CONSTANT_Class_info extends CPInfo {
431        CONSTANT_Class_info(ConstantPool cp, ClassReader cr) throws IOException {
432            super(cp);
433            name_index = cr.readUnsignedShort();
434        }
435
436        public CONSTANT_Class_info(ConstantPool cp, int name_index) {
437            super(cp);
438            this.name_index = name_index;
439        }
440
441        public int getTag() {
442            return CONSTANT_Class;
443        }
444
445        public int  byteLength() {
446            return 3;
447        }
448
449        /**
450         * Get the raw value of the class referenced by this constant pool entry.
451         * This will either be the name of the class, in internal form, or a
452         * descriptor for an array class.
453         * @return the raw value of the class
454         */
455        public String getName() throws ConstantPoolException {
456            return cp.getUTF8Value(name_index);
457        }
458
459        /**
460         * If this constant pool entry identifies either a class or interface type,
461         * or a possibly multi-dimensional array of a class of interface type,
462         * return the name of the class or interface in internal form. Otherwise,
463         * (i.e. if this is a possibly multi-dimensional array of a primitive type),
464         * return null.
465         * @return the base class or interface name
466         */
467        public String getBaseName() throws ConstantPoolException {
468            String name = getName();
469            if (name.startsWith("[")) {
470                int index = name.indexOf("[L");
471                if (index == -1)
472                    return null;
473                return name.substring(index + 2, name.length() - 1);
474            } else
475                return name;
476        }
477
478        public int getDimensionCount() throws ConstantPoolException {
479            String name = getName();
480            int count = 0;
481            while (name.charAt(count) == '[')
482                count++;
483            return count;
484        }
485
486        @Override
487        public String toString() {
488            return "CONSTANT_Class_info[name_index: " + name_index + "]";
489        }
490
491        public <R, D> R accept(Visitor<R, D> visitor, D data) {
492            return visitor.visitClass(this, data);
493        }
494
495        public final int name_index;
496    }
497
498    public static class CONSTANT_Double_info extends CPInfo {
499        CONSTANT_Double_info(ClassReader cr) throws IOException {
500            value = cr.readDouble();
501        }
502
503        public CONSTANT_Double_info(double value) {
504            this.value = value;
505        }
506
507        public int getTag() {
508            return CONSTANT_Double;
509        }
510
511        public int  byteLength() {
512            return 9;
513        }
514
515        @Override
516        public int size() {
517            return 2;
518        }
519
520        @Override
521        public String toString() {
522            return "CONSTANT_Double_info[value: " + value + "]";
523        }
524
525        public <R, D> R accept(Visitor<R, D> visitor, D data) {
526            return visitor.visitDouble(this, data);
527        }
528
529        public final double value;
530    }
531
532    public static class CONSTANT_Fieldref_info extends CPRefInfo {
533        CONSTANT_Fieldref_info(ConstantPool cp, ClassReader cr) throws IOException {
534            super(cp, cr, CONSTANT_Fieldref);
535        }
536
537        public CONSTANT_Fieldref_info(ConstantPool cp, int class_index, int name_and_type_index) {
538            super(cp, CONSTANT_Fieldref, class_index, name_and_type_index);
539        }
540
541        @Override
542        public String toString() {
543            return "CONSTANT_Fieldref_info[class_index: " + class_index + ", name_and_type_index: " + name_and_type_index + "]";
544        }
545
546        public <R, D> R accept(Visitor<R, D> visitor, D data) {
547            return visitor.visitFieldref(this, data);
548        }
549    }
550
551    public static class CONSTANT_Float_info extends CPInfo {
552        CONSTANT_Float_info(ClassReader cr) throws IOException {
553            value = cr.readFloat();
554        }
555
556        public CONSTANT_Float_info(float value) {
557            this.value = value;
558        }
559
560        public int getTag() {
561            return CONSTANT_Float;
562        }
563
564        public int byteLength() {
565            return 5;
566        }
567
568        @Override
569        public String toString() {
570            return "CONSTANT_Float_info[value: " + value + "]";
571        }
572
573        public <R, D> R accept(Visitor<R, D> visitor, D data) {
574            return visitor.visitFloat(this, data);
575        }
576
577        public final float value;
578    }
579
580    public static class CONSTANT_Integer_info extends CPInfo {
581        CONSTANT_Integer_info(ClassReader cr) throws IOException {
582            value = cr.readInt();
583        }
584
585        public CONSTANT_Integer_info(int value) {
586            this.value = value;
587        }
588
589        public int getTag() {
590            return CONSTANT_Integer;
591        }
592
593        public int byteLength() {
594            return 5;
595        }
596
597        @Override
598        public String toString() {
599            return "CONSTANT_Integer_info[value: " + value + "]";
600        }
601
602        public <R, D> R accept(Visitor<R, D> visitor, D data) {
603            return visitor.visitInteger(this, data);
604        }
605
606        public final int value;
607    }
608
609    public static class CONSTANT_InterfaceMethodref_info extends CPRefInfo {
610        CONSTANT_InterfaceMethodref_info(ConstantPool cp, ClassReader cr) throws IOException {
611            super(cp, cr, CONSTANT_InterfaceMethodref);
612        }
613
614        public CONSTANT_InterfaceMethodref_info(ConstantPool cp, int class_index, int name_and_type_index) {
615            super(cp, CONSTANT_InterfaceMethodref, class_index, name_and_type_index);
616        }
617
618        @Override
619        public String toString() {
620            return "CONSTANT_InterfaceMethodref_info[class_index: " + class_index + ", name_and_type_index: " + name_and_type_index + "]";
621        }
622
623        public <R, D> R accept(Visitor<R, D> visitor, D data) {
624            return visitor.visitInterfaceMethodref(this, data);
625        }
626    }
627
628    public static class CONSTANT_InvokeDynamic_info extends CPInfo {
629        CONSTANT_InvokeDynamic_info(ConstantPool cp, ClassReader cr) throws IOException {
630            super(cp);
631            bootstrap_method_attr_index = cr.readUnsignedShort();
632            name_and_type_index = cr.readUnsignedShort();
633        }
634
635        public CONSTANT_InvokeDynamic_info(ConstantPool cp, int bootstrap_method_index, int name_and_type_index) {
636            super(cp);
637            this.bootstrap_method_attr_index = bootstrap_method_index;
638            this.name_and_type_index = name_and_type_index;
639        }
640
641        public int getTag() {
642            return CONSTANT_InvokeDynamic;
643        }
644
645        public int byteLength() {
646            return 5;
647        }
648
649        @Override
650        public String toString() {
651            return "CONSTANT_InvokeDynamic_info[bootstrap_method_index: " + bootstrap_method_attr_index + ", name_and_type_index: " + name_and_type_index + "]";
652        }
653
654        public <R, D> R accept(Visitor<R, D> visitor, D data) {
655            return visitor.visitInvokeDynamic(this, data);
656        }
657
658        public CONSTANT_NameAndType_info getNameAndTypeInfo() throws ConstantPoolException {
659            return cp.getNameAndTypeInfo(name_and_type_index);
660        }
661
662        public final int bootstrap_method_attr_index;
663        public final int name_and_type_index;
664    }
665
666    public static class CONSTANT_Long_info extends CPInfo {
667        CONSTANT_Long_info(ClassReader cr) throws IOException {
668            value = cr.readLong();
669        }
670
671        public CONSTANT_Long_info(long value) {
672            this.value = value;
673        }
674
675        public int getTag() {
676            return CONSTANT_Long;
677        }
678
679        @Override
680        public int size() {
681            return 2;
682        }
683
684        public int byteLength() {
685            return 9;
686        }
687
688        @Override
689        public String toString() {
690            return "CONSTANT_Long_info[value: " + value + "]";
691        }
692
693        public <R, D> R accept(Visitor<R, D> visitor, D data) {
694            return visitor.visitLong(this, data);
695        }
696
697        public final long value;
698    }
699
700    public static class CONSTANT_MethodHandle_info extends CPInfo {
701        CONSTANT_MethodHandle_info(ConstantPool cp, ClassReader cr) throws IOException {
702            super(cp);
703            reference_kind =  RefKind.getRefkind(cr.readUnsignedByte());
704            reference_index = cr.readUnsignedShort();
705        }
706
707        public CONSTANT_MethodHandle_info(ConstantPool cp, RefKind ref_kind, int member_index) {
708            super(cp);
709            this.reference_kind = ref_kind;
710            this.reference_index = member_index;
711        }
712
713        public int getTag() {
714            return CONSTANT_MethodHandle;
715        }
716
717        public int byteLength() {
718            return 4;
719        }
720
721        @Override
722        public String toString() {
723            return "CONSTANT_MethodHandle_info[ref_kind: " + reference_kind + ", member_index: " + reference_index + "]";
724        }
725
726        public <R, D> R accept(Visitor<R, D> visitor, D data) {
727            return visitor.visitMethodHandle(this, data);
728        }
729
730        public CPRefInfo getCPRefInfo() throws ConstantPoolException {
731            int expected = CONSTANT_Methodref;
732            int actual = cp.get(reference_index).getTag();
733            // allow these tag types also:
734            switch (actual) {
735                case CONSTANT_Fieldref:
736                case CONSTANT_InterfaceMethodref:
737                    expected = actual;
738            }
739            return (CPRefInfo) cp.get(reference_index, expected);
740        }
741
742        public final RefKind reference_kind;
743        public final int reference_index;
744    }
745
746    public static class CONSTANT_MethodType_info extends CPInfo {
747        CONSTANT_MethodType_info(ConstantPool cp, ClassReader cr) throws IOException {
748            super(cp);
749            descriptor_index = cr.readUnsignedShort();
750        }
751
752        public CONSTANT_MethodType_info(ConstantPool cp, int signature_index) {
753            super(cp);
754            this.descriptor_index = signature_index;
755        }
756
757        public int getTag() {
758            return CONSTANT_MethodType;
759        }
760
761        public int byteLength() {
762            return 3;
763        }
764
765        @Override
766        public String toString() {
767            return "CONSTANT_MethodType_info[signature_index: " + descriptor_index + "]";
768        }
769
770        public <R, D> R accept(Visitor<R, D> visitor, D data) {
771            return visitor.visitMethodType(this, data);
772        }
773
774        public String getType() throws ConstantPoolException {
775            return cp.getUTF8Value(descriptor_index);
776        }
777
778        public final int descriptor_index;
779    }
780
781    public static class CONSTANT_Methodref_info extends CPRefInfo {
782        CONSTANT_Methodref_info(ConstantPool cp, ClassReader cr) throws IOException {
783            super(cp, cr, CONSTANT_Methodref);
784        }
785
786        public CONSTANT_Methodref_info(ConstantPool cp, int class_index, int name_and_type_index) {
787            super(cp, CONSTANT_Methodref, class_index, name_and_type_index);
788        }
789
790        @Override
791        public String toString() {
792            return "CONSTANT_Methodref_info[class_index: " + class_index + ", name_and_type_index: " + name_and_type_index + "]";
793        }
794
795        public <R, D> R accept(Visitor<R, D> visitor, D data) {
796            return visitor.visitMethodref(this, data);
797        }
798    }
799
800    public static class CONSTANT_Module_info extends CPInfo {
801        CONSTANT_Module_info(ConstantPool cp, ClassReader cr) throws IOException {
802            super(cp);
803            name_index = cr.readUnsignedShort();
804        }
805
806        public CONSTANT_Module_info(ConstantPool cp, int name_index) {
807            super(cp);
808            this.name_index = name_index;
809        }
810
811        public int getTag() {
812            return CONSTANT_Module;
813        }
814
815        public int  byteLength() {
816            return 3;
817        }
818
819        /**
820         * Get the raw value of the module name referenced by this constant pool entry.
821         * This will be the name of the module.
822         * @return the raw value of the module name
823         */
824        public String getName() throws ConstantPoolException {
825            return cp.getUTF8Value(name_index);
826        }
827
828        @Override
829        public String toString() {
830            return "CONSTANT_Module_info[name_index: " + name_index + "]";
831        }
832
833        public <R, D> R accept(Visitor<R, D> visitor, D data) {
834            return visitor.visitModule(this, data);
835        }
836
837        public final int name_index;
838    }
839
840    public static class CONSTANT_NameAndType_info extends CPInfo {
841        CONSTANT_NameAndType_info(ConstantPool cp, ClassReader cr) throws IOException {
842            super(cp);
843            name_index = cr.readUnsignedShort();
844            type_index = cr.readUnsignedShort();
845        }
846
847        public CONSTANT_NameAndType_info(ConstantPool cp, int name_index, int type_index) {
848            super(cp);
849            this.name_index = name_index;
850            this.type_index = type_index;
851        }
852
853        public int getTag() {
854            return CONSTANT_NameAndType;
855        }
856
857        public int byteLength() {
858            return 5;
859        }
860
861        public String getName() throws ConstantPoolException {
862            return cp.getUTF8Value(name_index);
863        }
864
865        public String getType() throws ConstantPoolException {
866            return cp.getUTF8Value(type_index);
867        }
868
869        public <R, D> R accept(Visitor<R, D> visitor, D data) {
870            return visitor.visitNameAndType(this, data);
871        }
872
873        @Override
874        public String toString() {
875            return "CONSTANT_NameAndType_info[name_index: " + name_index + ", type_index: " + type_index + "]";
876        }
877
878        public final int name_index;
879        public final int type_index;
880    }
881
882    public static class CONSTANT_Package_info extends CPInfo {
883        CONSTANT_Package_info(ConstantPool cp, ClassReader cr) throws IOException {
884            super(cp);
885            name_index = cr.readUnsignedShort();
886        }
887
888        public CONSTANT_Package_info(ConstantPool cp, int name_index) {
889            super(cp);
890            this.name_index = name_index;
891        }
892
893        public int getTag() {
894            return CONSTANT_Package;
895        }
896
897        public int  byteLength() {
898            return 3;
899        }
900
901        /**
902         * Get the raw value of the package name referenced by this constant pool entry.
903         * This will be the name of the package, in internal form.
904         * @return the raw value of the module name
905         */
906        public String getName() throws ConstantPoolException {
907            return cp.getUTF8Value(name_index);
908        }
909
910        @Override
911        public String toString() {
912            return "CONSTANT_Package_info[name_index: " + name_index + "]";
913        }
914
915        public <R, D> R accept(Visitor<R, D> visitor, D data) {
916            return visitor.visitPackage(this, data);
917        }
918
919        public final int name_index;
920    }
921
922    public static class CONSTANT_String_info extends CPInfo {
923        CONSTANT_String_info(ConstantPool cp, ClassReader cr) throws IOException {
924            super(cp);
925            string_index = cr.readUnsignedShort();
926        }
927
928        public CONSTANT_String_info(ConstantPool cp, int string_index) {
929            super(cp);
930            this.string_index = string_index;
931        }
932
933        public int getTag() {
934            return CONSTANT_String;
935        }
936
937        public int byteLength() {
938            return 3;
939        }
940
941        public String getString() throws ConstantPoolException {
942            return cp.getUTF8Value(string_index);
943        }
944
945        public <R, D> R accept(Visitor<R, D> visitor, D data) {
946            return visitor.visitString(this, data);
947        }
948
949        @Override
950        public String toString() {
951            return "CONSTANT_String_info[class_index: " + string_index + "]";
952        }
953
954        public final int string_index;
955    }
956
957    public static class CONSTANT_Utf8_info extends CPInfo {
958        CONSTANT_Utf8_info(ClassReader cr) throws IOException {
959            value = cr.readUTF();
960        }
961
962        public CONSTANT_Utf8_info(String value) {
963            this.value = value;
964        }
965
966        public int getTag() {
967            return CONSTANT_Utf8;
968        }
969
970        public int byteLength() {
971            class SizeOutputStream extends OutputStream {
972                @Override
973                public void write(int b) {
974                    size++;
975                }
976                int size;
977            }
978            SizeOutputStream sizeOut = new SizeOutputStream();
979            DataOutputStream out = new DataOutputStream(sizeOut);
980            try { out.writeUTF(value); } catch (IOException ignore) { }
981            return 1 + sizeOut.size;
982        }
983
984        @Override
985        public String toString() {
986            if (value.length() < 32 && isPrintableAscii(value))
987                return "CONSTANT_Utf8_info[value: \"" + value + "\"]";
988            else
989                return "CONSTANT_Utf8_info[value: (" + value.length() + " chars)]";
990        }
991
992        static boolean isPrintableAscii(String s) {
993            for (int i = 0; i < s.length(); i++) {
994                char c = s.charAt(i);
995                if (c < 32 || c >= 127)
996                    return false;
997            }
998            return true;
999        }
1000
1001        public <R, D> R accept(Visitor<R, D> visitor, D data) {
1002            return visitor.visitUtf8(this, data);
1003        }
1004
1005        public final String value;
1006    }
1007
1008}
1009