// Copyright (c) 2011, David J. Pearce (djp@ecs.vuw.ac.nz)
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the <organization> nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL DAVID J. PEARCE BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package jasm.attributes;
import jasm.io.BinaryOutputStream;
import jasm.io.ClassFileReader;
import jasm.lang.*;
import jasm.util.Triple;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.*;
public class InnerClasses implements BytecodeAttribute {
protected List<Triple<JvmType.Clazz,JvmType.Clazz,List<Modifier>>> inners;
protected JvmType.Clazz type;
public String name() {
return "InnerClasses";
}
/**
* Create an InnerClasses attribute (see JLS Section 4.7.5).
*
* @param type
* - the type of the class containing this attribute.
* @param inners
* - the types and modifiers for all classes contained in this
* class.
*/
public InnerClasses(JvmType.Clazz type,
List<Triple<JvmType.Clazz, JvmType.Clazz, List<Modifier>>> inners) {
this.type = type;
this.inners = inners;
}
public List<Triple<JvmType.Clazz,JvmType.Clazz,List<Modifier>>> inners() {
return inners;
}
public JvmType.Clazz type() {
return type;
}
@Override
public void addPoolItems(Set<Constant.Info> constantPool) {
Constant.addPoolItem(new Constant.Utf8("InnerClasses"), constantPool);
for(Triple<JvmType.Clazz,JvmType.Clazz,List<Modifier>> i : inners) {
if(i.first() != null) {
Constant.addPoolItem(Constant.buildClass(i.first()),constantPool);
}
if(i.second() != null) {
Constant.addPoolItem(Constant.buildClass(i.second()),constantPool);
}
String name = i.second().lastComponent().first();
Constant.addPoolItem(new Constant.Utf8(name),constantPool);
}
}
@Override
public void print(PrintWriter output, Map<Constant.Info, Integer> constantPool) {
output.println(" InnerClasses:");
for (Triple<JvmType.Clazz, JvmType.Clazz, List<Modifier>> i : inners) {
String name = i.second().lastComponent().first();
int nameIndex = constantPool.get(new Constant.Utf8(name));
int outerIndex = 0;
if (i.first() != null) {
outerIndex = constantPool.get(Constant.buildClass(i.first()));
}
int innerIndex = 0;
if (i.second() != null) {
innerIndex = constantPool.get(Constant.buildClass(i.second()));
}
output.print(" ");
output.print(nameIndex + " (");
output.println(") = " + innerIndex + " of " + outerIndex);
}
}
@Override
public void write(BinaryOutputStream output, Map<Constant.Info, Integer> constantPool) throws IOException {
output.write_u16(constantPool.get(new Constant.Utf8("InnerClasses")));
int ninners = inners.size();
output.write_u32(2 + (8 * ninners));
output.write_u16(ninners);
for(Triple<JvmType.Clazz,JvmType.Clazz,List<Modifier>> i : inners) {
if(i.second() == null) {
output.write_u16(0);
} else {
output.write_u16(constantPool.get(Constant.buildClass(i.second())));
}
if(i.first() == null) {
output.write_u16(0);
} else {
output.write_u16(constantPool.get(Constant.buildClass(i.first())));
}
String name = i.second().lastComponent().first();
output.write_u16(constantPool.get(new Constant.Utf8(name)));
writeInnerModifiers(i.third(),output);
}
}
private static void writeInnerModifiers(List<Modifier> modifiers,
BinaryOutputStream output)
throws IOException {
int mods = 0;
for (Modifier m : modifiers) {
if (m instanceof Modifier.Public) {
mods |= ClassFileReader.ACC_PUBLIC;
} else if (m instanceof Modifier.Private) {
mods |= ClassFileReader.ACC_PRIVATE;
} else if (m instanceof Modifier.Protected) {
mods |= ClassFileReader.ACC_PROTECTED;
} else if (m instanceof Modifier.Static) {
mods |= ClassFileReader.ACC_STATIC;
} else if (m instanceof Modifier.Final) {
mods |= ClassFileReader.ACC_FINAL;
} else if (m instanceof Modifier.Interface) {
mods |= ClassFileReader.ACC_INTERFACE;
} else if (m instanceof Modifier.Abstract) {
mods |= ClassFileReader.ACC_ABSTRACT;
} else if (m instanceof Modifier.Synthetic) {
mods |= ClassFileReader.ACC_SYNTHETIC;
} else if (m instanceof Modifier.Enum) {
mods |= ClassFileReader.ACC_ENUM;
}
}
output.write_u16(mods);
}
}