/// <summary>
 /// Whether the specified primitive type requires a lower innerLevel symbol at the end.
 /// </summary>
 /// <param name="type">The type to check.</param>
 /// <returns>Whether it requires a lower innerLevel symbol at the end.</returns>
 public static bool RequiresLowerInnerLevelSymbol(ABSavePrimitiveType type)
 {
     return(type == ABSavePrimitiveType.Object || type == ABSavePrimitiveType.Array || type == ABSavePrimitiveType.Dictionary);
 }
        /// <summary>
        /// Serializes an object. The object could be anything.
        /// </summary>
        /// <param name="obj">The object to serialize</param>
        /// <param name="useSB">Whether this will write to a string builder (if true), or return a string (if false).</param>
        /// <param name="sb">The StringBuilder to write to - if <paramref name="useSB"/> is true.</param>
        /// <param name="determinedType">The primitive type which has been decided for it.</param>
        /// <param name="writeNextInstructionSymbol">Whether it will write \u0001 on the start - usually false if it is serializing the first object in a class.</param>
        /// <param name="dnWriteEndLevel">"Do Not Write End Level Symbol" - Marks whether to NOT write \u0005 (if true), commonly used for the last object of all.</param>
        /// <returns>If <paramref name="useSB"/> is false, this method will return the result as a string.</returns>
        public static string Serialize(dynamic obj, ABSaveType type, ABSaveSettings settings, out ABSavePrimitiveType determinedType, bool useSB = false, StringBuilder sb = null, bool writeNextInstructionSymbol = true, bool dnWriteEndLevel = false)
        {
            // This will be what to return if useSB is false.
            string ret;

            // For now, make it so we output "unknown".
            determinedType = ABSavePrimitiveType.Unknown;

            // Check if the object is null... or an IntPtr, write the null symbol - otherwise, we could get a StackOverflowException.
            if (obj == null || obj is IntPtr || obj is UIntPtr)
            {
                return(ABSaveWriter.WriteNullItem(useSB, sb));
            }

            // Remember what type the object is - as well as the TypeCode.
            Type objType = obj.GetType();
            var  tCode   = Type.GetTypeCode(obj.GetType());

            // If the object is a string - write it as a string.
            if (tCode == TypeCode.String)
            {
                ret            = ABSaveWriter.WriteString(obj, writeNextInstructionSymbol, useSB, sb);
                determinedType = ABSavePrimitiveType.String;
            }

            // If the object is a number - write it as a number.
            else if (IsNumericType(tCode))
            {
                ret            = ABSaveWriter.WriteNumerical(obj, tCode, true, useSB, sb);
                determinedType = ABSavePrimitiveType.Number;
            }

            // If the object is an array - serialize it as an array.
            else if (IsArray(objType))
            {
                ret            = SerializeArray(obj, objType, type, settings, useSB, sb, dnWriteEndLevel);
                determinedType = ABSavePrimitiveType.Array;
            }

            // If the object is a dictionary - serialize it as a dictionary.
            else if (IsDictionary(objType))
            {
                ret            = SerializeDictionary(obj, type, settings, useSB, sb, dnWriteEndLevel);
                determinedType = ABSavePrimitiveType.Dictionary;
            }

            // If the object is a boolean - serialize it as a boolean.
            else if (tCode == TypeCode.Boolean)
            {
                ret            = SerializeBool(obj, writeNextInstructionSymbol, useSB, sb);
                determinedType = ABSavePrimitiveType.Boolean;
            }

            // If the object is a DateTime - serialize it as a DateTime.
            else if (tCode == TypeCode.DateTime)
            {
                ret            = SerializeDateTime(obj, useSB, sb);
                determinedType = ABSavePrimitiveType.DateTime;
            }

            // If it's a type, just write it out using the ABSaveWriter (for some reason there is no TypeConverter built-in for a type!)
            else if (obj is Type)
            {
                ret            = SerializeType(obj, useSB, sb);
                determinedType = ABSavePrimitiveType.Type;
            }

            // Otherwise, we'll attempt to find a built-in type converter (to a string)
            else
            {
                // Mark it as an object.
                determinedType = ABSavePrimitiveType.Object;

                // Attempt to get a converter for it.
                var canBeTypeConverted = false;
                var typeConv           = TypeDescriptor.GetConverter(objType);

                // Check if the type converter can actually convert it to a string.
                if (typeConv.IsValid(obj))
                {
                    if (typeConv.CanConvertTo(typeof(string)))
                    {
                        canBeTypeConverted = true;
                    }
                }

                // If it can be type converted, convert it using that, and then write it as a string.
                if (canBeTypeConverted)
                {
                    ret = ABSaveWriter.WriteString(typeConv.ConvertToString(obj), writeNextInstructionSymbol, useSB, sb);
                }

                // Otherwise, if it can't be type converted... Manually convert it.
                else
                {
                    ret = SerializeObject(obj, type, objType, settings, writeNextInstructionSymbol, useSB, sb, dnWriteEndLevel);
                }
            }

            // Return the result from this.
            return(ret);
        }
