@@ -122,41 +122,53 @@ internal open class ProtobufDecoder(
122
122
}
123
123
124
124
override fun beginStructure (descriptor : SerialDescriptor ): CompositeDecoder {
125
- return when (descriptor.kind) {
126
- StructureKind .LIST -> {
127
- val tag = currentTagOrDefault
128
- return if (this .descriptor.kind == StructureKind .LIST && tag != MISSING_TAG && this .descriptor != descriptor) {
129
- val reader = makeDelimited(reader, tag)
130
- // repeated decoder expects the first tag to be read already
131
- reader.readTag()
132
- // all elements always have id = 1
133
- RepeatedDecoder (proto, reader, ProtoDesc (1 , ProtoIntegerType .DEFAULT ), descriptor)
134
-
135
- } else if (reader.currentType == SIZE_DELIMITED && descriptor.getElementDescriptor(0 ).isPackable) {
136
- val sliceReader = ProtobufReader (reader.objectInput())
137
- PackedArrayDecoder (proto, sliceReader, descriptor)
138
-
139
- } else {
140
- RepeatedDecoder (proto, reader, tag, descriptor)
125
+ return try {
126
+ when (descriptor.kind) {
127
+ StructureKind .LIST -> {
128
+ val tag = currentTagOrDefault
129
+ return if (this .descriptor.kind == StructureKind .LIST && tag != MISSING_TAG && this .descriptor != descriptor) {
130
+ val reader = makeDelimited(reader, tag)
131
+ // repeated decoder expects the first tag to be read already
132
+ reader.readTag()
133
+ // all elements always have id = 1
134
+ RepeatedDecoder (proto, reader, ProtoDesc (1 , ProtoIntegerType .DEFAULT ), descriptor)
135
+
136
+ } else if (reader.currentType == ProtoWireType .SIZE_DELIMITED && descriptor.getElementDescriptor(0 ).isPackable) {
137
+ val sliceReader = ProtobufReader (reader.objectInput())
138
+ PackedArrayDecoder (proto, sliceReader, descriptor)
139
+
140
+ } else {
141
+ RepeatedDecoder (proto, reader, tag, descriptor)
142
+ }
141
143
}
142
- }
143
- StructureKind .CLASS , StructureKind .OBJECT , is PolymorphicKind -> {
144
- val tag = currentTagOrDefault
145
- // Do not create redundant copy
146
- if (tag == MISSING_TAG && this .descriptor == descriptor) return this
147
- if (tag.isOneOf) {
148
- // If a tag is annotated as oneof
149
- // [tag.protoId] here is overwritten with index-based default id in
150
- // [kotlinx.serialization.protobuf.internal.HelpersKt.extractParameters]
151
- // and restored the real id from index2IdMap, set by [decodeElementIndex]
152
- val rawIndex = tag.protoId - 1
153
- val restoredTag = index2IdMap?.get(rawIndex)?.let { tag.overrideId(it) } ? : tag
154
- return OneOfPolymorphicReader (proto, reader, restoredTag, descriptor)
144
+
145
+ StructureKind .CLASS , StructureKind .OBJECT , is PolymorphicKind -> {
146
+ val tag = currentTagOrDefault
147
+ // Do not create redundant copy
148
+ if (tag == MISSING_TAG && this .descriptor == descriptor) return this
149
+ if (tag.isOneOf) {
150
+ // If a tag is annotated as oneof
151
+ // [tag.protoId] here is overwritten with index-based default id in
152
+ // [kotlinx.serialization.protobuf.internal.HelpersKt.extractParameters]
153
+ // and restored the real id from index2IdMap, set by [decodeElementIndex]
154
+ val rawIndex = tag.protoId - 1
155
+ val restoredTag = index2IdMap?.get(rawIndex)?.let { tag.overrideId(it) } ? : tag
156
+ return OneOfPolymorphicReader (proto, reader, restoredTag, descriptor)
157
+ }
158
+ return ProtobufDecoder (proto, makeDelimited(reader, tag), descriptor)
155
159
}
156
- return ProtobufDecoder (proto, makeDelimited(reader, tag), descriptor)
160
+
161
+ StructureKind .MAP -> MapEntryReader (
162
+ proto,
163
+ makeDelimitedForced(reader, currentTagOrDefault),
164
+ currentTagOrDefault,
165
+ descriptor
166
+ )
167
+
168
+ else -> throw SerializationException (" Primitives are not supported at top-level" )
157
169
}
158
- StructureKind . MAP -> MapEntryReader (proto, makeDelimitedForced(reader, currentTagOrDefault), currentTagOrDefault, descriptor)
159
- else -> throw SerializationException ( " Primitives are not supported at top-level " )
170
+ } catch (e : ProtobufDecodingException ) {
171
+ throw ProtobufDecodingException ( " Fail to begin structure for ${descriptor.serialName} in ${ this .descriptor.serialName} at proto number ${currentTagOrDefault.protoId} " , e )
160
172
}
161
173
}
162
174
@@ -173,41 +185,51 @@ internal open class ProtobufDecoder(
173
185
override fun decodeTaggedByte (tag : ProtoDesc ): Byte = decodeTaggedInt(tag).toByte()
174
186
override fun decodeTaggedShort (tag : ProtoDesc ): Short = decodeTaggedInt(tag).toShort()
175
187
override fun decodeTaggedInt (tag : ProtoDesc ): Int {
176
- return if (tag == MISSING_TAG ) {
177
- reader.readInt32NoTag()
178
- } else {
179
- reader.readInt(tag.integerType)
188
+ return decodeOrThrow(tag) {
189
+ if (tag == MISSING_TAG ) {
190
+ reader.readInt32NoTag()
191
+ } else {
192
+ reader.readInt(tag.integerType)
193
+ }
180
194
}
181
195
}
182
196
override fun decodeTaggedLong (tag : ProtoDesc ): Long {
183
- return if (tag == MISSING_TAG ) {
184
- reader.readLongNoTag()
185
- } else {
186
- reader.readLong(tag.integerType)
197
+ return decodeOrThrow(tag) {
198
+ if (tag == MISSING_TAG ) {
199
+ reader.readLongNoTag()
200
+ } else {
201
+ reader.readLong(tag.integerType)
202
+ }
187
203
}
188
204
}
189
205
190
206
override fun decodeTaggedFloat (tag : ProtoDesc ): Float {
191
- return if (tag == MISSING_TAG ) {
192
- reader.readFloatNoTag()
193
- } else {
194
- reader.readFloat()
207
+ return decodeOrThrow(tag) {
208
+ if (tag == MISSING_TAG ) {
209
+ reader.readFloatNoTag()
210
+ } else {
211
+ reader.readFloat()
212
+ }
195
213
}
196
214
}
197
215
override fun decodeTaggedDouble (tag : ProtoDesc ): Double {
198
- return if (tag == MISSING_TAG ) {
199
- reader.readDoubleNoTag()
200
- } else {
201
- reader.readDouble()
216
+ return decodeOrThrow(tag) {
217
+ if (tag == MISSING_TAG ) {
218
+ reader.readDoubleNoTag()
219
+ } else {
220
+ reader.readDouble()
221
+ }
202
222
}
203
223
}
204
224
override fun decodeTaggedChar (tag : ProtoDesc ): Char = decodeTaggedInt(tag).toChar()
205
225
206
226
override fun decodeTaggedString (tag : ProtoDesc ): String {
207
- return if (tag == MISSING_TAG ) {
208
- reader.readStringNoTag()
209
- } else {
210
- reader.readString()
227
+ return decodeOrThrow(tag) {
228
+ if (tag == MISSING_TAG ) {
229
+ reader.readStringNoTag()
230
+ } else {
231
+ reader.readString()
232
+ }
211
233
}
212
234
}
213
235
@@ -218,22 +240,49 @@ internal open class ProtobufDecoder(
218
240
override fun <T > decodeSerializableValue (deserializer : DeserializationStrategy <T >): T = decodeSerializableValue(deserializer, null )
219
241
220
242
@Suppress(" UNCHECKED_CAST" )
221
- override fun <T > decodeSerializableValue (deserializer : DeserializationStrategy <T >, previousValue : T ? ): T = when {
222
- deserializer is MapLikeSerializer <* , * , * , * > -> {
223
- deserializeMap(deserializer as DeserializationStrategy <T >, previousValue)
243
+ override fun <T > decodeSerializableValue (deserializer : DeserializationStrategy <T >, previousValue : T ? ): T = try {
244
+ when {
245
+ deserializer is MapLikeSerializer <* , * , * , * > -> {
246
+ deserializeMap(deserializer as DeserializationStrategy <T >, previousValue)
247
+ }
248
+
249
+ deserializer.descriptor == ByteArraySerializer ().descriptor -> deserializeByteArray(previousValue as ByteArray? ) as T
250
+ deserializer is AbstractCollectionSerializer <* , * , * > ->
251
+ (deserializer as AbstractCollectionSerializer <* , T , * >).merge(this , previousValue)
252
+
253
+ else -> deserializer.deserialize(this )
254
+ }
255
+ } catch (e: ProtobufDecodingException ) {
256
+ val currentTag = currentTagOrDefault
257
+ val msg = if (descriptor != deserializer.descriptor) {
258
+ // Decoding child element
259
+ if (descriptor.kind == StructureKind .LIST && deserializer.descriptor.kind != StructureKind .MAP ) {
260
+ // Decoding repeated field
261
+ " Error while decoding index ${currentTag.protoId - 1 } in repeated field of ${deserializer.descriptor.serialName} "
262
+ } else if (descriptor.kind == StructureKind .MAP ) {
263
+ // Decoding map field
264
+ val index = (currentTag.protoId - 1 ) / 2
265
+ val field = if ((currentTag.protoId - 1 ) % 2 == 0 ) { " key" } else " value"
266
+ " Error while decoding $field of index $index in map field of ${deserializer.descriptor.serialName} "
267
+ } else {
268
+ // Decoding common class
269
+ " Error while decoding ${deserializer.descriptor.serialName} at proto number ${currentTag.protoId} of ${descriptor.serialName} "
270
+ }
271
+ } else {
272
+ // Decoding self
273
+ " Error while decoding ${descriptor.serialName} "
224
274
}
225
- deserializer.descriptor == ByteArraySerializer ().descriptor -> deserializeByteArray(previousValue as ByteArray? ) as T
226
- deserializer is AbstractCollectionSerializer <* , * , * > ->
227
- (deserializer as AbstractCollectionSerializer <* , T , * >).merge(this , previousValue)
228
- else -> deserializer.deserialize(this )
275
+ throw ProtobufDecodingException (msg, e)
229
276
}
230
277
231
278
private fun deserializeByteArray (previousValue : ByteArray? ): ByteArray {
232
279
val tag = currentTagOrDefault
233
- val array = if (tag == MISSING_TAG ) {
234
- reader.readByteArrayNoTag()
235
- } else {
236
- reader.readByteArray()
280
+ val array = decodeOrThrow(tag) {
281
+ if (tag == MISSING_TAG ) {
282
+ reader.readByteArrayNoTag()
283
+ } else {
284
+ reader.readByteArray()
285
+ }
237
286
}
238
287
return if (previousValue == null ) array else previousValue + array
239
288
}
@@ -252,29 +301,33 @@ internal open class ProtobufDecoder(
252
301
override fun SerialDescriptor.getTag (index : Int ) = extractParameters(index)
253
302
254
303
override fun decodeElementIndex (descriptor : SerialDescriptor ): Int {
255
- while (true ) {
256
- val protoId = reader.readTag()
257
- if (protoId == - 1 ) { // EOF
258
- return elementMarker.nextUnmarkedIndex()
259
- }
260
- val index = getIndexByNum(protoId)
261
- if (index == - 1 ) { // not found
262
- reader.skipElement()
263
- } else {
264
- if (descriptor.extractParameters(index).isOneOf) {
265
- /* *
266
- * While decoding message with one-of field,
267
- * the proto id read from wire data cannot be easily found
268
- * in the properties of this type,
269
- * So the index of this one-of property and the id read from the wire
270
- * are saved in this map, then restored in [beginStructure]
271
- * and passed to [OneOfPolymorphicReader] to get the actual deserializer.
272
- */
273
- index2IdMap?.put(index, protoId)
304
+ try {
305
+ while (true ) {
306
+ val protoId = reader.readTag()
307
+ if (protoId == - 1 ) { // EOF
308
+ return elementMarker.nextUnmarkedIndex()
309
+ }
310
+ val index = getIndexByNum(protoId)
311
+ if (index == - 1 ) { // not found
312
+ reader.skipElement()
313
+ } else {
314
+ if (descriptor.extractParameters(index).isOneOf) {
315
+ /* *
316
+ * While decoding message with one-of field,
317
+ * the proto id read from wire data cannot be easily found
318
+ * in the properties of this type,
319
+ * So the index of this one-of property and the id read from the wire
320
+ * are saved in this map, then restored in [beginStructure]
321
+ * and passed to [OneOfPolymorphicReader] to get the actual deserializer.
322
+ */
323
+ index2IdMap?.put(index, protoId)
324
+ }
325
+ elementMarker.mark(index)
326
+ return index
274
327
}
275
- elementMarker.mark(index)
276
- return index
277
328
}
329
+ } catch (e: ProtobufDecodingException ) {
330
+ throw ProtobufDecodingException (" Fail to get element index for ${descriptor.serialName} in ${this .descriptor.serialName} " , e)
278
331
}
279
332
}
280
333
@@ -296,6 +349,19 @@ internal open class ProtobufDecoder(
296
349
}
297
350
return false
298
351
}
352
+
353
+ private inline fun <T > decodeOrThrow (tag : ProtoDesc , action : (tag: ProtoDesc ) -> T ): T {
354
+ try {
355
+ return action(tag)
356
+ } catch (e: ProtobufDecodingException ) {
357
+ rethrowException(tag, e)
358
+ }
359
+ }
360
+
361
+ @Suppress(" NOTHING_TO_INLINE" )
362
+ private inline fun rethrowException (tag : ProtoDesc , e : ProtobufDecodingException ): Nothing {
363
+ throw ProtobufDecodingException (" Error while decoding proto number ${tag.protoId} of ${descriptor.serialName} " , e)
364
+ }
299
365
}
300
366
301
367
private class RepeatedDecoder (
0 commit comments