blob: ff6a1534eac95b44da9afb576d1803135389e0fa [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>
csharptestffafdaa2011-06-03 12:58:14 -0500127 public void WriteTo(ICodedOutputStream output)
csharptest71f662c2011-05-20 15:15:34 -0500128 {
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
csharptestffafdaa2011-06-03 12:58:14 -0500171 /// just a trivial wrapper around WriteTo(ICodedOutputStream).
csharptest71f662c2011-05-20 15:15:34 -0500172 /// </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
csharptestffafdaa2011-06-03 12:58:14 -0500183 /// just a trivial wrapper around WriteTo(ICodedOutputStream).
csharptest71f662c2011-05-20 15:15:34 -0500184 /// </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
csharptestffafdaa2011-06-03 12:58:14 -0500197 /// just a trivial wrapper around WriteTo(ICodedOutputStream).
csharptest71f662c2011-05-20 15:15:34 -0500198 /// </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>
csharptestffafdaa2011-06-03 12:58:14 -0500211 public void WriteAsMessageSetTo(ICodedOutputStream output)
csharptest71f662c2011-05-20 15:15:34 -0500212 {
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 {
csharptest123e5342011-06-03 14:15:21 -0500422 uint tag;
423 string name;
424 while (input.ReadTag(out tag, out name))
csharptest71f662c2011-05-20 15:15:34 -0500425 {
csharptest123e5342011-06-03 14:15:21 -0500426 if (tag == 0)
csharptest71f662c2011-05-20 15:15:34 -0500427 {
csharptest123e5342011-06-03 14:15:21 -0500428 if (input.SkipField())
429 continue; //can't merge unknown without field tag
csharptest71f662c2011-05-20 15:15:34 -0500430 break;
431 }
csharptest123e5342011-06-03 14:15:21 -0500432
433 if(!MergeFieldFrom(tag, input))
434 break;
csharptest71f662c2011-05-20 15:15:34 -0500435 }
436 return this;
437 }
438
439 /// <summary>
440 /// Parse a single field from <paramref name="input"/> and merge it
441 /// into this set.
442 /// </summary>
443 /// <param name="tag">The field's tag number, which was already parsed.</param>
444 /// <param name="input">The coded input stream containing the field</param>
445 /// <returns>false if the tag is an "end group" tag, true otherwise</returns>
446 [CLSCompliant(false)]
447 public bool MergeFieldFrom(uint tag, CodedInputStream input)
448 {
449 int number = WireFormat.GetTagFieldNumber(tag);
450 switch (WireFormat.GetTagWireType(tag))
451 {
452 case WireFormat.WireType.Varint:
453 GetFieldBuilder(number).AddVarint(input.ReadUInt64());
454 return true;
455 case WireFormat.WireType.Fixed64:
456 GetFieldBuilder(number).AddFixed64(input.ReadFixed64());
457 return true;
458 case WireFormat.WireType.LengthDelimited:
459 GetFieldBuilder(number).AddLengthDelimited(input.ReadBytes());
460 return true;
461 case WireFormat.WireType.StartGroup:
462 {
463 Builder subBuilder = CreateBuilder();
464#pragma warning disable 0612
465 input.ReadUnknownGroup(number, subBuilder);
466#pragma warning restore 0612
467 GetFieldBuilder(number).AddGroup(subBuilder.Build());
468 return true;
469 }
470 case WireFormat.WireType.EndGroup:
471 return false;
472 case WireFormat.WireType.Fixed32:
473 GetFieldBuilder(number).AddFixed32(input.ReadFixed32());
474 return true;
475 default:
476 throw InvalidProtocolBufferException.InvalidWireType();
477 }
478 }
479
480 /// <summary>
481 /// Parses <paramref name="input"/> as an UnknownFieldSet and merge it
482 /// with the set being built. This is just a small wrapper around
483 /// MergeFrom(CodedInputStream).
484 /// </summary>
485 public Builder MergeFrom(Stream input)
486 {
487 CodedInputStream codedInput = CodedInputStream.CreateInstance(input);
488 MergeFrom(codedInput);
489 codedInput.CheckLastTagWas(0);
490 return this;
491 }
492
493 /// <summary>
494 /// Parses <paramref name="data"/> as an UnknownFieldSet and merge it
495 /// with the set being built. This is just a small wrapper around
496 /// MergeFrom(CodedInputStream).
497 /// </summary>
498 public Builder MergeFrom(ByteString data)
499 {
500 CodedInputStream input = data.CreateCodedInput();
501 MergeFrom(input);
502 input.CheckLastTagWas(0);
503 return this;
504 }
505
506 /// <summary>
507 /// Parses <paramref name="data"/> as an UnknownFieldSet and merge it
508 /// with the set being built. This is just a small wrapper around
509 /// MergeFrom(CodedInputStream).
510 /// </summary>
511 public Builder MergeFrom(byte[] data)
512 {
513 CodedInputStream input = CodedInputStream.CreateInstance(data);
514 MergeFrom(input);
515 input.CheckLastTagWas(0);
516 return this;
517 }
518
519 /// <summary>
520 /// Convenience method for merging a new field containing a single varint
521 /// value. This is used in particular when an unknown enum value is
522 /// encountered.
523 /// </summary>
524 [CLSCompliant(false)]
525 public Builder MergeVarintField(int number, ulong value)
526 {
527 if (number == 0)
528 {
529 throw new ArgumentOutOfRangeException("number", "Zero is not a valid field number.");
530 }
531 GetFieldBuilder(number).AddVarint(value);
532 return this;
533 }
534
535 /// <summary>
536 /// Merges the fields from <paramref name="other"/> into this set.
537 /// If a field number exists in both sets, the values in <paramref name="other"/>
538 /// will be appended to the values in this set.
539 /// </summary>
540 public Builder MergeFrom(UnknownFieldSet other)
541 {
542 if (other != DefaultInstance)
543 {
544 foreach (KeyValuePair<int, UnknownField> entry in other.fields)
545 {
546 MergeField(entry.Key, entry.Value);
547 }
548 }
549 return this;
550 }
551
552 /// <summary>
553 /// Checks if the given field number is present in the set.
554 /// </summary>
555 public bool HasField(int number)
556 {
557 if (number == 0)
558 {
559 throw new ArgumentOutOfRangeException("number", "Zero is not a valid field number.");
560 }
561 return number == lastFieldNumber || fields.ContainsKey(number);
562 }
563
564 /// <summary>
565 /// Adds a field to the unknown field set. If a field with the same
566 /// number already exists, the two are merged.
567 /// </summary>
568 public Builder MergeField(int number, UnknownField field)
569 {
570 if (number == 0)
571 {
572 throw new ArgumentOutOfRangeException("number", "Zero is not a valid field number.");
573 }
574 if (HasField(number))
575 {
576 GetFieldBuilder(number).MergeFrom(field);
577 }
578 else
579 {
580 // Optimization: We could call getFieldBuilder(number).mergeFrom(field)
581 // in this case, but that would create a copy of the Field object.
582 // We'd rather reuse the one passed to us, so call AddField() instead.
583 AddField(number, field);
584 }
585 return this;
586 }
587
588 internal void MergeFrom(CodedInputStream input, ExtensionRegistry extensionRegistry, IBuilder builder)
589 {
csharptest123e5342011-06-03 14:15:21 -0500590 uint tag;
591 string name;
592 while (input.ReadTag(out tag, out name))
csharptest71f662c2011-05-20 15:15:34 -0500593 {
csharptest71f662c2011-05-20 15:15:34 -0500594 if (tag == 0)
595 {
csharptest123e5342011-06-03 14:15:21 -0500596 if (input.SkipField())
597 continue; //can't merge unknown without field tag
csharptest71f662c2011-05-20 15:15:34 -0500598 break;
599 }
600
601 if (!MergeFieldFrom(input, extensionRegistry, builder, tag))
602 {
603 // end group tag
604 break;
605 }
606 }
607 }
608
609 /// <summary>
610 /// Like <see cref="MergeFrom(CodedInputStream, ExtensionRegistry, IBuilder)" />
611 /// but parses a single field.
612 /// </summary>
613 /// <param name="input">The input to read the field from</param>
614 /// <param name="extensionRegistry">Registry to use when an extension field is encountered</param>
615 /// <param name="builder">Builder to merge field into, if it's a known field</param>
616 /// <param name="tag">The tag, which should already have been read from the input</param>
617 /// <returns>true unless the tag is an end-group tag</returns>
618 internal bool MergeFieldFrom(CodedInputStream input,
619 ExtensionRegistry extensionRegistry, IBuilder builder, uint tag)
620 {
621 MessageDescriptor type = builder.DescriptorForType;
622 if (type.Options.MessageSetWireFormat && tag == WireFormat.MessageSetTag.ItemStart)
623 {
624 MergeMessageSetExtensionFromCodedStream(input, extensionRegistry, builder);
625 return true;
626 }
627
628 WireFormat.WireType wireType = WireFormat.GetTagWireType(tag);
629 int fieldNumber = WireFormat.GetTagFieldNumber(tag);
630
631 FieldDescriptor field;
632 IMessageLite defaultFieldInstance = null;
633
634 if (type.IsExtensionNumber(fieldNumber))
635 {
636 ExtensionInfo extension = extensionRegistry[type, fieldNumber];
637 if (extension == null)
638 {
639 field = null;
640 }
641 else
642 {
643 field = extension.Descriptor;
644 defaultFieldInstance = extension.DefaultInstance;
645 }
646 }
647 else
648 {
649 field = type.FindFieldByNumber(fieldNumber);
650 }
651
652 // Unknown field or wrong wire type. Skip.
653 if (field == null || wireType != WireFormat.GetWireType(field))
654 {
655 return MergeFieldFrom(tag, input);
656 }
657
658 if (field.IsPacked)
659 {
660 int length = (int) input.ReadRawVarint32();
661 int limit = input.PushLimit(length);
662 if (field.FieldType == FieldType.Enum)
663 {
664 while (!input.ReachedLimit)
665 {
666 int rawValue = input.ReadEnum();
667 object value = field.EnumType.FindValueByNumber(rawValue);
668 if (value == null)
669 {
670 // If the number isn't recognized as a valid value for this
671 // enum, drop it (don't even add it to unknownFields).
672 return true;
673 }
674 builder.WeakAddRepeatedField(field, value);
675 }
676 }
677 else
678 {
679 while (!input.ReachedLimit)
680 {
681 Object value = input.ReadPrimitiveField(field.FieldType);
682 builder.WeakAddRepeatedField(field, value);
683 }
684 }
685 input.PopLimit(limit);
686 }
687 else
688 {
689 object value;
690 switch (field.FieldType)
691 {
692 case FieldType.Group:
693 case FieldType.Message:
694 {
695 IBuilderLite subBuilder;
696 if (defaultFieldInstance != null)
697 {
698 subBuilder = defaultFieldInstance.WeakCreateBuilderForType();
699 }
700 else
701 {
702 subBuilder = builder.CreateBuilderForField(field);
703 }
704 if (!field.IsRepeated)
705 {
706 subBuilder.WeakMergeFrom((IMessageLite) builder[field]);
707 }
708 if (field.FieldType == FieldType.Group)
709 {
710 input.ReadGroup(field.FieldNumber, subBuilder, extensionRegistry);
711 }
712 else
713 {
714 input.ReadMessage(subBuilder, extensionRegistry);
715 }
716 value = subBuilder.WeakBuild();
717 break;
718 }
719 case FieldType.Enum:
720 {
721 int rawValue = input.ReadEnum();
722 value = field.EnumType.FindValueByNumber(rawValue);
723 // If the number isn't recognized as a valid value for this enum,
724 // drop it.
725 if (value == null)
726 {
727 MergeVarintField(fieldNumber, (ulong) rawValue);
728 return true;
729 }
730 break;
731 }
732 default:
733 value = input.ReadPrimitiveField(field.FieldType);
734 break;
735 }
736 if (field.IsRepeated)
737 {
738 builder.WeakAddRepeatedField(field, value);
739 }
740 else
741 {
742 builder[field] = value;
743 }
744 }
745 return true;
746 }
747
748 /// <summary>
749 /// Called by MergeFieldFrom to parse a MessageSet extension.
750 /// </summary>
751 private void MergeMessageSetExtensionFromCodedStream(CodedInputStream input,
752 ExtensionRegistry extensionRegistry, IBuilder builder)
753 {
754 MessageDescriptor type = builder.DescriptorForType;
755
756 // The wire format for MessageSet is:
757 // message MessageSet {
758 // repeated group Item = 1 {
759 // required int32 typeId = 2;
760 // required bytes message = 3;
761 // }
762 // }
763 // "typeId" is the extension's field number. The extension can only be
764 // a message type, where "message" contains the encoded bytes of that
765 // message.
766 //
767 // In practice, we will probably never see a MessageSet item in which
768 // the message appears before the type ID, or where either field does not
769 // appear exactly once. However, in theory such cases are valid, so we
770 // should be prepared to accept them.
771
772 int typeId = 0;
773 ByteString rawBytes = null; // If we encounter "message" before "typeId"
774 IBuilderLite subBuilder = null;
775 FieldDescriptor field = null;
776
csharptest123e5342011-06-03 14:15:21 -0500777 uint tag;
778 string name;
779 while (input.ReadTag(out tag, out name))
csharptest71f662c2011-05-20 15:15:34 -0500780 {
csharptest71f662c2011-05-20 15:15:34 -0500781 if (tag == 0)
782 {
csharptest123e5342011-06-03 14:15:21 -0500783 if (input.SkipField())
784 continue; //can't merge unknown without field tag
csharptest71f662c2011-05-20 15:15:34 -0500785 break;
786 }
787
788 if (tag == WireFormat.MessageSetTag.TypeID)
789 {
790 typeId = input.ReadInt32();
791 // Zero is not a valid type ID.
792 if (typeId != 0)
793 {
794 ExtensionInfo extension = extensionRegistry[type, typeId];
795 if (extension != null)
796 {
797 field = extension.Descriptor;
798 subBuilder = extension.DefaultInstance.WeakCreateBuilderForType();
799 IMessageLite originalMessage = (IMessageLite) builder[field];
800 if (originalMessage != null)
801 {
802 subBuilder.WeakMergeFrom(originalMessage);
803 }
804 if (rawBytes != null)
805 {
806 // We already encountered the message. Parse it now.
807 // TODO(jonskeet): Check this is okay. It's subtly different from the Java, as it doesn't create an input stream from rawBytes.
808 // In fact, why don't we just call MergeFrom(rawBytes)? And what about the extension registry?
809 subBuilder.WeakMergeFrom(rawBytes.CreateCodedInput());
810 rawBytes = null;
811 }
812 }
813 else
814 {
815 // Unknown extension number. If we already saw data, put it
816 // in rawBytes.
817 if (rawBytes != null)
818 {
819 MergeField(typeId, UnknownField.CreateBuilder().AddLengthDelimited(rawBytes).Build());
820 rawBytes = null;
821 }
822 }
823 }
824 }
825 else if (tag == WireFormat.MessageSetTag.Message)
826 {
827 if (typeId == 0)
828 {
829 // We haven't seen a type ID yet, so we have to store the raw bytes for now.
830 rawBytes = input.ReadBytes();
831 }
832 else if (subBuilder == null)
833 {
834 // We don't know how to parse this. Ignore it.
835 MergeField(typeId,
836 UnknownField.CreateBuilder().AddLengthDelimited(input.ReadBytes()).Build());
837 }
838 else
839 {
840 // We already know the type, so we can parse directly from the input
841 // with no copying. Hooray!
842 input.ReadMessage(subBuilder, extensionRegistry);
843 }
844 }
845 else
846 {
847 // Unknown tag. Skip it.
csharptest123e5342011-06-03 14:15:21 -0500848 if (!input.SkipField())
csharptest71f662c2011-05-20 15:15:34 -0500849 {
850 break; // end of group
851 }
852 }
853 }
854
855 input.CheckLastTagWas(WireFormat.MessageSetTag.ItemEnd);
856
857 if (subBuilder != null)
858 {
859 builder[field] = subBuilder.WeakBuild();
860 }
861 }
862
863 #region IBuilderLite Members
864
865 bool IBuilderLite.IsInitialized
866 {
867 get { return fields != null; }
868 }
869
870 IBuilderLite IBuilderLite.WeakClear()
871 {
872 return Clear();
873 }
874
875 IBuilderLite IBuilderLite.WeakMergeFrom(IMessageLite message)
876 {
877 return MergeFrom((UnknownFieldSet) message);
878 }
879
880 IBuilderLite IBuilderLite.WeakMergeFrom(ByteString data)
881 {
882 return MergeFrom(data);
883 }
884
885 IBuilderLite IBuilderLite.WeakMergeFrom(ByteString data, ExtensionRegistry registry)
886 {
887 return MergeFrom(data);
888 }
889
890 IBuilderLite IBuilderLite.WeakMergeFrom(CodedInputStream input)
891 {
892 return MergeFrom(input);
893 }
894
895 IBuilderLite IBuilderLite.WeakMergeFrom(CodedInputStream input, ExtensionRegistry registry)
896 {
897 return MergeFrom(input);
898 }
899
900 IMessageLite IBuilderLite.WeakBuild()
901 {
902 return Build();
903 }
904
905 IMessageLite IBuilderLite.WeakBuildPartial()
906 {
907 return Build();
908 }
909
910 IBuilderLite IBuilderLite.WeakClone()
911 {
912 return Build().WeakToBuilder();
913 }
914
915 IMessageLite IBuilderLite.WeakDefaultInstanceForType
916 {
917 get { return DefaultInstance; }
918 }
919
920 #endregion
921 }
csharptestd965c662011-05-20 13:57:07 -0500922 }
csharptest71f662c2011-05-20 15:15:34 -0500923}