Add size of length to buffer, cleanup
This commit is contained in:
@@ -1,27 +1,34 @@
|
||||
package nl.astraeus.tba
|
||||
|
||||
enum class DataType(val size: Int) {
|
||||
enum class DataType(
|
||||
val size: Int,
|
||||
val bytesUsedInternally: Int = 0
|
||||
) {
|
||||
BYTE(1),
|
||||
SHORT(2),
|
||||
INT(4),
|
||||
LONG(8),
|
||||
FLOAT(4),
|
||||
DOUBLE(8),
|
||||
STRING(-1), // max length 65535
|
||||
CLOB(-1), // max length 2^32-1
|
||||
BLOB(-1), // max length 2^32-1
|
||||
STRING(-1, 2), // max length 65535
|
||||
CLOB(-1, 4), // max length 2^32-1
|
||||
BLOB(-1, 4), // max length 2^32-1
|
||||
;
|
||||
}
|
||||
|
||||
class Type(
|
||||
val name: String,
|
||||
val type: DataType,
|
||||
val size: Int = if (type.size == -1) {
|
||||
size: Int = 0,
|
||||
) {
|
||||
val size: Int = if (size > 0) {
|
||||
size + type.bytesUsedInternally
|
||||
} else if (type.size == -1) {
|
||||
throw IllegalArgumentException("Size must be defined for type ${type.name}")
|
||||
} else {
|
||||
type.size
|
||||
},
|
||||
)
|
||||
type.size + type.bytesUsedInternally
|
||||
}
|
||||
}
|
||||
|
||||
open class ByteArrayDefinition(
|
||||
vararg types: Type,
|
||||
@@ -31,4 +38,4 @@ open class ByteArrayDefinition(
|
||||
val size: Int by lazy {
|
||||
this.types.sumOf { it.size }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
package nl.astraeus.tba
|
||||
|
||||
fun ByteArray.setShort(index: Int, value: Short) {
|
||||
this[index] = (value.toInt() shr 8).toByte()
|
||||
this[index + 1] = value.toByte()
|
||||
}
|
||||
|
||||
fun ByteArray.getShort(index: Int): Short {
|
||||
return ((this[index].toInt() shl 8) or (this[index + 1].toInt() and 0xff)).toShort()
|
||||
}
|
||||
|
||||
fun ByteArray.setInt(index: Int, value: Int) {
|
||||
this[index] = ((value shr 24) and 0xff).toByte()
|
||||
this[index + 1] = ((value shr 16) and 0xff).toByte()
|
||||
this[index + 2] = ((value shr 8) and 0xff).toByte()
|
||||
this[index + 3] = (value and 0xff).toByte()
|
||||
}
|
||||
|
||||
fun ByteArray.getInt(index: Int): Int {
|
||||
return (
|
||||
(this[index].toInt() shl 24) or
|
||||
((this[index+1].toInt() shl 16) and 0xff0000) or
|
||||
((this[index+2].toInt() shl 8) and 0xff00) or
|
||||
(this[index+3].toInt() and 0xff)
|
||||
)
|
||||
}
|
||||
|
||||
fun ByteArray.setLong(index: Int, value: Long) {
|
||||
this[index] = ((value shr 56) and 0xff).toByte()
|
||||
this[index + 1] = ((value shr 48) and 0xff).toByte()
|
||||
this[index + 2] = ((value shr 40) and 0xff).toByte()
|
||||
this[index + 3] = ((value shr 32) and 0xff).toByte()
|
||||
this[index + 4] = ((value shr 24) and 0xff).toByte()
|
||||
this[index + 5] = ((value shr 16) and 0xff).toByte()
|
||||
this[index + 6] = ((value shr 8) and 0xff).toByte()
|
||||
this[index + 7] = (value and 0xff).toByte()
|
||||
}
|
||||
|
||||
fun ByteArray.getLong(index: Int): Long {
|
||||
return (
|
||||
(this[index].toLong() shl 56) or
|
||||
((this[index+1].toLong() and 0xff) shl 48) or
|
||||
((this[index+2].toLong() and 0xff) shl 40) or
|
||||
((this[index+3].toLong() and 0xff) shl 32) or
|
||||
((this[index+4].toLong() and 0xff) shl 24) or
|
||||
((this[index+5].toLong() and 0xff) shl 16) or
|
||||
((this[index+6].toLong() and 0xff) shl 8) or
|
||||
(this[index+7].toLong() and 0xff)
|
||||
)
|
||||
}
|
||||
|
||||
fun ByteArray.setDouble(index: Int, value: Double) = this.setLong(index, value.toRawBits())
|
||||
fun ByteArray.getDouble(index: Int): Double = Double.fromBits(this.getLong(index))
|
||||
|
||||
fun ByteArray.setFloat(index: Int, value: Float) = this.setInt(index, value.toRawBits())
|
||||
fun ByteArray.getFloat(index: Int): Float = Float.fromBits(this.getInt(index))
|
||||
|
||||
fun ByteArray.getString(index: Int): Pair<String, Int> {
|
||||
val length = this.getInt(index)
|
||||
val str = this.copyOfRange(index + 4, index + 4 + length).decodeToString()
|
||||
return Pair(str, index + 4 + length)
|
||||
}
|
||||
|
||||
fun ByteArray.setString(index: Int, value: String): Int {
|
||||
val bytes = value.encodeToByteArray()
|
||||
this.setInt(index, bytes.size)
|
||||
bytes.copyInto(this, index + 4)
|
||||
return index + bytes.size + 4
|
||||
}
|
||||
@@ -2,9 +2,13 @@ package nl.astraeus.tba
|
||||
|
||||
class MutableByteArrayHandler(
|
||||
initialSize: Int = 1024,
|
||||
buffer: ByteArray = ByteArray(initialSize)
|
||||
buffer: SlicedByteArray = SlicedByteArray.wrap(ByteArray(initialSize), 0, initialSize),
|
||||
) : ByteArrayHandler(initialSize, buffer) {
|
||||
|
||||
constructor(buffer: ByteArray, range: IntRange = buffer.indices) : this(
|
||||
buffer = SlicedByteArray.wrap(buffer, range.first, range.last - range.first)
|
||||
)
|
||||
|
||||
operator fun set(index: Int, value: Byte) {
|
||||
buffer[index] = value
|
||||
}
|
||||
@@ -32,8 +36,8 @@ class MutableByteArrayHandler(
|
||||
buffer[index + 7] = (value and 0xff).toByte()
|
||||
}
|
||||
|
||||
fun setFloat(index: Int, value: Float) = buffer.setInt(index, value.toRawBits())
|
||||
fun setDouble(index: Int, value: Double) = buffer.setLong(index, value.toRawBits())
|
||||
fun setFloat(index: Int, value: Float) = setInt(index, value.toRawBits())
|
||||
fun setDouble(index: Int, value: Double) = setLong(index, value.toRawBits())
|
||||
|
||||
fun setString(index: Int, value: String, maxLength: Int): Int {
|
||||
val bytes = value.encodeToByteArray()
|
||||
@@ -41,7 +45,7 @@ class MutableByteArrayHandler(
|
||||
throw IllegalArgumentException("String is too long")
|
||||
}
|
||||
this.setShort(index, bytes.size.toShort())
|
||||
bytes.copyInto(buffer, index + 2)
|
||||
bytes.copyInto(buffer.data, index + 2)
|
||||
return index + bytes.size + 2
|
||||
}
|
||||
|
||||
@@ -51,7 +55,7 @@ class MutableByteArrayHandler(
|
||||
throw IllegalArgumentException("String is too long")
|
||||
}
|
||||
this.setInt(index, bytes.size)
|
||||
bytes.copyInto(buffer, index + 4)
|
||||
bytes.copyInto(buffer.data, index + 4)
|
||||
return index + bytes.size + 4
|
||||
}
|
||||
|
||||
@@ -60,7 +64,7 @@ class MutableByteArrayHandler(
|
||||
throw IllegalArgumentException("String is too long")
|
||||
}
|
||||
this.setInt(index, bytes.size)
|
||||
bytes.copyInto(buffer, index + 4)
|
||||
bytes.copyInto(buffer.data, index + 4)
|
||||
return index + bytes.size + 4
|
||||
}
|
||||
|
||||
@@ -68,15 +72,11 @@ class MutableByteArrayHandler(
|
||||
|
||||
open class ByteArrayHandler(
|
||||
size: Int = 1024,
|
||||
var buffer: ByteArray = ByteArray(size),
|
||||
val firstIndex: Int = 0,
|
||||
val lastIndex: Int = buffer.size
|
||||
var buffer: SlicedByteArray = SlicedByteArray.wrap(ByteArray(size), 0, size),
|
||||
) {
|
||||
|
||||
constructor(buffer: ByteArray, range: IntRange) : this(
|
||||
buffer = buffer,
|
||||
firstIndex = range.first,
|
||||
lastIndex = range.last
|
||||
constructor(buffer: ByteArray, range: IntRange = buffer.indices) : this(
|
||||
buffer = SlicedByteArray.wrap(buffer, range.first, range.last - range.first)
|
||||
)
|
||||
|
||||
operator fun get(index: Int): Byte {
|
||||
@@ -109,35 +109,34 @@ open class ByteArrayHandler(
|
||||
)
|
||||
}
|
||||
|
||||
fun getFloat(index: Int): Float = Float.fromBits(buffer.getInt(index))
|
||||
fun getDouble(index: Int): Double = Double.fromBits(buffer.getLong(index))
|
||||
fun getFloat(index: Int): Float = Float.fromBits(getInt(index))
|
||||
fun getDouble(index: Int): Double = Double.fromBits(getLong(index))
|
||||
|
||||
fun getString(index: Int): String {
|
||||
val length = getShort(index)
|
||||
val str = buffer.copyOfRange(index + 2, index + 2 + length).decodeToString()
|
||||
val str = buffer.data.copyOfRange(index + 2, index + 2 + length).decodeToString()
|
||||
return str
|
||||
}
|
||||
|
||||
fun getClob(index: Int): String {
|
||||
val length = getInt(index)
|
||||
val str = buffer.copyOfRange(index + 4, index + 4 + length).decodeToString()
|
||||
val str = buffer.data.copyOfRange(index + 4, index + 4 + length).decodeToString()
|
||||
return str
|
||||
}
|
||||
|
||||
fun getBlob(index: Int): ByteArray {
|
||||
val length = getInt(index)
|
||||
val str = buffer.copyOfRange(index + 4, index + 4 + length)
|
||||
val str = buffer.data.copyOfRange(index + 4, index + 4 + length)
|
||||
return str
|
||||
}
|
||||
|
||||
fun slice(range: IntRange): ByteArrayHandler {
|
||||
return ByteArrayHandler(
|
||||
buffer,
|
||||
range
|
||||
buffer = SlicedByteArray(this.buffer.data, range.first, range.last - range.first)
|
||||
)
|
||||
}
|
||||
|
||||
fun asMutable(): MutableByteArrayHandler {
|
||||
return MutableByteArrayHandler(buffer = buffer.copyOfRange(firstIndex, lastIndex))
|
||||
return MutableByteArrayHandler(buffer = SlicedByteArray(buffer.data, 0, buffer.data.size))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,10 @@ abstract class ByteArrayPropertyWithLength<T>(
|
||||
|
||||
protected fun getMaxLength(thisRef: TypedByteArray): Int {
|
||||
if (maxLength == null) {
|
||||
maxLength = thisRef.typeMap[name]!!.size - 2
|
||||
val type = thisRef.typeMap[name] ?: throw IllegalArgumentException(
|
||||
"Type $name not found in typemap in $thisRef"
|
||||
)
|
||||
maxLength = type.size
|
||||
}
|
||||
return maxLength!!
|
||||
}
|
||||
|
||||
32
src/commonMain/kotlin/nl/astraeus/tba/SlicedByteArray.kt
Normal file
32
src/commonMain/kotlin/nl/astraeus/tba/SlicedByteArray.kt
Normal file
@@ -0,0 +1,32 @@
|
||||
package nl.astraeus.tba
|
||||
|
||||
class SlicedByteArray(
|
||||
val data: ByteArray,
|
||||
val offset: Int,
|
||||
val length: Int
|
||||
) {
|
||||
val size: Int
|
||||
get() = length
|
||||
|
||||
operator fun get(index: Int): Byte {
|
||||
return data[offset + index]
|
||||
}
|
||||
|
||||
operator fun set(index: Int, value: Byte) {
|
||||
data[offset + index] = value
|
||||
}
|
||||
|
||||
fun copyInto(dest: ByteArray, destOffset: Int, length: Int) {
|
||||
data.copyInto(dest, destOffset, offset, offset + length)
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun wrap(
|
||||
data: ByteArray,
|
||||
offset: Int,
|
||||
length: Int
|
||||
): SlicedByteArray {
|
||||
return SlicedByteArray(data, offset,length)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,8 @@ open class TypedByteArray(
|
||||
}
|
||||
}
|
||||
|
||||
constructor(vararg types: Type): this(ByteArrayDefinition(*types))
|
||||
|
||||
constructor(data: ByteArray): this(ByteArrayDefinition()) {
|
||||
this.data = MutableByteArrayHandler(buffer = data)
|
||||
}
|
||||
|
||||
@@ -9,12 +9,10 @@ class ExtendedByteArrayDefinition {
|
||||
open class MessageByteArray(
|
||||
vararg types: Type
|
||||
) : TypedByteArray(
|
||||
ByteArrayDefinition(
|
||||
Type("messageType", DataType.BYTE),
|
||||
Type("messageLength", DataType.SHORT),
|
||||
Type("message", DataType.STRING, 1024),
|
||||
*types,
|
||||
)
|
||||
) {
|
||||
var messageType by byte("messageType")
|
||||
var messageLength by short("messageLength")
|
||||
|
||||
36
src/commonTest/kotlin/nl/astraeus/tba/TypedByteArraySize.kt
Normal file
36
src/commonTest/kotlin/nl/astraeus/tba/TypedByteArraySize.kt
Normal file
@@ -0,0 +1,36 @@
|
||||
package nl.astraeus.tba
|
||||
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class TypedByteArraySize {
|
||||
|
||||
class Person() : TypedByteArray(
|
||||
Type("name", DataType.STRING, 100),
|
||||
) {
|
||||
var name by string("name")
|
||||
|
||||
constructor(name: String): this() {
|
||||
this.name = name
|
||||
}
|
||||
|
||||
constructor(data: ByteArray): this() {
|
||||
this.data = MutableByteArrayHandler(buffer = data)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testPersonSize() {
|
||||
val type = Type("name", DataType.STRING, 10)
|
||||
|
||||
assertEquals(12, type.size)
|
||||
|
||||
val person = Person("Test")
|
||||
|
||||
assertEquals(102, person.data.buffer.size)
|
||||
|
||||
val clobType = Type("long-name", DataType.CLOB, 100)
|
||||
|
||||
assertEquals(104, clobType.size)
|
||||
}
|
||||
}
|
||||
@@ -6,11 +6,9 @@ import kotlin.test.assertEquals
|
||||
class TypedByteArrayTest {
|
||||
|
||||
class Person() : TypedByteArray(
|
||||
ByteArrayDefinition(
|
||||
Type("name", DataType.STRING, 102),
|
||||
Type("name", DataType.STRING, 100),
|
||||
Type("age", DataType.BYTE),
|
||||
Type("length", DataType.SHORT),
|
||||
)
|
||||
) {
|
||||
var name by string("name")
|
||||
var age by byte("age")
|
||||
@@ -33,6 +31,7 @@ class TypedByteArrayTest {
|
||||
|
||||
assertEquals(4, person.data.buffer[1])
|
||||
assertEquals(42, person.data.buffer[102])
|
||||
assertEquals(180.toByte(), person.data.buffer[104])
|
||||
|
||||
assertEquals("Test", person.name)
|
||||
assertEquals(42.toByte(), person.age)
|
||||
@@ -42,7 +41,7 @@ class TypedByteArrayTest {
|
||||
@Test
|
||||
fun testToByteArrayAndBack() {
|
||||
val person = Person("Test", 42, 180)
|
||||
val bytes: ByteArray = person.data.buffer
|
||||
val bytes: ByteArray = person.data.buffer.data
|
||||
|
||||
val person2 = Person(bytes)
|
||||
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
package nl.astraeus.tba
|
||||
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class TypedByteArrayWithByteArrayTest {
|
||||
|
||||
class Person1() : TypedByteArray(
|
||||
Type("name", DataType.STRING, 10),
|
||||
) {
|
||||
var name by string("name")
|
||||
|
||||
constructor(name: String): this() {
|
||||
this.name = name
|
||||
}
|
||||
|
||||
constructor(data: ByteArray): this() {
|
||||
this.data = MutableByteArrayHandler(buffer = data)
|
||||
}
|
||||
}
|
||||
|
||||
class Company() : TypedByteArray(
|
||||
Type("name", DataType.STRING, 10),
|
||||
Type("person", DataType.BLOB, 12)
|
||||
) {
|
||||
var name by string("name")
|
||||
var personData by blob("person")
|
||||
val person by lazy { Person1(personData) }
|
||||
|
||||
constructor(name: String, person: Person1): this() {
|
||||
this.name = name
|
||||
this.personData = person.data.buffer.data
|
||||
}
|
||||
|
||||
constructor(data: ByteArray): this() {
|
||||
this.data = MutableByteArrayHandler(buffer = data)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testPersonSize() {
|
||||
val person = Person1("A Name")
|
||||
|
||||
assertEquals(12, person.data.buffer.size)
|
||||
|
||||
val company = Company("A Company", person)
|
||||
|
||||
assertEquals("A Name", company.person.name)
|
||||
|
||||
company.person.name = "2nd Name"
|
||||
|
||||
assertEquals("2nd Name", company.person.name)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user