1/*
2 * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
3 */
4/*
5 * Licensed to the Apache Software Foundation (ASF) under one or more
6 * contributor license agreements.  See the NOTICE file distributed with
7 * this work for additional information regarding copyright ownership.
8 * The ASF licenses this file to You under the Apache License, Version 2.0
9 * (the "License"); you may not use this file except in compliance with
10 * the License.  You may obtain a copy of the License at
11 *
12 *      http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 */
20package com.sun.org.apache.bcel.internal.classfile;
21
22import java.io.DataInput;
23import java.io.DataInputStream;
24import java.io.DataOutputStream;
25import java.io.IOException;
26
27import com.sun.org.apache.bcel.internal.Const;
28
29/**
30 * Abstract super class for fields and methods.
31 *
32 * @version $Id: FieldOrMethod.java 1750029 2016-06-23 22:14:38Z sebb $
33 */
34public abstract class FieldOrMethod extends AccessFlags implements Cloneable, Node {
35    private int name_index; // Points to field name in constant pool
36    private int signature_index; // Points to encoded signature
37    private Attribute[] attributes; // Collection of attributes
38    private int attributes_count; // No. of attributes
39
40    // @since 6.0
41    private AnnotationEntry[] annotationEntries; // annotations defined on the field or method
42
43    private ConstantPool constant_pool;
44
45    private String signatureAttributeString = null;
46    private boolean searchedForSignatureAttribute = false;
47
48    FieldOrMethod() {
49    }
50
51    /**
52     * Initialize from another object. Note that both objects use the same
53     * references (shallow copy). Use clone() for a physical copy.
54     */
55    protected FieldOrMethod(final FieldOrMethod c) {
56        this(c.getAccessFlags(), c.getNameIndex(), c.getSignatureIndex(),
57                c.getAttributes(), c.getConstantPool());
58    }
59
60    /**
61     * Construct object from file stream.
62     *
63     * @param file Input stream
64     * @throws IOException
65     * @throws ClassFormatException
66     * @deprecated (6.0) Use
67     * {@link #FieldOrMethod(java.io.DataInput, ConstantPool)} instead.
68     */
69    @java.lang.Deprecated
70    protected FieldOrMethod(final DataInputStream file,
71            final ConstantPool constant_pool) throws IOException,
72            ClassFormatException {
73        this((DataInput) file, constant_pool);
74    }
75
76    /**
77     * Construct object from file stream.
78     *
79     * @param file Input stream
80     * @throws IOException
81     * @throws ClassFormatException
82     */
83    protected FieldOrMethod(final DataInput file,
84            final ConstantPool constant_pool) throws IOException, ClassFormatException {
85        this(file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort(), null,
86                constant_pool);
87        attributes_count = file.readUnsignedShort();
88        attributes = new Attribute[attributes_count];
89        for (int i = 0; i < attributes_count; i++) {
90            attributes[i] = Attribute.readAttribute(file, constant_pool);
91        }
92    }
93
94    /**
95     * @param access_flags Access rights of method
96     * @param name_index Points to field name in constant pool
97     * @param signature_index Points to encoded signature
98     * @param attributes Collection of attributes
99     * @param constant_pool Array of constants
100     */
101    protected FieldOrMethod(final int access_flags, final int name_index, final int signature_index,
102            final Attribute[] attributes, final ConstantPool constant_pool) {
103        super(access_flags);
104        this.name_index = name_index;
105        this.signature_index = signature_index;
106        this.constant_pool = constant_pool;
107        setAttributes(attributes);
108    }
109
110    /**
111     * Dump object to file stream on binary format.
112     *
113     * @param file Output file stream
114     * @throws IOException
115     */
116    public final void dump(final DataOutputStream file) throws IOException {
117        file.writeShort(super.getAccessFlags());
118        file.writeShort(name_index);
119        file.writeShort(signature_index);
120        file.writeShort(attributes_count);
121
122        for(int i=0; i < attributes_count; i++) {
123            attributes[i].dump(file);
124        }
125    }
126
127    /**
128     * @return Collection of object attributes.
129     */
130    public final Attribute[] getAttributes() {
131        return attributes;
132    }
133
134    /**
135     * @param attributes Collection of object attributes.
136     */
137    public final void setAttributes(final Attribute[] attributes) {
138        this.attributes = attributes;
139        this.attributes_count = attributes != null ? attributes.length : 0;
140    }
141
142    /**
143     * @return Constant pool used by this object.
144     */
145    public final ConstantPool getConstantPool() {
146        return constant_pool;
147    }
148
149    /**
150     * @param constant_pool Constant pool to be used for this object.
151     */
152    public final void setConstantPool(final ConstantPool constant_pool) {
153        this.constant_pool = constant_pool;
154    }
155
156    /**
157     * @return Index in constant pool of object's name.
158     */
159    public final int getNameIndex() {
160        return name_index;
161    }
162
163    /**
164     * @param name_index Index in constant pool of object's name.
165     */
166    public final void setNameIndex(final int name_index) {
167        this.name_index = name_index;
168    }
169
170    /**
171     * @return Index in constant pool of field signature.
172     */
173    public final int getSignatureIndex() {
174        return signature_index;
175    }
176
177    /**
178     * @param signature_index Index in constant pool of field signature.
179     */
180    public final void setSignatureIndex(final int signature_index) {
181        this.signature_index = signature_index;
182    }
183
184    /**
185     * @return Name of object, i.e., method name or field name
186     */
187    public final String getName() {
188        ConstantUtf8 c;
189        c = (ConstantUtf8) constant_pool.getConstant(name_index, Const.CONSTANT_Utf8);
190        return c.getBytes();
191    }
192
193    /**
194     * @return String representation of object's type signature (java style)
195     */
196    public final String getSignature() {
197        ConstantUtf8 c;
198        c = (ConstantUtf8) constant_pool.getConstant(signature_index, Const.CONSTANT_Utf8);
199        return c.getBytes();
200    }
201
202    /**
203     * @return deep copy of this field
204     */
205    protected FieldOrMethod copy_(final ConstantPool _constant_pool) {
206        FieldOrMethod c = null;
207
208        try {
209            c = (FieldOrMethod) clone();
210        } catch (final CloneNotSupportedException e) {
211            // ignored, but will cause NPE ...
212        }
213
214        c.constant_pool = constant_pool;
215        c.attributes = new Attribute[attributes_count];
216        c.attributes_count = attributes_count;
217
218        for (int i = 0; i < attributes_count; i++) {
219            c.attributes[i] = attributes[i].copy(constant_pool);
220        }
221
222        return c;
223    }
224
225    /**
226     * @return Annotations on the field or method
227     * @since 6.0
228     */
229    public AnnotationEntry[] getAnnotationEntries() {
230        if (annotationEntries == null) {
231            annotationEntries = AnnotationEntry.createAnnotationEntries(getAttributes());
232        }
233
234        return annotationEntries;
235    }
236
237    /**
238     * Hunts for a signature attribute on the member and returns its contents.
239     * So where the 'regular' signature may be (Ljava/util/Vector;)V the
240     * signature attribute may in fact say
241     * 'Ljava/lang/Vector&lt;Ljava/lang/String&gt;;' Coded for performance -
242     * searches for the attribute only when requested - only searches for it
243     * once.
244     *
245     * @since 6.0
246     */
247    public final String getGenericSignature() {
248        if (!searchedForSignatureAttribute) {
249            boolean found = false;
250            for (int i = 0; !found && i < attributes.length; i++) {
251                if (attributes[i] instanceof Signature) {
252                    signatureAttributeString = ((Signature) attributes[i])
253                            .getSignature();
254                    found = true;
255                }
256            }
257            searchedForSignatureAttribute = true;
258        }
259        return signatureAttributeString;
260    }
261}
262