KStarbound/src/main/kotlin/ru/dbotthepony/kstarbound/io/BinaryJson.kt
2022-07-28 21:44:04 +07:00

192 lines
4.2 KiB
Kotlin
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package ru.dbotthepony.kstarbound.io
import com.google.gson.*
import java.io.DataInputStream
import java.io.InputStream
import java.io.RandomAccessFile
/**
* Represents interface to read binary json format by Chucklefish
*/
object BinaryJson {
const val TYPE_NULL = 0x01
const val TYPE_FLOAT = 0x02
const val TYPE_DOUBLE = TYPE_FLOAT
const val TYPE_BOOLEAN = 0x03
/**
* На самом деле, variable int
*/
const val TYPE_INT = 0x04
const val TYPE_STRING = 0x05
const val TYPE_ARRAY = 0x06
const val TYPE_OBJECT = 0x07
fun readElement(reader: RandomAccessFile): JsonElement {
return when (val id = reader.read()) {
TYPE_NULL -> JsonNull.INSTANCE
TYPE_DOUBLE -> JsonPrimitive(reader.readDouble())
TYPE_BOOLEAN -> JsonPrimitive(reader.readBoolean())
TYPE_INT -> {
var read = reader.readVarLong()
val sign = read and 0x1L
read = read ushr 1
if (sign == 1L) {
JsonPrimitive(read - 1L)
} else {
JsonPrimitive(read)
}
}
TYPE_STRING -> JsonPrimitive(reader.readASCIIString(reader.readVarInt()))
TYPE_ARRAY -> readArray(reader)
TYPE_OBJECT -> readObject(reader)
else -> throw JsonParseException("Unknown element type $id")
}
}
fun readElement(reader: DataInputStream): JsonElement {
return when (val id = reader.read()) {
TYPE_NULL -> JsonNull.INSTANCE
TYPE_DOUBLE -> JsonPrimitive(reader.readDouble())
TYPE_BOOLEAN -> JsonPrimitive(reader.readBoolean())
TYPE_INT -> {
var read = reader.readVarLong()
val sign = read and 0x1L
read = read ushr 1
if (sign == 1L) {
JsonPrimitive(read - 1L)
} else {
JsonPrimitive(read)
}
}
TYPE_STRING -> JsonPrimitive(reader.readASCIIString(reader.readVarInt()))
TYPE_ARRAY -> readArray(reader)
TYPE_OBJECT -> readObject(reader)
else -> throw JsonParseException("Unknown element type $id")
}
}
fun readObject(reader: RandomAccessFile): JsonObject {
val values = reader.readVarInt() - 1
if (values == -1) {
return JsonObject()
}
if (values < -1) {
throw JsonParseException("Tried to read json object with $values elements in it")
}
val build = JsonObject()
for (i in 0 .. values) {
val key: String
try {
key = reader.readASCIIString(reader.readVarInt())
} catch(err: Throwable) {
throw JsonParseException("Reading json object at $i", err)
}
try {
build.add(key, readElement(reader))
} catch(err: Throwable) {
throw JsonParseException("Reading json object at $i with name $key", err)
}
}
return build
}
fun readObject(reader: DataInputStream): JsonObject {
val values = reader.readVarInt() - 1
if (values == -1) {
return JsonObject()
}
if (values < -1) {
throw JsonParseException("Tried to read json object with $values elements in it")
}
val build = JsonObject()
for (i in 0 .. values) {
val key: String
try {
key = reader.readASCIIString(reader.readVarInt())
} catch(err: Throwable) {
throw JsonParseException("Reading json object at $i", err)
}
try {
build.add(key, readElement(reader))
} catch(err: Throwable) {
throw JsonParseException("Reading json object at $i with name $key", err)
}
}
return build
}
fun readArray(reader: RandomAccessFile): JsonArray {
val values = reader.readVarInt() - 1
if (values == -1) {
return JsonArray()
}
if (values < -1) {
throw JsonParseException("Tried to read json array with $values elements in it")
}
val build = JsonArray()
for (i in 0 .. values) {
build.add(readElement(reader))
}
return build
}
fun readArray(reader: DataInputStream): JsonArray {
val values = reader.readVarInt() - 1
if (values == -1) {
return JsonArray()
}
if (values < -1) {
throw JsonParseException("Tried to read json array with $values elements in it")
}
val build = JsonArray()
for (i in 0 .. values) {
build.add(readElement(reader))
}
return build
}
}
class VersionedJSON(var name: String = "Versioned JSON") {
var isVersioned = false
var version = 0
var data: JsonElement? = null
constructor(stream: DataInputStream) : this() {
name = stream.readASCIIString(stream.readVarInt())
isVersioned = stream.readBoolean()
if (isVersioned) {
version = stream.readInt()
}
data = BinaryJson.readElement(stream)
}
}