159 lines
5.7 KiB
Kotlin
159 lines
5.7 KiB
Kotlin
import com.dowstats.data.rgd.RgdData
|
|
import org.junit.jupiter.api.Test
|
|
import java.io.DataInputStream
|
|
import java.io.File
|
|
import java.io.PrintWriter
|
|
import java.math.RoundingMode
|
|
import java.nio.ByteBuffer
|
|
import java.nio.file.Paths
|
|
|
|
class RgdParserServiceTest {
|
|
|
|
val zeroByte: Byte = 0
|
|
|
|
val rgdDictionary: MutableMap<Int, String> = mutableMapOf()
|
|
|
|
fun readDictionary() {
|
|
File("src/test/resources/RGD_DIC.TXT").forEachLine {
|
|
if(it.isNotEmpty() && it[0] != '#'){
|
|
val kv = it.split('=')
|
|
val key = kv.first().drop(2).decodeHex().getUIntAt(0).toInt()
|
|
val value = kv.last()
|
|
rgdDictionary[key] = value
|
|
}
|
|
}
|
|
}
|
|
|
|
private fun String.decodeHex(): ByteArray {
|
|
check(length % 2 == 0) { "Must have an even length" }
|
|
return chunked(2)
|
|
.map { it.toInt(16).toByte() }
|
|
.toByteArray()
|
|
}
|
|
|
|
@Test
|
|
fun testSum() {
|
|
|
|
readDictionary()
|
|
|
|
|
|
|
|
val path = Paths.get("").toAbsolutePath().toString()
|
|
println(path)
|
|
val bufferedReader: DataInputStream = DataInputStream(File("src/test/resources/chaos_marine_squad.rgd").inputStream())
|
|
val res = bufferedReader.use { it.readAllBytes() }
|
|
|
|
println("${res.size} bytes")
|
|
|
|
val dataInfo = res.copyOfRange(24, 32)
|
|
println(dataInfo.toString(Charsets.UTF_8))
|
|
|
|
val chunkBytes = res.drop(32).toByteArray()
|
|
|
|
val version = chunkBytes.copyOfRange(0,4).reversedArray().getUIntAt(0)
|
|
val chunkLength = chunkBytes.copyOfRange(4,8).reversedArray().getUIntAt(0)
|
|
val stringLength = chunkBytes.copyOfRange(8,12).reversedArray().getUIntAt(0).toInt()
|
|
|
|
println("version: $version; chunkLength: $chunkLength; stringLength: $stringLength")
|
|
|
|
//val sString = chunkBytes.copyOfRange(12, 12 + stringLength).toString(Charsets.UTF_8)
|
|
//val iCRC = chunkBytes.copyOfRange(12 + stringLength, 12 + stringLength + 4).reversedArray().getUIntAt(0)
|
|
val dataLength = chunkBytes.copyOfRange(16 + stringLength, 16 + stringLength + 4).reversedArray().getUIntAt(0).toInt()
|
|
|
|
//println("sString: $sString; iCRC: $iCRC; dataLength: $dataLength")
|
|
|
|
fun printRgdData(data: List<RgdData>, out: PrintWriter){
|
|
data.sortedBy { it.name }.forEach{
|
|
if(it.value is List<*>){
|
|
out.println("<details closed>")
|
|
out.println("<summary>${it.name}</summary>")
|
|
|
|
out.println("<ul>")
|
|
printRgdData(it.value as List<RgdData>, out)
|
|
out.println("</ul>")
|
|
|
|
out.println("</details>")
|
|
}else{
|
|
out.println("<li>${it.name} → ${it.value}</li>")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private fun handleRgdData(byteArray: ByteArray): List<RgdData> {
|
|
|
|
var keyCount = byteArray.copyOfRange(0,4).reversedArray().getUIntAt(0).toInt()
|
|
val totalKeyCount = keyCount
|
|
var offset = 4
|
|
|
|
val rgdData = mutableListOf<RgdData>()
|
|
|
|
while (keyCount != 0){
|
|
|
|
val hash = byteArray.copyOfRange(offset,offset + 4).reversedArray().getUIntAt(0).toInt()
|
|
offset += 4
|
|
|
|
val valueName = rgdDictionary[hash] ?: hash.toString()
|
|
|
|
val type = byteArray.copyOfRange(offset,offset + 4).reversedArray().getUIntAt(0).toInt()
|
|
offset += 4
|
|
|
|
val iOffset = byteArray.copyOfRange(offset,offset + 4).reversedArray().getUIntAt(0).toInt()
|
|
offset += 4
|
|
//println("$space iOffset: $iOffset")
|
|
|
|
val dataOffset = totalKeyCount * (3 * 4) + iOffset + 4
|
|
|
|
val data: Any = when(type){
|
|
0 -> {// Float
|
|
val entityData = byteArray.copyOfRange(dataOffset,dataOffset + 4).reversedArray().getFloat()
|
|
entityData.toBigDecimal().setScale(2, RoundingMode.HALF_UP).toDouble()
|
|
}
|
|
1 -> {// Int
|
|
val entityData = byteArray.copyOfRange(dataOffset,dataOffset + 8).reversedArray().getUIntAt(0)
|
|
entityData
|
|
}
|
|
2 -> {// Bool
|
|
val entityData = byteArray.copyOfRange(dataOffset,dataOffset + 1).map { it }.toString()
|
|
entityData
|
|
}
|
|
3 -> {// String
|
|
var zeroByteOffset = 0
|
|
while(byteArray[dataOffset+zeroByteOffset] != zeroByte){
|
|
zeroByteOffset++
|
|
}
|
|
byteArray.copyOfRange(dataOffset,dataOffset + zeroByteOffset).toString(Charsets.UTF_8)
|
|
}
|
|
4 -> {// String
|
|
var zeroByteOffset = 0
|
|
while(byteArray[dataOffset+zeroByteOffset] != zeroByte || byteArray[dataOffset+zeroByteOffset+1] != zeroByte){
|
|
zeroByteOffset++
|
|
}
|
|
zeroByteOffset++
|
|
byteArray.copyOfRange(dataOffset,dataOffset + zeroByteOffset).toString(Charsets.UTF_16LE)
|
|
}
|
|
100 -> {
|
|
handleRgdData(byteArray.copyOfRange(dataOffset, byteArray.size))
|
|
}
|
|
else -> 0
|
|
}
|
|
|
|
rgdData.add(RgdData(hash, valueName, type, data))
|
|
keyCount--
|
|
}
|
|
|
|
return rgdData
|
|
}
|
|
|
|
private fun ByteArray.getFloat(): Float {
|
|
val buffer = ByteBuffer.wrap(this)
|
|
return buffer.float
|
|
}
|
|
|
|
private fun ByteArray.getUIntAt(idx: Int): UInt =
|
|
((this[idx].toUInt() and 0xFFu) shl 24) or
|
|
((this[idx + 1].toUInt() and 0xFFu) shl 16) or
|
|
((this[idx + 2].toUInt() and 0xFFu) shl 8) or
|
|
(this[idx + 3].toUInt() and 0xFFu)
|
|
|
|
} |