From 6710a0682b7f26a8ee0e2a22e0ba536d5de6d9e5 Mon Sep 17 00:00:00 2001 From: BaerMitUmlaut Date: Sat, 28 Dec 2019 22:38:25 +0100 Subject: [PATCH 01/10] Add JSON parse and encode function --- addons/hashes/CfgFunctions.hpp | 2 + addons/hashes/fnc_encodeJSON.sqf | 88 +++++++++++ addons/hashes/fnc_parseJSON.sqf | 249 +++++++++++++++++++++++++++++++ addons/hashes/test_parseJSON.sqf | 40 +++++ 4 files changed, 379 insertions(+) create mode 100644 addons/hashes/fnc_encodeJSON.sqf create mode 100644 addons/hashes/fnc_parseJSON.sqf create mode 100644 addons/hashes/test_parseJSON.sqf diff --git a/addons/hashes/CfgFunctions.hpp b/addons/hashes/CfgFunctions.hpp index 66227fde1..111fd3c53 100644 --- a/addons/hashes/CfgFunctions.hpp +++ b/addons/hashes/CfgFunctions.hpp @@ -14,6 +14,8 @@ class CfgFunctions { PATHTO_FNC(parseYAML); PATHTO_FNC(serializeNamespace); PATHTO_FNC(deserializeNamespace); + PATHTO_FNC(encodeJSON); + PATHTO_FNC(parseJSON); }; }; }; diff --git a/addons/hashes/fnc_encodeJSON.sqf b/addons/hashes/fnc_encodeJSON.sqf new file mode 100644 index 000000000..debc6e518 --- /dev/null +++ b/addons/hashes/fnc_encodeJSON.sqf @@ -0,0 +1,88 @@ +#include "script_component.hpp" +/* ---------------------------------------------------------------------------- +Function: CBA_fnc_encodeJSON + +Description: + Serializes input to a JSON string. Can handle + - ARRAY + - BOOL + - CONTROL + - GROUP + - LOCATION + - NAMESPACE + - NIL (ANY) + - NUMBER + - OBJECT + - STRING + - TASK + - TEAM_MEMBER + +Parameters: + _object - Object to serialize. + +Returns: + _json - JSON string containing serialized object. + +Examples: + (begin example) + private _settings = call CBA_fnc_createNamespace; + _settings setVariable ["enabled", true]; + private _json = [_settings] call CBA_fnc_encodeJSON; + (end) + +Author: + BaerMitUmlaut +---------------------------------------------------------------------------- */ +SCRIPT(encodeJSON); +params ["_object"]; + +if (isNil "_object") exitWith { "null" }; + +switch (typeName _object) do { + case "SCALAR"; + case "BOOL": { + str _object; + }; + + case "STRING": { + { + _object = [_object, _x#0, _x#1] call CBA_fnc_replace; + } forEach [ + ["""", "\"""], + ["\", "\\"], + [toString [8], "\b"], + [toString [12], "\f"], + [endl, "\n"], + [toString [13], "\r"], + [toString [9], "\t"] + ]; + str _object + }; + + case "ARRAY": { + if ([_object] call CBA_fnc_isHash) then { + private _json = (([_object] call CBA_fnc_hashKeys) apply { + private _name = _x; + private _value = [_object, _name] call CBA_fnc_hashGet; + + format ["%1: %2", [_name] call CBA_fnc_encodeJSON, [_value] call CBA_fnc_encodeJSON] + }) joinString ", "; + "{" + _json + "}" + } else { + private _json = (_object apply {[_x] call CBA_fnc_encodeJSON}) joinString ", "; + "[" + _json + "]" + }; + }; + + default { + if (isNull _object) exitWith { "null" }; + + private _json = ((allVariables _object) apply { + private _name = _x; + private _value = _object getVariable _name; + + format ["%1: %2", [_name] call CBA_fnc_encodeJSON, [_value] call CBA_fnc_encodeJSON] + }) joinString ", "; + "{" + _json + "}" + }; +}; diff --git a/addons/hashes/fnc_parseJSON.sqf b/addons/hashes/fnc_parseJSON.sqf new file mode 100644 index 000000000..2a1b5fc7e --- /dev/null +++ b/addons/hashes/fnc_parseJSON.sqf @@ -0,0 +1,249 @@ +#include "script_component.hpp" +/* ---------------------------------------------------------------------------- +Function: CBA_fnc_parseJSON + +Description: + Deserializes a JSON string. + +Parameters: + _json - String containing valid JSON. + _useHashes - Output CBA hashes instead of namespaces + (optional, default: false) + +Returns: + _object - The deserialized JSON object or nil if JSON is invalid. + + +Examples: + (begin example) + private _json = "{ ""enabled"": true }"; + private _settings = [_json] call CBA_fnc_parseJSON; + private _enabled = _settings getVariable "enabled"; + (end) + +Author: + BaerMitUmlaut +---------------------------------------------------------------------------- */ +SCRIPT(parseJSON); +params ["_json", ["_useHashes", false]]; + +// Wrappers for creating "objects" and setting values on them +private ["_objectSet", "_createObject"]; +if (_useHashes) then { + _createObject = CBA_fnc_hashCreate; + _objectSet = CBA_fnc_hashSet; +} else { + _createObject = CBA_fnc_createNamespace; + _objectSet = { + params ["_obj", "_key", "_val"]; + _obj setVariable [_key, _val]; + }; +}; + +// Handles escaped characters, except for unicode escapes (\uXXXX) +private _unescape = { + params ["_char"]; + + switch (_char) do { + case """": { """" }; + case "\": { "\" }; + case "/": { "/" }; + case "b": { toString [8] }; + case "f": { toString [12] }; + case "n": { endl }; + case "r": { toString [13] }; + case "t": { toString [9] }; + default { "" }; + }; +}; + +// Splits the input string into tokens +// Tokens can be numbers, strings, null, true, false and symbols +// Strings are prefixed with $ to distinguish them from symbols +private _tokenize = { + params ["_input"]; + + // Split string into chars, works with unicode unlike splitString + _input = toArray _input apply {toString [_x]}; + + private _tokens = []; + private _numeric = "+-.0123456789e" splitString ""; + private _symbols = "{}[]:," splitString ""; + private _consts = "tfn" splitString ""; + + while {count _input > 0} do { + private _c = _input deleteAt 0; + + switch (true) do { + // Symbols ({}[]:,) are passed directly into the tokens + case (_c in _symbols): { + _tokens pushBack _c; + }; + + // Number parsing + // This can fail with some invalid JSON numbers, like e10 + // Those would require some additional logic or regex + // Valid numbers are all parsed correctly though + case (_c in _numeric): { + private _numStr = _c; + while { _c = _input deleteAt 0; _c in _numeric } do { + _numStr = _numStr + _c; + }; + _tokens pushBack parseNumber _numStr; + _input = [_c] + _input; + }; + + // true, false and null + // Only check first char and assume JSON is valid + case (_c in _consts): { + switch (_c) do { + case "t": { + _input deleteRange [0, 3]; + _tokens pushBack true; + }; + case "f": { + _input deleteRange [0, 4]; + _tokens pushBack false; + }; + case "n": { + _input deleteRange [0, 3]; + _tokens pushBack objNull; + }; + }; + }; + + // String parsing + case (_c == """"): { + private _str = "$"; + + while {true} do { + _c = _input deleteAt 0; + + if (_c == """") exitWith {}; + + if (_c == "\") then { + _str = _str + ((_input deleteAt 0) call _unescape); + } else { + _str = _str + _c; + }; + }; + + _tokens pushBack _str; + }; + }; + }; + + _tokens +}; + +// Appends the next token to the parsing stack +// Returns true unless no more tokens left +private _shift = { + params ["_parseStack", "_tokens"]; + + if (count _tokens > 0) then { + _parseStack pushBack (_tokens deleteAt 0); + true + } else { + false + }; +}; + +// Tries to reduce the current parsing stack (collect arrays or objects) +// Returns true if parsing stack could be reduced +private _reduce = { + params ["_parseStack", "_tokens"]; + + // Nothing to reduce + if (count _parseStack == 0) exitWith { false }; + + // Check top of stack + switch (_parseStack#(count _parseStack - 1)) do { + + // Reached end of array, time to collect elements + case "]": { + private _array = []; + + // Empty arrays need special handling + if !(_parseStack#(count _parseStack - 2) isEqualTo "[") then { + // Get next token, if [ beginning is reached, otherwise assume + // valid JSON and that the token is a comma + while {_parseStack deleteAt (count _parseStack - 1) != "["} do { + private _element = _parseStack deleteAt (count _parseStack - 1); + + // Remove $ prefix from string + if (_element isEqualType "") then { + _element = _element select [1]; + }; + + _array pushBack _element; + }; + + reverse _array; + } else { + _parseStack resize (count _parseStack - 2); + }; + + _parseStack pushBack _array; + true + }; + + // Reached end of array, time to collect elements + // Works very similar to arrays + case "}": { + private _object = [] call _createObject; + + // Empty objects need special handling + if !(_parseStack#(count _parseStack - 2) isEqualTo "{") then { + // Get next token, if { beginning is reached, otherwise assume + // valid JSON and that token is comma + while {_parseStack deleteAt (count _parseStack - 1) != "{"} do { + private _value = _parseStack deleteAt (count _parseStack - 1); + private _colon = _parseStack deleteAt (count _parseStack - 1); + private _name = _parseStack deleteAt (count _parseStack - 1); + + // Remove $ prefix from strings + if (_value isEqualType "") then { + _value = _value select [1]; + }; + _name = _name select [1]; + + [_object, _name, _value] call _objectSet; + }; + } else { + _parseStack resize (count _parseStack - 2); + }; + + _parseStack pushBack _object; + true + }; + + default { + false + }; + }; +}; + +// Simple shift-reduce parser +private _parse = { + params ["_tokens"]; + private _parseStack = []; + private _params = [_parseStack, _tokens]; + + while { _params call _reduce || {_params call _shift} } do {}; + + if (count _parseStack != 1) then { + nil + } else { + private _object = _parseStack#0; + + // If JSON is just a string, remove $ prefix from it + if (_object isEqualType "") then { + _object = _object select [1]; + }; + + _object + }; +}; + +[_json call _tokenize] call _parse diff --git a/addons/hashes/test_parseJSON.sqf b/addons/hashes/test_parseJSON.sqf new file mode 100644 index 000000000..485d18107 --- /dev/null +++ b/addons/hashes/test_parseJSON.sqf @@ -0,0 +1,40 @@ +#include "script_component.hpp" + +SCRIPT(test_parseJSON); + +LOG("Testing CBA_fnc_parseJSON"); + +private _testCases = [ + "null", + "true", + "1.2", + """Hello, World!""", + "[]", + "{}", + "[null, true, 1.2, ""Hello, World!""]", + "[{""nested"": [{""nested"": [{""nested"": [{""nested"": [{""nested"": [{""nested"": [{""nested"": []}]}]}]}]}]}]}]" +]; + +{ + private _useHashes = _x; + + { + diag_log _x; + private _input = _x; + private _object = [_x, _useHashes] call CBA_fnc_parseJSON; + private _output = [_object] call CBA_fnc_encodeJSON; + TEST_OP(_input,==,_output,_fn); + } forEach _testCases; +} forEach [true, false]; + +// Special test for complex object because properties are unordered +private _json = "{""OBJECT"": null, ""BOOL"": true, ""SCALAR"": 1.2, ""STRING"": ""Hello, World!"", ""ARRAY"": [], ""LOCATION"": {}}"; +private _object = [_json, false] call CBA_fnc_parseJSON; +private _properties = allVariables _object; +TEST_OP(count _properties,==,6,_fn); +{ + private _value = _object getVariable _x; + TEST_OP(typeName _value,==,_x,_fn); +} forEach _properties; + +nil From 5481dd8b1514b0a91b72ee27e35a378f7bf07521 Mon Sep 17 00:00:00 2001 From: commy2 Date: Tue, 31 Dec 2019 15:48:50 +0100 Subject: [PATCH 02/10] fix the test --- addons/hashes/test.sqf | 2 +- addons/hashes/test_parseJSON.sqf | 70 +++++++++++++++++++++++- addons/hashes/test_parseJSON_config.json | 17 ++++++ 3 files changed, 87 insertions(+), 2 deletions(-) create mode 100644 addons/hashes/test_parseJSON_config.json diff --git a/addons/hashes/test.sqf b/addons/hashes/test.sqf index 552dd9c4c..45db263d5 100644 --- a/addons/hashes/test.sqf +++ b/addons/hashes/test.sqf @@ -5,7 +5,7 @@ #define DEBUG_MODE_FULL #include "script_component.hpp" -#define TESTS ["hashEachPair", "hashes", "parseYaml", "hashFilter"] +#define TESTS ["hashEachPair", "hashes", "parseJSON", "parseYaml", "hashFilter"] SCRIPT(test-hashes); diff --git a/addons/hashes/test_parseJSON.sqf b/addons/hashes/test_parseJSON.sqf index 485d18107..8ee26bc19 100644 --- a/addons/hashes/test_parseJSON.sqf +++ b/addons/hashes/test_parseJSON.sqf @@ -1,9 +1,77 @@ +// ---------------------------------------------------------------------------- + #include "script_component.hpp" SCRIPT(test_parseJSON); -LOG("Testing CBA_fnc_parseJSON"); +// ---------------------------------------------------------------------------- + +private ["_expected", "_result", "_fn", "_data"]; + +_fn = "CBA_fnc_parseJSON"; +LOG("Testing " + _fn); + +TEST_DEFINED("CBA_fnc_parseJSON",_fn); + +// Namespace syntax +_data = [preprocessFile "\x\cba\addons\hashes\test_parseJSON_config.json"] call CBA_fnc_parseJSON; + +_result = [_data] call CBA_fnc_isHash; +TEST_FALSE(_result,_fn); + +_result = allVariables _data; +_result sort true; +_expected = ["address","age","companyname","firstname","lastname","newsubscription","phonenumber"]; //all lower case +TEST_OP(_result,isEqualTo,_expected,_fn); + +_result = _data getVariable "address" getVariable "city"; +_expected = "New York"; +TEST_OP(_result,==,_expected,_fn); + +_result = _data getVariable "phoneNumber" select 0 getVariable "type"; +_expected = "home"; +TEST_OP(_result,==,_expected,_fn); + +_result = _data getVariable "phoneNumber" select 1 getVariable "type"; +_expected = "fax"; +TEST_OP(_result,==,_expected,_fn); + +_result = _data getVariable "newSubscription"; +TEST_FALSE(_result,_fn); + +_result = _data getVariable "companyName"; +TEST_TRUE(isNull _result,_fn); + +// Hash syntax +_data = [preprocessFile "\x\cba\addons\hashes\test_parseJSON_config.json", true] call CBA_fnc_parseJSON; + +_result = [_data] call CBA_fnc_isHash; +TEST_TRUE(_result,_fn); + +_result = [_data] call CBA_fnc_hashKeys; +_result sort true; +_expected = ["address","age","companyName","firstName","lastName","newSubscription","phoneNumber"]; //camel case +TEST_OP(_result,isEqualTo,_expected,_fn); + +_result = [[_data, "address"] call CBA_fnc_hashGet, "city"] call CBA_fnc_hashGet; +_expected = "New York"; +TEST_OP(_result,==,_expected,_fn); + +_result = [[_data, "phoneNumber"] call CBA_fnc_hashGet select 0, "type"] call CBA_fnc_hashGet; +_expected = "home"; +TEST_OP(_result,==,_expected,_fn); + +_result = [[_data, "phoneNumber"] call CBA_fnc_hashGet select 1, "type"] call CBA_fnc_hashGet; +_expected = "fax"; +TEST_OP(_result,==,_expected,_fn); + +_result = [_data, "newSubscription"] call CBA_fnc_hashGet; +TEST_FALSE(_result,_fn); + +_result = [_data, "companyName"] call CBA_fnc_hashGet; +TEST_TRUE(isNull _result,_fn); +/* ??? private _testCases = [ "null", "true", diff --git a/addons/hashes/test_parseJSON_config.json b/addons/hashes/test_parseJSON_config.json new file mode 100644 index 000000000..1fa47277d --- /dev/null +++ b/addons/hashes/test_parseJSON_config.json @@ -0,0 +1,17 @@ +{ + "firstName": "Jason", + "lastName": "Smith", + "age": 25, + "address": { + "streetAddress": "21 2nd Street", + "city": "New York", + "state": "NY", + "postalCode": "10021" + }, + "phoneNumber": [ + { "type": "home", "number": "212 555-1234" }, + { "type": "fax", "number": "646 555-4567" } + ], + "newSubscription": false, + "companyName": null +} From f0481684297ee1121385474b4d8df1b2ed9a0072 Mon Sep 17 00:00:00 2001 From: commy2 Date: Tue, 31 Dec 2019 15:56:48 +0100 Subject: [PATCH 03/10] more tests --- addons/hashes/test_parseJSON.sqf | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/addons/hashes/test_parseJSON.sqf b/addons/hashes/test_parseJSON.sqf index 8ee26bc19..46a046f80 100644 --- a/addons/hashes/test_parseJSON.sqf +++ b/addons/hashes/test_parseJSON.sqf @@ -24,6 +24,14 @@ _result sort true; _expected = ["address","age","companyname","firstname","lastname","newsubscription","phonenumber"]; //all lower case TEST_OP(_result,isEqualTo,_expected,_fn); +_result = _data getVariable "lastName"; +_expected = "Smith"; +TEST_OP(_result,==,_expected,_fn); + +_result = _data getVariable "age"; +_expected = 25; +TEST_OP(_result,==,_expected,_fn); + _result = _data getVariable "address" getVariable "city"; _expected = "New York"; TEST_OP(_result,==,_expected,_fn); @@ -53,6 +61,14 @@ _result sort true; _expected = ["address","age","companyName","firstName","lastName","newSubscription","phoneNumber"]; //camel case TEST_OP(_result,isEqualTo,_expected,_fn); +_result = [_data, "lastName"] call CBA_fnc_hashGet; +_expected = "Smith"; +TEST_OP(_result,==,_expected,_fn); + +_result = [_data, "age"] call CBA_fnc_hashGet; +_expected = 25; +TEST_OP(_result,==,_expected,_fn); + _result = [[_data, "address"] call CBA_fnc_hashGet, "city"] call CBA_fnc_hashGet; _expected = "New York"; TEST_OP(_result,==,_expected,_fn); From 0cf4cc1d9db9f819d61a7a9d8c9acd5060edc10a Mon Sep 17 00:00:00 2001 From: commy2 Date: Tue, 31 Dec 2019 16:16:01 +0100 Subject: [PATCH 04/10] more examples to header --- addons/hashes/fnc_parseJSON.sqf | 3 +++ 1 file changed, 3 insertions(+) diff --git a/addons/hashes/fnc_parseJSON.sqf b/addons/hashes/fnc_parseJSON.sqf index 2a1b5fc7e..85425a4f2 100644 --- a/addons/hashes/fnc_parseJSON.sqf +++ b/addons/hashes/fnc_parseJSON.sqf @@ -19,6 +19,9 @@ Examples: private _json = "{ ""enabled"": true }"; private _settings = [_json] call CBA_fnc_parseJSON; private _enabled = _settings getVariable "enabled"; + + loadFile "data\config.json" call CBA_fnc_parseJSON + [preprocessFile "data\config.json", true] call CBA_fnc_parseJSON (end) Author: From 5d8d84a0afd2d8058449d0bf4e88677d389cafe6 Mon Sep 17 00:00:00 2001 From: BaerMitUmlaut Date: Wed, 1 Jan 2020 14:18:19 +0100 Subject: [PATCH 05/10] Fix number parsing in scheduled --- addons/hashes/fnc_parseJSON.sqf | 7 +++++-- addons/hashes/test_parseJSON.sqf | 1 - 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/addons/hashes/fnc_parseJSON.sqf b/addons/hashes/fnc_parseJSON.sqf index 85425a4f2..fee634f72 100644 --- a/addons/hashes/fnc_parseJSON.sqf +++ b/addons/hashes/fnc_parseJSON.sqf @@ -89,11 +89,14 @@ private _tokenize = { // Valid numbers are all parsed correctly though case (_c in _numeric): { private _numStr = _c; - while { _c = _input deleteAt 0; _c in _numeric } do { + while { _c = _input deleteAt 0; !isNil "_c" && {_c in _numeric} } do { _numStr = _numStr + _c; }; _tokens pushBack parseNumber _numStr; - _input = [_c] + _input; + + if (!isNil "_c") then { + _input = [_c] + _input; + }; }; // true, false and null diff --git a/addons/hashes/test_parseJSON.sqf b/addons/hashes/test_parseJSON.sqf index 46a046f80..2d44529b9 100644 --- a/addons/hashes/test_parseJSON.sqf +++ b/addons/hashes/test_parseJSON.sqf @@ -87,7 +87,6 @@ TEST_FALSE(_result,_fn); _result = [_data, "companyName"] call CBA_fnc_hashGet; TEST_TRUE(isNull _result,_fn); -/* ??? private _testCases = [ "null", "true", From 52ab2798e627cfe11e112b12587ee4604029d7bb Mon Sep 17 00:00:00 2001 From: BaerMitUmlaut Date: Wed, 1 Jan 2020 18:11:40 +0100 Subject: [PATCH 06/10] Update addons/hashes/test_parseJSON.sqf Co-Authored-By: commy2 --- addons/hashes/test_parseJSON.sqf | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/addons/hashes/test_parseJSON.sqf b/addons/hashes/test_parseJSON.sqf index 2d44529b9..9aa1a3ec3 100644 --- a/addons/hashes/test_parseJSON.sqf +++ b/addons/hashes/test_parseJSON.sqf @@ -87,6 +87,15 @@ TEST_FALSE(_result,_fn); _result = [_data, "companyName"] call CBA_fnc_hashGet; TEST_TRUE(isNull _result,_fn); +// ---------------------------------------------------------------------------- + +_fn = "CBA_fnc_encodeJSON"; +LOG("Testing " + _fn); + +TEST_DEFINED("CBA_fnc_encodeJSON",_fn); + +// ---------------------------------------------------------------------------- + private _testCases = [ "null", "true", From dd4139914b0509ee41190b430bdee4698976b5ba Mon Sep 17 00:00:00 2001 From: BaerMitUmlaut Date: Thu, 2 Jan 2020 00:39:45 +0100 Subject: [PATCH 07/10] Fix string serialization, add stringification of other data types --- addons/hashes/fnc_encodeJSON.sqf | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/addons/hashes/fnc_encodeJSON.sqf b/addons/hashes/fnc_encodeJSON.sqf index debc6e518..77aaa2001 100644 --- a/addons/hashes/fnc_encodeJSON.sqf +++ b/addons/hashes/fnc_encodeJSON.sqf @@ -16,6 +16,7 @@ Description: - STRING - TASK - TEAM_MEMBER + - Everything else will simply be stringified. Parameters: _object - Object to serialize. @@ -48,15 +49,16 @@ switch (typeName _object) do { { _object = [_object, _x#0, _x#1] call CBA_fnc_replace; } forEach [ - ["""", "\"""], ["\", "\\"], + ["""", "\"""], [toString [8], "\b"], [toString [12], "\f"], [endl, "\n"], + [toString [10], "\n"], [toString [13], "\r"], [toString [9], "\t"] ]; - str _object + """" + _object + """" }; case "ARRAY": { @@ -75,6 +77,10 @@ switch (typeName _object) do { }; default { + if !(typename _object in (supportinfo "u:allVariables*" apply {_x splitString " " select 1})) exitWith { + [str _object] call CBA_fnc_encodeJSON + }; + if (isNull _object) exitWith { "null" }; private _json = ((allVariables _object) apply { From 33bd93cf35646e2c5e7b8708717713ef051ac8f6 Mon Sep 17 00:00:00 2001 From: BaerMitUmlaut Date: Thu, 2 Jan 2020 09:29:33 +0100 Subject: [PATCH 08/10] Update addons/hashes/fnc_encodeJSON.sqf Co-Authored-By: commy2 --- addons/hashes/fnc_encodeJSON.sqf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/hashes/fnc_encodeJSON.sqf b/addons/hashes/fnc_encodeJSON.sqf index 77aaa2001..9832e7eec 100644 --- a/addons/hashes/fnc_encodeJSON.sqf +++ b/addons/hashes/fnc_encodeJSON.sqf @@ -77,7 +77,7 @@ switch (typeName _object) do { }; default { - if !(typename _object in (supportinfo "u:allVariables*" apply {_x splitString " " select 1})) exitWith { + if !(typeName _object in (supportInfo "u:allVariables*" apply {_x splitString " " select 1})) exitWith { [str _object] call CBA_fnc_encodeJSON }; From fecaa46c74a4622138bad9ca1bc222f138ab25a9 Mon Sep 17 00:00:00 2001 From: BaerMitUmlaut Date: Fri, 3 Jan 2020 00:13:22 +0100 Subject: [PATCH 09/10] Use synchronous debugging in JSON unit test --- addons/hashes/test_parseJSON.sqf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/hashes/test_parseJSON.sqf b/addons/hashes/test_parseJSON.sqf index 9aa1a3ec3..9c02c02a9 100644 --- a/addons/hashes/test_parseJSON.sqf +++ b/addons/hashes/test_parseJSON.sqf @@ -1,5 +1,5 @@ // ---------------------------------------------------------------------------- - +#define DEBUG_SYNCHRONOUS #include "script_component.hpp" SCRIPT(test_parseJSON); From d3b8f322c553daa3265af7925f0af4404b86d680 Mon Sep 17 00:00:00 2001 From: BaerMitUmlaut Date: Fri, 3 Jan 2020 09:47:20 +0100 Subject: [PATCH 10/10] Update addons/hashes/fnc_encodeJSON.sqf Co-Authored-By: commy2 --- addons/hashes/fnc_encodeJSON.sqf | 1 + 1 file changed, 1 insertion(+) diff --git a/addons/hashes/fnc_encodeJSON.sqf b/addons/hashes/fnc_encodeJSON.sqf index 9832e7eec..d8a08a193 100644 --- a/addons/hashes/fnc_encodeJSON.sqf +++ b/addons/hashes/fnc_encodeJSON.sqf @@ -58,6 +58,7 @@ switch (typeName _object) do { [toString [13], "\r"], [toString [9], "\t"] ]; + // Stringify without escaping inter string quote marks. """" + _object + """" };