Merge various proto utils together in core-util-jvm.
This commit is contained in:
parent
5b69d98579
commit
ec49352635
17 changed files with 122 additions and 136 deletions
|
@ -8,6 +8,7 @@ package org.thoughtcrime.securesms.backup.v2.database
|
|||
import android.database.Cursor
|
||||
import androidx.core.content.contentValuesOf
|
||||
import org.signal.core.util.SqlUtil
|
||||
import org.signal.core.util.decodeOrNull
|
||||
import org.signal.core.util.insertInto
|
||||
import org.signal.core.util.logging.Log
|
||||
import org.signal.core.util.requireBlob
|
||||
|
@ -30,7 +31,6 @@ import org.thoughtcrime.securesms.database.model.databaseprotos.ChatColor
|
|||
import org.thoughtcrime.securesms.database.model.databaseprotos.Wallpaper
|
||||
import org.thoughtcrime.securesms.mms.PartAuthority
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId
|
||||
import org.thoughtcrime.securesms.util.decodeOrNull
|
||||
import org.thoughtcrime.securesms.wallpaper.ChatWallpaper
|
||||
import org.thoughtcrime.securesms.wallpaper.ChatWallpaperFactory
|
||||
import org.thoughtcrime.securesms.wallpaper.UriChatWallpaper
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
|
||||
package org.thoughtcrime.securesms.database.model
|
||||
|
||||
import ProtoUtil.isNullOrEmpty
|
||||
import okio.ByteString
|
||||
import org.signal.core.util.StringUtil
|
||||
import org.signal.core.util.isNullOrEmpty
|
||||
import org.signal.storageservice.protos.groups.AccessControl
|
||||
import org.signal.storageservice.protos.groups.AccessControl.AccessRequired
|
||||
import org.signal.storageservice.protos.groups.Member
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package org.thoughtcrime.securesms.messages
|
||||
|
||||
import ProtoUtil.isNotEmpty
|
||||
import android.content.Context
|
||||
import android.text.TextUtils
|
||||
import com.mobilecoin.lib.exceptions.SerializationException
|
||||
|
@ -8,6 +7,7 @@ import okio.ByteString.Companion.toByteString
|
|||
import org.signal.core.util.Base64
|
||||
import org.signal.core.util.Hex
|
||||
import org.signal.core.util.concurrent.SignalExecutors
|
||||
import org.signal.core.util.isNotEmpty
|
||||
import org.signal.core.util.logging.Log
|
||||
import org.signal.core.util.orNull
|
||||
import org.signal.core.util.toOptional
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
package org.thoughtcrime.securesms.messages
|
||||
|
||||
import ProtoUtil.isNotEmpty
|
||||
import com.squareup.wire.Message
|
||||
import okio.ByteString
|
||||
import okio.ByteString.Companion.toByteString
|
||||
import org.signal.core.util.isNotEmpty
|
||||
import org.signal.core.util.orNull
|
||||
import org.signal.libsignal.protocol.message.DecryptionErrorMessage
|
||||
import org.signal.libsignal.zkgroup.groups.GroupMasterKey
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
package org.thoughtcrime.securesms.messages
|
||||
|
||||
import ProtoUtil.isNotEmpty
|
||||
import android.content.Context
|
||||
import com.mobilecoin.lib.exceptions.SerializationException
|
||||
import okio.ByteString
|
||||
import org.signal.core.util.Base64
|
||||
import org.signal.core.util.Hex
|
||||
import org.signal.core.util.isNotEmpty
|
||||
import org.signal.core.util.orNull
|
||||
import org.signal.libsignal.protocol.IdentityKey
|
||||
import org.signal.libsignal.protocol.InvalidKeyException
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
/*
|
||||
* Copyright 2024 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.thoughtcrime.securesms.util
|
||||
|
||||
import com.google.protobuf.InvalidProtocolBufferException
|
||||
import com.squareup.wire.ProtoAdapter
|
||||
|
||||
/**
|
||||
* Performs the common pattern of attempting to decode a serialized proto and returning null if it fails to decode.
|
||||
*/
|
||||
fun <E> ProtoAdapter<E>.decodeOrNull(serialized: ByteArray): E? {
|
||||
return try {
|
||||
this.decode(serialized)
|
||||
} catch (e: InvalidProtocolBufferException) {
|
||||
null
|
||||
}
|
||||
}
|
|
@ -10,6 +10,7 @@ plugins {
|
|||
id("java-library")
|
||||
id("org.jetbrains.kotlin.jvm")
|
||||
id("ktlint")
|
||||
id("com.squareup.wire")
|
||||
}
|
||||
|
||||
java {
|
||||
|
@ -23,6 +24,16 @@ kotlin {
|
|||
}
|
||||
}
|
||||
|
||||
wire {
|
||||
kotlin {
|
||||
javaInterop = true
|
||||
}
|
||||
|
||||
sourcePath {
|
||||
srcDir("src/main/protowire")
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(libs.kotlin.reflect)
|
||||
implementation(libs.kotlinx.coroutines.core)
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* Copyright 2024 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
@file:JvmName("ProtoUtil")
|
||||
|
||||
package org.signal.core.util
|
||||
|
||||
import com.squareup.wire.FieldEncoding
|
||||
import com.squareup.wire.Message
|
||||
import com.squareup.wire.ProtoAdapter
|
||||
import com.squareup.wire.ProtoReader
|
||||
import com.squareup.wire.ProtoWriter
|
||||
import okio.Buffer
|
||||
import okio.ByteString
|
||||
import org.signal.core.util.logging.Log
|
||||
import java.io.IOException
|
||||
import java.util.LinkedList
|
||||
|
||||
private const val TAG = "ProtoExtension"
|
||||
|
||||
fun ByteString?.isNotEmpty(): Boolean {
|
||||
return this != null && this.size > 0
|
||||
}
|
||||
|
||||
fun ByteString?.isNullOrEmpty(): Boolean {
|
||||
return this == null || this.size == 0
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the common pattern of attempting to decode a serialized proto and returning null if it fails to decode.
|
||||
*/
|
||||
fun <E> ProtoAdapter<E>.decodeOrNull(serialized: ByteArray): E? {
|
||||
return try {
|
||||
this.decode(serialized)
|
||||
} catch (e: IOException) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* True if there are unknown fields anywhere inside the proto or its nested protos.
|
||||
*/
|
||||
fun Message<*, *>.hasUnknownFields(): Boolean {
|
||||
val allProtos = this.getInnerProtos()
|
||||
allProtos.add(this)
|
||||
for (proto in allProtos) {
|
||||
val unknownFields = proto.unknownFields
|
||||
if (unknownFields.size > 0) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fun Message<*, *>.getUnknownEnumValue(tag: Int): Int {
|
||||
val reader = ProtoReader(Buffer().write(this.unknownFields))
|
||||
reader.forEachTag { unknownTag ->
|
||||
if (unknownTag == tag) {
|
||||
return ProtoAdapter.INT32.decode(reader)
|
||||
}
|
||||
}
|
||||
|
||||
throw AssertionError("Tag $tag not found in unknown fields")
|
||||
}
|
||||
|
||||
fun writeUnknownEnumValue(tag: Int, enumValue: Int): ByteString {
|
||||
val buffer = Buffer()
|
||||
val writer = ProtoWriter(buffer)
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
(FieldEncoding.VARINT.rawProtoAdapter() as ProtoAdapter<Any>).encodeWithTag(writer, tag, enumValue.toLong())
|
||||
|
||||
return buffer.readByteString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively retrieves all inner complex proto types inside a given proto.
|
||||
*/
|
||||
private fun Message<*, *>.getInnerProtos(): MutableList<Message<*, *>> {
|
||||
val innerProtos: MutableList<Message<*, *>> = LinkedList()
|
||||
try {
|
||||
val fields = this.javaClass.declaredFields
|
||||
for (field in fields) {
|
||||
if (Message::class.java.isAssignableFrom(field.type)) {
|
||||
field.isAccessible = true
|
||||
val inner = field[this] as? Message<*, *>
|
||||
if (inner != null) {
|
||||
innerProtos.add(inner)
|
||||
innerProtos.addAll(inner.getInnerProtos())
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e: IllegalAccessException) {
|
||||
Log.w(TAG, "Failed to get inner protos!", e)
|
||||
}
|
||||
return innerProtos
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
/*
|
||||
* Copyright 2023 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
@file:JvmName("ProtoUtil")
|
||||
|
||||
import okio.ByteString
|
||||
|
||||
object ProtoUtil {
|
||||
|
||||
fun ByteString?.isNotEmpty(): Boolean {
|
||||
return this != null && this.size > 0
|
||||
}
|
||||
|
||||
fun ByteString?.isNullOrEmpty(): Boolean {
|
||||
return this == null || this.size == 0
|
||||
}
|
||||
}
|
|
@ -1,11 +1,11 @@
|
|||
package org.whispersystems.signalservice.api.storage;
|
||||
|
||||
import org.signal.core.util.ProtoUtil;
|
||||
import org.signal.libsignal.protocol.logging.Log;
|
||||
import org.whispersystems.signalservice.api.payments.PaymentsConstants;
|
||||
import org.whispersystems.signalservice.api.push.ServiceId;
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
import org.whispersystems.signalservice.api.util.OptionalUtil;
|
||||
import org.whispersystems.signalservice.api.util.ProtoUtil;
|
||||
import org.whispersystems.signalservice.internal.storage.protos.AccountRecord;
|
||||
import org.whispersystems.signalservice.internal.storage.protos.OptionalBool;
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
package org.whispersystems.signalservice.api.storage;
|
||||
|
||||
import org.signal.core.util.ProtoUtil;
|
||||
import org.signal.libsignal.protocol.logging.Log;
|
||||
import org.whispersystems.signalservice.api.push.ServiceId;
|
||||
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
|
||||
import org.whispersystems.signalservice.api.push.ServiceId.PNI;
|
||||
import org.whispersystems.signalservice.api.util.OptionalUtil;
|
||||
import org.whispersystems.signalservice.api.util.ProtoUtil;
|
||||
import org.whispersystems.signalservice.internal.storage.protos.ContactRecord;
|
||||
import org.whispersystems.signalservice.internal.storage.protos.ContactRecord.IdentityState;
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package org.whispersystems.signalservice.api.storage;
|
||||
|
||||
import org.signal.core.util.ProtoUtil;
|
||||
import org.signal.libsignal.protocol.logging.Log;
|
||||
import org.whispersystems.signalservice.api.util.ProtoUtil;
|
||||
import org.whispersystems.signalservice.internal.storage.protos.GroupV1Record;
|
||||
|
||||
import java.io.IOException;
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
package org.whispersystems.signalservice.api.storage;
|
||||
|
||||
import org.signal.core.util.ProtoUtil;
|
||||
import org.signal.libsignal.protocol.logging.Log;
|
||||
import org.signal.libsignal.zkgroup.InvalidInputException;
|
||||
import org.signal.libsignal.zkgroup.groups.GroupMasterKey;
|
||||
import org.whispersystems.signalservice.api.util.ProtoUtil;
|
||||
import org.whispersystems.signalservice.internal.storage.protos.GroupV2Record;
|
||||
|
||||
import java.io.IOException;
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package org.whispersystems.signalservice.api.storage;
|
||||
|
||||
import org.whispersystems.signalservice.api.messages.multidevice.MessageRequestResponseMessage;
|
||||
import org.whispersystems.signalservice.api.util.ProtoUtil;
|
||||
import org.signal.core.util.ProtoUtil;
|
||||
import org.whispersystems.signalservice.internal.storage.protos.ManifestRecord;
|
||||
import org.whispersystems.signalservice.internal.storage.protos.StorageManifest;
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
package org.whispersystems.signalservice.api.storage;
|
||||
|
||||
import org.signal.core.util.ProtoUtil;
|
||||
import org.signal.libsignal.protocol.InvalidKeyException;
|
||||
import org.signal.libsignal.protocol.logging.Log;
|
||||
import org.signal.libsignal.zkgroup.groups.GroupMasterKey;
|
||||
import org.whispersystems.signalservice.api.util.ProtoUtil;
|
||||
import org.whispersystems.signalservice.internal.storage.protos.ManifestRecord;
|
||||
import org.whispersystems.signalservice.internal.storage.protos.StorageItem;
|
||||
import org.whispersystems.signalservice.internal.storage.protos.StorageManifest;
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
package org.whispersystems.signalservice.api.storage;
|
||||
|
||||
import org.signal.core.util.ProtoUtil;
|
||||
import org.signal.libsignal.protocol.logging.Log;
|
||||
import org.whispersystems.signalservice.api.push.ServiceId;
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
import org.whispersystems.signalservice.api.util.ProtoUtil;
|
||||
import org.whispersystems.signalservice.internal.storage.protos.StoryDistributionListRecord;
|
||||
|
||||
import java.io.IOException;
|
||||
|
|
|
@ -1,84 +0,0 @@
|
|||
/*
|
||||
* Copyright 2023 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
@file:JvmName("ProtoUtil")
|
||||
|
||||
package org.whispersystems.signalservice.api.util
|
||||
|
||||
import com.squareup.wire.FieldEncoding
|
||||
import com.squareup.wire.Message
|
||||
import com.squareup.wire.ProtoAdapter
|
||||
import com.squareup.wire.ProtoReader
|
||||
import com.squareup.wire.ProtoWriter
|
||||
import okio.Buffer
|
||||
import okio.ByteString
|
||||
import org.signal.libsignal.protocol.logging.Log
|
||||
import java.util.LinkedList
|
||||
|
||||
object ProtoUtil {
|
||||
private val TAG = ProtoUtil::class.java.simpleName
|
||||
|
||||
/**
|
||||
* True if there are unknown fields anywhere inside the proto or its nested protos.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun hasUnknownFields(rootProto: Message<*, *>): Boolean {
|
||||
val allProtos = getInnerProtos(rootProto)
|
||||
allProtos.add(rootProto)
|
||||
for (proto in allProtos) {
|
||||
val unknownFields = proto.unknownFields
|
||||
if (unknownFields.size > 0) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getUnknownEnumValue(proto: Message<*, *>, tag: Int): Int {
|
||||
val reader = ProtoReader(Buffer().write(proto.unknownFields))
|
||||
reader.forEachTag { unknownTag ->
|
||||
if (unknownTag == tag) {
|
||||
return ProtoAdapter.INT32.decode(reader)
|
||||
}
|
||||
}
|
||||
|
||||
throw AssertionError("Tag $tag not found in unknown fields")
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun writeUnknownEnumValue(tag: Int, enumValue: Int): ByteString {
|
||||
val buffer = Buffer()
|
||||
val writer = ProtoWriter(buffer)
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
(FieldEncoding.VARINT.rawProtoAdapter() as ProtoAdapter<Any>).encodeWithTag(writer, tag, enumValue.toLong())
|
||||
|
||||
return buffer.readByteString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively retrieves all inner complex proto types inside a given proto.
|
||||
*/
|
||||
private fun getInnerProtos(proto: Message<*, *>): MutableList<Message<*, *>> {
|
||||
val innerProtos: MutableList<Message<*, *>> = LinkedList()
|
||||
try {
|
||||
val fields = proto.javaClass.declaredFields
|
||||
for (field in fields) {
|
||||
if (Message::class.java.isAssignableFrom(field.type)) {
|
||||
field.isAccessible = true
|
||||
val inner = field[proto] as? Message<*, *>
|
||||
if (inner != null) {
|
||||
innerProtos.add(inner)
|
||||
innerProtos.addAll(getInnerProtos(inner))
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e: IllegalAccessException) {
|
||||
Log.w(TAG, "Failed to get inner protos!", e)
|
||||
}
|
||||
return innerProtos
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue