    001/*
    002 *  Licensed to the Apache Software Foundation (ASF) under one or more
    003 *  contributor license agreements.  See the NOTICE file distributed with
    004 *  this work for additional information regarding copyright ownership.
    005 *  The ASF licenses this file to You under the Apache License, Version 2.0
    006 *  (the "License"); you may not use this file except in compliance with
    007 *  the License.  You may obtain a copy of the License at
    008 *
    009 *     http://www.apache.org/licenses/LICENSE-2.0
    010 *
    011 *  Unless required by applicable law or agreed to in writing, software
    012 *  distributed under the License is distributed on an "AS IS" BASIS,
    013 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014 *  See the License for the specific language governing permissions and
    015 *  limitations under the License.
    016 */
    017package org.apache.commons.compress.harmony.unpack200.bytecode;
    018
    019import java.io.DataOutputStream;
    020import java.io.IOException;
    021import java.util.ArrayList;
    022import java.util.List;
    023
    024/**
    025 * Inner classes class file attribute
    026 */
    027public class InnerClassesAttribute extends Attribute {
    028
    029    private static CPUTF8 attributeName;
    030
    031    public static void setAttributeName(final CPUTF8 cpUTF8Value) {
    032        attributeName = cpUTF8Value;
    033    }
    034
    035    private static class InnerClassesEntry {
    036
    037        CPClass inner_class_info;
    038        CPClass outer_class_info;
    039        CPUTF8 inner_class_name;
    040
    041        int inner_class_info_index = -1;
    042        int outer_class_info_index = -1;
    043        int inner_name_index = -1;
    044        int inner_class_access_flags = -1;
    045
    046        public InnerClassesEntry(final CPClass innerClass, final CPClass outerClass, final CPUTF8 innerName,
    047            final int flags) {
    048            this.inner_class_info = innerClass;
    049            this.outer_class_info = outerClass;
    050            this.inner_class_name = innerName;
    051            this.inner_class_access_flags = flags;
    052        }
    053
    054        /**
    055         * Determine the indices of the things in the receiver which point to elements of the ClassConstantPool
    056         *
    057         * @param pool ClassConstantPool which holds the CPClass and CPUTF8 objects.
    058         */
    059        public void resolve(final ClassConstantPool pool) {
    060            if (inner_class_info != null) {
    061                inner_class_info.resolve(pool);
    062                inner_class_info_index = pool.indexOf(inner_class_info);
    063            } else {
    064                inner_class_info_index = 0;
    065            }
    066
    067            if (inner_class_name != null) {
    068                inner_class_name.resolve(pool);
    069                inner_name_index = pool.indexOf(inner_class_name);
    070            } else {
    071                inner_name_index = 0;
    072            }
    073
    074            if (outer_class_info != null) {
    075                outer_class_info.resolve(pool);
    076                outer_class_info_index = pool.indexOf(outer_class_info);
    077            } else {
    078                outer_class_info_index = 0;
    079            }
    080        }
    081
    082        public void write(final DataOutputStream dos) throws IOException {
    083            dos.writeShort(inner_class_info_index);
    084            dos.writeShort(outer_class_info_index);
    085            dos.writeShort(inner_name_index);
    086            dos.writeShort(inner_class_access_flags);
    087        }
    088
    089    }
    090
    091    private final List innerClasses = new ArrayList();
    092    private final List nestedClassFileEntries = new ArrayList();
    093
    094    public InnerClassesAttribute(final String name) {
    095        super(attributeName);
    096        nestedClassFileEntries.add(getAttributeName());
    097    }
    098
    099    @Override
    100    public boolean equals(final Object obj) {
    101        if (this == obj) {
    102            return true;
    103        }
    104        if (!super.equals(obj)) {
    105            return false;
    106        }
    107        if (this.getClass() != obj.getClass()) {
    108            return false;
    109        }
    110        final InnerClassesAttribute other = (InnerClassesAttribute) obj;
    111        if (getAttributeName() == null) {
    112            if (other.getAttributeName() != null) {
    113                return false;
    114            }
    115        } else if (!getAttributeName().equals(other.getAttributeName())) {
    116            return false;
    117        }
    118        return true;
    119    }
    120
    121    @Override
    122    protected int getLength() {
    123        return 2 + ((2 + 2 + 2 + 2) * innerClasses.size());
    124    }
    125
    126    @Override
    127    protected ClassFileEntry[] getNestedClassFileEntries() {
    128        final ClassFileEntry[] result = new ClassFileEntry[nestedClassFileEntries.size()];
    129        for (int index = 0; index < result.length; index++) {
    130            result[index] = (ClassFileEntry) nestedClassFileEntries.get(index);
    131        }
    132        return result;
    133    }
    134
    135    @Override
    136    public int hashCode() {
    137        final int PRIME = 31;
    138        int result = super.hashCode();
    139        result = PRIME * result + ((getAttributeName() == null) ? 0 : getAttributeName().hashCode());
    140        return result;
    141    }
    142
    143    @Override
    144    protected void resolve(final ClassConstantPool pool) {
    145        super.resolve(pool);
    146        for (int it = 0; it < innerClasses.size(); it++) {
    147            final InnerClassesEntry entry = (InnerClassesEntry) innerClasses.get(it);
    148            entry.resolve(pool);
    149        }
    150    }
    151
    152    @Override
    153    public String toString() {
    154        return "InnerClasses: " + getAttributeName();
    155    }
    156
    157    @Override
    158    protected void doWrite(final DataOutputStream dos) throws IOException {
    159        // Hack so I can see what's being written.
    160        super.doWrite(dos);
    161    }
    162
    163    @Override
    164    protected void writeBody(final DataOutputStream dos) throws IOException {
    165        dos.writeShort(innerClasses.size());
    166
    167        for (int it = 0; it < innerClasses.size(); it++) {
    168            final InnerClassesEntry entry = (InnerClassesEntry) innerClasses.get(it);
    169            entry.write(dos);
    170        }
    171    }
    172
    173    public void addInnerClassesEntry(final CPClass innerClass, final CPClass outerClass, final CPUTF8 innerName,
    174        final int flags) {
    175        if (innerClass != null) {
    176            nestedClassFileEntries.add(innerClass);
    177        }
    178        if (outerClass != null) {
    179            nestedClassFileEntries.add(outerClass);
    180        }
    181        if (innerName != null) {
    182            nestedClassFileEntries.add(innerName);
    183        }
    184        addInnerClassesEntry(new InnerClassesEntry(innerClass, outerClass, innerName, flags));
    185    }
    186
    187    private void addInnerClassesEntry(final InnerClassesEntry innerClassesEntry) {
    188        innerClasses.add(innerClassesEntry);
    189    }
    190}