Exemplo n.º 1
0
        /// <summary>
        /// Turns a whole object into ABSave, excluding everything extra, and places the result in a StringBuilder.
        /// </summary>
        public static string ObjectToABSave(object obj, ABSaveType type, ABSaveSettings settings)
        {
            var sb = new StringBuilder();

            ObjectToABSave(obj, type, sb, settings);
            return(sb.ToString());
        }
Exemplo n.º 2
0
        /// <summary>
        /// Deserializes an ABSave document into a whole object.
        /// </summary>
        /// <typeparam name="T">The type of the object to deserialize into.</typeparam>
        /// <param name="str">The string to deserialize from.</param>
        /// <param name="type">The type of the ABSave Document.</param>
        /// <param name="errorHandler">The way of handling errors through the process.</param>
        /// <returns></returns>
        public static T ABSaveToObject <T>(string str, ABSaveType type, ABSaveSettings errorHandler = null)
        {
            // Create a new parser.
            var parser = new ABSaveParser <T>(type, errorHandler);

            // Start the new parser.
            parser.Start(str);

            // Return the result.
            return(parser.Result);
        }
Exemplo n.º 3
0
        // An internal helper that automatically decides which version of "ObjectToABSave" to use.
        internal static string ObjectToABSave(object obj, ABSaveType type, ABSaveSettings settings, bool writeToSB = false, StringBuilder sb = null)
        {
            if (writeToSB)
            {
                ObjectToABSave(obj, type, sb, settings);
            }
            else
            {
                return(ObjectToABSave(obj, type, settings));
            }

            return("");
        }
Exemplo n.º 4
0
        /// <summary>
        /// The main parser which is used over and over again to parse strings.
        /// </summary>
        //internal static ABSaveParser<T> MainParser;

        /// <summary>
        /// Turns a whole object into a string with an ABSave document.
        /// </summary>
        /// <param name="obj">The object to convert.</param>
        /// <param name="type">The way of serializing this ABSave (unnamed/named).</param>
        /// <param name="settings">The settings for how to handle certain parts.</param>
        /// <param name="writeHeader">Whether we should write the header in or not.</param>
        /// <returns>The ABSave string.</returns>
        public static string ObjectToABSaveDocument(object obj, ABSaveType type, ABSaveSettings settings, bool writeHeader = true)
        {
            var ret = new StringBuilder();

            // NOTE: (tl;dr)
            // Why do we use a StringBuilder, and not just a string?
            // Well, there's one word to explain that:
            // Performance.
            // The ONLY reason we are using a StringBuilder instead of a string is because it's much faster.
            // HOWEVER, we don't want to just support StringBuilder - we want to allow users to use strings as well.
            // And THAT'S why we have a string mode (just set UseSB to false on most methods) and a StringBuilder mode!
            // StringBuilder is faster, but less flexible - I mean, you can do basically anything with a string, because it's a standard type.

            ObjectToABSaveDocument(obj, type, ret, settings, writeHeader);
            return(ret.ToString());
        }
Exemplo n.º 5
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;
            }
        }
