Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* MetadataReader.java
*
* Copyright (c) 2013 Mike Strobel
*
* This source code is based on Mono.Cecil from Jb Evain, Copyright (c) Jb Evain;
* and ILSpy/ICSharpCode from SharpDevelop, Copyright (c) AlphaSierraPapa.
*
* This source code is subject to terms and conditions of the Apache License, Version 2.0.
* A copy of the license can be found in the License.html file at the root of this distribution.
* By using this source code in any fashion, you are agreeing to be bound by the terms of the
* Apache License, Version 2.0.
*
* You must not remove this notice, or any other, from this software.
*/
package com.strobel.assembler.ir;
import com.strobel.assembler.ir.attributes.*;
import com.strobel.assembler.metadata.*;
import com.strobel.assembler.metadata.annotations.AnnotationElement;
import com.strobel.assembler.metadata.annotations.CustomAnnotation;
import com.strobel.core.ArrayUtilities;
import com.strobel.core.VerifyArgument;
import java.util.List;
/**
* @author Mike Strobel
*/
public abstract class MetadataReader {
protected MetadataReader() {
}
protected abstract IMetadataScope getScope();
protected abstract MetadataParser getParser();
public void readAttributes(final Buffer input, final SourceAttribute[] attributes) {
for (int i = 0; i < attributes.length; i++) {
attributes[i] = readAttribute(input);
}
}
public SourceAttribute readAttribute(final Buffer buffer) {
final int nameIndex = buffer.readUnsignedShort();
final int length = buffer.readInt();
final IMetadataScope scope = getScope();
final String name = scope.lookupConstant(nameIndex);
return readAttributeCore(name, buffer, -1, length);
}
/**
* Reads a {@link SourceAttribute} from the specified buffer.
*
* @param name
* The name of the attribute to decode.
* @param buffer
* A buffer containing the attribute blob.
* @param originalOffset
* The offset of position 0 in the buffer relative to the start of the original class file.
* This is needed during lazy inflation of {@link CodeAttribute} (and possibly others). In
* the case of {@link CodeAttribute}, it is helpful to know exactly where each method's body
* begins so we can load it on demand at some point in the future.
* @param length
* The length of the attribute. Implementations should not rely on {@link Buffer#size()
* buffer.size()}.
*/
protected SourceAttribute readAttributeCore(final String name, final Buffer buffer, final int originalOffset, final int length) {
final IMetadataScope scope = getScope();
if (length == 0) {
return SourceAttribute.create(name);
}
switch (name) {
case AttributeNames.SourceFile: {
final int token = buffer.readUnsignedShort();
final String sourceFile = scope.lookupConstant(token);
return new SourceFileAttribute(sourceFile);
}
case AttributeNames.ConstantValue: {
final int token = buffer.readUnsignedShort();
final Object constantValue = scope.lookupConstant(token);
return new ConstantValueAttribute(constantValue);
}
case AttributeNames.Code: {
final int maxStack = buffer.readUnsignedShort();
final int maxLocals = buffer.readUnsignedShort();
final int codeLength = buffer.readInt();
final int relativeOffset = buffer.position();
final int codeOffset = (originalOffset >= 0) ? (originalOffset - 2 + relativeOffset) : relativeOffset;
final byte[] code = new byte[codeLength];
buffer.read(code, 0, codeLength);
final int exceptionTableLength = buffer.readUnsignedShort();
final ExceptionTableEntry[] exceptionTable = new ExceptionTableEntry[exceptionTableLength];
for (int k = 0; k < exceptionTableLength; k++) {
final int startOffset = buffer.readUnsignedShort();
final int endOffset = buffer.readUnsignedShort();
final int handlerOffset = buffer.readUnsignedShort();
final int catchTypeToken = buffer.readUnsignedShort();
final TypeReference catchType;
if (catchTypeToken == 0) {
catchType = null;
}
else {
catchType = scope.lookupType(catchTypeToken);
}
exceptionTable[k] = new ExceptionTableEntry(
startOffset,
endOffset,
handlerOffset,
catchType
);
}
final int attributeCount = buffer.readUnsignedShort();
final SourceAttribute[] attributes = new SourceAttribute[attributeCount];
readAttributes(buffer, attributes);
return new CodeAttribute(
length,
maxStack,
maxLocals,
codeOffset,
codeLength,
buffer,
exceptionTable,
attributes
);
}
case AttributeNames.Exceptions: {
final int exceptionCount = buffer.readUnsignedShort();
final TypeReference[] exceptionTypes = new TypeReference[exceptionCount];
for (int i = 0; i < exceptionTypes.length; i++) {
exceptionTypes[i] = scope.lookupType(buffer.readUnsignedShort());
}
return new ExceptionsAttribute(exceptionTypes);
}
case AttributeNames.LineNumberTable: {
final int entryCount = buffer.readUnsignedShort();
final LineNumberTableEntry[] entries = new LineNumberTableEntry[entryCount];
for (int i = 0; i < entries.length; i++) {
entries[i] = new LineNumberTableEntry(
buffer.readUnsignedShort(),
buffer.readUnsignedShort()
);
}
return new LineNumberTableAttribute(entries);
}
case AttributeNames.LocalVariableTable:
case AttributeNames.LocalVariableTypeTable: {
final int entryCount = buffer.readUnsignedShort();
final LocalVariableTableEntry[] entries = new LocalVariableTableEntry[entryCount];
for (int i = 0; i < entries.length; i++) {
final int scopeOffset = buffer.readUnsignedShort();
final int scopeLength = buffer.readUnsignedShort();
final int nameToken = buffer.readUnsignedShort();
final int typeToken = buffer.readUnsignedShort();
final int variableIndex = buffer.readUnsignedShort();
final String variableName = scope.lookupConstant(nameToken);
final String descriptor = scope.lookupConstant(typeToken);
entries[i] = new LocalVariableTableEntry(
variableIndex,
variableName,
getParser().parseTypeSignature(descriptor),
scopeOffset,
scopeLength
);
}
return new LocalVariableTableAttribute(name, entries);
}
case AttributeNames.EnclosingMethod: {
final int typeToken = buffer.readUnsignedShort();
final int methodToken = buffer.readUnsignedShort();
return new EnclosingMethodAttribute(
scope.lookupType(typeToken),
methodToken > 0 ? scope.lookupMethod(typeToken, methodToken)
: null
);
}
case AttributeNames.RuntimeVisibleAnnotations:
case AttributeNames.RuntimeInvisibleAnnotations: {
final CustomAnnotation[] annotations = new CustomAnnotation[buffer.readUnsignedShort()];
for (int i = 0; i < annotations.length; i++) {
annotations[i] = AnnotationReader.read(scope, buffer);
}
return new AnnotationsAttribute(name, length, annotations);
}
case AttributeNames.RuntimeVisibleParameterAnnotations:
case AttributeNames.RuntimeInvisibleParameterAnnotations: {
final CustomAnnotation[][] annotations = new CustomAnnotation[buffer.readUnsignedByte()][];
for (int i = 0; i < annotations.length; i++) {
final CustomAnnotation[] parameterAnnotations = new CustomAnnotation[buffer.readUnsignedShort()];
for (int j = 0; j < parameterAnnotations.length; j++) {
parameterAnnotations[j] = AnnotationReader.read(scope, buffer);
}
annotations[i] = parameterAnnotations;
}
return new ParameterAnnotationsAttribute(name, length, annotations);
}
case AttributeNames.AnnotationDefault: {
final AnnotationElement defaultValue = AnnotationReader.readElement(scope, buffer);
return new AnnotationDefaultAttribute(length, defaultValue);
}
case AttributeNames.Signature: {
final int token = buffer.readUnsignedShort();
final String signature = scope.lookupConstant(token);
return new SignatureAttribute(signature);
}
case AttributeNames.BootstrapMethods: {
final BootstrapMethodsTableEntry[] methods = new BootstrapMethodsTableEntry[buffer.readUnsignedShort()];
for (int i = 0; i < methods.length; i++) {
final MethodReference bootstrapMethod = scope.lookupMethod(buffer.readUnsignedShort());
final Object[] arguments = new Object[buffer.readUnsignedShort()];
final List parameters = bootstrapMethod.getParameters();
if (parameters.size() != arguments.length + 3) {
final MethodDefinition resolved = bootstrapMethod.resolve();
if (resolved == null || !resolved.isVarArgs() || parameters.size() >= arguments.length + 3) {
throw Error.invalidBootstrapMethodEntry(bootstrapMethod, parameters.size(), arguments.length);
}
}
for (int j = 0; j < arguments.length; j++) {
final TypeReference parameterType;
final int token = buffer.readUnsignedShort();
final int parameterIndex = j + 3;
if (parameterIndex < parameters.size()) {
parameterType = parameters.get(parameterIndex).getParameterType();
}
else {
parameterType = BuiltinTypes.Object;
}
switch (parameterType.getInternalName()) {
case "java/lang/invoke/MethodHandle":
arguments[j] = scope.lookupMethodHandle(token);
continue;
case "java/lang/invoke/MethodType":
arguments[j] = scope.lookupMethodType(token);
continue;
default:
arguments[j] = scope.lookup(token);
continue;
}
}
methods[i] = new BootstrapMethodsTableEntry(bootstrapMethod, arguments);
}
return new BootstrapMethodsAttribute(methods);
}
case AttributeNames.MethodParameters: {
final int methodParameterCount = buffer.readUnsignedByte();
final int computedCount = (length - 1) / 4;
final MethodParameterEntry[] entries = new MethodParameterEntry[methodParameterCount];
for (int i = 0; i < entries.length; i++) {
final int nameIndex;
final int flags;
if (i < computedCount) {
nameIndex = buffer.readUnsignedShort();
flags = buffer.readUnsignedShort();
}
else {
nameIndex = 0;
flags = 0;
}
entries[i] = new MethodParameterEntry(
nameIndex != 0 ? getScope().lookupConstant(nameIndex) : null,
flags
);
}
return new MethodParametersAttribute(ArrayUtilities.asUnmodifiableList(entries));
}
default: {
final byte[] blob = new byte[length];
final int offset = buffer.position();
buffer.read(blob, 0, blob.length);
return new BlobAttribute(name, blob, offset);
}
}
}
protected void inflateAttributes(final SourceAttribute[] attributes) {
VerifyArgument.noNullElements(attributes, "attributes");
if (attributes.length == 0) {
return;
}
Buffer buffer = null;
for (int i = 0; i < attributes.length; i++) {
final SourceAttribute attribute = attributes[i];
if (attribute instanceof BlobAttribute) {
if (buffer == null) {
buffer = new Buffer(attribute.getLength());
}
attributes[i] = inflateAttribute(buffer, attribute);
}
}
}
protected final SourceAttribute inflateAttribute(final SourceAttribute attribute) {
return inflateAttribute(new Buffer(0), attribute);
}
protected final SourceAttribute inflateAttribute(final Buffer buffer, final SourceAttribute attribute) {
if (attribute instanceof BlobAttribute) {
buffer.reset(attribute.getLength());
final BlobAttribute blobAttribute = (BlobAttribute) attribute;
System.arraycopy(
blobAttribute.getData(),
0,
buffer.array(),
0,
attribute.getLength()
);
return readAttributeCore(
attribute.getName(),
buffer,
blobAttribute.getDataOffset(),
attribute.getLength()
);
}
return attribute;
}
protected void inflateAttributes(final List attributes) {
VerifyArgument.noNullElements(attributes, "attributes");
if (attributes.isEmpty()) {
return;
}
Buffer buffer = null;
for (int i = 0; i < attributes.size(); i++) {
final SourceAttribute attribute = attributes.get(i);
if (attribute instanceof BlobAttribute) {
if (buffer == null) {
buffer = new Buffer(attribute.getLength());
}
else if (buffer.size() < attribute.getLength()) {
buffer.reset(attribute.getLength());
}
else {
buffer.position(0);
}
final BlobAttribute blobAttribute = (BlobAttribute) attribute;
System.arraycopy(
blobAttribute.getData(),
0,
buffer.array(),
0,
attribute.getLength()
);
attributes.set(
i,
readAttributeCore(
attribute.getName(),
buffer,
blobAttribute.getDataOffset(),
attribute.getLength()
)
);
}
}
}
}