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