Skip to content

Commit

Permalink
Kotlin TLV Implementation: Removed Dependency on Protobuf (#26641)
Browse files Browse the repository at this point in the history
Instead of protobuf.ByteString using ByteArray to implement Octate String
TLV type.
  • Loading branch information
emargolis authored and pull[bot] committed Nov 7, 2023
1 parent 2f22be1 commit 3394619
Show file tree
Hide file tree
Showing 14 changed files with 57 additions and 66 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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())
}
},
)
}
}
}
2 changes: 0 additions & 2 deletions src/controller/java/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
5 changes: 2 additions & 3 deletions src/controller/java/src/chip/jsontlv/JsonToTlv.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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.*

Expand Down Expand Up @@ -150,8 +149,8 @@ private fun extractTagAndTypeFromJsonKey(key: String): Triple<Tag, String, Strin
return Triple(tag, type, subType)
}

private fun String.base64Encode(): ByteString {
return ByteString.copyFrom(Base64.getDecoder().decode(this))
private fun String.base64Encode(): ByteArray {
return Base64.getDecoder().decode(this)
}

/** Verifies JsonElement is Number. If yes, returns the value. */
Expand Down
5 changes: 2 additions & 3 deletions src/controller/java/src/chip/jsontlv/TlvToJson.kt
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,7 @@ private fun TlvReader.getStructJson(): JsonObject {
}
}
is Utf8StringValue -> 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))
Expand Down Expand Up @@ -144,7 +143,7 @@ private fun TlvReader.getArrayJsonWithElementsType(): Pair<JsonArray, String> {
}
}
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))
Expand Down
5 changes: 2 additions & 3 deletions src/controller/java/src/chip/tlv/TlvReader.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@

package chip.tlv

import com.google.protobuf.ByteString
import java.lang.Double.longBitsToDouble
import java.lang.Float.intBitsToFloat

Expand Down Expand Up @@ -87,7 +86,7 @@ class TlvReader(bytes: ByteArray) : Iterable<Element> {
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()))
Expand Down Expand Up @@ -248,7 +247,7 @@ class TlvReader(bytes: ByteArray) : Iterable<Element> {
*
* @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)"
Expand Down
7 changes: 3 additions & 4 deletions src/controller/java/src/chip/tlv/TlvWriter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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

/**
Expand Down Expand Up @@ -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)))
}

Expand Down Expand Up @@ -261,7 +260,7 @@ class TlvWriter(initialCapacity: Int = 32) {
*
* @throws TlvEncodingException if the data was invalid
*/
fun putByteStringArray(tag: Tag, array: List<ByteString>): TlvWriter {
fun putByteStringArray(tag: Tag, array: List<ByteArray>): TlvWriter {
startArray(tag)
array.forEach { put(AnonymousTag, it) }
return endArray()
Expand Down
2 changes: 1 addition & 1 deletion src/controller/java/src/chip/tlv/tags.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/controller/java/src/chip/tlv/types.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/controller/java/src/chip/tlv/utils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
Expand Down
12 changes: 5 additions & 7 deletions src/controller/java/src/chip/tlv/values.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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. */
Expand Down
37 changes: 17 additions & 20 deletions src/controller/java/tests/chip/jsontlv/JsonToTlvToJsonTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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,
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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>(
ByteString.fromHex("0001020304"),
ByteString.fromHex("FF"),
ByteString.fromHex("4AEF88")
listOf<ByteArray>(
"0001020304".octetsToByteArray(),
"FF".octetsToByteArray(),
"4AEF88".octetsToByteArray()
)
val encoding =
TlvWriter()
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand All @@ -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)
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -1426,13 +1423,13 @@ class JsonToTlvToJsonTest {

@Test
fun convertArrayOfByteStrings() {
// Array of ByteString elements
// Array of ByteArray elements
val values =
listOf<ByteString>(
"Test array member 0".toByteString(),
"Test array member 1".toByteString(),
"Test array member 2".toByteString(),
"Test array member 3".toByteString(),
listOf<ByteArray>(
"Test array member 0".toByteArray(),
"Test array member 1".toByteArray(),
"Test array member 2".toByteArray(),
"Test array member 3".toByteArray(),
)
val encoding =
TlvWriter()
Expand Down Expand Up @@ -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)
Expand Down
11 changes: 5 additions & 6 deletions src/controller/java/tests/chip/tlv/TlvReadWriteTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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>(
ByteString.fromHex("0001020304"),
ByteString.fromHex("FF"),
ByteString.fromHex("4AEF88")
listOf<ByteArray>(
"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()

Expand Down
18 changes: 10 additions & 8 deletions src/controller/java/tests/chip/tlv/TlvReaderTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
Expand Down Expand Up @@ -88,15 +90,15 @@ 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 {
assertThat(tag).isInstanceOf(ContextSpecificTag::class.java)
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 {
Expand Down Expand Up @@ -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())
}
}

Expand Down Expand Up @@ -268,4 +270,4 @@ class TlvReaderTest {
assertThat(tag).isInstanceOf(ContextSpecificTag::class.java)
assertThat((tag as ContextSpecificTag).tagNumber).isEqualTo(0xFE)
}
}
}
Loading

0 comments on commit 3394619

Please sign in to comment.