1 | // Protocol Buffers - Google's data interchange format |
---|
2 | // Copyright 2008 Google Inc. All rights reserved. |
---|
3 | // http://code.google.com/p/protobuf/ |
---|
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.AbstractMessageLite.Builder.LimitedInputStream; |
---|
34 | |
---|
35 | import java.io.IOException; |
---|
36 | import java.io.InputStream; |
---|
37 | import java.io.OutputStream; |
---|
38 | import java.util.ArrayList; |
---|
39 | import java.util.Arrays; |
---|
40 | import java.util.Collections; |
---|
41 | import java.util.List; |
---|
42 | import java.util.Map; |
---|
43 | import java.util.TreeMap; |
---|
44 | |
---|
45 | /** |
---|
46 | * {@code UnknownFieldSet} is used to keep track of fields which were seen when |
---|
47 | * parsing a protocol message but whose field numbers or types are unrecognized. |
---|
48 | * This most frequently occurs when new fields are added to a message type |
---|
49 | * and then messages containing those feilds are read by old software that was |
---|
50 | * compiled before the new types were added. |
---|
51 | * |
---|
52 | * <p>Every {@link Message} contains an {@code UnknownFieldSet} (and every |
---|
53 | * {@link Message.Builder} contains an {@link Builder}). |
---|
54 | * |
---|
55 | * <p>Most users will never need to use this class. |
---|
56 | * |
---|
57 | * @author kenton@google.com Kenton Varda |
---|
58 | */ |
---|
59 | public final class UnknownFieldSet implements MessageLite { |
---|
60 | private UnknownFieldSet() {} |
---|
61 | |
---|
62 | /** Create a new {@link Builder}. */ |
---|
63 | public static Builder newBuilder() { |
---|
64 | return Builder.create(); |
---|
65 | } |
---|
66 | |
---|
67 | /** |
---|
68 | * Create a new {@link Builder} and initialize it to be a copy |
---|
69 | * of {@code copyFrom}. |
---|
70 | */ |
---|
71 | public static Builder newBuilder(final UnknownFieldSet copyFrom) { |
---|
72 | return newBuilder().mergeFrom(copyFrom); |
---|
73 | } |
---|
74 | |
---|
75 | /** Get an empty {@code UnknownFieldSet}. */ |
---|
76 | public static UnknownFieldSet getDefaultInstance() { |
---|
77 | return defaultInstance; |
---|
78 | } |
---|
79 | public UnknownFieldSet getDefaultInstanceForType() { |
---|
80 | return defaultInstance; |
---|
81 | } |
---|
82 | private static final UnknownFieldSet defaultInstance = |
---|
83 | new UnknownFieldSet(Collections.<Integer, Field>emptyMap()); |
---|
84 | |
---|
85 | /** |
---|
86 | * Construct an {@code UnknownFieldSet} around the given map. The map is |
---|
87 | * expected to be immutable. |
---|
88 | */ |
---|
89 | private UnknownFieldSet(final Map<Integer, Field> fields) { |
---|
90 | this.fields = fields; |
---|
91 | } |
---|
92 | private Map<Integer, Field> fields; |
---|
93 | |
---|
94 | @Override |
---|
95 | public boolean equals(final Object other) { |
---|
96 | if (this == other) { |
---|
97 | return true; |
---|
98 | } |
---|
99 | return (other instanceof UnknownFieldSet) && |
---|
100 | fields.equals(((UnknownFieldSet) other).fields); |
---|
101 | } |
---|
102 | |
---|
103 | @Override |
---|
104 | public int hashCode() { |
---|
105 | return fields.hashCode(); |
---|
106 | } |
---|
107 | |
---|
108 | /** Get a map of fields in the set by number. */ |
---|
109 | public Map<Integer, Field> asMap() { |
---|
110 | return fields; |
---|
111 | } |
---|
112 | |
---|
113 | /** Check if the given field number is present in the set. */ |
---|
114 | public boolean hasField(final int number) { |
---|
115 | return fields.containsKey(number); |
---|
116 | } |
---|
117 | |
---|
118 | /** |
---|
119 | * Get a field by number. Returns an empty field if not present. Never |
---|
120 | * returns {@code null}. |
---|
121 | */ |
---|
122 | public Field getField(final int number) { |
---|
123 | final Field result = fields.get(number); |
---|
124 | return (result == null) ? Field.getDefaultInstance() : result; |
---|
125 | } |
---|
126 | |
---|
127 | /** Serializes the set and writes it to {@code output}. */ |
---|
128 | public void writeTo(final CodedOutputStream output) throws IOException { |
---|
129 | for (final Map.Entry<Integer, Field> entry : fields.entrySet()) { |
---|
130 | entry.getValue().writeTo(entry.getKey(), output); |
---|
131 | } |
---|
132 | } |
---|
133 | |
---|
134 | /** |
---|
135 | * Converts the set to a string in protocol buffer text format. This is |
---|
136 | * just a trivial wrapper around |
---|
137 | * {@link TextFormat#printToString(UnknownFieldSet)}. |
---|
138 | */ |
---|
139 | @Override |
---|
140 | public String toString() { |
---|
141 | return TextFormat.printToString(this); |
---|
142 | } |
---|
143 | |
---|
144 | /** |
---|
145 | * Serializes the message to a {@code ByteString} and returns it. This is |
---|
146 | * just a trivial wrapper around {@link #writeTo(CodedOutputStream)}. |
---|
147 | */ |
---|
148 | public ByteString toByteString() { |
---|
149 | try { |
---|
150 | final ByteString.CodedBuilder out = |
---|
151 | ByteString.newCodedBuilder(getSerializedSize()); |
---|
152 | writeTo(out.getCodedOutput()); |
---|
153 | return out.build(); |
---|
154 | } catch (final IOException e) { |
---|
155 | throw new RuntimeException( |
---|
156 | "Serializing to a ByteString threw an IOException (should " + |
---|
157 | "never happen).", e); |
---|
158 | } |
---|
159 | } |
---|
160 | |
---|
161 | /** |
---|
162 | * Serializes the message to a {@code byte} array and returns it. This is |
---|
163 | * just a trivial wrapper around {@link #writeTo(CodedOutputStream)}. |
---|
164 | */ |
---|
165 | public byte[] toByteArray() { |
---|
166 | try { |
---|
167 | final byte[] result = new byte[getSerializedSize()]; |
---|
168 | final CodedOutputStream output = CodedOutputStream.newInstance(result); |
---|
169 | writeTo(output); |
---|
170 | output.checkNoSpaceLeft(); |
---|
171 | return result; |
---|
172 | } catch (final IOException e) { |
---|
173 | throw new RuntimeException( |
---|
174 | "Serializing to a byte array threw an IOException " + |
---|
175 | "(should never happen).", e); |
---|
176 | } |
---|
177 | } |
---|
178 | |
---|
179 | /** |
---|
180 | * Serializes the message and writes it to {@code output}. This is just a |
---|
181 | * trivial wrapper around {@link #writeTo(CodedOutputStream)}. |
---|
182 | */ |
---|
183 | public void writeTo(final OutputStream output) throws IOException { |
---|
184 | final CodedOutputStream codedOutput = CodedOutputStream.newInstance(output); |
---|
185 | writeTo(codedOutput); |
---|
186 | codedOutput.flush(); |
---|
187 | } |
---|
188 | |
---|
189 | public void writeDelimitedTo(OutputStream output) throws IOException { |
---|
190 | final CodedOutputStream codedOutput = CodedOutputStream.newInstance(output); |
---|
191 | codedOutput.writeRawVarint32(getSerializedSize()); |
---|
192 | writeTo(codedOutput); |
---|
193 | codedOutput.flush(); |
---|
194 | } |
---|
195 | |
---|
196 | /** Get the number of bytes required to encode this set. */ |
---|
197 | public int getSerializedSize() { |
---|
198 | int result = 0; |
---|
199 | for (final Map.Entry<Integer, Field> entry : fields.entrySet()) { |
---|
200 | result += entry.getValue().getSerializedSize(entry.getKey()); |
---|
201 | } |
---|
202 | return result; |
---|
203 | } |
---|
204 | |
---|
205 | /** |
---|
206 | * Serializes the set and writes it to {@code output} using |
---|
207 | * {@code MessageSet} wire format. |
---|
208 | */ |
---|
209 | public void writeAsMessageSetTo(final CodedOutputStream output) |
---|
210 | throws IOException { |
---|
211 | for (final Map.Entry<Integer, Field> entry : fields.entrySet()) { |
---|
212 | entry.getValue().writeAsMessageSetExtensionTo( |
---|
213 | entry.getKey(), output); |
---|
214 | } |
---|
215 | } |
---|
216 | |
---|
217 | /** |
---|
218 | * Get the number of bytes required to encode this set using |
---|
219 | * {@code MessageSet} wire format. |
---|
220 | */ |
---|
221 | public int getSerializedSizeAsMessageSet() { |
---|
222 | int result = 0; |
---|
223 | for (final Map.Entry<Integer, Field> entry : fields.entrySet()) { |
---|
224 | result += entry.getValue().getSerializedSizeAsMessageSetExtension( |
---|
225 | entry.getKey()); |
---|
226 | } |
---|
227 | return result; |
---|
228 | } |
---|
229 | |
---|
230 | public boolean isInitialized() { |
---|
231 | // UnknownFieldSets do not have required fields, so they are always |
---|
232 | // initialized. |
---|
233 | return true; |
---|
234 | } |
---|
235 | |
---|
236 | /** Parse an {@code UnknownFieldSet} from the given input stream. */ |
---|
237 | public static UnknownFieldSet parseFrom(final CodedInputStream input) |
---|
238 | throws IOException { |
---|
239 | return newBuilder().mergeFrom(input).build(); |
---|
240 | } |
---|
241 | |
---|
242 | /** Parse {@code data} as an {@code UnknownFieldSet} and return it. */ |
---|
243 | public static UnknownFieldSet parseFrom(final ByteString data) |
---|
244 | throws InvalidProtocolBufferException { |
---|
245 | return newBuilder().mergeFrom(data).build(); |
---|
246 | } |
---|
247 | |
---|
248 | /** Parse {@code data} as an {@code UnknownFieldSet} and return it. */ |
---|
249 | public static UnknownFieldSet parseFrom(final byte[] data) |
---|
250 | throws InvalidProtocolBufferException { |
---|
251 | return newBuilder().mergeFrom(data).build(); |
---|
252 | } |
---|
253 | |
---|
254 | /** Parse an {@code UnknownFieldSet} from {@code input} and return it. */ |
---|
255 | public static UnknownFieldSet parseFrom(final InputStream input) |
---|
256 | throws IOException { |
---|
257 | return newBuilder().mergeFrom(input).build(); |
---|
258 | } |
---|
259 | |
---|
260 | public Builder newBuilderForType() { |
---|
261 | return newBuilder(); |
---|
262 | } |
---|
263 | |
---|
264 | public Builder toBuilder() { |
---|
265 | return newBuilder().mergeFrom(this); |
---|
266 | } |
---|
267 | |
---|
268 | /** |
---|
269 | * Builder for {@link UnknownFieldSet}s. |
---|
270 | * |
---|
271 | * <p>Note that this class maintains {@link Field.Builder}s for all fields |
---|
272 | * in the set. Thus, adding one element to an existing {@link Field} does not |
---|
273 | * require making a copy. This is important for efficient parsing of |
---|
274 | * unknown repeated fields. However, it implies that {@link Field}s cannot |
---|
275 | * be constructed independently, nor can two {@link UnknownFieldSet}s share |
---|
276 | * the same {@code Field} object. |
---|
277 | * |
---|
278 | * <p>Use {@link UnknownFieldSet#newBuilder()} to construct a {@code Builder}. |
---|
279 | */ |
---|
280 | public static final class Builder implements MessageLite.Builder { |
---|
281 | // This constructor should never be called directly (except from 'create'). |
---|
282 | private Builder() {} |
---|
283 | |
---|
284 | private Map<Integer, Field> fields; |
---|
285 | |
---|
286 | // Optimization: We keep around a builder for the last field that was |
---|
287 | // modified so that we can efficiently add to it multiple times in a |
---|
288 | // row (important when parsing an unknown repeated field). |
---|
289 | private int lastFieldNumber; |
---|
290 | private Field.Builder lastField; |
---|
291 | |
---|
292 | private static Builder create() { |
---|
293 | Builder builder = new Builder(); |
---|
294 | builder.reinitialize(); |
---|
295 | return builder; |
---|
296 | } |
---|
297 | |
---|
298 | /** |
---|
299 | * Get a field builder for the given field number which includes any |
---|
300 | * values that already exist. |
---|
301 | */ |
---|
302 | private Field.Builder getFieldBuilder(final int number) { |
---|
303 | if (lastField != null) { |
---|
304 | if (number == lastFieldNumber) { |
---|
305 | return lastField; |
---|
306 | } |
---|
307 | // Note: addField() will reset lastField and lastFieldNumber. |
---|
308 | addField(lastFieldNumber, lastField.build()); |
---|
309 | } |
---|
310 | if (number == 0) { |
---|
311 | return null; |
---|
312 | } else { |
---|
313 | final Field existing = fields.get(number); |
---|
314 | lastFieldNumber = number; |
---|
315 | lastField = Field.newBuilder(); |
---|
316 | if (existing != null) { |
---|
317 | lastField.mergeFrom(existing); |
---|
318 | } |
---|
319 | return lastField; |
---|
320 | } |
---|
321 | } |
---|
322 | |
---|
323 | /** |
---|
324 | * Build the {@link UnknownFieldSet} and return it. |
---|
325 | * |
---|
326 | * <p>Once {@code build()} has been called, the {@code Builder} will no |
---|
327 | * longer be usable. Calling any method after {@code build()} will result |
---|
328 | * in undefined behavior and can cause a {@code NullPointerException} to be |
---|
329 | * thrown. |
---|
330 | */ |
---|
331 | public UnknownFieldSet build() { |
---|
332 | getFieldBuilder(0); // Force lastField to be built. |
---|
333 | final UnknownFieldSet result; |
---|
334 | if (fields.isEmpty()) { |
---|
335 | result = getDefaultInstance(); |
---|
336 | } else { |
---|
337 | result = new UnknownFieldSet(Collections.unmodifiableMap(fields)); |
---|
338 | } |
---|
339 | fields = null; |
---|
340 | return result; |
---|
341 | } |
---|
342 | |
---|
343 | public UnknownFieldSet buildPartial() { |
---|
344 | // No required fields, so this is the same as build(). |
---|
345 | return build(); |
---|
346 | } |
---|
347 | |
---|
348 | @Override |
---|
349 | public Builder clone() { |
---|
350 | getFieldBuilder(0); // Force lastField to be built. |
---|
351 | return UnknownFieldSet.newBuilder().mergeFrom( |
---|
352 | new UnknownFieldSet(fields)); |
---|
353 | } |
---|
354 | |
---|
355 | public UnknownFieldSet getDefaultInstanceForType() { |
---|
356 | return UnknownFieldSet.getDefaultInstance(); |
---|
357 | } |
---|
358 | |
---|
359 | private void reinitialize() { |
---|
360 | fields = Collections.emptyMap(); |
---|
361 | lastFieldNumber = 0; |
---|
362 | lastField = null; |
---|
363 | } |
---|
364 | |
---|
365 | /** Reset the builder to an empty set. */ |
---|
366 | public Builder clear() { |
---|
367 | reinitialize(); |
---|
368 | return this; |
---|
369 | } |
---|
370 | |
---|
371 | /** |
---|
372 | * Merge the fields from {@code other} into this set. If a field number |
---|
373 | * exists in both sets, {@code other}'s values for that field will be |
---|
374 | * appended to the values in this set. |
---|
375 | */ |
---|
376 | public Builder mergeFrom(final UnknownFieldSet other) { |
---|
377 | if (other != getDefaultInstance()) { |
---|
378 | for (final Map.Entry<Integer, Field> entry : other.fields.entrySet()) { |
---|
379 | mergeField(entry.getKey(), entry.getValue()); |
---|
380 | } |
---|
381 | } |
---|
382 | return this; |
---|
383 | } |
---|
384 | |
---|
385 | /** |
---|
386 | * Add a field to the {@code UnknownFieldSet}. If a field with the same |
---|
387 | * number already exists, the two are merged. |
---|
388 | */ |
---|
389 | public Builder mergeField(final int number, final Field field) { |
---|
390 | if (number == 0) { |
---|
391 | throw new IllegalArgumentException("Zero is not a valid field number."); |
---|
392 | } |
---|
393 | if (hasField(number)) { |
---|
394 | getFieldBuilder(number).mergeFrom(field); |
---|
395 | } else { |
---|
396 | // Optimization: We could call getFieldBuilder(number).mergeFrom(field) |
---|
397 | // in this case, but that would create a copy of the Field object. |
---|
398 | // We'd rather reuse the one passed to us, so call addField() instead. |
---|
399 | addField(number, field); |
---|
400 | } |
---|
401 | return this; |
---|
402 | } |
---|
403 | |
---|
404 | /** |
---|
405 | * Convenience method for merging a new field containing a single varint |
---|
406 | * value. This is used in particular when an unknown enum value is |
---|
407 | * encountered. |
---|
408 | */ |
---|
409 | public Builder mergeVarintField(final int number, final int value) { |
---|
410 | if (number == 0) { |
---|
411 | throw new IllegalArgumentException("Zero is not a valid field number."); |
---|
412 | } |
---|
413 | getFieldBuilder(number).addVarint(value); |
---|
414 | return this; |
---|
415 | } |
---|
416 | |
---|
417 | /** Check if the given field number is present in the set. */ |
---|
418 | public boolean hasField(final int number) { |
---|
419 | if (number == 0) { |
---|
420 | throw new IllegalArgumentException("Zero is not a valid field number."); |
---|
421 | } |
---|
422 | return number == lastFieldNumber || fields.containsKey(number); |
---|
423 | } |
---|
424 | |
---|
425 | /** |
---|
426 | * Add a field to the {@code UnknownFieldSet}. If a field with the same |
---|
427 | * number already exists, it is removed. |
---|
428 | */ |
---|
429 | public Builder addField(final int number, final Field field) { |
---|
430 | if (number == 0) { |
---|
431 | throw new IllegalArgumentException("Zero is not a valid field number."); |
---|
432 | } |
---|
433 | if (lastField != null && lastFieldNumber == number) { |
---|
434 | // Discard this. |
---|
435 | lastField = null; |
---|
436 | lastFieldNumber = 0; |
---|
437 | } |
---|
438 | if (fields.isEmpty()) { |
---|
439 | fields = new TreeMap<Integer,Field>(); |
---|
440 | } |
---|
441 | fields.put(number, field); |
---|
442 | return this; |
---|
443 | } |
---|
444 | |
---|
445 | /** |
---|
446 | * Get all present {@code Field}s as an immutable {@code Map}. If more |
---|
447 | * fields are added, the changes may or may not be reflected in this map. |
---|
448 | */ |
---|
449 | public Map<Integer, Field> asMap() { |
---|
450 | getFieldBuilder(0); // Force lastField to be built. |
---|
451 | return Collections.unmodifiableMap(fields); |
---|
452 | } |
---|
453 | |
---|
454 | /** |
---|
455 | * Parse an entire message from {@code input} and merge its fields into |
---|
456 | * this set. |
---|
457 | */ |
---|
458 | public Builder mergeFrom(final CodedInputStream input) throws IOException { |
---|
459 | while (true) { |
---|
460 | final int tag = input.readTag(); |
---|
461 | if (tag == 0 || !mergeFieldFrom(tag, input)) { |
---|
462 | break; |
---|
463 | } |
---|
464 | } |
---|
465 | return this; |
---|
466 | } |
---|
467 | |
---|
468 | /** |
---|
469 | * Parse a single field from {@code input} and merge it into this set. |
---|
470 | * @param tag The field's tag number, which was already parsed. |
---|
471 | * @return {@code false} if the tag is an engroup tag. |
---|
472 | */ |
---|
473 | public boolean mergeFieldFrom(final int tag, final CodedInputStream input) |
---|
474 | throws IOException { |
---|
475 | final int number = WireFormat.getTagFieldNumber(tag); |
---|
476 | switch (WireFormat.getTagWireType(tag)) { |
---|
477 | case WireFormat.WIRETYPE_VARINT: |
---|
478 | getFieldBuilder(number).addVarint(input.readInt64()); |
---|
479 | return true; |
---|
480 | case WireFormat.WIRETYPE_FIXED64: |
---|
481 | getFieldBuilder(number).addFixed64(input.readFixed64()); |
---|
482 | return true; |
---|
483 | case WireFormat.WIRETYPE_LENGTH_DELIMITED: |
---|
484 | getFieldBuilder(number).addLengthDelimited(input.readBytes()); |
---|
485 | return true; |
---|
486 | case WireFormat.WIRETYPE_START_GROUP: |
---|
487 | final Builder subBuilder = newBuilder(); |
---|
488 | input.readGroup(number, subBuilder, |
---|
489 | ExtensionRegistry.getEmptyRegistry()); |
---|
490 | getFieldBuilder(number).addGroup(subBuilder.build()); |
---|
491 | return true; |
---|
492 | case WireFormat.WIRETYPE_END_GROUP: |
---|
493 | return false; |
---|
494 | case WireFormat.WIRETYPE_FIXED32: |
---|
495 | getFieldBuilder(number).addFixed32(input.readFixed32()); |
---|
496 | return true; |
---|
497 | default: |
---|
498 | throw InvalidProtocolBufferException.invalidWireType(); |
---|
499 | } |
---|
500 | } |
---|
501 | |
---|
502 | /** |
---|
503 | * Parse {@code data} as an {@code UnknownFieldSet} and merge it with the |
---|
504 | * set being built. This is just a small wrapper around |
---|
505 | * {@link #mergeFrom(CodedInputStream)}. |
---|
506 | */ |
---|
507 | public Builder mergeFrom(final ByteString data) |
---|
508 | throws InvalidProtocolBufferException { |
---|
509 | try { |
---|
510 | final CodedInputStream input = data.newCodedInput(); |
---|
511 | mergeFrom(input); |
---|
512 | input.checkLastTagWas(0); |
---|
513 | return this; |
---|
514 | } catch (final InvalidProtocolBufferException e) { |
---|
515 | throw e; |
---|
516 | } catch (final IOException e) { |
---|
517 | throw new RuntimeException( |
---|
518 | "Reading from a ByteString threw an IOException (should " + |
---|
519 | "never happen).", e); |
---|
520 | } |
---|
521 | } |
---|
522 | |
---|
523 | /** |
---|
524 | * Parse {@code data} as an {@code UnknownFieldSet} and merge it with the |
---|
525 | * set being built. This is just a small wrapper around |
---|
526 | * {@link #mergeFrom(CodedInputStream)}. |
---|
527 | */ |
---|
528 | public Builder mergeFrom(final byte[] data) |
---|
529 | throws InvalidProtocolBufferException { |
---|
530 | try { |
---|
531 | final CodedInputStream input = CodedInputStream.newInstance(data); |
---|
532 | mergeFrom(input); |
---|
533 | input.checkLastTagWas(0); |
---|
534 | return this; |
---|
535 | } catch (final InvalidProtocolBufferException e) { |
---|
536 | throw e; |
---|
537 | } catch (final IOException e) { |
---|
538 | throw new RuntimeException( |
---|
539 | "Reading from a byte array threw an IOException (should " + |
---|
540 | "never happen).", e); |
---|
541 | } |
---|
542 | } |
---|
543 | |
---|
544 | /** |
---|
545 | * Parse an {@code UnknownFieldSet} from {@code input} and merge it with the |
---|
546 | * set being built. This is just a small wrapper around |
---|
547 | * {@link #mergeFrom(CodedInputStream)}. |
---|
548 | */ |
---|
549 | public Builder mergeFrom(final InputStream input) throws IOException { |
---|
550 | final CodedInputStream codedInput = CodedInputStream.newInstance(input); |
---|
551 | mergeFrom(codedInput); |
---|
552 | codedInput.checkLastTagWas(0); |
---|
553 | return this; |
---|
554 | } |
---|
555 | |
---|
556 | public boolean mergeDelimitedFrom(InputStream input) |
---|
557 | throws IOException { |
---|
558 | final int firstByte = input.read(); |
---|
559 | if (firstByte == -1) { |
---|
560 | return false; |
---|
561 | } |
---|
562 | final int size = CodedInputStream.readRawVarint32(firstByte, input); |
---|
563 | final InputStream limitedInput = new LimitedInputStream(input, size); |
---|
564 | mergeFrom(limitedInput); |
---|
565 | return true; |
---|
566 | } |
---|
567 | |
---|
568 | public boolean mergeDelimitedFrom( |
---|
569 | InputStream input, |
---|
570 | ExtensionRegistryLite extensionRegistry) throws IOException { |
---|
571 | // UnknownFieldSet has no extensions. |
---|
572 | return mergeDelimitedFrom(input); |
---|
573 | } |
---|
574 | |
---|
575 | public Builder mergeFrom( |
---|
576 | CodedInputStream input, |
---|
577 | ExtensionRegistryLite extensionRegistry) throws IOException { |
---|
578 | // UnknownFieldSet has no extensions. |
---|
579 | return mergeFrom(input); |
---|
580 | } |
---|
581 | |
---|
582 | public Builder mergeFrom( |
---|
583 | ByteString data, |
---|
584 | ExtensionRegistryLite extensionRegistry) |
---|
585 | throws InvalidProtocolBufferException { |
---|
586 | // UnknownFieldSet has no extensions. |
---|
587 | return mergeFrom(data); |
---|
588 | } |
---|
589 | |
---|
590 | public Builder mergeFrom(byte[] data, int off, int len) |
---|
591 | throws InvalidProtocolBufferException { |
---|
592 | try { |
---|
593 | final CodedInputStream input = |
---|
594 | CodedInputStream.newInstance(data, off, len); |
---|
595 | mergeFrom(input); |
---|
596 | input.checkLastTagWas(0); |
---|
597 | return this; |
---|
598 | } catch (InvalidProtocolBufferException e) { |
---|
599 | throw e; |
---|
600 | } catch (IOException e) { |
---|
601 | throw new RuntimeException( |
---|
602 | "Reading from a byte array threw an IOException (should " + |
---|
603 | "never happen).", e); |
---|
604 | } |
---|
605 | } |
---|
606 | |
---|
607 | public Builder mergeFrom( |
---|
608 | byte[] data, |
---|
609 | ExtensionRegistryLite extensionRegistry) |
---|
610 | throws InvalidProtocolBufferException { |
---|
611 | // UnknownFieldSet has no extensions. |
---|
612 | return mergeFrom(data); |
---|
613 | } |
---|
614 | |
---|
615 | public Builder mergeFrom( |
---|
616 | byte[] data, int off, int len, |
---|
617 | ExtensionRegistryLite extensionRegistry) |
---|
618 | throws InvalidProtocolBufferException { |
---|
619 | // UnknownFieldSet has no extensions. |
---|
620 | return mergeFrom(data, off, len); |
---|
621 | } |
---|
622 | |
---|
623 | public Builder mergeFrom( |
---|
624 | InputStream input, |
---|
625 | ExtensionRegistryLite extensionRegistry) throws IOException { |
---|
626 | // UnknownFieldSet has no extensions. |
---|
627 | return mergeFrom(input); |
---|
628 | } |
---|
629 | |
---|
630 | public boolean isInitialized() { |
---|
631 | // UnknownFieldSets do not have required fields, so they are always |
---|
632 | // initialized. |
---|
633 | return true; |
---|
634 | } |
---|
635 | } |
---|
636 | |
---|
637 | /** |
---|
638 | * Represents a single field in an {@code UnknownFieldSet}. |
---|
639 | * |
---|
640 | * <p>A {@code Field} consists of five lists of values. The lists correspond |
---|
641 | * to the five "wire types" used in the protocol buffer binary format. |
---|
642 | * The wire type of each field can be determined from the encoded form alone, |
---|
643 | * without knowing the field's declared type. So, we are able to parse |
---|
644 | * unknown values at least this far and separate them. Normally, only one |
---|
645 | * of the five lists will contain any values, since it is impossible to |
---|
646 | * define a valid message type that declares two different types for the |
---|
647 | * same field number. However, the code is designed to allow for the case |
---|
648 | * where the same unknown field number is encountered using multiple different |
---|
649 | * wire types. |
---|
650 | * |
---|
651 | * <p>{@code Field} is an immutable class. To construct one, you must use a |
---|
652 | * {@link Builder}. |
---|
653 | * |
---|
654 | * @see UnknownFieldSet |
---|
655 | */ |
---|
656 | public static final class Field { |
---|
657 | private Field() {} |
---|
658 | |
---|
659 | /** Construct a new {@link Builder}. */ |
---|
660 | public static Builder newBuilder() { |
---|
661 | return Builder.create(); |
---|
662 | } |
---|
663 | |
---|
664 | /** |
---|
665 | * Construct a new {@link Builder} and initialize it to a copy of |
---|
666 | * {@code copyFrom}. |
---|
667 | */ |
---|
668 | public static Builder newBuilder(final Field copyFrom) { |
---|
669 | return newBuilder().mergeFrom(copyFrom); |
---|
670 | } |
---|
671 | |
---|
672 | /** Get an empty {@code Field}. */ |
---|
673 | public static Field getDefaultInstance() { |
---|
674 | return fieldDefaultInstance; |
---|
675 | } |
---|
676 | private static final Field fieldDefaultInstance = newBuilder().build(); |
---|
677 | |
---|
678 | /** Get the list of varint values for this field. */ |
---|
679 | public List<Long> getVarintList() { return varint; } |
---|
680 | |
---|
681 | /** Get the list of fixed32 values for this field. */ |
---|
682 | public List<Integer> getFixed32List() { return fixed32; } |
---|
683 | |
---|
684 | /** Get the list of fixed64 values for this field. */ |
---|
685 | public List<Long> getFixed64List() { return fixed64; } |
---|
686 | |
---|
687 | /** Get the list of length-delimited values for this field. */ |
---|
688 | public List<ByteString> getLengthDelimitedList() { return lengthDelimited; } |
---|
689 | |
---|
690 | /** |
---|
691 | * Get the list of embedded group values for this field. These are |
---|
692 | * represented using {@link UnknownFieldSet}s rather than {@link Message}s |
---|
693 | * since the group's type is presumably unknown. |
---|
694 | */ |
---|
695 | public List<UnknownFieldSet> getGroupList() { return group; } |
---|
696 | |
---|
697 | @Override |
---|
698 | public boolean equals(final Object other) { |
---|
699 | if (this == other) { |
---|
700 | return true; |
---|
701 | } |
---|
702 | if (!(other instanceof Field)) { |
---|
703 | return false; |
---|
704 | } |
---|
705 | return Arrays.equals(getIdentityArray(), |
---|
706 | ((Field) other).getIdentityArray()); |
---|
707 | } |
---|
708 | |
---|
709 | @Override |
---|
710 | public int hashCode() { |
---|
711 | return Arrays.hashCode(getIdentityArray()); |
---|
712 | } |
---|
713 | |
---|
714 | /** |
---|
715 | * Returns the array of objects to be used to uniquely identify this |
---|
716 | * {@link Field} instance. |
---|
717 | */ |
---|
718 | private Object[] getIdentityArray() { |
---|
719 | return new Object[] { |
---|
720 | varint, |
---|
721 | fixed32, |
---|
722 | fixed64, |
---|
723 | lengthDelimited, |
---|
724 | group}; |
---|
725 | } |
---|
726 | |
---|
727 | /** |
---|
728 | * Serializes the field, including field number, and writes it to |
---|
729 | * {@code output}. |
---|
730 | */ |
---|
731 | public void writeTo(final int fieldNumber, final CodedOutputStream output) |
---|
732 | throws IOException { |
---|
733 | for (final long value : varint) { |
---|
734 | output.writeUInt64(fieldNumber, value); |
---|
735 | } |
---|
736 | for (final int value : fixed32) { |
---|
737 | output.writeFixed32(fieldNumber, value); |
---|
738 | } |
---|
739 | for (final long value : fixed64) { |
---|
740 | output.writeFixed64(fieldNumber, value); |
---|
741 | } |
---|
742 | for (final ByteString value : lengthDelimited) { |
---|
743 | output.writeBytes(fieldNumber, value); |
---|
744 | } |
---|
745 | for (final UnknownFieldSet value : group) { |
---|
746 | output.writeGroup(fieldNumber, value); |
---|
747 | } |
---|
748 | } |
---|
749 | |
---|
750 | /** |
---|
751 | * Get the number of bytes required to encode this field, including field |
---|
752 | * number. |
---|
753 | */ |
---|
754 | public int getSerializedSize(final int fieldNumber) { |
---|
755 | int result = 0; |
---|
756 | for (final long value : varint) { |
---|
757 | result += CodedOutputStream.computeUInt64Size(fieldNumber, value); |
---|
758 | } |
---|
759 | for (final int value : fixed32) { |
---|
760 | result += CodedOutputStream.computeFixed32Size(fieldNumber, value); |
---|
761 | } |
---|
762 | for (final long value : fixed64) { |
---|
763 | result += CodedOutputStream.computeFixed64Size(fieldNumber, value); |
---|
764 | } |
---|
765 | for (final ByteString value : lengthDelimited) { |
---|
766 | result += CodedOutputStream.computeBytesSize(fieldNumber, value); |
---|
767 | } |
---|
768 | for (final UnknownFieldSet value : group) { |
---|
769 | result += CodedOutputStream.computeGroupSize(fieldNumber, value); |
---|
770 | } |
---|
771 | return result; |
---|
772 | } |
---|
773 | |
---|
774 | /** |
---|
775 | * Serializes the field, including field number, and writes it to |
---|
776 | * {@code output}, using {@code MessageSet} wire format. |
---|
777 | */ |
---|
778 | public void writeAsMessageSetExtensionTo( |
---|
779 | final int fieldNumber, |
---|
780 | final CodedOutputStream output) |
---|
781 | throws IOException { |
---|
782 | for (final ByteString value : lengthDelimited) { |
---|
783 | output.writeRawMessageSetExtension(fieldNumber, value); |
---|
784 | } |
---|
785 | } |
---|
786 | |
---|
787 | /** |
---|
788 | * Get the number of bytes required to encode this field, including field |
---|
789 | * number, using {@code MessageSet} wire format. |
---|
790 | */ |
---|
791 | public int getSerializedSizeAsMessageSetExtension(final int fieldNumber) { |
---|
792 | int result = 0; |
---|
793 | for (final ByteString value : lengthDelimited) { |
---|
794 | result += CodedOutputStream.computeRawMessageSetExtensionSize( |
---|
795 | fieldNumber, value); |
---|
796 | } |
---|
797 | return result; |
---|
798 | } |
---|
799 | |
---|
800 | private List<Long> varint; |
---|
801 | private List<Integer> fixed32; |
---|
802 | private List<Long> fixed64; |
---|
803 | private List<ByteString> lengthDelimited; |
---|
804 | private List<UnknownFieldSet> group; |
---|
805 | |
---|
806 | /** |
---|
807 | * Used to build a {@link Field} within an {@link UnknownFieldSet}. |
---|
808 | * |
---|
809 | * <p>Use {@link Field#newBuilder()} to construct a {@code Builder}. |
---|
810 | */ |
---|
811 | public static final class Builder { |
---|
812 | // This constructor should never be called directly (except from 'create'). |
---|
813 | private Builder() {} |
---|
814 | |
---|
815 | private static Builder create() { |
---|
816 | Builder builder = new Builder(); |
---|
817 | builder.result = new Field(); |
---|
818 | return builder; |
---|
819 | } |
---|
820 | |
---|
821 | private Field result; |
---|
822 | |
---|
823 | /** |
---|
824 | * Build the field. After {@code build()} has been called, the |
---|
825 | * {@code Builder} is no longer usable. Calling any other method will |
---|
826 | * result in undefined behavior and can cause a |
---|
827 | * {@code NullPointerException} to be thrown. |
---|
828 | */ |
---|
829 | public Field build() { |
---|
830 | if (result.varint == null) { |
---|
831 | result.varint = Collections.emptyList(); |
---|
832 | } else { |
---|
833 | result.varint = Collections.unmodifiableList(result.varint); |
---|
834 | } |
---|
835 | if (result.fixed32 == null) { |
---|
836 | result.fixed32 = Collections.emptyList(); |
---|
837 | } else { |
---|
838 | result.fixed32 = Collections.unmodifiableList(result.fixed32); |
---|
839 | } |
---|
840 | if (result.fixed64 == null) { |
---|
841 | result.fixed64 = Collections.emptyList(); |
---|
842 | } else { |
---|
843 | result.fixed64 = Collections.unmodifiableList(result.fixed64); |
---|
844 | } |
---|
845 | if (result.lengthDelimited == null) { |
---|
846 | result.lengthDelimited = Collections.emptyList(); |
---|
847 | } else { |
---|
848 | result.lengthDelimited = |
---|
849 | Collections.unmodifiableList(result.lengthDelimited); |
---|
850 | } |
---|
851 | if (result.group == null) { |
---|
852 | result.group = Collections.emptyList(); |
---|
853 | } else { |
---|
854 | result.group = Collections.unmodifiableList(result.group); |
---|
855 | } |
---|
856 | |
---|
857 | final Field returnMe = result; |
---|
858 | result = null; |
---|
859 | return returnMe; |
---|
860 | } |
---|
861 | |
---|
862 | /** Discard the field's contents. */ |
---|
863 | public Builder clear() { |
---|
864 | result = new Field(); |
---|
865 | return this; |
---|
866 | } |
---|
867 | |
---|
868 | /** |
---|
869 | * Merge the values in {@code other} into this field. For each list |
---|
870 | * of values, {@code other}'s values are append to the ones in this |
---|
871 | * field. |
---|
872 | */ |
---|
873 | public Builder mergeFrom(final Field other) { |
---|
874 | if (!other.varint.isEmpty()) { |
---|
875 | if (result.varint == null) { |
---|
876 | result.varint = new ArrayList<Long>(); |
---|
877 | } |
---|
878 | result.varint.addAll(other.varint); |
---|
879 | } |
---|
880 | if (!other.fixed32.isEmpty()) { |
---|
881 | if (result.fixed32 == null) { |
---|
882 | result.fixed32 = new ArrayList<Integer>(); |
---|
883 | } |
---|
884 | result.fixed32.addAll(other.fixed32); |
---|
885 | } |
---|
886 | if (!other.fixed64.isEmpty()) { |
---|
887 | if (result.fixed64 == null) { |
---|
888 | result.fixed64 = new ArrayList<Long>(); |
---|
889 | } |
---|
890 | result.fixed64.addAll(other.fixed64); |
---|
891 | } |
---|
892 | if (!other.lengthDelimited.isEmpty()) { |
---|
893 | if (result.lengthDelimited == null) { |
---|
894 | result.lengthDelimited = new ArrayList<ByteString>(); |
---|
895 | } |
---|
896 | result.lengthDelimited.addAll(other.lengthDelimited); |
---|
897 | } |
---|
898 | if (!other.group.isEmpty()) { |
---|
899 | if (result.group == null) { |
---|
900 | result.group = new ArrayList<UnknownFieldSet>(); |
---|
901 | } |
---|
902 | result.group.addAll(other.group); |
---|
903 | } |
---|
904 | return this; |
---|
905 | } |
---|
906 | |
---|
907 | /** Add a varint value. */ |
---|
908 | public Builder addVarint(final long value) { |
---|
909 | if (result.varint == null) { |
---|
910 | result.varint = new ArrayList<Long>(); |
---|
911 | } |
---|
912 | result.varint.add(value); |
---|
913 | return this; |
---|
914 | } |
---|
915 | |
---|
916 | /** Add a fixed32 value. */ |
---|
917 | public Builder addFixed32(final int value) { |
---|
918 | if (result.fixed32 == null) { |
---|
919 | result.fixed32 = new ArrayList<Integer>(); |
---|
920 | } |
---|
921 | result.fixed32.add(value); |
---|
922 | return this; |
---|
923 | } |
---|
924 | |
---|
925 | /** Add a fixed64 value. */ |
---|
926 | public Builder addFixed64(final long value) { |
---|
927 | if (result.fixed64 == null) { |
---|
928 | result.fixed64 = new ArrayList<Long>(); |
---|
929 | } |
---|
930 | result.fixed64.add(value); |
---|
931 | return this; |
---|
932 | } |
---|
933 | |
---|
934 | /** Add a length-delimited value. */ |
---|
935 | public Builder addLengthDelimited(final ByteString value) { |
---|
936 | if (result.lengthDelimited == null) { |
---|
937 | result.lengthDelimited = new ArrayList<ByteString>(); |
---|
938 | } |
---|
939 | result.lengthDelimited.add(value); |
---|
940 | return this; |
---|
941 | } |
---|
942 | |
---|
943 | /** Add an embedded group. */ |
---|
944 | public Builder addGroup(final UnknownFieldSet value) { |
---|
945 | if (result.group == null) { |
---|
946 | result.group = new ArrayList<UnknownFieldSet>(); |
---|
947 | } |
---|
948 | result.group.add(value); |
---|
949 | return this; |
---|
950 | } |
---|
951 | } |
---|
952 | } |
---|
953 | } |
---|