Beispiel #3
0
        static void ConvertVariableToABSave(ABSaveType type, StringBuilder sb, ABSaveSettings settings, Helpers.ABSaveObjectItems members, ref bool notFirst, ref ABSavePrimitiveType lastType, int i)
        {
            // If we're doing it named - write the name.
            if (type == ABSaveType.WithNames)
            {
                // Write the name out, don't write the Next Instruction character if it's the first item or the last item had a "lowerInnerlevel" sign after it.
                ABSaveWriter.WriteString(members.Items[i].Info.Name, ABSaveUtils.RequiresLowerInnerLevelSymbol(lastType) ? false : notFirst, true, sb);

                // Since we've written the name out... And the "notFirst" variable is used to determine whether to write the next instruction symbol or not... Set "notFirst" to true since it will HAVE to have the next instruction symbol now.
                notFirst = true;
            }

            // Serialize each variable, to the StringBuilder. If the last member was an array or object, then instead of getting it to write the
            // "next instruction" character, we need to get it to write the "lower" symbol instead.
            ABSaveSerializer.Serialize(members.Items[i].Value, type, settings, out lastType, true, sb, ABSaveUtils.RequiresLowerInnerLevelSymbol(lastType) ? false : notFirst, i == members.Count - 1);

            // Update the "notFirst" variable if it's false and we've gone through one item.
            if (!notFirst)
            {
                notFirst = true;
            }
        }
        internal static void SerializeArrayItem(ABSaveType type, ABSaveSettings settings, bool useSB, StringBuilder sb, bool dnWriteEndLevel, ref string ret, ref bool notFirst, ref ABSavePrimitiveType lastType, dynamic item)
        {
            // Serialize the item and write to either the StringBuilder or the "ret"...
            ret += Serialize(item, type, settings, out lastType, useSB, sb, RequiresLowerInnerLevelSymbol(lastType) ? false : notFirst, dnWriteEndLevel);

            // Update the "notFirst" variable.
            if (!notFirst)
            {
                notFirst = true;
            }
        }
        /// <summary>
        /// Figures out what a string is and how to deserialize it. This does not deserialize objects, arrays or dictionaries, however.
        /// </summary>
        /// <param name="str">The string to deserialize.</param>
        /// <param name="objType">The type of the object to deserialize to.</param>
        /// <param name="determinedType">The primitive that the object has been determined as.</param>
        /// <param name="manuallyParse">Whether a parser using this should manually parse the object or not.</param>
        /// <param name="settings">The settings for how to handle certain parts.</param>
        /// <param name="location">OPTIONAL: This is used to add a location to the error from the <paramref name="settings"/></param>
        /// <returns>The deserialized object - can be null if it needs to be manually parsed.</returns>
        public static object Deserialize(string str, Type objType, ABSaveSettings settings, out ABSavePrimitiveType determinedType, out bool manuallyParse, int location = 0)
        {
            // Set the "determinedType" to Unknown for now, and, manuallyParse to false.
            determinedType = ABSavePrimitiveType.Unknown;
            manuallyParse  = false;

            // Get a type code.
            var tCode = Type.GetTypeCode(objType);

            // Now, go through what it could be and convert it.
            if (objType == typeof(string))
            {
                determinedType = ABSavePrimitiveType.String;
                return(str);
            }

            // Check if it's a number.
            else if (ABSaveUtils.IsNumericType(tCode))
            {
                determinedType = ABSavePrimitiveType.Number;
                return(DeserializeNumber(str, objType, settings, location));
            }

            // Check if it's an array - if so, all we can do is set the "determinedType" to "array" since this method doesn't deal with that.
            else if (ABSaveUtils.IsArray(objType))
            {
                manuallyParse  = true;
                determinedType = ABSavePrimitiveType.Array;
            }

            // Check if it's a dictionary - if so, all we can do is set the "determinedType" to "dictionary" since this method doesn't deal with that.
            else if (ABSaveUtils.IsDictionary(objType))
            {
                manuallyParse  = true;
                determinedType = ABSavePrimitiveType.Dictionary;
            }

            // Check if it's a boolean - if so, we can get the result out of that using "DeserializeBool"
            else if (objType == typeof(bool))
            {
                determinedType = ABSavePrimitiveType.Boolean;
                return(DeserializeBool(str, settings, location));
            }

            // Check if it's a DateTime - if so, we can get the result out of that using "DeserializeDateTime"
            else if (objType == typeof(DateTime))
            {
                determinedType = ABSavePrimitiveType.DateTime;
                return(DeserializeDateTime(str, settings, location));
            }

            // Check if it's a Type - if so, we can get the result using "Type.GetType()"
            else if (objType == typeof(Type))
            {
                determinedType = ABSavePrimitiveType.Type;
                return(Type.GetType(str));
            }

            // If it wasn't any of the above - it's probably an object, now, we've been given a string which is actually the type name of it (unless the ABSave is incorrect).
            else
            {
                // Mark it as an object.
                determinedType = ABSavePrimitiveType.Object;

                // We're going to try and find a TypeConverter. But if we can't find one - we'll just return the correct type based on the TypeName we were given.
                TypeConverter typeConv = TypeDescriptor.GetConverter(objType);

                // Check if the type converter can actually convert it FROM a string, if it can, use it.
                if (typeConv.CanConvertFrom(typeof(string)))
                {
                    return(typeConv.ConvertFrom(str));
                }

                // However, otherwise, since we know what the type is - we'll return that, and let the parser manually parse it.
                else
                {
                    manuallyParse = true;
                    return(Type.GetType(str));
                }
            }

            // If we got here it was probably manually making the parser do the rest to return null.
            return(null);
        }