001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *   https://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied.  See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019package org.apache.commons.compress.harmony.unpack200.bytecode;
020
021import java.io.DataOutputStream;
022import java.io.IOException;
023import java.util.Objects;
024
025/**
026 * Abstract superclass for class file attributes
027 */
028public abstract class Attribute extends ClassFileEntry {
029
030    /**
031     * The attribute name.
032     */
033    protected final CPUTF8 attributeName;
034
035    private int attributeNameIndex;
036
037    /**
038     * Constructs a new instance for an attribute name.
039     *
040     * @param attributeName an attribute name.
041     */
042    public Attribute(final CPUTF8 attributeName) {
043        this.attributeName = attributeName;
044    }
045
046    @Override
047    protected void doWrite(final DataOutputStream dos) throws IOException {
048        dos.writeShort(attributeNameIndex);
049        dos.writeInt(getLength());
050        writeBody(dos);
051    }
052
053    @Override
054    public boolean equals(final Object obj) {
055        if (this == obj) {
056            return true;
057        }
058        if (obj == null || this.getClass() != obj.getClass()) {
059            return false;
060        }
061        final Attribute other = (Attribute) obj;
062        return Objects.equals(attributeName, other.attributeName);
063    }
064
065    /**
066     * Gets the attribute name.
067     *
068     * @return the attribute name.
069     */
070    protected CPUTF8 getAttributeName() {
071        return attributeName;
072    }
073
074    /**
075     * Gets the length.
076     *
077     * @return the length.
078     */
079    protected abstract int getLength();
080
081    /**
082     * 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
083     * attributes are nested within other attributes - the outer attribute needs to take the inner attribute headers into account when calculating its length.
084     *
085     * @return int adjusted length
086     */
087    protected int getLengthIncludingHeader() {
088        return getLength() + 2 + 4;
089    }
090
091    @Override
092    protected ClassFileEntry[] getNestedClassFileEntries() {
093        return new ClassFileEntry[] { getAttributeName() };
094    }
095
096    /**
097     * Answer true if the receiver needs to have BCI renumbering applied to it; otherwise answer false.
098     *
099     * @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}