• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc.  All rights reserved.
3 // https://developers.google.com/protocol-buffers/
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 //     * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 //     * Redistributions in binary form must reproduce the above
12 // copyright notice, this list of conditions and the following disclaimer
13 // in the documentation and/or other materials provided with the
14 // distribution.
15 //     * Neither the name of Google Inc. nor the names of its
16 // contributors may be used to endorse or promote products derived from
17 // this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 
31 package com.google.protobuf;
32 
33 import com.google.protobuf.FieldSet.FieldDescriptorLite;
34 import com.google.protobuf.Internal.EnumLiteMap;
35 import com.google.protobuf.Internal.EnumVerifier;
36 import java.io.IOException;
37 import java.lang.reflect.Field;
38 import java.util.Iterator;
39 import java.util.List;
40 import java.util.RandomAccess;
41 
42 /** Helper methods used by schemas. */
43 @ExperimentalApi
44 final class SchemaUtil {
45   private static final Class<?> GENERATED_MESSAGE_CLASS = getGeneratedMessageClass();
46   private static final UnknownFieldSchema<?, ?> PROTO2_UNKNOWN_FIELD_SET_SCHEMA =
47       getUnknownFieldSetSchema(false);
48   private static final UnknownFieldSchema<?, ?> PROTO3_UNKNOWN_FIELD_SET_SCHEMA =
49       getUnknownFieldSetSchema(true);
50   private static final UnknownFieldSchema<?, ?> UNKNOWN_FIELD_SET_LITE_SCHEMA =
51       new UnknownFieldSetLiteSchema();
52 
53   private static final int DEFAULT_LOOK_UP_START_NUMBER = 40;
54 
SchemaUtil()55   private SchemaUtil() {}
56 
57   /**
58    * Requires that the given message extend {@link com.google.protobuf.GeneratedMessageV3} or {@link
59    * GeneratedMessageLite}.
60    */
requireGeneratedMessage(Class<?> messageType)61   public static void requireGeneratedMessage(Class<?> messageType) {
62     // TODO(b/248560713) decide if we're keeping support for Full in schema classes and handle this
63     // better.
64     if (!GeneratedMessageLite.class.isAssignableFrom(messageType)
65         && GENERATED_MESSAGE_CLASS != null
66         && !GENERATED_MESSAGE_CLASS.isAssignableFrom(messageType)) {
67       throw new IllegalArgumentException(
68           "Message classes must extend GeneratedMessage or GeneratedMessageLite");
69     }
70   }
71 
writeDouble(int fieldNumber, double value, Writer writer)72   public static void writeDouble(int fieldNumber, double value, Writer writer) throws IOException {
73     if (Double.compare(value, 0.0) != 0) {
74       writer.writeDouble(fieldNumber, value);
75     }
76   }
77 
writeFloat(int fieldNumber, float value, Writer writer)78   public static void writeFloat(int fieldNumber, float value, Writer writer) throws IOException {
79     if (Float.compare(value, 0.0f) != 0) {
80       writer.writeFloat(fieldNumber, value);
81     }
82   }
83 
writeInt64(int fieldNumber, long value, Writer writer)84   public static void writeInt64(int fieldNumber, long value, Writer writer) throws IOException {
85     if (value != 0) {
86       writer.writeInt64(fieldNumber, value);
87     }
88   }
89 
writeUInt64(int fieldNumber, long value, Writer writer)90   public static void writeUInt64(int fieldNumber, long value, Writer writer) throws IOException {
91     if (value != 0) {
92       writer.writeUInt64(fieldNumber, value);
93     }
94   }
95 
writeSInt64(int fieldNumber, long value, Writer writer)96   public static void writeSInt64(int fieldNumber, long value, Writer writer) throws IOException {
97     if (value != 0) {
98       writer.writeSInt64(fieldNumber, value);
99     }
100   }
101 
writeFixed64(int fieldNumber, long value, Writer writer)102   public static void writeFixed64(int fieldNumber, long value, Writer writer) throws IOException {
103     if (value != 0) {
104       writer.writeFixed64(fieldNumber, value);
105     }
106   }
107 
writeSFixed64(int fieldNumber, long value, Writer writer)108   public static void writeSFixed64(int fieldNumber, long value, Writer writer) throws IOException {
109     if (value != 0) {
110       writer.writeSFixed64(fieldNumber, value);
111     }
112   }
113 
writeInt32(int fieldNumber, int value, Writer writer)114   public static void writeInt32(int fieldNumber, int value, Writer writer) throws IOException {
115     if (value != 0) {
116       writer.writeInt32(fieldNumber, value);
117     }
118   }
119 
writeUInt32(int fieldNumber, int value, Writer writer)120   public static void writeUInt32(int fieldNumber, int value, Writer writer) throws IOException {
121     if (value != 0) {
122       writer.writeUInt32(fieldNumber, value);
123     }
124   }
125 
writeSInt32(int fieldNumber, int value, Writer writer)126   public static void writeSInt32(int fieldNumber, int value, Writer writer) throws IOException {
127     if (value != 0) {
128       writer.writeSInt32(fieldNumber, value);
129     }
130   }
131 
writeFixed32(int fieldNumber, int value, Writer writer)132   public static void writeFixed32(int fieldNumber, int value, Writer writer) throws IOException {
133     if (value != 0) {
134       writer.writeFixed32(fieldNumber, value);
135     }
136   }
137 
writeSFixed32(int fieldNumber, int value, Writer writer)138   public static void writeSFixed32(int fieldNumber, int value, Writer writer) throws IOException {
139     if (value != 0) {
140       writer.writeSFixed32(fieldNumber, value);
141     }
142   }
143 
writeEnum(int fieldNumber, int value, Writer writer)144   public static void writeEnum(int fieldNumber, int value, Writer writer) throws IOException {
145     if (value != 0) {
146       writer.writeEnum(fieldNumber, value);
147     }
148   }
149 
writeBool(int fieldNumber, boolean value, Writer writer)150   public static void writeBool(int fieldNumber, boolean value, Writer writer) throws IOException {
151     if (value) {
152       writer.writeBool(fieldNumber, true);
153     }
154   }
155 
writeString(int fieldNumber, Object value, Writer writer)156   public static void writeString(int fieldNumber, Object value, Writer writer) throws IOException {
157     if (value instanceof String) {
158       writeStringInternal(fieldNumber, (String) value, writer);
159     } else {
160       writeBytes(fieldNumber, (ByteString) value, writer);
161     }
162   }
163 
writeStringInternal(int fieldNumber, String value, Writer writer)164   private static void writeStringInternal(int fieldNumber, String value, Writer writer)
165       throws IOException {
166     if (value != null && !value.isEmpty()) {
167       writer.writeString(fieldNumber, value);
168     }
169   }
170 
writeBytes(int fieldNumber, ByteString value, Writer writer)171   public static void writeBytes(int fieldNumber, ByteString value, Writer writer)
172       throws IOException {
173     if (value != null && !value.isEmpty()) {
174       writer.writeBytes(fieldNumber, value);
175     }
176   }
177 
writeMessage(int fieldNumber, Object value, Writer writer)178   public static void writeMessage(int fieldNumber, Object value, Writer writer) throws IOException {
179     if (value != null) {
180       writer.writeMessage(fieldNumber, value);
181     }
182   }
183 
writeDoubleList( int fieldNumber, List<Double> value, Writer writer, boolean packed)184   public static void writeDoubleList(
185       int fieldNumber, List<Double> value, Writer writer, boolean packed) throws IOException {
186     if (value != null && !value.isEmpty()) {
187       writer.writeDoubleList(fieldNumber, value, packed);
188     }
189   }
190 
writeFloatList( int fieldNumber, List<Float> value, Writer writer, boolean packed)191   public static void writeFloatList(
192       int fieldNumber, List<Float> value, Writer writer, boolean packed) throws IOException {
193     if (value != null && !value.isEmpty()) {
194       writer.writeFloatList(fieldNumber, value, packed);
195     }
196   }
197 
writeInt64List( int fieldNumber, List<Long> value, Writer writer, boolean packed)198   public static void writeInt64List(
199       int fieldNumber, List<Long> value, Writer writer, boolean packed) throws IOException {
200     if (value != null && !value.isEmpty()) {
201       writer.writeInt64List(fieldNumber, value, packed);
202     }
203   }
204 
writeUInt64List( int fieldNumber, List<Long> value, Writer writer, boolean packed)205   public static void writeUInt64List(
206       int fieldNumber, List<Long> value, Writer writer, boolean packed) throws IOException {
207     if (value != null && !value.isEmpty()) {
208       writer.writeUInt64List(fieldNumber, value, packed);
209     }
210   }
211 
writeSInt64List( int fieldNumber, List<Long> value, Writer writer, boolean packed)212   public static void writeSInt64List(
213       int fieldNumber, List<Long> value, Writer writer, boolean packed) throws IOException {
214     if (value != null && !value.isEmpty()) {
215       writer.writeSInt64List(fieldNumber, value, packed);
216     }
217   }
218 
writeFixed64List( int fieldNumber, List<Long> value, Writer writer, boolean packed)219   public static void writeFixed64List(
220       int fieldNumber, List<Long> value, Writer writer, boolean packed) throws IOException {
221     if (value != null && !value.isEmpty()) {
222       writer.writeFixed64List(fieldNumber, value, packed);
223     }
224   }
225 
writeSFixed64List( int fieldNumber, List<Long> value, Writer writer, boolean packed)226   public static void writeSFixed64List(
227       int fieldNumber, List<Long> value, Writer writer, boolean packed) throws IOException {
228     if (value != null && !value.isEmpty()) {
229       writer.writeSFixed64List(fieldNumber, value, packed);
230     }
231   }
232 
writeInt32List( int fieldNumber, List<Integer> value, Writer writer, boolean packed)233   public static void writeInt32List(
234       int fieldNumber, List<Integer> value, Writer writer, boolean packed) throws IOException {
235     if (value != null && !value.isEmpty()) {
236       writer.writeInt32List(fieldNumber, value, packed);
237     }
238   }
239 
writeUInt32List( int fieldNumber, List<Integer> value, Writer writer, boolean packed)240   public static void writeUInt32List(
241       int fieldNumber, List<Integer> value, Writer writer, boolean packed) throws IOException {
242     if (value != null && !value.isEmpty()) {
243       writer.writeUInt32List(fieldNumber, value, packed);
244     }
245   }
246 
writeSInt32List( int fieldNumber, List<Integer> value, Writer writer, boolean packed)247   public static void writeSInt32List(
248       int fieldNumber, List<Integer> value, Writer writer, boolean packed) throws IOException {
249     if (value != null && !value.isEmpty()) {
250       writer.writeSInt32List(fieldNumber, value, packed);
251     }
252   }
253 
writeFixed32List( int fieldNumber, List<Integer> value, Writer writer, boolean packed)254   public static void writeFixed32List(
255       int fieldNumber, List<Integer> value, Writer writer, boolean packed) throws IOException {
256     if (value != null && !value.isEmpty()) {
257       writer.writeFixed32List(fieldNumber, value, packed);
258     }
259   }
260 
writeSFixed32List( int fieldNumber, List<Integer> value, Writer writer, boolean packed)261   public static void writeSFixed32List(
262       int fieldNumber, List<Integer> value, Writer writer, boolean packed) throws IOException {
263     if (value != null && !value.isEmpty()) {
264       writer.writeSFixed32List(fieldNumber, value, packed);
265     }
266   }
267 
writeEnumList( int fieldNumber, List<Integer> value, Writer writer, boolean packed)268   public static void writeEnumList(
269       int fieldNumber, List<Integer> value, Writer writer, boolean packed) throws IOException {
270     if (value != null && !value.isEmpty()) {
271       writer.writeEnumList(fieldNumber, value, packed);
272     }
273   }
274 
writeBoolList( int fieldNumber, List<Boolean> value, Writer writer, boolean packed)275   public static void writeBoolList(
276       int fieldNumber, List<Boolean> value, Writer writer, boolean packed) throws IOException {
277     if (value != null && !value.isEmpty()) {
278       writer.writeBoolList(fieldNumber, value, packed);
279     }
280   }
281 
writeStringList(int fieldNumber, List<String> value, Writer writer)282   public static void writeStringList(int fieldNumber, List<String> value, Writer writer)
283       throws IOException {
284     if (value != null && !value.isEmpty()) {
285       writer.writeStringList(fieldNumber, value);
286     }
287   }
288 
writeBytesList(int fieldNumber, List<ByteString> value, Writer writer)289   public static void writeBytesList(int fieldNumber, List<ByteString> value, Writer writer)
290       throws IOException {
291     if (value != null && !value.isEmpty()) {
292       writer.writeBytesList(fieldNumber, value);
293     }
294   }
295 
writeMessageList(int fieldNumber, List<?> value, Writer writer)296   public static void writeMessageList(int fieldNumber, List<?> value, Writer writer)
297       throws IOException {
298     if (value != null && !value.isEmpty()) {
299       writer.writeMessageList(fieldNumber, value);
300     }
301   }
302 
writeMessageList(int fieldNumber, List<?> value, Writer writer, Schema schema)303   public static void writeMessageList(int fieldNumber, List<?> value, Writer writer, Schema schema)
304       throws IOException {
305     if (value != null && !value.isEmpty()) {
306       writer.writeMessageList(fieldNumber, value, schema);
307     }
308   }
309 
writeLazyFieldList(int fieldNumber, List<?> value, Writer writer)310   public static void writeLazyFieldList(int fieldNumber, List<?> value, Writer writer)
311       throws IOException {
312     if (value != null && !value.isEmpty()) {
313       for (Object item : value) {
314         ((LazyFieldLite) item).writeTo(writer, fieldNumber);
315       }
316     }
317   }
318 
writeGroupList(int fieldNumber, List<?> value, Writer writer)319   public static void writeGroupList(int fieldNumber, List<?> value, Writer writer)
320       throws IOException {
321     if (value != null && !value.isEmpty()) {
322       writer.writeGroupList(fieldNumber, value);
323     }
324   }
325 
writeGroupList(int fieldNumber, List<?> value, Writer writer, Schema schema)326   public static void writeGroupList(int fieldNumber, List<?> value, Writer writer, Schema schema)
327       throws IOException {
328     if (value != null && !value.isEmpty()) {
329       writer.writeGroupList(fieldNumber, value, schema);
330     }
331   }
332 
computeSizeInt64ListNoTag(List<Long> list)333   static int computeSizeInt64ListNoTag(List<Long> list) {
334     final int length = list.size();
335     if (length == 0) {
336       return 0;
337     }
338 
339     int size = 0;
340 
341     if (list instanceof LongArrayList) {
342       final LongArrayList primitiveList = (LongArrayList) list;
343       for (int i = 0; i < length; i++) {
344         size += CodedOutputStream.computeInt64SizeNoTag(primitiveList.getLong(i));
345       }
346     } else {
347       for (int i = 0; i < length; i++) {
348         size += CodedOutputStream.computeInt64SizeNoTag(list.get(i));
349       }
350     }
351     return size;
352   }
353 
computeSizeInt64List(int fieldNumber, List<Long> list, boolean packed)354   static int computeSizeInt64List(int fieldNumber, List<Long> list, boolean packed) {
355     final int length = list.size();
356     if (length == 0) {
357       return 0;
358     }
359     int size = computeSizeInt64ListNoTag(list);
360 
361     if (packed) {
362       return CodedOutputStream.computeTagSize(fieldNumber)
363           + CodedOutputStream.computeLengthDelimitedFieldSize(size);
364     } else {
365       return size + (list.size() * CodedOutputStream.computeTagSize(fieldNumber));
366     }
367   }
368 
computeSizeUInt64ListNoTag(List<Long> list)369   static int computeSizeUInt64ListNoTag(List<Long> list) {
370     final int length = list.size();
371     if (length == 0) {
372       return 0;
373     }
374 
375     int size = 0;
376 
377     if (list instanceof LongArrayList) {
378       final LongArrayList primitiveList = (LongArrayList) list;
379       for (int i = 0; i < length; i++) {
380         size += CodedOutputStream.computeUInt64SizeNoTag(primitiveList.getLong(i));
381       }
382     } else {
383       for (int i = 0; i < length; i++) {
384         size += CodedOutputStream.computeUInt64SizeNoTag(list.get(i));
385       }
386     }
387     return size;
388   }
389 
computeSizeUInt64List(int fieldNumber, List<Long> list, boolean packed)390   static int computeSizeUInt64List(int fieldNumber, List<Long> list, boolean packed) {
391     final int length = list.size();
392     if (length == 0) {
393       return 0;
394     }
395     int size = computeSizeUInt64ListNoTag(list);
396 
397     if (packed) {
398       return CodedOutputStream.computeTagSize(fieldNumber)
399           + CodedOutputStream.computeLengthDelimitedFieldSize(size);
400     } else {
401       return size + (length * CodedOutputStream.computeTagSize(fieldNumber));
402     }
403   }
404 
computeSizeSInt64ListNoTag(List<Long> list)405   static int computeSizeSInt64ListNoTag(List<Long> list) {
406     final int length = list.size();
407     if (length == 0) {
408       return 0;
409     }
410 
411     int size = 0;
412 
413     if (list instanceof LongArrayList) {
414       final LongArrayList primitiveList = (LongArrayList) list;
415       for (int i = 0; i < length; i++) {
416         size += CodedOutputStream.computeSInt64SizeNoTag(primitiveList.getLong(i));
417       }
418     } else {
419       for (int i = 0; i < length; i++) {
420         size += CodedOutputStream.computeSInt64SizeNoTag(list.get(i));
421       }
422     }
423     return size;
424   }
425 
computeSizeSInt64List(int fieldNumber, List<Long> list, boolean packed)426   static int computeSizeSInt64List(int fieldNumber, List<Long> list, boolean packed) {
427     final int length = list.size();
428     if (length == 0) {
429       return 0;
430     }
431     int size = computeSizeSInt64ListNoTag(list);
432 
433     if (packed) {
434       return CodedOutputStream.computeTagSize(fieldNumber)
435           + CodedOutputStream.computeLengthDelimitedFieldSize(size);
436     } else {
437       return size + (length * CodedOutputStream.computeTagSize(fieldNumber));
438     }
439   }
440 
computeSizeEnumListNoTag(List<Integer> list)441   static int computeSizeEnumListNoTag(List<Integer> list) {
442     final int length = list.size();
443     if (length == 0) {
444       return 0;
445     }
446 
447     int size = 0;
448 
449     if (list instanceof IntArrayList) {
450       final IntArrayList primitiveList = (IntArrayList) list;
451       for (int i = 0; i < length; i++) {
452         size += CodedOutputStream.computeEnumSizeNoTag(primitiveList.getInt(i));
453       }
454     } else {
455       for (int i = 0; i < length; i++) {
456         size += CodedOutputStream.computeEnumSizeNoTag(list.get(i));
457       }
458     }
459     return size;
460   }
461 
computeSizeEnumList(int fieldNumber, List<Integer> list, boolean packed)462   static int computeSizeEnumList(int fieldNumber, List<Integer> list, boolean packed) {
463     final int length = list.size();
464     if (length == 0) {
465       return 0;
466     }
467     int size = computeSizeEnumListNoTag(list);
468 
469     if (packed) {
470       return CodedOutputStream.computeTagSize(fieldNumber)
471           + CodedOutputStream.computeLengthDelimitedFieldSize(size);
472     } else {
473       return size + (length * CodedOutputStream.computeTagSize(fieldNumber));
474     }
475   }
476 
computeSizeInt32ListNoTag(List<Integer> list)477   static int computeSizeInt32ListNoTag(List<Integer> list) {
478     final int length = list.size();
479     if (length == 0) {
480       return 0;
481     }
482 
483     int size = 0;
484 
485     if (list instanceof IntArrayList) {
486       final IntArrayList primitiveList = (IntArrayList) list;
487       for (int i = 0; i < length; i++) {
488         size += CodedOutputStream.computeInt32SizeNoTag(primitiveList.getInt(i));
489       }
490     } else {
491       for (int i = 0; i < length; i++) {
492         size += CodedOutputStream.computeInt32SizeNoTag(list.get(i));
493       }
494     }
495     return size;
496   }
497 
computeSizeInt32List(int fieldNumber, List<Integer> list, boolean packed)498   static int computeSizeInt32List(int fieldNumber, List<Integer> list, boolean packed) {
499     final int length = list.size();
500     if (length == 0) {
501       return 0;
502     }
503     int size = computeSizeInt32ListNoTag(list);
504 
505     if (packed) {
506       return CodedOutputStream.computeTagSize(fieldNumber)
507           + CodedOutputStream.computeLengthDelimitedFieldSize(size);
508     } else {
509       return size + (length * CodedOutputStream.computeTagSize(fieldNumber));
510     }
511   }
512 
computeSizeUInt32ListNoTag(List<Integer> list)513   static int computeSizeUInt32ListNoTag(List<Integer> list) {
514     final int length = list.size();
515     if (length == 0) {
516       return 0;
517     }
518 
519     int size = 0;
520 
521     if (list instanceof IntArrayList) {
522       final IntArrayList primitiveList = (IntArrayList) list;
523       for (int i = 0; i < length; i++) {
524         size += CodedOutputStream.computeUInt32SizeNoTag(primitiveList.getInt(i));
525       }
526     } else {
527       for (int i = 0; i < length; i++) {
528         size += CodedOutputStream.computeUInt32SizeNoTag(list.get(i));
529       }
530     }
531     return size;
532   }
533 
computeSizeUInt32List(int fieldNumber, List<Integer> list, boolean packed)534   static int computeSizeUInt32List(int fieldNumber, List<Integer> list, boolean packed) {
535     final int length = list.size();
536     if (length == 0) {
537       return 0;
538     }
539     int size = computeSizeUInt32ListNoTag(list);
540 
541     if (packed) {
542       return CodedOutputStream.computeTagSize(fieldNumber)
543           + CodedOutputStream.computeLengthDelimitedFieldSize(size);
544     } else {
545       return size + (length * CodedOutputStream.computeTagSize(fieldNumber));
546     }
547   }
548 
computeSizeSInt32ListNoTag(List<Integer> list)549   static int computeSizeSInt32ListNoTag(List<Integer> list) {
550     final int length = list.size();
551     if (length == 0) {
552       return 0;
553     }
554 
555     int size = 0;
556 
557     if (list instanceof IntArrayList) {
558       final IntArrayList primitiveList = (IntArrayList) list;
559       for (int i = 0; i < length; i++) {
560         size += CodedOutputStream.computeSInt32SizeNoTag(primitiveList.getInt(i));
561       }
562     } else {
563       for (int i = 0; i < length; i++) {
564         size += CodedOutputStream.computeSInt32SizeNoTag(list.get(i));
565       }
566     }
567     return size;
568   }
569 
computeSizeSInt32List(int fieldNumber, List<Integer> list, boolean packed)570   static int computeSizeSInt32List(int fieldNumber, List<Integer> list, boolean packed) {
571     final int length = list.size();
572     if (length == 0) {
573       return 0;
574     }
575 
576     int size = computeSizeSInt32ListNoTag(list);
577 
578     if (packed) {
579       return CodedOutputStream.computeTagSize(fieldNumber)
580           + CodedOutputStream.computeLengthDelimitedFieldSize(size);
581     } else {
582       return size + (length * CodedOutputStream.computeTagSize(fieldNumber));
583     }
584   }
585 
computeSizeFixed32ListNoTag(List<?> list)586   static int computeSizeFixed32ListNoTag(List<?> list) {
587     return list.size() * WireFormat.FIXED32_SIZE;
588   }
589 
computeSizeFixed32List(int fieldNumber, List<?> list, boolean packed)590   static int computeSizeFixed32List(int fieldNumber, List<?> list, boolean packed) {
591     final int length = list.size();
592     if (length == 0) {
593       return 0;
594     }
595     if (packed) {
596       int dataSize = length * WireFormat.FIXED32_SIZE;
597       return CodedOutputStream.computeTagSize(fieldNumber)
598           + CodedOutputStream.computeLengthDelimitedFieldSize(dataSize);
599     } else {
600       return length * CodedOutputStream.computeFixed32Size(fieldNumber, 0);
601     }
602   }
603 
computeSizeFixed64ListNoTag(List<?> list)604   static int computeSizeFixed64ListNoTag(List<?> list) {
605     return list.size() * WireFormat.FIXED64_SIZE;
606   }
607 
computeSizeFixed64List(int fieldNumber, List<?> list, boolean packed)608   static int computeSizeFixed64List(int fieldNumber, List<?> list, boolean packed) {
609     final int length = list.size();
610     if (length == 0) {
611       return 0;
612     }
613     if (packed) {
614       final int dataSize = length * WireFormat.FIXED64_SIZE;
615       return CodedOutputStream.computeTagSize(fieldNumber)
616           + CodedOutputStream.computeLengthDelimitedFieldSize(dataSize);
617     } else {
618       return length * CodedOutputStream.computeFixed64Size(fieldNumber, 0);
619     }
620   }
621 
computeSizeBoolListNoTag(List<?> list)622   static int computeSizeBoolListNoTag(List<?> list) {
623     // bools are 1 byte varints
624     return list.size();
625   }
626 
computeSizeBoolList(int fieldNumber, List<?> list, boolean packed)627   static int computeSizeBoolList(int fieldNumber, List<?> list, boolean packed) {
628     final int length = list.size();
629     if (length == 0) {
630       return 0;
631     }
632     if (packed) {
633       // bools are 1 byte varints
634       return CodedOutputStream.computeTagSize(fieldNumber)
635           + CodedOutputStream.computeLengthDelimitedFieldSize(length);
636     } else {
637       return length * CodedOutputStream.computeBoolSize(fieldNumber, true);
638     }
639   }
640 
computeSizeStringList(int fieldNumber, List<?> list)641   static int computeSizeStringList(int fieldNumber, List<?> list) {
642     final int length = list.size();
643     if (length == 0) {
644       return 0;
645     }
646     int size = length * CodedOutputStream.computeTagSize(fieldNumber);
647     if (list instanceof LazyStringList) {
648       LazyStringList lazyList = ((LazyStringList) list);
649       for (int i = 0; i < length; i++) {
650         Object value = lazyList.getRaw(i);
651         if (value instanceof ByteString) {
652           size += CodedOutputStream.computeBytesSizeNoTag((ByteString) value);
653         } else {
654           size += CodedOutputStream.computeStringSizeNoTag((String) value);
655         }
656       }
657     } else {
658       for (int i = 0; i < length; i++) {
659         Object value = list.get(i);
660         if (value instanceof ByteString) {
661           size += CodedOutputStream.computeBytesSizeNoTag((ByteString) value);
662         } else {
663           size += CodedOutputStream.computeStringSizeNoTag((String) value);
664         }
665       }
666     }
667     return size;
668   }
669 
computeSizeMessage(int fieldNumber, Object value, Schema schema)670   static int computeSizeMessage(int fieldNumber, Object value, Schema schema) {
671     if (value instanceof LazyFieldLite) {
672       return CodedOutputStream.computeLazyFieldSize(fieldNumber, (LazyFieldLite) value);
673     } else {
674       return CodedOutputStream.computeMessageSize(fieldNumber, (MessageLite) value, schema);
675     }
676   }
677 
computeSizeMessageList(int fieldNumber, List<?> list)678   static int computeSizeMessageList(int fieldNumber, List<?> list) {
679     final int length = list.size();
680     if (length == 0) {
681       return 0;
682     }
683     int size = length * CodedOutputStream.computeTagSize(fieldNumber);
684     for (int i = 0; i < length; i++) {
685       Object value = list.get(i);
686       if (value instanceof LazyFieldLite) {
687         size += CodedOutputStream.computeLazyFieldSizeNoTag((LazyFieldLite) value);
688       } else {
689         size += CodedOutputStream.computeMessageSizeNoTag((MessageLite) value);
690       }
691     }
692     return size;
693   }
694 
computeSizeMessageList(int fieldNumber, List<?> list, Schema schema)695   static int computeSizeMessageList(int fieldNumber, List<?> list, Schema schema) {
696     final int length = list.size();
697     if (length == 0) {
698       return 0;
699     }
700     int size = length * CodedOutputStream.computeTagSize(fieldNumber);
701     for (int i = 0; i < length; i++) {
702       Object value = list.get(i);
703       if (value instanceof LazyFieldLite) {
704         size += CodedOutputStream.computeLazyFieldSizeNoTag((LazyFieldLite) value);
705       } else {
706         size += CodedOutputStream.computeMessageSizeNoTag((MessageLite) value, schema);
707       }
708     }
709     return size;
710   }
711 
computeSizeByteStringList(int fieldNumber, List<ByteString> list)712   static int computeSizeByteStringList(int fieldNumber, List<ByteString> list) {
713     final int length = list.size();
714     if (length == 0) {
715       return 0;
716     }
717     int size = length * CodedOutputStream.computeTagSize(fieldNumber);
718     for (int i = 0; i < list.size(); i++) {
719       size += CodedOutputStream.computeBytesSizeNoTag(list.get(i));
720     }
721     return size;
722   }
723 
computeSizeGroupList(int fieldNumber, List<MessageLite> list)724   static int computeSizeGroupList(int fieldNumber, List<MessageLite> list) {
725     final int length = list.size();
726     if (length == 0) {
727       return 0;
728     }
729     int size = 0;
730     for (int i = 0; i < length; i++) {
731       size += CodedOutputStream.computeGroupSize(fieldNumber, list.get(i));
732     }
733     return size;
734   }
735 
computeSizeGroupList(int fieldNumber, List<MessageLite> list, Schema schema)736   static int computeSizeGroupList(int fieldNumber, List<MessageLite> list, Schema schema) {
737     final int length = list.size();
738     if (length == 0) {
739       return 0;
740     }
741     int size = 0;
742     for (int i = 0; i < length; i++) {
743       size += CodedOutputStream.computeGroupSize(fieldNumber, list.get(i), schema);
744     }
745     return size;
746   }
747 
748   /**
749    * Determines whether to issue tableswitch or lookupswitch for the mergeFrom method.
750    *
751    * @see #shouldUseTableSwitch(int, int, int)
752    */
shouldUseTableSwitch(FieldInfo[] fields)753   public static boolean shouldUseTableSwitch(FieldInfo[] fields) {
754     // Determine whether to issue a tableswitch or a lookupswitch
755     // instruction.
756     if (fields.length == 0) {
757       return false;
758     }
759 
760     int lo = fields[0].getFieldNumber();
761     int hi = fields[fields.length - 1].getFieldNumber();
762     return shouldUseTableSwitch(lo, hi, fields.length);
763   }
764 
765   /**
766    * Determines whether to issue tableswitch or lookupswitch for the mergeFrom method. This is based
767    * on the <a href=
768    * "http://hg.openjdk.java.net/jdk8/jdk8/langtools/file/30db5e0aaf83/src/share/classes/com/sun/tools/javac/jvm/Gen.java#l1159">
769    * logic in the JDK</a>.
770    *
771    * @param lo the lowest fieldNumber contained within the message.
772    * @param hi the highest fieldNumber contained within the message.
773    * @param numFields the total number of fields in the message.
774    * @return {@code true} if tableswitch should be used, rather than lookupswitch.
775    */
shouldUseTableSwitch(int lo, int hi, int numFields)776   public static boolean shouldUseTableSwitch(int lo, int hi, int numFields) {
777     if (hi < DEFAULT_LOOK_UP_START_NUMBER) {
778       return true;
779     }
780     long tableSpaceCost = ((long) hi - lo + 1); // words
781     long tableTimeCost = 3; // comparisons
782     long lookupSpaceCost = 3 + 2 * (long) numFields;
783     long lookupTimeCost = 3 + (long) numFields;
784     return tableSpaceCost + 3 * tableTimeCost <= lookupSpaceCost + 3 * lookupTimeCost;
785   }
786 
proto2UnknownFieldSetSchema()787   public static UnknownFieldSchema<?, ?> proto2UnknownFieldSetSchema() {
788     return PROTO2_UNKNOWN_FIELD_SET_SCHEMA;
789   }
790 
proto3UnknownFieldSetSchema()791   public static UnknownFieldSchema<?, ?> proto3UnknownFieldSetSchema() {
792     return PROTO3_UNKNOWN_FIELD_SET_SCHEMA;
793   }
794 
unknownFieldSetLiteSchema()795   public static UnknownFieldSchema<?, ?> unknownFieldSetLiteSchema() {
796     return UNKNOWN_FIELD_SET_LITE_SCHEMA;
797   }
798 
getUnknownFieldSetSchema(boolean proto3)799   private static UnknownFieldSchema<?, ?> getUnknownFieldSetSchema(boolean proto3) {
800     try {
801       Class<?> clz = getUnknownFieldSetSchemaClass();
802       if (clz == null) {
803         return null;
804       }
805       return (UnknownFieldSchema) clz.getConstructor(boolean.class).newInstance(proto3);
806     } catch (Throwable t) {
807       return null;
808     }
809   }
810 
getGeneratedMessageClass()811   private static Class<?> getGeneratedMessageClass() {
812     try {
813       // TODO(b/248560713) decide if we're keeping support for Full in schema classes and handle
814       // this better.
815       return Class.forName("com.google.protobuf.GeneratedMessageV3");
816     } catch (Throwable e) {
817       return null;
818     }
819   }
820 
getUnknownFieldSetSchemaClass()821   private static Class<?> getUnknownFieldSetSchemaClass() {
822     try {
823       return Class.forName("com.google.protobuf.UnknownFieldSetSchema");
824     } catch (Throwable e) {
825       return null;
826     }
827   }
828 
getMapDefaultEntry(Class<?> clazz, String name)829   static Object getMapDefaultEntry(Class<?> clazz, String name) {
830     try {
831       Class<?> holder =
832           Class.forName(clazz.getName() + "$" + toCamelCase(name, true) + "DefaultEntryHolder");
833       Field[] fields = holder.getDeclaredFields();
834       if (fields.length != 1) {
835         throw new IllegalStateException(
836             "Unable to look up map field default entry holder class for "
837                 + name
838                 + " in "
839                 + clazz.getName());
840       }
841       return UnsafeUtil.getStaticObject(fields[0]);
842     } catch (Throwable t) {
843       throw new RuntimeException(t);
844     }
845   }
846 
toCamelCase(String name, boolean capNext)847   static String toCamelCase(String name, boolean capNext) {
848     StringBuilder sb = new StringBuilder();
849     for (int i = 0; i < name.length(); ++i) {
850       char c = name.charAt(i);
851       // Matches protoc field name function:
852       if ('a' <= c && c <= 'z') {
853         if (capNext) {
854           sb.append((char) (c + ('A' - 'a')));
855         } else {
856           sb.append(c);
857         }
858         capNext = false;
859       } else if ('A' <= c && c <= 'Z') {
860         if (i == 0 && !capNext) {
861           // Force first letter to lower-case unless explicitly told to capitalize it.
862           sb.append((char) (c - ('A' - 'a')));
863         } else {
864           sb.append(c);
865         }
866         capNext = false;
867       } else if ('0' <= c && c <= '9') {
868         sb.append(c);
869         capNext = true;
870       } else {
871         capNext = true;
872       }
873     }
874     return sb.toString();
875   }
876 
877   /** Returns true if both are null or both are {@link Object#equals}. */
safeEquals(Object a, Object b)878   static boolean safeEquals(Object a, Object b) {
879     return a == b || (a != null && a.equals(b));
880   }
881 
mergeMap(MapFieldSchema mapFieldSchema, T message, T o, long offset)882   static <T> void mergeMap(MapFieldSchema mapFieldSchema, T message, T o, long offset) {
883     Object merged =
884         mapFieldSchema.mergeFrom(
885             UnsafeUtil.getObject(message, offset), UnsafeUtil.getObject(o, offset));
886     UnsafeUtil.putObject(message, offset, merged);
887   }
888 
mergeExtensions( ExtensionSchema<FT> schema, T message, T other)889   static <T, FT extends FieldDescriptorLite<FT>> void mergeExtensions(
890       ExtensionSchema<FT> schema, T message, T other) {
891     FieldSet<FT> otherExtensions = schema.getExtensions(other);
892     if (!otherExtensions.isEmpty()) {
893       FieldSet<FT> messageExtensions = schema.getMutableExtensions(message);
894       messageExtensions.mergeFrom(otherExtensions);
895     }
896   }
897 
mergeUnknownFields( UnknownFieldSchema<UT, UB> schema, T message, T other)898   static <T, UT, UB> void mergeUnknownFields(
899       UnknownFieldSchema<UT, UB> schema, T message, T other) {
900     UT messageUnknowns = schema.getFromMessage(message);
901     UT otherUnknowns = schema.getFromMessage(other);
902     UT merged = schema.merge(messageUnknowns, otherUnknowns);
903     schema.setToMessage(message, merged);
904   }
905 
906   /** Filters unrecognized enum values in a list. */
filterUnknownEnumList( Object containerMessage, int number, List<Integer> enumList, EnumLiteMap<?> enumMap, UB unknownFields, UnknownFieldSchema<UT, UB> unknownFieldSchema)907   static <UT, UB> UB filterUnknownEnumList(
908       Object containerMessage,
909       int number,
910       List<Integer> enumList,
911       EnumLiteMap<?> enumMap,
912       UB unknownFields,
913       UnknownFieldSchema<UT, UB> unknownFieldSchema) {
914     if (enumMap == null) {
915       return unknownFields;
916     }
917     // TODO(dweis): Specialize for IntArrayList to avoid boxing.
918     if (enumList instanceof RandomAccess) {
919       int writePos = 0;
920       int size = enumList.size();
921       for (int readPos = 0; readPos < size; ++readPos) {
922         int enumValue = enumList.get(readPos);
923         if (enumMap.findValueByNumber(enumValue) != null) {
924           if (readPos != writePos) {
925             enumList.set(writePos, enumValue);
926           }
927           ++writePos;
928         } else {
929           unknownFields =
930               storeUnknownEnum(
931                   containerMessage, number, enumValue, unknownFields, unknownFieldSchema);
932         }
933       }
934       if (writePos != size) {
935         enumList.subList(writePos, size).clear();
936       }
937     } else {
938       for (Iterator<Integer> it = enumList.iterator(); it.hasNext(); ) {
939         int enumValue = it.next();
940         if (enumMap.findValueByNumber(enumValue) == null) {
941           unknownFields =
942               storeUnknownEnum(
943                   containerMessage, number, enumValue, unknownFields, unknownFieldSchema);
944           it.remove();
945         }
946       }
947     }
948     return unknownFields;
949   }
950 
951   /** Filters unrecognized enum values in a list. */
filterUnknownEnumList( Object containerMessage, int number, List<Integer> enumList, EnumVerifier enumVerifier, UB unknownFields, UnknownFieldSchema<UT, UB> unknownFieldSchema)952   static <UT, UB> UB filterUnknownEnumList(
953       Object containerMessage,
954       int number,
955       List<Integer> enumList,
956       EnumVerifier enumVerifier,
957       UB unknownFields,
958       UnknownFieldSchema<UT, UB> unknownFieldSchema) {
959     if (enumVerifier == null) {
960       return unknownFields;
961     }
962     // TODO(dweis): Specialize for IntArrayList to avoid boxing.
963     if (enumList instanceof RandomAccess) {
964       int writePos = 0;
965       int size = enumList.size();
966       for (int readPos = 0; readPos < size; ++readPos) {
967         int enumValue = enumList.get(readPos);
968         if (enumVerifier.isInRange(enumValue)) {
969           if (readPos != writePos) {
970             enumList.set(writePos, enumValue);
971           }
972           ++writePos;
973         } else {
974           unknownFields =
975               storeUnknownEnum(
976                   containerMessage, number, enumValue, unknownFields, unknownFieldSchema);
977         }
978       }
979       if (writePos != size) {
980         enumList.subList(writePos, size).clear();
981       }
982     } else {
983       for (Iterator<Integer> it = enumList.iterator(); it.hasNext(); ) {
984         int enumValue = it.next();
985         if (!enumVerifier.isInRange(enumValue)) {
986           unknownFields =
987               storeUnknownEnum(
988                   containerMessage, number, enumValue, unknownFields, unknownFieldSchema);
989           it.remove();
990         }
991       }
992     }
993     return unknownFields;
994   }
995 
996   /** Stores an unrecognized enum value as an unknown value. */
storeUnknownEnum( Object containerMessage, int number, int enumValue, UB unknownFields, UnknownFieldSchema<UT, UB> unknownFieldSchema)997   static <UT, UB> UB storeUnknownEnum(
998       Object containerMessage,
999       int number,
1000       int enumValue,
1001       UB unknownFields,
1002       UnknownFieldSchema<UT, UB> unknownFieldSchema) {
1003     if (unknownFields == null) {
1004       unknownFields = unknownFieldSchema.getBuilderFromMessage(containerMessage);
1005     }
1006     unknownFieldSchema.addVarint(unknownFields, number, enumValue);
1007     return unknownFields;
1008   }
1009 }
1010