From c4493a23d584969f61f4c77e87a75158ac11a13c Mon Sep 17 00:00:00 2001 From: Evgeny Margolis Date: Thu, 18 May 2023 03:17:05 -1000 Subject: [PATCH] Kotlin TLV Implementation: Removed Dependency on Protobuf (#26641) Instead of protobuf.ByteString using ByteArray to implement Octate String TLV type. --- .../clusterclient/WildcardFragment.kt | 5 +-- src/controller/java/BUILD.gn | 2 - .../java/src/chip/jsontlv/JsonToTlv.kt | 5 +-- .../java/src/chip/jsontlv/TlvToJson.kt | 5 +-- src/controller/java/src/chip/tlv/TlvReader.kt | 5 +-- src/controller/java/src/chip/tlv/TlvWriter.kt | 7 ++-- src/controller/java/src/chip/tlv/tags.kt | 2 +- src/controller/java/src/chip/tlv/types.kt | 2 +- src/controller/java/src/chip/tlv/utils.kt | 2 +- src/controller/java/src/chip/tlv/values.kt | 12 +++--- .../tests/chip/jsontlv/JsonToTlvToJsonTest.kt | 37 +++++++++---------- .../java/tests/chip/tlv/TlvReadWriteTest.kt | 11 +++--- .../java/tests/chip/tlv/TlvReaderTest.kt | 18 +++++---- .../java/tests/chip/tlv/TlvWriterTest.kt | 10 +++-- 14 files changed, 57 insertions(+), 66 deletions(-) diff --git a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/WildcardFragment.kt b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/WildcardFragment.kt index 4ceb3d2164147b..cff6d0f81cff66 100644 --- a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/WildcardFragment.kt +++ b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/WildcardFragment.kt @@ -576,10 +576,9 @@ class WildcardFragment : Fragment() { }, "ByteArray(Hex)" to object:TlvWriterInterface { override fun generate(writer : TlvWriter, value: String, tag: chip.tlv.Tag) { - val byteStringValue = ByteString.fromHex(value) - writer.put(tag, byteStringValue) + writer.put(tag, value.chunked(2).map { it.toInt(16) and 0xFF }.map { it.toByte() }.toByteArray()) } }, ) } -} \ No newline at end of file +} diff --git a/src/controller/java/BUILD.gn b/src/controller/java/BUILD.gn index f4d65b32a55e8c..1f911dd0bd61cb 100644 --- a/src/controller/java/BUILD.gn +++ b/src/controller/java/BUILD.gn @@ -146,8 +146,6 @@ if (chip_link_tests) { kotlin_library("tlv") { output_name = "libCHIPTlv.jar" - deps = [ "${chip_root}/third_party/java_deps:protobuf-java" ] - sources = [ "src/chip/tlv/Element.kt", "src/chip/tlv/TlvReader.kt", diff --git a/src/controller/java/src/chip/jsontlv/JsonToTlv.kt b/src/controller/java/src/chip/jsontlv/JsonToTlv.kt index 0cc592a29a4608..80909d4d5f999f 100644 --- a/src/controller/java/src/chip/jsontlv/JsonToTlv.kt +++ b/src/controller/java/src/chip/jsontlv/JsonToTlv.kt @@ -22,7 +22,6 @@ import com.google.gson.JsonArray import com.google.gson.JsonElement import com.google.gson.JsonObject import com.google.gson.JsonParser -import com.google.protobuf.ByteString import java.util.Base64 import chip.tlv.* @@ -150,8 +149,8 @@ private fun extractTagAndTypeFromJsonKey(key: String): Triple json.addProperty(key, value.value) - is ByteStringValue -> - json.addProperty(key, Base64.getEncoder().encodeToString(value.value.toByteArray())) + is ByteStringValue -> json.addProperty(key, Base64.getEncoder().encodeToString(value.value)) is BooleanValue -> json.addProperty(key, value.value) is FloatValue -> json.addProperty(key, validateFloat(value.value)) is DoubleValue -> json.addProperty(key, validateDouble(value.value)) @@ -144,7 +143,7 @@ private fun TlvReader.getArrayJsonWithElementsType(): Pair { } } is Utf8StringValue -> json.add(value.value) - is ByteStringValue -> json.add(Base64.getEncoder().encodeToString(value.value.toByteArray())) + is ByteStringValue -> json.add(Base64.getEncoder().encodeToString(value.value)) is BooleanValue -> json.add(value.value) is FloatValue -> json.add(validateFloat(value.value)) is DoubleValue -> json.add(validateDouble(value.value)) diff --git a/src/controller/java/src/chip/tlv/TlvReader.kt b/src/controller/java/src/chip/tlv/TlvReader.kt index cf23f3f2719d94..489d4444370d5e 100644 --- a/src/controller/java/src/chip/tlv/TlvReader.kt +++ b/src/controller/java/src/chip/tlv/TlvReader.kt @@ -18,7 +18,6 @@ package chip.tlv -import com.google.protobuf.ByteString import java.lang.Double.longBitsToDouble import java.lang.Float.intBitsToFloat @@ -87,7 +86,7 @@ class TlvReader(bytes: ByteArray) : Iterable { is SignedIntType -> IntValue(valueBytes.fromLittleEndianToLong(isSigned = true)) is UnsignedIntType -> UnsignedIntValue(valueBytes.fromLittleEndianToLong()) is Utf8StringType -> Utf8StringValue(String(valueBytes, Charsets.UTF_8)) - is ByteStringType -> ByteStringValue(ByteString.copyFrom(valueBytes)) + is ByteStringType -> ByteStringValue(valueBytes) is BooleanType -> BooleanValue(elementType.value) is FloatType -> FloatValue(intBitsToFloat(valueBytes.fromLittleEndianToLong().toInt())) is DoubleType -> DoubleValue(longBitsToDouble(valueBytes.fromLittleEndianToLong())) @@ -248,7 +247,7 @@ class TlvReader(bytes: ByteArray) : Iterable { * * @throws TlvParsingException if the element is not of the expected type or tag */ - fun getByteString(tag: Tag): ByteString { + fun getByteString(tag: Tag): ByteArray { val value = nextElement().verifyTagAndGetValue(tag) require(value is ByteStringValue) { "Unexpected value $value at index $index (expected ByteStringValue)" diff --git a/src/controller/java/src/chip/tlv/TlvWriter.kt b/src/controller/java/src/chip/tlv/TlvWriter.kt index 1cf2a295653df3..0b81960212f196 100644 --- a/src/controller/java/src/chip/tlv/TlvWriter.kt +++ b/src/controller/java/src/chip/tlv/TlvWriter.kt @@ -15,10 +15,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - + package chip.tlv -import com.google.protobuf.ByteString import java.io.ByteArrayOutputStream /** @@ -224,7 +223,7 @@ class TlvWriter(initialCapacity: Int = 32) { * * @throws TlvEncodingException if the data was invalid */ - fun put(tag: Tag, value: ByteString): TlvWriter { + fun put(tag: Tag, value: ByteArray): TlvWriter { return put(Element(tag, ByteStringValue(value))) } @@ -261,7 +260,7 @@ class TlvWriter(initialCapacity: Int = 32) { * * @throws TlvEncodingException if the data was invalid */ - fun putByteStringArray(tag: Tag, array: List): TlvWriter { + fun putByteStringArray(tag: Tag, array: List): TlvWriter { startArray(tag) array.forEach { put(AnonymousTag, it) } return endArray() diff --git a/src/controller/java/src/chip/tlv/tags.kt b/src/controller/java/src/chip/tlv/tags.kt index bd6128b1baf913..527fd8537e1a43 100644 --- a/src/controller/java/src/chip/tlv/tags.kt +++ b/src/controller/java/src/chip/tlv/tags.kt @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - + package chip.tlv import kotlin.experimental.and diff --git a/src/controller/java/src/chip/tlv/types.kt b/src/controller/java/src/chip/tlv/types.kt index d4949877b783f3..28b9836f02adaf 100644 --- a/src/controller/java/src/chip/tlv/types.kt +++ b/src/controller/java/src/chip/tlv/types.kt @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - + package chip.tlv import kotlin.experimental.and diff --git a/src/controller/java/src/chip/tlv/utils.kt b/src/controller/java/src/chip/tlv/utils.kt index a8d6bc11f0b2c5..c845bc6c2fdef3 100644 --- a/src/controller/java/src/chip/tlv/utils.kt +++ b/src/controller/java/src/chip/tlv/utils.kt @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - + package chip.tlv /** Converts bytes in a Little Endian format into Long integer. */ diff --git a/src/controller/java/src/chip/tlv/values.kt b/src/controller/java/src/chip/tlv/values.kt index b28eabf3bcd9ca..ce1c99186c8e8f 100644 --- a/src/controller/java/src/chip/tlv/values.kt +++ b/src/controller/java/src/chip/tlv/values.kt @@ -15,10 +15,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - + package chip.tlv -import com.google.protobuf.ByteString import java.lang.Double.doubleToLongBits import java.lang.Float.floatToIntBits @@ -65,11 +64,10 @@ data class Utf8StringValue(val value: String) : Value() { value.toByteArray().size.toByteArrayLittleEndian(toType().lengthSize) + value.toByteArray() } -/** Represents a byte string value of a TLV element. */ -data class ByteStringValue(val value: ByteString) : Value() { - override fun toType() = ByteStringType(unsignedIntSize(value.size().toULong())) - override fun encode() = - value.toByteArray().size.toByteArrayLittleEndian(toType().lengthSize) + value.toByteArray() +/** Represents an octet string value of a TLV element. */ +data class ByteStringValue(val value: ByteArray) : Value() { + override fun toType() = ByteStringType(unsignedIntSize(value.size.toULong())) + override fun encode() = value.size.toByteArrayLittleEndian(toType().lengthSize) + value } /** Represents a null value in a TLV element. */ diff --git a/src/controller/java/tests/chip/jsontlv/JsonToTlvToJsonTest.kt b/src/controller/java/tests/chip/jsontlv/JsonToTlvToJsonTest.kt index d3ce441243120d..cfb9d98c4299c9 100644 --- a/src/controller/java/tests/chip/jsontlv/JsonToTlvToJsonTest.kt +++ b/src/controller/java/tests/chip/jsontlv/JsonToTlvToJsonTest.kt @@ -20,7 +20,6 @@ package chip.jsontlv import com.google.common.truth.Truth.assertThat import com.google.gson.JsonParser -import com.google.protobuf.ByteString import kotlin.test.assertFailsWith import org.junit.Test import org.junit.runner.RunWith @@ -35,8 +34,6 @@ class JsonToTlvToJsonTest { private fun String.octetsToByteArray(): ByteArray = replace(" ", "").chunked(2).map { it.toInt(16) and 0xFF }.map { it.toByte() }.toByteArray() - private fun String.toByteString(): ByteString = ByteString.copyFrom(this.toByteArray()) - private fun checkValidConversion( jsonOriginal: String, tlvEncoding: ByteArray, @@ -283,7 +280,7 @@ class JsonToTlvToJsonTest { @Test fun convertOctetString() { // Octet String, 1-octet length, octets 00 01 02 03 04 - val value = ByteString.fromHex("0001020304") + val value = "0001020304".octetsToByteArray() val encoding = TlvWriter() .startStructure(AnonymousTag) @@ -1207,12 +1204,12 @@ class JsonToTlvToJsonTest { @Test fun convertByteStringArray() { - // Anonymous Array of ByteString, [{00 01 02 03 04}, {FF}, {4A EF 88}] + // Anonymous Array of ByteArray, [{00 01 02 03 04}, {FF}, {4A EF 88}] val values = - listOf( - ByteString.fromHex("0001020304"), - ByteString.fromHex("FF"), - ByteString.fromHex("4AEF88") + listOf( + "0001020304".octetsToByteArray(), + "FF".octetsToByteArray(), + "4AEF88".octetsToByteArray() ) val encoding = TlvWriter() @@ -1245,7 +1242,7 @@ class JsonToTlvToJsonTest { .put(ContextSpecificTag(0), 20.toLong()) .put(ContextSpecificTag(1), true) .put(ContextSpecificTag(2), 0.toULong()) - .put(ContextSpecificTag(3), "Test ByteString Value".toByteString()) + .put(ContextSpecificTag(3), "Test ByteString Value".toByteArray()) .put(ContextSpecificTag(4), "hello") .put(ContextSpecificTag(5), -500000) .put(ContextSpecificTag(6), 17.9) @@ -1284,7 +1281,7 @@ class JsonToTlvToJsonTest { .put(ContextSpecificTag(0), 20) .put(ContextSpecificTag(1), true) .put(ContextSpecificTag(2), 0.toULong()) - .put(ContextSpecificTag(3), "Test ByteString Value 1".toByteString()) + .put(ContextSpecificTag(3), "Test ByteString Value 1".toByteArray()) .put(ContextSpecificTag(4), "hello1") .put(ContextSpecificTag(5), -500000) .put(ContextSpecificTag(6), 17.9) @@ -1294,7 +1291,7 @@ class JsonToTlvToJsonTest { .put(ContextSpecificTag(0), -10) .put(ContextSpecificTag(1), false) .put(ContextSpecificTag(2), 128.toULong()) - .put(ContextSpecificTag(3), "Test ByteString Value 2".toByteString()) + .put(ContextSpecificTag(3), "Test ByteString Value 2".toByteArray()) .put(ContextSpecificTag(4), "hello2") .put(ContextSpecificTag(5), 40000000000) .put(ContextSpecificTag(6), -1754.923) @@ -1350,7 +1347,7 @@ class JsonToTlvToJsonTest { .put(ContextSpecificTag(1), 17.4f) .startStructure(ContextSpecificTag(2)) .put(ContextSpecificTag(0), "Test String Element #2") - .put(ContextSpecificTag(3), "Test ByteString Element #3".toByteString()) + .put(ContextSpecificTag(3), "Test ByteString Element #3".toByteArray()) .endStructure() .endStructure() .endStructure() @@ -1426,13 +1423,13 @@ class JsonToTlvToJsonTest { @Test fun convertArrayOfByteStrings() { - // Array of ByteString elements + // Array of ByteArray elements val values = - listOf( - "Test array member 0".toByteString(), - "Test array member 1".toByteString(), - "Test array member 2".toByteString(), - "Test array member 3".toByteString(), + listOf( + "Test array member 0".toByteArray(), + "Test array member 1".toByteArray(), + "Test array member 2".toByteArray(), + "Test array member 3".toByteArray(), ) val encoding = TlvWriter() @@ -1463,7 +1460,7 @@ class JsonToTlvToJsonTest { TlvWriter() .startStructure(AnonymousTag) .put(ContextSpecificTag(0), 42) - .put(ContextSpecificTag(1), "Test array member 0".toByteString()) + .put(ContextSpecificTag(1), "Test array member 0".toByteArray()) .put(ContextSpecificTag(2), 156.398) .put(ContextSpecificTag(3), 73709551615U) .put(ContextSpecificTag(4), true) diff --git a/src/controller/java/tests/chip/tlv/TlvReadWriteTest.kt b/src/controller/java/tests/chip/tlv/TlvReadWriteTest.kt index 1a2766eba76e95..7fc5cc8e9dc721 100644 --- a/src/controller/java/tests/chip/tlv/TlvReadWriteTest.kt +++ b/src/controller/java/tests/chip/tlv/TlvReadWriteTest.kt @@ -19,7 +19,6 @@ package chip.tlv import com.google.common.truth.Truth.assertThat -import com.google.protobuf.ByteString import kotlin.test.assertFailsWith import org.junit.Test import org.junit.runner.RunWith @@ -484,7 +483,7 @@ class TlvReadWriteTest { @Test fun encodeOctetString() { // Octet String, 1-octet length, octets 00 01 02 03 04 - val value = ByteString.fromHex("00 01 02 03 04".replace(" ", "")) + val value = "00 01 02 03 04".octetsToByteArray() val encoding = "10 05 00 01 02 03 04".octetsToByteArray() TlvWriter().apply { @@ -1093,10 +1092,10 @@ class TlvReadWriteTest { fun putByteStringArray() { // Anonumous Array of Signed Integers, [{00 01 02 03 04}, {FF}, {4A EF 88}] val values = - listOf( - ByteString.fromHex("0001020304"), - ByteString.fromHex("FF"), - ByteString.fromHex("4AEF88") + listOf( + "0001020304".octetsToByteArray(), + "FF".octetsToByteArray(), + "4AEF88".octetsToByteArray() ) val encoding = "16 10 05 00 01 02 03 04 10 01 FF 10 03 4A EF 88 18".octetsToByteArray() diff --git a/src/controller/java/tests/chip/tlv/TlvReaderTest.kt b/src/controller/java/tests/chip/tlv/TlvReaderTest.kt index f7a6b4dbbe0b25..fa7a23d6e66ecf 100644 --- a/src/controller/java/tests/chip/tlv/TlvReaderTest.kt +++ b/src/controller/java/tests/chip/tlv/TlvReaderTest.kt @@ -19,7 +19,6 @@ package chip.tlv import com.google.common.truth.Truth.assertThat -import com.google.protobuf.ByteString import java.math.BigInteger import org.junit.Test import org.junit.runner.RunWith @@ -45,6 +44,9 @@ private val fabricConfig = @RunWith(JUnit4::class) class TlvReaderTest { + private fun String.octetsToByteArray(): ByteArray = + replace(" ", "").chunked(2).map { it.toInt(16) and 0xFF }.map { it.toByte() }.toByteArray() + @Test fun parsingFabricConfig_extractsFabricId() { val reader = TlvReader(fabricConfig) @@ -88,7 +90,7 @@ class TlvReaderTest { assertThat((tag as ContextSpecificTag).tagNumber).isEqualTo(3) assertThat(value).isInstanceOf(ByteStringValue::class.java) assertThat((value as ByteStringValue).value) - .isEqualTo(ByteString.fromHex("149BF1430B26F5E4BBF380D3DB855BA1")) + .isEqualTo("149BF1430B26F5E4BBF380D3DB855BA1".octetsToByteArray()) } reader.nextElement().apply { @@ -96,7 +98,7 @@ class TlvReaderTest { assertThat((tag as ContextSpecificTag).tagNumber).isEqualTo(4) assertThat(value).isInstanceOf(ByteStringValue::class.java) assertThat((value as ByteStringValue).value) - .isEqualTo(ByteString.fromHex("E0E8BAA1CAC6E8E7216D720BD13C61C5E0E7B901")) + .isEqualTo("E0E8BAA1CAC6E8E7216D720BD13C61C5E0E7B901".octetsToByteArray()) } reader.nextElement().apply { @@ -178,16 +180,16 @@ class TlvReaderTest { // Common-profile 2-bytes Tag with ByteString 1-byte type val control = 0b01010000.toByte() val length = 0b10000.toByte() - val v = ByteString.copyFromUtf8("byte_string_utf8") - assertThat(v.toByteArray().size).isEqualTo(16) + val v = "byte_string_utf8".toByteArray() + assertThat(v.size).isEqualTo(16) - val reader = TlvReader(byteArrayOf(control, 0x0, 0x0, length, *v.toByteArray())) + val reader = TlvReader(byteArrayOf(control, 0x0, 0x0, length, *v)) reader.nextElement().apply { assertThat(tag).isInstanceOf(CommonProfileTag::class.java) assertThat((tag as CommonProfileTag).size).isEqualTo(2) assertThat(value).isInstanceOf(ByteStringValue::class.java) assertThat((value as ByteStringValue).value) - .isEqualTo(ByteString.copyFromUtf8("byte_string_utf8")) + .isEqualTo("byte_string_utf8".toByteArray()) } } @@ -268,4 +270,4 @@ class TlvReaderTest { assertThat(tag).isInstanceOf(ContextSpecificTag::class.java) assertThat((tag as ContextSpecificTag).tagNumber).isEqualTo(0xFE) } -} \ No newline at end of file +} diff --git a/src/controller/java/tests/chip/tlv/TlvWriterTest.kt b/src/controller/java/tests/chip/tlv/TlvWriterTest.kt index a45c0bfd093837..be88a2755db859 100644 --- a/src/controller/java/tests/chip/tlv/TlvWriterTest.kt +++ b/src/controller/java/tests/chip/tlv/TlvWriterTest.kt @@ -19,7 +19,6 @@ package chip.tlv import com.google.common.truth.Truth.assertThat -import com.google.protobuf.ByteString import java.math.BigInteger import org.junit.Test import org.junit.runner.RunWith @@ -44,6 +43,9 @@ private val fabricConfig = @RunWith(JUnit4::class) class TlvWriterTest { + private fun String.octetsToByteArray(): ByteArray = + replace(" ", "").chunked(2).map { it.toInt(16) and 0xFF }.map { it.toByte() }.toByteArray() + @Test fun encodingFabricConfig_allElements() { val encodedTlv = @@ -54,8 +56,8 @@ class TlvWriterTest { .startStructure(AnonymousTag) .put(ContextSpecificTag(1), 0x1001u) .put(ContextSpecificTag(2), 0x01u) - .put(ContextSpecificTag(3), ByteString.fromHex("149BF1430B26F5E4BBF380D3DB855BA1")) - .put(ContextSpecificTag(4), ByteString.fromHex("E0E8BAA1CAC6E8E7216D720BD13C61C5E0E7B901")) + .put(ContextSpecificTag(3), "149BF1430B26F5E4BBF380D3DB855BA1".octetsToByteArray()) + .put(ContextSpecificTag(4), "E0E8BAA1CAC6E8E7216D720BD13C61C5E0E7B901".octetsToByteArray()) .put(ContextSpecificTag(5), 0u) .put(ContextSpecificTag(6), 0u) .endStructure() @@ -66,4 +68,4 @@ class TlvWriterTest { assertThat(encodedTlv).isEqualTo(fabricConfig) } -} \ No newline at end of file +}