/** * This class implements JSON object storage capabilities. * Whenever one wants to store JSON data, they need to define such object. * It stores name-value pairs, where names are strings and values can be: * ~ Boolean, string, null or number (float in this implementation) data; * ~ Other JSON objects; * ~ JSON Arrays (see `JSONArray` class). * * This implementation provides getters and setters for boolean, string, * null or number types that allow to freely set and fetch their values * by name. * JSON objects and arrays can be fetched by getters, but you cannot * add existing object or array to another object. Instead one has to create * a new, empty object with a certain name and then fill it with data. * This allows to avoid loop situations, where object is contained in itself. * Functions to remove existing values are also provided and are applicable * to all variable types. * Setters can also be used to overwrite any value by a different value, * even of a different type. * 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 JSONObject extends JSONBase; // We will store all our data as a simple array of key(name)-value pairs. struct JSONKeyValuePair { var string key; var JSONStorageValue value; }; var private array data; // Returns index of key-value pair in `data` with a given key. // Returns `-1` if such a pair does not exist in `data`. private final function int GetIndex(string key) { local int i; for (i = 0; i < data.length; i += 1) { if (key == data[i].key) { return i; } } return -1; } // Returns `JSONType` of a variable with a given key in our data. // This function can be used to check if certain variable exists // in this object, since if such variable does not exist - // function will return `JSON_Undefined`. public final function JSONType GetType(string key) { local int index; index = GetIndex(key); if (index < 0) return JSON_Undefined; return data[index].value.type; } // Following functions are getters for various types of variables. // Getter for null value simply checks if it's null // and returns true/false as a result. // Getters for simple types (number, string, boolean) can have optional // default value specified, that will be returned if requested variable // doesn't exist or has a different type. // Getters for object and array types don't take default values and // will simply return `none`. public final function float GetNumber(string key, optional float defaultValue) { local int index; index = GetIndex(key); if (index < 0) return defaultValue; if (data[index].value.type != JSON_Number) return defaultValue; return data[index].value.numberValue; } public final function string GetString(string key, optional string defaultValue) { local int index; index = GetIndex(key); if (index < 0) return defaultValue; if (data[index].value.type != JSON_String) return defaultValue; return data[index].value.stringValue; } public final function bool GetBoolean(string key, optional bool defaultValue) { local int index; index = GetIndex(key); if (index < 0) return defaultValue; if (data[index].value.type != JSON_Boolean) return defaultValue; return data[index].value.booleanValue; } public final function bool IsNull(string key) { local int index; index = GetIndex(key); if (index < 0) return false; if (data[index].value.type != JSON_Null) return false; return (data[index].value.type == JSON_Null); } public final function JSONArray GetArray(string key) { local int index; index = GetIndex(key); if (index < 0) return none; if (data[index].value.type != JSON_Array) return none; return JSONArray(data[index].value.complexValue); } public final function JSONObject GetObject(string key) { local int index; index = GetIndex(key); if (index < 0) return none; if (data[index].value.type != JSON_Object) return none; return JSONObject(data[index].value.complexValue); } // Following functions provide simple setters for boolean, string, number // and null values. // They return object itself, allowing user to chain calls like this: // `object.SetNumber("num1", 1).SetNumber("num2", 2);`. public final function JSONObject SetNumber(string key, float value) { local int index; local JSONKeyValuePair newKeyValuePair; local JSONStorageValue newStorageValue; index = GetIndex(key); if (index < 0) { index = data.length; } newStorageValue.type = JSON_Number; newStorageValue.numberValue = value; newKeyValuePair.key = key; newKeyValuePair.value = newStorageValue; data[index] = newKeyValuePair; return self; } public final function JSONObject SetString(string key, string value) { local int index; local JSONKeyValuePair newKeyValuePair; local JSONStorageValue newStorageValue; index = GetIndex(key); if (index < 0) { index = data.length; } newStorageValue.type = JSON_String; newStorageValue.stringValue = value; newKeyValuePair.key = key; newKeyValuePair.value = newStorageValue; data[index] = newKeyValuePair; return self; } public final function JSONObject SetBoolean(string key, bool value) { local int index; local JSONKeyValuePair newKeyValuePair; local JSONStorageValue newStorageValue; index = GetIndex(key); if (index < 0) { index = data.length; } newStorageValue.type = JSON_Boolean; newStorageValue.booleanValue = value; newKeyValuePair.key = key; newKeyValuePair.value = newStorageValue; data[index] = newKeyValuePair; return self; } public final function JSONObject SetNull(string key) { local int index; local JSONKeyValuePair newKeyValuePair; local JSONStorageValue newStorageValue; index = GetIndex(key); if (index < 0) { index = data.length; } newStorageValue.type = JSON_Null; newKeyValuePair.key = key; newKeyValuePair.value = newStorageValue; data[index] = newKeyValuePair; return self; } // JSON array and object types don't have setters, but instead have // functions to create a new, empty array/object under a certain name. // They return object itself, allowing user to chain calls like this: // `object.CreateObject("folded object").CreateArray("names list");`. public final function JSONObject CreateArray(string key) { local int index; local JSONKeyValuePair newKeyValuePair; local JSONStorageValue newStorageValue; index = GetIndex(key); if (index < 0) { index = data.length; } newStorageValue.type = JSON_Array; newStorageValue.complexValue = new class'JSONArray'; newKeyValuePair.key = key; newKeyValuePair.value = newStorageValue; data[index] = newKeyValuePair; return self; } public final function JSONObject CreateObject(string key) { local int index; local JSONKeyValuePair newKeyValuePair; local JSONStorageValue newStorageValue; index = GetIndex(key); if (index < 0) { index = data.length; } newStorageValue.type = JSON_Object; newStorageValue.complexValue = new class'JSONObject'; newKeyValuePair.key = key; newKeyValuePair.value = newStorageValue; data[index] = newKeyValuePair; return self; } // Removes values with a given name. // Returns `true` if value was actually removed and `false` if it didn't exist. public final function bool RemoveValue(string key) { local int index; index = GetIndex(key); if (index < 0) return false; data.Remove(index, 1); return true; } defaultproperties { }