Exemplo n.º 1
0
        /// <summary>
        /// Creates a string representation of a JsonObj, list, string, or double that conforms to the JSON or JSON5 standards.
        /// </summary>
        /// <param name="object">The object to stringify.</param>
        /// <param name="space">How many spaces to indent each level.</param>
        /// <returns>A string representation of the input object.</returns>
        public static string Stringify(this object @object, int space = 2)
        {
            var previousCulture = System.Threading.Thread.CurrentThread.CurrentCulture;

            System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.InvariantCulture;

            Func <char, bool> isWordChar = (c) =>
            {
                return((c >= 'a' && c <= 'z') ||
                       (c >= 'A' && c <= 'Z') ||
                       (c >= '0' && c <= '9') ||
                       c == '_' || c == '$');
            };
            Func <char, bool> isWordStart = (c) =>
            {
                return((c >= 'a' && c <= 'z') ||
                       (c >= 'A' && c <= 'Z') ||
                       c == '_' || c == '$');
            };
            Func <object, bool> isWord = (key) =>
            {
                if (!AllowBareKeys)
                {
                    return(false);
                }
                if (!(key is string))
                {
                    return(false);
                }
                var k = key as string;
                if (!isWordStart(k[0]))
                {
                    return(false);
                }
                var i = 1;
                while (i < k.Length)
                {
                    if (!isWordChar(k[i]))
                    {
                        return(false);
                    }
                    i++;
                }
                return(true);
            };

            var objStack = new Stack <object>();

            Action <object> checkForCircular = (obj) =>
            {
                if (objStack.Contains(obj))
                {
                    throw new JsonException("Converting circular structure to JSON");
                }
            };

            Func <string, int, bool, string> makeIndent = (str, num, noNewLine) =>
            {
                if (string.IsNullOrEmpty(str))
                {
                    return(string.Empty);
                }
                // indentation no more than 10 chars
                if (str.Length > 10)
                {
                    str = str.Substring(0, 10);
                }

                var indent = new StringBuilder(noNewLine ? "" : "\n");
                for (var i = 0; i < num; i++)
                {
                    indent.Append(str);
                }

                return(indent.ToString());
            };

            var indentStr = space == 0 ? string.Empty : makeIndent(" ", space, true);

            Func <string, string> escapeString = (str) =>
            {
                return('\"' + str.Replace("\"", "\\\"") + '\"');
            };

            Func <object, string> internalStringify = null;

            internalStringify = (obj_part) =>
            {
                var buffer       = new StringBuilder();
                var singleBuffer = new StringBuilder();
                var res          = string.Empty;
                if (obj_part == null)
                {
                    return("null");
                }
                if (obj_part is bool)
                {
                    return(obj_part.ToString().ToLowerInvariant());
                }
                if (obj_part is double || obj_part is float)
                {
                    if (!AllowNaN && (double.IsNaN((double)obj_part) || double.IsInfinity((double)obj_part)))
                    {
                        throw new JsonException("Found an unallowed NaN or Infinity value.");
                    }
                    else
                    {
                        return(obj_part.ToString());
                    }
                }
                if (obj_part is int || obj_part is long || obj_part is byte || obj_part is sbyte)
                {
                    return(obj_part.ToString());
                }
                if (obj_part is int[])
                {
                    return(internalStringify(((int[])obj_part).Cast <object>().ToList()));
                }
                if (obj_part is long[])
                {
                    return(internalStringify(((long[])obj_part).Cast <object>().ToList()));
                }
                if (obj_part is byte[])
                {
                    return(internalStringify(((byte[])obj_part).Cast <object>().ToList()));
                }
                if (obj_part is sbyte[])
                {
                    return(internalStringify(((sbyte[])obj_part).Cast <object>().ToList()));
                }
                if (obj_part is double[])
                {
                    return(internalStringify(((double[])obj_part).Cast <object>().ToList()));
                }
                if (obj_part is float[])
                {
                    return(internalStringify(((float[])obj_part).Cast <object>().ToList()));
                }
                if (obj_part is string[])
                {
                    return(internalStringify(((string[])obj_part).Cast <object>().ToList()));
                }
                if (obj_part is List <int> )
                {
                    return(internalStringify(((List <int>)obj_part).Cast <object>().ToList()));
                }
                if (obj_part is List <long> )
                {
                    return(internalStringify(((List <long>)obj_part).Cast <object>().ToList()));
                }
                if (obj_part is List <byte> )
                {
                    return(internalStringify(((List <byte>)obj_part).Cast <object>().ToList()));
                }
                if (obj_part is List <sbyte> )
                {
                    return(internalStringify(((List <sbyte>)obj_part).Cast <object>().ToList()));
                }
                if (obj_part is List <double> )
                {
                    return(internalStringify(((List <double>)obj_part).Cast <object>().ToList()));
                }
                if (obj_part is List <float> )
                {
                    return(internalStringify(((List <float>)obj_part).Cast <object>().ToList()));
                }
                if (obj_part is List <string> )
                {
                    return(internalStringify(((List <string>)obj_part).Cast <object>().ToList()));
                }
                if (obj_part is string)
                {
                    return(escapeString(obj_part.ToString()));
                }
                if (obj_part is object)
                {
                    if (obj_part is object[])
                    {
                        obj_part = ((object[])obj_part).ToList();
                    }
                    if (obj_part == null)
                    {
                        return("null");
                    }
                    else if (obj_part is List <object> )
                    {
                        checkForCircular(obj_part);
                        var objPartAsArray = obj_part as List <object>;
                        if (objPartAsArray.Count == 0)
                        {
                            return("[]");
                        }
                        buffer.Append('[');
                        singleBuffer.Append('[');
                        objStack.Push(obj_part);
                        for (var i = 0; i < objPartAsArray.Count; i++)
                        {
                            res = internalStringify(objPartAsArray[i]);
                            buffer.Append(makeIndent(indentStr, objStack.Count, false));
                            singleBuffer.Append(' ');
                            if (res == null)
                            {
                                buffer.Append("null");
                                singleBuffer.Append("null");
                            }
                            else
                            {
                                buffer.Append(res);
                                singleBuffer.Append(res);
                            }
                            if (i < objPartAsArray.Count - 1)
                            {
                                buffer.Append(',');
                                singleBuffer.Append(',');
                            }
                            else if (string.IsNullOrEmpty(indentStr))
                            {
                                buffer.Append('\n');
                            }
                        }
                        objStack.Pop();
                        buffer.Append(makeIndent(indentStr, objStack.Count, false));
                        buffer.Append(']');
                        singleBuffer.Append(" ]");
                        if (FoldMode.HasFlag(FoldMode.Arrays) && singleBuffer.Length < FoldLength)
                        {
                            return(singleBuffer.ToString());
                        }
                    }
                    else if (obj_part is JsonObj)
                    {
                        checkForCircular(obj_part);
                        buffer.Append('{');
                        singleBuffer.Append('{');
                        objStack.Push(obj_part);
                        var nonEmpty      = false;
                        var objPartAsDict = obj_part as JsonObj;
                        foreach (var pair in objPartAsDict)
                        {
                            var val = internalStringify(pair.Value);
                            if (val != null)
                            {
                                buffer.Append(makeIndent(indentStr, objStack.Count, false));
                                singleBuffer.Append(' ');
                                nonEmpty = true;
                                var key = isWord(pair.Key) ? pair.Key : escapeString(pair.Key);
                                buffer.AppendFormat("{0} : {1},", key, val);
                                singleBuffer.AppendFormat("{0} : {1},", key, val);
                            }
                        }
                        objStack.Pop();
                        if (nonEmpty)
                        {
                            if (FoldMode.HasFlag(FoldMode.Objects) && singleBuffer.Length < FoldLength)
                            {
                                return(singleBuffer.ToString().Substring(0, singleBuffer.Length - 1) + " }");
                            }
                            return(buffer.ToString().Substring(0, buffer.Length - 1) + makeIndent(indentStr, objStack.Count, false) + '}');
                        }
                        return("{}");
                    }
                    return(buffer.ToString());
                }
                else
                {
                    return(null);
                }
            };

            var ret = internalStringify(@object);

            System.Threading.Thread.CurrentThread.CurrentCulture = previousCulture;
            return(ret);
        }