/** * JSON is an open standard file format, and data interchange format, * that uses human-readable text to store and transmit data objects * consisting of name–value pairs and array data types. * For more information refer to https://en.wikipedia.org/wiki/JSON * This is a base class for implementation of JSON data storage for Acedia. * It does not implement parsing and printing from/into human-readable * text representation, just provides means to store such information. * * JSON data is stored as an object (represented via `JSONObject`) that * contains a set of name-value pairs, where value can be * a number, string, boolean value, another object or * an array (represented by `JSONArray`). * Copyright 2020 Anton Tarasenko *------------------------------------------------------------------------------ * This file is part of Acedia. * * Acedia is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, version 3 of the License, or * (at your option) any later version. * * Acedia is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Acedia. If not, see . */ class JSON extends AcediaActor abstract; // Enumeration for possible types of JSON values. enum JType { // Technical type, used to indicate that requested value is missing. // Undefined values are not part of JSON format. JSON_Undefined, // An empty value, in teste representation defined by a single word "null". JSON_Null, // A number, recorded as a float. // JSON itself doesn't specify whether number is an integer or float. JSON_Number, // A string. JSON_String, // A bool value. JSON_Boolean, // Array of other JSON values, stored without names; // Single array can contain any mix of value types. JSON_Array, // Another JSON object, i.e. associative array of name-value pairs JSON_Object }; // Stores a single JSON value struct JStorageAtom { // What type is stored exactly? // Depending on that, uses one of the other fields as a storage. var protected JType type; var protected float numberValue; var protected string stringValue; var protected bool booleanValue; // Used for storing both JSON objects and arrays. var protected JSON complexValue; // Numeric value might not fit into a `float` very well, so we will store // them as both `float` and `integer` and allow user to request any version // of them var protected int numberValueAsInt; // Some `string` values might be actually used to represent classes, // so we will give users an ability to request `string` value as a class. var protected class stringValueAsClass; // To avoid several unsuccessful attempts to load `class` object from // a `string`, we will record whether we've already tied that. var protected bool classLoadingWasAttempted; }; enum JComparisonResult { JCR_Incomparable, JCR_SubSet, JCR_Overset, JCR_Equal }; public function JSON Clone() { return none; } public function bool IsSubsetOf(JSON rightJSON) { return false; } public final function JComparisonResult Compare(JSON rightJSON) { local bool firstIsSubset, secondIsSubset; if (rightJSON == none) return JCR_Incomparable; firstIsSubset = IsSubsetOf(rightJSON); secondIsSubset = rightJSON.IsSubsetOf(self); if (firstIsSubset) { if (secondIsSubset) { return JCR_Equal; } else { return JCR_SubSet; } } else { if (secondIsSubset) { return JCR_Overset; } else { return JCR_Incomparable; } } } public final function bool IsEqual(JSON rightJSON) { return (Compare(rightJSON) == JCR_Equal); } protected final function bool AreAtomsEqual( JStorageAtom atom1, JStorageAtom atom2) { if (atom1.type != atom2.type) return false; if (atom1.type == JSON_Undefined) return true; if (atom1.type == JSON_Null) return true; if (atom1.type == JSON_Number) { return ( atom1.numberValue == atom2.numberValue && atom1.numberValueAsInt == atom2.numberValueAsInt); } if (atom1.type == JSON_Boolean) { return (atom1.booleanValue == atom2.booleanValue); } if (atom1.type == JSON_String) { return (atom1.stringValue == atom2.stringValue); } if (atom1.complexValue == none && atom2.complexValue == none) { return true; } if (atom1.complexValue == none || atom2.complexValue == none) { return false; } return atom1.complexValue.IsEqual(atom2.complexValue); } protected final function TryLoadingStringAsClass(out JStorageAtom atom) { if (atom.classLoadingWasAttempted) return; atom.classLoadingWasAttempted = true; atom.stringValueAsClass = class(DynamicLoadObject(atom.stringValue, class'Class', true)); } defaultproperties { }