View Javadoc
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  
19  import java.io.DataOutputStream;
20  import java.io.IOException;
21  import java.util.ArrayList;
22  import java.util.List;
23  
24  /**
25   * Inner classes class file attribute
26   */
27  public class InnerClassesAttribute extends Attribute {
28  
29      private static final class InnerClassesEntry {
30  
31          CPClass innerClassInfo;
32          CPClass outerClassInfo;
33          CPUTF8 innerClassName;
34  
35          int innerClassInfoIndex = -1;
36          int outerClassInfoIndex = -1;
37          int innerNameIndex = -1;
38          int innerClassAccessFlags = -1;
39  
40          InnerClassesEntry(final CPClass innerClass, final CPClass outerClass, final CPUTF8 innerName, final int flags) {
41              this.innerClassInfo = innerClass;
42              this.outerClassInfo = outerClass;
43              this.innerClassName = innerName;
44              this.innerClassAccessFlags = flags;
45          }
46  
47          /**
48           * Determine the indices of the things in the receiver which point to elements of the ClassConstantPool
49           *
50           * @param pool ClassConstantPool which holds the CPClass and CPUTF8 objects.
51           */
52          public void resolve(final ClassConstantPool pool) {
53              if (innerClassInfo != null) {
54                  innerClassInfo.resolve(pool);
55                  innerClassInfoIndex = pool.indexOf(innerClassInfo);
56              } else {
57                  innerClassInfoIndex = 0;
58              }
59  
60              if (innerClassName != null) {
61                  innerClassName.resolve(pool);
62                  innerNameIndex = pool.indexOf(innerClassName);
63              } else {
64                  innerNameIndex = 0;
65              }
66  
67              if (outerClassInfo != null) {
68                  outerClassInfo.resolve(pool);
69                  outerClassInfoIndex = pool.indexOf(outerClassInfo);
70              } else {
71                  outerClassInfoIndex = 0;
72              }
73          }
74  
75          public void write(final DataOutputStream dos) throws IOException {
76              dos.writeShort(innerClassInfoIndex);
77              dos.writeShort(outerClassInfoIndex);
78              dos.writeShort(innerNameIndex);
79              dos.writeShort(innerClassAccessFlags);
80          }
81  
82      }
83  
84      private static CPUTF8 attributeName;
85  
86      public static void setAttributeName(final CPUTF8 cpUTF8Value) {
87          attributeName = cpUTF8Value;
88      }
89  
90      private final List<InnerClassesEntry> innerClasses = new ArrayList<>();
91      private final List<ConstantPoolEntry> nestedClassFileEntries = new ArrayList<>();
92  
93      public InnerClassesAttribute(final String name) {
94          super(attributeName);
95          nestedClassFileEntries.add(getAttributeName());
96      }
97  
98      public void addInnerClassesEntry(final CPClass innerClass, final CPClass outerClass, final CPUTF8 innerName, final int flags) {
99          if (innerClass != null) {
100             nestedClassFileEntries.add(innerClass);
101         }
102         if (outerClass != null) {
103             nestedClassFileEntries.add(outerClass);
104         }
105         if (innerName != null) {
106             nestedClassFileEntries.add(innerName);
107         }
108         addInnerClassesEntry(new InnerClassesEntry(innerClass, outerClass, innerName, flags));
109     }
110 
111     private void addInnerClassesEntry(final InnerClassesEntry innerClassesEntry) {
112         innerClasses.add(innerClassesEntry);
113     }
114 
115     @Override
116     public boolean equals(final Object obj) {
117         if (this == obj) {
118             return true;
119         }
120         if (!super.equals(obj)) {
121             return false;
122         }
123         if (this.getClass() != obj.getClass()) {
124             return false;
125         }
126         final InnerClassesAttribute other = (InnerClassesAttribute) obj;
127         if (getAttributeName() == null) {
128             if (other.getAttributeName() != null) {
129                 return false;
130             }
131         } else if (!getAttributeName().equals(other.getAttributeName())) {
132             return false;
133         }
134         return true;
135     }
136 
137     @Override
138     protected int getLength() {
139         return 2 + (2 + 2 + 2 + 2) * innerClasses.size();
140     }
141 
142     @Override
143     protected ClassFileEntry[] getNestedClassFileEntries() {
144         return nestedClassFileEntries.toArray(NONE);
145     }
146 
147     @Override
148     public int hashCode() {
149         final int PRIME = 31;
150         int result = super.hashCode();
151         result = PRIME * result + (getAttributeName() == null ? 0 : getAttributeName().hashCode());
152         return result;
153     }
154 
155     @Override
156     protected void resolve(final ClassConstantPool pool) {
157         super.resolve(pool);
158         for (final InnerClassesEntry entry : innerClasses) {
159             entry.resolve(pool);
160         }
161     }
162 
163     @Override
164     public String toString() {
165         return "InnerClasses: " + getAttributeName();
166     }
167 
168     @Override
169     protected void writeBody(final DataOutputStream dos) throws IOException {
170         dos.writeShort(innerClasses.size());
171 
172         for (final InnerClassesEntry entry : innerClasses) {
173             entry.write(dos);
174         }
175     }
176 }