    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.ArrayList;
    024import java.util.List;
    025
    026/**
    027 * Inner classes class file attribute
    028 */
    029public class InnerClassesAttribute extends Attribute {
    030
    031    private static final class InnerClassesEntry {
    032
    033        CPClass innerClassInfo;
    034        CPClass outerClassInfo;
    035        CPUTF8 innerClassName;
    036
    037        int innerClassInfoIndex = -1;
    038        int outerClassInfoIndex = -1;
    039        int innerNameIndex = -1;
    040        int innerClassAccessFlags = -1;
    041
    042        InnerClassesEntry(final CPClass innerClass, final CPClass outerClass, final CPUTF8 innerName, final int flags) {
    043            this.innerClassInfo = innerClass;
    044            this.outerClassInfo = outerClass;
    045            this.innerClassName = innerName;
    046            this.innerClassAccessFlags = flags;
    047        }
    048
    049        /**
    050         * Determine the indices of the things in the receiver which point to elements of the ClassConstantPool
    051         *
    052         * @param pool ClassConstantPool which holds the CPClass and CPUTF8 objects.
    053         */
    054        public void resolve(final ClassConstantPool pool) {
    055            if (innerClassInfo != null) {
    056                innerClassInfo.resolve(pool);
    057                innerClassInfoIndex = pool.indexOf(innerClassInfo);
    058            } else {
    059                innerClassInfoIndex = 0;
    060            }
    061
    062            if (innerClassName != null) {
    063                innerClassName.resolve(pool);
    064                innerNameIndex = pool.indexOf(innerClassName);
    065            } else {
    066                innerNameIndex = 0;
    067            }
    068
    069            if (outerClassInfo != null) {
    070                outerClassInfo.resolve(pool);
    071                outerClassInfoIndex = pool.indexOf(outerClassInfo);
    072            } else {
    073                outerClassInfoIndex = 0;
    074            }
    075        }
    076
    077        public void write(final DataOutputStream dos) throws IOException {
    078            dos.writeShort(innerClassInfoIndex);
    079            dos.writeShort(outerClassInfoIndex);
    080            dos.writeShort(innerNameIndex);
    081            dos.writeShort(innerClassAccessFlags);
    082        }
    083
    084    }
    085
    086    private static CPUTF8 attributeName;
    087
    088    public static void setAttributeName(final CPUTF8 cpUTF8Value) {
    089        attributeName = cpUTF8Value;
    090    }
    091
    092    private final List<InnerClassesEntry> innerClasses = new ArrayList<>();
    093    private final List<ConstantPoolEntry> nestedClassFileEntries = new ArrayList<>();
    094
    095    public InnerClassesAttribute(final String name) {
    096        super(attributeName);
    097        nestedClassFileEntries.add(getAttributeName());
    098    }
    099
    100    public void addInnerClassesEntry(final CPClass innerClass, final CPClass outerClass, final CPUTF8 innerName, final int flags) {
    101        if (innerClass != null) {
    102            nestedClassFileEntries.add(innerClass);
    103        }
    104        if (outerClass != null) {
    105            nestedClassFileEntries.add(outerClass);
    106        }
    107        if (innerName != null) {
    108            nestedClassFileEntries.add(innerName);
    109        }
    110        addInnerClassesEntry(new InnerClassesEntry(innerClass, outerClass, innerName, flags));
    111    }
    112
    113    private void addInnerClassesEntry(final InnerClassesEntry innerClassesEntry) {
    114        innerClasses.add(innerClassesEntry);
    115    }
    116
    117    @Override
    118    public boolean equals(final Object obj) {
    119        if (this == obj) {
    120            return true;
    121        }
    122        if (!super.equals(obj) || this.getClass() != obj.getClass()) {
    123            return false;
    124        }
    125        final InnerClassesAttribute other = (InnerClassesAttribute) obj;
    126        if (getAttributeName() == null) {
    127            if (other.getAttributeName() != null) {
    128                return false;
    129            }
    130        } else if (!getAttributeName().equals(other.getAttributeName())) {
    131            return false;
    132        }
    133        return true;
    134    }
    135
    136    @Override
    137    protected int getLength() {
    138        return 2 + (2 + 2 + 2 + 2) * innerClasses.size();
    139    }
    140
    141    @Override
    142    protected ClassFileEntry[] getNestedClassFileEntries() {
    143        return nestedClassFileEntries.toArray(NONE);
    144    }
    145
    146    @Override
    147    public int hashCode() {
    148        final int PRIME = 31;
    149        int result = super.hashCode();
    150        result = PRIME * result + (getAttributeName() == null ? 0 : getAttributeName().hashCode());
    151        return result;
    152    }
    153
    154    @Override
    155    protected void resolve(final ClassConstantPool pool) {
    156        super.resolve(pool);
    157        for (final InnerClassesEntry entry : innerClasses) {
    158            entry.resolve(pool);
    159        }
    160    }
    161
    162    @Override
    163    public String toString() {
    164        return "InnerClasses: " + getAttributeName();
    165    }
    166
    167    @Override
    168    protected void writeBody(final DataOutputStream dos) throws IOException {
    169        dos.writeShort(innerClasses.size());
    170
    171        for (final InnerClassesEntry entry : innerClasses) {
    172            entry.write(dos);
    173        }
    174    }
    175}