Exemplo n.º 6
0
        /// <summary>
        /// Attempts to create an instance of an object, based on a NameValueTypeDictionary - if the object's constructors have parameters, we'll attempt to figure out how to use them.
        /// </summary>
        /// <typeparam name="T">The type of the object.</typeparam>
        /// <param name="settings">The way of handling any errors.</param>
        /// <param name="location">OPTIONAL: The location this happened in an ABSave string - used in any errors.</param>
        public static object CreateInstance(Type type, ABSaveSettings settings, ABSaveObjectItems values, int location = 0)
        {
            // =======================
            // Variables
            // =======================

            // First of all, get all the constructor out of the type.
            var constructors = type.GetConstructors();

            // Remember all the values if there was a constructor with "No Case Match".
            object[] noCaseMatchValues = new object[0];

            // Next, remember all the REMAINING values if there was a constructor with "No Case Match"
            ABSaveObjectItems noCaseMatchRemaining = null;

            // Also, if we don't find a perfect constructor and there's too many "No Case Match" constructor, it will cause an error, so remember if there are more than one "No Case Match" constructors.
            var multipleNoCaseMatchConstructors = false;

            // =======================
            // Each Constructor
            // =======================

            for (int i = 0; i < constructors.Length; i++)
            {
                // Keep track of whether all the parameters in this constructor are valid and how close they are to the real thing.
                var passed = ABSaveConstructorInferer.Failed;

                // Get all the parameters for this constructor.
                var parameters      = constructors[i].GetParameters();
                var parametersCount = parameters.Length;

                // If there aren't any parameters, this is the one we preferably want.
                if (parametersCount == 0)
                {
                    return(InsertValuesIntoObject(Activator.CreateInstance(type), values));
                }

                // Keep track of the parameters' values in order.
                var parametersArguments = new object[parametersCount];

                // Also, keep track of any objects we were unable to pass into this constructor.
                var remainingValues = new ABSaveObjectItems();

                // If there are too many parameters, this constructor won't work.
                if (parametersCount > values.Count)
                {
                    continue;
                }

                // =======================
                // Each Item - To Find A Matching Parameter
                // =======================

                for (int j = 0; j < values.Count; j++)
                {
                    // Whether a parameter was found or not.
                    var parameterFound = ABSaveConstructorInferer.Failed;

                    // The index of the best parameter for this value.
                    var bestParam = -1;

                    // =======================
                    // Each Parameter
                    // =======================

                    for (int k = 0; k < parametersCount; k++)
                    {
                        // If the types don't match, this parameter failed, so try a different one.
                        if (!(values.Items[j].Info.FieldType == parameters[k].ParameterType))
                        {
                            continue;
                        }

                        // Check if the names perfectly match now.
                        if (values.Items[k].Info.Name == parameters[j].Name)
                        {
                            // This parameter is perfect.
                            parameterFound = ABSaveConstructorInferer.Perfect;
                            bestParam      = k;

                            // We want to break out of the "parameter" loop since this is a perfect match and it can't be anything else.
                            break;
                        }

                        // Otherwise, try and ignore the case and see if that helps.
                        else if (values.Items[k].Info.Name.ToLower() == parameters[j].Name.ToLower())
                        {
                            // Set the bestParam so that we can remember which parameter this was.
                            bestParam = k;

                            // Now, make sure we set this as a POSSIBLE value for this parameter and see if any other fields would work better.
                            parameterFound = ABSaveConstructorInferer.NoCaseMatch;
                            continue;
                        }
                    }

                    // =======================
                    // Check Value Results
                    // =======================

                    // If it failed, add this as failed value since it obviously can't work, and try some others!
                    if (bestParam == -1)
                    {
                        remainingValues.Add(values.Items[j]);
                        continue;
                    }

                    // Now, set the main "passed" variable for this constructor to how well this value did - but, if the constructor is on "No Case Match", leave it, since we know that this parameter didn't fail.
                    // Essentially, when the constructor is on "NoCaseMatch" because one of the parameters doesn't match case, it doesn't matter what the others are, they can't fix that one parameter.
                    if (passed != ABSaveConstructorInferer.NoCaseMatch)
                    {
                        passed = parameterFound;
                    }

                    // Now that we've decided the best object for a certain parameter, add that as the value at the correct index.
                    parametersArguments[bestParam] = values.Items[j].Value;
                }

                // =======================
                // Check Constructor Results
                // =======================

                // If this was a perfect constructor, return this one - with all the remaining items getting added in!
                if (passed == ABSaveConstructorInferer.Perfect)
                {
                    return(InsertValuesIntoObject(Activator.CreateInstance(type, parametersArguments), remainingValues));
                }

                // If this constructor overall got a "No Case Match", attempt to place the values into the "noCaseMatchValues".
                if (passed == ABSaveConstructorInferer.NoCaseMatch)
                {
                    // Determine how many values we were actually able to fill in a parameter as well as how many the LAST "No Case Match" constructor did.
                    var filledParameters     = values.Count - remainingValues.Count;
                    var lastFilledParameters = (noCaseMatchRemaining == null) ? 0 : values.Count - noCaseMatchRemaining.Count;

                    // If there was already a "No Case Match"... and we CAN'T override the last one, make sure we remember there's too many.
                    if (noCaseMatchValues.Count() > 0 && ((lastFilledParameters == values.Count) || (lastFilledParameters > filledParameters)))
                    {
                        multipleNoCaseMatchConstructors = true;
                    }

                    // If we can override the last one, though, mark it as "false" since this is the parameter we need.
                    else
                    {
                        multipleNoCaseMatchConstructors = false;
                    }

                    // Now, place the current values/remaining values into the main arrays.
                    noCaseMatchValues    = parametersArguments;
                    noCaseMatchRemaining = remainingValues;
                }
            }

            // =======================
            // Check Final Results
            // =======================

            // If we made it here, it means there weren't any PERFECT ones, so, before we attempt anything, we'll want to throw an error if we have come across more than one "No Case Match" constructor (in which case we wouldn't know what to use).
            if (multipleNoCaseMatchConstructors)
            {
                settings.ErrorHandler.TooManyConstructorsWithDifferentCase(type, location);
            }

            // And, now see if there was a "No Case Match" one, if so, that's the constructor we need!
            if (noCaseMatchValues.Count() > 0)
            {
                return(InsertValuesIntoObject(Activator.CreateInstance(type, noCaseMatchValues), noCaseMatchRemaining));
            }

            // And, if we got all the way here - it failed completely.
            settings.ErrorHandler.InvalidConstructorsForCreatingObject(type, location);
            return(null);
        }
