using System; using System.Collections.Generic; using System.Globalization; using Google.ProtocolBuffers.Descriptors; namespace Google.ProtocolBuffers.Serialization { /// /// Allows reading messages from a name/value dictionary /// public class DictionaryReader : AbstractReader { private readonly IEnumerator> _input; private bool _ready; /// /// Creates a dictionary reader from an enumeration of KeyValuePair data, like an IDictionary /// public DictionaryReader(IEnumerable> input) { _input = input.GetEnumerator(); _ready = _input.MoveNext(); } /// /// No-op /// public override void ReadMessageStart() { } /// /// No-op /// public override void ReadMessageEnd() { } /// /// Merges the contents of stream into the provided message builder /// public override TBuilder Merge(TBuilder builder, ExtensionRegistry registry) { builder.WeakMergeFrom(this, registry); return builder; } /// /// Peeks at the next field in the input stream and returns what information is available. /// /// /// This may be called multiple times without actually reading the field. Only after the field /// is either read, or skipped, should PeekNext return a different value. /// protected override bool PeekNext(out string field) { field = _ready ? _input.Current.Key : null; return _ready; } /// /// Causes the reader to skip past this field /// protected override void Skip() { _ready = _input.MoveNext(); } private bool GetValue(ref T value) { if (!_ready) { return false; } object obj = _input.Current.Value; if (obj is T) { value = (T) obj; } else { try { if (obj is IConvertible) { value = (T)Convert.ChangeType(obj, typeof(T), FrameworkPortability.InvariantCulture); } else { value = (T) obj; } } catch { _ready = _input.MoveNext(); return false; } } _ready = _input.MoveNext(); return true; } /// /// Returns true if it was able to read a Boolean from the input /// protected override bool Read(ref bool value) { return GetValue(ref value); } /// /// Returns true if it was able to read a Int32 from the input /// protected override bool Read(ref int value) { return GetValue(ref value); } /// /// Returns true if it was able to read a UInt32 from the input /// protected override bool Read(ref uint value) { return GetValue(ref value); } /// /// Returns true if it was able to read a Int64 from the input /// protected override bool Read(ref long value) { return GetValue(ref value); } /// /// Returns true if it was able to read a UInt64 from the input /// protected override bool Read(ref ulong value) { return GetValue(ref value); } /// /// Returns true if it was able to read a Single from the input /// protected override bool Read(ref float value) { return GetValue(ref value); } /// /// Returns true if it was able to read a Double from the input /// protected override bool Read(ref double value) { return GetValue(ref value); } /// /// Returns true if it was able to read a String from the input /// protected override bool Read(ref string value) { return GetValue(ref value); } /// /// Returns true if it was able to read a ByteString from the input /// protected override bool Read(ref ByteString value) { byte[] rawbytes = null; if (GetValue(ref rawbytes)) { value = ByteString.CopyFrom(rawbytes); return true; } return false; } /// /// returns true if it was able to read a single value into the value reference. The value /// stored may be of type System.String, System.Int32, or an IEnumLite from the IEnumLiteMap. /// protected override bool ReadEnum(ref object value) { return GetValue(ref value); } /// /// Merges the input stream into the provided IBuilderLite /// protected override bool ReadMessage(IBuilderLite builder, ExtensionRegistry registry) { IDictionary values = null; if (GetValue(ref values)) { new DictionaryReader(values).Merge(builder, registry); return true; } return false; } public override bool ReadArray(FieldType type, string field, ICollection items) { object[] array = null; if (GetValue(ref array)) { if (typeof(T) == typeof(ByteString)) { ICollection output = (ICollection) items; foreach (byte[] item in array) { output.Add(ByteString.CopyFrom(item)); } } else { foreach (T item in array) { items.Add(item); } } return true; } return false; } public override bool ReadEnumArray(string field, ICollection items) { object[] array = null; if (GetValue(ref array)) { foreach (object item in array) { items.Add(item); } return true; } return false; } public override bool ReadMessageArray(string field, ICollection items, IMessageLite messageType, ExtensionRegistry registry) { object[] array = null; if (GetValue(ref array)) { foreach (IDictionary item in array) { IBuilderLite builder = messageType.WeakCreateBuilderForType(); new DictionaryReader(item).Merge(builder); items.Add((T) builder.WeakBuild()); } return true; } return false; } public override bool ReadGroupArray(string field, ICollection items, IMessageLite messageType, ExtensionRegistry registry) { return ReadMessageArray(field, items, messageType, registry); } } }