Idiot proof network read methods
This commit is contained in:
parent
a7266ec01e
commit
513ef21926
@ -2,6 +2,7 @@ package ru.dbotthepony.mc.otm.core.math
|
|||||||
|
|
||||||
import net.minecraft.nbt.ByteArrayTag
|
import net.minecraft.nbt.ByteArrayTag
|
||||||
import net.minecraft.nbt.CompoundTag
|
import net.minecraft.nbt.CompoundTag
|
||||||
|
import net.minecraft.nbt.NbtAccounter
|
||||||
import net.minecraft.nbt.StringTag
|
import net.minecraft.nbt.StringTag
|
||||||
import net.minecraft.nbt.Tag
|
import net.minecraft.nbt.Tag
|
||||||
import net.minecraft.network.FriendlyByteBuf
|
import net.minecraft.network.FriendlyByteBuf
|
||||||
@ -859,8 +860,11 @@ class Decimal @JvmOverloads constructor(whole: BigInteger, decimal: Double = 0.0
|
|||||||
fun FriendlyByteBuf.readDecimal() = Decimal.read(this)
|
fun FriendlyByteBuf.readDecimal() = Decimal.read(this)
|
||||||
fun FriendlyByteBuf.writeDecimal(value: Decimal) = value.write(this)
|
fun FriendlyByteBuf.writeDecimal(value: Decimal) = value.write(this)
|
||||||
|
|
||||||
fun InputStream.readDecimal(): Decimal {
|
fun InputStream.readDecimal(sizeLimit: NbtAccounter = NbtAccounter(512L)): Decimal {
|
||||||
val bytes = ByteArray(readVarIntLE())
|
val size = readVarIntLE(sizeLimit)
|
||||||
|
require(size >= 0) { "Negative payload size: $size" }
|
||||||
|
sizeLimit.accountBytes(size.toLong() + 8L)
|
||||||
|
val bytes = ByteArray(size)
|
||||||
read(bytes)
|
read(bytes)
|
||||||
return Decimal(BigInteger(bytes), readDouble())
|
return Decimal(BigInteger(bytes), readDouble())
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
package ru.dbotthepony.mc.otm.core.util
|
package ru.dbotthepony.mc.otm.core.util
|
||||||
|
|
||||||
|
import net.minecraft.nbt.NbtAccounter
|
||||||
import net.minecraft.world.item.ItemStack
|
import net.minecraft.world.item.ItemStack
|
||||||
import ru.dbotthepony.mc.otm.core.math.readDecimal
|
import ru.dbotthepony.mc.otm.core.math.readDecimal
|
||||||
import ru.dbotthepony.mc.otm.core.math.writeDecimal
|
import ru.dbotthepony.mc.otm.core.math.writeDecimal
|
||||||
|
import java.io.DataInput
|
||||||
import java.io.DataInputStream
|
import java.io.DataInputStream
|
||||||
|
import java.io.DataOutput
|
||||||
import java.io.DataOutputStream
|
import java.io.DataOutputStream
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
@ -18,7 +21,7 @@ import kotlin.math.absoluteValue
|
|||||||
* Also provides [copy] and [compare] methods
|
* Also provides [copy] and [compare] methods
|
||||||
*/
|
*/
|
||||||
interface IStreamCodec<V> {
|
interface IStreamCodec<V> {
|
||||||
fun read(stream: DataInputStream): V
|
fun read(stream: DataInputStream, sizeLimit: NbtAccounter = NbtAccounter(1L shl 18 /* 256 KiB */)): V
|
||||||
fun write(stream: DataOutputStream, value: V)
|
fun write(stream: DataOutputStream, value: V)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -37,13 +40,21 @@ interface IStreamCodec<V> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class StreamCodec<V>(
|
class StreamCodec<V>(
|
||||||
private val reader: (stream: DataInputStream) -> V,
|
private val reader: (stream: DataInputStream, sizeLimit: NbtAccounter) -> V,
|
||||||
private val writer: (stream: DataOutputStream, value: V) -> Unit,
|
private val writer: (stream: DataOutputStream, value: V) -> Unit,
|
||||||
private val copier: ((value: V) -> V) = { it },
|
private val copier: ((value: V) -> V) = { it },
|
||||||
private val comparator: ((a: V, b: V) -> Boolean) = { a, b -> a == b }
|
private val comparator: ((a: V, b: V) -> Boolean) = { a, b -> a == b }
|
||||||
) : IStreamCodec<V> {
|
) : IStreamCodec<V> {
|
||||||
override fun read(stream: DataInputStream): V {
|
constructor(
|
||||||
return reader.invoke(stream)
|
reader: (stream: DataInputStream) -> V,
|
||||||
|
payloadSize: Long,
|
||||||
|
writer: (stream: DataOutputStream, value: V) -> Unit,
|
||||||
|
copier: ((value: V) -> V) = { it },
|
||||||
|
comparator: ((a: V, b: V) -> Boolean) = { a, b -> a == b }
|
||||||
|
) : this({ stream, sizeLimit -> sizeLimit.accountBytes(payloadSize); reader.invoke(stream) }, writer, copier, comparator)
|
||||||
|
|
||||||
|
override fun read(stream: DataInputStream, sizeLimit: NbtAccounter): V {
|
||||||
|
return reader.invoke(stream, sizeLimit)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun write(stream: DataOutputStream, value: V) {
|
override fun write(stream: DataOutputStream, value: V) {
|
||||||
@ -59,18 +70,18 @@ class StreamCodec<V>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val NullValueCodec = StreamCodec({ null }, { _, _ -> })
|
val NullValueCodec = StreamCodec({ _, _ -> null }, { _, _ -> })
|
||||||
val BooleanValueCodec = StreamCodec(DataInputStream::readBoolean, DataOutputStream::writeBoolean)
|
val BooleanValueCodec = StreamCodec(DataInputStream::readBoolean, 1L, DataOutputStream::writeBoolean)
|
||||||
val ByteValueCodec = StreamCodec(DataInputStream::readByte, { s, v -> s.writeByte(v.toInt()) })
|
val ByteValueCodec = StreamCodec(DataInputStream::readByte, 1L, { s, v -> s.writeByte(v.toInt()) })
|
||||||
val ShortValueCodec = StreamCodec(DataInputStream::readShort, { s, v -> s.writeShort(v.toInt()) })
|
val ShortValueCodec = StreamCodec(DataInputStream::readShort, 2L, { s, v -> s.writeShort(v.toInt()) })
|
||||||
val IntValueCodec = StreamCodec(DataInputStream::readInt, DataOutputStream::writeInt)
|
val IntValueCodec = StreamCodec(DataInputStream::readInt, 4L, DataOutputStream::writeInt)
|
||||||
val LongValueCodec = StreamCodec(DataInputStream::readLong, DataOutputStream::writeLong)
|
val LongValueCodec = StreamCodec(DataInputStream::readLong, 8L, DataOutputStream::writeLong)
|
||||||
val FloatValueCodec = StreamCodec(DataInputStream::readFloat, DataOutputStream::writeFloat)
|
val FloatValueCodec = StreamCodec(DataInputStream::readFloat, 4L, DataOutputStream::writeFloat)
|
||||||
val DoubleValueCodec = StreamCodec(DataInputStream::readDouble, DataOutputStream::writeDouble)
|
val DoubleValueCodec = StreamCodec(DataInputStream::readDouble, 8L, DataOutputStream::writeDouble)
|
||||||
val ItemStackValueCodec = StreamCodec(DataInputStream::readItem, DataOutputStream::writeItem, ItemStack::copy) { a, b -> a.equals(b, true) }
|
val ItemStackValueCodec = StreamCodec(DataInputStream::readItem, DataOutputStream::writeItem, ItemStack::copy) { a, b -> a.equals(b, true) }
|
||||||
val ImpreciseFractionValueCodec = StreamCodec(DataInputStream::readDecimal, DataOutputStream::writeDecimal)
|
val ImpreciseFractionValueCodec = StreamCodec(DataInputStream::readDecimal, DataOutputStream::writeDecimal)
|
||||||
val BigDecimalValueCodec = StreamCodec(DataInputStream::readBigDecimal, DataOutputStream::writeBigDecimal)
|
val BigDecimalValueCodec = StreamCodec(DataInputStream::readBigDecimal, DataOutputStream::writeBigDecimal)
|
||||||
val UUIDValueCodec = StreamCodec({ s -> UUID(s.readLong(), s.readLong()) }, { s, v -> s.writeLong(v.mostSignificantBits); s.writeLong(v.leastSignificantBits) })
|
val UUIDValueCodec = StreamCodec({ s, a -> a.accountBytes(8L); UUID(s.readLong(), s.readLong()) }, { s, v -> s.writeLong(v.mostSignificantBits); s.writeLong(v.leastSignificantBits) })
|
||||||
val VarIntValueCodec = StreamCodec(DataInputStream::readVarIntLE, DataOutputStream::writeVarIntLE)
|
val VarIntValueCodec = StreamCodec(DataInputStream::readVarIntLE, DataOutputStream::writeVarIntLE)
|
||||||
val VarLongValueCodec = StreamCodec(DataInputStream::readVarLongLE, DataOutputStream::writeVarLongLE)
|
val VarLongValueCodec = StreamCodec(DataInputStream::readVarLongLE, DataOutputStream::writeVarLongLE)
|
||||||
val BinaryStringCodec = StreamCodec(DataInputStream::readBinaryString, DataOutputStream::writeBinaryString)
|
val BinaryStringCodec = StreamCodec(DataInputStream::readBinaryString, DataOutputStream::writeBinaryString)
|
||||||
@ -79,13 +90,13 @@ class EnumValueCodec<V : Enum<V>>(clazz: Class<out V>, val writeByIndices: Boole
|
|||||||
val clazz = searchClass(clazz)
|
val clazz = searchClass(clazz)
|
||||||
private val values = searchClass(clazz).enumConstants!!
|
private val values = searchClass(clazz).enumConstants!!
|
||||||
|
|
||||||
override fun read(stream: DataInputStream): V {
|
override fun read(stream: DataInputStream, sizeLimit: NbtAccounter): V {
|
||||||
if (writeByIndices) {
|
if (writeByIndices) {
|
||||||
val id = stream.readVarIntLE()
|
val id = stream.readVarIntLE(sizeLimit)
|
||||||
return values.getOrNull(id) ?: throw NoSuchElementException("No such enum with index $id")
|
return values.getOrNull(id) ?: throw NoSuchElementException("No such enum with index $id")
|
||||||
}
|
}
|
||||||
|
|
||||||
val id = stream.readBinaryString()
|
val id = stream.readBinaryString(sizeLimit)
|
||||||
return values.firstOrNull { id == it.name } ?: throw NoSuchElementException("No such enum $id")
|
return values.firstOrNull { id == it.name } ?: throw NoSuchElementException("No such enum $id")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,7 +138,7 @@ class EnumValueCodec<V : Enum<V>>(clazz: Class<out V>, val writeByIndices: Boole
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun OutputStream.writeInt(value: Int) {
|
fun OutputStream.writeInt(value: Int) {
|
||||||
if (this is DataOutputStream) {
|
if (this is DataOutput) {
|
||||||
writeInt(value)
|
writeInt(value)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -139,7 +150,7 @@ fun OutputStream.writeInt(value: Int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun InputStream.readInt(): Int {
|
fun InputStream.readInt(): Int {
|
||||||
if (this is DataInputStream) {
|
if (this is DataInput) {
|
||||||
return readInt()
|
return readInt()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,7 +158,7 @@ fun InputStream.readInt(): Int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun OutputStream.writeLong(value: Long) {
|
fun OutputStream.writeLong(value: Long) {
|
||||||
if (this is DataOutputStream) {
|
if (this is DataOutput) {
|
||||||
writeLong(value)
|
writeLong(value)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -162,7 +173,7 @@ fun OutputStream.writeLong(value: Long) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun InputStream.readLong(): Long {
|
fun InputStream.readLong(): Long {
|
||||||
if (this is DataInputStream) {
|
if (this is DataInput) {
|
||||||
return readLong()
|
return readLong()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -180,7 +191,8 @@ fun InputStream.readFloat() = Float.fromBits(readInt())
|
|||||||
fun OutputStream.writeDouble(value: Double) = writeLong(value.toBits())
|
fun OutputStream.writeDouble(value: Double) = writeLong(value.toBits())
|
||||||
fun InputStream.readDouble() = Double.fromBits(readLong())
|
fun InputStream.readDouble() = Double.fromBits(readLong())
|
||||||
|
|
||||||
fun InputStream.readVarIntLE(): Int {
|
fun InputStream.readVarIntLE(sizeLimit: NbtAccounter? = null): Int {
|
||||||
|
sizeLimit?.accountBytes(1L)
|
||||||
val readFirst = read()
|
val readFirst = read()
|
||||||
|
|
||||||
if (readFirst < 0) {
|
if (readFirst < 0) {
|
||||||
@ -198,6 +210,7 @@ fun InputStream.readVarIntLE(): Int {
|
|||||||
|
|
||||||
while (nextBit != 0) {
|
while (nextBit != 0) {
|
||||||
result = result or (read shl i)
|
result = result or (read shl i)
|
||||||
|
sizeLimit?.accountBytes(1L)
|
||||||
read = read()
|
read = read()
|
||||||
|
|
||||||
if (read < 0) {
|
if (read < 0) {
|
||||||
@ -227,7 +240,9 @@ fun OutputStream.writeVarIntLE(value: Int) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun InputStream.readVarLongLE(): Long {
|
fun InputStream.readVarLongLE(sizeLimit: NbtAccounter? = null): Long {
|
||||||
|
sizeLimit?.accountBytes(1L)
|
||||||
|
|
||||||
val readFirst = read()
|
val readFirst = read()
|
||||||
|
|
||||||
if (readFirst < 0) {
|
if (readFirst < 0) {
|
||||||
@ -245,6 +260,7 @@ fun InputStream.readVarLongLE(): Long {
|
|||||||
|
|
||||||
while (nextBit != 0) {
|
while (nextBit != 0) {
|
||||||
result = result or (read shl i).toLong()
|
result = result or (read shl i).toLong()
|
||||||
|
sizeLimit?.accountBytes(1L)
|
||||||
read = read()
|
read = read()
|
||||||
|
|
||||||
if (read < 0) {
|
if (read < 0) {
|
||||||
@ -274,8 +290,10 @@ fun OutputStream.writeVarLongLE(value: Long) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun InputStream.readBinaryString(): String {
|
fun InputStream.readBinaryString(sizeLimit: NbtAccounter = NbtAccounter(1L shl 18 /* 256 KiB */)): String {
|
||||||
val size = readVarIntLE()
|
val size = readVarIntLE()
|
||||||
|
require(size >= 0) { "Negative payload size: $size" }
|
||||||
|
sizeLimit.accountBytes(size.toLong())
|
||||||
val bytes = ByteArray(size)
|
val bytes = ByteArray(size)
|
||||||
read(bytes)
|
read(bytes)
|
||||||
return bytes.decodeToString()
|
return bytes.decodeToString()
|
||||||
@ -292,8 +310,8 @@ private data class IndexedStreamCodec<T>(
|
|||||||
val id: Int,
|
val id: Int,
|
||||||
val codec: StreamCodec<T>
|
val codec: StreamCodec<T>
|
||||||
) {
|
) {
|
||||||
fun read(stream: DataInputStream): T {
|
fun read(stream: DataInputStream, sizeLimit: NbtAccounter = NbtAccounter(1L shl 18 /* 256 KiB */)): T {
|
||||||
return codec.read(stream)
|
return codec.read(stream, sizeLimit)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun write(stream: DataOutputStream, value: Any?) {
|
fun write(stream: DataOutputStream, value: Any?) {
|
||||||
@ -346,12 +364,13 @@ fun DataOutputStream.writeType(value: Any?) {
|
|||||||
/**
|
/**
|
||||||
* Read arbitrary data from this stream, in exploit-free way
|
* Read arbitrary data from this stream, in exploit-free way
|
||||||
*/
|
*/
|
||||||
fun DataInputStream.readType(): Any? {
|
fun DataInputStream.readType(sizeLimit: NbtAccounter = NbtAccounter(1L shl 18 /* 256 KiB */)): Any? {
|
||||||
|
sizeLimit.accountBytes(1L)
|
||||||
val id = read()
|
val id = read()
|
||||||
|
|
||||||
if (id >= codecs.size) {
|
if (id >= codecs.size) {
|
||||||
throw IndexOutOfBoundsException("No codec for network type $id")
|
throw IndexOutOfBoundsException("No codec for network type $id")
|
||||||
}
|
}
|
||||||
|
|
||||||
return codecs[id].read(this)
|
return codecs[id].read(this, sizeLimit)
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ import net.minecraft.world.item.Item
|
|||||||
import net.minecraft.world.item.ItemStack
|
import net.minecraft.world.item.ItemStack
|
||||||
import net.minecraftforge.registries.ForgeRegistries
|
import net.minecraftforge.registries.ForgeRegistries
|
||||||
import net.minecraftforge.registries.ForgeRegistry
|
import net.minecraftforge.registries.ForgeRegistry
|
||||||
|
import org.apache.commons.lang3.mutable.MutableInt
|
||||||
import java.io.*
|
import java.io.*
|
||||||
import java.math.BigDecimal
|
import java.math.BigDecimal
|
||||||
import java.math.BigInteger
|
import java.math.BigInteger
|
||||||
@ -36,7 +37,7 @@ fun OutputStream.writeNbt(value: CompoundTag) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun InputStream.readNbt(accounter: NbtAccounter = NbtAccounter.UNLIMITED): CompoundTag {
|
fun InputStream.readNbt(accounter: NbtAccounter = NbtAccounter(1L shl 18 /* 256 KiB */)): CompoundTag {
|
||||||
return try {
|
return try {
|
||||||
NbtIo.read(if (this is DataInputStream) this else DataInputStream(this), accounter)
|
NbtIo.read(if (this is DataInputStream) this else DataInputStream(this), accounter)
|
||||||
} catch (ioexception: IOException) {
|
} catch (ioexception: IOException) {
|
||||||
@ -68,17 +69,19 @@ fun OutputStream.writeItem(itemStack: ItemStack, limitedTag: Boolean = true) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun InputStream.readItem(): ItemStack {
|
fun InputStream.readItem(sizeLimit: NbtAccounter = NbtAccounter(1L shl 18 /* 256 KiB */)): ItemStack {
|
||||||
|
sizeLimit.accountBytes(1L)
|
||||||
|
|
||||||
if (read() == 0) {
|
if (read() == 0) {
|
||||||
return ItemStack.EMPTY
|
return ItemStack.EMPTY
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sizeLimit.accountBytes(9L)
|
||||||
val item = (ForgeRegistries.ITEMS as ForgeRegistry<Item>).getValue(readInt())
|
val item = (ForgeRegistries.ITEMS as ForgeRegistry<Item>).getValue(readInt())
|
||||||
val itemStack = ItemStack(item, readInt())
|
val itemStack = ItemStack(item, readInt())
|
||||||
|
|
||||||
if (read() != 0) {
|
if (read() != 0) {
|
||||||
itemStack.readShareTag(readNbt())
|
itemStack.readShareTag(readNbt(sizeLimit))
|
||||||
}
|
}
|
||||||
|
|
||||||
return itemStack
|
return itemStack
|
||||||
@ -91,9 +94,11 @@ fun OutputStream.writeBigDecimal(value: BigDecimal) {
|
|||||||
write(bytes)
|
write(bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun InputStream.readBigDecimal(): BigDecimal {
|
fun InputStream.readBigDecimal(sizeLimit: NbtAccounter = NbtAccounter(512L)): BigDecimal {
|
||||||
val scale = readInt()
|
val scale = readInt()
|
||||||
val size = readVarIntLE()
|
val size = readVarIntLE(sizeLimit)
|
||||||
|
require(size >= 0) { "Negative payload size: $size" }
|
||||||
|
sizeLimit.accountBytes(size.toLong() + 4L)
|
||||||
val bytes = ByteArray(size)
|
val bytes = ByteArray(size)
|
||||||
read(bytes)
|
read(bytes)
|
||||||
return BigDecimal(BigInteger(bytes), scale)
|
return BigDecimal(BigInteger(bytes), scale)
|
||||||
@ -180,25 +185,33 @@ fun OutputStream.writeJson(element: JsonElement) {
|
|||||||
*
|
*
|
||||||
* just copy pasted this code from my another project because i was lazy
|
* just copy pasted this code from my another project because i was lazy
|
||||||
*/
|
*/
|
||||||
fun InputStream.readJson(): JsonElement {
|
fun InputStream.readJson(sizeLimit: NbtAccounter = NbtAccounter(1L shl 18 /* 256 KiB */)): JsonElement {
|
||||||
|
sizeLimit.accountBytes(1L)
|
||||||
|
|
||||||
return when (val id = read()) {
|
return when (val id = read()) {
|
||||||
TYPE_NULL -> JsonNull.INSTANCE
|
TYPE_NULL -> JsonNull.INSTANCE
|
||||||
TYPE_DOUBLE -> JsonPrimitive(readDouble())
|
TYPE_DOUBLE -> {
|
||||||
TYPE_BOOLEAN -> JsonPrimitive(read() > 1)
|
sizeLimit.accountBytes(8L)
|
||||||
TYPE_INT -> JsonPrimitive(fixSignedInt(readVarLongLE()))
|
JsonPrimitive(readDouble())
|
||||||
TYPE_STRING -> JsonPrimitive(readBinaryString())
|
}
|
||||||
|
TYPE_BOOLEAN -> {
|
||||||
|
sizeLimit.accountBytes(1L)
|
||||||
|
JsonPrimitive(read() > 1)
|
||||||
|
}
|
||||||
|
TYPE_INT -> JsonPrimitive(fixSignedInt(readVarLongLE(sizeLimit)))
|
||||||
|
TYPE_STRING -> JsonPrimitive(readBinaryString(sizeLimit))
|
||||||
TYPE_ARRAY -> {
|
TYPE_ARRAY -> {
|
||||||
val values = readVarIntLE()
|
val values = readVarIntLE(sizeLimit)
|
||||||
|
|
||||||
if (values == 0) return JsonArray()
|
if (values == 0) return JsonArray()
|
||||||
if (values < 0) throw JsonSyntaxException("Tried to read json array with $values elements in it")
|
if (values < 0) throw JsonSyntaxException("Tried to read json array with $values elements in it")
|
||||||
|
|
||||||
val build = JsonArray(values)
|
val build = JsonArray(values)
|
||||||
for (i in 0 until values) build.add(readJson())
|
for (i in 0 until values) build.add(readJson(sizeLimit))
|
||||||
return build
|
return build
|
||||||
}
|
}
|
||||||
TYPE_OBJECT -> {
|
TYPE_OBJECT -> {
|
||||||
val values = readVarIntLE()
|
val values = readVarIntLE(sizeLimit)
|
||||||
if (values == 0) return JsonObject()
|
if (values == 0) return JsonObject()
|
||||||
if (values < 0) throw JsonSyntaxException("Tried to read json object with $values elements in it")
|
if (values < 0) throw JsonSyntaxException("Tried to read json object with $values elements in it")
|
||||||
|
|
||||||
@ -208,13 +221,13 @@ fun InputStream.readJson(): JsonElement {
|
|||||||
val key: String
|
val key: String
|
||||||
|
|
||||||
try {
|
try {
|
||||||
key = readBinaryString()
|
key = readBinaryString(sizeLimit)
|
||||||
} catch(err: Throwable) {
|
} catch(err: Throwable) {
|
||||||
throw JsonSyntaxException("Reading json object at $i", err)
|
throw JsonSyntaxException("Reading json object at $i", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
build.add(key, readJson())
|
build.add(key, readJson(sizeLimit))
|
||||||
} catch(err: Throwable) {
|
} catch(err: Throwable) {
|
||||||
throw JsonSyntaxException("Reading json object at $i with name $key", err)
|
throw JsonSyntaxException("Reading json object at $i with name $key", err)
|
||||||
}
|
}
|
||||||
@ -226,8 +239,8 @@ fun InputStream.readJson(): JsonElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun FriendlyByteBuf.readJson(): JsonElement {
|
fun FriendlyByteBuf.readJson(sizeLimit: NbtAccounter = NbtAccounter(1L shl 18)): JsonElement {
|
||||||
return ByteBufInputStream(this).readJson()
|
return ByteBufInputStream(this).readJson(sizeLimit)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun FriendlyByteBuf.writeJson(value: JsonElement) {
|
fun FriendlyByteBuf.writeJson(value: JsonElement) {
|
||||||
|
@ -17,6 +17,7 @@ import io.netty.buffer.ByteBufInputStream
|
|||||||
import io.netty.buffer.ByteBufOutputStream
|
import io.netty.buffer.ByteBufOutputStream
|
||||||
import it.unimi.dsi.fastutil.io.FastByteArrayInputStream
|
import it.unimi.dsi.fastutil.io.FastByteArrayInputStream
|
||||||
import it.unimi.dsi.fastutil.io.FastByteArrayOutputStream
|
import it.unimi.dsi.fastutil.io.FastByteArrayOutputStream
|
||||||
|
import net.minecraft.nbt.NbtAccounter
|
||||||
import net.minecraft.network.FriendlyByteBuf
|
import net.minecraft.network.FriendlyByteBuf
|
||||||
import net.minecraft.resources.ResourceLocation
|
import net.minecraft.resources.ResourceLocation
|
||||||
import ru.dbotthepony.mc.otm.core.util.readType
|
import ru.dbotthepony.mc.otm.core.util.readType
|
||||||
@ -175,9 +176,10 @@ class SerializedFunctionRegistry<R, T>(val gson: Gson = Gson()) : JsonSerializer
|
|||||||
val stream = DataInputStream(ByteBufInputStream(buff))
|
val stream = DataInputStream(ByteBufInputStream(buff))
|
||||||
|
|
||||||
val arguments = LinkedList<Any?>()
|
val arguments = LinkedList<Any?>()
|
||||||
|
val sizeLimit = NbtAccounter(1L shl 18 /* 256 KiB */)
|
||||||
|
|
||||||
for (i in 0 until stream.readVarIntLE()) {
|
for (i in 0 until stream.readVarIntLE(sizeLimit)) {
|
||||||
arguments.add(stream.readType())
|
arguments.add(stream.readType(sizeLimit))
|
||||||
}
|
}
|
||||||
|
|
||||||
return map[id]?.bind(arguments)
|
return map[id]?.bind(arguments)
|
||||||
@ -192,9 +194,10 @@ class SerializedFunctionRegistry<R, T>(val gson: Gson = Gson()) : JsonSerializer
|
|||||||
val argumentString = value["arguments"]?.asString ?: return null
|
val argumentString = value["arguments"]?.asString ?: return null
|
||||||
val stream = DataInputStream(FastByteArrayInputStream(Base64.getDecoder().decode(argumentString)))
|
val stream = DataInputStream(FastByteArrayInputStream(Base64.getDecoder().decode(argumentString)))
|
||||||
val arguments = LinkedList<Any?>()
|
val arguments = LinkedList<Any?>()
|
||||||
|
val sizeLimit = NbtAccounter(1L shl 18 /* 256 KiB */)
|
||||||
|
|
||||||
for (i in 0 until stream.readVarIntLE()) {
|
for (i in 0 until stream.readVarIntLE(sizeLimit)) {
|
||||||
arguments.add(stream.readType())
|
arguments.add(stream.readType(sizeLimit))
|
||||||
}
|
}
|
||||||
|
|
||||||
return map[ResourceLocation(id)]?.bind(arguments)
|
return map[ResourceLocation(id)]?.bind(arguments)
|
||||||
|
@ -8,6 +8,7 @@ import it.unimi.dsi.fastutil.objects.ObjectArraySet
|
|||||||
import it.unimi.dsi.fastutil.objects.Reference2ObjectFunction
|
import it.unimi.dsi.fastutil.objects.Reference2ObjectFunction
|
||||||
import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap
|
import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap
|
||||||
import it.unimi.dsi.fastutil.objects.ReferenceArraySet
|
import it.unimi.dsi.fastutil.objects.ReferenceArraySet
|
||||||
|
import net.minecraft.nbt.NbtAccounter
|
||||||
import net.minecraft.world.item.ItemStack
|
import net.minecraft.world.item.ItemStack
|
||||||
import org.apache.logging.log4j.LogManager
|
import org.apache.logging.log4j.LogManager
|
||||||
import ru.dbotthepony.mc.otm.core.*
|
import ru.dbotthepony.mc.otm.core.*
|
||||||
@ -1111,15 +1112,15 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
|
|||||||
private val missingFields = ObjectArraySet<String>()
|
private val missingFields = ObjectArraySet<String>()
|
||||||
private val missingFieldsMap = Int2ObjectArrayMap<String>()
|
private val missingFieldsMap = Int2ObjectArrayMap<String>()
|
||||||
|
|
||||||
fun applyNetworkPayload(stream: InputStream): Int {
|
fun applyNetworkPayload(stream: InputStream, sizeLimit: NbtAccounter = NbtAccounter(1L shl 21 /* 2 MiB */)): Int {
|
||||||
if (stream.read() > 0) {
|
if (stream.read() > 0) {
|
||||||
idToField.clear()
|
idToField.clear()
|
||||||
missingFieldsMap.clear()
|
missingFieldsMap.clear()
|
||||||
|
|
||||||
var fieldId = stream.readVarIntLE()
|
var fieldId = stream.readVarIntLE(sizeLimit)
|
||||||
|
|
||||||
while (fieldId != 0) {
|
while (fieldId != 0) {
|
||||||
val size = stream.readVarIntLE()
|
val size = stream.readVarIntLE(sizeLimit)
|
||||||
val nameBytes = ByteArray(size)
|
val nameBytes = ByteArray(size)
|
||||||
stream.read(nameBytes)
|
stream.read(nameBytes)
|
||||||
val name = String(nameBytes, Charsets.UTF_8)
|
val name = String(nameBytes, Charsets.UTF_8)
|
||||||
@ -1137,27 +1138,29 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
|
|||||||
findField.id = fieldId
|
findField.id = fieldId
|
||||||
}
|
}
|
||||||
|
|
||||||
fieldId = stream.readVarIntLE()
|
fieldId = stream.readVarIntLE(sizeLimit)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var fieldId = stream.readVarIntLE()
|
var fieldId = stream.readVarIntLE(sizeLimit)
|
||||||
var i = 0
|
var i = 0
|
||||||
|
|
||||||
while (fieldId != 0) {
|
while (fieldId != 0) {
|
||||||
val field = idToField[fieldId]
|
val field = idToField[fieldId]
|
||||||
val payloadSize = stream.readVarIntLE()
|
val payloadSize = stream.readVarIntLE(sizeLimit)
|
||||||
|
|
||||||
if (field == null) {
|
if (field == null) {
|
||||||
LOGGER.error("Unable to read field $fieldId (${missingFieldsMap[fieldId]}) because we don't know anything about it! Skipping $payloadSize bytes", IllegalStateException("Unknown field $fieldId"))
|
LOGGER.error("Unable to read field $fieldId (${missingFieldsMap[fieldId]}) because we don't know anything about it! Skipping $payloadSize bytes", IllegalStateException("Unknown field $fieldId"))
|
||||||
|
sizeLimit.accountBytes(payloadSize.toLong())
|
||||||
stream.skipNBytes(payloadSize.toLong())
|
stream.skipNBytes(payloadSize.toLong())
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sizeLimit.accountBytes(payloadSize.toLong())
|
||||||
val bytes = ByteArray(payloadSize)
|
val bytes = ByteArray(payloadSize)
|
||||||
stream.read(bytes)
|
stream.read(bytes)
|
||||||
field.read(DataInputStream(FastByteArrayInputStream(bytes)), payloadSize)
|
field.read(DataInputStream(FastByteArrayInputStream(bytes)), payloadSize)
|
||||||
fieldId = stream.readVarIntLE()
|
fieldId = stream.readVarIntLE(sizeLimit)
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user