2025-03-15 21:49:52 +03:00

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)
}