forked from openrs2/openrs2
parent
ad0cdb6056
commit
2a6b97480c
@ -1,11 +1,36 @@ |
|||||||
package org.openrs2.asm.io |
package org.openrs2.asm.io |
||||||
|
|
||||||
|
import io.netty.buffer.ByteBufAllocator |
||||||
import org.objectweb.asm.tree.ClassNode |
import org.objectweb.asm.tree.ClassNode |
||||||
|
import org.openrs2.asm.packclass.ConstantPool |
||||||
|
import org.openrs2.asm.packclass.PackClass |
||||||
|
import org.openrs2.buffer.use |
||||||
|
import org.openrs2.cache.Js5Pack |
||||||
import java.io.InputStream |
import java.io.InputStream |
||||||
|
import javax.inject.Inject |
||||||
|
import javax.inject.Singleton |
||||||
|
|
||||||
public object PackClassLibraryReader : LibraryReader { |
@Singleton |
||||||
|
public class PackClassLibraryReader @Inject constructor( |
||||||
|
private val alloc: ByteBufAllocator |
||||||
|
) : LibraryReader { |
||||||
override fun read(input: InputStream): Iterable<ClassNode> { |
override fun read(input: InputStream): Iterable<ClassNode> { |
||||||
// TODO(gpe): implement |
Js5Pack.read(input, alloc).use { pack -> |
||||||
return emptyList() |
// read constant pool |
||||||
|
val constantPool = pack.read(PackClass.CONSTANT_POOL_GROUP, PackClass.CONSTANT_POOL_FILE).use { buf -> |
||||||
|
ConstantPool.read(buf) |
||||||
|
} |
||||||
|
|
||||||
|
// read classes |
||||||
|
val classes = mutableListOf<ClassNode>() |
||||||
|
|
||||||
|
for (entry in pack.list(PackClass.CLASS_GROUP)) { |
||||||
|
pack.read(PackClass.CLASS_GROUP, entry.id).use { buf -> |
||||||
|
classes += PackClass.read(buf, constantPool) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return classes |
||||||
|
} |
||||||
} |
} |
||||||
} |
} |
||||||
|
@ -1,11 +1,45 @@ |
|||||||
package org.openrs2.asm.io |
package org.openrs2.asm.io |
||||||
|
|
||||||
|
import io.netty.buffer.ByteBufAllocator |
||||||
import org.objectweb.asm.tree.ClassNode |
import org.objectweb.asm.tree.ClassNode |
||||||
import org.openrs2.asm.classpath.ClassPath |
import org.openrs2.asm.classpath.ClassPath |
||||||
|
import org.openrs2.asm.packclass.ConstantPool |
||||||
|
import org.openrs2.asm.packclass.PackClass |
||||||
|
import org.openrs2.buffer.use |
||||||
|
import org.openrs2.cache.Js5Pack |
||||||
import java.io.OutputStream |
import java.io.OutputStream |
||||||
|
import javax.inject.Inject |
||||||
|
import javax.inject.Singleton |
||||||
|
|
||||||
public object PackClassLibraryWriter : LibraryWriter { |
@Singleton |
||||||
|
public class PackClassLibraryWriter @Inject constructor( |
||||||
|
private val alloc: ByteBufAllocator |
||||||
|
) : LibraryWriter { |
||||||
override fun write(output: OutputStream, classPath: ClassPath, classes: Iterable<ClassNode>) { |
override fun write(output: OutputStream, classPath: ClassPath, classes: Iterable<ClassNode>) { |
||||||
// TODO(gpe): implement |
Js5Pack.create(alloc).use { pack -> |
||||||
|
// create constant pool |
||||||
|
val builder = ConstantPool.Builder() |
||||||
|
for (clazz in classes) { |
||||||
|
builder.add(clazz) |
||||||
|
} |
||||||
|
val constantPool = builder.build() |
||||||
|
|
||||||
|
// write classes |
||||||
|
for ((i, clazz) in classes.withIndex()) { |
||||||
|
alloc.buffer().use { buf -> |
||||||
|
PackClass.write(buf, constantPool, clazz) |
||||||
|
pack.write(PackClass.CLASS_GROUP, i, buf) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// write constant pool |
||||||
|
alloc.buffer().use { buf -> |
||||||
|
constantPool.write(buf) |
||||||
|
pack.write(PackClass.CONSTANT_POOL_GROUP, PackClass.CONSTANT_POOL_FILE, buf) |
||||||
|
} |
||||||
|
|
||||||
|
// write pack |
||||||
|
pack.write(output) |
||||||
|
} |
||||||
} |
} |
||||||
} |
} |
||||||
|
@ -0,0 +1,565 @@ |
|||||||
|
package org.openrs2.asm.packclass |
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf |
||||||
|
import it.unimi.dsi.fastutil.doubles.DoubleAVLTreeSet |
||||||
|
import it.unimi.dsi.fastutil.floats.FloatAVLTreeSet |
||||||
|
import it.unimi.dsi.fastutil.ints.IntAVLTreeSet |
||||||
|
import it.unimi.dsi.fastutil.longs.LongAVLTreeSet |
||||||
|
import it.unimi.dsi.fastutil.objects.ObjectAVLTreeSet |
||||||
|
import org.objectweb.asm.Type |
||||||
|
import org.objectweb.asm.tree.ClassNode |
||||||
|
import org.objectweb.asm.tree.FieldInsnNode |
||||||
|
import org.objectweb.asm.tree.LdcInsnNode |
||||||
|
import org.objectweb.asm.tree.MethodInsnNode |
||||||
|
import org.objectweb.asm.tree.MultiANewArrayInsnNode |
||||||
|
import org.objectweb.asm.tree.TypeInsnNode |
||||||
|
import org.openrs2.buffer.readString |
||||||
|
import org.openrs2.buffer.writeString |
||||||
|
import org.openrs2.util.charset.ModifiedUtf8Charset |
||||||
|
|
||||||
|
public class ConstantPool private constructor( |
||||||
|
private val strings: Array<String>, |
||||||
|
private val fieldNamesAndTypes: Array<NameAndType>, |
||||||
|
private val methodNamesAndTypes: Array<NameAndType>, |
||||||
|
private val fieldRefs: Array<MemberRef>, |
||||||
|
private val methodRefs: Array<MemberRef>, |
||||||
|
private val interfaceMethodRefs: Array<MemberRef>, |
||||||
|
private val ints: IntArray, |
||||||
|
private val longs: LongArray, |
||||||
|
private val floats: FloatArray, |
||||||
|
private val doubles: DoubleArray |
||||||
|
) { |
||||||
|
public class Builder { |
||||||
|
private val strings = ObjectAVLTreeSet<String>() |
||||||
|
private val fieldNamesAndTypes = ObjectAVLTreeSet<NameAndType>() |
||||||
|
private val methodNamesAndTypes = ObjectAVLTreeSet<NameAndType>() |
||||||
|
private val fieldRefs = ObjectAVLTreeSet<MemberRef>() |
||||||
|
private val methodRefs = ObjectAVLTreeSet<MemberRef>() |
||||||
|
private val interfaceMethodRefs = ObjectAVLTreeSet<MemberRef>() |
||||||
|
private val ints = IntAVLTreeSet() |
||||||
|
private val longs = LongAVLTreeSet() |
||||||
|
private val floats = FloatAVLTreeSet() |
||||||
|
private val doubles = DoubleAVLTreeSet() |
||||||
|
|
||||||
|
public fun add(clazz: ClassNode): Builder { |
||||||
|
if (clazz.sourceFile != null) { |
||||||
|
strings += clazz.sourceFile |
||||||
|
} |
||||||
|
|
||||||
|
strings += clazz.name |
||||||
|
strings += clazz.superName |
||||||
|
|
||||||
|
strings.addAll(clazz.interfaces) |
||||||
|
|
||||||
|
for (method in clazz.methods) { |
||||||
|
addMethodNameAndType(NameAndType(method.name, method.desc)) |
||||||
|
|
||||||
|
strings += method.exceptions |
||||||
|
|
||||||
|
for (tryCatch in method.tryCatchBlocks) { |
||||||
|
if (tryCatch.type != null) { |
||||||
|
strings += tryCatch.type |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
for (insn in method.instructions) { |
||||||
|
when (insn) { |
||||||
|
is LdcInsnNode -> addConstant(insn.cst) |
||||||
|
is MultiANewArrayInsnNode -> strings += insn.desc |
||||||
|
is MethodInsnNode -> { |
||||||
|
val methodRef = MemberRef(insn.owner, insn.name, insn.desc) |
||||||
|
if (insn.itf) { |
||||||
|
addInterfaceMethodRef(methodRef) |
||||||
|
} else { |
||||||
|
addMethodRef(methodRef) |
||||||
|
} |
||||||
|
} |
||||||
|
is FieldInsnNode -> addFieldRef(MemberRef(insn.owner, insn.name, insn.desc)) |
||||||
|
is TypeInsnNode -> strings += insn.desc |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
for (field in clazz.fields) { |
||||||
|
addFieldNameAndType(NameAndType(field.name, field.desc)) |
||||||
|
|
||||||
|
if (field.value != null) { |
||||||
|
addConstant(field.value) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return this |
||||||
|
} |
||||||
|
|
||||||
|
private fun addFieldNameAndType(nameAndType: NameAndType) { |
||||||
|
strings += nameAndType.name |
||||||
|
strings += nameAndType.descriptor |
||||||
|
fieldNamesAndTypes += nameAndType |
||||||
|
} |
||||||
|
|
||||||
|
private fun addMethodNameAndType(nameAndType: NameAndType) { |
||||||
|
strings += nameAndType.name |
||||||
|
strings += nameAndType.descriptor |
||||||
|
methodNamesAndTypes += nameAndType |
||||||
|
} |
||||||
|
|
||||||
|
private fun addFieldRef(fieldRef: MemberRef) { |
||||||
|
strings += fieldRef.clazz |
||||||
|
addFieldNameAndType(fieldRef.nameAndType) |
||||||
|
fieldRefs += fieldRef |
||||||
|
} |
||||||
|
|
||||||
|
private fun addMethodRef(methodRef: MemberRef) { |
||||||
|
strings += methodRef.clazz |
||||||
|
addMethodNameAndType(methodRef.nameAndType) |
||||||
|
methodRefs += methodRef |
||||||
|
} |
||||||
|
|
||||||
|
private fun addInterfaceMethodRef(methodRef: MemberRef) { |
||||||
|
strings += methodRef.clazz |
||||||
|
addMethodNameAndType(methodRef.nameAndType) |
||||||
|
interfaceMethodRefs += methodRef |
||||||
|
} |
||||||
|
|
||||||
|
private fun addConstant(value: Any) { |
||||||
|
when (value) { |
||||||
|
is Int -> ints += value |
||||||
|
is Long -> longs += value |
||||||
|
is Float -> floats += value |
||||||
|
is Double -> doubles += value |
||||||
|
is String -> strings += value |
||||||
|
is Type -> { |
||||||
|
if (value.sort == Type.OBJECT) { |
||||||
|
strings += value.internalName |
||||||
|
} else { |
||||||
|
throw IllegalArgumentException("Unsupported constant type: ${value.sort}") |
||||||
|
} |
||||||
|
} |
||||||
|
else -> throw IllegalArgumentException("Unsupported constant type: ${value.javaClass.name}") |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public fun build(): ConstantPool { |
||||||
|
strings.remove(CODE) |
||||||
|
strings.remove(EXCEPTIONS) |
||||||
|
strings.remove(SYNTHETIC) |
||||||
|
strings.remove(CONSTANT_VALUE) |
||||||
|
strings.remove(SOURCE_FILE) |
||||||
|
strings.remove(LINE_NUMBER_TABLE) |
||||||
|
|
||||||
|
val it = strings.iterator() |
||||||
|
val stringArray = Array(6 + strings.size) { i -> |
||||||
|
when (i) { |
||||||
|
0 -> CODE |
||||||
|
1 -> EXCEPTIONS |
||||||
|
2 -> SYNTHETIC |
||||||
|
3 -> CONSTANT_VALUE |
||||||
|
4 -> SOURCE_FILE |
||||||
|
5 -> LINE_NUMBER_TABLE |
||||||
|
else -> it.next() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return ConstantPool( |
||||||
|
stringArray, |
||||||
|
fieldNamesAndTypes.toTypedArray(), |
||||||
|
methodNamesAndTypes.toTypedArray(), |
||||||
|
fieldRefs.toTypedArray(), |
||||||
|
methodRefs.toTypedArray(), |
||||||
|
interfaceMethodRefs.toTypedArray(), |
||||||
|
ints.toIntArray(), |
||||||
|
longs.toLongArray(), |
||||||
|
floats.toFloatArray(), |
||||||
|
doubles.toDoubleArray() |
||||||
|
) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public fun readString(buf: ByteBuf): String { |
||||||
|
val index = buf.readUnsignedShort() |
||||||
|
return strings[index] |
||||||
|
} |
||||||
|
|
||||||
|
private fun getStringIndex(value: String): Int { |
||||||
|
return when (value) { |
||||||
|
CODE -> 0 |
||||||
|
EXCEPTIONS -> 1 |
||||||
|
SYNTHETIC -> 2 |
||||||
|
CONSTANT_VALUE -> 3 |
||||||
|
SOURCE_FILE -> 4 |
||||||
|
LINE_NUMBER_TABLE -> 5 |
||||||
|
else -> strings.binarySearch(value, 6) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public fun writeString(buf: ByteBuf, value: String) { |
||||||
|
buf.writeShort(getStringIndex(value)) |
||||||
|
} |
||||||
|
|
||||||
|
public fun readOptionalString(buf: ByteBuf): String? { |
||||||
|
val index = buf.readUnsignedShort() |
||||||
|
return if (index != 0) { |
||||||
|
strings[index - 1] |
||||||
|
} else { |
||||||
|
null |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public fun writeOptionalString(buf: ByteBuf, value: String?) { |
||||||
|
if (value != null) { |
||||||
|
buf.writeShort(getStringIndex(value) + 1) |
||||||
|
} else { |
||||||
|
buf.writeShort(0) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public fun readFieldNameAndType(buf: ByteBuf): NameAndType { |
||||||
|
val index = buf.readUnsignedShort() |
||||||
|
return fieldNamesAndTypes[index] |
||||||
|
} |
||||||
|
|
||||||
|
public fun writeFieldNameAndType(buf: ByteBuf, value: NameAndType) { |
||||||
|
buf.writeShort(fieldNamesAndTypes.binarySearch(value)) |
||||||
|
} |
||||||
|
|
||||||
|
public fun readMethodNameAndType(buf: ByteBuf): NameAndType { |
||||||
|
val index = buf.readUnsignedShort() |
||||||
|
return methodNamesAndTypes[index] |
||||||
|
} |
||||||
|
|
||||||
|
public fun writeMethodNameAndType(buf: ByteBuf, value: NameAndType) { |
||||||
|
buf.writeShort(methodNamesAndTypes.binarySearch(value)) |
||||||
|
} |
||||||
|
|
||||||
|
public fun readFieldRef(buf: ByteBuf): MemberRef { |
||||||
|
val index = buf.readUnsignedShort() |
||||||
|
return fieldRefs[index] |
||||||
|
} |
||||||
|
|
||||||
|
public fun writeFieldRef(buf: ByteBuf, value: MemberRef) { |
||||||
|
buf.writeShort(fieldRefs.binarySearch(value)) |
||||||
|
} |
||||||
|
|
||||||
|
public fun readMethodRef(buf: ByteBuf): MemberRef { |
||||||
|
val index = buf.readUnsignedShort() |
||||||
|
return methodRefs[index] |
||||||
|
} |
||||||
|
|
||||||
|
public fun writeMethodRef(buf: ByteBuf, value: MemberRef) { |
||||||
|
buf.writeShort(methodRefs.binarySearch(value)) |
||||||
|
} |
||||||
|
|
||||||
|
public fun readInterfaceMethodRef(buf: ByteBuf): MemberRef { |
||||||
|
val index = buf.readUnsignedShort() |
||||||
|
return interfaceMethodRefs[index] |
||||||
|
} |
||||||
|
|
||||||
|
public fun writeInterfaceMethodRef(buf: ByteBuf, value: MemberRef) { |
||||||
|
buf.writeShort(interfaceMethodRefs.binarySearch(value)) |
||||||
|
} |
||||||
|
|
||||||
|
public fun readInt(buf: ByteBuf): Int { |
||||||
|
val index = buf.readUnsignedShort() |
||||||
|
return ints[index] |
||||||
|
} |
||||||
|
|
||||||
|
public fun writeInt(buf: ByteBuf, value: Int) { |
||||||
|
buf.writeShort(ints.binarySearch(value)) |
||||||
|
} |
||||||
|
|
||||||
|
public fun readLong(buf: ByteBuf): Long { |
||||||
|
val index = buf.readUnsignedShort() |
||||||
|
return longs[index] |
||||||
|
} |
||||||
|
|
||||||
|
public fun writeLong(buf: ByteBuf, value: Long) { |
||||||
|
buf.writeShort(longs.binarySearch(value)) |
||||||
|
} |
||||||
|
|
||||||
|
public fun readFloat(buf: ByteBuf): Float { |
||||||
|
val index = buf.readUnsignedShort() |
||||||
|
return floats[index] |
||||||
|
} |
||||||
|
|
||||||
|
public fun writeFloat(buf: ByteBuf, value: Float) { |
||||||
|
buf.writeShort(floats.binarySearch(value)) |
||||||
|
} |
||||||
|
|
||||||
|
public fun readDouble(buf: ByteBuf): Double { |
||||||
|
val index = buf.readUnsignedShort() |
||||||
|
return doubles[index] |
||||||
|
} |
||||||
|
|
||||||
|
public fun writeDouble(buf: ByteBuf, value: Double) { |
||||||
|
buf.writeShort(doubles.binarySearch(value)) |
||||||
|
} |
||||||
|
|
||||||
|
public fun write(buf: ByteBuf) { |
||||||
|
writeStrings(buf) |
||||||
|
|
||||||
|
writeNameAndTypeNames(buf, fieldNamesAndTypes) |
||||||
|
writeNameAndTypeNames(buf, methodNamesAndTypes) |
||||||
|
writeNameAndTypeDescriptors(buf, fieldNamesAndTypes) |
||||||
|
writeNameAndTypeDescriptors(buf, methodNamesAndTypes) |
||||||
|
|
||||||
|
writeMemberRefClasses(buf, fieldRefs) |
||||||
|
writeMemberRefClasses(buf, methodRefs) |
||||||
|
writeMemberRefClasses(buf, interfaceMethodRefs) |
||||||
|
writeFieldRefNamesAndTypes(buf) |
||||||
|
writeMethodRefNamesAndTypes(buf, methodRefs) |
||||||
|
writeMethodRefNamesAndTypes(buf, interfaceMethodRefs) |
||||||
|
|
||||||
|
writeInts(buf, ints) |
||||||
|
writeLongs(buf, longs) |
||||||
|
writeFloats(buf) |
||||||
|
writeDoubles(buf) |
||||||
|
|
||||||
|
buf.writeShort(strings.size) |
||||||
|
buf.writeShort(ints.size) |
||||||
|
buf.writeShort(longs.size) |
||||||
|
buf.writeShort(floats.size) |
||||||
|
buf.writeShort(doubles.size) |
||||||
|
buf.writeShort(fieldNamesAndTypes.size) |
||||||
|
buf.writeShort(methodNamesAndTypes.size) |
||||||
|
buf.writeShort(fieldRefs.size) |
||||||
|
buf.writeShort(methodRefs.size) |
||||||
|
buf.writeShort(interfaceMethodRefs.size) |
||||||
|
} |
||||||
|
|
||||||
|
private fun writeStrings(buf: ByteBuf) { |
||||||
|
for (i in 6 until strings.size) { |
||||||
|
buf.writeString(strings[i], ModifiedUtf8Charset) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private fun writeNameAndTypeNames(buf: ByteBuf, namesAndTypes: Array<NameAndType>) { |
||||||
|
for (nameAndType in namesAndTypes) { |
||||||
|
writeString(buf, nameAndType.name) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private fun writeNameAndTypeDescriptors(buf: ByteBuf, namesAndTypes: Array<NameAndType>) { |
||||||
|
for (nameAndType in namesAndTypes) { |
||||||
|
writeString(buf, nameAndType.descriptor) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private fun writeMemberRefClasses(buf: ByteBuf, memberRefs: Array<MemberRef>) { |
||||||
|
for (memberRef in memberRefs) { |
||||||
|
writeString(buf, memberRef.clazz) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private fun writeFieldRefNamesAndTypes(buf: ByteBuf) { |
||||||
|
for (fieldRef in fieldRefs) { |
||||||
|
writeFieldNameAndType(buf, fieldRef.nameAndType) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private fun writeMethodRefNamesAndTypes(buf: ByteBuf, methodRefs: Array<MemberRef>) { |
||||||
|
for (methodRef in methodRefs) { |
||||||
|
writeMethodNameAndType(buf, methodRef.nameAndType) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private fun writeInts(buf: ByteBuf, values: IntArray) { |
||||||
|
for (i in 24 downTo 0 step 8) { |
||||||
|
var previous = 0 |
||||||
|
for (value in values) { |
||||||
|
buf.writeByte((value - previous) shr i) |
||||||
|
previous = value |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private fun writeLongs(buf: ByteBuf, values: LongArray) { |
||||||
|
for (i in 56 downTo 0 step 8) { |
||||||
|
var previous = 0L |
||||||
|
for (value in values) { |
||||||
|
buf.writeByte(((value - previous) shr i).toInt()) |
||||||
|
previous = value |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private fun writeFloats(buf: ByteBuf) { |
||||||
|
writeInts(buf, IntArray(floats.size) { i -> |
||||||
|
floats[i].toRawBits() |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
private fun writeDoubles(buf: ByteBuf) { |
||||||
|
writeLongs(buf, LongArray(doubles.size) { i -> |
||||||
|
doubles[i].toRawBits() |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
public companion object { |
||||||
|
public const val CODE: String = "Code" |
||||||
|
public const val EXCEPTIONS: String = "Exceptions" |
||||||
|
public const val SYNTHETIC: String = "Synthetic" |
||||||
|
public const val CONSTANT_VALUE: String = "ConstantValue" |
||||||
|
public const val SOURCE_FILE: String = "SourceFile" |
||||||
|
public const val LINE_NUMBER_TABLE: String = "LineNumberTable" |
||||||
|
|
||||||
|
private const val TRAILER_LEN = 20 |
||||||
|
|
||||||
|
public fun read(buf: ByteBuf): ConstantPool { |
||||||
|
// read trailer |
||||||
|
buf.markReaderIndex() |
||||||
|
buf.readerIndex(buf.writerIndex() - TRAILER_LEN) |
||||||
|
|
||||||
|
val stringCount = buf.readUnsignedShort() |
||||||
|
val intCount = buf.readUnsignedShort() |
||||||
|
val longCount = buf.readUnsignedShort() |
||||||
|
val floatCount = buf.readUnsignedShort() |
||||||
|
val doubleCount = buf.readUnsignedShort() |
||||||
|
val fieldNameAndTypeCount = buf.readUnsignedShort() |
||||||
|
val methodNameAndTypeCount = buf.readUnsignedShort() |
||||||
|
val fieldRefCount = buf.readUnsignedShort() |
||||||
|
val methodRefCount = buf.readUnsignedShort() |
||||||
|
val interfaceMethodRefCount = buf.readUnsignedShort() |
||||||
|
|
||||||
|
buf.resetReaderIndex() |
||||||
|
|
||||||
|
// read UTF-8 entries |
||||||
|
val strings = readStrings(buf, stringCount) |
||||||
|
|
||||||
|
// read NameAndType entries |
||||||
|
val fieldNames = readStringPointers(buf, fieldNameAndTypeCount, strings) |
||||||
|
val methodNames = readStringPointers(buf, methodNameAndTypeCount, strings) |
||||||
|
val fieldDescriptors = readStringPointers(buf, fieldNameAndTypeCount, strings) |
||||||
|
val methodDescriptors = readStringPointers(buf, methodNameAndTypeCount, strings) |
||||||
|
|
||||||
|
val fieldNamesAndTypes = createNamesAndTypes(fieldNames, fieldDescriptors) |
||||||
|
val methodNamesAndTypes = createNamesAndTypes(methodNames, methodDescriptors) |
||||||
|
|
||||||
|
// read FieldRef, MethodRef and InterfaceMethodRef entries |
||||||
|
val fieldRefClasses = readStringPointers(buf, fieldRefCount, strings) |
||||||
|
val methodRefClasses = readStringPointers(buf, methodRefCount, strings) |
||||||
|
val interfaceRefMethodClasses = readStringPointers(buf, interfaceMethodRefCount, strings) |
||||||
|
|
||||||
|
val fieldRefNamesAndTypes = readNameAndTypePointers(buf, fieldRefCount, fieldNamesAndTypes) |
||||||
|
val methodRefNamesAndTypes = readNameAndTypePointers(buf, methodRefCount, methodNamesAndTypes) |
||||||
|
val interfaceMethodRefNamesAndTypes = readNameAndTypePointers( |
||||||
|
buf, |
||||||
|
interfaceMethodRefCount, |
||||||
|
methodNamesAndTypes |
||||||
|
) |
||||||
|
|
||||||
|
val fieldRefs = createMembers(fieldRefClasses, fieldRefNamesAndTypes) |
||||||
|
val methodRefs = createMembers(methodRefClasses, methodRefNamesAndTypes) |
||||||
|
val interfaceMethodRefs = createMembers(interfaceRefMethodClasses, interfaceMethodRefNamesAndTypes) |
||||||
|
|
||||||
|
// read numeric entries |
||||||
|
val ints = readInts(buf, intCount) |
||||||
|
val longs = readLongs(buf, longCount) |
||||||
|
val floats = readFloats(buf, floatCount) |
||||||
|
val doubles = readDoubles(buf, doubleCount) |
||||||
|
|
||||||
|
// skip trailer |
||||||
|
buf.skipBytes(TRAILER_LEN) |
||||||
|
|
||||||
|
return ConstantPool( |
||||||
|
strings, |
||||||
|
fieldNamesAndTypes, |
||||||
|
methodNamesAndTypes, |
||||||
|
fieldRefs, |
||||||
|
methodRefs, |
||||||
|
interfaceMethodRefs, |
||||||
|
ints, |
||||||
|
longs, |
||||||
|
floats, |
||||||
|
doubles |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
private fun readStrings(buf: ByteBuf, size: Int): Array<String> { |
||||||
|
require(size >= 6) |
||||||
|
|
||||||
|
return Array(size) { i -> |
||||||
|
when (i) { |
||||||
|
0 -> CODE |
||||||
|
1 -> EXCEPTIONS |
||||||
|
2 -> SYNTHETIC |
||||||
|
3 -> CONSTANT_VALUE |
||||||
|
4 -> SOURCE_FILE |
||||||
|
5 -> LINE_NUMBER_TABLE |
||||||
|
else -> buf.readString(ModifiedUtf8Charset) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private fun readStringPointers(buf: ByteBuf, size: Int, entries: Array<String>): Array<String> { |
||||||
|
return Array(size) { |
||||||
|
val index = buf.readUnsignedShort() |
||||||
|
entries[index] |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private fun createNamesAndTypes(names: Array<String>, descriptors: Array<String>): Array<NameAndType> { |
||||||
|
check(names.size == descriptors.size) |
||||||
|
|
||||||
|
return Array(names.size) { i -> |
||||||
|
NameAndType(names[i], descriptors[i]) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private fun readNameAndTypePointers(buf: ByteBuf, size: Int, entries: Array<NameAndType>): Array<NameAndType> { |
||||||
|
return Array(size) { |
||||||
|
val index = buf.readUnsignedShort() |
||||||
|
entries[index] |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private fun createMembers(classes: Array<String>, namesAndTypes: Array<NameAndType>): Array<MemberRef> { |
||||||
|
check(classes.size == namesAndTypes.size) |
||||||
|
|
||||||
|
return Array(classes.size) { i -> |
||||||
|
MemberRef(classes[i], namesAndTypes[i]) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private fun readInts(buf: ByteBuf, size: Int): IntArray { |
||||||
|
val entries = IntArray(size) |
||||||
|
|
||||||
|
for (i in 24 downTo 0 step 8) { |
||||||
|
var accumulator = 0 |
||||||
|
for (j in entries.indices) { |
||||||
|
accumulator += buf.readUnsignedByte().toInt() shl i |
||||||
|
entries[j] += accumulator |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return entries |
||||||
|
} |
||||||
|
|
||||||
|
private fun readLongs(buf: ByteBuf, size: Int): LongArray { |
||||||
|
val entries = LongArray(size) |
||||||
|
|
||||||
|
for (i in 56 downTo 0 step 8) { |
||||||
|
var accumulator = 0L |
||||||
|
for (j in entries.indices) { |
||||||
|
accumulator += buf.readUnsignedByte().toLong() shl i |
||||||
|
entries[j] += accumulator |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return entries |
||||||
|
} |
||||||
|
|
||||||
|
private fun readFloats(buf: ByteBuf, size: Int): FloatArray { |
||||||
|
val entries = readInts(buf, size) |
||||||
|
return FloatArray(entries.size) { i -> |
||||||
|
Float.fromBits(entries[i]) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private fun readDoubles(buf: ByteBuf, size: Int): DoubleArray { |
||||||
|
val entries = readLongs(buf, size) |
||||||
|
return DoubleArray(entries.size) { i -> |
||||||
|
Double.fromBits(entries[i]) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,15 @@ |
|||||||
|
package org.openrs2.asm.packclass |
||||||
|
|
||||||
|
public data class MemberRef( |
||||||
|
public val clazz: String, |
||||||
|
public val nameAndType: NameAndType |
||||||
|
) : Comparable<MemberRef> { |
||||||
|
public constructor(clazz: String, name: String, descriptor: String) : this(clazz, NameAndType(name, descriptor)) |
||||||
|
|
||||||
|
public val name: String = nameAndType.name |
||||||
|
public val descriptor: String = nameAndType.descriptor |
||||||
|
|
||||||
|
override fun compareTo(other: MemberRef): Int { |
||||||
|
return compareValuesBy(this, other, MemberRef::clazz, MemberRef::nameAndType) |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,10 @@ |
|||||||
|
package org.openrs2.asm.packclass |
||||||
|
|
||||||
|
public data class NameAndType( |
||||||
|
public val name: String, |
||||||
|
public val descriptor: String |
||||||
|
) : Comparable<NameAndType> { |
||||||
|
override fun compareTo(other: NameAndType): Int { |
||||||
|
return compareValuesBy(this, other, NameAndType::name, NameAndType::descriptor) |
||||||
|
} |
||||||
|
} |
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue