blob: 0918503eabfdb0b827fecc37d59d2749e80ff2a7 [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 {
csharptest2b868842011-06-10 14:41:47 -0500449 if (tag == 0)
450 {
451 input.SkipField();
452 return true;
453 }
454
csharptest71f662c2011-05-20 15:15:34 -0500455 int number = WireFormat.GetTagFieldNumber(tag);
456 switch (WireFormat.GetTagWireType(tag))
457 {
458 case WireFormat.WireType.Varint:
csharptestd2af9e92011-06-03 21:35:02 -0500459 {
460 ulong uint64 = 0;
461 if(input.ReadUInt64(ref uint64))
462 GetFieldBuilder(number).AddVarint(uint64);
463 return true;
464 }
465 case WireFormat.WireType.Fixed32:
466 {
467 uint uint32 = 0;
468 if (input.ReadFixed32(ref uint32))
469 GetFieldBuilder(number).AddFixed32(uint32);
470 return true;
471 }
csharptest71f662c2011-05-20 15:15:34 -0500472 case WireFormat.WireType.Fixed64:
csharptestd2af9e92011-06-03 21:35:02 -0500473 {
474 ulong uint64 = 0;
475 if (input.ReadFixed64(ref uint64))
476 GetFieldBuilder(number).AddFixed64(uint64);
477 return true;
478 }
csharptest71f662c2011-05-20 15:15:34 -0500479 case WireFormat.WireType.LengthDelimited:
csharptestd2af9e92011-06-03 21:35:02 -0500480 {
481 ByteString bytes = null;
482 if (input.ReadBytes(ref bytes))
483 GetFieldBuilder(number).AddLengthDelimited(bytes);
484 return true;
485 }
csharptest71f662c2011-05-20 15:15:34 -0500486 case WireFormat.WireType.StartGroup:
487 {
488 Builder subBuilder = CreateBuilder();
489#pragma warning disable 0612
490 input.ReadUnknownGroup(number, subBuilder);
491#pragma warning restore 0612
492 GetFieldBuilder(number).AddGroup(subBuilder.Build());
493 return true;
494 }
495 case WireFormat.WireType.EndGroup:
496 return false;
csharptest71f662c2011-05-20 15:15:34 -0500497 default:
498 throw InvalidProtocolBufferException.InvalidWireType();
499 }
500 }
501
502 /// <summary>
503 /// Parses <paramref name="input"/> as an UnknownFieldSet and merge it
504 /// with the set being built. This is just a small wrapper around
csharptest17699c22011-06-03 21:57:15 -0500505 /// MergeFrom(ICodedInputStream).
csharptest71f662c2011-05-20 15:15:34 -0500506 /// </summary>
507 public Builder MergeFrom(Stream input)
508 {
509 CodedInputStream codedInput = CodedInputStream.CreateInstance(input);
510 MergeFrom(codedInput);
511 codedInput.CheckLastTagWas(0);
512 return this;
513 }
514
515 /// <summary>
516 /// Parses <paramref name="data"/> as an UnknownFieldSet and merge it
517 /// with the set being built. This is just a small wrapper around
csharptest17699c22011-06-03 21:57:15 -0500518 /// MergeFrom(ICodedInputStream).
csharptest71f662c2011-05-20 15:15:34 -0500519 /// </summary>
520 public Builder MergeFrom(ByteString data)
521 {
522 CodedInputStream input = data.CreateCodedInput();
523 MergeFrom(input);
524 input.CheckLastTagWas(0);
525 return this;
526 }
527
528 /// <summary>
529 /// Parses <paramref name="data"/> as an UnknownFieldSet and merge it
530 /// with the set being built. This is just a small wrapper around
csharptest17699c22011-06-03 21:57:15 -0500531 /// MergeFrom(ICodedInputStream).
csharptest71f662c2011-05-20 15:15:34 -0500532 /// </summary>
533 public Builder MergeFrom(byte[] data)
534 {
535 CodedInputStream input = CodedInputStream.CreateInstance(data);
536 MergeFrom(input);
537 input.CheckLastTagWas(0);
538 return this;
539 }
540
541 /// <summary>
542 /// Convenience method for merging a new field containing a single varint
543 /// value. This is used in particular when an unknown enum value is
544 /// encountered.
545 /// </summary>
546 [CLSCompliant(false)]
547 public Builder MergeVarintField(int number, ulong value)
548 {
549 if (number == 0)
550 {
551 throw new ArgumentOutOfRangeException("number", "Zero is not a valid field number.");
552 }
553 GetFieldBuilder(number).AddVarint(value);
554 return this;
555 }
556
557 /// <summary>
558 /// Merges the fields from <paramref name="other"/> into this set.
559 /// If a field number exists in both sets, the values in <paramref name="other"/>
560 /// will be appended to the values in this set.
561 /// </summary>
562 public Builder MergeFrom(UnknownFieldSet other)
563 {
564 if (other != DefaultInstance)
565 {
566 foreach (KeyValuePair<int, UnknownField> entry in other.fields)
567 {
568 MergeField(entry.Key, entry.Value);
569 }
570 }
571 return this;
572 }
573
574 /// <summary>
575 /// Checks if the given field number is present in the set.
576 /// </summary>
577 public bool HasField(int number)
578 {
579 if (number == 0)
580 {
581 throw new ArgumentOutOfRangeException("number", "Zero is not a valid field number.");
582 }
583 return number == lastFieldNumber || fields.ContainsKey(number);
584 }
585
586 /// <summary>
587 /// Adds a field to the unknown field set. If a field with the same
588 /// number already exists, the two are merged.
589 /// </summary>
590 public Builder MergeField(int number, UnknownField field)
591 {
592 if (number == 0)
593 {
594 throw new ArgumentOutOfRangeException("number", "Zero is not a valid field number.");
595 }
596 if (HasField(number))
597 {
598 GetFieldBuilder(number).MergeFrom(field);
599 }
600 else
601 {
602 // Optimization: We could call getFieldBuilder(number).mergeFrom(field)
603 // in this case, but that would create a copy of the Field object.
604 // We'd rather reuse the one passed to us, so call AddField() instead.
605 AddField(number, field);
606 }
607 return this;
608 }
609
csharptest17699c22011-06-03 21:57:15 -0500610 internal void MergeFrom(ICodedInputStream input, ExtensionRegistry extensionRegistry, IBuilder builder)
csharptest71f662c2011-05-20 15:15:34 -0500611 {
csharptest123e5342011-06-03 14:15:21 -0500612 uint tag;
613 string name;
614 while (input.ReadTag(out tag, out name))
csharptest71f662c2011-05-20 15:15:34 -0500615 {
csharptest920b09a2011-06-08 20:13:29 -0500616 if (tag == 0 && name != null)
617 {
618 FieldDescriptor fieldByName = builder.DescriptorForType.FindFieldByName(name);
619 if (fieldByName != null)
620 tag = WireFormat.MakeTag(fieldByName);
621 else
622 {
623 ExtensionInfo extension = extensionRegistry.FindByName(builder.DescriptorForType, name);
624 if (extension != null)
625 tag = WireFormat.MakeTag(extension.Descriptor);
626 }
627 }
csharptest71f662c2011-05-20 15:15:34 -0500628 if (tag == 0)
629 {
csharptest123e5342011-06-03 14:15:21 -0500630 if (input.SkipField())
631 continue; //can't merge unknown without field tag
csharptest71f662c2011-05-20 15:15:34 -0500632 break;
633 }
634
csharptestd2af9e92011-06-03 21:35:02 -0500635 if (!MergeFieldFrom(input, extensionRegistry, builder, tag, name))
csharptest71f662c2011-05-20 15:15:34 -0500636 {
637 // end group tag
638 break;
639 }
640 }
641 }
642
643 /// <summary>
csharptest17699c22011-06-03 21:57:15 -0500644 /// Like <see cref="MergeFrom(ICodedInputStream, ExtensionRegistry, IBuilder)" />
csharptest71f662c2011-05-20 15:15:34 -0500645 /// but parses a single field.
646 /// </summary>
647 /// <param name="input">The input to read the field from</param>
648 /// <param name="extensionRegistry">Registry to use when an extension field is encountered</param>
649 /// <param name="builder">Builder to merge field into, if it's a known field</param>
650 /// <param name="tag">The tag, which should already have been read from the input</param>
651 /// <returns>true unless the tag is an end-group tag</returns>
csharptest17699c22011-06-03 21:57:15 -0500652 internal bool MergeFieldFrom(ICodedInputStream input,
csharptestd2af9e92011-06-03 21:35:02 -0500653 ExtensionRegistry extensionRegistry, IBuilder builder, uint tag, string fieldName)
csharptest71f662c2011-05-20 15:15:34 -0500654 {
csharptest920b09a2011-06-08 20:13:29 -0500655 if (tag == 0 && fieldName != null)
656 {
657 FieldDescriptor fieldByName = builder.DescriptorForType.FindFieldByName(fieldName);
658 if (fieldByName != null)
659 tag = WireFormat.MakeTag(fieldByName);
660 else
661 {
662 ExtensionInfo extension = extensionRegistry.FindByName(builder.DescriptorForType, fieldName);
663 if (extension != null)
664 tag = WireFormat.MakeTag(extension.Descriptor);
665 }
666 }
667
csharptest71f662c2011-05-20 15:15:34 -0500668 MessageDescriptor type = builder.DescriptorForType;
669 if (type.Options.MessageSetWireFormat && tag == WireFormat.MessageSetTag.ItemStart)
670 {
671 MergeMessageSetExtensionFromCodedStream(input, extensionRegistry, builder);
672 return true;
673 }
674
675 WireFormat.WireType wireType = WireFormat.GetTagWireType(tag);
676 int fieldNumber = WireFormat.GetTagFieldNumber(tag);
677
678 FieldDescriptor field;
679 IMessageLite defaultFieldInstance = null;
680
681 if (type.IsExtensionNumber(fieldNumber))
682 {
683 ExtensionInfo extension = extensionRegistry[type, fieldNumber];
684 if (extension == null)
685 {
686 field = null;
687 }
688 else
689 {
690 field = extension.Descriptor;
691 defaultFieldInstance = extension.DefaultInstance;
692 }
693 }
694 else
695 {
696 field = type.FindFieldByNumber(fieldNumber);
697 }
698
699 // Unknown field or wrong wire type. Skip.
csharptest6da31702011-06-04 12:52:57 -0500700 if (field == null)
csharptest71f662c2011-05-20 15:15:34 -0500701 {
702 return MergeFieldFrom(tag, input);
703 }
csharptest6da31702011-06-04 12:52:57 -0500704 if (wireType != WireFormat.GetWireType(field))
705 {
706 WireFormat.WireType expectedType = WireFormat.GetWireType(field.FieldType);
707 if (wireType == expectedType)
708 {
709 //Allowed as of 2.3, this is unpacked data for a packed array
710 }
711 else if (field.IsRepeated && wireType == WireFormat.WireType.LengthDelimited &&
712 (expectedType == WireFormat.WireType.Varint || expectedType == WireFormat.WireType.Fixed32 || expectedType == WireFormat.WireType.Fixed64))
713 {
714 //Allowed as of 2.3, this is packed data for an unpacked array
715 }
716 else
717 return MergeFieldFrom(tag, input);
718 }
csharptest71f662c2011-05-20 15:15:34 -0500719
csharptestd2af9e92011-06-03 21:35:02 -0500720 switch (field.FieldType)
csharptest71f662c2011-05-20 15:15:34 -0500721 {
csharptestd2af9e92011-06-03 21:35:02 -0500722 case FieldType.Group:
723 case FieldType.Message:
csharptest71f662c2011-05-20 15:15:34 -0500724 {
csharptestd2af9e92011-06-03 21:35:02 -0500725 IBuilderLite subBuilder = (defaultFieldInstance != null) ? defaultFieldInstance.WeakCreateBuilderForType() : builder.CreateBuilderForField(field);
726 if (!field.IsRepeated)
csharptest71f662c2011-05-20 15:15:34 -0500727 {
csharptestd2af9e92011-06-03 21:35:02 -0500728 subBuilder.WeakMergeFrom((IMessageLite)builder[field]);
729 if (field.FieldType == FieldType.Group)
730 input.ReadGroup(field.FieldNumber, subBuilder, extensionRegistry);
731 else
732 input.ReadMessage(subBuilder, extensionRegistry);
733 builder[field] = subBuilder.WeakBuild();
734 }
735 else
736 {
737 List<IMessageLite> list = new List<IMessageLite>();
738 if (field.FieldType == FieldType.Group)
739 input.ReadGroupArray(tag, fieldName, list, subBuilder.WeakDefaultInstanceForType, extensionRegistry);
740 else
741 input.ReadMessageArray(tag, fieldName, list, subBuilder.WeakDefaultInstanceForType, extensionRegistry);
742
743 foreach (IMessageLite m in list)
744 builder.WeakAddRepeatedField(field, m);
csharptest71f662c2011-05-20 15:15:34 -0500745 return true;
746 }
csharptest71f662c2011-05-20 15:15:34 -0500747 break;
csharptestd2af9e92011-06-03 21:35:02 -0500748 }
749 case FieldType.Enum:
750 {
751 if (!field.IsRepeated)
752 {
753 object unknown;
754 IEnumLite value = null;
755 if (input.ReadEnum(ref value, out unknown, field.EnumType))
756 builder[field] = value;
757 else if(unknown is int)
758 MergeVarintField(fieldNumber, (ulong)(int)unknown);
759 }
760 else
761 {
762 ICollection<object> unknown;
763 List<IEnumLite> list = new List<IEnumLite>();
764 input.ReadEnumArray(tag, fieldName, list, out unknown, field.EnumType);
765
766 foreach (IEnumLite en in list)
767 builder.WeakAddRepeatedField(field, en);
768
769 if (unknown != null)
770 {
771 foreach (object oval in unknown)
772 if (oval is int)
773 MergeVarintField(fieldNumber, (ulong)(int)oval);
774 }
775 }
776 break;
777 }
778 default:
779 {
780 if (!field.IsRepeated)
781 {
782 object value = null;
783 if (input.ReadPrimitiveField(field.FieldType, ref value))
784 builder[field] = value;
785 }
786 else
787 {
788 List<object> list = new List<object>();
789 input.ReadPrimitiveArray(field.FieldType, tag, fieldName, list);
790 foreach (object oval in list)
791 builder.WeakAddRepeatedField(field, oval);
792 }
793 break;
794 }
csharptest71f662c2011-05-20 15:15:34 -0500795 }
796 return true;
797 }
798
799 /// <summary>
800 /// Called by MergeFieldFrom to parse a MessageSet extension.
801 /// </summary>
csharptest17699c22011-06-03 21:57:15 -0500802 private void MergeMessageSetExtensionFromCodedStream(ICodedInputStream input,
csharptest71f662c2011-05-20 15:15:34 -0500803 ExtensionRegistry extensionRegistry, IBuilder builder)
804 {
805 MessageDescriptor type = builder.DescriptorForType;
806
807 // The wire format for MessageSet is:
808 // message MessageSet {
809 // repeated group Item = 1 {
810 // required int32 typeId = 2;
811 // required bytes message = 3;
812 // }
813 // }
814 // "typeId" is the extension's field number. The extension can only be
815 // a message type, where "message" contains the encoded bytes of that
816 // message.
817 //
818 // In practice, we will probably never see a MessageSet item in which
819 // the message appears before the type ID, or where either field does not
820 // appear exactly once. However, in theory such cases are valid, so we
821 // should be prepared to accept them.
822
823 int typeId = 0;
824 ByteString rawBytes = null; // If we encounter "message" before "typeId"
825 IBuilderLite subBuilder = null;
826 FieldDescriptor field = null;
827
csharptest17699c22011-06-03 21:57:15 -0500828 uint lastTag = WireFormat.MessageSetTag.ItemStart;
csharptest123e5342011-06-03 14:15:21 -0500829 uint tag;
830 string name;
831 while (input.ReadTag(out tag, out name))
csharptest71f662c2011-05-20 15:15:34 -0500832 {
csharptest920b09a2011-06-08 20:13:29 -0500833 if (tag == 0 && name != null)
834 {
835 if (name == "type_id") tag = WireFormat.MessageSetTag.TypeID;
836 else if (name == "message") tag = WireFormat.MessageSetTag.Message;
837 }
csharptest71f662c2011-05-20 15:15:34 -0500838 if (tag == 0)
839 {
csharptest123e5342011-06-03 14:15:21 -0500840 if (input.SkipField())
841 continue; //can't merge unknown without field tag
csharptest71f662c2011-05-20 15:15:34 -0500842 break;
843 }
844
csharptest17699c22011-06-03 21:57:15 -0500845 lastTag = tag;
csharptest71f662c2011-05-20 15:15:34 -0500846 if (tag == WireFormat.MessageSetTag.TypeID)
847 {
csharptestd2af9e92011-06-03 21:35:02 -0500848 typeId = 0;
csharptest71f662c2011-05-20 15:15:34 -0500849 // Zero is not a valid type ID.
csharptestd2af9e92011-06-03 21:35:02 -0500850 if (input.ReadInt32(ref typeId) && typeId != 0)
csharptest71f662c2011-05-20 15:15:34 -0500851 {
852 ExtensionInfo extension = extensionRegistry[type, typeId];
853 if (extension != null)
854 {
855 field = extension.Descriptor;
856 subBuilder = extension.DefaultInstance.WeakCreateBuilderForType();
857 IMessageLite originalMessage = (IMessageLite) builder[field];
858 if (originalMessage != null)
859 {
860 subBuilder.WeakMergeFrom(originalMessage);
861 }
862 if (rawBytes != null)
863 {
864 // We already encountered the message. Parse it now.
865 // TODO(jonskeet): Check this is okay. It's subtly different from the Java, as it doesn't create an input stream from rawBytes.
866 // In fact, why don't we just call MergeFrom(rawBytes)? And what about the extension registry?
867 subBuilder.WeakMergeFrom(rawBytes.CreateCodedInput());
868 rawBytes = null;
869 }
870 }
871 else
872 {
873 // Unknown extension number. If we already saw data, put it
874 // in rawBytes.
875 if (rawBytes != null)
876 {
877 MergeField(typeId, UnknownField.CreateBuilder().AddLengthDelimited(rawBytes).Build());
878 rawBytes = null;
879 }
880 }
881 }
882 }
883 else if (tag == WireFormat.MessageSetTag.Message)
884 {
csharptestd2af9e92011-06-03 21:35:02 -0500885 if(subBuilder != null)
csharptest71f662c2011-05-20 15:15:34 -0500886 {
887 // We already know the type, so we can parse directly from the input
888 // with no copying. Hooray!
889 input.ReadMessage(subBuilder, extensionRegistry);
890 }
csharptestd2af9e92011-06-03 21:35:02 -0500891 else if (input.ReadBytes(ref rawBytes))
892 {
893 if (typeId != 0)
894 {
895 // We don't know how to parse this. Ignore it.
896 MergeField(typeId,
897 UnknownField.CreateBuilder().AddLengthDelimited(rawBytes).Build());
898 }
899 }
csharptest71f662c2011-05-20 15:15:34 -0500900 }
901 else
902 {
903 // Unknown tag. Skip it.
csharptest123e5342011-06-03 14:15:21 -0500904 if (!input.SkipField())
csharptest71f662c2011-05-20 15:15:34 -0500905 {
906 break; // end of group
907 }
908 }
909 }
910
csharptest17699c22011-06-03 21:57:15 -0500911 if (lastTag != WireFormat.MessageSetTag.ItemEnd)
912 throw InvalidProtocolBufferException.InvalidEndTag();
csharptest71f662c2011-05-20 15:15:34 -0500913
914 if (subBuilder != null)
915 {
916 builder[field] = subBuilder.WeakBuild();
917 }
918 }
919
920 #region IBuilderLite Members
921
922 bool IBuilderLite.IsInitialized
923 {
924 get { return fields != null; }
925 }
926
927 IBuilderLite IBuilderLite.WeakClear()
928 {
929 return Clear();
930 }
931
932 IBuilderLite IBuilderLite.WeakMergeFrom(IMessageLite message)
933 {
934 return MergeFrom((UnknownFieldSet) message);
935 }
936
937 IBuilderLite IBuilderLite.WeakMergeFrom(ByteString data)
938 {
939 return MergeFrom(data);
940 }
941
942 IBuilderLite IBuilderLite.WeakMergeFrom(ByteString data, ExtensionRegistry registry)
943 {
944 return MergeFrom(data);
945 }
946
csharptest17699c22011-06-03 21:57:15 -0500947 IBuilderLite IBuilderLite.WeakMergeFrom(ICodedInputStream input)
csharptest71f662c2011-05-20 15:15:34 -0500948 {
949 return MergeFrom(input);
950 }
951
csharptest17699c22011-06-03 21:57:15 -0500952 IBuilderLite IBuilderLite.WeakMergeFrom(ICodedInputStream input, ExtensionRegistry registry)
csharptest71f662c2011-05-20 15:15:34 -0500953 {
954 return MergeFrom(input);
955 }
956
957 IMessageLite IBuilderLite.WeakBuild()
958 {
959 return Build();
960 }
961
962 IMessageLite IBuilderLite.WeakBuildPartial()
963 {
964 return Build();
965 }
966
967 IBuilderLite IBuilderLite.WeakClone()
968 {
969 return Build().WeakToBuilder();
970 }
971
972 IMessageLite IBuilderLite.WeakDefaultInstanceForType
973 {
974 get { return DefaultInstance; }
975 }
976
977 #endregion
978 }
csharptestd965c662011-05-20 13:57:07 -0500979 }
csharptest71f662c2011-05-20 15:15:34 -0500980}