guru.nidi.codeassert.model.ClassFileParser Maven / Gradle / Ivy
/*
* Copyright © 2015 Stefan Niederhauser ([email protected])
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package guru.nidi.codeassert.model;
import org.apache.commons.io.input.CountingInputStream;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
/**
* The ClassFileParser
class is responsible for
* parsing a Java class file to create a JavaClass
* instance.
*
* @author Mike Clark
* @author Clarkware Consulting, Inc.
*/
class ClassFileParser {
private static final int JAVA_MAGIC = 0xCAFEBABE;
private ConstantPool constantPool;
private DataInputStream in;
CodeClass parse(File file, Model model) throws IOException {
try (InputStream in = new FileInputStream(file)) {
return parse(in, model);
}
}
CodeClass parse(InputStream is, Model model) throws IOException {
final CountingInputStream counter = new CountingInputStream(is);
in = new DataInputStream(counter);
parseMagic();
parseMinorVersion();
parseMajorVersion();
constantPool = ConstantPool.fromData(in);
final int flags = parseAccessFlags();
final String className = parseClassName();
if (model.isIgnoreClass(className)) {
return null;
}
final String superClassName = parseSuperClassName();
final List interfaceNames = parseInterfaces();
final List fields = parseMembers();
final List methods = parseMembers();
final List attributes = parseAttributes();
return new CodeClassBuilder(className, model, constantPool)
.addClassConstantReferences()
.addFlags(flags)
.addSuperClass(superClassName)
.addInterfaces(interfaceNames)
.addFieldRefs(fields)
.addMethodRefs(methods)
.addAttributeRefs(attributes)
.addPackageInfo(model, className)
.addCodeSizes(counter.getCount(), methods)
.clazz;
}
private int parseMagic() throws IOException {
final int magic = in.readInt();
if (magic != JAVA_MAGIC) {
throw new IOException("Invalid class file");
}
return magic;
}
private int parseMinorVersion() throws IOException {
return in.readUnsignedShort();
}
private int parseMajorVersion() throws IOException {
return in.readUnsignedShort();
}
private int parseAccessFlags() throws IOException {
return in.readUnsignedShort();
}
private String parseClassName() throws IOException {
final int entryIndex = in.readUnsignedShort();
return constantPool.getClassConstantName(entryIndex);
}
private String parseSuperClassName() throws IOException {
final int entryIndex = in.readUnsignedShort();
return constantPool.getClassConstantName(entryIndex);
}
private List parseInterfaces() throws IOException {
final int count = in.readUnsignedShort();
final List names = new ArrayList<>(count);
for (int i = 0; i < count; i++) {
final int entryIndex = in.readUnsignedShort();
names.add(constantPool.getClassConstantName(entryIndex));
}
return names;
}
private List parseMembers() throws IOException {
final int count = in.readUnsignedShort();
final List infos = new ArrayList<>(count);
for (int i = 0; i < count; i++) {
infos.add(MemberInfo.fromData(in, constantPool));
}
return infos;
}
private List parseAttributes() throws IOException {
final int count = in.readUnsignedShort();
final List attributes = new ArrayList<>(count);
for (int i = 0; i < count; i++) {
attributes.add(AttributeInfo.fromData(in, constantPool));
}
return attributes;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy