diff --git a/gradle.properties b/gradle.properties index 62500e3..836ce74 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,7 +1,7 @@ kotlin.code.style=official group=io.rebble.libpebblecommon -version=0.1.23 +version=0.1.24 org.gradle.jvmargs=-Xms128M -Xmx1G -XX:ReservedCodeCacheSize=200M kotlin.native.binary.memoryModel=experimental kotlin.mpp.androidSourceSetLayoutVersion=2 diff --git a/src/androidMain/kotlin/util/DataBuffer.kt b/src/androidMain/kotlin/util/DataBuffer.kt index ec5838b..e58b09a 100644 --- a/src/androidMain/kotlin/util/DataBuffer.kt +++ b/src/androidMain/kotlin/util/DataBuffer.kt @@ -62,10 +62,11 @@ actual class DataBuffer { actual fun array(): UByteArray = actualBuf.array().toUByteArray() - actual fun setEndian(endian: Char) { + actual fun setEndian(endian: Endian) { when (endian) { - '>' -> actualBuf.order(ByteOrder.BIG_ENDIAN) - '<' -> actualBuf.order(ByteOrder.LITTLE_ENDIAN) + Endian.Big -> actualBuf.order(ByteOrder.BIG_ENDIAN) + Endian.Little -> actualBuf.order(ByteOrder.LITTLE_ENDIAN) + else -> {} } } diff --git a/src/commonMain/kotlin/io/rebble/libpebblecommon/packets/AppCustomization.kt b/src/commonMain/kotlin/io/rebble/libpebblecommon/packets/AppCustomization.kt index 506d0bc..50ba45a 100644 --- a/src/commonMain/kotlin/io/rebble/libpebblecommon/packets/AppCustomization.kt +++ b/src/commonMain/kotlin/io/rebble/libpebblecommon/packets/AppCustomization.kt @@ -8,6 +8,7 @@ import io.rebble.libpebblecommon.structmapper.SUByte import io.rebble.libpebblecommon.structmapper.SUShort import io.rebble.libpebblecommon.util.Bitmap import io.rebble.libpebblecommon.util.DataBuffer +import io.rebble.libpebblecommon.util.Endian class AppCustomizationSetStockAppTitleMessage( appType: AppType, @@ -23,21 +24,21 @@ class AppCustomizationSetStockAppIconMessage( ) : PebblePacket(ProtocolEndpoint.APP_CUSTOMIZE) { // First bit being set signifies that this is icon packet instead of name packet val appType = SUByte(m, appType.value or 0b10000000u) - val bytesPerLine = SUShort(m, endianness = '<') + val bytesPerLine = SUShort(m, endianness = Endian.Little) /** * No idea what flags are possible. Stock app always sends 4096 here. */ - val flags = SUShort(m, 4096u, endianness = '<') + val flags = SUShort(m, 4096u, endianness = Endian.Little) /** * Offset is not supported by app. Always 0. */ - val originY = SUShort(m, 0u, endianness = '<') - val originX = SUShort(m, 0u, endianness = '<') + val originY = SUShort(m, 0u, endianness = Endian.Little) + val originX = SUShort(m, 0u, endianness = Endian.Little) - val width = SUShort(m, endianness = '<') - val height = SUShort(m, endianness = '<') + val width = SUShort(m, endianness = Endian.Little) + val height = SUShort(m, endianness = Endian.Little) val imageData = SBytes(m) diff --git a/src/commonMain/kotlin/io/rebble/libpebblecommon/packets/AppFetch.kt b/src/commonMain/kotlin/io/rebble/libpebblecommon/packets/AppFetch.kt index b29cb73..919169d 100644 --- a/src/commonMain/kotlin/io/rebble/libpebblecommon/packets/AppFetch.kt +++ b/src/commonMain/kotlin/io/rebble/libpebblecommon/packets/AppFetch.kt @@ -6,6 +6,7 @@ import io.rebble.libpebblecommon.protocolhelpers.ProtocolEndpoint import io.rebble.libpebblecommon.structmapper.SUByte import io.rebble.libpebblecommon.structmapper.SUInt import io.rebble.libpebblecommon.structmapper.SUUID +import io.rebble.libpebblecommon.util.Endian sealed class AppFetchIncomingPacket() : PebblePacket(ProtocolEndpoint.APP_FETCH) { /** @@ -38,7 +39,7 @@ class AppFetchRequest : AppFetchIncomingPacket() { /** * ID of the app bank. Use in the [PutBytesAppInit] packet to identify this app install. */ - val appId = SUInt(m, endianness = '<') + val appId = SUInt(m, endianness = Endian.Little) } /** diff --git a/src/commonMain/kotlin/io/rebble/libpebblecommon/packets/AppMessage.kt b/src/commonMain/kotlin/io/rebble/libpebblecommon/packets/AppMessage.kt index 262a44f..b6acf90 100644 --- a/src/commonMain/kotlin/io/rebble/libpebblecommon/packets/AppMessage.kt +++ b/src/commonMain/kotlin/io/rebble/libpebblecommon/packets/AppMessage.kt @@ -6,6 +6,7 @@ import io.rebble.libpebblecommon.protocolhelpers.PebblePacket import io.rebble.libpebblecommon.protocolhelpers.ProtocolEndpoint import io.rebble.libpebblecommon.structmapper.* import io.rebble.libpebblecommon.util.DataBuffer +import io.rebble.libpebblecommon.util.Endian class AppMessageTuple() : StructMappable() { @@ -22,9 +23,9 @@ class AppMessageTuple() : StructMappable() { } } - val key = SUInt(m, endianness = '<') + val key = SUInt(m, endianness = Endian.Little) val type = SUByte(m) - val dataLength = SUShort(m, endianness = '<') + val dataLength = SUShort(m, endianness = Endian.Little) val data = SBytes(m, 0) init { @@ -46,8 +47,8 @@ class AppMessageTuple() : StructMappable() { get() { val obj = when (val size = dataLength.get().toInt()) { 1 -> SByte(StructMapper()) - 2 -> SShort(StructMapper(), endianness = '<') - 4 -> SInt(StructMapper(), endianness = '<') + 2 -> SShort(StructMapper(), endianness = Endian.Little) + 4 -> SInt(StructMapper(), endianness = Endian.Little) else -> error("Size not supported: $size") } return obj.apply { @@ -59,8 +60,8 @@ class AppMessageTuple() : StructMappable() { get() { val obj = when (val size = dataLength.get().toInt()) { 1 -> SUByte(StructMapper()) - 2 -> SUShort(StructMapper(), endianness = '<') - 4 -> SUInt(StructMapper(), endianness = '<') + 2 -> SUShort(StructMapper(), endianness = Endian.Little) + 4 -> SUInt(StructMapper(), endianness = Endian.Little) else -> error("Size not supported: $size") } return obj.apply { @@ -146,7 +147,7 @@ class AppMessageTuple() : StructMappable() { this.key.set(key) this.type.set(Type.Int.value) - val bytes = SShort(StructMapper(), data, endianness = '<').toBytes() + val bytes = SShort(StructMapper(), data, endianness = Endian.Little).toBytes() this.dataLength.set(bytes.size.toUShort()) this.data.set(bytes) } @@ -158,7 +159,7 @@ class AppMessageTuple() : StructMappable() { this.key.set(key) this.type.set(Type.UInt.value) - val bytes = SUShort(StructMapper(), data, endianness = '<').toBytes() + val bytes = SUShort(StructMapper(), data, endianness = Endian.Little).toBytes() this.dataLength.set(bytes.size.toUShort()) this.data.set(bytes) } @@ -170,7 +171,7 @@ class AppMessageTuple() : StructMappable() { this.key.set(key) this.type.set(Type.Int.value) - val bytes = SInt(StructMapper(), data, endianness = '<').toBytes() + val bytes = SInt(StructMapper(), data, endianness = Endian.Little).toBytes() this.dataLength.set(bytes.size.toUShort()) this.data.set(bytes) } @@ -182,7 +183,7 @@ class AppMessageTuple() : StructMappable() { this.key.set(key) this.type.set(Type.UInt.value) - val bytes = SUInt(StructMapper(), data, endianness = '<').toBytes() + val bytes = SUInt(StructMapper(), data, endianness = Endian.Little).toBytes() this.dataLength.set(bytes.size.toUShort()) this.data.set(bytes) } diff --git a/src/commonMain/kotlin/io/rebble/libpebblecommon/packets/Music.kt b/src/commonMain/kotlin/io/rebble/libpebblecommon/packets/Music.kt index cc6845a..7621f24 100644 --- a/src/commonMain/kotlin/io/rebble/libpebblecommon/packets/Music.kt +++ b/src/commonMain/kotlin/io/rebble/libpebblecommon/packets/Music.kt @@ -4,6 +4,7 @@ import io.rebble.libpebblecommon.protocolhelpers.PacketRegistry import io.rebble.libpebblecommon.protocolhelpers.PebblePacket import io.rebble.libpebblecommon.protocolhelpers.ProtocolEndpoint import io.rebble.libpebblecommon.structmapper.* +import io.rebble.libpebblecommon.util.Endian open class MusicControl(val message: Message) : PebblePacket(ProtocolEndpoint.MUSIC_CONTROL) { val command = SUByte(m, message.value) @@ -43,17 +44,17 @@ open class MusicControl(val message: Message) : PebblePacket(ProtocolEndpoint.MU val title = SString(m, title) val trackLength = SOptional( m, - SUInt(StructMapper(), trackLength?.toUInt() ?: 0u, '<'), + SUInt(StructMapper(), trackLength?.toUInt() ?: 0u, Endian.Little), trackLength != null ) val trackCount = SOptional( m, - SUInt(StructMapper(), trackCount?.toUInt() ?: 0u, '<'), + SUInt(StructMapper(), trackCount?.toUInt() ?: 0u, Endian.Little), trackCount != null ) val currentTrack = SOptional( m, - SUInt(StructMapper(), currentTrack?.toUInt() ?: 0u, '<'), + SUInt(StructMapper(), currentTrack?.toUInt() ?: 0u, Endian.Little), currentTrack != null ) } @@ -72,8 +73,8 @@ open class MusicControl(val message: Message) : PebblePacket(ProtocolEndpoint.MU repeat: RepeatState = RepeatState.Unknown ) : MusicControl(Message.UpdatePlayStateInfo) { val state = SUByte(m, playbackState.value) - val trackPosition = SUInt(m, trackPosition, '<') - val playRate = SUInt(m, playRate, '<') + val trackPosition = SUInt(m, trackPosition, Endian.Little) + val playRate = SUInt(m, playRate, Endian.Little) val shuffle = SUByte(m, shuffle.value) val repeat = SUByte(m, repeat.value) } diff --git a/src/commonMain/kotlin/io/rebble/libpebblecommon/packets/System.kt b/src/commonMain/kotlin/io/rebble/libpebblecommon/packets/System.kt index 3ae2816..97c26e9 100644 --- a/src/commonMain/kotlin/io/rebble/libpebblecommon/packets/System.kt +++ b/src/commonMain/kotlin/io/rebble/libpebblecommon/packets/System.kt @@ -9,6 +9,7 @@ import io.rebble.libpebblecommon.protocolhelpers.PacketRegistry import io.rebble.libpebblecommon.protocolhelpers.PebblePacket import io.rebble.libpebblecommon.protocolhelpers.ProtocolEndpoint import io.rebble.libpebblecommon.structmapper.* +import io.rebble.libpebblecommon.util.Endian sealed class SystemPacket(endpoint: ProtocolEndpoint) : PebblePacket(endpoint) @@ -410,8 +411,8 @@ open class SystemMessage(message: Message) : SystemPacket(endpoint) { class NewFirmwareAvailable: SystemMessage(Message.NewFirmwareAvailable) class FirmwareUpdateStart(bytesAlreadyTransferred: UInt, bytesToSend: UInt): SystemMessage(Message.FirmwareUpdateStart) { - val bytesAlreadyTransferred = SUInt(m, bytesAlreadyTransferred, endianness = '<') - val bytesToSend = SUInt(m, bytesToSend, endianness = '<') + val bytesAlreadyTransferred = SUInt(m, bytesAlreadyTransferred, endianness = Endian.Little) + val bytesToSend = SUInt(m, bytesToSend, endianness = Endian.Little) } class FirmwareUpdateComplete: SystemMessage(Message.FirmwareUpdateComplete) class FirmwareUpdateFailed: SystemMessage(Message.FirmwareUpdateFailed) diff --git a/src/commonMain/kotlin/io/rebble/libpebblecommon/packets/blobdb/App.kt b/src/commonMain/kotlin/io/rebble/libpebblecommon/packets/blobdb/App.kt index 8aaa913..9005e8e 100644 --- a/src/commonMain/kotlin/io/rebble/libpebblecommon/packets/blobdb/App.kt +++ b/src/commonMain/kotlin/io/rebble/libpebblecommon/packets/blobdb/App.kt @@ -1,6 +1,7 @@ package io.rebble.libpebblecommon.packets.blobdb import io.rebble.libpebblecommon.structmapper.* +import io.rebble.libpebblecommon.util.Endian /** * Data of the APP BlobDB Entry @@ -14,12 +15,12 @@ class AppMetadata() : StructMappable() { /** * App install flags. */ - val flags: SUInt = SUInt(m) + val flags: SUInt = SUInt(m, endianness = Endian.Little) /** * Resource ID of the primary icon. */ - val icon: SUInt = SUInt(m) + val icon: SUInt = SUInt(m, endianness = Endian.Little) /** * Major app version. diff --git a/src/commonMain/kotlin/io/rebble/libpebblecommon/packets/blobdb/BlobDB.kt b/src/commonMain/kotlin/io/rebble/libpebblecommon/packets/blobdb/BlobDB.kt index 0d721d9..146e916 100644 --- a/src/commonMain/kotlin/io/rebble/libpebblecommon/packets/blobdb/BlobDB.kt +++ b/src/commonMain/kotlin/io/rebble/libpebblecommon/packets/blobdb/BlobDB.kt @@ -6,6 +6,7 @@ import io.rebble.libpebblecommon.protocolhelpers.ProtocolEndpoint import io.rebble.libpebblecommon.structmapper.SBytes import io.rebble.libpebblecommon.structmapper.SUByte import io.rebble.libpebblecommon.structmapper.SUShort +import io.rebble.libpebblecommon.util.Endian open class BlobCommand constructor(message: Message, token: UShort, database: BlobDatabase) : PebblePacket( @@ -46,7 +47,7 @@ open class BlobCommand constructor(message: Message, token: UShort, database: Bl ) { val keySize = SUByte(m, key.size.toUByte()) val targetKey = SBytes(m, key.size, key) - val valSize = SUShort(m, value.size.toUShort(), endianness = '<') + val valSize = SUShort(m, value.size.toUShort(), endianness = Endian.Little) val targetValue = SBytes(m, value.size, value) } diff --git a/src/commonMain/kotlin/io/rebble/libpebblecommon/packets/blobdb/Timeline.kt b/src/commonMain/kotlin/io/rebble/libpebblecommon/packets/blobdb/Timeline.kt index 9b6ba44..0218024 100644 --- a/src/commonMain/kotlin/io/rebble/libpebblecommon/packets/blobdb/Timeline.kt +++ b/src/commonMain/kotlin/io/rebble/libpebblecommon/packets/blobdb/Timeline.kt @@ -7,6 +7,7 @@ import io.rebble.libpebblecommon.protocolhelpers.PebblePacket import io.rebble.libpebblecommon.protocolhelpers.ProtocolEndpoint import io.rebble.libpebblecommon.structmapper.* import io.rebble.libpebblecommon.util.DataBuffer +import io.rebble.libpebblecommon.util.Endian class TimelineItem( itemId: Uuid, @@ -52,12 +53,12 @@ class TimelineItem( /** * Timeline pin timestamp in unix time */ - val timestamp = SUInt(m, timestamp, endianness = '<') + val timestamp = SUInt(m, timestamp, endianness = Endian.Little) /** * Duration of the pin in minutes */ - val duration = SUShort(m, duration, endianness = '<') + val duration = SUShort(m, duration, endianness = Endian.Little) /** * Serialization of [Type]. Use [Type.value]. @@ -67,10 +68,10 @@ class TimelineItem( /** * Serialization of [Flag] entries. Use [Flag.makeFlags]. */ - val flags = SUShort(m, flags, endianness = '<') + val flags = SUShort(m, flags, endianness = Endian.Little) val layout = SUByte(m, layout.value) - val dataLength = SUShort(m, endianness = '<') + val dataLength = SUShort(m, endianness = Endian.Little) val attrCount = SUByte(m, attributes.size.toUByte()) val actionCount = SUByte(m, actions.size.toUByte()) val attributes = @@ -87,7 +88,7 @@ class TimelineItem( dataLength.set((this.attributes.toBytes().size + this.actions.toBytes().size).toUShort()) } - class Action(actionID: UByte, type: Type, attributes: List) : Mappable { + class Action(actionID: UByte, type: Type, attributes: List) : Mappable() { val m = StructMapper() enum class Type(val value: UByte) { @@ -121,22 +122,21 @@ class TimelineItem( get() = m.size } - class Attribute() : StructMappable() { + class Attribute(contentEndianness: Endian = Endian.Unspecified) : StructMappable() { val attributeId = SUByte(m) - val length = SUShort(m, endianness = '<') - val content = SBytes(m, 0) + val length = SUShort(m, endianness = Endian.Little) + val content = SBytes(m, 0, endianness = contentEndianness) constructor( attributeId: UByte, content: UByteArray, - contentEndianness: Char = '|' - ) : this() { + contentEndianness: Endian = Endian.Unspecified + ) : this(contentEndianness) { this.attributeId.set(attributeId) this.length.set(content.size.toUShort()) this.content.set(content) - this.content.setEndiannes(contentEndianness) } init { diff --git a/src/commonMain/kotlin/io/rebble/libpebblecommon/structmapper/StructMappable.kt b/src/commonMain/kotlin/io/rebble/libpebblecommon/structmapper/StructMappable.kt index ddf426b..17204b1 100644 --- a/src/commonMain/kotlin/io/rebble/libpebblecommon/structmapper/StructMappable.kt +++ b/src/commonMain/kotlin/io/rebble/libpebblecommon/structmapper/StructMappable.kt @@ -1,9 +1,10 @@ package io.rebble.libpebblecommon.structmapper import io.rebble.libpebblecommon.util.DataBuffer +import io.rebble.libpebblecommon.util.Endian -abstract class StructMappable : Mappable { - val m = StructMapper() +abstract class StructMappable(endianness: Endian = Endian.Unspecified) : Mappable(endianness) { + val m = StructMapper(endianness = endianness) override fun toBytes(): UByteArray { return m.toBytes() diff --git a/src/commonMain/kotlin/io/rebble/libpebblecommon/structmapper/StructMapper.kt b/src/commonMain/kotlin/io/rebble/libpebblecommon/structmapper/StructMapper.kt index bba650b..31a5ce3 100644 --- a/src/commonMain/kotlin/io/rebble/libpebblecommon/structmapper/StructMapper.kt +++ b/src/commonMain/kotlin/io/rebble/libpebblecommon/structmapper/StructMapper.kt @@ -2,11 +2,12 @@ package io.rebble.libpebblecommon.structmapper import io.rebble.libpebblecommon.exceptions.PacketDecodeException import io.rebble.libpebblecommon.util.DataBuffer +import io.rebble.libpebblecommon.util.Endian /** * Maps class properties to a struct equivalent */ -class StructMapper: Mappable { +class StructMapper(endianness: Endian = Endian.Unspecified): Mappable(endianness) { private var struct: MutableList = mutableListOf() /** diff --git a/src/commonMain/kotlin/io/rebble/libpebblecommon/structmapper/types.kt b/src/commonMain/kotlin/io/rebble/libpebblecommon/structmapper/types.kt index d11f61c..3547cee 100644 --- a/src/commonMain/kotlin/io/rebble/libpebblecommon/structmapper/types.kt +++ b/src/commonMain/kotlin/io/rebble/libpebblecommon/structmapper/types.kt @@ -6,28 +6,30 @@ import com.benasher44.uuid.uuidOf import io.rebble.libpebblecommon.exceptions.PacketDecodeException import io.rebble.libpebblecommon.exceptions.PacketEncodeException import io.rebble.libpebblecommon.util.DataBuffer +import io.rebble.libpebblecommon.util.Endian + /** * Represents anything mappable to a struct via a StructMapper */ -interface Mappable { +abstract class Mappable(val endianness: Endian = Endian.Unspecified) { /** * Serializes/packs the mappable to its raw equivalent * @return The serialized mappable */ - fun toBytes(): UByteArray + abstract fun toBytes(): UByteArray /** * Deserializes/unpacks raw data into the mappable * This will increment the seek position on the DataBuffer * @param bytes the data to read, seek position is incremented */ - fun fromBytes(bytes: DataBuffer) + abstract fun fromBytes(bytes: DataBuffer) /** * The projected size in bytes of the raw data returned by [toBytes] */ - val size: Int + abstract val size: Int } interface NumberStructElement { @@ -44,8 +46,9 @@ open class StructElement( mapper: StructMapper, size: Int, default: T, - endianness: Char = '|' -) : Mappable { //TODO: Element-level endianness on deserialization + endianness: Endian = Endian.Unspecified +) : Mappable(endianness) { + override var size = size get() { return linkedSize?.valueNumber?.toInt() ?: field @@ -59,7 +62,6 @@ open class StructElement( private val mapIndex = mapper.register(this) private var value: T = default - var isLittleEndian = endianness == '<' fun get(): T { return value @@ -74,20 +76,16 @@ open class StructElement( if (size < 0) throw PacketDecodeException("Invalid StructElement size: $size") else if (size == 0) return ubyteArrayOf() val buf = DataBuffer(size) - buf.setEndian(if (isLittleEndian) '<' else '>') + buf.setEndian(endianness) putType(buf, this) return buf.array() } override fun fromBytes(bytes: DataBuffer) { - bytes.setEndian(if (isLittleEndian) '<' else '>') + bytes.setEndian(endianness) getType(bytes, this) } - fun setEndiannes(endianness: Char) { - isLittleEndian = endianness == '<' - } - /** * Link the size of this element to the value of another struct element. Size will * automatically match value of the target element. @@ -98,7 +96,7 @@ open class StructElement( override fun toString(): String { return "StructElement(size=$size, linkedSize=${linkedSize?.valueNumber}, " + - "value=$value, isLittleEndian=$isLittleEndian)" + "value=$value)" } override fun equals(other: Any?): Boolean { @@ -141,7 +139,7 @@ class SByte(mapper: StructMapper, default: Byte = 0) : get() = get().toLong() } -class SUInt(mapper: StructMapper, default: UInt = 0u, endianness: Char = '|') : +class SUInt(mapper: StructMapper, default: UInt = 0u, endianness: Endian = Endian.Unspecified) : StructElement( { buf, el -> buf.putUInt(el.get()) }, { buf, el -> el.set(buf.getUInt()) }, @@ -154,7 +152,7 @@ class SUInt(mapper: StructMapper, default: UInt = 0u, endianness: Char = '|') : get() = get().toLong() } -class SInt(mapper: StructMapper, default: Int = 0, endianness: Char = '|') : +class SInt(mapper: StructMapper, default: Int = 0, endianness: Endian = Endian.Unspecified) : StructElement( { buf, el -> buf.putInt(el.get()) }, { buf, el -> el.set(buf.getInt()) }, @@ -179,7 +177,7 @@ class SULong(mapper: StructMapper, default: ULong = 0u) : get() = get().toLong() } -class SUShort(mapper: StructMapper, default: UShort = 0u, endianness: Char = '|') : +class SUShort(mapper: StructMapper, default: UShort = 0u, endianness: Endian = Endian.Unspecified) : StructElement( { buf, el -> buf.putUShort(el.get()) }, { buf, el -> el.set(buf.getUShort()) }, @@ -192,7 +190,7 @@ class SUShort(mapper: StructMapper, default: UShort = 0u, endianness: Char = '|' get() = get().toLong() } -class SShort(mapper: StructMapper, default: Short = 0, endianness: Char = '|') : +class SShort(mapper: StructMapper, default: Short = 0, endianness: Endian = Endian.Unspecified) : StructElement( { buf, el -> buf.putShort(el.get()) }, { buf, el -> el.set(buf.getShort()) }, @@ -295,7 +293,7 @@ class SBytes( mapper: StructMapper, length: Int = -1, default: UByteArray = ubyteArrayOf(), - endianness: Char = '|' + endianness: Endian = Endian.Unspecified ) : StructElement( { buf, el -> @@ -306,12 +304,12 @@ class SBytes( } else if (el.size != -1 && mValue.size < length) { mValue += UByteArray(length - el.size)// Pad if too short } - buf.putBytes(if (el.isLittleEndian) mValue.reversedArray() else mValue) + buf.putBytes(if (el.endianness == Endian.Little) mValue.reversedArray() else mValue) } }, { buf, el -> val value = buf.getBytes(el.size) - el.set(if (el.isLittleEndian) value.reversedArray() else value) + el.set(if (el.endianness == Endian.Little) value.reversedArray() else value) }, mapper, length, default, endianness ) { @@ -340,7 +338,7 @@ class SBytes( */ class SUnboundBytes( mapper: StructMapper, - endianness: Char = '|' + endianness: Endian = Endian.Unspecified ) : StructElement( { buf, el -> throw UnsupportedOperationException("SUnboundBytes is read-only") @@ -348,7 +346,7 @@ class SUnboundBytes( { buf, el -> val leftBytes = buf.length - buf.readPosition val value = buf.getBytes(leftBytes) - el.set(if (el.isLittleEndian) value.reversedArray() else value) + el.set(if (el.endianness == Endian.Little) value.reversedArray() else value) }, mapper, 0, ubyteArrayOf(), endianness ) { @@ -379,7 +377,7 @@ class SFixedList( default: List = emptyList(), private val itemFactory: () -> T ) : - Mappable { + Mappable(Endian.Unspecified) { var count = count set(value) { @@ -445,8 +443,9 @@ class SFixedList( class SOptional( mapper: StructMapper, val value: StructElement, - var present: Boolean -) : Mappable { + var present: Boolean, + endianness: Endian = Endian.Unspecified +) : Mappable(endianness) { init { mapper.register(this) } diff --git a/src/commonMain/kotlin/io/rebble/libpebblecommon/util/Crc32Calculator.kt b/src/commonMain/kotlin/io/rebble/libpebblecommon/util/Crc32Calculator.kt index cccf276..6559c30 100644 --- a/src/commonMain/kotlin/io/rebble/libpebblecommon/util/Crc32Calculator.kt +++ b/src/commonMain/kotlin/io/rebble/libpebblecommon/util/Crc32Calculator.kt @@ -16,7 +16,7 @@ class Crc32Calculator { val mergedArray = leftoverBytes + bytes val buffer = DataBuffer(mergedArray) - buffer.setEndian('<') + buffer.setEndian(Endian.Little) val finalPosition = mergedArray.size - mergedArray.size % 4 while (buffer.readPosition < finalPosition) { @@ -36,7 +36,7 @@ class Crc32Calculator { if (leftoverBytes.isNotEmpty()) { leftoverBytes = leftoverBytes.padZerosLeft(4 - leftoverBytes.size).reversedArray() - addInt(DataBuffer(leftoverBytes).apply { setEndian('<') }.getUInt()) + addInt(DataBuffer(leftoverBytes).apply { setEndian(Endian.Little) }.getUInt()) } finalized = true diff --git a/src/commonMain/kotlin/io/rebble/libpebblecommon/util/DataBuffer.kt b/src/commonMain/kotlin/io/rebble/libpebblecommon/util/DataBuffer.kt index d743064..07a026f 100644 --- a/src/commonMain/kotlin/io/rebble/libpebblecommon/util/DataBuffer.kt +++ b/src/commonMain/kotlin/io/rebble/libpebblecommon/util/DataBuffer.kt @@ -33,7 +33,7 @@ expect class DataBuffer { fun array(): UByteArray - fun setEndian(endian: Char) + fun setEndian(endian: Endian) fun rewind() diff --git a/src/commonMain/kotlin/io/rebble/libpebblecommon/util/Endian.kt b/src/commonMain/kotlin/io/rebble/libpebblecommon/util/Endian.kt new file mode 100644 index 0000000..1c0c5ed --- /dev/null +++ b/src/commonMain/kotlin/io/rebble/libpebblecommon/util/Endian.kt @@ -0,0 +1,7 @@ +package io.rebble.libpebblecommon.util + +enum class Endian { + Big, + Little, + Unspecified +} \ No newline at end of file diff --git a/src/commonMain/kotlin/io/rebble/libpebblecommon/util/TimelineAttributeFactory.kt b/src/commonMain/kotlin/io/rebble/libpebblecommon/util/TimelineAttributeFactory.kt index 10a3eab..1b09894 100644 --- a/src/commonMain/kotlin/io/rebble/libpebblecommon/util/TimelineAttributeFactory.kt +++ b/src/commonMain/kotlin/io/rebble/libpebblecommon/util/TimelineAttributeFactory.kt @@ -9,7 +9,7 @@ import io.rebble.libpebblecommon.structmapper.StructMapper import kotlin.math.round object TimelineAttributeFactory { - private fun createAttribute(attributeId: UByte, content: UByteArray, contentEndianness: Char = '|'): TimelineItem.Attribute { + private fun createAttribute(attributeId: UByte, content: UByteArray, contentEndianness: Endian = Endian.Unspecified): TimelineItem.Attribute { return TimelineItem.Attribute(attributeId, content, contentEndianness) } @@ -30,7 +30,7 @@ object TimelineAttributeFactory { } private fun createUIntAttribute(type: TimelineAttribute, value: UInt): TimelineItem.Attribute { - val content = SUInt(StructMapper(), value, '<').toBytes() + val content = SUInt(StructMapper(), value, Endian.Little).toBytes() return createAttribute(type.id, content) } diff --git a/src/commonTest/kotlin/io/rebble/libpebblecommon/packets/blobdb/AppTest.kt b/src/commonTest/kotlin/io/rebble/libpebblecommon/packets/blobdb/AppTest.kt new file mode 100644 index 0000000..6ef7ce3 --- /dev/null +++ b/src/commonTest/kotlin/io/rebble/libpebblecommon/packets/blobdb/AppTest.kt @@ -0,0 +1,16 @@ +package io.rebble.libpebblecommon.packets.blobdb + +import assertUByteArrayEquals +import io.rebble.libpebblecommon.util.DataBuffer +import kotlin.test.Test + +internal class AppTest { + @Test + fun `AppMetadata flags should be little endian`() { + val appMetadata = AppMetadata() + appMetadata.flags.set(0x00FFu) + val serialized = appMetadata.toBytes() + val bytes = ubyteArrayOf(serialized[16], serialized[17]) + assertUByteArrayEquals(ubyteArrayOf(0xFFu, 0x00u), bytes) + } +} \ No newline at end of file diff --git a/src/iosMain/kotlin/util/DataBuffer.kt b/src/iosMain/kotlin/util/DataBuffer.kt index 3e4d539..c626bb3 100644 --- a/src/iosMain/kotlin/util/DataBuffer.kt +++ b/src/iosMain/kotlin/util/DataBuffer.kt @@ -126,8 +126,8 @@ actual class DataBuffer { actual fun array(): UByteArray = getBytes(actualBuf.length.toInt()) - actual fun setEndian(endian: Char) { - littleEndian = endian == '<' + actual fun setEndian(endian: Endian) { + littleEndian = endian == Endian.Little } actual fun putUInt(uint: UInt) { diff --git a/src/jvmMain/kotlin/util/DataBuffer.kt b/src/jvmMain/kotlin/util/DataBuffer.kt index ee7aba0..ab8c455 100644 --- a/src/jvmMain/kotlin/util/DataBuffer.kt +++ b/src/jvmMain/kotlin/util/DataBuffer.kt @@ -63,10 +63,11 @@ actual class DataBuffer { actual fun array(): UByteArray = actualBuf.array().toUByteArray() - actual fun setEndian(endian: Char) { + actual fun setEndian(endian: Endian) { when (endian) { - '>' -> actualBuf.order(ByteOrder.BIG_ENDIAN) - '<' -> actualBuf.order(ByteOrder.LITTLE_ENDIAN) + Endian.Big -> actualBuf.order(ByteOrder.BIG_ENDIAN) + Endian.Little -> actualBuf.order(ByteOrder.LITTLE_ENDIAN) + Endian.Unspecified -> {actualBuf.order(ByteOrder.BIG_ENDIAN)} } }