Free cookie consent management tool by TermsFeed Policy Generator

source: branches/RemoveBackwardsCompatibility/HeuristicLab.ExtLibs/HeuristicLab.ProtobufCS/2.4.1/ProtobufCS/src/ProtocolBuffers/UnknownFieldSet.cs

Last change on this file was 8295, checked in by abeham, 12 years ago

#1897:

  • Removed protocol buffers 0.9.1
  • Added protocol buffers 2.4.1
  • Updated proto processing command
File size: 41.0 KB
Line 
1#region Copyright notice and license
2
3// 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.
34
35#endregion
36
37using System;
38using System.Collections.Generic;
39using System.IO;
40using Google.ProtocolBuffers.Collections;
41using Google.ProtocolBuffers.Descriptors;
42
43namespace Google.ProtocolBuffers
44{
45    /// <summary>
46    /// Used to keep track of fields which were seen when parsing a protocol message
47    /// but whose field numbers or types are unrecognized. This most frequently
48    /// occurs when new fields are added to a message type and then messages containing
49    /// those fields are read by old software that was built before the new types were
50    /// added.
51    ///
52    /// Every message contains an UnknownFieldSet.
53    ///
54    /// Most users will never need to use this class directly.
55    /// </summary>
56    public sealed partial class UnknownFieldSet : IMessageLite
57    {
58        private static readonly UnknownFieldSet defaultInstance =
59            new UnknownFieldSet(new Dictionary<int, UnknownField>());
60
61        private readonly IDictionary<int, UnknownField> fields;
62
63        private UnknownFieldSet(IDictionary<int, UnknownField> fields)
64        {
65            this.fields = fields;
66        }
67
68        /// <summary>
69        /// Creates a new unknown field set builder.
70        /// </summary>
71        public static Builder CreateBuilder()
72        {
73            return new Builder();
74        }
75
76        /// <summary>
77        /// Creates a new unknown field set builder
78        /// and initialize it from <paramref name="original"/>.
79        /// </summary>
80        public static Builder CreateBuilder(UnknownFieldSet original)
81        {
82            return new Builder().MergeFrom(original);
83        }
84
85        public static UnknownFieldSet DefaultInstance
86        {
87            get { return defaultInstance; }
88        }
89
90        /// <summary>
91        /// Returns a read-only view of the mapping from field numbers to values.
92        /// </summary>
93        public IDictionary<int, UnknownField> FieldDictionary
94        {
95            get { return Dictionaries.AsReadOnly(fields); }
96        }
97
98        /// <summary>
99        /// Checks whether or not the given field number is present in the set.
100        /// </summary>
101        public bool HasField(int field)
102        {
103            return fields.ContainsKey(field);
104        }
105
106        /// <summary>
107        /// Fetches a field by number, returning an empty field if not present.
108        /// Never returns null.
109        /// </summary>
110        public UnknownField this[int number]
111        {
112            get
113            {
114                UnknownField ret;
115                if (!fields.TryGetValue(number, out ret))
116                {
117                    ret = UnknownField.DefaultInstance;
118                }
119                return ret;
120            }
121        }
122
123        /// <summary>
124        /// Serializes the set and writes it to <paramref name="output"/>.
125        /// </summary>
126        public void WriteTo(ICodedOutputStream output)
127        {
128            foreach (KeyValuePair<int, UnknownField> entry in fields)
129            {
130                entry.Value.WriteTo(entry.Key, output);
131            }
132        }
133
134        /// <summary>
135        /// Gets the number of bytes required to encode this set.
136        /// </summary>
137        public int SerializedSize
138        {
139            get
140            {
141                int result = 0;
142                foreach (KeyValuePair<int, UnknownField> entry in fields)
143                {
144                    result += entry.Value.GetSerializedSize(entry.Key);
145                }
146                return result;
147            }
148        }
149
150        /// <summary>
151        /// Converts the set to a string in protocol buffer text format. This
152        /// is just a trivial wrapper around TextFormat.PrintToString.
153        /// </summary>
154        public override String ToString()
155        {
156            return TextFormat.PrintToString(this);
157        }
158
159        /// <summary>
160        /// Converts the set to a string in protocol buffer text format. This
161        /// is just a trivial wrapper around TextFormat.PrintToString.
162        /// </summary>
163        public void PrintTo(TextWriter writer)
164        {
165            TextFormat.Print(this, writer);
166        }
167
168        /// <summary>
169        /// Serializes the message to a ByteString and returns it. This is
170        /// just a trivial wrapper around WriteTo(ICodedOutputStream).
171        /// </summary>
172        /// <returns></returns>
173        public ByteString ToByteString()
174        {
175            ByteString.CodedBuilder codedBuilder = new ByteString.CodedBuilder(SerializedSize);
176            WriteTo(codedBuilder.CodedOutput);
177            return codedBuilder.Build();
178        }
179
180        /// <summary>
181        /// Serializes the message to a byte array and returns it. This is
182        /// just a trivial wrapper around WriteTo(ICodedOutputStream).
183        /// </summary>
184        /// <returns></returns>
185        public byte[] ToByteArray()
186        {
187            byte[] data = new byte[SerializedSize];
188            CodedOutputStream output = CodedOutputStream.CreateInstance(data);
189            WriteTo(output);
190            output.CheckNoSpaceLeft();
191            return data;
192        }
193
194        /// <summary>
195        /// Serializes the message and writes it to <paramref name="output"/>. This is
196        /// just a trivial wrapper around WriteTo(ICodedOutputStream).
197        /// </summary>
198        /// <param name="output"></param>
199        public void WriteTo(Stream output)
200        {
201            CodedOutputStream codedOutput = CodedOutputStream.CreateInstance(output);
202            WriteTo(codedOutput);
203            codedOutput.Flush();
204        }
205
206        /// <summary>
207        /// Serializes the set and writes it to <paramref name="output"/> using
208        /// the MessageSet wire format.
209        /// </summary>
210        public void WriteAsMessageSetTo(ICodedOutputStream output)
211        {
212            foreach (KeyValuePair<int, UnknownField> entry in fields)
213            {
214                entry.Value.WriteAsMessageSetExtensionTo(entry.Key, output);
215            }
216        }
217
218        /// <summary>
219        /// Gets the number of bytes required to encode this set using the MessageSet
220        /// wire format.
221        /// </summary>
222        public int SerializedSizeAsMessageSet
223        {
224            get
225            {
226                int result = 0;
227                foreach (KeyValuePair<int, UnknownField> entry in fields)
228                {
229                    result += entry.Value.GetSerializedSizeAsMessageSetExtension(entry.Key);
230                }
231                return result;
232            }
233        }
234
235        public override bool Equals(object other)
236        {
237            if (ReferenceEquals(this, other))
238            {
239                return true;
240            }
241            UnknownFieldSet otherSet = other as UnknownFieldSet;
242            return otherSet != null && Dictionaries.Equals(fields, otherSet.fields);
243        }
244
245        public override int GetHashCode()
246        {
247            return Dictionaries.GetHashCode(fields);
248        }
249
250        /// <summary>
251        /// Parses an UnknownFieldSet from the given input.
252        /// </summary>
253        public static UnknownFieldSet ParseFrom(ICodedInputStream input)
254        {
255            return CreateBuilder().MergeFrom(input).Build();
256        }
257
258        /// <summary>
259        /// Parses an UnknownFieldSet from the given data.
260        /// </summary>
261        public static UnknownFieldSet ParseFrom(ByteString data)
262        {
263            return CreateBuilder().MergeFrom(data).Build();
264        }
265
266        /// <summary>
267        /// Parses an UnknownFieldSet from the given data.
268        /// </summary>
269        public static UnknownFieldSet ParseFrom(byte[] data)
270        {
271            return CreateBuilder().MergeFrom(data).Build();
272        }
273
274        /// <summary>
275        /// Parses an UnknownFieldSet from the given input.
276        /// </summary>
277        public static UnknownFieldSet ParseFrom(Stream input)
278        {
279            return CreateBuilder().MergeFrom(input).Build();
280        }
281
282        #region IMessageLite Members
283
284        public bool IsInitialized
285        {
286            get { return fields != null; }
287        }
288
289        public void WriteDelimitedTo(Stream output)
290        {
291            CodedOutputStream codedOutput = CodedOutputStream.CreateInstance(output);
292            codedOutput.WriteRawVarint32((uint) SerializedSize);
293            WriteTo(codedOutput);
294            codedOutput.Flush();
295        }
296
297        public IBuilderLite WeakCreateBuilderForType()
298        {
299            return new Builder();
300        }
301
302        public IBuilderLite WeakToBuilder()
303        {
304            return new Builder(fields);
305        }
306
307        public IMessageLite WeakDefaultInstanceForType
308        {
309            get { return defaultInstance; }
310        }
311
312        #endregion
313
314        /// <summary>
315        /// Builder for UnknownFieldSets.
316        /// </summary>
317        public sealed partial class Builder : IBuilderLite
318        {
319            /// <summary>
320            /// Mapping from number to field. Note that by using a SortedList we ensure
321            /// that the fields will be serialized in ascending order.
322            /// </summary>
323            private IDictionary<int, UnknownField> fields;
324
325            // Optimization:  We keep around a builder for the last field that was
326            // modified so that we can efficiently add to it multiple times in a
327            // row (important when parsing an unknown repeated field).
328            private int lastFieldNumber;
329            private UnknownField.Builder lastField;
330
331            internal Builder()
332            {
333                fields = new SortedList<int, UnknownField>();
334            }
335
336            internal Builder(IDictionary<int, UnknownField> dictionary)
337            {
338                fields = new SortedList<int, UnknownField>(dictionary);
339            }
340
341            /// <summary>
342            /// Returns a field builder for the specified field number, including any values
343            /// which already exist.
344            /// </summary>
345            private UnknownField.Builder GetFieldBuilder(int number)
346            {
347                if (lastField != null)
348                {
349                    if (number == lastFieldNumber)
350                    {
351                        return lastField;
352                    }
353                    // Note: AddField() will reset lastField and lastFieldNumber.
354                    AddField(lastFieldNumber, lastField.Build());
355                }
356                if (number == 0)
357                {
358                    return null;
359                }
360
361                lastField = UnknownField.CreateBuilder();
362                UnknownField existing;
363                if (fields.TryGetValue(number, out existing))
364                {
365                    lastField.MergeFrom(existing);
366                }
367                lastFieldNumber = number;
368                return lastField;
369            }
370
371            /// <summary>
372            /// Build the UnknownFieldSet and return it. Once this method has been called,
373            /// this instance will no longer be usable. Calling any method after this
374            /// will throw a NullReferenceException.
375            /// </summary>
376            public UnknownFieldSet Build()
377            {
378                GetFieldBuilder(0); // Force lastField to be built.
379                UnknownFieldSet result = fields.Count == 0 ? DefaultInstance : new UnknownFieldSet(fields);
380                fields = null;
381                return result;
382            }
383
384            /// <summary>
385            /// Adds a field to the set. If a field with the same number already exists, it
386            /// is replaced.
387            /// </summary>
388            public Builder AddField(int number, UnknownField field)
389            {
390                if (number == 0)
391                {
392                    throw new ArgumentOutOfRangeException("number", "Zero is not a valid field number.");
393                }
394                if (lastField != null && lastFieldNumber == number)
395                {
396                    // Discard this.
397                    lastField = null;
398                    lastFieldNumber = 0;
399                }
400                fields[number] = field;
401                return this;
402            }
403
404            /// <summary>
405            /// Resets the builder to an empty set.
406            /// </summary>
407            public Builder Clear()
408            {
409                fields.Clear();
410                lastFieldNumber = 0;
411                lastField = null;
412                return this;
413            }
414
415            /// <summary>
416            /// Parse an entire message from <paramref name="input"/> and merge
417            /// its fields into this set.
418            /// </summary>
419            public Builder MergeFrom(ICodedInputStream input)
420            {
421                uint tag;
422                string name;
423                while (input.ReadTag(out tag, out name))
424                {
425                    if (tag == 0)
426                    {
427                        if (input.SkipField())
428                        {
429                            continue; //can't merge unknown without field tag
430                        }
431                        break;
432                    }
433
434                    if (!MergeFieldFrom(tag, input))
435                    {
436                        break;
437                    }
438                }
439                return this;
440            }
441
442            /// <summary>
443            /// Parse a single field from <paramref name="input"/> and merge it
444            /// into this set.
445            /// </summary>
446            /// <param name="tag">The field's tag number, which was already parsed.</param>
447            /// <param name="input">The coded input stream containing the field</param>
448            /// <returns>false if the tag is an "end group" tag, true otherwise</returns>
449            [CLSCompliant(false)]
450            public bool MergeFieldFrom(uint tag, ICodedInputStream input)
451            {
452                if (tag == 0)
453                {
454                    input.SkipField();
455                    return true;
456                }
457
458                int number = WireFormat.GetTagFieldNumber(tag);
459                switch (WireFormat.GetTagWireType(tag))
460                {
461                    case WireFormat.WireType.Varint:
462                        {
463                            ulong uint64 = 0;
464                            if (input.ReadUInt64(ref uint64))
465                            {
466                                GetFieldBuilder(number).AddVarint(uint64);
467                            }
468                            return true;
469                        }
470                    case WireFormat.WireType.Fixed32:
471                        {
472                            uint uint32 = 0;
473                            if (input.ReadFixed32(ref uint32))
474                            {
475                                GetFieldBuilder(number).AddFixed32(uint32);
476                            }
477                            return true;
478                        }
479                    case WireFormat.WireType.Fixed64:
480                        {
481                            ulong uint64 = 0;
482                            if (input.ReadFixed64(ref uint64))
483                            {
484                                GetFieldBuilder(number).AddFixed64(uint64);
485                            }
486                            return true;
487                        }
488                    case WireFormat.WireType.LengthDelimited:
489                        {
490                            ByteString bytes = null;
491                            if (input.ReadBytes(ref bytes))
492                            {
493                                GetFieldBuilder(number).AddLengthDelimited(bytes);
494                            }
495                            return true;
496                        }
497                    case WireFormat.WireType.StartGroup:
498                        {
499                            Builder subBuilder = CreateBuilder();
500#pragma warning disable 0612
501                            input.ReadUnknownGroup(number, subBuilder);
502#pragma warning restore 0612
503                            GetFieldBuilder(number).AddGroup(subBuilder.Build());
504                            return true;
505                        }
506                    case WireFormat.WireType.EndGroup:
507                        return false;
508                    default:
509                        throw InvalidProtocolBufferException.InvalidWireType();
510                }
511            }
512
513            /// <summary>
514            /// Parses <paramref name="input"/> as an UnknownFieldSet and merge it
515            /// with the set being built. This is just a small wrapper around
516            /// MergeFrom(ICodedInputStream).
517            /// </summary>
518            public Builder MergeFrom(Stream input)
519            {
520                CodedInputStream codedInput = CodedInputStream.CreateInstance(input);
521                MergeFrom(codedInput);
522                codedInput.CheckLastTagWas(0);
523                return this;
524            }
525
526            /// <summary>
527            /// Parses <paramref name="data"/> as an UnknownFieldSet and merge it
528            /// with the set being built. This is just a small wrapper around
529            /// MergeFrom(ICodedInputStream).
530            /// </summary>
531            public Builder MergeFrom(ByteString data)
532            {
533                CodedInputStream input = data.CreateCodedInput();
534                MergeFrom(input);
535                input.CheckLastTagWas(0);
536                return this;
537            }
538
539            /// <summary>
540            /// Parses <paramref name="data"/> as an UnknownFieldSet and merge it
541            /// with the set being built. This is just a small wrapper around
542            /// MergeFrom(ICodedInputStream).
543            /// </summary>
544            public Builder MergeFrom(byte[] data)
545            {
546                CodedInputStream input = CodedInputStream.CreateInstance(data);
547                MergeFrom(input);
548                input.CheckLastTagWas(0);
549                return this;
550            }
551
552            /// <summary>
553            /// Convenience method for merging a new field containing a single varint
554            /// value.  This is used in particular when an unknown enum value is
555            /// encountered.
556            /// </summary>
557            [CLSCompliant(false)]
558            public Builder MergeVarintField(int number, ulong value)
559            {
560                if (number == 0)
561                {
562                    throw new ArgumentOutOfRangeException("number", "Zero is not a valid field number.");
563                }
564                GetFieldBuilder(number).AddVarint(value);
565                return this;
566            }
567
568            /// <summary>
569            /// Merges the fields from <paramref name="other"/> into this set.
570            /// If a field number exists in both sets, the values in <paramref name="other"/>
571            /// will be appended to the values in this set.
572            /// </summary>
573            public Builder MergeFrom(UnknownFieldSet other)
574            {
575                if (other != DefaultInstance)
576                {
577                    foreach (KeyValuePair<int, UnknownField> entry in other.fields)
578                    {
579                        MergeField(entry.Key, entry.Value);
580                    }
581                }
582                return this;
583            }
584
585            /// <summary>
586            /// Checks if the given field number is present in the set.
587            /// </summary>
588            public bool HasField(int number)
589            {
590                if (number == 0)
591                {
592                    throw new ArgumentOutOfRangeException("number", "Zero is not a valid field number.");
593                }
594                return number == lastFieldNumber || fields.ContainsKey(number);
595            }
596
597            /// <summary>
598            /// Adds a field to the unknown field set. If a field with the same
599            /// number already exists, the two are merged.
600            /// </summary>
601            public Builder MergeField(int number, UnknownField field)
602            {
603                if (number == 0)
604                {
605                    throw new ArgumentOutOfRangeException("number", "Zero is not a valid field number.");
606                }
607                if (HasField(number))
608                {
609                    GetFieldBuilder(number).MergeFrom(field);
610                }
611                else
612                {
613                    // Optimization:  We could call getFieldBuilder(number).mergeFrom(field)
614                    // in this case, but that would create a copy of the Field object.
615                    // We'd rather reuse the one passed to us, so call AddField() instead.
616                    AddField(number, field);
617                }
618                return this;
619            }
620
621            internal void MergeFrom(ICodedInputStream input, ExtensionRegistry extensionRegistry, IBuilder builder)
622            {
623                uint tag;
624                string name;
625                while (input.ReadTag(out tag, out name))
626                {
627                    if (tag == 0 && name != null)
628                    {
629                        FieldDescriptor fieldByName = builder.DescriptorForType.FindFieldByName(name);
630                        if (fieldByName != null)
631                        {
632                            tag = WireFormat.MakeTag(fieldByName);
633                        }
634                        else
635                        {
636                            ExtensionInfo extension = extensionRegistry.FindByName(builder.DescriptorForType, name);
637                            if (extension != null)
638                            {
639                                tag = WireFormat.MakeTag(extension.Descriptor);
640                            }
641                        }
642                    }
643                    if (tag == 0)
644                    {
645                        if (input.SkipField())
646                        {
647                            continue; //can't merge unknown without field tag
648                        }
649                        break;
650                    }
651
652                    if (!MergeFieldFrom(input, extensionRegistry, builder, tag, name))
653                    {
654                        // end group tag
655                        break;
656                    }
657                }
658            }
659
660            /// <summary>
661            /// Like <see cref="MergeFrom(ICodedInputStream, ExtensionRegistry, IBuilder)" />
662            /// but parses a single field.
663            /// </summary>
664            /// <param name="input">The input to read the field from</param>
665            /// <param name="extensionRegistry">Registry to use when an extension field is encountered</param>
666            /// <param name="builder">Builder to merge field into, if it's a known field</param>
667            /// <param name="tag">The tag, which should already have been read from the input</param>
668            /// <returns>true unless the tag is an end-group tag</returns>
669            internal bool MergeFieldFrom(ICodedInputStream input,
670                                         ExtensionRegistry extensionRegistry, IBuilder builder, uint tag,
671                                         string fieldName)
672            {
673                if (tag == 0 && fieldName != null)
674                {
675                    FieldDescriptor fieldByName = builder.DescriptorForType.FindFieldByName(fieldName);
676                    if (fieldByName != null)
677                    {
678                        tag = WireFormat.MakeTag(fieldByName);
679                    }
680                    else
681                    {
682                        ExtensionInfo extension = extensionRegistry.FindByName(builder.DescriptorForType, fieldName);
683                        if (extension != null)
684                        {
685                            tag = WireFormat.MakeTag(extension.Descriptor);
686                        }
687                    }
688                }
689
690                MessageDescriptor type = builder.DescriptorForType;
691                if (type.Options.MessageSetWireFormat && tag == WireFormat.MessageSetTag.ItemStart)
692                {
693                    MergeMessageSetExtensionFromCodedStream(input, extensionRegistry, builder);
694                    return true;
695                }
696
697                WireFormat.WireType wireType = WireFormat.GetTagWireType(tag);
698                int fieldNumber = WireFormat.GetTagFieldNumber(tag);
699
700                FieldDescriptor field;
701                IMessageLite defaultFieldInstance = null;
702
703                if (type.IsExtensionNumber(fieldNumber))
704                {
705                    ExtensionInfo extension = extensionRegistry[type, fieldNumber];
706                    if (extension == null)
707                    {
708                        field = null;
709                    }
710                    else
711                    {
712                        field = extension.Descriptor;
713                        defaultFieldInstance = extension.DefaultInstance;
714                    }
715                }
716                else
717                {
718                    field = type.FindFieldByNumber(fieldNumber);
719                }
720
721                // Unknown field or wrong wire type. Skip.
722                if (field == null)
723                {
724                    return MergeFieldFrom(tag, input);
725                }
726                if (wireType != WireFormat.GetWireType(field))
727                {
728                    WireFormat.WireType expectedType = WireFormat.GetWireType(field.FieldType);
729                    if (wireType == expectedType)
730                    {
731                        //Allowed as of 2.3, this is unpacked data for a packed array
732                    }
733                    else if (field.IsRepeated && wireType == WireFormat.WireType.LengthDelimited &&
734                             (expectedType == WireFormat.WireType.Varint || expectedType == WireFormat.WireType.Fixed32 ||
735                              expectedType == WireFormat.WireType.Fixed64))
736                    {
737                        //Allowed as of 2.3, this is packed data for an unpacked array
738                    }
739                    else
740                    {
741                        return MergeFieldFrom(tag, input);
742                    }
743                }
744
745                switch (field.FieldType)
746                {
747                    case FieldType.Group:
748                    case FieldType.Message:
749                        {
750                            IBuilderLite subBuilder = (defaultFieldInstance != null)
751                                                          ? defaultFieldInstance.WeakCreateBuilderForType()
752                                                          : builder.CreateBuilderForField(field);
753                            if (!field.IsRepeated)
754                            {
755                                subBuilder.WeakMergeFrom((IMessageLite) builder[field]);
756                                if (field.FieldType == FieldType.Group)
757                                {
758                                    input.ReadGroup(field.FieldNumber, subBuilder, extensionRegistry);
759                                }
760                                else
761                                {
762                                    input.ReadMessage(subBuilder, extensionRegistry);
763                                }
764                                builder[field] = subBuilder.WeakBuild();
765                            }
766                            else
767                            {
768                                List<IMessageLite> list = new List<IMessageLite>();
769                                if (field.FieldType == FieldType.Group)
770                                {
771                                    input.ReadGroupArray(tag, fieldName, list, subBuilder.WeakDefaultInstanceForType,
772                                                         extensionRegistry);
773                                }
774                                else
775                                {
776                                    input.ReadMessageArray(tag, fieldName, list, subBuilder.WeakDefaultInstanceForType,
777                                                           extensionRegistry);
778                                }
779
780                                foreach (IMessageLite m in list)
781                                {
782                                    builder.WeakAddRepeatedField(field, m);
783                                }
784                                return true;
785                            }
786                            break;
787                        }
788                    case FieldType.Enum:
789                        {
790                            if (!field.IsRepeated)
791                            {
792                                object unknown;
793                                IEnumLite value = null;
794                                if (input.ReadEnum(ref value, out unknown, field.EnumType))
795                                {
796                                    builder[field] = value;
797                                }
798                                else if (unknown is int)
799                                {
800                                    MergeVarintField(fieldNumber, (ulong) (int) unknown);
801                                }
802                            }
803                            else
804                            {
805                                ICollection<object> unknown;
806                                List<IEnumLite> list = new List<IEnumLite>();
807                                input.ReadEnumArray(tag, fieldName, list, out unknown, field.EnumType);
808
809                                foreach (IEnumLite en in list)
810                                {
811                                    builder.WeakAddRepeatedField(field, en);
812                                }
813
814                                if (unknown != null)
815                                {
816                                    foreach (object oval in unknown)
817                                    {
818                                        if (oval is int)
819                                        {
820                                            MergeVarintField(fieldNumber, (ulong) (int) oval);
821                                        }
822                                    }
823                                }
824                            }
825                            break;
826                        }
827                    default:
828                        {
829                            if (!field.IsRepeated)
830                            {
831                                object value = null;
832                                if (input.ReadPrimitiveField(field.FieldType, ref value))
833                                {
834                                    builder[field] = value;
835                                }
836                            }
837                            else
838                            {
839                                List<object> list = new List<object>();
840                                input.ReadPrimitiveArray(field.FieldType, tag, fieldName, list);
841                                foreach (object oval in list)
842                                {
843                                    builder.WeakAddRepeatedField(field, oval);
844                                }
845                            }
846                            break;
847                        }
848                }
849                return true;
850            }
851
852            /// <summary>
853            /// Called by MergeFieldFrom to parse a MessageSet extension.
854            /// </summary>
855            private void MergeMessageSetExtensionFromCodedStream(ICodedInputStream input,
856                                                                 ExtensionRegistry extensionRegistry, IBuilder builder)
857            {
858                MessageDescriptor type = builder.DescriptorForType;
859
860                // The wire format for MessageSet is:
861                //   message MessageSet {
862                //     repeated group Item = 1 {
863                //       required int32 typeId = 2;
864                //       required bytes message = 3;
865                //     }
866                //   }
867                // "typeId" is the extension's field number.  The extension can only be
868                // a message type, where "message" contains the encoded bytes of that
869                // message.
870                //
871                // In practice, we will probably never see a MessageSet item in which
872                // the message appears before the type ID, or where either field does not
873                // appear exactly once.  However, in theory such cases are valid, so we
874                // should be prepared to accept them.
875
876                int typeId = 0;
877                ByteString rawBytes = null; // If we encounter "message" before "typeId"
878                IBuilderLite subBuilder = null;
879                FieldDescriptor field = null;
880
881                uint lastTag = WireFormat.MessageSetTag.ItemStart;
882                uint tag;
883                string name;
884                while (input.ReadTag(out tag, out name))
885                {
886                    if (tag == 0 && name != null)
887                    {
888                        if (name == "type_id")
889                        {
890                            tag = WireFormat.MessageSetTag.TypeID;
891                        }
892                        else if (name == "message")
893                        {
894                            tag = WireFormat.MessageSetTag.Message;
895                        }
896                    }
897                    if (tag == 0)
898                    {
899                        if (input.SkipField())
900                        {
901                            continue; //can't merge unknown without field tag
902                        }
903                        break;
904                    }
905
906                    lastTag = tag;
907                    if (tag == WireFormat.MessageSetTag.TypeID)
908                    {
909                        typeId = 0;
910                        // Zero is not a valid type ID.
911                        if (input.ReadInt32(ref typeId) && typeId != 0)
912                        {
913                            ExtensionInfo extension = extensionRegistry[type, typeId];
914                            if (extension != null)
915                            {
916                                field = extension.Descriptor;
917                                subBuilder = extension.DefaultInstance.WeakCreateBuilderForType();
918                                IMessageLite originalMessage = (IMessageLite) builder[field];
919                                if (originalMessage != null)
920                                {
921                                    subBuilder.WeakMergeFrom(originalMessage);
922                                }
923                                if (rawBytes != null)
924                                {
925                                    // We already encountered the message.  Parse it now.
926                                    // TODO(jonskeet): Check this is okay. It's subtly different from the Java, as it doesn't create an input stream from rawBytes.
927                                    // In fact, why don't we just call MergeFrom(rawBytes)? And what about the extension registry?
928                                    subBuilder.WeakMergeFrom(rawBytes.CreateCodedInput());
929                                    rawBytes = null;
930                                }
931                            }
932                            else
933                            {
934                                // Unknown extension number.  If we already saw data, put it
935                                // in rawBytes.
936                                if (rawBytes != null)
937                                {
938                                    MergeField(typeId, UnknownField.CreateBuilder().AddLengthDelimited(rawBytes).Build());
939                                    rawBytes = null;
940                                }
941                            }
942                        }
943                    }
944                    else if (tag == WireFormat.MessageSetTag.Message)
945                    {
946                        if (subBuilder != null)
947                        {
948                            // We already know the type, so we can parse directly from the input
949                            // with no copying.  Hooray!
950                            input.ReadMessage(subBuilder, extensionRegistry);
951                        }
952                        else if (input.ReadBytes(ref rawBytes))
953                        {
954                            if (typeId != 0)
955                            {
956                                // We don't know how to parse this.  Ignore it.
957                                MergeField(typeId,
958                                           UnknownField.CreateBuilder().AddLengthDelimited(rawBytes).Build());
959                            }
960                        }
961                    }
962                    else
963                    {
964                        // Unknown tag.  Skip it.
965                        if (!input.SkipField())
966                        {
967                            break; // end of group
968                        }
969                    }
970                }
971
972                if (lastTag != WireFormat.MessageSetTag.ItemEnd)
973                {
974                    throw InvalidProtocolBufferException.InvalidEndTag();
975                }
976
977                if (subBuilder != null)
978                {
979                    builder[field] = subBuilder.WeakBuild();
980                }
981            }
982
983            #region IBuilderLite Members
984
985            bool IBuilderLite.IsInitialized
986            {
987                get { return fields != null; }
988            }
989
990            IBuilderLite IBuilderLite.WeakClear()
991            {
992                return Clear();
993            }
994
995            IBuilderLite IBuilderLite.WeakMergeFrom(IMessageLite message)
996            {
997                return MergeFrom((UnknownFieldSet) message);
998            }
999
1000            IBuilderLite IBuilderLite.WeakMergeFrom(ByteString data)
1001            {
1002                return MergeFrom(data);
1003            }
1004
1005            IBuilderLite IBuilderLite.WeakMergeFrom(ByteString data, ExtensionRegistry registry)
1006            {
1007                return MergeFrom(data);
1008            }
1009
1010            IBuilderLite IBuilderLite.WeakMergeFrom(ICodedInputStream input)
1011            {
1012                return MergeFrom(input);
1013            }
1014
1015            IBuilderLite IBuilderLite.WeakMergeFrom(ICodedInputStream input, ExtensionRegistry registry)
1016            {
1017                return MergeFrom(input);
1018            }
1019
1020            IMessageLite IBuilderLite.WeakBuild()
1021            {
1022                return Build();
1023            }
1024
1025            IMessageLite IBuilderLite.WeakBuildPartial()
1026            {
1027                return Build();
1028            }
1029
1030            IBuilderLite IBuilderLite.WeakClone()
1031            {
1032                return Build().WeakToBuilder();
1033            }
1034
1035            IMessageLite IBuilderLite.WeakDefaultInstanceForType
1036            {
1037                get { return DefaultInstance; }
1038            }
1039
1040            #endregion
1041        }
1042    }
1043}
Note: See TracBrowser for help on using the repository browser.