Exemplo n.º 7
0
        /// <summary>
        /// Turns a whole object into an ABSave document, and places the result in a StringBuilder.
        /// </summary>
        /// <param name="obj">The object to convert.</param>
        /// <param name="type">The way of serializing this ABSave (unnamed/named).</param>
        /// <param name="sb">The StringBuilder to write to</param>
        /// <param name="settings">The settings for how to handle certain parts.</param>
        /// <param name="writeHeader">Whether we should write the header in or not.</param>
        public static void ObjectToABSaveDocument(object obj, ABSaveType type, StringBuilder sb, ABSaveSettings settings, bool writeHeader = true)
        {
            // If the type is invalid, throw an exception.
            if (type == ABSaveType.Infer)
            {
                settings.ErrorHandler.InferTypeWhenSerializing();
                return;
            }

            // Write the header.
            ABSaveWriter.WriteHeader(type, sb, settings, writeHeader);

            // Write the actual object.
            ObjectToABSave(obj, type, sb, settings);
        }
Exemplo n.º 8
0
        /// <summary>
        /// Turns a whole object into ABSave, and places the result in a StringBuilder.
        /// (Does not include anything extra, such as "\u0003" or the type that goes before - for that, use <see cref="ABSaveSerializer.SerializeObject(object, ABSaveType, System.Type, ABSaveSettings, bool, bool, StringBuilder, bool)"/>)
        /// </summary>
        public static void ObjectToABSave(object obj, ABSaveType type, StringBuilder sb, ABSaveSettings settings)
        {
            // If the object is null, don't bother with doing anything.
            if (obj == null)
            {
                return;
            }

            // Get all of the variables inside this object.
            var members = ABSaveUtils.GetFieldsAndPropertiesWithValues(obj);

            // This is a variable used across the whole process to decide whether this is the first one or not (to write the "Next Item" character or not).
            var notFirst = false;

            // Keep track of what type the last property was - this allows us to decide whether to add the Next Item character to the next item.
            var lastType = ABSavePrimitiveType.Unknown;

            // Go through each variable, and process it.
            for (var i = 0; i < members.Count; i++)
            {
                ConvertVariableToABSave(type, sb, settings, members, ref notFirst, ref lastType, i);
            }
        }