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     protected void doWrite(final DataOutputStream dos) throws IOException {
117         // Hack so I can see what's being written.
118         super.doWrite(dos);
119     }
120 
121     @Override
122     public boolean equals(final Object obj) {
123         if (this == obj) {
124             return true;
125         }
126         if (!super.equals(obj)) {
127             return false;
128         }
129         if (this.getClass() != obj.getClass()) {
130             return false;
131         }
132         final InnerClassesAttribute other = (InnerClassesAttribute) obj;
133         if (getAttributeName() == null) {
134             if (other.getAttributeName() != null) {
135                 return false;
136             }
137         } else if (!getAttributeName().equals(other.getAttributeName())) {
138             return false;
139         }
140         return true;
141     }
142 
143     @Override
144     protected int getLength() {
145         return 2 + (2 + 2 + 2 + 2) * innerClasses.size();
146     }
147 
148     @Override
149     protected ClassFileEntry[] getNestedClassFileEntries() {
150         return nestedClassFileEntries.toArray(ClassFileEntry.NONE);
151     }
152 
153     @Override
154     public int hashCode() {
155         final int PRIME = 31;
156         int result = super.hashCode();
157         result = PRIME * result + (getAttributeName() == null ? 0 : getAttributeName().hashCode());
158         return result;
159     }
160 
161     @Override
162     protected void resolve(final ClassConstantPool pool) {
163         super.resolve(pool);
164         for (final InnerClassesEntry entry : innerClasses) {
165             entry.resolve(pool);
166         }
167     }
168 
169     @Override
170     public String toString() {
171         return "InnerClasses: " + getAttributeName();
172     }
173 
174     @Override
175     protected void writeBody(final DataOutputStream dos) throws IOException {
176         dos.writeShort(innerClasses.size());
177 
178         for (final InnerClassesEntry entry : innerClasses) {
179             entry.write(dos);
180         }
181     }
182 }