//********************************** Banshee Engine (www.banshee3d.com) **************************************************// //**************** Copyright (c) 2016 Marko Pintera (marko.pintera@gmail.com). All rights reserved. **********************// using System; using System.Runtime.CompilerServices; using System.Text; namespace BansheeEngine { /** @addtogroup Serialization * @{ */ #pragma warning disable 649 /// /// Allows you to access meta-data about a managed object and its fields. Similar to Reflection but simpler and faster. /// public sealed class SerializableObject : ScriptObject { internal SerializableProperty parentProperty; internal object parentObject; private SerializableField[] _fields; private Type type; /// /// Type of the underlying object. /// public Type Type { get { return type; } } /// /// Underlying object instance, if any. /// public object Object { get { return parentObject; } } /// /// Creates a new serializable object for the specified object type. /// /// C# type of the object. /// Property used for retrieving this entry. public SerializableObject(Type objectType, SerializableProperty parentProperty) { Internal_CreateInstance(this, objectType); this.parentProperty = parentProperty; this.parentObject = null; this.type = objectType; } /// /// Creates a new serializable object for the specified object type. /// /// C# type of the object. /// Specific instance of the object of . public SerializableObject(Type objectType, object parentObject) { Internal_CreateInstance(this, objectType); this.parentProperty = null; this.parentObject = parentObject; this.type = objectType; } /// /// Creates a new serializable object for the specified object. Object must not be null. /// /// Specific instance of the object. public SerializableObject(object parentObject) { Internal_CreateInstance(this, parentObject.GetType()); this.parentProperty = null; this.parentObject = parentObject; this.type = parentObject.GetType(); } /// /// Returns all fields in the object. /// public SerializableField[] Fields { get { return _fields; } } /// /// Returns the specific object instance this object is operating on. /// /// Object instance. public object GetReferencedObject() { if (parentProperty != null) return parentProperty.GetValue(); else return parentObject; } /// /// Searches the object, and all child objects for a field or entry with the specified name. /// /// Slash separated path with field name(s) to search for. If a field contains an array, list or /// a dictionary append its name with a "[x]" where x is the element index in the array/list, or /// a key name (surrounded by "") in case of a dictionary. Only primitive dictionary keys are /// supported. /// /// Example path: subObject/myDictionary["someElement"]/theArray[4]/fieldToGet /// /// Property you can use for reading or modifying the property, or null if not found. public SerializableProperty FindProperty(string path) { if (path == null) return null; string trimmedPath = path.Trim('/'); string[] pathEntries = trimmedPath.Split('/'); PropertyPathElement[] pathElements = new PropertyPathElement[pathEntries.Length]; for (int i = 0; i < pathEntries.Length; i++) { string entry = pathEntries[i]; if (string.IsNullOrEmpty(entry)) return null; pathElements[i] = new PropertyPathElement(); int startIdx = 0; int nameEndIdx = 0; int endIdx = entry.Length - 1; if (entry[entry.Length - 1] == ']') { bool foundKey = false; for (int j = 0; j < entry.Length - 1; j++) { if (entry[j] == '[') { startIdx = j; nameEndIdx = j; foundKey = true; } } // Trim string quotes, if they exist if (startIdx < (endIdx - 1) && entry[startIdx + 1] == '"') startIdx++; if (endIdx > (startIdx + 1) && entry[endIdx - 1] == '"') endIdx--; if (foundKey) { pathElements[i].name = entry.Substring(0, nameEndIdx); pathElements[i].key = entry.Substring(startIdx + 1, endIdx - (startIdx + 1)); } else pathElements[i].name = entry; } else { pathElements[i].name = entry; } } return FindProperty(pathElements, 0); } /// /// Searches the object hierarchy using the provided path elements. /// /// Path elements representing field names and keys to look for. /// Index in the array to start the search at. /// Property representing the final path element, or null if not found. internal SerializableProperty FindProperty(PropertyPathElement[] pathElements, int elementIdx) { SerializableField field = FindField(pathElements[0].name); if (field != null) { SerializableProperty property = field.GetProperty(); if (elementIdx == (pathElements.Length - 1)) return property; return property.FindProperty(pathElements, elementIdx + 1); } return null; } /// /// Searches the object for a field with the specified name. /// /// Name of the field. /// Object representing the field, if found, null otherwise. public SerializableField FindField(string name) { foreach (var field in _fields) { if (field.Name == name) return field; } return null; } [MethodImpl(MethodImplOptions.InternalCall)] private static extern void Internal_CreateInstance(SerializableObject instance, Type objectType); } /// /// Contains a single element of a path to a field or array/list/dictionary entry, as used for /// . /// internal struct PropertyPathElement { public string name; public string key; } /** @} */ }