1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * https://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19 package org.apache.commons.compress.harmony.unpack200.bytecode;
20
21 import java.io.DataOutputStream;
22 import java.io.IOException;
23 import java.util.Objects;
24
25 /**
26 * Abstract superclass for class file attributes
27 */
28 public abstract class Attribute extends ClassFileEntry {
29
30 /**
31 * The attribute name.
32 */
33 protected final CPUTF8 attributeName;
34
35 private int attributeNameIndex;
36
37 /**
38 * Constructs a new instance for an attribute name.
39 *
40 * @param attributeName an attribute name.
41 */
42 public Attribute(final CPUTF8 attributeName) {
43 this.attributeName = attributeName;
44 }
45
46 @Override
47 protected void doWrite(final DataOutputStream dos) throws IOException {
48 dos.writeShort(attributeNameIndex);
49 dos.writeInt(getLength());
50 writeBody(dos);
51 }
52
53 @Override
54 public boolean equals(final Object obj) {
55 if (this == obj) {
56 return true;
57 }
58 if (obj == null || this.getClass() != obj.getClass()) {
59 return false;
60 }
61 final Attribute other = (Attribute) obj;
62 return Objects.equals(attributeName, other.attributeName);
63 }
64
65 /**
66 * Gets the attribute name.
67 *
68 * @return the attribute name.
69 */
70 protected CPUTF8 getAttributeName() {
71 return attributeName;
72 }
73
74 /**
75 * Gets the length.
76 *
77 * @return the length.
78 */
79 protected abstract int getLength();
80
81 /**
82 * Answer the length of the receiver including its header (the u2 for the attribute name and the u4 for the attribute length). This is relevant when
83 * attributes are nested within other attributes - the outer attribute needs to take the inner attribute headers into account when calculating its length.
84 *
85 * @return int adjusted length
86 */
87 protected int getLengthIncludingHeader() {
88 return getLength() + 2 + 4;
89 }
90
91 @Override
92 protected ClassFileEntry[] getNestedClassFileEntries() {
93 return new ClassFileEntry[] { getAttributeName() };
94 }
95
96 /**
97 * Answer true if the receiver needs to have BCI renumbering applied to it; otherwise answer false.
98 *
99 * @return boolean BCI renumbering required
100 */
101 public boolean hasBCIRenumbering() {
102 return false;
103 }
104
105 @Override
106 public int hashCode() {
107 return Objects.hash(attributeName);
108 }
109
110 /**
111 * Answer true if the receiver is a source file attribute (which gets special handling when the class is built); otherwise answer false.
112 *
113 * @return boolean source file attribute
114 */
115 public boolean isSourceFileAttribute() {
116 return false;
117 }
118
119 @Override
120 protected void resolve(final ClassConstantPool pool) {
121 super.resolve(pool);
122 attributeNameIndex = pool.indexOf(attributeName);
123 }
124
125 /**
126 * Writes this body to the given output stream.
127 *
128 * @param out the output stream.
129 * @throws IOException if an I/O error occurs.
130 */
131 protected abstract void writeBody(DataOutputStream out) throws IOException;
132
133 }