mirror of
https://gitee.com/zhangsken/AndroidIDE.git
synced 2026-10-16 07:49:44 +08:00
ClassFileReader: Implemented field reader
This commit is contained in:
+31
@@ -53,4 +53,35 @@ public class ClassFileConstants {
|
||||
|
||||
/** Is a module, not a class or interface. */
|
||||
public static final int ACC_MODULE = 0x8000;
|
||||
|
||||
public static final String ATTR_CONSTANT_VALUE = "ConstantValue";
|
||||
public static final String ATTR_CODE = "Code";
|
||||
public static final String ATTR_EXCEPTIONS = "Exceptions";
|
||||
public static final String ATTR_SOURCE_FILE = "SourceFile";
|
||||
public static final String ATTR_LINE_NUMBER_TABLE = "LineNumberTable";
|
||||
public static final String ATTR_LOCAL_VARIABLE_TABLE = "LocalVariableTable";
|
||||
public static final String ATTR_INNER_CLASSES = "InnerClasses";
|
||||
public static final String ATTR_SYNTHETIC = "Synthetic";
|
||||
public static final String ATTR_DEPRECATED = "Deprecated";
|
||||
public static final String ATTR_ENCLOSING_METHOD = "EnclosingMethod";
|
||||
public static final String ATTR_SIGNATURE = "Signature";
|
||||
public static final String ATTR_SOURCE_DEBUG_EXTENSION = "SourceDebugExtension";
|
||||
public static final String ATTR_LOCAL_VARIABLE_TYPE_TABLE = "LocalVariableTypeTable";
|
||||
public static final String ATTR_RUNTIME_VISIBLE_ANNOTATIONS = "RuntimeVisibleAnnotations";
|
||||
public static final String ATTR_RUNTIME_INVISIBLE_ANNOTATIONS = "RuntimeInvisibleAnnotations";
|
||||
public static final String ATTR_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS = "RuntimeVisibleParameterAnnotations";
|
||||
public static final String ATTR_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS = "RuntimeInvisibleParameterAnnotations";
|
||||
public static final String ATTR_ANNOTATION_DEFAULT = "AnnotationDefault";
|
||||
public static final String ATTR_STACK_MAP_TABLE = "StackMapTable";
|
||||
public static final String ATTR_BOOTSTRAP_METHODS = "BootstrapMethods";
|
||||
public static final String ATTR_RUNTIME_VISIBLE_TYPE_ANNOTATIONS = "RuntimeVisibleTypeAnnotations";
|
||||
public static final String ATTR_RUNTIME_INVISIBLE_TYPE_ANNOTATIONS = "RuntimeInvisibleTypeAnnotations";
|
||||
public static final String ATTR_METHOD_PARAMETERS = "MethodParameters";
|
||||
public static final String ATTR_MODULE = "Module";
|
||||
public static final String ATTR_MODULE_PACKAGES = "ModulePackages";
|
||||
public static final String ATTR_MAIN_CLASS = "ModuleMainClass";
|
||||
public static final String ATTR_NEST_HOST = "NestHost";
|
||||
public static final String ATTR_NEST_MEMBERS = "NestMembers";
|
||||
public static final String ATTR_RECORD = "Record";
|
||||
public static final String ATTR_PERMITTED_SUBCLASSES = "PermittedSubclasses";
|
||||
}
|
||||
|
||||
+22
-10
@@ -22,6 +22,7 @@ import com.itsaky.androidide.classfile.constants.IConstant.Type.DOUBLE
|
||||
import com.itsaky.androidide.classfile.constants.IConstant.Type.LONG
|
||||
import com.itsaky.androidide.classfile.internal.ClassFile
|
||||
import com.itsaky.androidide.classfile.internal.NullConstant
|
||||
import com.itsaky.androidide.classfile.internal.NullField
|
||||
import java.io.DataInputStream
|
||||
import java.io.InputStream
|
||||
|
||||
@@ -31,7 +32,7 @@ import java.io.InputStream
|
||||
*
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
class ClassFileReader(val stream: InputStream) {
|
||||
class ClassFileReader(private val stream: InputStream) {
|
||||
|
||||
/**
|
||||
* Read the class file.
|
||||
@@ -48,13 +49,15 @@ class ClassFileReader(val stream: InputStream) {
|
||||
}
|
||||
|
||||
val file = ClassFile()
|
||||
file.minorVersion = input.readUnsignedShort()
|
||||
file.majorVersion = input.readUnsignedShort()
|
||||
|
||||
if (file.majorVersion >= 56 && file.minorVersion != 0 && file.minorVersion != 65535) {
|
||||
val minorVersion = input.readUnsignedShort()
|
||||
val majorVersion = input.readUnsignedShort()
|
||||
|
||||
if (majorVersion >= 56 && minorVersion != 0 && minorVersion != 65535) {
|
||||
// When major version is >= 56, minor version must be 0 or 65535
|
||||
throw IllegalStateException("Invalid class file minor version: '${file.minorVersion}'")
|
||||
throw IllegalStateException("Invalid class file minor version: '${minorVersion}'")
|
||||
}
|
||||
|
||||
file.version = ClassFileVersion.get(majorVersion, minorVersion)
|
||||
|
||||
val poolCount = input.readUnsignedShort()
|
||||
file.constantPool = Array(poolCount) { NullConstant }
|
||||
@@ -63,27 +66,36 @@ class ClassFileReader(val stream: InputStream) {
|
||||
while (index < poolCount) {
|
||||
val constant = readPoolConstant(input)
|
||||
file.constantPool[index] = constant
|
||||
|
||||
|
||||
if (constant.type == LONG || constant.type == DOUBLE) {
|
||||
++index
|
||||
}
|
||||
|
||||
|
||||
++index
|
||||
}
|
||||
|
||||
file.accessFlags = input.readUnsignedShort()
|
||||
file.thisClass = input.readUnsignedShort()
|
||||
file.superClass = input.readUnsignedShort()
|
||||
|
||||
|
||||
val interfaceCount = input.readUnsignedShort()
|
||||
file.interfaces = IntArray(interfaceCount)
|
||||
|
||||
|
||||
index = 0
|
||||
while (index < interfaceCount) {
|
||||
file.interfaces[index] = input.readUnsignedShort()
|
||||
++index
|
||||
}
|
||||
|
||||
val fieldCount = input.readUnsignedShort()
|
||||
file.fields = Array(fieldCount) { NullField }
|
||||
|
||||
index = 0
|
||||
while (index < fieldCount) {
|
||||
file.fields[index] = IFieldInfo.read(input, file)
|
||||
++index
|
||||
}
|
||||
|
||||
return file
|
||||
}
|
||||
|
||||
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AndroidIDE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.itsaky.androidide.classfile
|
||||
|
||||
/**
|
||||
* Version info for the class file.
|
||||
*
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
enum class ClassFileVersion(val major: Int, val minor: Int) {
|
||||
JAVA_1_0(45, 0),
|
||||
JAVA_1_1(45, 3),
|
||||
JAVA_1_2(46, 0),
|
||||
JAVA_1_3(47, 0),
|
||||
JAVA_1_4(48, 0),
|
||||
JAVA_5(49, 0),
|
||||
JAVA_6(50, 0),
|
||||
JAVA_7(51, 0),
|
||||
JAVA_8(52, 0),
|
||||
JAVA_9(53, 0),
|
||||
JAVA_10(54, 0),
|
||||
JAVA_11(55, 0),
|
||||
JAVA_12(56, 0),
|
||||
JAVA_13(57, 0),
|
||||
JAVA_14(58, 0),
|
||||
JAVA_15(59, 0),
|
||||
JAVA_16(60, 0),
|
||||
JAVA_17(61, 0);
|
||||
|
||||
companion object {
|
||||
internal fun get(major: Int, minor: Int): ClassFileVersion {
|
||||
return values().firstOrNull { it.major == major && it.minor == minor }
|
||||
?: throw IllegalArgumentException("Unknown class file version '${major}.${minor}'")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,11 +25,9 @@ import com.itsaky.androidide.classfile.constants.IConstant
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
interface IClassFile {
|
||||
/** Major version of the class file. */
|
||||
val majorVersion: Int
|
||||
|
||||
/** Minor version of the class file. */
|
||||
val minorVersion: Int
|
||||
/** The class file version. */
|
||||
val version: ClassFileVersion
|
||||
|
||||
/** The constant pool. */
|
||||
val constantPool: Array<IConstant>
|
||||
@@ -52,6 +50,9 @@ interface IClassFile {
|
||||
/** The interfaces that this class implements. */
|
||||
val interfaces: IntArray
|
||||
|
||||
/** The fields of this class. */
|
||||
val fields: Array<IFieldInfo>
|
||||
|
||||
/** Get the string representation of this class' name. */
|
||||
fun getName(): String
|
||||
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AndroidIDE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.itsaky.androidide.classfile
|
||||
|
||||
import com.itsaky.androidide.classfile.attributes.IAttribute
|
||||
import com.itsaky.androidide.classfile.internal.ClassFile
|
||||
import com.itsaky.androidide.classfile.internal.FieldInfo
|
||||
import com.itsaky.androidide.classfile.internal.NullAttribute
|
||||
import java.io.DataInputStream
|
||||
|
||||
/**
|
||||
* Information about a field.
|
||||
*
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
interface IFieldInfo {
|
||||
|
||||
/** Access flags for this field. */
|
||||
val accessFlags: Int
|
||||
|
||||
/** The index in the constant pool which corresponds to the name of this field. */
|
||||
val nameIndex: Int
|
||||
|
||||
/**
|
||||
* The index in the constant pool which corresponds to the field descriptor string for this field.
|
||||
*/
|
||||
val descriptorIndex: Int
|
||||
|
||||
/** The attributes of this field. */
|
||||
val attributes: Array<IAttribute>
|
||||
|
||||
companion object {
|
||||
|
||||
internal fun read(input: DataInputStream, file: ClassFile): IFieldInfo {
|
||||
val field = FieldInfo()
|
||||
field.accessFlags = input.readUnsignedShort()
|
||||
field.nameIndex = input.readUnsignedShort()
|
||||
field.descriptorIndex = input.readUnsignedShort()
|
||||
|
||||
val attrCount = input.readUnsignedShort()
|
||||
field.attributes = Array(attrCount) { NullAttribute }
|
||||
|
||||
var index = 0
|
||||
while (index < attrCount) {
|
||||
field.attributes[index] = IAttribute.read(input, file)
|
||||
++index
|
||||
}
|
||||
return field
|
||||
}
|
||||
}
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AndroidIDE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.itsaky.androidide.classfile.attributes
|
||||
|
||||
import java.io.DataInputStream
|
||||
|
||||
/**
|
||||
* Annotation model for annotation based attributes in class files.
|
||||
*
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
open class Annotation {
|
||||
|
||||
/**
|
||||
* Index of the entry in the constant pool which corresponds to the type of the the annotation.
|
||||
* The entry at this index is always an UTF-8 constant.
|
||||
*/
|
||||
var typeIndex: Int = -1
|
||||
internal set
|
||||
|
||||
/** The element value pairs. */
|
||||
open var elementValues: Array<Pair<Int, ElementValue>> = emptyArray()
|
||||
internal set
|
||||
|
||||
companion object {
|
||||
internal fun read(input: DataInputStream): Annotation {
|
||||
val annotation = Annotation()
|
||||
annotation.typeIndex = input.readUnsignedShort()
|
||||
|
||||
val valueCount = input.readUnsignedShort()
|
||||
annotation.elementValues =
|
||||
Array(valueCount) { input.readUnsignedShort() to ElementValue.read(input) }
|
||||
|
||||
return annotation
|
||||
}
|
||||
}
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AndroidIDE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.itsaky.androidide.classfile.attributes
|
||||
|
||||
import com.itsaky.androidide.classfile.ClassFileVersion
|
||||
import com.itsaky.androidide.classfile.ClassFileVersion.JAVA_5
|
||||
import com.itsaky.androidide.classfile.IClassFile
|
||||
import java.io.DataInputStream
|
||||
|
||||
/**
|
||||
* An attribute which stores information about annotations.
|
||||
*
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
abstract class AnnotationAttr(nameIndex: Int) : BaseAttribute(nameIndex) {
|
||||
override val version: ClassFileVersion = JAVA_5
|
||||
|
||||
/** The annotations. */
|
||||
var annotations: Array<Annotation> = emptyArray()
|
||||
|
||||
override fun read(attrLength: Int, file: IClassFile, input: DataInputStream) {
|
||||
val count = input.readUnsignedShort()
|
||||
this.annotations = Array(count) { Annotation.read(input) }
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AndroidIDE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.itsaky.androidide.classfile.attributes
|
||||
|
||||
/**
|
||||
* Base class for attrbutes.
|
||||
*
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
abstract class BaseAttribute(override val nameIndex: Int): IAttribute
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AndroidIDE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.itsaky.androidide.classfile.attributes
|
||||
|
||||
import com.itsaky.androidide.classfile.ClassFileVersion
|
||||
import com.itsaky.androidide.classfile.ClassFileVersion.JAVA_1_2
|
||||
import com.itsaky.androidide.classfile.IClassFile
|
||||
import com.itsaky.androidide.classfile.attributes.IAttribute.Type
|
||||
import com.itsaky.androidide.classfile.attributes.IAttribute.Type.CONSTANT_VALUE
|
||||
import java.io.DataInputStream
|
||||
|
||||
/**
|
||||
* Constant value for a field.
|
||||
*
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
class ConstantValueAttr(nameIndex: Int) : BaseAttribute(nameIndex) {
|
||||
override val version: ClassFileVersion = JAVA_1_2
|
||||
override val type: Type = CONSTANT_VALUE
|
||||
|
||||
/** The index in the constant pool which corresponds to the value of this constant. */
|
||||
var valueIndex: Int = -1
|
||||
internal set
|
||||
|
||||
override fun read(attrLength: Int, file: IClassFile, input: DataInputStream) {
|
||||
this.valueIndex = input.readUnsignedShort()
|
||||
}
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AndroidIDE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.itsaky.androidide.classfile.attributes
|
||||
|
||||
import com.itsaky.androidide.classfile.ClassFileVersion.JAVA_1_1
|
||||
import com.itsaky.androidide.classfile.attributes.IAttribute.Type.DEPRECATED
|
||||
|
||||
/**
|
||||
* Indicates that a class, field or method is deprecated.
|
||||
*
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
class DeprecatedAttr(nameIndex: Int) : MarkerAttribute(nameIndex, DEPRECATED, JAVA_1_1)
|
||||
+140
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AndroidIDE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.itsaky.androidide.classfile.attributes
|
||||
|
||||
import com.itsaky.androidide.classfile.attributes.ElementValue.Type.ANNOTATION_INTERFACE
|
||||
import com.itsaky.androidide.classfile.attributes.ElementValue.Type.ARRAY_TYPE
|
||||
import com.itsaky.androidide.classfile.attributes.ElementValue.Type.CLASS
|
||||
import com.itsaky.androidide.classfile.attributes.ElementValue.Type.ENUM_CLASS
|
||||
import com.itsaky.androidide.classfile.attributes.ElementValue.Type.UNKNOWN
|
||||
import java.io.DataInputStream
|
||||
|
||||
/**
|
||||
* The element value in an annotation.
|
||||
*
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
class ElementValue {
|
||||
|
||||
/** The element tag. */
|
||||
var type: Type = UNKNOWN
|
||||
internal set
|
||||
|
||||
/**
|
||||
* The constant value if the [type] is one of the following :
|
||||
*
|
||||
* - [Type.BYTE]
|
||||
* - [Type.CHAR]
|
||||
* - [Type.DOUBLE]
|
||||
* - [Type.FLOAT]
|
||||
* - [Type.INT]
|
||||
* - [Type.LONG]
|
||||
* - [Type.SHORT]
|
||||
* - [Type.BOOLEAN]
|
||||
* - [Type.STRING]
|
||||
*/
|
||||
var constValIndex: Int = -1
|
||||
internal set
|
||||
|
||||
/** The element constant value if the [type] is [Type.ENUM_CLASS]. */
|
||||
var enumValue: EnumConstValue? = null
|
||||
internal set
|
||||
|
||||
/** The class name index if the [type] is [Type.CLASS]. */
|
||||
var classNameIndex: Int = -1
|
||||
internal set
|
||||
|
||||
/** The annotation constant value if the [type] is [Type.ANNOTATION_INTERFACE]. */
|
||||
var annotationValue: Annotation? = null
|
||||
internal set
|
||||
|
||||
/** The array constant value if the [type] is [Type.ARRAY_TYPE]. */
|
||||
var arrayValue: Array<ElementValue>? = null
|
||||
internal set
|
||||
|
||||
companion object {
|
||||
internal fun read(input: DataInputStream): ElementValue {
|
||||
val value = ElementValue()
|
||||
value.type = Type.forTag(input.readUnsignedByte())
|
||||
when (value.type) {
|
||||
ENUM_CLASS -> value.enumValue = EnumConstValue.read(input)
|
||||
CLASS -> value.classNameIndex = input.readUnsignedShort()
|
||||
ANNOTATION_INTERFACE -> value.annotationValue = Annotation.read(input)
|
||||
ARRAY_TYPE -> {
|
||||
val count = input.readUnsignedShort()
|
||||
val nullElem = ElementValue()
|
||||
value.arrayValue = Array(count) { nullElem }
|
||||
|
||||
var index = 0
|
||||
while (index < count) {
|
||||
value.arrayValue!![index] = read(input)
|
||||
++index
|
||||
}
|
||||
}
|
||||
else -> value.constValIndex = input.readUnsignedShort()
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The enum constant value.
|
||||
*
|
||||
* @property typeNameIndex The index of the entry in the constant pool which corresponds to the
|
||||
* name of the type of this constant.
|
||||
* @property constNameIndex The index of the entry in the constant pool which corresponds to the
|
||||
* name of this constant.
|
||||
*/
|
||||
data class EnumConstValue(val typeNameIndex: Int, val constNameIndex: Int) {
|
||||
companion object {
|
||||
internal fun read(input: DataInputStream): EnumConstValue {
|
||||
return EnumConstValue(input.readUnsignedShort(), input.readUnsignedShort())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** The type of [ElementValue]. */
|
||||
enum class Type(val tag: Int) {
|
||||
BYTE('B'.code),
|
||||
CHAR('C'.code),
|
||||
DOUBLE('D'.code),
|
||||
FLOAT('F'.code),
|
||||
INT('I'.code),
|
||||
LONG('J'.code),
|
||||
SHORT('S'.code),
|
||||
BOOLEAN('Z'.code),
|
||||
STRING('s'.code),
|
||||
ENUM_CLASS('e'.code),
|
||||
CLASS('c'.code),
|
||||
ANNOTATION_INTERFACE('@'.code),
|
||||
ARRAY_TYPE('['.code),
|
||||
|
||||
/** **FOR INTERNAL USE ONLY** */
|
||||
UNKNOWN('-'.code);
|
||||
|
||||
companion object {
|
||||
|
||||
/** Get the element type for the given tag value. */
|
||||
internal fun forTag(tag: Int): Type {
|
||||
return values().firstOrNull { it.tag == tag }
|
||||
?: throw IllegalArgumentException("Invalid tag for element value type tag '$tag'")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AndroidIDE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.itsaky.androidide.classfile.attributes
|
||||
|
||||
import com.itsaky.androidide.classfile.ClassFileConstants.ATTR_CONSTANT_VALUE
|
||||
import com.itsaky.androidide.classfile.ClassFileConstants.ATTR_DEPRECATED
|
||||
import com.itsaky.androidide.classfile.ClassFileConstants.ATTR_RUNTIME_INVISIBLE_ANNOTATIONS
|
||||
import com.itsaky.androidide.classfile.ClassFileConstants.ATTR_RUNTIME_INVISIBLE_TYPE_ANNOTATIONS
|
||||
import com.itsaky.androidide.classfile.ClassFileConstants.ATTR_RUNTIME_VISIBLE_ANNOTATIONS
|
||||
import com.itsaky.androidide.classfile.ClassFileConstants.ATTR_RUNTIME_VISIBLE_TYPE_ANNOTATIONS
|
||||
import com.itsaky.androidide.classfile.ClassFileConstants.ATTR_SIGNATURE
|
||||
import com.itsaky.androidide.classfile.ClassFileConstants.ATTR_SYNTHETIC
|
||||
import com.itsaky.androidide.classfile.ClassFileVersion
|
||||
import com.itsaky.androidide.classfile.IClassFile
|
||||
import com.itsaky.androidide.classfile.attributes.IAttribute.Type.CONSTANT_VALUE
|
||||
import com.itsaky.androidide.classfile.attributes.IAttribute.Type.DEPRECATED
|
||||
import com.itsaky.androidide.classfile.attributes.IAttribute.Type.RUNTIME_INVISIBLE_ANNOTATIONS
|
||||
import com.itsaky.androidide.classfile.attributes.IAttribute.Type.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS
|
||||
import com.itsaky.androidide.classfile.attributes.IAttribute.Type.RUNTIME_VISIBLE_ANNOTATIONS
|
||||
import com.itsaky.androidide.classfile.attributes.IAttribute.Type.RUNTIME_VISIBLE_TYPE_ANNOTATIONS
|
||||
import com.itsaky.androidide.classfile.attributes.IAttribute.Type.SIGNATURE
|
||||
import com.itsaky.androidide.classfile.attributes.IAttribute.Type.SYNTHETIC
|
||||
import com.itsaky.androidide.classfile.constants.Utf8Constant
|
||||
import com.itsaky.androidide.classfile.internal.ClassFile
|
||||
import java.io.DataInputStream
|
||||
|
||||
/**
|
||||
* Base class for all attributes in a class, field or method.
|
||||
*
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
interface IAttribute {
|
||||
|
||||
/** The version of the class file in which this attribute appears. */
|
||||
val version: ClassFileVersion
|
||||
|
||||
/** The index of the entry in the constant pool which represents the name of this attrbute. */
|
||||
val nameIndex: Int
|
||||
|
||||
/** The type of attribute. */
|
||||
val type: Type
|
||||
|
||||
/**
|
||||
* **FOR INTERNAL USE ONLY**
|
||||
*
|
||||
* Read further information from the given input.
|
||||
*/
|
||||
fun read(attrLength: Int, file: IClassFile, input: DataInputStream)
|
||||
|
||||
enum class Type(val attrName: String) {
|
||||
CONSTANT_VALUE(ATTR_CONSTANT_VALUE),
|
||||
SYNTHETIC(ATTR_SYNTHETIC),
|
||||
SIGNATURE(ATTR_SIGNATURE),
|
||||
DEPRECATED(ATTR_DEPRECATED),
|
||||
RUNTIME_VISIBLE_ANNOTATIONS(ATTR_RUNTIME_VISIBLE_ANNOTATIONS),
|
||||
RUNTIME_INVISIBLE_ANNOTATIONS(ATTR_RUNTIME_INVISIBLE_ANNOTATIONS),
|
||||
RUNTIME_VISIBLE_TYPE_ANNOTATIONS(ATTR_RUNTIME_VISIBLE_TYPE_ANNOTATIONS),
|
||||
RUNTIME_INVISIBLE_TYPE_ANNOTATIONS(ATTR_RUNTIME_INVISIBLE_TYPE_ANNOTATIONS);
|
||||
|
||||
companion object {
|
||||
internal fun forName(name: String): Type {
|
||||
return values().firstOrNull { it.attrName == name }
|
||||
?: throw IllegalArgumentException("Unknown attribute '$name'")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
internal fun read(input: DataInputStream, file: ClassFile): IAttribute {
|
||||
val nameIndex = input.readUnsignedShort()
|
||||
val attrLength = input.readInt()
|
||||
val name = (file.constantPool[nameIndex] as Utf8Constant).content()
|
||||
val type = Type.forName(name)
|
||||
return createForType(type, nameIndex).also { it.read(attrLength, file, input) }
|
||||
}
|
||||
|
||||
private fun createForType(type: Type, nameIndex: Int): IAttribute {
|
||||
return when (type) {
|
||||
CONSTANT_VALUE -> ConstantValueAttr(nameIndex)
|
||||
SYNTHETIC -> SyntheticAttr(nameIndex)
|
||||
SIGNATURE -> SignatureAttr(nameIndex)
|
||||
DEPRECATED -> DeprecatedAttr(nameIndex)
|
||||
RUNTIME_VISIBLE_ANNOTATIONS -> RuntimeVisibleAnnotationsAttr(nameIndex)
|
||||
RUNTIME_INVISIBLE_ANNOTATIONS -> RuntimeVisibleAnnotationsAttr(nameIndex)
|
||||
RUNTIME_VISIBLE_TYPE_ANNOTATIONS -> RuntimeVisibleTypeAnnotations(nameIndex)
|
||||
RUNTIME_INVISIBLE_TYPE_ANNOTATIONS -> RuntimeInvisibleTypeAnnotations(nameIndex)
|
||||
else -> throw IllegalArgumentException("Unknown attribute type $type")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AndroidIDE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.itsaky.androidide.classfile.attributes
|
||||
|
||||
import com.itsaky.androidide.classfile.ClassFileVersion
|
||||
import com.itsaky.androidide.classfile.IClassFile
|
||||
import com.itsaky.androidide.classfile.attributes.IAttribute.Type
|
||||
import java.io.DataInputStream
|
||||
|
||||
/**
|
||||
* An attribute which is simply a marker and does not contain any further information.
|
||||
*
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
abstract class MarkerAttribute(
|
||||
nameIndex: Int,
|
||||
override val type: Type,
|
||||
override val version: ClassFileVersion
|
||||
) : BaseAttribute(nameIndex) {
|
||||
override fun read(attrLength: Int, file: IClassFile, input: DataInputStream) {}
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AndroidIDE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.itsaky.androidide.classfile.attributes
|
||||
|
||||
import com.itsaky.androidide.classfile.attributes.IAttribute.Type
|
||||
import com.itsaky.androidide.classfile.attributes.IAttribute.Type.RUNTIME_INVISIBLE_ANNOTATIONS
|
||||
|
||||
/**
|
||||
* Stores run-time invisible annotations on the declaration of the corresponding class, method,
|
||||
* field, or record component.
|
||||
*
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
class RuntimeInvisibleAnnotationsAttr(nameIndex: Int) : AnnotationAttr(nameIndex) {
|
||||
override val type: Type = RUNTIME_INVISIBLE_ANNOTATIONS
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AndroidIDE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.itsaky.androidide.classfile.attributes
|
||||
|
||||
import com.itsaky.androidide.classfile.attributes.IAttribute.Type
|
||||
import com.itsaky.androidide.classfile.attributes.IAttribute.Type.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS
|
||||
import com.itsaky.androidide.classfile.attributes.IAttribute.Type.RUNTIME_VISIBLE_TYPE_ANNOTATIONS
|
||||
|
||||
/**
|
||||
* Stores run-time invisible annotations on type parameter declarations of generic classes,
|
||||
* interfaces, methods, and constructors.
|
||||
*
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
class RuntimeInvisibleTypeAnnotations(nameIndex: Int) : AnnotationAttr(nameIndex) {
|
||||
override val type: Type = RUNTIME_INVISIBLE_TYPE_ANNOTATIONS
|
||||
|
||||
/**
|
||||
* The annotations always of type [TypeAnnotation]
|
||||
*/
|
||||
var typeAnnotations: Array<TypeAnnotation> = emptyArray()
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AndroidIDE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.itsaky.androidide.classfile.attributes
|
||||
|
||||
import com.itsaky.androidide.classfile.attributes.IAttribute.Type
|
||||
import com.itsaky.androidide.classfile.attributes.IAttribute.Type.RUNTIME_VISIBLE_ANNOTATIONS
|
||||
|
||||
/**
|
||||
* Stores run-time visible annotations on the declaration of the corresponding class, field, method,
|
||||
* or record component.
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
class RuntimeVisibleAnnotationsAttr(nameIndex: Int) : AnnotationAttr(nameIndex) {
|
||||
override val type: Type = RUNTIME_VISIBLE_ANNOTATIONS
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AndroidIDE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.itsaky.androidide.classfile.attributes
|
||||
|
||||
import com.itsaky.androidide.classfile.attributes.IAttribute.Type
|
||||
import com.itsaky.androidide.classfile.attributes.IAttribute.Type.RUNTIME_VISIBLE_TYPE_ANNOTATIONS
|
||||
|
||||
/**
|
||||
* Stores run-time visible annotations on type parameter declarations of generic classes,
|
||||
* interfaces, methods, and constructors.
|
||||
*
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
class RuntimeVisibleTypeAnnotations(nameIndex: Int) : AnnotationAttr(nameIndex) {
|
||||
override val type: Type = RUNTIME_VISIBLE_TYPE_ANNOTATIONS
|
||||
|
||||
/**
|
||||
* The annotations always of type [TypeAnnotation]
|
||||
*/
|
||||
var typeAnnotations: Array<TypeAnnotation> = emptyArray()
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AndroidIDE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.itsaky.androidide.classfile.attributes
|
||||
|
||||
import com.itsaky.androidide.classfile.ClassFileVersion
|
||||
import com.itsaky.androidide.classfile.ClassFileVersion.JAVA_5
|
||||
import com.itsaky.androidide.classfile.IClassFile
|
||||
import com.itsaky.androidide.classfile.attributes.IAttribute.Type
|
||||
import com.itsaky.androidide.classfile.attributes.IAttribute.Type.SIGNATURE
|
||||
import java.io.DataInputStream
|
||||
|
||||
/**
|
||||
* Signature of a class, field or method.
|
||||
*
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
class SignatureAttr(nameIndex: Int) : BaseAttribute(nameIndex) {
|
||||
override val version: ClassFileVersion = JAVA_5
|
||||
override val type: Type = SIGNATURE
|
||||
|
||||
var signatureIndex: Int = -1
|
||||
internal set
|
||||
|
||||
override fun read(attrLength: Int, file: IClassFile, input: DataInputStream) {
|
||||
this.signatureIndex = input.readUnsignedShort()
|
||||
}
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AndroidIDE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.itsaky.androidide.classfile.attributes
|
||||
|
||||
import com.itsaky.androidide.classfile.ClassFileVersion.JAVA_1_1
|
||||
import com.itsaky.androidide.classfile.attributes.IAttribute.Type.SYNTHETIC
|
||||
|
||||
/**
|
||||
* Indicates that a class, field or method is synthetic.
|
||||
*
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
class SyntheticAttr(nameIndex: Int) : MarkerAttribute(nameIndex, SYNTHETIC, JAVA_1_1)
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AndroidIDE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.itsaky.androidide.classfile.attributes
|
||||
|
||||
import java.io.DataInputStream
|
||||
|
||||
/**
|
||||
* Annotation model for (in)visible type annotations.
|
||||
*
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
class TypeAnnotation {
|
||||
|
||||
lateinit var targetInfo: TargetInfo
|
||||
internal set
|
||||
|
||||
lateinit var typePath: TypePath
|
||||
internal set
|
||||
|
||||
/**
|
||||
* Index of the entry in the constant pool which corresponds to the type of the the annotation.
|
||||
* The entry at this index is always an UTF-8 constant.
|
||||
*/
|
||||
var typeIndex: Int = -1
|
||||
internal set
|
||||
|
||||
/** The element value pairs. */
|
||||
var elementValues: Array<Pair<Int, ElementValue>> = emptyArray()
|
||||
internal set
|
||||
|
||||
companion object {
|
||||
internal fun read(input: DataInputStream): TypeAnnotation {
|
||||
val annotation = TypeAnnotation()
|
||||
val targetType = input.readUnsignedByte()
|
||||
annotation.targetInfo = TargetInfo.forType(targetType).apply { read(input) }
|
||||
annotation.typePath = TypePath().apply { read(input) }
|
||||
annotation.typeIndex = input.readUnsignedShort()
|
||||
val valueCount = input.readUnsignedShort()
|
||||
annotation.elementValues =
|
||||
Array(valueCount) { input.readUnsignedShort() to ElementValue.read(input) }
|
||||
return annotation
|
||||
}
|
||||
}
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AndroidIDE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.itsaky.androidide.classfile.attributes
|
||||
|
||||
import java.io.DataInputStream
|
||||
|
||||
/**
|
||||
* Wherever a type is used in a declaration or expression, the type_path structure identifies which
|
||||
* part of the type is annotated. An annotation may appear on the type itself, but if the type is a
|
||||
* reference type, then there are additional locations where an annotation may appear.
|
||||
*
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
class TypePath {
|
||||
|
||||
var paths: Array<PathEntry> = emptyArray()
|
||||
internal set
|
||||
|
||||
class PathEntry {
|
||||
var typePathKind: Int = -1
|
||||
internal set
|
||||
var typeArgumentIndex: Int = -1
|
||||
internal set
|
||||
|
||||
internal fun read(input: DataInputStream) {
|
||||
this.typePathKind = input.readUnsignedByte()
|
||||
this.typeArgumentIndex = input.readUnsignedByte()
|
||||
}
|
||||
}
|
||||
|
||||
internal fun read(input: DataInputStream) {
|
||||
this.paths =
|
||||
Array(input.readUnsignedByte()) {
|
||||
val entry = PathEntry()
|
||||
entry.read(input)
|
||||
entry
|
||||
}
|
||||
}
|
||||
}
|
||||
+210
@@ -0,0 +1,210 @@
|
||||
/*
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AndroidIDE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.itsaky.androidide.classfile.attributes
|
||||
|
||||
import java.io.DataInputStream
|
||||
|
||||
/**
|
||||
* Target information in a type annotation.
|
||||
*
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
abstract class TargetInfo(val currentType: Int, val types: IntArray) {
|
||||
|
||||
/** The read the target info. */
|
||||
internal abstract fun read(input: DataInputStream)
|
||||
|
||||
companion object {
|
||||
|
||||
internal fun forType(type: Int): TargetInfo {
|
||||
return when (type) {
|
||||
0x00,
|
||||
0x01 -> TypeParameterTarget(type)
|
||||
0x10 -> SupertypeTarget(type)
|
||||
0x11,
|
||||
0x12 -> TypeParameterBoundTarget(type)
|
||||
0x13,
|
||||
0x14,
|
||||
0x15 -> EmptyTarget(type)
|
||||
0x16 -> FormalParameterTarget(type)
|
||||
0x17 -> ThrowsTarget(type)
|
||||
0x40,
|
||||
0x41 -> LocalVarTarget(type)
|
||||
0x42 -> CatchTarget(type)
|
||||
0x43,
|
||||
0x44,
|
||||
0x45,
|
||||
0x46 -> OffsetTarget(type)
|
||||
0x47,
|
||||
0x48,
|
||||
0x49,
|
||||
0x4A,
|
||||
0x4B -> TypeArgumentTarget(type)
|
||||
else -> throw IllegalArgumentException("Unknown type parameter target")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
open class TypeParameterTarget
|
||||
@JvmOverloads
|
||||
constructor(currentType: Int, types: IntArray = intArrayOf(0x00, 0x01)) :
|
||||
TargetInfo(currentType, types) {
|
||||
|
||||
/**
|
||||
* The value of the type_parameter_index item specifies which type parameter declaration is
|
||||
* annotated. A type_parameter_index value of 0 specifies the first type parameter declaration.
|
||||
*/
|
||||
var typeParameterIndex: Int = -1
|
||||
internal set
|
||||
|
||||
override fun read(input: DataInputStream) {
|
||||
this.typeParameterIndex = input.readUnsignedByte()
|
||||
}
|
||||
}
|
||||
|
||||
class SupertypeTarget(currentType: Int) : TargetInfo(currentType, intArrayOf(0x10)) {
|
||||
|
||||
/**
|
||||
* A supertype_index value of 65535 specifies that the annotation appears on the superclass in an
|
||||
* extends clause of a class declaration.
|
||||
*
|
||||
* Any other supertype_index value is an index into the interfaces array of the enclosing
|
||||
* ClassFile structure, and specifies that the annotation appears on that superinterface in either
|
||||
* the implements clause of a class declaration or the extends clause of an interface declaration.
|
||||
*/
|
||||
var supertypeIndex: Int = -1
|
||||
internal set
|
||||
|
||||
override fun read(input: DataInputStream) {
|
||||
this.supertypeIndex = input.readUnsignedShort()
|
||||
}
|
||||
}
|
||||
|
||||
class TypeParameterBoundTarget(currentType: Int) :
|
||||
TypeParameterTarget(currentType, intArrayOf(0x11, 0x12)) {
|
||||
|
||||
/**
|
||||
* The value of the bound_index item specifies which bound of the type parameter declaration
|
||||
* indicated by type_parameter_index is annotated. A bound_index value of 0 specifies the first
|
||||
* bound of a type parameter declaration.
|
||||
*/
|
||||
var boundIndex: Int = -1
|
||||
internal set
|
||||
|
||||
override fun read(input: DataInputStream) {
|
||||
super.read(input)
|
||||
this.boundIndex = input.readUnsignedShort()
|
||||
}
|
||||
}
|
||||
|
||||
class EmptyTarget(currentType: Int) : TargetInfo(currentType, intArrayOf(0x13, 0x14, 0x15)) {
|
||||
|
||||
override fun read(input: DataInputStream) {}
|
||||
}
|
||||
|
||||
class FormalParameterTarget(currentType: Int) : TargetInfo(currentType, intArrayOf(0x16)) {
|
||||
|
||||
/**
|
||||
* The value of the formal_parameter_index item specifies which formal parameter declaration has
|
||||
* an annotated type. A formal_parameter_index value of i may, but is not required to, correspond
|
||||
* to the i'th parameter descriptor in the method descriptor.
|
||||
*/
|
||||
var formalParameterIndex: Int = -1
|
||||
internal set
|
||||
|
||||
override fun read(input: DataInputStream) {
|
||||
this.formalParameterIndex = input.readUnsignedByte()
|
||||
}
|
||||
}
|
||||
|
||||
class ThrowsTarget(currentType: Int) : TargetInfo(currentType, intArrayOf(0x17)) {
|
||||
|
||||
/**
|
||||
* The value of the throws_type_index item is an index into the exception_index_table array of the
|
||||
* Exceptions attribute of the method_info structure enclosing the RuntimeVisibleTypeAnnotations
|
||||
* attribute.
|
||||
*/
|
||||
var throwsTypeIndex: Int = -1
|
||||
internal set
|
||||
|
||||
override fun read(input: DataInputStream) {
|
||||
this.throwsTypeIndex = input.readUnsignedShort()
|
||||
}
|
||||
}
|
||||
|
||||
class LocalVarTarget(currentType: Int) : TargetInfo(currentType, intArrayOf(0x40, 0x41)) {
|
||||
|
||||
var table: Array<LocalVarTagetTableEntry> = emptyArray()
|
||||
|
||||
class LocalVarTagetTableEntry {
|
||||
var startPc: Int = -1
|
||||
internal set
|
||||
var length: Int = -1
|
||||
internal set
|
||||
var index: Int = -1
|
||||
internal set
|
||||
}
|
||||
|
||||
override fun read(input: DataInputStream) {
|
||||
val length = input.readUnsignedShort()
|
||||
this.table =
|
||||
Array(length) {
|
||||
val entry = LocalVarTagetTableEntry()
|
||||
entry.startPc = input.readUnsignedShort()
|
||||
entry.length = input.readUnsignedShort()
|
||||
entry.index = input.readUnsignedShort()
|
||||
entry
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class CatchTarget(currentType: Int) : TargetInfo(currentType, intArrayOf(0x42)) {
|
||||
|
||||
var exceptionTableIndex: Int = -1
|
||||
internal set
|
||||
|
||||
override fun read(input: DataInputStream) {
|
||||
this.exceptionTableIndex = input.readUnsignedShort()
|
||||
}
|
||||
}
|
||||
|
||||
class OffsetTarget(currentType: Int) : TargetInfo(currentType, intArrayOf(0x43, 0x44, 0x45, 0x46)) {
|
||||
|
||||
var offset: Int = -1
|
||||
internal set
|
||||
|
||||
override fun read(input: DataInputStream) {
|
||||
this.offset = input.readUnsignedShort()
|
||||
}
|
||||
}
|
||||
|
||||
class TypeArgumentTarget(currentType: Int) :
|
||||
TargetInfo(currentType, intArrayOf(0x47, 0x48, 0x49, 0x4A, 0x4B)) {
|
||||
|
||||
var offset: Int = -1
|
||||
internal set
|
||||
|
||||
var typeArgumentIndex: Int = -1
|
||||
internal set
|
||||
|
||||
override fun read(input: DataInputStream) {
|
||||
this.offset = input.readUnsignedShort()
|
||||
this.typeArgumentIndex = input.readUnsignedByte()
|
||||
}
|
||||
}
|
||||
+4
-1
@@ -33,6 +33,9 @@ class Utf8Constant : IConstant {
|
||||
var bytes: ByteArray = ByteArray(0)
|
||||
private set
|
||||
|
||||
/** Get the string represented by this constant. */
|
||||
fun content() = this.bytes.decodeToString()
|
||||
|
||||
override fun read(input: DataInputStream) {
|
||||
val length = input.readUnsignedShort()
|
||||
this.bytes = ByteArray(length)
|
||||
@@ -56,6 +59,6 @@ class Utf8Constant : IConstant {
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "Utf8Constant(type=$type, bytes=${bytes.contentToString()}, bytesAsString=${bytes.decodeToString()})"
|
||||
return "Utf8Constant(type=$type, bytes=${bytes.contentToString()}, bytesAsString=${content()})"
|
||||
}
|
||||
}
|
||||
|
||||
+5
-20
@@ -17,8 +17,11 @@
|
||||
|
||||
package com.itsaky.androidide.classfile.internal
|
||||
|
||||
import com.itsaky.androidide.classfile.ClassFileVersion
|
||||
import com.itsaky.androidide.classfile.ClassFileVersion.JAVA_1_0
|
||||
import com.itsaky.androidide.classfile.constants.IConstant
|
||||
import com.itsaky.androidide.classfile.IClassFile
|
||||
import com.itsaky.androidide.classfile.IFieldInfo
|
||||
import com.itsaky.androidide.classfile.constants.ClassConstant
|
||||
import com.itsaky.androidide.classfile.constants.Utf8Constant
|
||||
|
||||
@@ -29,31 +32,13 @@ import com.itsaky.androidide.classfile.constants.Utf8Constant
|
||||
*/
|
||||
internal class ClassFile : IClassFile {
|
||||
|
||||
/** Major version of the class file. */
|
||||
override var majorVersion: Int = 0
|
||||
|
||||
/** Minor version of the class file. */
|
||||
override var minorVersion: Int = 0
|
||||
|
||||
/** The constant pool. */
|
||||
override var version: ClassFileVersion = JAVA_1_0
|
||||
override var constantPool: Array<IConstant> = emptyArray()
|
||||
|
||||
/** Access flags for the class. */
|
||||
override var accessFlags: Int = 0
|
||||
|
||||
/**
|
||||
* The index in the constant pool which corresponds to the internal representation of the name of
|
||||
* this class.
|
||||
*/
|
||||
override var thisClass: Int = -1
|
||||
|
||||
/**
|
||||
* The index in the constant pool which corresponds to the internal representation of the name of
|
||||
* the super class of this class.
|
||||
*/
|
||||
override var superClass: Int = -1
|
||||
|
||||
override var interfaces: IntArray = IntArray(0)
|
||||
override var fields: Array<IFieldInfo> = emptyArray()
|
||||
|
||||
override fun getName(): String {
|
||||
val entry = constantPool[thisClass]
|
||||
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AndroidIDE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.itsaky.androidide.classfile.internal
|
||||
|
||||
import com.itsaky.androidide.classfile.IFieldInfo
|
||||
import com.itsaky.androidide.classfile.attributes.IAttribute
|
||||
|
||||
/**
|
||||
* Default internal implementation of [IFieldInfo].
|
||||
*
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
internal class FieldInfo : IFieldInfo {
|
||||
override var accessFlags: Int = 0
|
||||
internal set
|
||||
override var nameIndex: Int = -1
|
||||
internal set
|
||||
override var descriptorIndex: Int = -1
|
||||
internal set
|
||||
override var attributes: Array<IAttribute> = emptyArray()
|
||||
internal set
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AndroidIDE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.itsaky.androidide.classfile.internal
|
||||
|
||||
import com.itsaky.androidide.classfile.ClassFileVersion
|
||||
import com.itsaky.androidide.classfile.IClassFile
|
||||
import com.itsaky.androidide.classfile.attributes.IAttribute
|
||||
import com.itsaky.androidide.classfile.attributes.IAttribute.Type
|
||||
import java.io.DataInputStream
|
||||
|
||||
/**
|
||||
* **FOR INTERNAL USE ONLY**
|
||||
*
|
||||
* Represents a null attribute. Not present in a class file.
|
||||
*
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
internal object NullAttribute : IAttribute {
|
||||
override val version: ClassFileVersion
|
||||
get() = throw UnsupportedOperationException()
|
||||
override val nameIndex: Int
|
||||
get() = throw UnsupportedOperationException()
|
||||
override val type: Type
|
||||
get() = throw UnsupportedOperationException()
|
||||
|
||||
override fun read(attrLength: Int, file: IClassFile, input: DataInputStream) {
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AndroidIDE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.itsaky.androidide.classfile.internal
|
||||
|
||||
import com.itsaky.androidide.classfile.IFieldInfo
|
||||
import com.itsaky.androidide.classfile.attributes.IAttribute
|
||||
|
||||
/**
|
||||
* **FOR INTERNAL USE ONLY**
|
||||
*
|
||||
* Represents a null field. Not available in class file.
|
||||
*
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
internal object NullField : IFieldInfo {
|
||||
override val accessFlags: Int
|
||||
get() = throw UnsupportedOperationException()
|
||||
override val nameIndex: Int
|
||||
get() = throw UnsupportedOperationException()
|
||||
override val descriptorIndex: Int
|
||||
get() = throw UnsupportedOperationException()
|
||||
override val attributes: Array<IAttribute>
|
||||
get() = throw UnsupportedOperationException()
|
||||
}
|
||||
+1
-2
@@ -39,8 +39,7 @@ class ClassFileReaderTest {
|
||||
val file = reader.read()
|
||||
|
||||
assertThat(file).isNotNull()
|
||||
assertThat(file.majorVersion).isEqualTo(55)
|
||||
assertThat(file.minorVersion).isEqualTo(0)
|
||||
assertThat(file.version).isEqualTo(ClassFileVersion.JAVA_11)
|
||||
|
||||
assertThat(file.getName()).isEqualTo("io/github/rosemoe/sora/widget/CodeEditor")
|
||||
assertThat(file.getSuperClassName()).isEqualTo("android/view/View")
|
||||
|
||||
Reference in New Issue
Block a user