001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * https://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.apache.commons.compress.harmony.unpack200.bytecode; 020 021import java.io.DataOutputStream; 022import java.io.IOException; 023import java.util.ArrayList; 024import java.util.List; 025 026/** 027 * Inner classes class file attribute 028 */ 029public class InnerClassesAttribute extends Attribute { 030 031 private static final class InnerClassesEntry { 032 033 CPClass innerClassInfo; 034 CPClass outerClassInfo; 035 CPUTF8 innerClassName; 036 037 int innerClassInfoIndex = -1; 038 int outerClassInfoIndex = -1; 039 int innerNameIndex = -1; 040 int innerClassAccessFlags = -1; 041 042 InnerClassesEntry(final CPClass innerClass, final CPClass outerClass, final CPUTF8 innerName, final int flags) { 043 this.innerClassInfo = innerClass; 044 this.outerClassInfo = outerClass; 045 this.innerClassName = innerName; 046 this.innerClassAccessFlags = flags; 047 } 048 049 /** 050 * Determine the indices of the things in the receiver which point to elements of the ClassConstantPool 051 * 052 * @param pool ClassConstantPool which holds the CPClass and CPUTF8 objects. 053 */ 054 public void resolve(final ClassConstantPool pool) { 055 if (innerClassInfo != null) { 056 innerClassInfo.resolve(pool); 057 innerClassInfoIndex = pool.indexOf(innerClassInfo); 058 } else { 059 innerClassInfoIndex = 0; 060 } 061 062 if (innerClassName != null) { 063 innerClassName.resolve(pool); 064 innerNameIndex = pool.indexOf(innerClassName); 065 } else { 066 innerNameIndex = 0; 067 } 068 069 if (outerClassInfo != null) { 070 outerClassInfo.resolve(pool); 071 outerClassInfoIndex = pool.indexOf(outerClassInfo); 072 } else { 073 outerClassInfoIndex = 0; 074 } 075 } 076 077 public void write(final DataOutputStream dos) throws IOException { 078 dos.writeShort(innerClassInfoIndex); 079 dos.writeShort(outerClassInfoIndex); 080 dos.writeShort(innerNameIndex); 081 dos.writeShort(innerClassAccessFlags); 082 } 083 084 } 085 086 private static CPUTF8 attributeName; 087 088 public static void setAttributeName(final CPUTF8 cpUTF8Value) { 089 attributeName = cpUTF8Value; 090 } 091 092 private final List<InnerClassesEntry> innerClasses = new ArrayList<>(); 093 private final List<ConstantPoolEntry> nestedClassFileEntries = new ArrayList<>(); 094 095 public InnerClassesAttribute(final String name) { 096 super(attributeName); 097 nestedClassFileEntries.add(getAttributeName()); 098 } 099 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}