blob: fbafb8929a22b4cc600013a4b5373db83722a967 [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>
csharptest17699c22011-06-03 21:57:15 -0500254 public static UnknownFieldSet ParseFrom(ICodedInputStream input)
csharptest71f662c2011-05-20 15:15:34 -0500255 {
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>
csharptest17699c22011-06-03 21:57:15 -0500420 public Builder MergeFrom(ICodedInputStream input)
csharptest71f662c2011-05-20 15:15:34 -0500421 {
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)]
csharptest17699c22011-06-03 21:57:15 -0500447 public bool MergeFieldFrom(uint tag, ICodedInputStream input)
csharptest71f662c2011-05-20 15:15:34 -0500448 {
449 int number = WireFormat.GetTagFieldNumber(tag);
450 switch (WireFormat.GetTagWireType(tag))
451 {
452 case WireFormat.WireType.Varint:
csharptestd2af9e92011-06-03 21:35:02 -0500453 {
454 ulong uint64 = 0;
455 if(input.ReadUInt64(ref uint64))
456 GetFieldBuilder(number).AddVarint(uint64);
457 return true;
458 }
459 case WireFormat.WireType.Fixed32:
460 {
461 uint uint32 = 0;
462 if (input.ReadFixed32(ref uint32))
463 GetFieldBuilder(number).AddFixed32(uint32);
464 return true;
465 }
csharptest71f662c2011-05-20 15:15:34 -0500466 case WireFormat.WireType.Fixed64:
csharptestd2af9e92011-06-03 21:35:02 -0500467 {
468 ulong uint64 = 0;
469 if (input.ReadFixed64(ref uint64))
470 GetFieldBuilder(number).AddFixed64(uint64);
471 return true;
472 }
csharptest71f662c2011-05-20 15:15:34 -0500473 case WireFormat.WireType.LengthDelimited:
csharptestd2af9e92011-06-03 21:35:02 -0500474 {
475 ByteString bytes = null;
476 if (input.ReadBytes(ref bytes))
477 GetFieldBuilder(number).AddLengthDelimited(bytes);
478 return true;
479 }
csharptest71f662c2011-05-20 15:15:34 -0500480 case WireFormat.WireType.StartGroup:
481 {
482 Builder subBuilder = CreateBuilder();
483#pragma warning disable 0612
484 input.ReadUnknownGroup(number, subBuilder);
485#pragma warning restore 0612
486 GetFieldBuilder(number).AddGroup(subBuilder.Build());
487 return true;
488 }
489 case WireFormat.WireType.EndGroup:
490 return false;
csharptest71f662c2011-05-20 15:15:34 -0500491 default:
492 throw InvalidProtocolBufferException.InvalidWireType();
493 }
494 }
495
496 /// <summary>
497 /// Parses <paramref name="input"/> as an UnknownFieldSet and merge it
498 /// with the set being built. This is just a small wrapper around
csharptest17699c22011-06-03 21:57:15 -0500499 /// MergeFrom(ICodedInputStream).
csharptest71f662c2011-05-20 15:15:34 -0500500 /// </summary>
501 public Builder MergeFrom(Stream input)
502 {
503 CodedInputStream codedInput = CodedInputStream.CreateInstance(input);
504 MergeFrom(codedInput);
505 codedInput.CheckLastTagWas(0);
506 return this;
507 }
508
509 /// <summary>
510 /// Parses <paramref name="data"/> as an UnknownFieldSet and merge it
511 /// with the set being built. This is just a small wrapper around
csharptest17699c22011-06-03 21:57:15 -0500512 /// MergeFrom(ICodedInputStream).
csharptest71f662c2011-05-20 15:15:34 -0500513 /// </summary>
514 public Builder MergeFrom(ByteString data)
515 {
516 CodedInputStream input = data.CreateCodedInput();
517 MergeFrom(input);
518 input.CheckLastTagWas(0);
519 return this;
520 }
521
522 /// <summary>
523 /// Parses <paramref name="data"/> as an UnknownFieldSet and merge it
524 /// with the set being built. This is just a small wrapper around
csharptest17699c22011-06-03 21:57:15 -0500525 /// MergeFrom(ICodedInputStream).
csharptest71f662c2011-05-20 15:15:34 -0500526 /// </summary>
527 public Builder MergeFrom(byte[] data)
528 {
529 CodedInputStream input = CodedInputStream.CreateInstance(data);
530 MergeFrom(input);
531 input.CheckLastTagWas(0);
532 return this;
533 }
534
535 /// <summary>
536 /// Convenience method for merging a new field containing a single varint
537 /// value. This is used in particular when an unknown enum value is
538 /// encountered.
539 /// </summary>
540 [CLSCompliant(false)]
541 public Builder MergeVarintField(int number, ulong value)
542 {
543 if (number == 0)
544 {
545 throw new ArgumentOutOfRangeException("number", "Zero is not a valid field number.");
546 }
547 GetFieldBuilder(number).AddVarint(value);
548 return this;
549 }
550
551 /// <summary>
552 /// Merges the fields from <paramref name="other"/> into this set.
553 /// If a field number exists in both sets, the values in <paramref name="other"/>
554 /// will be appended to the values in this set.
555 /// </summary>
556 public Builder MergeFrom(UnknownFieldSet other)
557 {
558 if (other != DefaultInstance)
559 {
560 foreach (KeyValuePair<int, UnknownField> entry in other.fields)
561 {
562 MergeField(entry.Key, entry.Value);
563 }
564 }
565 return this;
566 }
567
568 /// <summary>
569 /// Checks if the given field number is present in the set.
570 /// </summary>
571 public bool HasField(int number)
572 {
573 if (number == 0)
574 {
575 throw new ArgumentOutOfRangeException("number", "Zero is not a valid field number.");
576 }
577 return number == lastFieldNumber || fields.ContainsKey(number);
578 }
579
580 /// <summary>
581 /// Adds a field to the unknown field set. If a field with the same
582 /// number already exists, the two are merged.
583 /// </summary>
584 public Builder MergeField(int number, UnknownField field)
585 {
586 if (number == 0)
587 {
588 throw new ArgumentOutOfRangeException("number", "Zero is not a valid field number.");
589 }
590 if (HasField(number))
591 {
592 GetFieldBuilder(number).MergeFrom(field);
593 }
594 else
595 {
596 // Optimization: We could call getFieldBuilder(number).mergeFrom(field)
597 // in this case, but that would create a copy of the Field object.
598 // We'd rather reuse the one passed to us, so call AddField() instead.
599 AddField(number, field);
600 }
601 return this;
602 }
603
csharptest17699c22011-06-03 21:57:15 -0500604 internal void MergeFrom(ICodedInputStream input, ExtensionRegistry extensionRegistry, IBuilder builder)
csharptest71f662c2011-05-20 15:15:34 -0500605 {
csharptest123e5342011-06-03 14:15:21 -0500606 uint tag;
607 string name;
608 while (input.ReadTag(out tag, out name))
csharptest71f662c2011-05-20 15:15:34 -0500609 {
csharptest920b09a2011-06-08 20:13:29 -0500610 if (tag == 0 && name != null)
611 {
612 FieldDescriptor fieldByName = builder.DescriptorForType.FindFieldByName(name);
613 if (fieldByName != null)
614 tag = WireFormat.MakeTag(fieldByName);
615 else
616 {
617 ExtensionInfo extension = extensionRegistry.FindByName(builder.DescriptorForType, name);
618 if (extension != null)
619 tag = WireFormat.MakeTag(extension.Descriptor);
620 }
621 }
csharptest71f662c2011-05-20 15:15:34 -0500622 if (tag == 0)
623 {
csharptest123e5342011-06-03 14:15:21 -0500624 if (input.SkipField())
625 continue; //can't merge unknown without field tag
csharptest71f662c2011-05-20 15:15:34 -0500626 break;
627 }
628
csharptestd2af9e92011-06-03 21:35:02 -0500629 if (!MergeFieldFrom(input, extensionRegistry, builder, tag, name))
csharptest71f662c2011-05-20 15:15:34 -0500630 {
631 // end group tag
632 break;
633 }
634 }
635 }
636
637 /// <summary>
csharptest17699c22011-06-03 21:57:15 -0500638 /// Like <see cref="MergeFrom(ICodedInputStream, ExtensionRegistry, IBuilder)" />
csharptest71f662c2011-05-20 15:15:34 -0500639 /// but parses a single field.
640 /// </summary>
641 /// <param name="input">The input to read the field from</param>
642 /// <param name="extensionRegistry">Registry to use when an extension field is encountered</param>
643 /// <param name="builder">Builder to merge field into, if it's a known field</param>
644 /// <param name="tag">The tag, which should already have been read from the input</param>
645 /// <returns>true unless the tag is an end-group tag</returns>
csharptest17699c22011-06-03 21:57:15 -0500646 internal bool MergeFieldFrom(ICodedInputStream input,
csharptestd2af9e92011-06-03 21:35:02 -0500647 ExtensionRegistry extensionRegistry, IBuilder builder, uint tag, string fieldName)
csharptest71f662c2011-05-20 15:15:34 -0500648 {
csharptest920b09a2011-06-08 20:13:29 -0500649 if (tag == 0 && fieldName != null)
650 {
651 FieldDescriptor fieldByName = builder.DescriptorForType.FindFieldByName(fieldName);
652 if (fieldByName != null)
653 tag = WireFormat.MakeTag(fieldByName);
654 else
655 {
656 ExtensionInfo extension = extensionRegistry.FindByName(builder.DescriptorForType, fieldName);
657 if (extension != null)
658 tag = WireFormat.MakeTag(extension.Descriptor);
659 }
660 }
661
csharptest71f662c2011-05-20 15:15:34 -0500662 MessageDescriptor type = builder.DescriptorForType;
663 if (type.Options.MessageSetWireFormat && tag == WireFormat.MessageSetTag.ItemStart)
664 {
665 MergeMessageSetExtensionFromCodedStream(input, extensionRegistry, builder);
666 return true;
667 }
668
669 WireFormat.WireType wireType = WireFormat.GetTagWireType(tag);
670 int fieldNumber = WireFormat.GetTagFieldNumber(tag);
671
672 FieldDescriptor field;
673 IMessageLite defaultFieldInstance = null;
674
675 if (type.IsExtensionNumber(fieldNumber))
676 {
677 ExtensionInfo extension = extensionRegistry[type, fieldNumber];
678 if (extension == null)
679 {
680 field = null;
681 }
682 else
683 {
684 field = extension.Descriptor;
685 defaultFieldInstance = extension.DefaultInstance;
686 }
687 }
688 else
689 {
690 field = type.FindFieldByNumber(fieldNumber);
691 }
692
693 // Unknown field or wrong wire type. Skip.
csharptest6da31702011-06-04 12:52:57 -0500694 if (field == null)
csharptest71f662c2011-05-20 15:15:34 -0500695 {
696 return MergeFieldFrom(tag, input);
697 }
csharptest6da31702011-06-04 12:52:57 -0500698 if (wireType != WireFormat.GetWireType(field))
699 {
700 WireFormat.WireType expectedType = WireFormat.GetWireType(field.FieldType);
701 if (wireType == expectedType)
702 {
703 //Allowed as of 2.3, this is unpacked data for a packed array
704 }
705 else if (field.IsRepeated && wireType == WireFormat.WireType.LengthDelimited &&
706 (expectedType == WireFormat.WireType.Varint || expectedType == WireFormat.WireType.Fixed32 || expectedType == WireFormat.WireType.Fixed64))
707 {
708 //Allowed as of 2.3, this is packed data for an unpacked array
709 }
710 else
711 return MergeFieldFrom(tag, input);
712 }
csharptest71f662c2011-05-20 15:15:34 -0500713
csharptestd2af9e92011-06-03 21:35:02 -0500714 switch (field.FieldType)
csharptest71f662c2011-05-20 15:15:34 -0500715 {
csharptestd2af9e92011-06-03 21:35:02 -0500716 case FieldType.Group:
717 case FieldType.Message:
csharptest71f662c2011-05-20 15:15:34 -0500718 {
csharptestd2af9e92011-06-03 21:35:02 -0500719 IBuilderLite subBuilder = (defaultFieldInstance != null) ? defaultFieldInstance.WeakCreateBuilderForType() : builder.CreateBuilderForField(field);
720 if (!field.IsRepeated)
csharptest71f662c2011-05-20 15:15:34 -0500721 {
csharptestd2af9e92011-06-03 21:35:02 -0500722 subBuilder.WeakMergeFrom((IMessageLite)builder[field]);
723 if (field.FieldType == FieldType.Group)
724 input.ReadGroup(field.FieldNumber, subBuilder, extensionRegistry);
725 else
726 input.ReadMessage(subBuilder, extensionRegistry);
727 builder[field] = subBuilder.WeakBuild();
728 }
729 else
730 {
731 List<IMessageLite> list = new List<IMessageLite>();
732 if (field.FieldType == FieldType.Group)
733 input.ReadGroupArray(tag, fieldName, list, subBuilder.WeakDefaultInstanceForType, extensionRegistry);
734 else
735 input.ReadMessageArray(tag, fieldName, list, subBuilder.WeakDefaultInstanceForType, extensionRegistry);
736
737 foreach (IMessageLite m in list)
738 builder.WeakAddRepeatedField(field, m);
csharptest71f662c2011-05-20 15:15:34 -0500739 return true;
740 }
csharptest71f662c2011-05-20 15:15:34 -0500741 break;
csharptestd2af9e92011-06-03 21:35:02 -0500742 }
743 case FieldType.Enum:
744 {
745 if (!field.IsRepeated)
746 {
747 object unknown;
748 IEnumLite value = null;
749 if (input.ReadEnum(ref value, out unknown, field.EnumType))
750 builder[field] = value;
751 else if(unknown is int)
752 MergeVarintField(fieldNumber, (ulong)(int)unknown);
753 }
754 else
755 {
756 ICollection<object> unknown;
757 List<IEnumLite> list = new List<IEnumLite>();
758 input.ReadEnumArray(tag, fieldName, list, out unknown, field.EnumType);
759
760 foreach (IEnumLite en in list)
761 builder.WeakAddRepeatedField(field, en);
762
763 if (unknown != null)
764 {
765 foreach (object oval in unknown)
766 if (oval is int)
767 MergeVarintField(fieldNumber, (ulong)(int)oval);
768 }
769 }
770 break;
771 }
772 default:
773 {
774 if (!field.IsRepeated)
775 {
776 object value = null;
777 if (input.ReadPrimitiveField(field.FieldType, ref value))
778 builder[field] = value;
779 }
780 else
781 {
782 List<object> list = new List<object>();
783 input.ReadPrimitiveArray(field.FieldType, tag, fieldName, list);
784 foreach (object oval in list)
785 builder.WeakAddRepeatedField(field, oval);
786 }
787 break;
788 }
csharptest71f662c2011-05-20 15:15:34 -0500789 }
790 return true;
791 }
792
793 /// <summary>
794 /// Called by MergeFieldFrom to parse a MessageSet extension.
795 /// </summary>
csharptest17699c22011-06-03 21:57:15 -0500796 private void MergeMessageSetExtensionFromCodedStream(ICodedInputStream input,
csharptest71f662c2011-05-20 15:15:34 -0500797 ExtensionRegistry extensionRegistry, IBuilder builder)
798 {
799 MessageDescriptor type = builder.DescriptorForType;
800
801 // The wire format for MessageSet is:
802 // message MessageSet {
803 // repeated group Item = 1 {
804 // required int32 typeId = 2;
805 // required bytes message = 3;
806 // }
807 // }
808 // "typeId" is the extension's field number. The extension can only be
809 // a message type, where "message" contains the encoded bytes of that
810 // message.
811 //
812 // In practice, we will probably never see a MessageSet item in which
813 // the message appears before the type ID, or where either field does not
814 // appear exactly once. However, in theory such cases are valid, so we
815 // should be prepared to accept them.
816
817 int typeId = 0;
818 ByteString rawBytes = null; // If we encounter "message" before "typeId"
819 IBuilderLite subBuilder = null;
820 FieldDescriptor field = null;
821
csharptest17699c22011-06-03 21:57:15 -0500822 uint lastTag = WireFormat.MessageSetTag.ItemStart;
csharptest123e5342011-06-03 14:15:21 -0500823 uint tag;
824 string name;
825 while (input.ReadTag(out tag, out name))
csharptest71f662c2011-05-20 15:15:34 -0500826 {
csharptest920b09a2011-06-08 20:13:29 -0500827 if (tag == 0 && name != null)
828 {
829 if (name == "type_id") tag = WireFormat.MessageSetTag.TypeID;
830 else if (name == "message") tag = WireFormat.MessageSetTag.Message;
831 }
csharptest71f662c2011-05-20 15:15:34 -0500832 if (tag == 0)
833 {
csharptest123e5342011-06-03 14:15:21 -0500834 if (input.SkipField())
835 continue; //can't merge unknown without field tag
csharptest71f662c2011-05-20 15:15:34 -0500836 break;
837 }
838
csharptest17699c22011-06-03 21:57:15 -0500839 lastTag = tag;
csharptest71f662c2011-05-20 15:15:34 -0500840 if (tag == WireFormat.MessageSetTag.TypeID)
841 {
csharptestd2af9e92011-06-03 21:35:02 -0500842 typeId = 0;
csharptest71f662c2011-05-20 15:15:34 -0500843 // Zero is not a valid type ID.
csharptestd2af9e92011-06-03 21:35:02 -0500844 if (input.ReadInt32(ref typeId) && typeId != 0)
csharptest71f662c2011-05-20 15:15:34 -0500845 {
846 ExtensionInfo extension = extensionRegistry[type, typeId];
847 if (extension != null)
848 {
849 field = extension.Descriptor;
850 subBuilder = extension.DefaultInstance.WeakCreateBuilderForType();
851 IMessageLite originalMessage = (IMessageLite) builder[field];
852 if (originalMessage != null)
853 {
854 subBuilder.WeakMergeFrom(originalMessage);
855 }
856 if (rawBytes != null)
857 {
858 // We already encountered the message. Parse it now.
859 // TODO(jonskeet): Check this is okay. It's subtly different from the Java, as it doesn't create an input stream from rawBytes.
860 // In fact, why don't we just call MergeFrom(rawBytes)? And what about the extension registry?
861 subBuilder.WeakMergeFrom(rawBytes.CreateCodedInput());
862 rawBytes = null;
863 }
864 }
865 else
866 {
867 // Unknown extension number. If we already saw data, put it
868 // in rawBytes.
869 if (rawBytes != null)
870 {
871 MergeField(typeId, UnknownField.CreateBuilder().AddLengthDelimited(rawBytes).Build());
872 rawBytes = null;
873 }
874 }
875 }
876 }
877 else if (tag == WireFormat.MessageSetTag.Message)
878 {
csharptestd2af9e92011-06-03 21:35:02 -0500879 if(subBuilder != null)
csharptest71f662c2011-05-20 15:15:34 -0500880 {
881 // We already know the type, so we can parse directly from the input
882 // with no copying. Hooray!
883 input.ReadMessage(subBuilder, extensionRegistry);
884 }
csharptestd2af9e92011-06-03 21:35:02 -0500885 else if (input.ReadBytes(ref rawBytes))
886 {
887 if (typeId != 0)
888 {
889 // We don't know how to parse this. Ignore it.
890 MergeField(typeId,
891 UnknownField.CreateBuilder().AddLengthDelimited(rawBytes).Build());
892 }
893 }
csharptest71f662c2011-05-20 15:15:34 -0500894 }
895 else
896 {
897 // Unknown tag. Skip it.
csharptest123e5342011-06-03 14:15:21 -0500898 if (!input.SkipField())
csharptest71f662c2011-05-20 15:15:34 -0500899 {
900 break; // end of group
901 }
902 }
903 }
904
csharptest17699c22011-06-03 21:57:15 -0500905 if (lastTag != WireFormat.MessageSetTag.ItemEnd)
906 throw InvalidProtocolBufferException.InvalidEndTag();
csharptest71f662c2011-05-20 15:15:34 -0500907
908 if (subBuilder != null)
909 {
910 builder[field] = subBuilder.WeakBuild();
911 }
912 }
913
914 #region IBuilderLite Members
915
916 bool IBuilderLite.IsInitialized
917 {
918 get { return fields != null; }
919 }
920
921 IBuilderLite IBuilderLite.WeakClear()
922 {
923 return Clear();
924 }
925
926 IBuilderLite IBuilderLite.WeakMergeFrom(IMessageLite message)
927 {
928 return MergeFrom((UnknownFieldSet) message);
929 }
930
931 IBuilderLite IBuilderLite.WeakMergeFrom(ByteString data)
932 {
933 return MergeFrom(data);
934 }
935
936 IBuilderLite IBuilderLite.WeakMergeFrom(ByteString data, ExtensionRegistry registry)
937 {
938 return MergeFrom(data);
939 }
940
csharptest17699c22011-06-03 21:57:15 -0500941 IBuilderLite IBuilderLite.WeakMergeFrom(ICodedInputStream input)
csharptest71f662c2011-05-20 15:15:34 -0500942 {
943 return MergeFrom(input);
944 }
945
csharptest17699c22011-06-03 21:57:15 -0500946 IBuilderLite IBuilderLite.WeakMergeFrom(ICodedInputStream input, ExtensionRegistry registry)
csharptest71f662c2011-05-20 15:15:34 -0500947 {
948 return MergeFrom(input);
949 }
950
951 IMessageLite IBuilderLite.WeakBuild()
952 {
953 return Build();
954 }
955
956 IMessageLite IBuilderLite.WeakBuildPartial()
957 {
958 return Build();
959 }
960
961 IBuilderLite IBuilderLite.WeakClone()
962 {
963 return Build().WeakToBuilder();
964 }
965
966 IMessageLite IBuilderLite.WeakDefaultInstanceForType
967 {
968 get { return DefaultInstance; }
969 }
970
971 #endregion
972 }
csharptestd965c662011-05-20 13:57:07 -0500973 }
csharptest71f662c2011-05-20 15:15:34 -0500974}