InnerClassesAttribute.java

  1. /*
  2.  *  Licensed to the Apache Software Foundation (ASF) under one or more
  3.  *  contributor license agreements.  See the NOTICE file distributed with
  4.  *  this work for additional information regarding copyright ownership.
  5.  *  The ASF licenses this file to You under the Apache License, Version 2.0
  6.  *  (the "License"); you may not use this file except in compliance with
  7.  *  the License.  You may obtain a copy of the License at
  8.  *
  9.  *     http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  *  Unless required by applicable law or agreed to in writing, software
  12.  *  distributed under the License is distributed on an "AS IS" BASIS,
  13.  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  *  See the License for the specific language governing permissions and
  15.  *  limitations under the License.
  16.  */
  17. package org.apache.commons.compress.harmony.unpack200.bytecode;

  18. import java.io.DataOutputStream;
  19. import java.io.IOException;
  20. import java.util.ArrayList;
  21. import java.util.List;

  22. /**
  23.  * Inner classes class file attribute
  24.  */
  25. public class InnerClassesAttribute extends Attribute {

  26.     private static final class InnerClassesEntry {

  27.         CPClass innerClassInfo;
  28.         CPClass outerClassInfo;
  29.         CPUTF8 innerClassName;

  30.         int innerClassInfoIndex = -1;
  31.         int outerClassInfoIndex = -1;
  32.         int innerNameIndex = -1;
  33.         int innerClassAccessFlags = -1;

  34.         InnerClassesEntry(final CPClass innerClass, final CPClass outerClass, final CPUTF8 innerName, final int flags) {
  35.             this.innerClassInfo = innerClass;
  36.             this.outerClassInfo = outerClass;
  37.             this.innerClassName = innerName;
  38.             this.innerClassAccessFlags = flags;
  39.         }

  40.         /**
  41.          * Determine the indices of the things in the receiver which point to elements of the ClassConstantPool
  42.          *
  43.          * @param pool ClassConstantPool which holds the CPClass and CPUTF8 objects.
  44.          */
  45.         public void resolve(final ClassConstantPool pool) {
  46.             if (innerClassInfo != null) {
  47.                 innerClassInfo.resolve(pool);
  48.                 innerClassInfoIndex = pool.indexOf(innerClassInfo);
  49.             } else {
  50.                 innerClassInfoIndex = 0;
  51.             }

  52.             if (innerClassName != null) {
  53.                 innerClassName.resolve(pool);
  54.                 innerNameIndex = pool.indexOf(innerClassName);
  55.             } else {
  56.                 innerNameIndex = 0;
  57.             }

  58.             if (outerClassInfo != null) {
  59.                 outerClassInfo.resolve(pool);
  60.                 outerClassInfoIndex = pool.indexOf(outerClassInfo);
  61.             } else {
  62.                 outerClassInfoIndex = 0;
  63.             }
  64.         }

  65.         public void write(final DataOutputStream dos) throws IOException {
  66.             dos.writeShort(innerClassInfoIndex);
  67.             dos.writeShort(outerClassInfoIndex);
  68.             dos.writeShort(innerNameIndex);
  69.             dos.writeShort(innerClassAccessFlags);
  70.         }

  71.     }

  72.     private static CPUTF8 attributeName;

  73.     public static void setAttributeName(final CPUTF8 cpUTF8Value) {
  74.         attributeName = cpUTF8Value;
  75.     }

  76.     private final List<InnerClassesEntry> innerClasses = new ArrayList<>();
  77.     private final List<ConstantPoolEntry> nestedClassFileEntries = new ArrayList<>();

  78.     public InnerClassesAttribute(final String name) {
  79.         super(attributeName);
  80.         nestedClassFileEntries.add(getAttributeName());
  81.     }

  82.     public void addInnerClassesEntry(final CPClass innerClass, final CPClass outerClass, final CPUTF8 innerName, final int flags) {
  83.         if (innerClass != null) {
  84.             nestedClassFileEntries.add(innerClass);
  85.         }
  86.         if (outerClass != null) {
  87.             nestedClassFileEntries.add(outerClass);
  88.         }
  89.         if (innerName != null) {
  90.             nestedClassFileEntries.add(innerName);
  91.         }
  92.         addInnerClassesEntry(new InnerClassesEntry(innerClass, outerClass, innerName, flags));
  93.     }

  94.     private void addInnerClassesEntry(final InnerClassesEntry innerClassesEntry) {
  95.         innerClasses.add(innerClassesEntry);
  96.     }

  97.     @Override
  98.     public boolean equals(final Object obj) {
  99.         if (this == obj) {
  100.             return true;
  101.         }
  102.         if (!super.equals(obj)) {
  103.             return false;
  104.         }
  105.         if (this.getClass() != obj.getClass()) {
  106.             return false;
  107.         }
  108.         final InnerClassesAttribute other = (InnerClassesAttribute) obj;
  109.         if (getAttributeName() == null) {
  110.             if (other.getAttributeName() != null) {
  111.                 return false;
  112.             }
  113.         } else if (!getAttributeName().equals(other.getAttributeName())) {
  114.             return false;
  115.         }
  116.         return true;
  117.     }

  118.     @Override
  119.     protected int getLength() {
  120.         return 2 + (2 + 2 + 2 + 2) * innerClasses.size();
  121.     }

  122.     @Override
  123.     protected ClassFileEntry[] getNestedClassFileEntries() {
  124.         return nestedClassFileEntries.toArray(NONE);
  125.     }

  126.     @Override
  127.     public int hashCode() {
  128.         final int PRIME = 31;
  129.         int result = super.hashCode();
  130.         result = PRIME * result + (getAttributeName() == null ? 0 : getAttributeName().hashCode());
  131.         return result;
  132.     }

  133.     @Override
  134.     protected void resolve(final ClassConstantPool pool) {
  135.         super.resolve(pool);
  136.         for (final InnerClassesEntry entry : innerClasses) {
  137.             entry.resolve(pool);
  138.         }
  139.     }

  140.     @Override
  141.     public String toString() {
  142.         return "InnerClasses: " + getAttributeName();
  143.     }

  144.     @Override
  145.     protected void writeBody(final DataOutputStream dos) throws IOException {
  146.         dos.writeShort(innerClasses.size());

  147.         for (final InnerClassesEntry entry : innerClasses) {
  148.             entry.write(dos);
  149.         }
  150.     }
  151. }