// Copyright Epic Games, Inc. All Rights Reserved. using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Tools.DotNETCommon { /// /// Options for serializing an object to JSON /// [Obsolete("Functionality in the Tools.DotNETCommon namespace is deprecated. Please reference the EpicGames.Core namespace and assembly instead.")] public enum JsonSerializeOptions { /// /// No options /// None, /// /// Whether to format the output for readability /// PrettyPrint = 1, } /// /// Wrapper class around fastJSON methods. /// [Obsolete("Functionality in the Tools.DotNETCommon namespace is deprecated. Please reference the EpicGames.Core namespace and assembly instead.")] public static class Json { /// /// Static constructor. Registers known types to the serializer. /// static Json() { fastJSON.JSON.Instance.RegisterCustomType(typeof(FileReference), x => EscapeString(x.ToString()), x => new FileReference(x)); fastJSON.JSON.Instance.RegisterCustomType(typeof(DirectoryReference), x => EscapeString(x.ToString()), x => new DirectoryReference(x)); } /// /// Serializes an object to JSON /// /// Object to be serialized /// JSON representation of the object public static string Serialize(object Object) { return Serialize(Object, JsonSerializeOptions.PrettyPrint); } /// /// Serializes an object to JSON /// /// Object to be serialized /// Options for formatting the object /// JSON representation of the object public static string Serialize(object Object, JsonSerializeOptions Options) { fastJSON.JSONParameters Params = new fastJSON.JSONParameters(); Params.EnableAnonymousTypes = true; string Text = fastJSON.JSON.Instance.ToJSON(Object, Params); if((Options & JsonSerializeOptions.PrettyPrint) != 0) { Text = Format(Text); } return Text; } /// /// Deserialize an object from text /// /// Type of the object to deserialize /// String to parse /// Constructed object public static T Deserialize(string Text) { return fastJSON.JSON.Instance.ToObject(Text); } /// /// Read a JSON object from a file on disk /// /// The type of the object to load /// The location of the file to read /// The deserialized object public static T Load(FileReference Location) { string Text; try { Text = FileReference.ReadAllText(Location); } catch(Exception Ex) { throw new Exception(String.Format("Unable to read '{0}'", Location), Ex); } return Deserialize(Text); } /// /// Save a JSON object to a file on disk /// /// The location of the file to read /// The object to save public static void Save(FileReference Location, object Object) { string Text = Serialize(Object); try { DirectoryReference.CreateDirectory(Location.Directory); FileReference.WriteAllText(Location, Text); } catch(Exception Ex) { throw new Exception(String.Format("Unable to write '{0}'", Location), Ex); } } /// /// Formats the given JSON string in 'Epic' format (parentheses/brackets on new lines, tabs instead of spaces, no space before colons in key/value pairs) /// /// The input string /// The formatted string public static string Format(string Input) { StringBuilder Result = new StringBuilder(Input.Length * 2); bool bOnEmptyLine = true; int Depth = 0; for(int Idx = 0; Idx < Input.Length; Idx++) { switch(Input[Idx]) { case '{': case '[': if(!bOnEmptyLine) { Result.AppendLine(); bOnEmptyLine = true; } AppendIndent(Result, Depth++); Result.Append(Input[Idx]); Result.AppendLine(); break; case '}': case ']': if(!bOnEmptyLine) { Result.AppendLine(); } AppendIndent(Result, --Depth); Result.Append(Input[Idx]); bOnEmptyLine = false; break; case ':': Result.Append(Input[Idx]); Result.Append(' '); break; case ',': Result.Append(Input[Idx]); Result.AppendLine(); bOnEmptyLine = true; break; default: if(!Char.IsWhiteSpace(Input[Idx])) { // If this is an empty line, append the indent if(bOnEmptyLine) { AppendIndent(Result, Depth); bOnEmptyLine = false; } // Append the character Result.Append(Input[Idx]); // If this was a string, also append everything to the end of the string if(Input[Idx] == '\"') { Idx++; for(; Idx < Input.Length; Idx++) { Result.Append(Input[Idx]); if(Input[Idx] == '\\' && Idx + 1 < Input.Length) { Result.Append(Input[++Idx]); } else if(Input[Idx] == '\"') { break; } } } } break; } } return Result.ToString(); } /// /// Appends an indent to the output string /// /// The string builder to append to /// The number of tabs to append private static void AppendIndent(StringBuilder Builder, int Depth) { for(int Idx = 0; Idx < Depth; Idx++) { Builder.Append('\t'); } } /// /// Escapes a string for serializing to JSON /// /// The string to escape /// The escaped string public static string EscapeString(string Value) { StringBuilder Result = new StringBuilder(); for (int Idx = 0; Idx < Value.Length; Idx++) { switch (Value[Idx]) { case '\"': Result.Append("\\\""); break; case '\\': Result.Append("\\\\"); break; case '\b': Result.Append("\\b"); break; case '\f': Result.Append("\\f"); break; case '\n': Result.Append("\\n"); break; case '\r': Result.Append("\\r"); break; case '\t': Result.Append("\\t"); break; default: if (Char.IsControl(Value[Idx])) { Result.AppendFormat("\\u{0:X4}", (int)Value[Idx]); } else { Result.Append(Value[Idx]); } break; } } return Result.ToString(); } } }