some support for fixed number

This commit is contained in:
sergeych committed 2023-04-01 16:12:20 +01:00
1 parent 5b8df2ff20
commit 86eb5e9d7f
8 files changed
+81 -15

No files matched your search

@@ -36,6 +36,10 @@ inline fun <reified T:Any>DataSink.writeNumber(value: T) {
fun DataSink.writeI32(value: Int) {
writeBytes(intToBytes(value))
}
fun DataSink.writeI16(value: Short) {
writeBytes(shortToBytes(value))
}
fun DataSink.writeU32(value: UInt) {
writeBytes(uintToBytes(value))
}
@@ -28,6 +28,7 @@ interface DataSource {
fun readU32(): UInt = bytesToUInt(readBytes(4))
fun readI32(): Int = bytesToInt(readBytes(4))
fun readI16(): Short = bytesToShort(readBytes(2))
fun readI64(): Long = bytesToLong(readBytes(8))
fun readDouble() = Double.fromBits(readI64())
@@ -20,6 +20,15 @@ fun intToBytes(value: Int): ByteArray {
}
return result
}
fun shortToBytes(value: Short): ByteArray {
var l = value.toInt()
val result = ByteArray(2)
for (i in 1 downTo 0) {
result[i] = (l and 0xFF).toByte()
l = l shr 8
}
return result
}
fun uintToBytes(value: UInt): ByteArray {
var l = value
@@ -52,6 +61,15 @@ fun bytesToInt(b: ByteArray): Int {
return result
}
fun bytesToShort(b: ByteArray): Short {
var result: Int = 0
for (i in 0 until 2) {
result = result shl 8
result = result or (b[i].toInt() and 0xFF)
}
return result.toShort()
}
fun bytesToUInt(b: ByteArray): UInt {
var result = 0u
for (i in 0 until 4) {
@@ -15,18 +15,26 @@ import net.sergeych.bintools.*
* Decode BiPack format. Note that it relies on [DataSource] so can throw [DataSource.EndOfData]
* excpetion. Specific frames when used can throw [InvalidFrameException] and its derivatives.e
*/
class BipackDecoder(val input: DataSource, var elementsCount: Int = 0,val isCollection: Boolean = false,
val hasFixedSize: Boolean = false) : AbstractDecoder() {
class BipackDecoder(
val input: DataSource, var elementsCount: Int = 0, val isCollection: Boolean = false,
val hasFixedSize: Boolean = false,
) : AbstractDecoder() {
private var elementIndex = 0
private var nextIsUnsigned = false
private var fixedSize = -1
private var fixedNumber = false
override val serializersModule: SerializersModule = EmptySerializersModule
override fun decodeBoolean(): Boolean = input.readByte().toInt() != 0
override fun decodeByte(): Byte = input.readByte()
override fun decodeShort(): Short = if (nextIsUnsigned) input.readNumber<UInt>().toShort() else input.readNumber()
override fun decodeInt(): Int = if (nextIsUnsigned) input.readNumber<UInt>().toInt() else input.readNumber()
override fun decodeShort(): Short =
if( fixedNumber ) input.readI16()
else if (nextIsUnsigned) input.readNumber<UInt>().toShort() else input.readNumber()
override fun decodeInt(): Int =
if (fixedNumber) input.readI32()
else if (nextIsUnsigned) input.readNumber<UInt>().toInt() else input.readNumber()
override fun decodeLong(): Long = if (nextIsUnsigned) input.readNumber<ULong>().toLong() else input.readNumber()
override fun decodeFloat(): Float = input.readFloat()
override fun decodeDouble(): Double = input.readDouble()
@@ -44,10 +52,11 @@ class BipackDecoder(val input: DataSource, var elementsCount: Int = 0,val isColl
override fun decodeElementIndex(descriptor: SerialDescriptor): Int {
if (elementIndex >= elementsCount) return CompositeDecoder.DECODE_DONE
nextIsUnsigned = false
for( a in descriptor.getElementAnnotations(elementIndex)) {
when(a) {
for (a in descriptor.getElementAnnotations(elementIndex)) {
when (a) {
is Unsigned -> nextIsUnsigned = true
is FixedSize -> fixedSize = a.size
is Fixed -> fixedNumber = true
}
}
return elementIndex++
@@ -65,7 +74,7 @@ class BipackDecoder(val input: DataSource, var elementsCount: Int = 0,val isColl
// Note: we should read from 'source' explicitely as it might ve
// CRC-calculating one, and the fields below are CRC protected too:
var count = if( fixedSize >= 0 ) fixedSize else descriptor.elementsCount
var count = if (fixedSize >= 0) fixedSize else descriptor.elementsCount
for (a in descriptor.annotations) {
if (a is Extendable)
count = source.readVarUInt().toInt()
@@ -83,7 +92,7 @@ class BipackDecoder(val input: DataSource, var elementsCount: Int = 0,val isColl
}
override fun decodeCollectionSize(descriptor: SerialDescriptor): Int {
return if( hasFixedSize )
return if (hasFixedSize)
elementsCount
else
input.readNumber<UInt>().toInt()
@@ -13,6 +13,7 @@ class BipackEncoder(val output: DataSink) : AbstractEncoder() {
private var nextIsUnsigned = false
private var fixedSize: Int = -1
private var fixedNumber: Boolean = false
override fun encodeElement(descriptor: SerialDescriptor, index: Int): Boolean =
super.encodeElement(descriptor, index).also {
@@ -21,21 +22,25 @@ class BipackEncoder(val output: DataSink) : AbstractEncoder() {
when (a) {
is Unsigned -> nextIsUnsigned = true
is FixedSize -> fixedSize = a.size
is Fixed -> fixedNumber = true
}
}
// nextIsUnsigned = descriptor.getElementAnnotations(index).any { it is Unsigned }
}
override val serializersModule: SerializersModule = EmptySerializersModule
override fun encodeBoolean(value: Boolean) = output.writeByte(if (value) 1 else 0)
override fun encodeByte(value: Byte) = output.writeByte(value.toInt())
override fun encodeShort(value: Short) = if (nextIsUnsigned)
output.writeNumber(value.toUInt())
else
output.writeNumber(value.toInt())
override fun encodeShort(value: Short) =
if (fixedNumber) output.writeI16(value)
else if (nextIsUnsigned)
output.writeNumber(value.toUInt())
else
output.writeNumber(value.toInt())
override fun encodeInt(value: Int) =
if (nextIsUnsigned) output.writeNumber(value.toUInt())
if (fixedNumber)
output.writeI32(value)
else if (nextIsUnsigned) output.writeNumber(value.toUInt())
else output.writeNumber(value)
fun encodeUInt(value: UInt) = output.writeNumber(value)
@@ -58,6 +58,10 @@ annotation class Unsigned
@Target(AnnotationTarget.FIELD, AnnotationTarget.PROPERTY)
annotation class FixedSize(val size: Int)
@SerialInfo
@Target(AnnotationTarget.FIELD, AnnotationTarget.PROPERTY)
annotation class Fixed
open class InvalidFrameException(reason: String) : Exception(reason)
class InvalidFrameHeaderException(reason: String = "Frame header does not match") : InvalidFrameException(reason)
class InvalidFrameCRCException : InvalidFrameException("Checksum CRC32 failed")