1 /*
  2  * Copyright (c) 2019, 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 org.openjdk.asmtools.jasm.JasmTokens;
 26 import org.openjdk.asmtools.jasm.Tables;
 27 
 28 import java.io.DataInputStream;
 29 import java.io.IOException;
 30 import java.util.ArrayList;
 31 import java.util.List;
 32 
 33 import static java.lang.String.format;
 34 import static org.openjdk.asmtools.jasm.JasmTokens.Token.*;
 35 import static org.openjdk.asmtools.jdis.TraceUtils.traceln;
 36 
 37 /**
 38  * The Record attribute data
 39  * <p>
 40  * since class file 58.65535 (JEP 359)
 41  */
 42 public class RecordData extends  Indenter {
 43 
 44 
 45     private final ClassData cls;
 46     private List<Component> components;
 47 
 48     public RecordData(ClassData cls) {
 49         this.cls = cls;
 50     }
 51 
 52     public RecordData read(DataInputStream in) throws IOException {
 53         int count = in.readUnsignedShort();
 54         traceln("components=" + count);
 55         components = new ArrayList<>(count);
 56         for (int i = 0; i < count; i++) {
 57             components.add(new Component(cls).read(in));
 58         }
 59         return this;
 60     }
 61 
 62     /**
 63      * Prints the record data to the current output stream. called from ClassData.
 64      */
 65     public void print() throws IOException {
 66         int count = components.size();
 67         if (count > 0) {
 68             cls.out.println(getIndentString() + RECORD.parseKey() + getIndentString() + LBRACE.parseKey());
 69             for (int i = 0; i < count; i++) {
 70                 Component cn = components.get(i);
 71                 cn.setIndent(indent() * 2);
 72                 if (i != 0 && cn.getAnnotationsCount() > 0)
 73                     cn.out.println();
 74                 cn.print();
 75             }
 76             cls.out.println(getIndentString() + RBRACE.parseKey());
 77             cls.out.println();
 78         }
 79     }
 80 
 81     private class Component extends MemberData {
 82         // CP index to the name
 83         private int name_cpx;
 84         // CP index to the type descriptor
 85         private int type_cpx;
 86 
 87         public Component(ClassData cls) {
 88             super(cls);
 89             memberType = "RecordData";
 90         }
 91 
 92         @Override
 93         protected boolean handleAttributes(DataInputStream in, Tables.AttrTag attrtag, int attrlen) throws IOException {
 94             // Read the Attributes
 95             boolean handled = true;
 96             switch (attrtag) {
 97                 case ATT_Signature:
 98                     if( signature != null ) {
 99                         traceln("Record attribute:  more than one attribute Signature are in component.attribute_info_attributes[attribute_count]");
100                         traceln("Last one will be used.");
101                     }
102                     signature = new SignatureData(cls).read(in, attrlen);
103                     break;
104                 default:
105                     handled = false;
106                     break;
107             }
108             return handled;
109         }
110 
111         /**
112          * Read and resolve the component data called from ClassData.
113          */
114         public Component read(DataInputStream in) throws IOException {
115             // read the Component CP indexes
116             name_cpx = in.readUnsignedShort();
117             type_cpx = in.readUnsignedShort();
118             traceln(2, "RecordComponent: name[" + name_cpx + "]=" + cls.pool.getString(name_cpx)
119                     + " descriptor[" + type_cpx + "]=" + cls.pool.getString(type_cpx));
120             // Read the attributes
121             readAttributes(in);
122             return this;
123         }
124 
125         /**
126          * Prints the component data to the current output stream. called from RecordData.
127          */
128         public void print() throws IOException {
129             // print component's attributes
130                 super.printAnnotations(getIndentString());
131             // print component
132             StringBuilder bodyPrefix = new StringBuilder(getIndentString());
133             StringBuilder tailPrefix = new StringBuilder();
134             if (isSynthetic) {
135                 bodyPrefix.append(JasmTokens.Token.SYNTHETIC.parseKey()).append(' ');
136             }
137             if (isDeprecated) {
138                 bodyPrefix.append(JasmTokens.Token.DEPRECATED.parseKey()).append(' ');
139             }
140             // component
141             bodyPrefix.append(JasmTokens.Token.COMPONENT.parseKey()).append(' ');
142 
143             printVar(bodyPrefix, tailPrefix,name_cpx, type_cpx);
144         }
145     }
146 }