InnerClassesAttribute.java

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

  20. import java.io.DataOutputStream;
  21. import java.io.IOException;
  22. import java.util.ArrayList;
  23. import java.util.List;

  24. /**
  25.  * Inner classes class file attribute
  26.  */
  27. public class InnerClassesAttribute extends Attribute {

  28.     private static final class InnerClassesEntry {

  29.         CPClass innerClassInfo;
  30.         CPClass outerClassInfo;
  31.         CPUTF8 innerClassName;

  32.         int innerClassInfoIndex = -1;
  33.         int outerClassInfoIndex = -1;
  34.         int innerNameIndex = -1;
  35.         int innerClassAccessFlags = -1;

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

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

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

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

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

  73.     }

  74.     private static CPUTF8 attributeName;

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

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

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

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

  96.     private void addInnerClassesEntry(final InnerClassesEntry innerClassesEntry) {
  97.         innerClasses.add(innerClassesEntry);
  98.     }

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

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

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

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

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

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

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

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