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.Collections;
024import java.util.List;
025import java.util.Objects;
026
027/**
028 * Superclass for member constant pool entries, such as fields or methods.
029 */
030public class CPMember extends ClassFileEntry {
031
032    List<Attribute> attributes;
033    short flags;
034    CPUTF8 name;
035    transient int nameIndex;
036    protected final CPUTF8 descriptor;
037    transient int descriptorIndex;
038
039    /**
040     * Constructs a new CPMember.
041     *
042     * @param name       TODO
043     * @param descriptor TODO
044     * @param flags      TODO
045     * @param attributes TODO
046     * @throws NullPointerException if name or descriptor is null
047     */
048    public CPMember(final CPUTF8 name, final CPUTF8 descriptor, final long flags, final List<Attribute> attributes) {
049        this.name = Objects.requireNonNull(name, "name");
050        this.descriptor = Objects.requireNonNull(descriptor, "descriptor");
051        this.flags = (short) flags;
052        this.attributes = attributes == null ? Collections.EMPTY_LIST : attributes;
053    }
054
055    @Override
056    protected void doWrite(final DataOutputStream dos) throws IOException {
057        dos.writeShort(flags);
058        dos.writeShort(nameIndex);
059        dos.writeShort(descriptorIndex);
060        final int attributeCount = attributes.size();
061        dos.writeShort(attributeCount);
062        for (int i = 0; i < attributeCount; i++) {
063            final Attribute attribute = attributes.get(i);
064            attribute.doWrite(dos);
065        }
066    }
067
068    @Override
069    public boolean equals(final Object obj) {
070        if (this == obj) {
071            return true;
072        }
073        if (obj == null || getClass() != obj.getClass()) {
074            return false;
075        }
076        final CPMember other = (CPMember) obj;
077        return Objects.equals(attributes, other.attributes)
078                && Objects.equals(descriptor, other.descriptor)
079                && flags == other.flags
080                && Objects.equals(name, other.name);
081    }
082
083    @Override
084    protected ClassFileEntry[] getNestedClassFileEntries() {
085        final int attributeCount = attributes.size();
086        final ClassFileEntry[] entries = new ClassFileEntry[attributeCount + 2];
087        entries[0] = name;
088        entries[1] = descriptor;
089        for (int i = 0; i < attributeCount; i++) {
090            entries[i + 2] = attributes.get(i);
091        }
092        return entries;
093    }
094
095    @Override
096    public int hashCode() {
097        final int PRIME = 31;
098        int result = 1;
099        result = PRIME * result + attributes.hashCode();
100        result = PRIME * result + descriptor.hashCode();
101        result = PRIME * result + flags;
102        result = PRIME * result + name.hashCode();
103        return result;
104    }
105
106    @Override
107    protected void resolve(final ClassConstantPool pool) {
108        super.resolve(pool);
109        nameIndex = pool.indexOf(name);
110        descriptorIndex = pool.indexOf(descriptor);
111        attributes.forEach(attribute -> attribute.resolve(pool));
112    }
113
114    @Override
115    public String toString() {
116        return "CPMember: " + name + "(" + descriptor + ")";
117    }
118
119}