// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved. using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; namespace Tools.DotNETCommon { /// /// Exception thrown for errors parsing JSON files /// public class JsonParseException : Exception { /// /// Constructor /// /// Format string /// Optional arguments public JsonParseException(string Format, params object[] Args) : base(String.Format(Format, Args)) { } } /// /// Stores a JSON object in memory /// public class JsonObject { Dictionary RawObject; /// /// Construct a JSON object from the raw string -> object dictionary /// /// Raw object parsed from disk public JsonObject(Dictionary InRawObject) { RawObject = new Dictionary(InRawObject, StringComparer.InvariantCultureIgnoreCase); } /// /// Read a JSON file from disk and construct a JsonObject from it /// /// File to read from /// New JsonObject instance public static JsonObject Read(FileReference File) { string Text = FileReference.ReadAllText(File); try { return Parse(Text); } catch(Exception Ex) { throw new JsonParseException("Unable to parse {0}: {1}", File, Ex.Message); } } /// /// Tries to read a JSON file from disk /// /// File to read from /// On success, receives the parsed object /// True if the file was read, false otherwise public static bool TryRead(FileReference FileName, out JsonObject Result) { if (!FileReference.Exists(FileName)) { Result = null; return false; } string Text = FileReference.ReadAllText(FileName); return TryParse(Text, out Result); } /// /// Parse a JsonObject from the given raw text string /// /// The text to parse /// New JsonObject instance public static JsonObject Parse(string Text) { Dictionary CaseSensitiveRawObject = (Dictionary)fastJSON.JSON.Instance.Parse(Text); return new JsonObject(CaseSensitiveRawObject); } /// /// Try to parse a JsonObject from the given raw text string /// /// The text to parse /// On success, receives the new JsonObject /// True if the object was parsed public static bool TryParse(string Text, out JsonObject Result) { try { Result = Parse(Text); return true; } catch (Exception) { Result = null; return false; } } /// /// List of key names in this object /// public IEnumerable KeyNames { get { return RawObject.Keys; } } /// /// Gets a string field by the given name from the object, throwing an exception if it is not there or cannot be parsed. /// /// Name of the field to get /// The field value public string GetStringField(string FieldName) { string StringValue; if (!TryGetStringField(FieldName, out StringValue)) { throw new JsonParseException("Missing or invalid '{0}' field", FieldName); } return StringValue; } /// /// Tries to read a string field by the given name from the object /// /// Name of the field to get /// On success, receives the field value /// True if the field could be read, false otherwise public bool TryGetStringField(string FieldName, out string Result) { object RawValue; if (RawObject.TryGetValue(FieldName, out RawValue) && (RawValue is string)) { Result = (string)RawValue; return true; } else { Result = null; return false; } } /// /// Gets a string array field by the given name from the object, throwing an exception if it is not there or cannot be parsed. /// /// Name of the field to get /// The field value public string[] GetStringArrayField(string FieldName) { string[] StringValues; if (!TryGetStringArrayField(FieldName, out StringValues)) { throw new JsonParseException("Missing or invalid '{0}' field", FieldName); } return StringValues; } /// /// Tries to read a string array field by the given name from the object /// /// Name of the field to get /// On success, receives the field value /// True if the field could be read, false otherwise public bool TryGetStringArrayField(string FieldName, out string[] Result) { object RawValue; if (RawObject.TryGetValue(FieldName, out RawValue) && (RawValue is IEnumerable) && ((IEnumerable)RawValue).All(x => x is string)) { Result = ((IEnumerable)RawValue).Select(x => (string)x).ToArray(); return true; } else { Result = null; return false; } } /// /// Gets a boolean field by the given name from the object, throwing an exception if it is not there or cannot be parsed. /// /// Name of the field to get /// The field value public bool GetBoolField(string FieldName) { bool BoolValue; if (!TryGetBoolField(FieldName, out BoolValue)) { throw new JsonParseException("Missing or invalid '{0}' field", FieldName); } return BoolValue; } /// /// Tries to read a bool field by the given name from the object /// /// Name of the field to get /// On success, receives the field value /// True if the field could be read, false otherwise public bool TryGetBoolField(string FieldName, out bool Result) { object RawValue; if (RawObject.TryGetValue(FieldName, out RawValue) && (RawValue is Boolean)) { Result = (bool)RawValue; return true; } else { Result = false; return false; } } /// /// Gets an integer field by the given name from the object, throwing an exception if it is not there or cannot be parsed. /// /// Name of the field to get /// The field value public int GetIntegerField(string FieldName) { int IntegerValue; if (!TryGetIntegerField(FieldName, out IntegerValue)) { throw new JsonParseException("Missing or invalid '{0}' field", FieldName); } return IntegerValue; } /// /// Tries to read an integer field by the given name from the object /// /// Name of the field to get /// On success, receives the field value /// True if the field could be read, false otherwise public bool TryGetIntegerField(string FieldName, out int Result) { object RawValue; if (!RawObject.TryGetValue(FieldName, out RawValue) || !int.TryParse(RawValue.ToString(), out Result)) { Result = 0; return false; } return true; } /// /// Tries to read an unsigned integer field by the given name from the object /// /// Name of the field to get /// On success, receives the field value /// True if the field could be read, false otherwise public bool TryGetUnsignedIntegerField(string FieldName, out uint Result) { object RawValue; if (!RawObject.TryGetValue(FieldName, out RawValue) || !uint.TryParse(RawValue.ToString(), out Result)) { Result = 0; return false; } return true; } /// /// Gets a double field by the given name from the object, throwing an exception if it is not there or cannot be parsed. /// /// Name of the field to get /// The field value public double GetDoubleField(string FieldName) { double DoubleValue; if (!TryGetDoubleField(FieldName, out DoubleValue)) { throw new JsonParseException("Missing or invalid '{0}' field", FieldName); } return DoubleValue; } /// /// Tries to read a double field by the given name from the object /// /// Name of the field to get /// On success, receives the field value /// True if the field could be read, false otherwise public bool TryGetDoubleField(string FieldName, out double Result) { object RawValue; if (!RawObject.TryGetValue(FieldName, out RawValue) || !double.TryParse(RawValue.ToString(), out Result)) { Result = 0.0; return false; } return true; } /// /// Gets an enum field by the given name from the object, throwing an exception if it is not there or cannot be parsed. /// /// Name of the field to get /// The field value public T GetEnumField(string FieldName) where T : struct { T EnumValue; if (!TryGetEnumField(FieldName, out EnumValue)) { throw new JsonParseException("Missing or invalid '{0}' field", FieldName); } return EnumValue; } /// /// Tries to read an enum field by the given name from the object /// /// Name of the field to get /// On success, receives the field value /// True if the field could be read, false otherwise public bool TryGetEnumField(string FieldName, out T Result) where T : struct { string StringValue; if (!TryGetStringField(FieldName, out StringValue) || !Enum.TryParse(StringValue, true, out Result)) { Result = default(T); return false; } return true; } /// /// Tries to read an enum array field by the given name from the object /// /// Name of the field to get /// On success, receives the field value /// True if the field could be read, false otherwise public bool TryGetEnumArrayField(string FieldName, out T[] Result) where T : struct { string[] StringValues; if (!TryGetStringArrayField(FieldName, out StringValues)) { Result = null; return false; } T[] EnumValues = new T[StringValues.Length]; for (int Idx = 0; Idx < StringValues.Length; Idx++) { if (!Enum.TryParse(StringValues[Idx], true, out EnumValues[Idx])) { Result = null; return false; } } Result = EnumValues; return true; } /// /// Gets an object field by the given name from the object, throwing an exception if it is not there or cannot be parsed. /// /// Name of the field to get /// The field value public JsonObject GetObjectField(string FieldName) { JsonObject Result; if (!TryGetObjectField(FieldName, out Result)) { throw new JsonParseException("Missing or invalid '{0}' field", FieldName); } return Result; } /// /// Tries to read an object field by the given name from the object /// /// Name of the field to get /// On success, receives the field value /// True if the field could be read, false otherwise public bool TryGetObjectField(string FieldName, out JsonObject Result) { object RawValue; if (RawObject.TryGetValue(FieldName, out RawValue) && (RawValue is Dictionary)) { Result = new JsonObject((Dictionary)RawValue); return true; } else { Result = null; return false; } } /// /// Gets an object array field by the given name from the object, throwing an exception if it is not there or cannot be parsed. /// /// Name of the field to get /// The field value public JsonObject[] GetObjectArrayField(string FieldName) { JsonObject[] Result; if (!TryGetObjectArrayField(FieldName, out Result)) { throw new JsonParseException("Missing or invalid '{0}' field", FieldName); } return Result; } /// /// Tries to read an object array field by the given name from the object /// /// Name of the field to get /// On success, receives the field value /// True if the field could be read, false otherwise public bool TryGetObjectArrayField(string FieldName, out JsonObject[] Result) { object RawValue; if (RawObject.TryGetValue(FieldName, out RawValue) && (RawValue is IEnumerable) && ((IEnumerable)RawValue).All(x => x is Dictionary)) { Result = ((IEnumerable)RawValue).Select(x => new JsonObject((Dictionary)x)).ToArray(); return true; } else { Result = null; return false; } } } }