• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc.  All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file or at
6 // https://developers.google.com/open-source/licenses/bsd
7 
8 package com.google.protobuf;
9 
10 import static com.google.protobuf.MessageSchema.getMutableUnknownFields;
11 
12 import com.google.protobuf.GeneratedMessageLite.ExtensionDescriptor;
13 import com.google.protobuf.Internal.ProtobufList;
14 import java.io.IOException;
15 
16 /**
17  * Helper functions to decode protobuf wire format from a byte array.
18  *
19  * <p>Note that these functions don't do boundary check on the byte array but instead rely on Java
20  * VM to check it. That means parsing routines utilizing these functions must catch
21  * IndexOutOfBoundsException and convert it to protobuf's InvalidProtocolBufferException when
22  * crossing protobuf public API boundaries.
23  */
24 @CheckReturnValue
25 final class ArrayDecoders {
26   static final int DEFAULT_RECURSION_LIMIT = 100;
27 
28   @SuppressWarnings("NonFinalStaticField")
29   private static volatile int recursionLimit = DEFAULT_RECURSION_LIMIT;
30 
ArrayDecoders()31   private ArrayDecoders() {}
32 
33   /**
34    * A helper used to return multiple values in a Java function. Java doesn't natively support
35    * returning multiple values in a function. Creating a new Object to hold the return values will
36    * be too expensive. Instead, we pass a Registers instance to functions that want to return
37    * multiple values and let the function set the return value in this Registers instance instead.
38    */
39   static final class Registers {
40     public int int1;
41     public long long1;
42     public Object object1;
43     public final ExtensionRegistryLite extensionRegistry;
44     public int recursionDepth;
45 
Registers()46     Registers() {
47       this.extensionRegistry = ExtensionRegistryLite.getEmptyRegistry();
48     }
49 
Registers(ExtensionRegistryLite extensionRegistry)50     Registers(ExtensionRegistryLite extensionRegistry) {
51       if (extensionRegistry == null) {
52         throw new NullPointerException();
53       }
54       this.extensionRegistry = extensionRegistry;
55     }
56   }
57 
58   /**
59    * Decodes a varint. Returns the position after the varint. The decoded varint is stored in
60    * registers.int1.
61    */
decodeVarint32(byte[] data, int position, Registers registers)62   static int decodeVarint32(byte[] data, int position, Registers registers) {
63     int value = data[position++];
64     if (value >= 0) {
65       registers.int1 = value;
66       return position;
67     }
68     return decodeVarint32(value, data, position, registers);
69   }
70 
71   /** Like decodeVarint32 except that the first byte is already read. */
decodeVarint32(int firstByte, byte[] data, int position, Registers registers)72   static int decodeVarint32(int firstByte, byte[] data, int position, Registers registers) {
73     int value = firstByte & 0x7F;
74     final byte b2 = data[position++];
75     if (b2 >= 0) {
76       registers.int1 = value | ((int) b2 << 7);
77       return position;
78     }
79     value |= (b2 & 0x7F) << 7;
80 
81     final byte b3 = data[position++];
82     if (b3 >= 0) {
83       registers.int1 = value | ((int) b3 << 14);
84       return position;
85     }
86     value |= (b3 & 0x7F) << 14;
87 
88     final byte b4 = data[position++];
89     if (b4 >= 0) {
90       registers.int1 = value | ((int) b4 << 21);
91       return position;
92     }
93     value |= (b4 & 0x7F) << 21;
94 
95     final byte b5 = data[position++];
96     if (b5 >= 0) {
97       registers.int1 = value | ((int) b5 << 28);
98       return position;
99     }
100     value |= (b5 & 0x7F) << 28;
101 
102     while (data[position++] < 0) {}
103 
104     registers.int1 = value;
105     return position;
106   }
107 
108   /**
109    * Decodes a varint. Returns the position after the varint. The decoded varint is stored in
110    * registers.long1.
111    */
decodeVarint64(byte[] data, int position, Registers registers)112   static int decodeVarint64(byte[] data, int position, Registers registers) {
113     long value = data[position++];
114     if (value >= 0) {
115       registers.long1 = value;
116       return position;
117     } else {
118       return decodeVarint64(value, data, position, registers);
119     }
120   }
121 
122   /** Like decodeVarint64 except that the first byte is already read. */
decodeVarint64(long firstByte, byte[] data, int position, Registers registers)123   static int decodeVarint64(long firstByte, byte[] data, int position, Registers registers) {
124     long value = firstByte & 0x7F;
125     byte next = data[position++];
126     int shift = 7;
127     value |= (long) (next & 0x7F) << 7;
128     while (next < 0) {
129       next = data[position++];
130       shift += 7;
131       value |= (long) (next & 0x7F) << shift;
132     }
133     registers.long1 = value;
134     return position;
135   }
136 
137   /** Decodes and returns a fixed32 value. */
decodeFixed32(byte[] data, int position)138   static int decodeFixed32(byte[] data, int position) {
139     return (data[position] & 0xff)
140         | ((data[position + 1] & 0xff) << 8)
141         | ((data[position + 2] & 0xff) << 16)
142         | ((data[position + 3] & 0xff) << 24);
143   }
144 
145   /** Decodes and returns a fixed64 value. */
decodeFixed64(byte[] data, int position)146   static long decodeFixed64(byte[] data, int position) {
147     return (data[position] & 0xffL)
148         | ((data[position + 1] & 0xffL) << 8)
149         | ((data[position + 2] & 0xffL) << 16)
150         | ((data[position + 3] & 0xffL) << 24)
151         | ((data[position + 4] & 0xffL) << 32)
152         | ((data[position + 5] & 0xffL) << 40)
153         | ((data[position + 6] & 0xffL) << 48)
154         | ((data[position + 7] & 0xffL) << 56);
155   }
156 
157   /** Decodes and returns a double value. */
decodeDouble(byte[] data, int position)158   static double decodeDouble(byte[] data, int position) {
159     return Double.longBitsToDouble(decodeFixed64(data, position));
160   }
161 
162   /** Decodes and returns a float value. */
decodeFloat(byte[] data, int position)163   static float decodeFloat(byte[] data, int position) {
164     return Float.intBitsToFloat(decodeFixed32(data, position));
165   }
166 
167   /** Decodes a string value. */
decodeString(byte[] data, int position, Registers registers)168   static int decodeString(byte[] data, int position, Registers registers)
169       throws InvalidProtocolBufferException {
170     position = decodeVarint32(data, position, registers);
171     final int length = registers.int1;
172     if (length < 0) {
173       throw InvalidProtocolBufferException.negativeSize();
174     } else if (length == 0) {
175       registers.object1 = "";
176       return position;
177     } else {
178       registers.object1 = new String(data, position, length, Internal.UTF_8);
179       return position + length;
180     }
181   }
182 
183   /** Decodes a string value with utf8 check. */
decodeStringRequireUtf8(byte[] data, int position, Registers registers)184   static int decodeStringRequireUtf8(byte[] data, int position, Registers registers)
185       throws InvalidProtocolBufferException {
186     position = decodeVarint32(data, position, registers);
187     final int length = registers.int1;
188     if (length < 0) {
189       throw InvalidProtocolBufferException.negativeSize();
190     } else if (length == 0) {
191       registers.object1 = "";
192       return position;
193     } else {
194       registers.object1 = Utf8.decodeUtf8(data, position, length);
195       return position + length;
196     }
197   }
198 
199   /** Decodes a bytes value. */
decodeBytes(byte[] data, int position, Registers registers)200   static int decodeBytes(byte[] data, int position, Registers registers)
201       throws InvalidProtocolBufferException {
202     position = decodeVarint32(data, position, registers);
203     final int length = registers.int1;
204     if (length < 0) {
205       throw InvalidProtocolBufferException.negativeSize();
206     } else if (length > data.length - position) {
207       throw InvalidProtocolBufferException.truncatedMessage();
208     } else if (length == 0) {
209       registers.object1 = ByteString.EMPTY;
210       return position;
211     } else {
212       registers.object1 = ByteString.copyFrom(data, position, length);
213       return position + length;
214     }
215   }
216 
217   /** Decodes a message value. */
218   @SuppressWarnings({"unchecked", "rawtypes"})
decodeMessageField( Schema schema, byte[] data, int position, int limit, Registers registers)219   static int decodeMessageField(
220       Schema schema, byte[] data, int position, int limit, Registers registers) throws IOException {
221     Object msg = schema.newInstance();
222     int offset = mergeMessageField(msg, schema, data, position, limit, registers);
223     schema.makeImmutable(msg);
224     registers.object1 = msg;
225     return offset;
226   }
227 
228   /** Decodes a group value. */
229   @SuppressWarnings({"unchecked", "rawtypes"})
decodeGroupField( Schema schema, byte[] data, int position, int limit, int endGroup, Registers registers)230   static int decodeGroupField(
231       Schema schema, byte[] data, int position, int limit, int endGroup, Registers registers)
232       throws IOException {
233     Object msg = schema.newInstance();
234     int offset = mergeGroupField(msg, schema, data, position, limit, endGroup, registers);
235     schema.makeImmutable(msg);
236     registers.object1 = msg;
237     return offset;
238   }
239 
240   @SuppressWarnings({"unchecked", "rawtypes"})
mergeMessageField( Object msg, Schema schema, byte[] data, int position, int limit, Registers registers)241   static int mergeMessageField(
242       Object msg, Schema schema, byte[] data, int position, int limit, Registers registers)
243       throws IOException {
244     int length = data[position++];
245     if (length < 0) {
246       position = decodeVarint32(length, data, position, registers);
247       length = registers.int1;
248     }
249     if (length < 0 || length > limit - position) {
250       throw InvalidProtocolBufferException.truncatedMessage();
251     }
252     registers.recursionDepth++;
253     checkRecursionLimit(registers.recursionDepth);
254     schema.mergeFrom(msg, data, position, position + length, registers);
255     registers.recursionDepth--;
256     registers.object1 = msg;
257     return position + length;
258   }
259 
260   @SuppressWarnings({"unchecked", "rawtypes"})
mergeGroupField( Object msg, Schema schema, byte[] data, int position, int limit, int endGroup, Registers registers)261   static int mergeGroupField(
262       Object msg,
263       Schema schema,
264       byte[] data,
265       int position,
266       int limit,
267       int endGroup,
268       Registers registers)
269       throws IOException {
270     // A group field must has a MessageSchema (the only other subclass of Schema is MessageSetSchema
271     // and it can't be used in group fields).
272     final MessageSchema messageSchema = (MessageSchema) schema;
273     registers.recursionDepth++;
274     checkRecursionLimit(registers.recursionDepth);
275     final int endPosition =
276         messageSchema.parseMessage(msg, data, position, limit, endGroup, registers);
277     registers.recursionDepth--;
278     registers.object1 = msg;
279     return endPosition;
280   }
281 
282   /** Decodes a repeated 32-bit varint field. Returns the position after all read values. */
decodeVarint32List( int tag, byte[] data, int position, int limit, ProtobufList<?> list, Registers registers)283   static int decodeVarint32List(
284       int tag, byte[] data, int position, int limit, ProtobufList<?> list, Registers registers) {
285     final IntArrayList output = (IntArrayList) list;
286     position = decodeVarint32(data, position, registers);
287     output.addInt(registers.int1);
288     while (position < limit) {
289       int nextPosition = decodeVarint32(data, position, registers);
290       if (tag != registers.int1) {
291         break;
292       }
293       position = decodeVarint32(data, nextPosition, registers);
294       output.addInt(registers.int1);
295     }
296     return position;
297   }
298 
299   /** Decodes a repeated 64-bit varint field. Returns the position after all read values. */
decodeVarint64List( int tag, byte[] data, int position, int limit, ProtobufList<?> list, Registers registers)300   static int decodeVarint64List(
301       int tag, byte[] data, int position, int limit, ProtobufList<?> list, Registers registers) {
302     final LongArrayList output = (LongArrayList) list;
303     position = decodeVarint64(data, position, registers);
304     output.addLong(registers.long1);
305     while (position < limit) {
306       int nextPosition = decodeVarint32(data, position, registers);
307       if (tag != registers.int1) {
308         break;
309       }
310       position = decodeVarint64(data, nextPosition, registers);
311       output.addLong(registers.long1);
312     }
313     return position;
314   }
315 
316   /** Decodes a repeated fixed32 field. Returns the position after all read values. */
decodeFixed32List( int tag, byte[] data, int position, int limit, ProtobufList<?> list, Registers registers)317   static int decodeFixed32List(
318       int tag, byte[] data, int position, int limit, ProtobufList<?> list, Registers registers) {
319     final IntArrayList output = (IntArrayList) list;
320     output.addInt(decodeFixed32(data, position));
321     position += 4;
322     while (position < limit) {
323       int nextPosition = decodeVarint32(data, position, registers);
324       if (tag != registers.int1) {
325         break;
326       }
327       output.addInt(decodeFixed32(data, nextPosition));
328       position = nextPosition + 4;
329     }
330     return position;
331   }
332 
333   /** Decodes a repeated fixed64 field. Returns the position after all read values. */
decodeFixed64List( int tag, byte[] data, int position, int limit, ProtobufList<?> list, Registers registers)334   static int decodeFixed64List(
335       int tag, byte[] data, int position, int limit, ProtobufList<?> list, Registers registers) {
336     final LongArrayList output = (LongArrayList) list;
337     output.addLong(decodeFixed64(data, position));
338     position += 8;
339     while (position < limit) {
340       int nextPosition = decodeVarint32(data, position, registers);
341       if (tag != registers.int1) {
342         break;
343       }
344       output.addLong(decodeFixed64(data, nextPosition));
345       position = nextPosition + 8;
346     }
347     return position;
348   }
349 
350   /** Decodes a repeated float field. Returns the position after all read values. */
decodeFloatList( int tag, byte[] data, int position, int limit, ProtobufList<?> list, Registers registers)351   static int decodeFloatList(
352       int tag, byte[] data, int position, int limit, ProtobufList<?> list, Registers registers) {
353     final FloatArrayList output = (FloatArrayList) list;
354     output.addFloat(decodeFloat(data, position));
355     position += 4;
356     while (position < limit) {
357       int nextPosition = decodeVarint32(data, position, registers);
358       if (tag != registers.int1) {
359         break;
360       }
361       output.addFloat(decodeFloat(data, nextPosition));
362       position = nextPosition + 4;
363     }
364     return position;
365   }
366 
367   /** Decodes a repeated double field. Returns the position after all read values. */
decodeDoubleList( int tag, byte[] data, int position, int limit, ProtobufList<?> list, Registers registers)368   static int decodeDoubleList(
369       int tag, byte[] data, int position, int limit, ProtobufList<?> list, Registers registers) {
370     final DoubleArrayList output = (DoubleArrayList) list;
371     output.addDouble(decodeDouble(data, position));
372     position += 8;
373     while (position < limit) {
374       int nextPosition = decodeVarint32(data, position, registers);
375       if (tag != registers.int1) {
376         break;
377       }
378       output.addDouble(decodeDouble(data, nextPosition));
379       position = nextPosition + 8;
380     }
381     return position;
382   }
383 
384   /** Decodes a repeated boolean field. Returns the position after all read values. */
decodeBoolList( int tag, byte[] data, int position, int limit, ProtobufList<?> list, Registers registers)385   static int decodeBoolList(
386       int tag, byte[] data, int position, int limit, ProtobufList<?> list, Registers registers) {
387     final BooleanArrayList output = (BooleanArrayList) list;
388     position = decodeVarint64(data, position, registers);
389     output.addBoolean(registers.long1 != 0);
390     while (position < limit) {
391       int nextPosition = decodeVarint32(data, position, registers);
392       if (tag != registers.int1) {
393         break;
394       }
395       position = decodeVarint64(data, nextPosition, registers);
396       output.addBoolean(registers.long1 != 0);
397     }
398     return position;
399   }
400 
401   /** Decodes a repeated sint32 field. Returns the position after all read values. */
decodeSInt32List( int tag, byte[] data, int position, int limit, ProtobufList<?> list, Registers registers)402   static int decodeSInt32List(
403       int tag, byte[] data, int position, int limit, ProtobufList<?> list, Registers registers) {
404     final IntArrayList output = (IntArrayList) list;
405     position = decodeVarint32(data, position, registers);
406     output.addInt(CodedInputStream.decodeZigZag32(registers.int1));
407     while (position < limit) {
408       int nextPosition = decodeVarint32(data, position, registers);
409       if (tag != registers.int1) {
410         break;
411       }
412       position = decodeVarint32(data, nextPosition, registers);
413       output.addInt(CodedInputStream.decodeZigZag32(registers.int1));
414     }
415     return position;
416   }
417 
418   /** Decodes a repeated sint64 field. Returns the position after all read values. */
decodeSInt64List( int tag, byte[] data, int position, int limit, ProtobufList<?> list, Registers registers)419   static int decodeSInt64List(
420       int tag, byte[] data, int position, int limit, ProtobufList<?> list, Registers registers) {
421     final LongArrayList output = (LongArrayList) list;
422     position = decodeVarint64(data, position, registers);
423     output.addLong(CodedInputStream.decodeZigZag64(registers.long1));
424     while (position < limit) {
425       int nextPosition = decodeVarint32(data, position, registers);
426       if (tag != registers.int1) {
427         break;
428       }
429       position = decodeVarint64(data, nextPosition, registers);
430       output.addLong(CodedInputStream.decodeZigZag64(registers.long1));
431     }
432     return position;
433   }
434 
435   /** Decodes a packed 32-bit varint field. Returns the position after all read values. */
decodePackedVarint32List( byte[] data, int position, ProtobufList<?> list, Registers registers)436   static int decodePackedVarint32List(
437       byte[] data, int position, ProtobufList<?> list, Registers registers) throws IOException {
438     final IntArrayList output = (IntArrayList) list;
439     position = decodeVarint32(data, position, registers);
440     final int fieldLimit = position + registers.int1;
441     while (position < fieldLimit) {
442       position = decodeVarint32(data, position, registers);
443       output.addInt(registers.int1);
444     }
445     if (position != fieldLimit) {
446       throw InvalidProtocolBufferException.truncatedMessage();
447     }
448     return position;
449   }
450 
451   /** Decodes a packed 64-bit varint field. Returns the position after all read values. */
decodePackedVarint64List( byte[] data, int position, ProtobufList<?> list, Registers registers)452   static int decodePackedVarint64List(
453       byte[] data, int position, ProtobufList<?> list, Registers registers) throws IOException {
454     final LongArrayList output = (LongArrayList) list;
455     position = decodeVarint32(data, position, registers);
456     final int fieldLimit = position + registers.int1;
457     while (position < fieldLimit) {
458       position = decodeVarint64(data, position, registers);
459       output.addLong(registers.long1);
460     }
461     if (position != fieldLimit) {
462       throw InvalidProtocolBufferException.truncatedMessage();
463     }
464     return position;
465   }
466 
467   /** Decodes a packed fixed32 field. Returns the position after all read values. */
decodePackedFixed32List( byte[] data, int position, ProtobufList<?> list, Registers registers)468   static int decodePackedFixed32List(
469       byte[] data, int position, ProtobufList<?> list, Registers registers)
470       throws InvalidProtocolBufferException {
471     final IntArrayList output = (IntArrayList) list;
472     position = decodeVarint32(data, position, registers);
473     final int packedDataByteSize = registers.int1;
474     final int fieldLimit = position + packedDataByteSize;
475     if (fieldLimit > data.length) {
476       throw InvalidProtocolBufferException.truncatedMessage();
477     }
478     output.ensureCapacity(output.size() + packedDataByteSize / 4);
479     while (position < fieldLimit) {
480       output.addInt(decodeFixed32(data, position));
481       position += 4;
482     }
483     if (position != fieldLimit) {
484       throw InvalidProtocolBufferException.truncatedMessage();
485     }
486     return position;
487   }
488 
489   /** Decodes a packed fixed64 field. Returns the position after all read values. */
decodePackedFixed64List( byte[] data, int position, ProtobufList<?> list, Registers registers)490   static int decodePackedFixed64List(
491       byte[] data, int position, ProtobufList<?> list, Registers registers)
492       throws InvalidProtocolBufferException {
493     final LongArrayList output = (LongArrayList) list;
494     position = decodeVarint32(data, position, registers);
495     final int packedDataByteSize = registers.int1;
496     final int fieldLimit = position + packedDataByteSize;
497     if (fieldLimit > data.length) {
498       throw InvalidProtocolBufferException.truncatedMessage();
499     }
500     output.ensureCapacity(output.size() + packedDataByteSize / 8);
501     while (position < fieldLimit) {
502       output.addLong(decodeFixed64(data, position));
503       position += 8;
504     }
505     if (position != fieldLimit) {
506       throw InvalidProtocolBufferException.truncatedMessage();
507     }
508     return position;
509   }
510 
511   /** Decodes a packed float field. Returns the position after all read values. */
decodePackedFloatList( byte[] data, int position, ProtobufList<?> list, Registers registers)512   static int decodePackedFloatList(
513       byte[] data, int position, ProtobufList<?> list, Registers registers)
514       throws InvalidProtocolBufferException {
515     final FloatArrayList output = (FloatArrayList) list;
516     position = decodeVarint32(data, position, registers);
517     final int packedDataByteSize = registers.int1;
518     final int fieldLimit = position + packedDataByteSize;
519     if (fieldLimit > data.length) {
520       throw InvalidProtocolBufferException.truncatedMessage();
521     }
522     output.ensureCapacity(output.size() + packedDataByteSize / 4);
523     while (position < fieldLimit) {
524       output.addFloat(decodeFloat(data, position));
525       position += 4;
526     }
527     if (position != fieldLimit) {
528       throw InvalidProtocolBufferException.truncatedMessage();
529     }
530     return position;
531   }
532 
533   /** Decodes a packed double field. Returns the position after all read values. */
decodePackedDoubleList( byte[] data, int position, ProtobufList<?> list, Registers registers)534   static int decodePackedDoubleList(
535       byte[] data, int position, ProtobufList<?> list, Registers registers)
536       throws InvalidProtocolBufferException {
537     final DoubleArrayList output = (DoubleArrayList) list;
538     position = decodeVarint32(data, position, registers);
539     final int packedDataByteSize = registers.int1;
540     final int fieldLimit = position + packedDataByteSize;
541     if (fieldLimit > data.length) {
542       throw InvalidProtocolBufferException.truncatedMessage();
543     }
544     output.ensureCapacity(output.size() + packedDataByteSize / 8);
545     while (position < fieldLimit) {
546       output.addDouble(decodeDouble(data, position));
547       position += 8;
548     }
549     if (position != fieldLimit) {
550       throw InvalidProtocolBufferException.truncatedMessage();
551     }
552     return position;
553   }
554 
555   /** Decodes a packed boolean field. Returns the position after all read values. */
decodePackedBoolList( byte[] data, int position, ProtobufList<?> list, Registers registers)556   static int decodePackedBoolList(
557       byte[] data, int position, ProtobufList<?> list, Registers registers)
558       throws InvalidProtocolBufferException {
559     final BooleanArrayList output = (BooleanArrayList) list;
560     position = decodeVarint32(data, position, registers);
561     final int fieldLimit = position + registers.int1;
562     while (position < fieldLimit) {
563       position = decodeVarint64(data, position, registers);
564       output.addBoolean(registers.long1 != 0);
565     }
566     if (position != fieldLimit) {
567       throw InvalidProtocolBufferException.truncatedMessage();
568     }
569     return position;
570   }
571 
572   /** Decodes a packed sint32 field. Returns the position after all read values. */
decodePackedSInt32List( byte[] data, int position, ProtobufList<?> list, Registers registers)573   static int decodePackedSInt32List(
574       byte[] data, int position, ProtobufList<?> list, Registers registers)
575       throws InvalidProtocolBufferException {
576     final IntArrayList output = (IntArrayList) list;
577     position = decodeVarint32(data, position, registers);
578     final int fieldLimit = position + registers.int1;
579     while (position < fieldLimit) {
580       position = decodeVarint32(data, position, registers);
581       output.addInt(CodedInputStream.decodeZigZag32(registers.int1));
582     }
583     if (position != fieldLimit) {
584       throw InvalidProtocolBufferException.truncatedMessage();
585     }
586     return position;
587   }
588 
589   /** Decodes a packed sint64 field. Returns the position after all read values. */
decodePackedSInt64List( byte[] data, int position, ProtobufList<?> list, Registers registers)590   static int decodePackedSInt64List(
591       byte[] data, int position, ProtobufList<?> list, Registers registers)
592       throws InvalidProtocolBufferException {
593     final LongArrayList output = (LongArrayList) list;
594     position = decodeVarint32(data, position, registers);
595     final int fieldLimit = position + registers.int1;
596     while (position < fieldLimit) {
597       position = decodeVarint64(data, position, registers);
598       output.addLong(CodedInputStream.decodeZigZag64(registers.long1));
599     }
600     if (position != fieldLimit) {
601       throw InvalidProtocolBufferException.truncatedMessage();
602     }
603     return position;
604   }
605 
606   /** Decodes a repeated string field. Returns the position after all read values. */
607   @SuppressWarnings("unchecked")
decodeStringList( int tag, byte[] data, int position, int limit, ProtobufList<?> list, Registers registers)608   static int decodeStringList(
609       int tag, byte[] data, int position, int limit, ProtobufList<?> list, Registers registers)
610       throws InvalidProtocolBufferException {
611     final ProtobufList<String> output = (ProtobufList<String>) list;
612     position = decodeVarint32(data, position, registers);
613     final int length = registers.int1;
614     if (length < 0) {
615       throw InvalidProtocolBufferException.negativeSize();
616     } else if (length == 0) {
617       output.add("");
618     } else {
619       String value = new String(data, position, length, Internal.UTF_8);
620       output.add(value);
621       position += length;
622     }
623     while (position < limit) {
624       int nextPosition = decodeVarint32(data, position, registers);
625       if (tag != registers.int1) {
626         break;
627       }
628       position = decodeVarint32(data, nextPosition, registers);
629       final int nextLength = registers.int1;
630       if (nextLength < 0) {
631         throw InvalidProtocolBufferException.negativeSize();
632       } else if (nextLength == 0) {
633         output.add("");
634       } else {
635         String value = new String(data, position, nextLength, Internal.UTF_8);
636         output.add(value);
637         position += nextLength;
638       }
639     }
640     return position;
641   }
642 
643   /**
644    * Decodes a repeated string field with utf8 check. Returns the position after all read values.
645    */
646   @SuppressWarnings("unchecked")
decodeStringListRequireUtf8( int tag, byte[] data, int position, int limit, ProtobufList<?> list, Registers registers)647   static int decodeStringListRequireUtf8(
648       int tag, byte[] data, int position, int limit, ProtobufList<?> list, Registers registers)
649       throws InvalidProtocolBufferException {
650     final ProtobufList<String> output = (ProtobufList<String>) list;
651     position = decodeVarint32(data, position, registers);
652     final int length = registers.int1;
653     if (length < 0) {
654       throw InvalidProtocolBufferException.negativeSize();
655     } else if (length == 0) {
656       output.add("");
657     } else {
658       if (!Utf8.isValidUtf8(data, position, position + length)) {
659         throw InvalidProtocolBufferException.invalidUtf8();
660       }
661       String value = new String(data, position, length, Internal.UTF_8);
662       output.add(value);
663       position += length;
664     }
665     while (position < limit) {
666       int nextPosition = decodeVarint32(data, position, registers);
667       if (tag != registers.int1) {
668         break;
669       }
670       position = decodeVarint32(data, nextPosition, registers);
671       final int nextLength = registers.int1;
672       if (nextLength < 0) {
673         throw InvalidProtocolBufferException.negativeSize();
674       } else if (nextLength == 0) {
675         output.add("");
676       } else {
677         if (!Utf8.isValidUtf8(data, position, position + nextLength)) {
678           throw InvalidProtocolBufferException.invalidUtf8();
679         }
680         String value = new String(data, position, nextLength, Internal.UTF_8);
681         output.add(value);
682         position += nextLength;
683       }
684     }
685     return position;
686   }
687 
688   /** Decodes a repeated bytes field. Returns the position after all read values. */
689   @SuppressWarnings("unchecked")
decodeBytesList( int tag, byte[] data, int position, int limit, ProtobufList<?> list, Registers registers)690   static int decodeBytesList(
691       int tag, byte[] data, int position, int limit, ProtobufList<?> list, Registers registers)
692       throws InvalidProtocolBufferException {
693     final ProtobufList<ByteString> output = (ProtobufList<ByteString>) list;
694     position = decodeVarint32(data, position, registers);
695     final int length = registers.int1;
696     if (length < 0) {
697       throw InvalidProtocolBufferException.negativeSize();
698     } else if (length > data.length - position) {
699       throw InvalidProtocolBufferException.truncatedMessage();
700     } else if (length == 0) {
701       output.add(ByteString.EMPTY);
702     } else {
703       output.add(ByteString.copyFrom(data, position, length));
704       position += length;
705     }
706     while (position < limit) {
707       int nextPosition = decodeVarint32(data, position, registers);
708       if (tag != registers.int1) {
709         break;
710       }
711       position = decodeVarint32(data, nextPosition, registers);
712       final int nextLength = registers.int1;
713       if (nextLength < 0) {
714         throw InvalidProtocolBufferException.negativeSize();
715       } else if (nextLength > data.length - position) {
716         throw InvalidProtocolBufferException.truncatedMessage();
717       } else if (nextLength == 0) {
718         output.add(ByteString.EMPTY);
719       } else {
720         output.add(ByteString.copyFrom(data, position, nextLength));
721         position += nextLength;
722       }
723     }
724     return position;
725   }
726 
727   /**
728    * Decodes a repeated message field
729    *
730    * @return The position of after read all messages
731    */
732   @SuppressWarnings({"unchecked"})
decodeMessageList( Schema<?> schema, int tag, byte[] data, int position, int limit, ProtobufList<?> list, Registers registers)733   static int decodeMessageList(
734       Schema<?> schema,
735       int tag,
736       byte[] data,
737       int position,
738       int limit,
739       ProtobufList<?> list,
740       Registers registers)
741       throws IOException {
742     final ProtobufList<Object> output = (ProtobufList<Object>) list;
743     position = decodeMessageField(schema, data, position, limit, registers);
744     output.add(registers.object1);
745     while (position < limit) {
746       int nextPosition = decodeVarint32(data, position, registers);
747       if (tag != registers.int1) {
748         break;
749       }
750       position = decodeMessageField(schema, data, nextPosition, limit, registers);
751       output.add(registers.object1);
752     }
753     return position;
754   }
755 
756   /**
757    * Decodes a repeated group field
758    *
759    * @return The position of after read all groups
760    */
761   @SuppressWarnings({"unchecked", "rawtypes"})
decodeGroupList( Schema schema, int tag, byte[] data, int position, int limit, ProtobufList<?> list, Registers registers)762   static int decodeGroupList(
763       Schema schema,
764       int tag,
765       byte[] data,
766       int position,
767       int limit,
768       ProtobufList<?> list,
769       Registers registers)
770       throws IOException {
771     final ProtobufList<Object> output = (ProtobufList<Object>) list;
772     final int endgroup = (tag & ~0x7) | WireFormat.WIRETYPE_END_GROUP;
773     position = decodeGroupField(schema, data, position, limit, endgroup, registers);
774     output.add(registers.object1);
775     while (position < limit) {
776       int nextPosition = decodeVarint32(data, position, registers);
777       if (tag != registers.int1) {
778         break;
779       }
780       position = decodeGroupField(schema, data, nextPosition, limit, endgroup, registers);
781       output.add(registers.object1);
782     }
783     return position;
784   }
785 
decodeExtensionOrUnknownField( int tag, byte[] data, int position, int limit, Object message, MessageLite defaultInstance, UnknownFieldSchema<UnknownFieldSetLite, UnknownFieldSetLite> unknownFieldSchema, Registers registers)786   static int decodeExtensionOrUnknownField(
787       int tag, byte[] data, int position, int limit,
788       Object message,
789       MessageLite defaultInstance,
790       UnknownFieldSchema<UnknownFieldSetLite, UnknownFieldSetLite> unknownFieldSchema,
791       Registers registers)
792       throws IOException {
793     final int number = tag >>> 3;
794     GeneratedMessageLite.GeneratedExtension extension =
795         registers.extensionRegistry.findLiteExtensionByNumber(defaultInstance, number);
796     if (extension == null) {
797       return decodeUnknownField(
798           tag, data, position, limit, getMutableUnknownFields(message), registers);
799     } else  {
800       // TODO: remove the unused variable
801       FieldSet<ExtensionDescriptor> unused =
802           ((GeneratedMessageLite.ExtendableMessage<?, ?>) message).ensureExtensionsAreMutable();
803       return decodeExtension(
804           tag, data, position, limit, (GeneratedMessageLite.ExtendableMessage) message,
805           extension, unknownFieldSchema, registers);
806     }
807   }
808 
decodeExtension( int tag, byte[] data, int position, int limit, GeneratedMessageLite.ExtendableMessage<?, ?> message, GeneratedMessageLite.GeneratedExtension<?, ?> extension, UnknownFieldSchema<UnknownFieldSetLite, UnknownFieldSetLite> unknownFieldSchema, Registers registers)809   static int decodeExtension(
810       int tag,
811       byte[] data,
812       int position,
813       int limit,
814       GeneratedMessageLite.ExtendableMessage<?, ?> message,
815       GeneratedMessageLite.GeneratedExtension<?, ?> extension,
816       UnknownFieldSchema<UnknownFieldSetLite, UnknownFieldSetLite> unknownFieldSchema,
817       Registers registers)
818       throws IOException {
819     final FieldSet<GeneratedMessageLite.ExtensionDescriptor> extensions = message.extensions;
820     final int fieldNumber = tag >>> 3;
821     if (extension.descriptor.isRepeated() && extension.descriptor.isPacked()) {
822       switch (extension.getLiteType()) {
823         case DOUBLE:
824         {
825           DoubleArrayList list = new DoubleArrayList();
826           position = decodePackedDoubleList(data, position, list, registers);
827           extensions.setField(extension.descriptor, list);
828           break;
829         }
830         case FLOAT:
831         {
832           FloatArrayList list = new FloatArrayList();
833           position = decodePackedFloatList(data, position, list, registers);
834           extensions.setField(extension.descriptor, list);
835           break;
836         }
837         case INT64:
838         case UINT64:
839         {
840           LongArrayList list = new LongArrayList();
841           position = decodePackedVarint64List(data, position, list, registers);
842           extensions.setField(extension.descriptor, list);
843           break;
844         }
845         case INT32:
846         case UINT32:
847         {
848           IntArrayList list = new IntArrayList();
849           position = decodePackedVarint32List(data, position, list, registers);
850           extensions.setField(extension.descriptor, list);
851           break;
852         }
853         case FIXED64:
854         case SFIXED64:
855         {
856           LongArrayList list = new LongArrayList();
857           position = decodePackedFixed64List(data, position, list, registers);
858           extensions.setField(extension.descriptor, list);
859           break;
860         }
861         case FIXED32:
862         case SFIXED32:
863         {
864           IntArrayList list = new IntArrayList();
865           position = decodePackedFixed32List(data, position, list, registers);
866           extensions.setField(extension.descriptor, list);
867           break;
868         }
869         case BOOL:
870         {
871           BooleanArrayList list = new BooleanArrayList();
872           position = decodePackedBoolList(data, position, list, registers);
873           extensions.setField(extension.descriptor, list);
874           break;
875         }
876         case SINT32:
877         {
878           IntArrayList list = new IntArrayList();
879           position = decodePackedSInt32List(data, position, list, registers);
880           extensions.setField(extension.descriptor, list);
881           break;
882         }
883         case SINT64:
884         {
885           LongArrayList list = new LongArrayList();
886           position = decodePackedSInt64List(data, position, list, registers);
887           extensions.setField(extension.descriptor, list);
888           break;
889         }
890         case ENUM:
891           {
892             IntArrayList list = new IntArrayList();
893             position = decodePackedVarint32List(data, position, list, registers);
894             SchemaUtil.filterUnknownEnumList(
895                 message,
896                 fieldNumber,
897                 list,
898                 extension.descriptor.getEnumType(),
899                 null,
900                 unknownFieldSchema);
901             extensions.setField(extension.descriptor, list);
902             break;
903           }
904         default:
905           throw new IllegalStateException(
906               "Type cannot be packed: " + extension.descriptor.getLiteType());
907       }
908     } else {
909       Object value = null;
910       // Enum is a special case because unknown enum values will be put into UnknownFieldSetLite.
911       if (extension.getLiteType() == WireFormat.FieldType.ENUM) {
912         position = decodeVarint32(data, position, registers);
913         Object enumValue = extension.descriptor.getEnumType().findValueByNumber(registers.int1);
914         if (enumValue == null) {
915           SchemaUtil.storeUnknownEnum(
916               message, fieldNumber, registers.int1, null, unknownFieldSchema);
917           return position;
918         }
919         // Note, we store the integer value instead of the actual enum object in FieldSet.
920         // This is also different from full-runtime where we store EnumValueDescriptor.
921         value = registers.int1;
922       } else {
923         switch (extension.getLiteType()) {
924           case DOUBLE:
925             value = decodeDouble(data, position);
926             position += 8;
927             break;
928           case FLOAT:
929             value = decodeFloat(data, position);
930             position += 4;
931             break;
932           case INT64:
933           case UINT64:
934             position = decodeVarint64(data, position, registers);
935             value = registers.long1;
936             break;
937           case INT32:
938           case UINT32:
939             position = decodeVarint32(data, position, registers);
940             value = registers.int1;
941             break;
942           case FIXED64:
943           case SFIXED64:
944             value = decodeFixed64(data, position);
945             position += 8;
946             break;
947           case FIXED32:
948           case SFIXED32:
949             value = decodeFixed32(data, position);
950             position += 4;
951             break;
952           case BOOL:
953             position = decodeVarint64(data, position, registers);
954             value = (registers.long1 != 0);
955             break;
956           case BYTES:
957             position = decodeBytes(data, position, registers);
958             value = registers.object1;
959             break;
960           case SINT32:
961             position = decodeVarint32(data, position, registers);
962             value = CodedInputStream.decodeZigZag32(registers.int1);
963             break;
964           case SINT64:
965             position = decodeVarint64(data, position, registers);
966             value = CodedInputStream.decodeZigZag64(registers.long1);
967             break;
968           case STRING:
969             position = decodeString(data, position, registers);
970             value = registers.object1;
971             break;
972           case GROUP:
973             {
974               final int endTag = (fieldNumber << 3) | WireFormat.WIRETYPE_END_GROUP;
975               final Schema fieldSchema =
976                   Protobuf.getInstance()
977                       .schemaFor(extension.getMessageDefaultInstance().getClass());
978               if (extension.isRepeated()) {
979                 position = decodeGroupField(fieldSchema, data, position, limit, endTag, registers);
980                 extensions.addRepeatedField(extension.descriptor, registers.object1);
981               } else {
982                 Object oldValue = extensions.getField(extension.descriptor);
983                 if (oldValue == null) {
984                   oldValue = fieldSchema.newInstance();
985                   extensions.setField(extension.descriptor, oldValue);
986                 }
987                 position =
988                     mergeGroupField(
989                         oldValue, fieldSchema, data, position, limit, endTag, registers);
990               }
991               return position;
992             }
993           case MESSAGE:
994             {
995               final Schema fieldSchema =
996                   Protobuf.getInstance()
997                       .schemaFor(extension.getMessageDefaultInstance().getClass());
998               if (extension.isRepeated()) {
999                 position = decodeMessageField(fieldSchema, data, position, limit, registers);
1000                 extensions.addRepeatedField(extension.descriptor, registers.object1);
1001               } else {
1002                 Object oldValue = extensions.getField(extension.descriptor);
1003                 if (oldValue == null) {
1004                   oldValue = fieldSchema.newInstance();
1005                   extensions.setField(extension.descriptor, oldValue);
1006                 }
1007                 position =
1008                     mergeMessageField(oldValue, fieldSchema, data, position, limit, registers);
1009               }
1010               return position;
1011             }
1012           case ENUM:
1013             throw new IllegalStateException("Shouldn't reach here.");
1014         }
1015       }
1016       if (extension.isRepeated()) {
1017         extensions.addRepeatedField(extension.descriptor, value);
1018       } else {
1019         extensions.setField(extension.descriptor, value);
1020       }
1021     }
1022     return position;
1023   }
1024 
1025   /** Decodes an unknown field. */
decodeUnknownField( int tag, byte[] data, int position, int limit, UnknownFieldSetLite unknownFields, Registers registers)1026   static int decodeUnknownField(
1027       int tag,
1028       byte[] data,
1029       int position,
1030       int limit,
1031       UnknownFieldSetLite unknownFields,
1032       Registers registers)
1033       throws InvalidProtocolBufferException {
1034     if (WireFormat.getTagFieldNumber(tag) == 0) {
1035       throw InvalidProtocolBufferException.invalidTag();
1036     }
1037     switch (WireFormat.getTagWireType(tag)) {
1038       case WireFormat.WIRETYPE_VARINT:
1039         position = decodeVarint64(data, position, registers);
1040         unknownFields.storeField(tag, registers.long1);
1041         return position;
1042       case WireFormat.WIRETYPE_FIXED32:
1043         unknownFields.storeField(tag, decodeFixed32(data, position));
1044         return position + 4;
1045       case WireFormat.WIRETYPE_FIXED64:
1046         unknownFields.storeField(tag, decodeFixed64(data, position));
1047         return position + 8;
1048       case WireFormat.WIRETYPE_LENGTH_DELIMITED:
1049         position = decodeVarint32(data, position, registers);
1050         final int length = registers.int1;
1051         if (length < 0) {
1052           throw InvalidProtocolBufferException.negativeSize();
1053         } else if (length > data.length - position) {
1054           throw InvalidProtocolBufferException.truncatedMessage();
1055         } else if (length == 0) {
1056           unknownFields.storeField(tag, ByteString.EMPTY);
1057         } else {
1058           unknownFields.storeField(tag, ByteString.copyFrom(data, position, length));
1059         }
1060         return position + length;
1061       case WireFormat.WIRETYPE_START_GROUP:
1062         final UnknownFieldSetLite child = UnknownFieldSetLite.newInstance();
1063         final int endGroup = (tag & ~0x7) | WireFormat.WIRETYPE_END_GROUP;
1064         int lastTag = 0;
1065         registers.recursionDepth++;
1066         checkRecursionLimit(registers.recursionDepth);
1067         while (position < limit) {
1068           position = decodeVarint32(data, position, registers);
1069           lastTag = registers.int1;
1070           if (lastTag == endGroup) {
1071             break;
1072           }
1073           position = decodeUnknownField(lastTag, data, position, limit, child, registers);
1074         }
1075         registers.recursionDepth--;
1076         if (position > limit || lastTag != endGroup) {
1077           throw InvalidProtocolBufferException.parseFailure();
1078         }
1079         unknownFields.storeField(tag, child);
1080         return position;
1081       default:
1082         throw InvalidProtocolBufferException.invalidTag();
1083     }
1084   }
1085 
1086   /** Skips an unknown field. */
skipField(int tag, byte[] data, int position, int limit, Registers registers)1087   static int skipField(int tag, byte[] data, int position, int limit, Registers registers)
1088       throws InvalidProtocolBufferException {
1089     if (WireFormat.getTagFieldNumber(tag) == 0) {
1090       throw InvalidProtocolBufferException.invalidTag();
1091     }
1092     switch (WireFormat.getTagWireType(tag)) {
1093       case WireFormat.WIRETYPE_VARINT:
1094         position = decodeVarint64(data, position, registers);
1095         return position;
1096       case WireFormat.WIRETYPE_FIXED32:
1097         return position + 4;
1098       case WireFormat.WIRETYPE_FIXED64:
1099         return position + 8;
1100       case WireFormat.WIRETYPE_LENGTH_DELIMITED:
1101         position = decodeVarint32(data, position, registers);
1102         return position + registers.int1;
1103       case WireFormat.WIRETYPE_START_GROUP:
1104         final int endGroup = (tag & ~0x7) | WireFormat.WIRETYPE_END_GROUP;
1105         int lastTag = 0;
1106         while (position < limit) {
1107           position = decodeVarint32(data, position, registers);
1108           lastTag = registers.int1;
1109           if (lastTag == endGroup) {
1110             break;
1111           }
1112           position = skipField(lastTag, data, position, limit, registers);
1113         }
1114         if (position > limit || lastTag != endGroup) {
1115           throw InvalidProtocolBufferException.parseFailure();
1116         }
1117         return position;
1118       default:
1119         throw InvalidProtocolBufferException.invalidTag();
1120     }
1121   }
1122 
1123   /**
1124    * Set the maximum recursion limit that ArrayDecoders will allow. An exception will be thrown if
1125    * the depth of the message exceeds this limit.
1126    */
setRecursionLimit(int limit)1127   public static void setRecursionLimit(int limit) {
1128     recursionLimit = limit;
1129   }
1130 
checkRecursionLimit(int depth)1131   private static void checkRecursionLimit(int depth) throws InvalidProtocolBufferException {
1132     if (depth >= recursionLimit) {
1133       throw InvalidProtocolBufferException.recursionLimitExceeded();
1134     }
1135   }
1136 }
1137