diff --git a/build.gradle.kts b/build.gradle.kts index 8b8f5c5..0f1f342 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -6,7 +6,7 @@ plugins { } group = "nl.astraeus" -version = "0.2.0-SNAPSHOT" +version = "0.2.1-SNAPSHOT" repositories { mavenCentral() diff --git a/src/commonMain/kotlin/nl/astraeus/tba/ByteArrayDefinition.kt b/src/commonMain/kotlin/nl/astraeus/tba/ByteArrayDefinition.kt index d3535b5..10a0510 100644 --- a/src/commonMain/kotlin/nl/astraeus/tba/ByteArrayDefinition.kt +++ b/src/commonMain/kotlin/nl/astraeus/tba/ByteArrayDefinition.kt @@ -12,7 +12,7 @@ enum class DataType( DOUBLE(8), STRING(-1, 2), CLOB(-1, 4), - BLOB(-1, 4), + BLOB(-2, 0), ; } diff --git a/src/commonMain/kotlin/nl/astraeus/tba/ByteArrayHandler.kt b/src/commonMain/kotlin/nl/astraeus/tba/ByteArrayHandler.kt index 6df4d5e..f748ad7 100644 --- a/src/commonMain/kotlin/nl/astraeus/tba/ByteArrayHandler.kt +++ b/src/commonMain/kotlin/nl/astraeus/tba/ByteArrayHandler.kt @@ -25,21 +25,23 @@ class MutableByteArrayHandler( fun setFloat(index: Int, value: Float) = buffer.setFloat(index, value) fun setDouble(index: Int, value: Double) = buffer.setDouble(index, value) - fun setString(index: Int, value: String) { + fun setString(index: Int, value: String, maxLength: Int) { val bytes = value.encodeToByteArray() + check(bytes.size + 2 <= maxLength) { "String is too long" } buffer.setShort(index, bytes.size.toShort()) - buffer.setBlob(index + 2, SlicedByteArray.wrap(bytes)) + buffer.setBlob(index + 2, SlicedByteArray.wrap(bytes), maxLength - 2) } - fun setClob(index: Int, value: String) { + fun setClob(index: Int, value: String, maxLength: Int) { val bytes = value.encodeToByteArray() + check(bytes.size + 4 <= maxLength) { "Clob is too long" } buffer.setInt(index, bytes.size) - buffer.setBlob(index + 4, SlicedByteArray.wrap(bytes)) + buffer.setBlob(index + 4, SlicedByteArray.wrap(bytes), maxLength - 4) } - fun setBlob(index: Int, bytes: SlicedByteArray) { - buffer.setInt(index, bytes.length) - buffer.setBlob(index + 4, bytes) + fun setBlob(index: Int, bytes: SlicedByteArray, maxLength: Int) { + check(bytes.size <= maxLength) { "Blob is too long" } + buffer.setBlob(index, bytes, maxLength) } } @@ -87,9 +89,8 @@ open class ByteArrayHandler( return bytes.decodeToString() } - fun getBlob(index: Int): SlicedByteArray { - val length = buffer.getInt(index) - return buffer.getBlob(index + 4, length) + fun getBlob(index: Int, length: Int): SlicedByteArray { + return buffer.getBlob(index, length) } fun slice(range: IntRange): ByteArrayHandler { diff --git a/src/commonMain/kotlin/nl/astraeus/tba/ByteArrayProperties.kt b/src/commonMain/kotlin/nl/astraeus/tba/ByteArrayProperties.kt index ca9569f..516c0a5 100644 --- a/src/commonMain/kotlin/nl/astraeus/tba/ByteArrayProperties.kt +++ b/src/commonMain/kotlin/nl/astraeus/tba/ByteArrayProperties.kt @@ -6,7 +6,7 @@ import kotlin.reflect.KProperty abstract class ByteArrayProperty( val name: String ) : ReadWriteProperty { - var index: Int? = null + private var index: Int? = null protected fun getIndex(thisRef: TypedByteArray): Int { if (index == null) { @@ -16,6 +16,22 @@ abstract class ByteArrayProperty( } } +abstract class ByteArrayPropertyWithLength( + name: String +) : ByteArrayProperty(name) { + private var maxLength: Int? = null + + protected fun getMaxLength(thisRef: TypedByteArray): Int { + if (maxLength == null) { + val type = thisRef.typeMap[name] ?: throw IllegalArgumentException( + "Type $name not found in typemap in $thisRef" + ) + maxLength = type.size + } + return maxLength!! + } +} + class BooleanProperty( name: String ) : ByteArrayProperty(name) { @@ -102,20 +118,20 @@ class DoubleProperty( class StringProperty( name: String, -) : ByteArrayProperty(name) { +) : ByteArrayPropertyWithLength(name) { override fun getValue(thisRef: TypedByteArray, property: KProperty<*>): String { return thisRef.data.getString(getIndex(thisRef)) } override fun setValue(thisRef: TypedByteArray, property: KProperty<*>, value: String) { - thisRef.data.setString(getIndex(thisRef), value) + thisRef.data.setString(getIndex(thisRef), value, getMaxLength(thisRef)) } } class CachedStringProperty( name: String, -) : ByteArrayProperty(name) { +) : ByteArrayPropertyWithLength(name) { var cachedValue: String? = null override fun getValue(thisRef: TypedByteArray, property: KProperty<*>): String { @@ -126,33 +142,34 @@ class CachedStringProperty( } override fun setValue(thisRef: TypedByteArray, property: KProperty<*>, value: String) { - thisRef.data.setString(getIndex(thisRef), value) + thisRef.data.setString(getIndex(thisRef), value, getMaxLength(thisRef)) cachedValue = value } } class ClobProperty( name: String -) : ByteArrayProperty(name) { +) : ByteArrayPropertyWithLength(name) { override fun getValue(thisRef: TypedByteArray, property: KProperty<*>): String { return thisRef.data.getClob(getIndex(thisRef)) } override fun setValue(thisRef: TypedByteArray, property: KProperty<*>, value: String) { - thisRef.data.setClob(getIndex(thisRef), value) + thisRef.data.setClob(getIndex(thisRef), value, getMaxLength(thisRef)) } } class BlobProperty( name: String -) : ByteArrayProperty(name) { +) : ByteArrayPropertyWithLength(name) { + override fun getValue(thisRef: TypedByteArray, property: KProperty<*>): SlicedByteArray { - val result = thisRef.data.getBlob(getIndex(thisRef)) + val result = thisRef.data.getBlob(getIndex(thisRef), getMaxLength(thisRef)) return result } override fun setValue(thisRef: TypedByteArray, property: KProperty<*>, value: SlicedByteArray) { - thisRef.data.setBlob(getIndex(thisRef), value) + thisRef.data.setBlob(getIndex(thisRef), value, getMaxLength(thisRef)) } } diff --git a/src/commonMain/kotlin/nl/astraeus/tba/SlicedByteArray.kt b/src/commonMain/kotlin/nl/astraeus/tba/SlicedByteArray.kt index f41d9c7..21fcf49 100644 --- a/src/commonMain/kotlin/nl/astraeus/tba/SlicedByteArray.kt +++ b/src/commonMain/kotlin/nl/astraeus/tba/SlicedByteArray.kt @@ -19,20 +19,20 @@ class SlicedByteArray( } fun setShort(index: Int, value: Short) { - check(offset + index + 1 < offset + length) { "Index out of bounds" } + check(offset + index + 1 <= offset + length) { "Index out of bounds" } data[offset + index] = (value.toInt() shr 8).toByte() data[offset + index + 1] = value.toByte() } fun getShort(index: Int): Short { - check(offset + index + 1 < offset + length) { "Index out of bounds, ${offset + index + 1} > ${offset + length} ($offset, $index, $length)" } + check(offset + index + 1 <= offset + length) { "Index out of bounds, ${offset + index + 1} > ${offset + length} ($offset, $index, $length)" } return ((data[offset + index].toInt() shl 8) or (data[offset + index + 1].toInt() and 0xff)).toShort() } fun setInt(index: Int, value: Int) { - check(offset + index + 3 < offset + length) { "Index out of bounds" } + check(offset + index + 3 <= offset + length) { "Index out of bounds" } data[offset + index] = ((value shr 24) and 0xff).toByte() data[offset + index + 1] = ((value shr 16) and 0xff).toByte() @@ -41,7 +41,7 @@ class SlicedByteArray( } fun getInt(index: Int): Int { - check(offset + index + 3 < offset + length) { "Index out of bounds" } + check(offset + index + 3 <= offset + length) { "Index out of bounds" } return ( (data[offset + index].toInt() shl 24) or ((data[offset + index+1].toInt() shl 16) and 0xff0000) or @@ -51,7 +51,7 @@ class SlicedByteArray( } fun setLong(index: Int, value: Long) { - check(offset + index + 7 < offset + length) { "Index out of bounds" } + check(offset + index + 7 <= offset + length) { "Index out of bounds" } data[offset + index] = ((value shr 56) and 0xff).toByte() data[offset + index + 1] = ((value shr 48) and 0xff).toByte() data[offset + index + 2] = ((value shr 40) and 0xff).toByte() @@ -63,7 +63,7 @@ class SlicedByteArray( } fun getLong(index: Int): Long { - check(offset + index + 7 < offset + length) { "Index out of bounds" } + check(offset + index + 7 <= offset + length) { "Index out of bounds" } return ( (data[offset + index].toLong() shl 56) or ((data[offset + index+1].toLong() and 0xff) shl 48) or @@ -107,15 +107,15 @@ class SlicedByteArray( fun toByteArray(): ByteArray = data.copyOfRange(offset, offset + length) - fun setBlob(index: Int, bytes: SlicedByteArray) { - if (index + bytes.size > length) { + fun setBlob(index: Int, bytes: SlicedByteArray, blobLength: Int) { + if (bytes.size > blobLength) { throw IllegalArgumentException("Blob is too long") } bytes.copyInto(data, offset + index, bytes.size) data.fill( 0, offset + index + bytes.size, - offset + length + offset + index + blobLength ) } diff --git a/src/commonTest/kotlin/nl/astraeus/tba/ExtendedByteArrayDefinition.kt b/src/commonTest/kotlin/nl/astraeus/tba/ExtendedByteArrayDefinition.kt index 80354c6..b2918b8 100644 --- a/src/commonTest/kotlin/nl/astraeus/tba/ExtendedByteArrayDefinition.kt +++ b/src/commonTest/kotlin/nl/astraeus/tba/ExtendedByteArrayDefinition.kt @@ -51,7 +51,7 @@ class ExtendedByteArrayDefinition { @Test fun testSimpleTypedByteArray() { - val exception = assertFailsWith(IllegalArgumentException::class) { + val exception = assertFailsWith(IllegalStateException::class) { PersonMessage( 12, 123,