1 /*
  2  * Copyright (c) 1996, 2020, 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.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12  * version 2 for more details (a copy is included in the LICENSE file that
 13  * accompanied this code).
 14  *
 15  * You should have received a copy of the GNU General Public License version
 16  * 2 along with this work; if not, write to the Free Software Foundation,
 17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 18  *
 19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  */
 23 package org.openjdk.asmtools.jdis;
 24 
 25 import static java.lang.String.format;
 26 import static org.openjdk.asmtools.jasm.Tables.*;
 27 import java.io.DataInputStream;
 28 import java.io.IOException;
 29 import java.io.PrintWriter;
 30 import java.util.ArrayList;
 31 
 32 /**
 33  * Base class of all AnnotationElement entries
 34  */
 35 public class AnnotationElement {
 36 
 37     /**
 38      *
 39      * CPX_AnnotElem
 40      *
 41      * base class for an annotation value.
 42      *
 43      */
 44     public static class AnnotValue {
 45 
 46         /**
 47          * tag the descriptor for the constant
 48          */
 49         public AnnotElemType tag;
 50 
 51         // internal references
 52         protected ClassData cls;
 53 
 54         public AnnotValue(AnnotElemType tagval, ClassData cls) {
 55             tag = tagval;
 56             this.cls = cls;
 57         }
 58 
 59         public String stringVal() {
 60             return "";
 61         }
 62 
 63         public void print(PrintWriter out, String tab) {
 64             out.print(tag.val() + "  ");
 65         }
 66 
 67         @Override
 68         public String toString() {
 69             return "<AnnotValue " + tag.printval() + " " + stringVal() + ">";
 70         }
 71     }
 72 
 73     /**
 74      *
 75      * CPX_AnnotElem
 76      *
 77      * Annotation value which is described by a single CPX entry (ie. String, byte, char,
 78      * int, short, boolean, float, long, double, class reference).
 79      *
 80      */
 81     public static class CPX_AnnotValue extends AnnotValue {
 82 
 83         /**
 84          * tag the descriptor for the constant
 85          */
 86         public int cpx;
 87 
 88         public CPX_AnnotValue(AnnotElemType tag, ClassData cls, int cpx) {
 89             super(tag, cls);
 90             this.cpx = cpx;
 91         }
 92 
 93         @Override
 94         public String stringVal() {
 95             StringBuilder sb = new StringBuilder();
 96             switch (tag) {
 97                 case AE_STRING:    // String
 98                     sb.append('"' + cls.pool.getString(cpx) + '"');
 99                     break;
100                 case AE_BYTE:    // Byte
101                     sb.append("byte " + cls.pool.getConst(cpx).stringVal());
102                     break;
103                 case AE_CHAR:    // Char
104                     sb.append("char " + cls.pool.getConst(cpx).stringVal());
105                     break;
106                 case AE_INT:    // Int  (no need to add keyword)
107                     sb.append(cls.pool.getConst(cpx).stringVal());
108                     break;
109                 case AE_SHORT:    // Short
110                     sb.append("short " + cls.pool.getConst(cpx).stringVal());
111                     break;
112                 case AE_BOOLEAN:    // Boolean
113                     ConstantPool.CP_Int cns = (ConstantPool.CP_Int) cls.pool.getConst(cpx);
114                     sb.append("boolean " + (cns.value == 0 ? "false" : "true"));
115                     break;
116                 case AE_FLOAT:    // Float
117                     sb.append(cls.pool.getConst(cpx).stringVal()); // + "f");
118                     break;
119                 case AE_DOUBLE:    // Double
120                     sb.append(cls.pool.getConst(cpx).stringVal()); // + "d");
121                     break;
122                 case AE_LONG:    // Long
123                     sb.append(cls.pool.getConst(cpx).stringVal()); // + "l");
124                     break;
125                 case AE_CLASS:    // Class
126                     sb.append("class " + cls.pool.decodeClassDescriptor(cpx));
127                     break;
128                 default:
129                     break;
130             }
131             return sb.toString();
132         }
133 
134         @Override
135         public void print(PrintWriter out, String tab) {
136             out.print(tab + stringVal());
137         }
138 
139         @Override
140         public String toString() {
141             return "<CPX_AnnotValue tag: '" + tag + "' stringVal=" + this.stringVal() + ">";
142         }
143     }
144 
145     /**
146      *
147      * CPX_AnnotElem
148      *
149      * AnnotElements that contain 2 cpx indices (ie. enums).
150      *
151      */
152     public static class CPX2_AnnotValue extends AnnotValue {
153 
154         /**
155          * tag the descriptor for the constant
156          */
157         public int cpx1;
158         public int cpx2;
159 
160         public CPX2_AnnotValue(AnnotElemType tag, ClassData cls, int cpx1, int cpx2) {
161             super(tag, cls);
162             this.cpx1 = cpx1;
163             this.cpx2 = cpx2;
164         }
165 
166         @Override
167         public String stringVal() {
168             StringBuilder sb = new StringBuilder();
169             switch (tag) {
170 
171                 case AE_ENUM:    // Enum
172                     // print the enum type and constant name
173                     sb.append("enum " + cls.pool.decodeClassDescriptor(cpx1)
174                             + " " + cls.pool.getName(cpx2));
175                     break;
176                 default:
177                     break;
178             }
179             return sb.toString();
180         }
181 
182         @Override
183         public void print(PrintWriter out, String tab) {
184             out.print(tab + stringVal());
185         }
186 
187         @Override
188         public String toString() {
189             return "<CPX2_AnnotValue tag: '" + tag + "' stringVal=" + this.stringVal() + ">";
190         }
191     }
192 
193     /**
194      *
195      * Array_AnnotElem
196      *
197      * Annotation value that is an array of annotation elements.
198      *
199      */
200     public static class Array_AnnotValue extends AnnotValue {
201 
202         /**
203          * tag the descriptor for the constant
204          */
205         public ArrayList<AnnotValue> array = new ArrayList<>();
206 
207         public Array_AnnotValue(AnnotElemType tagval, ClassData cls) {
208             super(tagval, cls);
209         }
210 
211         @Override
212         public String stringVal() {
213             StringBuilder sb = new StringBuilder();
214             sb.append(super.stringVal() + " = ");
215             sb.append("{");
216             int i = 0;
217             int cnt = array.size();
218             for (AnnotValue arrayelem : array) {
219                 sb.append(arrayelem.toString());
220                 if (i < cnt - 1) {
221                     sb.append(",");
222                 }
223             }
224             sb.append("}");
225             return sb.toString();
226         }
227 
228         public void add(AnnotValue elem) {
229             array.add(elem);
230         }
231 
232         @Override
233         public void print(PrintWriter out, String tab) {
234             out.println("{");
235             int i = 0;
236             int cnt = array.size();
237             for (AnnotValue arrayelem : array) {
238                 arrayelem.print(out, tab + "  ");
239                 if (i < cnt - 1) {
240                     out.println(",");
241                 }
242                 i += 1;
243             }
244             out.println("}");
245         }
246 
247         @Override
248         public String toString() {
249             return "<Array_AnnotValue " + tag + " " + stringVal() + ">";
250         }
251     }
252 
253     /**
254      *
255      * Annot_AnnotValue
256      *
257      * Annotation value that is a reference to an annotation.
258      *
259      */
260     public static class Annot_AnnotValue extends AnnotValue {
261 
262         /**
263          * tag the descriptor for the constant
264          */
265         AnnotationData annot;
266 
267         public Annot_AnnotValue(AnnotElemType tagval, ClassData cls, AnnotationData annot) {
268             super(tagval, cls);
269             this.annot = annot;
270         }
271 
272         @Override
273         public String stringVal() {
274             return annot.toString();
275         }
276 
277         @Override
278         public void print(PrintWriter out, String tab) {
279 //            out.print(tag + "\t");
280             annot.print(out, tab);
281         }
282 
283         @Override
284         public String toString() {
285             return "<Annot_AnnotValue " + tag + " " + stringVal() + ">";
286         }
287     }
288 
289     /*========================================================*/
290     /* Factory Method */
291     /**
292      *
293      * read
294      *
295      * Static factory - creates Annotation Elements.
296      *
297      */
298     public static AnnotValue readValue(DataInputStream in, ClassData cls, boolean invisible) throws IOException {
299         AnnotValue val = null;
300         char tg = (char) in.readByte();
301         AnnotElemType tag = annotElemType(tg);
302 
303         switch (tag) {
304             case AE_STRING:     // String
305             case AE_BYTE:       // Byte
306             case AE_CHAR:       // Char
307             case AE_INT:        // Int  (no need to add keyword)
308             case AE_SHORT:      // Short
309             case AE_BOOLEAN:    // Boolean
310             case AE_FLOAT:      // Float
311             case AE_DOUBLE:     // Double
312             case AE_LONG:       // Long
313             case AE_CLASS:      // Class
314                 // CPX based Annotation
315                 int CPX = in.readShort();
316                 val = new CPX_AnnotValue(tag, cls, CPX);
317                 break;
318             case AE_ENUM:    // Enum
319                 // CPX2 based Annotation
320                 int CPX1 = in.readShort();
321                 int CPX2 = in.readShort();
322                 val = new CPX2_AnnotValue(tag, cls, CPX1, CPX2);
323                 break;
324             case AE_ANNOTATION:    // Annotation
325                 AnnotationData ad = new AnnotationData(invisible, cls);
326                 ad.read(in);
327                 val = new Annot_AnnotValue(tag, cls, ad);
328                 break;
329             case AE_ARRAY:    // Array
330                 Array_AnnotValue aelem = new Array_AnnotValue(tag, cls);
331                 val = aelem;
332                 int cnt = in.readShort();
333                 for (int i = 0; i < cnt; i++) {
334                     aelem.add(readValue(in, cls, invisible));
335                 }
336                 break;
337             default:
338                 throw new IOException("Unknown tag in annotation '" + tg + "' [" + Integer.toHexString(tg) + "]");
339         }
340 
341         return val;
342     }
343 
344     /*========================================================*/
345 
346     /*-------------------------------------------------------- */
347     /* AnnotElem Fields */
348     /**
349      * constant pool index for the name of the Annotation Element
350      */
351     public int name_cpx;
352 
353     public AnnotValue value = null;
354 
355     // internal references
356     protected ClassData cls;
357     /*-------------------------------------------------------- */
358 
359     public AnnotationElement(ClassData cls) {
360         this.cls = cls;
361     }
362 
363     /**
364      *
365      * read
366      *
367      * read and resolve the method data called from ClassData. precondition: NumFields has
368      * already been read from the stream.
369      *
370      */
371     public void read(DataInputStream in, boolean invisible) throws IOException {
372         name_cpx = in.readShort();
373         value = readValue(in, cls, invisible);
374         TraceUtils.traceln(format("                   AnnotElem: name[%d]=%s value=%s", name_cpx, cls.pool.getString(name_cpx), value.toString()));
375     }
376 
377     public String stringVal() {
378         return cls.pool.getName(name_cpx);
379     }
380 
381     public void print(PrintWriter out, String tab) {
382         out.print(stringVal() + " = ");
383         value.print(out, "");
384     }
385 
386     @Override
387     public String toString() {
388         return "<AnnotElem " + stringVal() + " = " + value.toString() + ">";
389     }
390 }