Esempio n. 1
0
        // ---- Serialization ----

        private void CollectArrayContents(object obj)
        {
            // Put strings into the string array.
            if (obj is string)
            {
                _stringArray.Add((string)obj);
                return;
            }

            // Put paths into the path array (if supported).
            if (Settings.SupportPaths)
            {
                if (obj is List <ByamlPathPoint> )
                {
                    _pathArray.Add((List <ByamlPathPoint>)obj);
                    return;
                }
            }

            // Traverse through arrays if the element type is of interest.
            if (obj is IList)
            {
                IList objArray    = (IList)obj;
                Type  elementType = objArray.GetType().GetTypeInfo().GetElementType();
                if (elementType == typeof(string) || elementType is IList || IsTypeByamlObject(elementType))
                {
                    foreach (object element in objArray)
                    {
                        CollectArrayContents(element);
                    }
                }
                return;
            }

            // Traverse through other types decorated with the ByamlObjectAttribute and collect their keys and values.
            Type type = obj.GetType();

            if (IsTypeByamlObject(type))
            {
                ByamlObjectInfo objectInfo;
                if (!_byamlObjectInfos.TryGetValue(type, out objectInfo))
                {
                    objectInfo = new ByamlObjectInfo(type);
                    _byamlObjectInfos.Add(type, objectInfo);
                }
                // Query the custom values and remember them for when to actually store them in the BYAML.
                if (objectInfo.ImplementsByamlSerializable)
                {
                    IByamlSerializable          byamlSerializable = (IByamlSerializable)obj;
                    Dictionary <string, object> customMembers     = new Dictionary <string, object>();
                    byamlSerializable.SerializeByaml(customMembers);
                    foreach (KeyValuePair <string, object> customMember in customMembers)
                    {
                        _nameArray.Add(customMember.Key);
                        CollectArrayContents(customMember.Value);
                    }
                    if (customMembers.Count > 0)
                    {
                        _customMembers.Add(obj, customMembers);
                    }
                }
                // Go through the default members.
                foreach (KeyValuePair <string, ByamlMemberInfo> member in objectInfo.Members)
                {
                    object value = member.Value.GetValue(obj);
                    if (value != null || !member.Value.Optional)
                    {
                        _nameArray.Add(member.Key);
                        if (value != null)
                        {
                            CollectArrayContents(value);
                        }
                    }
                }
                return;
            }
        }
Esempio n. 2
0
        private void WriteDictionary(BinaryDataWriter writer, object obj)
        {
            // Create a string-object dictionary out of the members.
            Dictionary <string, object> dictionary = new Dictionary <string, object>();
            // Add the custom members if any have been created when collecting node contents previously.
            Dictionary <string, object> customMembers;

            if (_customMembers.TryGetValue(obj, out customMembers))
            {
                foreach (KeyValuePair <string, object> customMember in customMembers)
                {
                    dictionary.Add(customMember.Key, customMember.Value);
                }
            }
            // Add the ByamlMemberAttribute decorated members.
            ByamlObjectInfo objectInfo = _byamlObjectInfos[obj.GetType()];

            foreach (KeyValuePair <string, ByamlMemberInfo> member in objectInfo.Members)
            {
                object value = member.Value.GetValue(obj);
                if (value != null || !member.Value.Optional)
                {
                    dictionary.Add(member.Key, value);
                }
            }
            // Dictionaries need to be sorted ordinally by key.
            var sortedDict = dictionary.Values.Zip(dictionary.Keys, (Value, Key) => new { Key, Value })
                             .OrderBy(x => x.Key, StringComparer.Ordinal).ToList();

            WriteTypeAndElementCount(writer, ByamlNodeType.Dictionary, dictionary.Count);

            // Write the key-value pairs.
            Dictionary <Offset, object> offsetElements = new Dictionary <Offset, object>();

            foreach (var keyValuePair in sortedDict)
            {
                string key     = keyValuePair.Key;
                object element = keyValuePair.Value;

                // Get the index of the key string in the file's name array and write it together with the type.
                uint          keyIndex = (uint)_nameArray.IndexOf(key);
                ByamlNodeType nodeType = element == null ? ByamlNodeType.Null : GetNodeType(element.GetType());
                if (Settings.ByteOrder == ByteOrder.BigEndian)
                {
                    writer.Write(keyIndex << 8 | (uint)nodeType);
                }
                else
                {
                    writer.Write(keyIndex | (uint)nodeType << 24);
                }

                // Write the elements. Complex types are just offsets, primitive types are directly written as values.
                if (nodeType == ByamlNodeType.Array || nodeType == ByamlNodeType.Dictionary)
                {
                    offsetElements.Add(writer.ReserveOffset(), element);
                }
                else
                {
                    WritePrimitiveType(writer, nodeType, element);
                }
            }

            // Write the array or dictionary elements and satisfy their offsets.
            foreach (KeyValuePair <Offset, object> offsetElement in offsetElements)
            {
                WriteArrayOrDictionary(writer, offsetElement.Key, offsetElement.Value);
            }
        }
Esempio n. 3
0
        private object ReadDictionary(BinaryDataReader reader, Type type, int length)
        {
            // Get the information required to serialize this type (for Nullables take the underlying type).
            Type nullableType = Nullable.GetUnderlyingType(type);

            if (nullableType != null)
            {
                type = nullableType;
            }
            ByamlObjectInfo objectInfo;

            if (!_byamlObjectInfos.TryGetValue(type, out objectInfo))
            {
                objectInfo = new ByamlObjectInfo(type);
                _byamlObjectInfos.Add(type, objectInfo);
            }

            // Instantiate the type and read in the elements. Use a given instance as the root if available.
            object instance;

            if (_instance == null)
            {
                instance = Activator.CreateInstance(type, true);
            }
            else
            {
                instance  = _instance;
                _instance = null;
            }
            // Collect them in a dictionary for custom deserialization.
            Dictionary <string, object> dictionary = new Dictionary <string, object>();

            for (int i = 0; i < length; i++)
            {
                uint          indexAndType  = reader.ReadUInt32();
                int           nodeNameIndex = (int)Get3MsbBytes(indexAndType);
                ByamlNodeType nodeType      = (ByamlNodeType)Get1MsbByte(indexAndType);
                string        key           = _nameArray[nodeNameIndex];
                // Find a member for it to map the value to.
                object          value;
                ByamlMemberInfo member;
                if (objectInfo.Members.TryGetValue(key, out member))
                {
                    // The key could be mapped to a member, read it as the member's type.
                    value = ReadValue(reader, member.Type, nodeType);
                    member.SetValue(instance, value);
                }
                else
                {
                    // If the key could not be mapped to a member, add it to the dictionary for custom deserialization.
                    //Debug.WriteLine($"No member in {type.Name} found to map key \"{key}\" to.");
                    value = ReadValue(reader, nodeType.GetInstanceType(), nodeType);
                }
                dictionary.Add(key, value);
            }

            // Call IByamlSerializable methods if the interface was implemented.
            if (objectInfo.ImplementsByamlSerializable)
            {
                IByamlSerializable byamlSerializable = (IByamlSerializable)instance;
                byamlSerializable.DeserializeByaml(dictionary);
            }

            // Check if any required fields were not filled.
            foreach (ByamlMemberInfo member in objectInfo.Members.Values)
            {
                if (!member.Optional && member.GetValue(instance) == null)
                {
                    throw new ByamlException(
                              $"Member {type.Name}.{member.MemberInfo.Name} is not optional, but has not been deserialized.");
                }
            }

            return(instance);
        }