blob: be773e41b25631e9322de785d6ad7a3df89239c6 [file] [log] [blame]
csharptestd965c662011-05-20 13:57:07 -05001#region Copyright notice and license
2// Protocol Buffers - Google's data interchange format
3// Copyright 2008 Google Inc. All rights reserved.
4// http://github.com/jskeet/dotnet-protobufs/
5// Original C++/Java/Python code:
6// http://code.google.com/p/protobuf/
7//
8// Redistribution and use in source and binary forms, with or without
9// modification, are permitted provided that the following conditions are
10// met:
11//
12// * Redistributions of source code must retain the above copyright
13// notice, this list of conditions and the following disclaimer.
14// * Redistributions in binary form must reproduce the above
15// copyright notice, this list of conditions and the following disclaimer
16// in the documentation and/or other materials provided with the
17// distribution.
18// * Neither the name of Google Inc. nor the names of its
19// contributors may be used to endorse or promote products derived from
20// this software without specific prior written permission.
21//
22// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33#endregion
34
35using System;
36using System.Collections.Generic;
37using System.IO;
38using Google.ProtocolBuffers.Collections;
39using Google.ProtocolBuffers.Descriptors;
40using Google.ProtocolBuffers.DescriptorProtos;
41
42namespace Google.ProtocolBuffers {
43 /// <summary>
44 /// Used to keep track of fields which were seen when parsing a protocol message
45 /// but whose field numbers or types are unrecognized. This most frequently
46 /// occurs when new fields are added to a message type and then messages containing
47 /// those fields are read by old software that was built before the new types were
48 /// added.
49 ///
50 /// Every message contains an UnknownFieldSet.
51 ///
52 /// Most users will never need to use this class directly.
53 /// </summary>
54 public sealed class UnknownFieldSet : IMessageLite {
55
56 private static readonly UnknownFieldSet defaultInstance = new UnknownFieldSet(new Dictionary<int, UnknownField>());
57
58 private readonly IDictionary<int, UnknownField> fields;
59
60 private UnknownFieldSet(IDictionary<int, UnknownField> fields) {
61 this.fields = fields;
62 }
63
64 /// <summary>
65 /// Creates a new unknown field set builder.
66 /// </summary>
67 public static Builder CreateBuilder() {
68 return new Builder();
69 }
70
71 /// <summary>
72 /// Creates a new unknown field set builder
73 /// and initialize it from <paramref name="original"/>.
74 /// </summary>
75 public static Builder CreateBuilder(UnknownFieldSet original) {
76 return new Builder().MergeFrom(original);
77 }
78
79 public static UnknownFieldSet DefaultInstance {
80 get { return defaultInstance; }
81 }
82
83 /// <summary>
84 /// Returns a read-only view of the mapping from field numbers to values.
85 /// </summary>
86 public IDictionary<int, UnknownField> FieldDictionary {
87 get { return Dictionaries.AsReadOnly(fields); }
88 }
89
90 /// <summary>
91 /// Checks whether or not the given field number is present in the set.
92 /// </summary>
93 public bool HasField(int field) {
94 return fields.ContainsKey(field);
95 }
96
97 /// <summary>
98 /// Fetches a field by number, returning an empty field if not present.
99 /// Never returns null.
100 /// </summary>
101 public UnknownField this[int number] {
102 get {
103 UnknownField ret;
104 if (!fields.TryGetValue(number, out ret)) {
105 ret = UnknownField.DefaultInstance;
106 }
107 return ret;
108 }
109 }
110
111 /// <summary>
112 /// Serializes the set and writes it to <paramref name="output"/>.
113 /// </summary>
114 public void WriteTo(CodedOutputStream output) {
115 foreach (KeyValuePair<int, UnknownField> entry in fields) {
116 entry.Value.WriteTo(entry.Key, output);
117 }
118 }
119
120 /// <summary>
121 /// Gets the number of bytes required to encode this set.
122 /// </summary>
123 public int SerializedSize {
124 get {
125 int result = 0;
126 foreach (KeyValuePair<int, UnknownField> entry in fields) {
127 result += entry.Value.GetSerializedSize(entry.Key);
128 }
129 return result;
130 }
131 }
132
133 /// <summary>
134 /// Converts the set to a string in protocol buffer text format. This
135 /// is just a trivial wrapper around TextFormat.PrintToString.
136 /// </summary>
137 public override String ToString() {
138 return TextFormat.PrintToString(this);
139 }
140
141 /// <summary>
142 /// Converts the set to a string in protocol buffer text format. This
143 /// is just a trivial wrapper around TextFormat.PrintToString.
144 /// </summary>
145 public void PrintTo(TextWriter writer) {
146 TextFormat.Print(this, writer);
147 }
148
149 /// <summary>
150 /// Serializes the message to a ByteString and returns it. This is
151 /// just a trivial wrapper around WriteTo(CodedOutputStream).
152 /// </summary>
153 /// <returns></returns>
154 public ByteString ToByteString() {
155 ByteString.CodedBuilder codedBuilder = new ByteString.CodedBuilder(SerializedSize);
156 WriteTo(codedBuilder.CodedOutput);
157 return codedBuilder.Build();
158 }
159
160 /// <summary>
161 /// Serializes the message to a byte array and returns it. This is
162 /// just a trivial wrapper around WriteTo(CodedOutputStream).
163 /// </summary>
164 /// <returns></returns>
165 public byte[] ToByteArray() {
166 byte[] data = new byte[SerializedSize];
167 CodedOutputStream output = CodedOutputStream.CreateInstance(data);
168 WriteTo(output);
169 output.CheckNoSpaceLeft();
170 return data;
171 }
172
173 /// <summary>
174 /// Serializes the message and writes it to <paramref name="output"/>. This is
175 /// just a trivial wrapper around WriteTo(CodedOutputStream).
176 /// </summary>
177 /// <param name="output"></param>
178 public void WriteTo(Stream output) {
179 CodedOutputStream codedOutput = CodedOutputStream.CreateInstance(output);
180 WriteTo(codedOutput);
181 codedOutput.Flush();
182 }
183
184 /// <summary>
185 /// Serializes the set and writes it to <paramref name="output"/> using
186 /// the MessageSet wire format.
187 /// </summary>
188 public void WriteAsMessageSetTo(CodedOutputStream output) {
189 foreach (KeyValuePair<int, UnknownField> entry in fields) {
190 entry.Value.WriteAsMessageSetExtensionTo(entry.Key, output);
191 }
192 }
193
194 /// <summary>
195 /// Gets the number of bytes required to encode this set using the MessageSet
196 /// wire format.
197 /// </summary>
198 public int SerializedSizeAsMessageSet {
199 get {
200 int result = 0;
201 foreach (KeyValuePair<int, UnknownField> entry in fields) {
202 result += entry.Value.GetSerializedSizeAsMessageSetExtension(entry.Key);
203 }
204 return result;
205 }
206 }
207
208 public override bool Equals(object other) {
209 if (ReferenceEquals(this, other)) {
210 return true;
211 }
212 UnknownFieldSet otherSet = other as UnknownFieldSet;
213 return otherSet != null && Dictionaries.Equals(fields, otherSet.fields);
214 }
215
216 public override int GetHashCode() {
217 return Dictionaries.GetHashCode(fields);
218 }
219
220 /// <summary>
221 /// Parses an UnknownFieldSet from the given input.
222 /// </summary>
223 public static UnknownFieldSet ParseFrom(CodedInputStream input) {
224 return CreateBuilder().MergeFrom(input).Build();
225 }
226
227 /// <summary>
228 /// Parses an UnknownFieldSet from the given data.
229 /// </summary>
230 public static UnknownFieldSet ParseFrom(ByteString data) {
231 return CreateBuilder().MergeFrom(data).Build();
232 }
233
234 /// <summary>
235 /// Parses an UnknownFieldSet from the given data.
236 /// </summary>
237 public static UnknownFieldSet ParseFrom(byte[] data) {
238 return CreateBuilder().MergeFrom(data).Build();
239 }
240
241 /// <summary>
242 /// Parses an UnknownFieldSet from the given input.
243 /// </summary>
244 public static UnknownFieldSet ParseFrom(Stream input) {
245 return CreateBuilder().MergeFrom(input).Build();
246 }
247
248 #region IMessageLite Members
249
250 public bool IsInitialized {
251 get { return fields != null; }
252 }
253
254 public void WriteDelimitedTo(Stream output) {
255 CodedOutputStream codedOutput = CodedOutputStream.CreateInstance(output);
256 codedOutput.WriteRawVarint32((uint) SerializedSize);
257 WriteTo(codedOutput);
258 codedOutput.Flush();
259 }
260
261 public IBuilderLite WeakCreateBuilderForType() {
262 return new Builder();
263 }
264
265 public IBuilderLite WeakToBuilder() {
266 return new Builder(fields);
267 }
268
269 public IMessageLite WeakDefaultInstanceForType {
270 get { return defaultInstance; }
271 }
272
273 #endregion
274
275 /// <summary>
276 /// Builder for UnknownFieldSets.
277 /// </summary>
278 public sealed class Builder : IBuilderLite
279 {
280 /// <summary>
281 /// Mapping from number to field. Note that by using a SortedList we ensure
282 /// that the fields will be serialized in ascending order.
283 /// </summary>
284 private IDictionary<int, UnknownField> fields;
285 // Optimization: We keep around a builder for the last field that was
286 // modified so that we can efficiently add to it multiple times in a
287 // row (important when parsing an unknown repeated field).
288 private int lastFieldNumber;
289 private UnknownField.Builder lastField;
290
291 internal Builder() {
292 fields = new SortedList<int, UnknownField>();
293 }
294
295 internal Builder(IDictionary<int, UnknownField> dictionary) {
296 fields = new SortedList<int, UnknownField>(dictionary);
297 }
298
299 /// <summary>
300 /// Returns a field builder for the specified field number, including any values
301 /// which already exist.
302 /// </summary>
303 private UnknownField.Builder GetFieldBuilder(int number) {
304 if (lastField != null) {
305 if (number == lastFieldNumber) {
306 return lastField;
307 }
308 // Note: AddField() will reset lastField and lastFieldNumber.
309 AddField(lastFieldNumber, lastField.Build());
310 }
311 if (number == 0) {
312 return null;
313 }
314
315 lastField = UnknownField.CreateBuilder();
316 UnknownField existing;
317 if (fields.TryGetValue(number, out existing)) {
318 lastField.MergeFrom(existing);
319 }
320 lastFieldNumber = number;
321 return lastField;
322 }
323
324 /// <summary>
325 /// Build the UnknownFieldSet and return it. Once this method has been called,
326 /// this instance will no longer be usable. Calling any method after this
327 /// will throw a NullReferenceException.
328 /// </summary>
329 public UnknownFieldSet Build() {
330 GetFieldBuilder(0); // Force lastField to be built.
331 UnknownFieldSet result = fields.Count == 0 ? DefaultInstance : new UnknownFieldSet(fields);
332 fields = null;
333 return result;
334 }
335
336 /// <summary>
337 /// Adds a field to the set. If a field with the same number already exists, it
338 /// is replaced.
339 /// </summary>
340 public Builder AddField(int number, UnknownField field) {
341 if (number == 0) {
342 throw new ArgumentOutOfRangeException("number", "Zero is not a valid field number.");
343 }
344 if (lastField != null && lastFieldNumber == number) {
345 // Discard this.
346 lastField = null;
347 lastFieldNumber = 0;
348 }
349 fields[number] = field;
350 return this;
351 }
352
353 /// <summary>
354 /// Resets the builder to an empty set.
355 /// </summary>
356 public Builder Clear() {
357 fields.Clear();
358 lastFieldNumber = 0;
359 lastField = null;
360 return this;
361 }
362
363 /// <summary>
364 /// Parse an entire message from <paramref name="input"/> and merge
365 /// its fields into this set.
366 /// </summary>
367 public Builder MergeFrom(CodedInputStream input) {
368 while (true) {
369 uint tag = input.ReadTag();
370 if (tag == 0 || !MergeFieldFrom(tag, input)) {
371 break;
372 }
373 }
374 return this;
375 }
376
377 /// <summary>
378 /// Parse a single field from <paramref name="input"/> and merge it
379 /// into this set.
380 /// </summary>
381 /// <param name="tag">The field's tag number, which was already parsed.</param>
382 /// <param name="input">The coded input stream containing the field</param>
383 /// <returns>false if the tag is an "end group" tag, true otherwise</returns>
384 [CLSCompliant(false)]
385 public bool MergeFieldFrom(uint tag, CodedInputStream input) {
386 int number = WireFormat.GetTagFieldNumber(tag);
387 switch (WireFormat.GetTagWireType(tag)) {
388 case WireFormat.WireType.Varint:
389 GetFieldBuilder(number).AddVarint(input.ReadUInt64());
390 return true;
391 case WireFormat.WireType.Fixed64:
392 GetFieldBuilder(number).AddFixed64(input.ReadFixed64());
393 return true;
394 case WireFormat.WireType.LengthDelimited:
395 GetFieldBuilder(number).AddLengthDelimited(input.ReadBytes());
396 return true;
397 case WireFormat.WireType.StartGroup: {
398 Builder subBuilder = CreateBuilder();
399#pragma warning disable 0612
400 input.ReadUnknownGroup(number, subBuilder);
401#pragma warning restore 0612
402 GetFieldBuilder(number).AddGroup(subBuilder.Build());
403 return true;
404 }
405 case WireFormat.WireType.EndGroup:
406 return false;
407 case WireFormat.WireType.Fixed32:
408 GetFieldBuilder(number).AddFixed32(input.ReadFixed32());
409 return true;
410 default:
411 throw InvalidProtocolBufferException.InvalidWireType();
412 }
413 }
414
415 /// <summary>
416 /// Parses <paramref name="input"/> as an UnknownFieldSet and merge it
417 /// with the set being built. This is just a small wrapper around
418 /// MergeFrom(CodedInputStream).
419 /// </summary>
420 public Builder MergeFrom(Stream input) {
421 CodedInputStream codedInput = CodedInputStream.CreateInstance(input);
422 MergeFrom(codedInput);
423 codedInput.CheckLastTagWas(0);
424 return this;
425 }
426
427 /// <summary>
428 /// Parses <paramref name="data"/> as an UnknownFieldSet and merge it
429 /// with the set being built. This is just a small wrapper around
430 /// MergeFrom(CodedInputStream).
431 /// </summary>
432 public Builder MergeFrom(ByteString data) {
433 CodedInputStream input = data.CreateCodedInput();
434 MergeFrom(input);
435 input.CheckLastTagWas(0);
436 return this;
437 }
438
439 /// <summary>
440 /// Parses <paramref name="data"/> as an UnknownFieldSet and merge it
441 /// with the set being built. This is just a small wrapper around
442 /// MergeFrom(CodedInputStream).
443 /// </summary>
444 public Builder MergeFrom(byte[] data) {
445 CodedInputStream input = CodedInputStream.CreateInstance(data);
446 MergeFrom(input);
447 input.CheckLastTagWas(0);
448 return this;
449 }
450
451 /// <summary>
452 /// Convenience method for merging a new field containing a single varint
453 /// value. This is used in particular when an unknown enum value is
454 /// encountered.
455 /// </summary>
456 [CLSCompliant(false)]
457 public Builder MergeVarintField(int number, ulong value) {
458 if (number == 0) {
459 throw new ArgumentOutOfRangeException("number", "Zero is not a valid field number.");
460 }
461 GetFieldBuilder(number).AddVarint(value);
462 return this;
463 }
464
465 /// <summary>
466 /// Merges the fields from <paramref name="other"/> into this set.
467 /// If a field number exists in both sets, the values in <paramref name="other"/>
468 /// will be appended to the values in this set.
469 /// </summary>
470 public Builder MergeFrom(UnknownFieldSet other) {
471 if (other != DefaultInstance) {
472 foreach(KeyValuePair<int, UnknownField> entry in other.fields) {
473 MergeField(entry.Key, entry.Value);
474 }
475 }
476 return this;
477 }
478
479 /// <summary>
480 /// Checks if the given field number is present in the set.
481 /// </summary>
482 public bool HasField(int number) {
483 if (number == 0) {
484 throw new ArgumentOutOfRangeException("number", "Zero is not a valid field number.");
485 }
486 return number == lastFieldNumber || fields.ContainsKey(number);
487 }
488
489 /// <summary>
490 /// Adds a field to the unknown field set. If a field with the same
491 /// number already exists, the two are merged.
492 /// </summary>
493 public Builder MergeField(int number, UnknownField field) {
494 if (number == 0) {
495 throw new ArgumentOutOfRangeException("number", "Zero is not a valid field number.");
496 }
497 if (HasField(number)) {
498 GetFieldBuilder(number).MergeFrom(field);
499 } else {
500 // Optimization: We could call getFieldBuilder(number).mergeFrom(field)
501 // in this case, but that would create a copy of the Field object.
502 // We'd rather reuse the one passed to us, so call AddField() instead.
503 AddField(number, field);
504 }
505 return this;
506 }
507
508 internal void MergeFrom(CodedInputStream input, ExtensionRegistry extensionRegistry, IBuilder builder) {
509 while (true) {
510 uint tag = input.ReadTag();
511 if (tag == 0) {
512 break;
513 }
514
515 if (!MergeFieldFrom(input, extensionRegistry, builder, tag)) {
516 // end group tag
517 break;
518 }
519 }
520 }
521
522 /// <summary>
523 /// Like <see cref="MergeFrom(CodedInputStream, ExtensionRegistry, IBuilder)" />
524 /// but parses a single field.
525 /// </summary>
526 /// <param name="input">The input to read the field from</param>
527 /// <param name="extensionRegistry">Registry to use when an extension field is encountered</param>
528 /// <param name="builder">Builder to merge field into, if it's a known field</param>
529 /// <param name="tag">The tag, which should already have been read from the input</param>
530 /// <returns>true unless the tag is an end-group tag</returns>
531 internal bool MergeFieldFrom(CodedInputStream input,
532 ExtensionRegistry extensionRegistry, IBuilder builder, uint tag) {
533
534 MessageDescriptor type = builder.DescriptorForType;
535 if (type.Options.MessageSetWireFormat && tag == WireFormat.MessageSetTag.ItemStart) {
536 MergeMessageSetExtensionFromCodedStream(input, extensionRegistry, builder);
537 return true;
538 }
539
540 WireFormat.WireType wireType = WireFormat.GetTagWireType(tag);
541 int fieldNumber = WireFormat.GetTagFieldNumber(tag);
542
543 FieldDescriptor field;
544 IMessageLite defaultFieldInstance = null;
545
546 if (type.IsExtensionNumber(fieldNumber)) {
547 ExtensionInfo extension = extensionRegistry[type, fieldNumber];
548 if (extension == null) {
549 field = null;
550 } else {
551 field = extension.Descriptor;
552 defaultFieldInstance = extension.DefaultInstance;
553 }
554 } else {
555 field = type.FindFieldByNumber(fieldNumber);
556 }
557
558 // Unknown field or wrong wire type. Skip.
559 if (field == null || wireType != WireFormat.GetWireType(field)) {
560 return MergeFieldFrom(tag, input);
561 }
562
563 if (field.IsPacked) {
564 int length = (int)input.ReadRawVarint32();
565 int limit = input.PushLimit(length);
566 if (field.FieldType == FieldType.Enum) {
567 while (!input.ReachedLimit) {
568 int rawValue = input.ReadEnum();
569 object value = field.EnumType.FindValueByNumber(rawValue);
570 if (value == null) {
571 // If the number isn't recognized as a valid value for this
572 // enum, drop it (don't even add it to unknownFields).
573 return true;
574 }
575 builder.WeakAddRepeatedField(field, value);
576 }
577 } else {
578 while (!input.ReachedLimit) {
579 Object value = input.ReadPrimitiveField(field.FieldType);
580 builder.WeakAddRepeatedField(field, value);
581 }
582 }
583 input.PopLimit(limit);
584 } else {
585 object value;
586 switch (field.FieldType) {
587 case FieldType.Group:
588 case FieldType.Message: {
589 IBuilderLite subBuilder;
590 if (defaultFieldInstance != null) {
591 subBuilder = defaultFieldInstance.WeakCreateBuilderForType();
592 } else {
593 subBuilder = builder.CreateBuilderForField(field);
594 }
595 if (!field.IsRepeated) {
596 subBuilder.WeakMergeFrom((IMessageLite)builder[field]);
597 }
598 if (field.FieldType == FieldType.Group) {
599 input.ReadGroup(field.FieldNumber, subBuilder, extensionRegistry);
600 } else {
601 input.ReadMessage(subBuilder, extensionRegistry);
602 }
603 value = subBuilder.WeakBuild();
604 break;
605 }
606 case FieldType.Enum: {
607 int rawValue = input.ReadEnum();
608 value = field.EnumType.FindValueByNumber(rawValue);
609 // If the number isn't recognized as a valid value for this enum,
610 // drop it.
611 if (value == null) {
612 MergeVarintField(fieldNumber, (ulong)rawValue);
613 return true;
614 }
615 break;
616 }
617 default:
618 value = input.ReadPrimitiveField(field.FieldType);
619 break;
620 }
621 if (field.IsRepeated) {
622 builder.WeakAddRepeatedField(field, value);
623 } else {
624 builder[field] = value;
625 }
626 }
627 return true;
628 }
629
630 /// <summary>
631 /// Called by MergeFieldFrom to parse a MessageSet extension.
632 /// </summary>
633 private void MergeMessageSetExtensionFromCodedStream(CodedInputStream input,
634 ExtensionRegistry extensionRegistry, IBuilder builder) {
635 MessageDescriptor type = builder.DescriptorForType;
636
637 // The wire format for MessageSet is:
638 // message MessageSet {
639 // repeated group Item = 1 {
640 // required int32 typeId = 2;
641 // required bytes message = 3;
642 // }
643 // }
644 // "typeId" is the extension's field number. The extension can only be
645 // a message type, where "message" contains the encoded bytes of that
646 // message.
647 //
648 // In practice, we will probably never see a MessageSet item in which
649 // the message appears before the type ID, or where either field does not
650 // appear exactly once. However, in theory such cases are valid, so we
651 // should be prepared to accept them.
652
653 int typeId = 0;
654 ByteString rawBytes = null; // If we encounter "message" before "typeId"
655 IBuilderLite subBuilder = null;
656 FieldDescriptor field = null;
657
658 while (true) {
659 uint tag = input.ReadTag();
660 if (tag == 0) {
661 break;
662 }
663
664 if (tag == WireFormat.MessageSetTag.TypeID) {
665 typeId = input.ReadInt32();
666 // Zero is not a valid type ID.
667 if (typeId != 0) {
668 ExtensionInfo extension = extensionRegistry[type, typeId];
669 if (extension != null) {
670 field = extension.Descriptor;
671 subBuilder = extension.DefaultInstance.WeakCreateBuilderForType();
672 IMessageLite originalMessage = (IMessageLite)builder[field];
673 if (originalMessage != null) {
674 subBuilder.WeakMergeFrom(originalMessage);
675 }
676 if (rawBytes != null) {
677 // We already encountered the message. Parse it now.
678 // TODO(jonskeet): Check this is okay. It's subtly different from the Java, as it doesn't create an input stream from rawBytes.
679 // In fact, why don't we just call MergeFrom(rawBytes)? And what about the extension registry?
680 subBuilder.WeakMergeFrom(rawBytes.CreateCodedInput());
681 rawBytes = null;
682 }
683 } else {
684 // Unknown extension number. If we already saw data, put it
685 // in rawBytes.
686 if (rawBytes != null) {
687 MergeField(typeId, UnknownField.CreateBuilder().AddLengthDelimited(rawBytes).Build());
688 rawBytes = null;
689 }
690 }
691 }
692 } else if (tag == WireFormat.MessageSetTag.Message) {
693 if (typeId == 0) {
694 // We haven't seen a type ID yet, so we have to store the raw bytes for now.
695 rawBytes = input.ReadBytes();
696 } else if (subBuilder == null) {
697 // We don't know how to parse this. Ignore it.
698 MergeField(typeId, UnknownField.CreateBuilder().AddLengthDelimited(input.ReadBytes()).Build());
699 } else {
700 // We already know the type, so we can parse directly from the input
701 // with no copying. Hooray!
702 input.ReadMessage(subBuilder, extensionRegistry);
703 }
704 } else {
705 // Unknown tag. Skip it.
706 if (!input.SkipField(tag)) {
707 break; // end of group
708 }
709 }
710 }
711
712 input.CheckLastTagWas(WireFormat.MessageSetTag.ItemEnd);
713
714 if (subBuilder != null) {
715 builder[field] = subBuilder.WeakBuild();
716 }
717 }
718
719 #region IBuilderLite Members
720
721 bool IBuilderLite.IsInitialized {
722 get { return fields != null; }
723 }
724
725 IBuilderLite IBuilderLite.WeakClear() {
726 return Clear();
727 }
728
729 IBuilderLite IBuilderLite.WeakMergeFrom(IMessageLite message) {
730 return MergeFrom((UnknownFieldSet)message);
731 }
732
733 IBuilderLite IBuilderLite.WeakMergeFrom(ByteString data) {
734 return MergeFrom(data);
735 }
736
737 IBuilderLite IBuilderLite.WeakMergeFrom(ByteString data, ExtensionRegistry registry) {
738 return MergeFrom(data);
739 }
740
741 IBuilderLite IBuilderLite.WeakMergeFrom(CodedInputStream input) {
742 return MergeFrom(input);
743 }
744
745 IBuilderLite IBuilderLite.WeakMergeFrom(CodedInputStream input, ExtensionRegistry registry) {
746 return MergeFrom(input);
747 }
748
749 IMessageLite IBuilderLite.WeakBuild() {
750 return Build();
751 }
752
753 IMessageLite IBuilderLite.WeakBuildPartial() {
754 return Build();
755 }
756
757 IBuilderLite IBuilderLite.WeakClone() {
758 return Build().WeakToBuilder();
759 }
760
761 IMessageLite IBuilderLite.WeakDefaultInstanceForType {
762 get { return DefaultInstance; }
763 }
764
765 #endregion
766 }
767 }
768}