    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}