Skip to content

Commit 9197f0a

Browse files
committed
Implemented skipping of filed with proto Id=0 if it missed in the descriptor
Also optimized skipping of size delimited fields - removed the creation of an byte array in case of skipping Fixes #2649
1 parent 85b3294 commit 9197f0a

File tree

4 files changed

+58
-2
lines changed

4 files changed

+58
-2
lines changed

formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/ProtobufDecoding.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,12 @@ internal open class ProtobufDecoder(
4545
* If we have reasonably small count of elements, try to build sequential
4646
* array for the fast-path. Fast-path implies that elements are not marked with @ProtoId
4747
* explicitly or are monotonic and incremental (maybe, 1-indexed)
48+
*
49+
* Since the library allows the use of fields with proto ID 0,
50+
* it is necessary to initialize all elements, because there will always be one extra element
51+
* in the fast path array, which misses in the descriptor
4852
*/
49-
val cache = IntArray(elements + 1)
53+
val cache = IntArray(elements + 1) { -1 }
5054
for (i in 0 until elements) {
5155
val protoId = extractProtoId(descriptor, i, false)
5256
// If any element is marked as ProtoOneOf,

formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/ProtobufReader.kt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ internal class ProtobufReader(private val input: ByteArrayInput) {
5959
when (currentType) {
6060
VARINT -> readInt(ProtoIntegerType.DEFAULT)
6161
i64 -> readLong(ProtoIntegerType.FIXED)
62-
SIZE_DELIMITED -> readByteArray()
62+
SIZE_DELIMITED -> skipSizeDelimited()
6363
i32 -> readInt(ProtoIntegerType.FIXED)
6464
else -> throw ProtobufDecodingException("Unsupported start group or end group wire type: $currentType")
6565
}
@@ -75,6 +75,13 @@ internal class ProtobufReader(private val input: ByteArrayInput) {
7575
return readByteArrayNoTag()
7676
}
7777

78+
fun skipSizeDelimited() {
79+
assertWireType(SIZE_DELIMITED)
80+
val length = decode32()
81+
checkLength(length)
82+
input.scipExactNBytes(length)
83+
}
84+
7885
fun readByteArrayNoTag(): ByteArray {
7986
val length = decode32()
8087
checkLength(length)

formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/Streams.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,12 @@ internal class ByteArrayInput(private var array: ByteArray, private val endIndex
3333
return b
3434
}
3535

36+
37+
fun scipExactNBytes(bytesCount: Int) {
38+
ensureEnoughBytes(bytesCount)
39+
position += bytesCount
40+
}
41+
3642
private fun ensureEnoughBytes(bytesCount: Int) {
3743
if (bytesCount > availableBytes) {
3844
throw SerializationException("Unexpected EOF, available $availableBytes bytes, requested: $bytesCount")
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
* Copyright 2017-2024 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
package kotlinx.serialization.protobuf
6+
7+
8+
import kotlinx.serialization.*
9+
import kotlin.test.*
10+
11+
class SkipFieldsTest {
12+
13+
@Serializable
14+
data class Holder(val value: Int)
15+
16+
@Test
17+
fun testSkipZeroId() {
18+
// first value with id = 0
19+
val hexString = "000f082a"
20+
val holder = ProtoBuf.decodeFromHexString<Holder>(hexString)
21+
assertEquals(42, holder.value)
22+
}
23+
24+
@Test
25+
fun testSkipBigId() {
26+
// first value with id = 2047 and takes 2 bytes
27+
val hexString = "f87f20082a"
28+
val holder = ProtoBuf.decodeFromHexString<Holder>(hexString)
29+
assertEquals(42, holder.value)
30+
}
31+
32+
@Test
33+
fun testSkipString() {
34+
// first value is size delimited (string) with id = 42
35+
val hexString = "d2020c48656c6c6f20576f726c6421082a"
36+
val holder = ProtoBuf.decodeFromHexString<Holder>(hexString)
37+
assertEquals(42, holder.value)
38+
}
39+
}

0 commit comments

Comments
 (0)