using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using LeanCloud.Utilities; using LeanCloud.Storage.Internal; namespace LeanCloud.Storage.Internal { /// /// A AVEncoder can be used to transform objects such as into JSON /// data structures. /// /// public abstract class AVEncoder { #if UNITY private static readonly bool isCompiledByIL2CPP = AppDomain.CurrentDomain.FriendlyName.Equals("IL2CPP Root Domain"); #else private static readonly bool isCompiledByIL2CPP = false; #endif public static bool IsValidType(object value) { return value == null || ReflectionHelpers.IsPrimitive(value.GetType()) || value is string || value is AVObject || value is AVACL || value is AVFile || value is AVGeoPoint || value is AVRelationBase || value is DateTime || value is byte[] || Conversion.As>(value) != null || Conversion.As>(value) != null; } public object Encode(object value) { // If this object has a special encoding, encode it and return the // encoded object. Otherwise, just return the original object. if (value is DateTime) { return new Dictionary { { "iso", ((DateTime)value).ToUniversalTime().ToString(AVClient.DateFormatStrings.First(), CultureInfo.InvariantCulture) }, { "__type", "Date" } }; } if (value is AVFile) { var file = value as AVFile; return new Dictionary { {"__type", "Pointer"}, { "className", "_File"}, { "objectId", file.ObjectId} }; } var bytes = value as byte[]; if (bytes != null) { return new Dictionary { { "__type", "Bytes"}, { "base64", Convert.ToBase64String(bytes)} }; } var obj = value as AVObject; if (obj != null) { return EncodeAVObject(obj); } var jsonConvertible = value as IJsonConvertible; if (jsonConvertible != null) { return jsonConvertible.ToJSON(); } var dict = Conversion.As>(value); if (dict != null) { var json = new Dictionary(); foreach (var pair in dict) { json[pair.Key] = Encode(pair.Value); } return json; } var list = Conversion.As>(value); if (list != null) { return EncodeList(list); } // TODO (hallucinogen): convert IAVFieldOperation to IJsonConvertible var operation = value as IAVFieldOperation; if (operation != null) { return operation.Encode(); } return value; } protected abstract IDictionary EncodeAVObject(AVObject value); private object EncodeList(IList list) { var newArray = new List(); // We need to explicitly cast `list` to `List` rather than // `IList` because IL2CPP is stricter than the usual Unity AOT compiler pipeline. if (isCompiledByIL2CPP && list.GetType().IsArray) { list = new List(list); } foreach (var item in list) { if (!IsValidType(item)) { throw new ArgumentException("Invalid type for value in an array"); } newArray.Add(Encode(item)); } return newArray; } } }