Skip to content
Snippets Groups Projects
Verified Commit cb0a2970 authored by Janne Mareike Koschinski's avatar Janne Mareike Koschinski
Browse files

Early experiments with improved Qt/Quassel type serialization

parent 24bd964e
No related branches found
No related tags found
1 merge request!2Draft: Jetpack compose rewrite
Pipeline #569 failed
Showing
with 614 additions and 49 deletions
/*
* Quasseldroid - Quassel client for Android
*
* Copyright (c) 2021 Janne Mareike Koschinski
* Copyright (c) 2021 The Quassel Project
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3 as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.kuschku.quasseldroid.protocol
inline class ExtendedFeatureName(
val name: String,
)
enum class ExtendedFeature {
SynchronizedMarkerLine,
SaslAuthentication,
SaslExternal,
HideInactiveNetworks,
PasswordChange,
/** IRCv3 capability negotiation, account tracking */
CapNegotiation,
/** IRC server SSL validation */
VerifyServerSSL,
/** IRC server custom message rate limits */
CustomRateLimits,
// Currently not supported
DccFileTransfer,
/** Timestamp formatting in away (e.g. %%hh:mm%%) */
AwayFormatTimestamp,
/** Whether or not the core supports auth backends. */
Authenticators,
/** Sync buffer activity status */
BufferActivitySync,
/** Core-Side highlight configuration and matching */
CoreSideHighlights,
/** Show prefixes for senders in backlog */
SenderPrefixes,
/** Supports RPC call disconnectFromCore to remotely disconnect a client */
RemoteDisconnect,
/** Transmit features as list of strings */
ExtendedFeatures,
/** Serialize message time as 64-bit */
LongTime,
/** Real Name and Avatar URL in backlog */
RichMessages,
/** Backlogmanager supports filtering backlog by messagetype */
BacklogFilterType,
/** ECDSA keys for CertFP in identities */
EcdsaCertfpKeys,
/** 64-bit IDs for messages */
LongMessageId,
/** CoreInfo dynamically updated using signals */
SyncedCoreInfo;
fun name(): ExtendedFeatureName = ExtendedFeatureName(name)
}
/*
* Quasseldroid - Quassel client for Android
*
* Copyright (c) 2021 Janne Mareike Koschinski
* Copyright (c) 2021 The Quassel Project
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3 as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.kuschku.quasseldroid.protocol
import kotlin.experimental.or
interface Flag<T> {
val value: T
}
@JvmName("toByteFlag")
fun Set<Flag<Byte>>.toFlag(): Byte = fold(0.toByte()) { acc, el ->
acc or el.value
}
@JvmName("toUByteFlag")
fun Set<Flag<UByte>>.toFlag(): UByte = fold(0.toUByte()) { acc, el ->
acc or el.value
}
@JvmName("toShortFlag")
fun Set<Flag<Short>>.toFlag(): Short = fold(0.toShort()) { acc, el ->
acc or el.value
}
@JvmName("toUShortFlag")
fun Set<Flag<UShort>>.toFlag(): UShort = fold(0.toUShort()) { acc, el ->
acc or el.value
}
@JvmName("toIntFlag")
fun Set<Flag<Int>>.toFlag(): Int = fold(0) { acc, el ->
acc or el.value
}
@JvmName("toUIntFlag")
fun Set<Flag<UInt>>.toFlag(): UInt = fold(0.toUInt()) { acc, el ->
acc or el.value
}
@JvmName("toLongFlag")
fun Set<Flag<Long>>.toFlag(): Long = fold(0.toLong()) { acc, el ->
acc or el.value
}
@JvmName("toULongFlag")
fun Set<Flag<ULong>>.toFlag(): ULong = fold(0.toULong()) { acc, el ->
acc or el.value
}
/*
* Quasseldroid - Quassel client for Android
*
* Copyright (c) 2021 Janne Mareike Koschinski
* Copyright (c) 2021 The Quassel Project
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3 as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.kuschku.quasseldroid.protocol
/**
* A list of features that are optional in core and/or client, but need runtime checking
*
* Some features require an uptodate counterpart, but don't justify a protocol break.
* This is what we use this enum for. Add such features to it and check at runtime on the other
* side for their existence.
*
* This list should be cleaned up after every protocol break, as we can assume them to be present then.
*/
enum class LegacyFeature(override val value: UInt): Flag<UInt> {
SynchronizedMarkerLine(0x0001u),
SaslAuthentication(0x0002u),
SaslExternal(0x0004u),
HideInactiveNetworks(0x0008u),
PasswordChange(0x0010u),
/** IRCv3 capability negotiation, account tracking */
CapNegotiation(0x0020u),
/** IRC server SSL validation */
VerifyServerSSL(0x0040u),
/** IRC server custom message rate limits */
CustomRateLimits(0x0080u),
DccFileTransfer(0x0100u),
/** Timestamp formatting in away (e.g. %%hh:mm%%) */
AwayFormatTimestamp(0x0200u),
/** Whether or not the core supports auth backends. */
Authenticators(0x0400u),
/** Sync buffer activity status */
BufferActivitySync(0x0800u),
/** Core-Side highlight configuration and matching */
CoreSideHighlights(0x1000u),
/** Show prefixes for senders in backlog */
SenderPrefixes(0x2000u),
/** Supports RPC call disconnectFromCore to remotely disconnect a client */
RemoteDisconnect(0x4000u),
/** Transmit features as list of strings */
ExtendedFeatures(0x8000u);
}
/*
* Quasseldroid - Quassel client for Android
*
* Copyright (c) 2021 Janne Mareike Koschinski
* Copyright (c) 2021 The Quassel Project
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3 as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.kuschku.quasseldroid.protocol.handshake
import de.kuschku.quasseldroid.protocol.ExtendedFeature
import de.kuschku.quasseldroid.protocol.LegacyFeature
import de.kuschku.quasseldroid.protocol.serializers.QtSerializer
class ClientInit(
val clientVersion: String?,
val buildDate: String?,
val clientFeatures: Set<LegacyFeature>?,
val featureList: List<ExtendedFeature>?,
)
......@@ -17,14 +17,9 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.kuschku.quasseldroid.protocol
package de.kuschku.quasseldroid.protocol.io
import de.kuschku.quasseldroid.util.CoroutineChannel
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.yield
import java.nio.ByteBuffer
import java.nio.channels.AsynchronousByteChannel
import java.nio.channels.WritableByteChannel
import java.util.*
class ChainedByteBuffer(private val bufferSize: Int = 1024, private val direct: Boolean = false) {
......@@ -53,6 +48,11 @@ class ChainedByteBuffer(private val bufferSize: Int = 1024, private val direct:
this.size += size
}
fun nextBuffer(length: Int = 1): ByteBuffer {
ensureSpace(length)
return bufferList.last()
}
fun put(value: Byte) {
ensureSpace(1)
......@@ -96,11 +96,18 @@ class ChainedByteBuffer(private val bufferSize: Int = 1024, private val direct:
}
fun put(value: ByteBuffer) {
while (value.remaining() > 8) {
putLong(value.long)
ensureSpace(value.remaining())
while (value.remaining() > 0) {
val buffer = bufferList.last()
if (buffer.remaining() >= value.remaining()) {
buffer.put(value)
} else {
val oldLimit = value.limit()
value.limit(value.position() + buffer.remaining())
buffer.put(value)
value.limit(oldLimit)
}
while (value.hasRemaining()) {
put(value.get())
}
}
......
......@@ -17,23 +17,47 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.kuschku.quasseldroid.util
package de.kuschku.quasseldroid.protocol.io
import de.kuschku.quasseldroid.protocol.ChainedByteBuffer
import de.kuschku.quasseldroid.util.TlsInfo
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.asCoroutineDispatcher
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.runInterruptible
import java.net.InetSocketAddress
import java.net.Socket
import java.nio.ByteBuffer
import java.util.concurrent.Executors
import javax.net.ssl.SSLContext
class CoroutineChannel {
private lateinit var channel: StreamChannel
private val writeContext = Executors.newSingleThreadExecutor().asCoroutineDispatcher()
private val readContext = Executors.newSingleThreadExecutor().asCoroutineDispatcher()
private val _tlsInfo = MutableStateFlow<TlsInfo?>(null)
val tlsInfo: StateFlow<TlsInfo?> get() = _tlsInfo
suspend fun connect(address: InetSocketAddress) = runInterruptible(writeContext) {
this.channel = StreamChannel(Socket(address.address, address.port))
suspend fun connect(
address: InetSocketAddress,
timeout: Int = 0,
keepAlive: Boolean = false,
) = runInterruptible(Dispatchers.IO) {
val socket = Socket()
socket.keepAlive = keepAlive
socket.connect(address, timeout)
this.channel = StreamChannel(socket)
}
fun enableCompression() {
channel = channel.withCompression()
}
suspend fun enableTLS(context: SSLContext) {
channel = runInterruptible(writeContext) {
channel.withTLS(context)
}
_tlsInfo.emit(channel.tlsInfo())
}
suspend fun read(buffer: ByteBuffer): Int = runInterruptible(readContext) {
......
/*
* Quasseldroid - Quassel client for Android
*
* Copyright (c) 2021 Janne Mareike Koschinski
* Copyright (c) 2021 The Quassel Project
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3 as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.kuschku.quasseldroid.protocol.io
import java.io.OutputStream
import java.util.zip.DeflaterOutputStream
class FixedDeflaterOutputStream(
stream: OutputStream
) : DeflaterOutputStream(stream, true) {
override fun close() {
try {
super.close()
} finally {
def.end()
}
}
}
......@@ -17,7 +17,7 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.kuschku.quasseldroid.util
package de.kuschku.quasseldroid.protocol.io
import android.util.Log
import java.io.InputStream
......
......@@ -17,8 +17,9 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.kuschku.quasseldroid.util
package de.kuschku.quasseldroid.protocol.io
import de.kuschku.quasseldroid.util.TlsInfo
import java.io.Flushable
import java.io.InputStream
import java.io.OutputStream
......@@ -26,8 +27,9 @@ import java.net.Socket
import java.nio.ByteBuffer
import java.nio.channels.ByteChannel
import java.nio.channels.InterruptibleChannel
import java.util.zip.DeflaterOutputStream
import java.util.zip.InflaterInputStream
import javax.net.ssl.SSLContext
import javax.net.ssl.SSLSocket
class StreamChannel constructor(
private val socket: Socket,
......@@ -37,14 +39,33 @@ class StreamChannel constructor(
private val input = ReadableWrappedChannel(inputStream)
private val output = WritableWrappedChannel(outputStream)
fun tlsInfo(): TlsInfo? {
val sslSocket = socket as? SSLSocket ?: return null
return TlsInfo.ofSession(sslSocket.session)
}
fun withCompression(): StreamChannel {
return StreamChannel(
socket,
InflaterInputStream(inputStream),
DeflaterOutputStream(outputStream),
FixedDeflaterOutputStream(outputStream),
)
}
fun withTLS(
context: SSLContext,
): StreamChannel {
val sslSocket = context.socketFactory.createSocket(
this.socket,
this.socket.inetAddress.hostAddress,
this.socket.port,
true
) as SSLSocket
sslSocket.useClientMode = true
sslSocket.startHandshake()
return StreamChannel(sslSocket)
}
override fun close() {
input.close()
output.close()
......
/*
* Quasseldroid 1 Quassel client for Android
*
* Copyright (c) 2021 Janne Mareike Koschinski
* Copyright (c) 2021 The Quassel Project
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3 as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.kuschku.quasseldroid.protocol.io
import java.nio.ByteBuffer
import java.nio.CharBuffer
import java.nio.charset.Charset
import java.nio.charset.CoderResult
class StringEncoder(charset: Charset) {
private val encoder = charset.newEncoder()
private val decoder = charset.newDecoder()
private val charBuffer = CharBuffer.allocate(1024)
private fun charBuffer(length: Int): CharBuffer =
if (length < 1024) charBuffer
else CharBuffer.allocate(length)
private fun encodingLength(length: Int, nullLimited: Boolean) =
if (nullLimited) length + 1
else length
private fun decodingLength(length: Int, nullLimited: Boolean) =
if (nullLimited) length - 1
else length
fun encode(data: String?, target: ChainedByteBuffer, nullLimited: Boolean = false) {
if (data == null) return
val charBuffer = charBuffer(encodingLength(data.length, nullLimited))
charBuffer.put(data)
if (nullLimited) charBuffer.put(0.toChar())
charBuffer.flip()
encoder.reset()
var result: CoderResult
do {
result = encoder.encode(charBuffer, target.nextBuffer(data.length), true)
} while (result == CoderResult.OVERFLOW)
}
fun encode(data: String?, nullLimited: Boolean = false): ByteBuffer {
if (data == null) return ByteBuffer.allocate(0)
val charBuffer = charBuffer(encodingLength(data.length, nullLimited))
charBuffer.put(data)
if (nullLimited) charBuffer.put(0.toChar())
charBuffer.flip()
encoder.reset()
return encoder.encode(charBuffer)
}
fun decode(source: ByteBuffer, length: Int, nullLimited: Boolean = false): String {
val charBuffer = charBuffer(decodingLength(length, nullLimited))
val oldlimit = source.limit()
source.limit(decodingLength(source.position() + length, nullLimited))
decoder.reset()
decoder.decode(source, charBuffer, true)
source.limit(oldlimit)
charBuffer.flip()
return charBuffer.toString()
}
fun decode(source: ByteBuffer, nullLimited: Boolean = false): String {
val charBuffer = charBuffer(decodingLength(source.remaining(), nullLimited))
source.limit(decodingLength(source.capacity(), nullLimited))
decoder.reset()
decoder.decode(source, charBuffer, true)
charBuffer.flip()
return charBuffer.toString()
}
}
/*
* Quasseldroid - Quassel client for Android
*
* Copyright (c) 2021 Janne Mareike Koschinski
* Copyright (c) 2021 The Quassel Project
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3 as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.kuschku.quasseldroid.protocol.io
import kotlin.concurrent.getOrSet
private val ascii = ThreadLocal<StringEncoder>()
private val utf8 = ThreadLocal<StringEncoder>()
private val utf16 = ThreadLocal<StringEncoder>()
fun stringEncoderAscii() = ascii.getOrSet { StringEncoder(Charsets.ISO_8859_1) }
fun stringEncoderUtf8() = utf8.getOrSet { StringEncoder(Charsets.UTF_8) }
fun stringEncoderUtf16() = utf16.getOrSet { StringEncoder(Charsets.UTF_16BE) }
......@@ -17,7 +17,7 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.kuschku.quasseldroid.util
package de.kuschku.quasseldroid.protocol.io
import java.io.OutputStream
import java.nio.ByteBuffer
......
/*
* Quasseldroid - Quassel client for Android
*
* Copyright (c) 2021 Janne Mareike Koschinski
* Copyright (c) 2021 The Quassel Project
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3 as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.kuschku.quasseldroid.protocol.serializers
import de.kuschku.quasseldroid.protocol.variant.QtType
import de.kuschku.quasseldroid.protocol.variant.QuasselType
class NoSerializerForTypeException(
private val javaType: Class<*>?,
private val qtType: Int,
private val quasselType: String?,
) : Exception() {
constructor(quasselType: QuasselType, javaType: Class<*>? = null) :
this(javaType, quasselType.qtType.id, quasselType.typeName)
constructor(qtType: QtType, javaType: Class<*>? = null) :
this(javaType, qtType.id, null)
constructor(qtType: Int, quasselType: String?) :
this(null, qtType, quasselType)
override fun toString(): String {
return "NoSerializerForTypeException(javaType=$javaType, qtType=${QtType.of(qtType) ?: qtType}, quasselType=${QuasselType.of(quasselType) ?: quasselType})"
}
}
......@@ -17,11 +17,15 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.kuschku.quasseldroid.protocol
package de.kuschku.quasseldroid.protocol.serializers
import de.kuschku.quasseldroid.protocol.io.ChainedByteBuffer
import de.kuschku.quasseldroid.protocol.variant.QtType
import java.nio.ByteBuffer
interface Serializer<T> {
interface QtSerializer<T> {
val qtType: QtType
val javaType: Class<out T>
fun serialize(buffer: ChainedByteBuffer, data: T)
fun deserialize(buffer: ByteBuffer): T
}
/*
* Quasseldroid - Quassel client for Android
*
* Copyright (c) 2021 Janne Mareike Koschinski
* Copyright (c) 2021 The Quassel Project
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3 as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.kuschku.quasseldroid.protocol.serializers
import de.kuschku.quasseldroid.protocol.variant.QtType
import de.kuschku.quasseldroid.protocol.variant.QuasselType
interface QuasselSerializer<T> : QtSerializer<T> {
override val qtType: QtType get() = quasselType.qtType
val quasselType: QuasselType
}
/*
* Quasseldroid - Quassel client for Android
*
* Copyright (c) 2021 Janne Mareike Koschinski
* Copyright (c) 2021 The Quassel Project
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3 as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.kuschku.quasseldroid.protocol.serializers
import de.kuschku.quasseldroid.protocol.serializers.primitive.*
import de.kuschku.quasseldroid.protocol.variant.QtType
import de.kuschku.quasseldroid.protocol.variant.QuasselType
import java.util.*
object Serializers {
private val qtSerializers = listOf<QtSerializer<*>>(
BoolSerializer,
ByteSerializer,
IntSerializer,
LongSerializer,
ShortSerializer,
UByteSerializer,
UIntSerializer,
ULongSerializer,
UShortSerializer,
StringSerializerUtf16,
VariantSerializer,
VariantMapSerializer,
).associateBy(QtSerializer<*>::qtType)
private val quasselSerializers = listOf<QuasselSerializer<*>>(
).associateBy(QuasselSerializer<*>::quasselType)
operator fun get(type: QtType) = qtSerializers[type]
operator fun get(type: QuasselType) = quasselSerializers[type]
}
@Suppress("UNCHECKED_CAST")
inline fun <reified T> serializerFor(type: QtType): QtSerializer<T> {
val serializer = Serializers[type]
?: throw NoSerializerForTypeException(type, T::class.java)
if (serializer.javaType == T::class.java) {
return serializer as QtSerializer<T>
} else {
throw NoSerializerForTypeException(type, T::class.java)
}
}
@Suppress("UNCHECKED_CAST")
inline fun <reified T> serializerFor(type: QuasselType): QuasselSerializer<T> {
val serializer = Serializers[type]
?: throw NoSerializerForTypeException(type, T::class.java)
if (serializer.javaType == T::class.java) {
return serializer as QuasselSerializer<T>
} else {
throw NoSerializerForTypeException(type, T::class.java)
}
}
......@@ -17,11 +17,17 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.kuschku.quasseldroid.protocol
package de.kuschku.quasseldroid.protocol.serializers.primitive
import de.kuschku.quasseldroid.protocol.io.ChainedByteBuffer
import de.kuschku.quasseldroid.protocol.serializers.QtSerializer
import de.kuschku.quasseldroid.protocol.variant.QtType
import java.nio.ByteBuffer
object BoolSerializer : Serializer<Boolean> {
object BoolSerializer : QtSerializer<Boolean> {
override val qtType: QtType = QtType.Bool
override val javaType: Class<Boolean> = Boolean::class.java
override fun serialize(buffer: ChainedByteBuffer, data: Boolean) {
buffer.put(
if (data) 0x01.toByte()
......
......@@ -17,13 +17,19 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.kuschku.quasseldroid.protocol
package de.kuschku.quasseldroid.protocol.serializers.primitive
import de.kuschku.quasseldroid.protocol.io.ChainedByteBuffer
import de.kuschku.quasseldroid.protocol.serializers.QtSerializer
import de.kuschku.quasseldroid.protocol.variant.QtType
import java.nio.ByteBuffer
object ByteSerializer : Serializer<Byte> {
object ByteSerializer : QtSerializer<Byte> {
override val qtType: QtType = QtType.Char
override val javaType: Class<Byte> = Byte::class.java
override fun serialize(buffer: ChainedByteBuffer, data: Byte) {
buffer.put(data)
buffer.put(data ?: 0)
}
override fun deserialize(buffer: ByteBuffer): Byte {
......
......@@ -17,13 +17,19 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.kuschku.quasseldroid.protocol
package de.kuschku.quasseldroid.protocol.serializers.primitive
import de.kuschku.quasseldroid.protocol.io.ChainedByteBuffer
import de.kuschku.quasseldroid.protocol.serializers.QtSerializer
import de.kuschku.quasseldroid.protocol.variant.QtType
import java.nio.ByteBuffer
object IntSerializer : Serializer<Int> {
object IntSerializer : QtSerializer<Int> {
override val qtType: QtType = QtType.Int
override val javaType: Class<Int> = Int::class.java
override fun serialize(buffer: ChainedByteBuffer, data: Int) {
buffer.putInt(data)
buffer.putInt(data ?: 0)
}
override fun deserialize(buffer: ByteBuffer): Int {
......
......@@ -17,13 +17,19 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.kuschku.quasseldroid.protocol
package de.kuschku.quasseldroid.protocol.serializers.primitive
import de.kuschku.quasseldroid.protocol.io.ChainedByteBuffer
import de.kuschku.quasseldroid.protocol.serializers.QtSerializer
import de.kuschku.quasseldroid.protocol.variant.QtType
import java.nio.ByteBuffer
object LongSerializer : Serializer<Long> {
object LongSerializer : QtSerializer<Long> {
override val qtType: QtType = QtType.Long
override val javaType: Class<Long> = Long::class.java
override fun serialize(buffer: ChainedByteBuffer, data: Long) {
buffer.putLong(data)
buffer.putLong(data?: 0)
}
override fun deserialize(buffer: ByteBuffer): Long {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment