Skip to content

Commit

Permalink
Implemented skipping of filed with proto Id=0 if it missed in the des…
Browse files Browse the repository at this point in the history
…criptor

Also optimized skipping of size delimited fields - removed the creation of an byte array in case of skipping

Fixes #2649
  • Loading branch information
shanshin committed Aug 23, 2024
1 parent 35a9edc commit b712494
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,12 @@ internal open class ProtobufDecoder(
* If we have reasonably small count of elements, try to build sequential
* array for the fast-path. Fast-path implies that elements are not marked with @ProtoId
* explicitly or are monotonic and incremental (maybe, 1-indexed)
*
* Since the library allows the use of fields with proto ID 0,
* it is necessary to initialize all elements, because there will always be one extra element
* in the fast path array, which misses in the descriptor
*/
val cache = IntArray(elements + 1)
val cache = IntArray(elements + 1) { -1 }
for (i in 0 until elements) {
val protoId = extractProtoId(descriptor, i, false)
// If any element is marked as ProtoOneOf,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ internal class ProtobufReader(private val input: ByteArrayInput) {
when (currentType) {
ProtoWireType.VARINT -> readInt(ProtoIntegerType.DEFAULT)
ProtoWireType.i64 -> readLong(ProtoIntegerType.FIXED)
ProtoWireType.SIZE_DELIMITED -> readByteArray()
ProtoWireType.SIZE_DELIMITED -> skipSizeDelimited()
ProtoWireType.i32 -> readInt(ProtoIntegerType.FIXED)
else -> throw ProtobufDecodingException("Unsupported start group or end group wire type: $currentType")
}
Expand All @@ -75,6 +75,13 @@ internal class ProtobufReader(private val input: ByteArrayInput) {
return readByteArrayNoTag()
}

fun skipSizeDelimited() {
assertWireType(SIZE_DELIMITED)
val length = decode32()
checkLength(length)
input.scipExactNBytes(length)
}

fun readByteArrayNoTag(): ByteArray {
val length = decode32()
checkLength(length)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@ internal class ByteArrayInput(private var array: ByteArray, private val endIndex
return b
}


fun scipExactNBytes(bytesCount: Int) {
ensureEnoughBytes(bytesCount)
position += bytesCount
}

private fun ensureEnoughBytes(bytesCount: Int) {
if (bytesCount > availableBytes) {
throw SerializationException("Unexpected EOF, available $availableBytes bytes, requested: $bytesCount")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright 2017-2024 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/

package kotlinx.serialization.protobuf


import kotlinx.serialization.*
import kotlin.test.*

class SkipFieldsTest {

@Serializable
data class Holder(val value: Int)

@Test
fun testSkipZeroId() {
// first value with id = 0
val hexString = "000f082a"
val holder = ProtoBuf.decodeFromHexString<Holder>(hexString)
assertEquals(42, holder.value)
}

@Test
fun testSkipBigId() {
// first value with id = 2047 and takes 2 bytes
val hexString = "f87f20082a"
val holder = ProtoBuf.decodeFromHexString<Holder>(hexString)
assertEquals(42, holder.value)
}

@Test
fun testSkipString() {
// first value is size delimited (string) with id = 42
val hexString = "d2020c48656c6c6f20576f726c6421082a"
val holder = ProtoBuf.decodeFromHexString<Holder>(hexString)
assertEquals(42, holder.value)
}
}

0 comments on commit b712494

Please sign in to comment.