001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.compress.harmony.unpack200.bytecode; 018 019import java.io.DataOutputStream; 020import java.io.IOException; 021import java.util.ArrayList; 022import java.util.List; 023 024/** 025 * Inner classes class file attribute 026 */ 027public class InnerClassesAttribute extends Attribute { 028 029 private static CPUTF8 attributeName; 030 031 public static void setAttributeName(final CPUTF8 cpUTF8Value) { 032 attributeName = cpUTF8Value; 033 } 034 035 private static class InnerClassesEntry { 036 037 CPClass inner_class_info; 038 CPClass outer_class_info; 039 CPUTF8 inner_class_name; 040 041 int inner_class_info_index = -1; 042 int outer_class_info_index = -1; 043 int inner_name_index = -1; 044 int inner_class_access_flags = -1; 045 046 public InnerClassesEntry(final CPClass innerClass, final CPClass outerClass, final CPUTF8 innerName, 047 final int flags) { 048 this.inner_class_info = innerClass; 049 this.outer_class_info = outerClass; 050 this.inner_class_name = innerName; 051 this.inner_class_access_flags = flags; 052 } 053 054 /** 055 * Determine the indices of the things in the receiver which point to elements of the ClassConstantPool 056 * 057 * @param pool ClassConstantPool which holds the CPClass and CPUTF8 objects. 058 */ 059 public void resolve(final ClassConstantPool pool) { 060 if (inner_class_info != null) { 061 inner_class_info.resolve(pool); 062 inner_class_info_index = pool.indexOf(inner_class_info); 063 } else { 064 inner_class_info_index = 0; 065 } 066 067 if (inner_class_name != null) { 068 inner_class_name.resolve(pool); 069 inner_name_index = pool.indexOf(inner_class_name); 070 } else { 071 inner_name_index = 0; 072 } 073 074 if (outer_class_info != null) { 075 outer_class_info.resolve(pool); 076 outer_class_info_index = pool.indexOf(outer_class_info); 077 } else { 078 outer_class_info_index = 0; 079 } 080 } 081 082 public void write(final DataOutputStream dos) throws IOException { 083 dos.writeShort(inner_class_info_index); 084 dos.writeShort(outer_class_info_index); 085 dos.writeShort(inner_name_index); 086 dos.writeShort(inner_class_access_flags); 087 } 088 089 } 090 091 private final List innerClasses = new ArrayList(); 092 private final List nestedClassFileEntries = new ArrayList(); 093 094 public InnerClassesAttribute(final String name) { 095 super(attributeName); 096 nestedClassFileEntries.add(getAttributeName()); 097 } 098 099 @Override 100 public boolean equals(final Object obj) { 101 if (this == obj) { 102 return true; 103 } 104 if (!super.equals(obj)) { 105 return false; 106 } 107 if (this.getClass() != obj.getClass()) { 108 return false; 109 } 110 final InnerClassesAttribute other = (InnerClassesAttribute) obj; 111 if (getAttributeName() == null) { 112 if (other.getAttributeName() != null) { 113 return false; 114 } 115 } else if (!getAttributeName().equals(other.getAttributeName())) { 116 return false; 117 } 118 return true; 119 } 120 121 @Override 122 protected int getLength() { 123 return 2 + ((2 + 2 + 2 + 2) * innerClasses.size()); 124 } 125 126 @Override 127 protected ClassFileEntry[] getNestedClassFileEntries() { 128 final ClassFileEntry[] result = new ClassFileEntry[nestedClassFileEntries.size()]; 129 for (int index = 0; index < result.length; index++) { 130 result[index] = (ClassFileEntry) nestedClassFileEntries.get(index); 131 } 132 return result; 133 } 134 135 @Override 136 public int hashCode() { 137 final int PRIME = 31; 138 int result = super.hashCode(); 139 result = PRIME * result + ((getAttributeName() == null) ? 0 : getAttributeName().hashCode()); 140 return result; 141 } 142 143 @Override 144 protected void resolve(final ClassConstantPool pool) { 145 super.resolve(pool); 146 for (int it = 0; it < innerClasses.size(); it++) { 147 final InnerClassesEntry entry = (InnerClassesEntry) innerClasses.get(it); 148 entry.resolve(pool); 149 } 150 } 151 152 @Override 153 public String toString() { 154 return "InnerClasses: " + getAttributeName(); 155 } 156 157 @Override 158 protected void doWrite(final DataOutputStream dos) throws IOException { 159 // Hack so I can see what's being written. 160 super.doWrite(dos); 161 } 162 163 @Override 164 protected void writeBody(final DataOutputStream dos) throws IOException { 165 dos.writeShort(innerClasses.size()); 166 167 for (int it = 0; it < innerClasses.size(); it++) { 168 final InnerClassesEntry entry = (InnerClassesEntry) innerClasses.get(it); 169 entry.write(dos); 170 } 171 } 172 173 public void addInnerClassesEntry(final CPClass innerClass, final CPClass outerClass, final CPUTF8 innerName, 174 final int flags) { 175 if (innerClass != null) { 176 nestedClassFileEntries.add(innerClass); 177 } 178 if (outerClass != null) { 179 nestedClassFileEntries.add(outerClass); 180 } 181 if (innerName != null) { 182 nestedClassFileEntries.add(innerName); 183 } 184 addInnerClassesEntry(new InnerClassesEntry(innerClass, outerClass, innerName, flags)); 185 } 186 187 private void addInnerClassesEntry(final InnerClassesEntry innerClassesEntry) { 188 innerClasses.add(innerClassesEntry); 189 } 190}