forked from openrs2/openrs2
parent
f6324198ef
commit
2a0401a35e
@ -0,0 +1,116 @@ |
||||
package org.openrs2.archive.client |
||||
|
||||
import io.netty.buffer.ByteBuf |
||||
import org.openrs2.buffer.readString |
||||
|
||||
public data class MachO( |
||||
public val architecture: Architecture, |
||||
public val symbols: Set<String>, |
||||
) { |
||||
public companion object { |
||||
private const val MACHO_UNIVERSAL = 0xCAFEBABE.toInt() |
||||
private const val MACHO32BE = 0xFEEDFACE.toInt() |
||||
private const val MACHO32LE = 0xCEFAEDFE.toInt() |
||||
private const val MACHO64BE = 0xFEEDFACF.toInt() |
||||
private const val MACHO64LE = 0xCFFAEDFE.toInt() |
||||
|
||||
private const val CPU_TYPE_X86 = 0x7 |
||||
private const val CPU_TYPE_AMD64 = 0x1000007 |
||||
private const val CPU_TYPE_POWERPC = 0x12 |
||||
|
||||
private const val COMMAND_SYMTAB = 0x2 |
||||
|
||||
public fun parse(buf: ByteBuf): MachO { |
||||
val magic = buf.getInt(buf.readerIndex()) |
||||
return if (magic == MACHO_UNIVERSAL) { |
||||
parseFat(buf) |
||||
} else { |
||||
parseMachO(buf) |
||||
} |
||||
} |
||||
|
||||
private fun parseFat(buf: ByteBuf): MachO { |
||||
buf.skipBytes(4) |
||||
|
||||
val symbols = mutableSetOf<String>() |
||||
val count = buf.readInt() |
||||
|
||||
for (i in 0 until count) { |
||||
buf.skipBytes(8) |
||||
|
||||
val offset = buf.readInt() |
||||
val size = buf.readInt() |
||||
|
||||
buf.skipBytes(4) |
||||
|
||||
symbols += parseMachO(buf.slice(offset, size)).symbols |
||||
} |
||||
|
||||
return MachO(Architecture.UNIVERSAL, symbols) |
||||
} |
||||
|
||||
private fun parseMachO(buf: ByteBuf): MachO { |
||||
val magic = buf.readInt() |
||||
require(magic == MACHO32BE || magic == MACHO32LE || magic == MACHO64BE || magic == MACHO64LE) |
||||
|
||||
val big = magic == MACHO32BE || magic == MACHO64BE |
||||
val x64 = magic == MACHO64LE || magic == MACHO64BE |
||||
|
||||
val arch = when (if (big) buf.readInt() else buf.readIntLE()) { |
||||
CPU_TYPE_X86 -> Architecture.X86 |
||||
CPU_TYPE_AMD64 -> Architecture.AMD64 |
||||
CPU_TYPE_POWERPC -> Architecture.POWERPC |
||||
else -> throw IllegalArgumentException() |
||||
} |
||||
|
||||
buf.skipBytes(4) // cpuSubType |
||||
buf.skipBytes(4) // fileType |
||||
|
||||
val nCmds = if (big) buf.readInt() else buf.readIntLE() |
||||
|
||||
buf.skipBytes(4) // sizeOfCmds |
||||
buf.skipBytes(4) // flags |
||||
|
||||
if (x64) { |
||||
buf.skipBytes(4) // reserved |
||||
} |
||||
|
||||
val symbols = parseCommands(buf, big, nCmds) |
||||
|
||||
return MachO(arch, symbols) |
||||
} |
||||
|
||||
private fun parseCommands(buf: ByteBuf, big: Boolean, count: Int): Set<String> { |
||||
for (i in 0 until count) { |
||||
val base = buf.readerIndex() |
||||
|
||||
val command = if (big) buf.readInt() else buf.readIntLE() |
||||
val size = if (big) buf.readInt() else buf.readIntLE() |
||||
|
||||
if (command == COMMAND_SYMTAB) { |
||||
buf.skipBytes(8) |
||||
|
||||
val strOff = if (big) buf.readInt() else buf.readIntLE() |
||||
val strSize = if (big) buf.readInt() else buf.readIntLE() |
||||
|
||||
return parseStringTable(buf.slice(strOff, strSize)) |
||||
} |
||||
|
||||
buf.readerIndex(base + size) |
||||
} |
||||
|
||||
return emptySet() |
||||
} |
||||
|
||||
private fun parseStringTable(buf: ByteBuf): Set<String> { |
||||
return buildSet { |
||||
while (buf.isReadable) { |
||||
val str = buf.readString(Charsets.US_ASCII) |
||||
if (str.isNotEmpty()) { |
||||
add(str) |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue