View Javadoc
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  
21  import java.io.DataOutputStream;
22  import java.io.IOException;
23  import java.util.ArrayList;
24  import java.util.List;
25  
26  /**
27   * Inner classes class file attribute
28   */
29  public class InnerClassesAttribute extends Attribute {
30  
31      private static final class InnerClassesEntry {
32  
33          CPClass innerClassInfo;
34          CPClass outerClassInfo;
35          CPUTF8 innerClassName;
36  
37          int innerClassInfoIndex = -1;
38          int outerClassInfoIndex = -1;
39          int innerNameIndex = -1;
40          int innerClassAccessFlags = -1;
41  
42          InnerClassesEntry(final CPClass innerClass, final CPClass outerClass, final CPUTF8 innerName, final int flags) {
43              this.innerClassInfo = innerClass;
44              this.outerClassInfo = outerClass;
45              this.innerClassName = innerName;
46              this.innerClassAccessFlags = flags;
47          }
48  
49          /**
50           * Determine the indices of the things in the receiver which point to elements of the ClassConstantPool
51           *
52           * @param pool ClassConstantPool which holds the CPClass and CPUTF8 objects.
53           */
54          public void resolve(final ClassConstantPool pool) {
55              if (innerClassInfo != null) {
56                  innerClassInfo.resolve(pool);
57                  innerClassInfoIndex = pool.indexOf(innerClassInfo);
58              } else {
59                  innerClassInfoIndex = 0;
60              }
61  
62              if (innerClassName != null) {
63                  innerClassName.resolve(pool);
64                  innerNameIndex = pool.indexOf(innerClassName);
65              } else {
66                  innerNameIndex = 0;
67              }
68  
69              if (outerClassInfo != null) {
70                  outerClassInfo.resolve(pool);
71                  outerClassInfoIndex = pool.indexOf(outerClassInfo);
72              } else {
73                  outerClassInfoIndex = 0;
74              }
75          }
76  
77          public void write(final DataOutputStream dos) throws IOException {
78              dos.writeShort(innerClassInfoIndex);
79              dos.writeShort(outerClassInfoIndex);
80              dos.writeShort(innerNameIndex);
81              dos.writeShort(innerClassAccessFlags);
82          }
83  
84      }
85  
86      private static CPUTF8 attributeName;
87  
88      public static void setAttributeName(final CPUTF8 cpUTF8Value) {
89          attributeName = cpUTF8Value;
90      }
91  
92      private final List<InnerClassesEntry> innerClasses = new ArrayList<>();
93      private final List<ConstantPoolEntry> nestedClassFileEntries = new ArrayList<>();
94  
95      public InnerClassesAttribute(final String name) {
96          super(attributeName);
97          nestedClassFileEntries.add(getAttributeName());
98      }
99  
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 }