blob: 70910cbf96c9689affccd64ae5254da4c92f7265 [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 {
csharptest71f662c2011-05-20 15:15:34 -0500610 if (tag == 0)
611 {
csharptest123e5342011-06-03 14:15:21 -0500612 if (input.SkipField())
613 continue; //can't merge unknown without field tag
csharptest71f662c2011-05-20 15:15:34 -0500614 break;
615 }
616
csharptestd2af9e92011-06-03 21:35:02 -0500617 if (!MergeFieldFrom(input, extensionRegistry, builder, tag, name))
csharptest71f662c2011-05-20 15:15:34 -0500618 {
619 // end group tag
620 break;
621 }
622 }
623 }
624
625 /// <summary>
csharptest17699c22011-06-03 21:57:15 -0500626 /// Like <see cref="MergeFrom(ICodedInputStream, ExtensionRegistry, IBuilder)" />
csharptest71f662c2011-05-20 15:15:34 -0500627 /// but parses a single field.
628 /// </summary>
629 /// <param name="input">The input to read the field from</param>
630 /// <param name="extensionRegistry">Registry to use when an extension field is encountered</param>
631 /// <param name="builder">Builder to merge field into, if it's a known field</param>
632 /// <param name="tag">The tag, which should already have been read from the input</param>
633 /// <returns>true unless the tag is an end-group tag</returns>
csharptest17699c22011-06-03 21:57:15 -0500634 internal bool MergeFieldFrom(ICodedInputStream input,
csharptestd2af9e92011-06-03 21:35:02 -0500635 ExtensionRegistry extensionRegistry, IBuilder builder, uint tag, string fieldName)
csharptest71f662c2011-05-20 15:15:34 -0500636 {
637 MessageDescriptor type = builder.DescriptorForType;
638 if (type.Options.MessageSetWireFormat && tag == WireFormat.MessageSetTag.ItemStart)
639 {
640 MergeMessageSetExtensionFromCodedStream(input, extensionRegistry, builder);
641 return true;
642 }
643
644 WireFormat.WireType wireType = WireFormat.GetTagWireType(tag);
645 int fieldNumber = WireFormat.GetTagFieldNumber(tag);
646
647 FieldDescriptor field;
648 IMessageLite defaultFieldInstance = null;
649
650 if (type.IsExtensionNumber(fieldNumber))
651 {
652 ExtensionInfo extension = extensionRegistry[type, fieldNumber];
653 if (extension == null)
654 {
655 field = null;
656 }
657 else
658 {
659 field = extension.Descriptor;
660 defaultFieldInstance = extension.DefaultInstance;
661 }
662 }
663 else
664 {
665 field = type.FindFieldByNumber(fieldNumber);
666 }
667
668 // Unknown field or wrong wire type. Skip.
csharptest6da31702011-06-04 12:52:57 -0500669 if (field == null)
csharptest71f662c2011-05-20 15:15:34 -0500670 {
671 return MergeFieldFrom(tag, input);
672 }
csharptest6da31702011-06-04 12:52:57 -0500673 if (wireType != WireFormat.GetWireType(field))
674 {
675 WireFormat.WireType expectedType = WireFormat.GetWireType(field.FieldType);
676 if (wireType == expectedType)
677 {
678 //Allowed as of 2.3, this is unpacked data for a packed array
679 }
680 else if (field.IsRepeated && wireType == WireFormat.WireType.LengthDelimited &&
681 (expectedType == WireFormat.WireType.Varint || expectedType == WireFormat.WireType.Fixed32 || expectedType == WireFormat.WireType.Fixed64))
682 {
683 //Allowed as of 2.3, this is packed data for an unpacked array
684 }
685 else
686 return MergeFieldFrom(tag, input);
687 }
csharptest71f662c2011-05-20 15:15:34 -0500688
csharptestd2af9e92011-06-03 21:35:02 -0500689 switch (field.FieldType)
csharptest71f662c2011-05-20 15:15:34 -0500690 {
csharptestd2af9e92011-06-03 21:35:02 -0500691 case FieldType.Group:
692 case FieldType.Message:
csharptest71f662c2011-05-20 15:15:34 -0500693 {
csharptestd2af9e92011-06-03 21:35:02 -0500694 IBuilderLite subBuilder = (defaultFieldInstance != null) ? defaultFieldInstance.WeakCreateBuilderForType() : builder.CreateBuilderForField(field);
695 if (!field.IsRepeated)
csharptest71f662c2011-05-20 15:15:34 -0500696 {
csharptestd2af9e92011-06-03 21:35:02 -0500697 subBuilder.WeakMergeFrom((IMessageLite)builder[field]);
698 if (field.FieldType == FieldType.Group)
699 input.ReadGroup(field.FieldNumber, subBuilder, extensionRegistry);
700 else
701 input.ReadMessage(subBuilder, extensionRegistry);
702 builder[field] = subBuilder.WeakBuild();
703 }
704 else
705 {
706 List<IMessageLite> list = new List<IMessageLite>();
707 if (field.FieldType == FieldType.Group)
708 input.ReadGroupArray(tag, fieldName, list, subBuilder.WeakDefaultInstanceForType, extensionRegistry);
709 else
710 input.ReadMessageArray(tag, fieldName, list, subBuilder.WeakDefaultInstanceForType, extensionRegistry);
711
712 foreach (IMessageLite m in list)
713 builder.WeakAddRepeatedField(field, m);
csharptest71f662c2011-05-20 15:15:34 -0500714 return true;
715 }
csharptest71f662c2011-05-20 15:15:34 -0500716 break;
csharptestd2af9e92011-06-03 21:35:02 -0500717 }
718 case FieldType.Enum:
719 {
720 if (!field.IsRepeated)
721 {
722 object unknown;
723 IEnumLite value = null;
724 if (input.ReadEnum(ref value, out unknown, field.EnumType))
725 builder[field] = value;
726 else if(unknown is int)
727 MergeVarintField(fieldNumber, (ulong)(int)unknown);
728 }
729 else
730 {
731 ICollection<object> unknown;
732 List<IEnumLite> list = new List<IEnumLite>();
733 input.ReadEnumArray(tag, fieldName, list, out unknown, field.EnumType);
734
735 foreach (IEnumLite en in list)
736 builder.WeakAddRepeatedField(field, en);
737
738 if (unknown != null)
739 {
740 foreach (object oval in unknown)
741 if (oval is int)
742 MergeVarintField(fieldNumber, (ulong)(int)oval);
743 }
744 }
745 break;
746 }
747 default:
748 {
749 if (!field.IsRepeated)
750 {
751 object value = null;
752 if (input.ReadPrimitiveField(field.FieldType, ref value))
753 builder[field] = value;
754 }
755 else
756 {
757 List<object> list = new List<object>();
758 input.ReadPrimitiveArray(field.FieldType, tag, fieldName, list);
759 foreach (object oval in list)
760 builder.WeakAddRepeatedField(field, oval);
761 }
762 break;
763 }
csharptest71f662c2011-05-20 15:15:34 -0500764 }
765 return true;
766 }
767
768 /// <summary>
769 /// Called by MergeFieldFrom to parse a MessageSet extension.
770 /// </summary>
csharptest17699c22011-06-03 21:57:15 -0500771 private void MergeMessageSetExtensionFromCodedStream(ICodedInputStream input,
csharptest71f662c2011-05-20 15:15:34 -0500772 ExtensionRegistry extensionRegistry, IBuilder builder)
773 {
774 MessageDescriptor type = builder.DescriptorForType;
775
776 // The wire format for MessageSet is:
777 // message MessageSet {
778 // repeated group Item = 1 {
779 // required int32 typeId = 2;
780 // required bytes message = 3;
781 // }
782 // }
783 // "typeId" is the extension's field number. The extension can only be
784 // a message type, where "message" contains the encoded bytes of that
785 // message.
786 //
787 // In practice, we will probably never see a MessageSet item in which
788 // the message appears before the type ID, or where either field does not
789 // appear exactly once. However, in theory such cases are valid, so we
790 // should be prepared to accept them.
791
792 int typeId = 0;
793 ByteString rawBytes = null; // If we encounter "message" before "typeId"
794 IBuilderLite subBuilder = null;
795 FieldDescriptor field = null;
796
csharptest17699c22011-06-03 21:57:15 -0500797 uint lastTag = WireFormat.MessageSetTag.ItemStart;
csharptest123e5342011-06-03 14:15:21 -0500798 uint tag;
799 string name;
800 while (input.ReadTag(out tag, out name))
csharptest71f662c2011-05-20 15:15:34 -0500801 {
csharptest71f662c2011-05-20 15:15:34 -0500802 if (tag == 0)
803 {
csharptest123e5342011-06-03 14:15:21 -0500804 if (input.SkipField())
805 continue; //can't merge unknown without field tag
csharptest71f662c2011-05-20 15:15:34 -0500806 break;
807 }
808
csharptest17699c22011-06-03 21:57:15 -0500809 lastTag = tag;
csharptest71f662c2011-05-20 15:15:34 -0500810 if (tag == WireFormat.MessageSetTag.TypeID)
811 {
csharptestd2af9e92011-06-03 21:35:02 -0500812 typeId = 0;
csharptest71f662c2011-05-20 15:15:34 -0500813 // Zero is not a valid type ID.
csharptestd2af9e92011-06-03 21:35:02 -0500814 if (input.ReadInt32(ref typeId) && typeId != 0)
csharptest71f662c2011-05-20 15:15:34 -0500815 {
816 ExtensionInfo extension = extensionRegistry[type, typeId];
817 if (extension != null)
818 {
819 field = extension.Descriptor;
820 subBuilder = extension.DefaultInstance.WeakCreateBuilderForType();
821 IMessageLite originalMessage = (IMessageLite) builder[field];
822 if (originalMessage != null)
823 {
824 subBuilder.WeakMergeFrom(originalMessage);
825 }
826 if (rawBytes != null)
827 {
828 // We already encountered the message. Parse it now.
829 // TODO(jonskeet): Check this is okay. It's subtly different from the Java, as it doesn't create an input stream from rawBytes.
830 // In fact, why don't we just call MergeFrom(rawBytes)? And what about the extension registry?
831 subBuilder.WeakMergeFrom(rawBytes.CreateCodedInput());
832 rawBytes = null;
833 }
834 }
835 else
836 {
837 // Unknown extension number. If we already saw data, put it
838 // in rawBytes.
839 if (rawBytes != null)
840 {
841 MergeField(typeId, UnknownField.CreateBuilder().AddLengthDelimited(rawBytes).Build());
842 rawBytes = null;
843 }
844 }
845 }
846 }
847 else if (tag == WireFormat.MessageSetTag.Message)
848 {
csharptestd2af9e92011-06-03 21:35:02 -0500849 if(subBuilder != null)
csharptest71f662c2011-05-20 15:15:34 -0500850 {
851 // We already know the type, so we can parse directly from the input
852 // with no copying. Hooray!
853 input.ReadMessage(subBuilder, extensionRegistry);
854 }
csharptestd2af9e92011-06-03 21:35:02 -0500855 else if (input.ReadBytes(ref rawBytes))
856 {
857 if (typeId != 0)
858 {
859 // We don't know how to parse this. Ignore it.
860 MergeField(typeId,
861 UnknownField.CreateBuilder().AddLengthDelimited(rawBytes).Build());
862 }
863 }
csharptest71f662c2011-05-20 15:15:34 -0500864 }
865 else
866 {
867 // Unknown tag. Skip it.
csharptest123e5342011-06-03 14:15:21 -0500868 if (!input.SkipField())
csharptest71f662c2011-05-20 15:15:34 -0500869 {
870 break; // end of group
871 }
872 }
873 }
874
csharptest17699c22011-06-03 21:57:15 -0500875 if (lastTag != WireFormat.MessageSetTag.ItemEnd)
876 throw InvalidProtocolBufferException.InvalidEndTag();
csharptest71f662c2011-05-20 15:15:34 -0500877
878 if (subBuilder != null)
879 {
880 builder[field] = subBuilder.WeakBuild();
881 }
882 }
883
884 #region IBuilderLite Members
885
886 bool IBuilderLite.IsInitialized
887 {
888 get { return fields != null; }
889 }
890
891 IBuilderLite IBuilderLite.WeakClear()
892 {
893 return Clear();
894 }
895
896 IBuilderLite IBuilderLite.WeakMergeFrom(IMessageLite message)
897 {
898 return MergeFrom((UnknownFieldSet) message);
899 }
900
901 IBuilderLite IBuilderLite.WeakMergeFrom(ByteString data)
902 {
903 return MergeFrom(data);
904 }
905
906 IBuilderLite IBuilderLite.WeakMergeFrom(ByteString data, ExtensionRegistry registry)
907 {
908 return MergeFrom(data);
909 }
910
csharptest17699c22011-06-03 21:57:15 -0500911 IBuilderLite IBuilderLite.WeakMergeFrom(ICodedInputStream input)
csharptest71f662c2011-05-20 15:15:34 -0500912 {
913 return MergeFrom(input);
914 }
915
csharptest17699c22011-06-03 21:57:15 -0500916 IBuilderLite IBuilderLite.WeakMergeFrom(ICodedInputStream input, ExtensionRegistry registry)
csharptest71f662c2011-05-20 15:15:34 -0500917 {
918 return MergeFrom(input);
919 }
920
921 IMessageLite IBuilderLite.WeakBuild()
922 {
923 return Build();
924 }
925
926 IMessageLite IBuilderLite.WeakBuildPartial()
927 {
928 return Build();
929 }
930
931 IBuilderLite IBuilderLite.WeakClone()
932 {
933 return Build().WeakToBuilder();
934 }
935
936 IMessageLite IBuilderLite.WeakDefaultInstanceForType
937 {
938 get { return DefaultInstance; }
939 }
940
941 #endregion
942 }
csharptestd965c662011-05-20 13:57:07 -0500943 }
csharptest71f662c2011-05-20 15:15:34 -0500944}