diff --git a/Convert.mqh b/Convert.mqh index 8676112cd..7ff9bbe9f 100644 --- a/Convert.mqh +++ b/Convert.mqh @@ -312,22 +312,54 @@ public: _out = _value != "" && _value != NULL && _value != "0" && _value != "false"; } + static void StringToType(string _value, char& _out) { + _out = (char)StringToInteger(_value); + } + + static void StringToType(string _value, unsigned char& _out) { + _out = (unsigned char)StringToInteger(_value); + } + static void StringToType(string _value, int& _out) { _out = (int)StringToInteger(_value); } + static void StringToType(string _value, unsigned int& _out) { + _out = (unsigned int)StringToInteger(_value); + } + static void StringToType(string _value, long& _out) { - _out = StringToInteger(_value); + _out = (long)StringToInteger(_value); + } + + static void StringToType(string _value, unsigned long& _out) { + _out = (unsigned long)StringToInteger(_value); } static void StringToType(string _value, short& _out) { _out = (short) StringToInteger(_value); } + static void StringToType(string _value, unsigned short& _out) { + _out = (unsigned short) StringToInteger(_value); + } + + static void StringToType(string _value, float& _out) { + _out = (float)StringToDouble(_value); + } + static void StringToType(string _value, double& _out) { _out = StringToDouble(_value); } + static void StringToType(string _value, color& _out) { + _out = StringToColor(_value); + } + + static void StringToType(string _value, datetime& _out) { + _out = StringToTime(_value); + } + static void StringToType(string _value, string& _out) { _out = _value; } diff --git a/Serializer.mqh b/Serializer.mqh index ed84d61f1..5e1647eb8 100644 --- a/Serializer.mqh +++ b/Serializer.mqh @@ -25,6 +25,7 @@ #define SERIALIZER_MQH // Includes. +#include "Convert.mqh" #include "DictBase.mqh" #include "Log.mqh" #include "Serializer.define.h" @@ -60,6 +61,10 @@ class Serializer { _logger = new Log(); _root_node_ownership = true; fp_precision = SERIALIZER_DEFAULT_FP_PRECISION; + if (_flags == 0) { + // Preventing flags misuse. + _flags = SERIALIZER_FLAG_INCLUDE_ALL; + } } /** @@ -208,6 +213,13 @@ class Serializer { return true; } + if ((field_flags & SERIALIZER_FIELD_FLAG_HIDDEN) == SERIALIZER_FIELD_FLAG_HIDDEN) { + if ((serializer_flags & SERIALIZER_FLAG_SKIP_HIDDEN) != SERIALIZER_FLAG_SKIP_HIDDEN) { + // Field is hidden, but serializer has no SERIALIZER_FLAG_SKIP_HIDDEN flag set, so field will be serialized. + return true; + } + } + // Is field hidden? if ((serializer_flags & SERIALIZER_FLAG_SKIP_HIDDEN) == SERIALIZER_FLAG_SKIP_HIDDEN) { if ((field_flags & SERIALIZER_FIELD_FLAG_HIDDEN) == SERIALIZER_FIELD_FLAG_HIDDEN) { @@ -229,20 +241,20 @@ class Serializer { } // Is field dynamic? - if ((serializer_flags & SERIALIZER_FLAG_INCLUDE_DYNAMIC) != SERIALIZER_FLAG_INCLUDE_DYNAMIC) { + if ((serializer_flags & SERIALIZER_FLAG_INCLUDE_DYNAMIC) == SERIALIZER_FLAG_INCLUDE_DYNAMIC) { if ((field_flags & SERIALIZER_FIELD_FLAG_DYNAMIC) == SERIALIZER_FIELD_FLAG_DYNAMIC) { - return false; + return true; } } // Is field a feature? - if ((serializer_flags & SERIALIZER_FLAG_INCLUDE_FEATURE) != SERIALIZER_FLAG_INCLUDE_FEATURE) { + if ((serializer_flags & SERIALIZER_FLAG_INCLUDE_FEATURE) == SERIALIZER_FLAG_INCLUDE_FEATURE) { if ((field_flags & SERIALIZER_FIELD_FLAG_FEATURE) == SERIALIZER_FIELD_FLAG_FEATURE) { - return false; + return true; } } - return true; + return false; } /** @@ -306,11 +318,9 @@ class Serializer { int num_items; if (_mode == Serialize) { - if ((_flags & SERIALIZER_FLAG_SKIP_HIDDEN) == SERIALIZER_FLAG_SKIP_HIDDEN) { - if ((flags & SERIALIZER_FIELD_FLAG_HIDDEN) == SERIALIZER_FIELD_FLAG_HIDDEN) { - // Skipping prematurely instead of creating object by new. - return; - } + if (!IsFieldVisible(_flags, flags)) { + // Skipping prematurely instead of creating object by new. + return; } } @@ -407,7 +417,7 @@ class Serializer { value = (V)child.GetValueParam()._integral._double; break; case SerializerNodeParamString: - value = (V)(int)child.GetValueParam()._string; + Convert::StringToType(child.GetValueParam()._string, value); break; } diff --git a/SerializerJson.mqh b/SerializerJson.mqh index be4dab091..72378504d 100644 --- a/SerializerJson.mqh +++ b/SerializerJson.mqh @@ -157,6 +157,11 @@ class SerializerJson { k = i + 1; do { ch2 = StringGetCharacter(data, k++); + if (GetLastError() == 5041) { + ResetLastError(); + ch2 = 0; + break; + } } while (ch2 == ' ' || ch2 == '\t' || ch2 == '\n' || ch2 == '\r'); if (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r') continue; @@ -169,7 +174,6 @@ class SerializerJson { } if (expectingKey) { key = SerializerNodeParam::FromString(extracted); - expectingKey = false; expectingSemicolon = true; } else if (expectingValue) { @@ -177,6 +181,11 @@ class SerializerJson { current.GetType() == SerializerNodeObject ? SerializerNodeObjectProperty : SerializerNodeArrayItem, current, key, SerializerNodeParam::FromString(extracted))); +#ifdef __debug__ + Print("SerializerJson: Value \"" + extracted + "\" for key " + + (key != NULL ? ("\"" + key.ToString() + "\"") : "")); +#endif + expectingValue = false; } else { return GracefulReturn("Unexpected '\"' symbol", i, root, key); @@ -195,6 +204,10 @@ class SerializerJson { return GracefulReturn("Cannot use object as a key", i, root, key); } +#ifdef __debug__ + Print("SerializerJson: Entering object for key " + (key != NULL ? ("\"" + key.ToString() + "\"") : "")); +#endif + node = new SerializerNode(SerializerNodeObject, current, key); if (!root) root = node; @@ -212,9 +225,19 @@ class SerializerJson { return GracefulReturn("Unexpected end of object", i, root, key); } +#ifdef __debug__ + Print("SerializerJson: Leaving object for key " + (current != NULL && current.GetKeyParam() != NULL + ? ("\"" + current.GetKeyParam().ToString() + "\"") + : "")); +#endif + current = current.GetParent(); expectingValue = false; } else if (ch == '[') { +#ifdef __debug__ + Print("SerializerJson: Entering list for key " + (key != NULL ? ("\"" + key.ToString() + "\"") : "")); +#endif + if (expectingKey) { return GracefulReturn("Cannot use array as a key", i, root, key); } @@ -230,6 +253,10 @@ class SerializerJson { isOuterScope = false; key = NULL; } else if (ch == ']') { +#ifdef __debug__ + Print("SerializerJson: Leaving list for key " + (key != NULL ? ("\"" + key.ToString() + "\"") : "")); +#endif + if (expectingKey || expectingValue || current.GetType() != SerializerNodeArray) { return GracefulReturn("Unexpected end of array", i, root, key); } @@ -247,6 +274,11 @@ class SerializerJson { value = StringFind(extracted, ".") != -1 ? SerializerNodeParam::FromValue(StringToDouble(extracted)) : SerializerNodeParam::FromValue(StringToInteger(extracted)); +#ifdef __debug__ + Print("SerializerJson: Value " + value.AsString() + " for key " + + (key != NULL ? ("\"" + key.ToString() + "\"") : "")); +#endif + current.AddChild(new SerializerNode( current.GetType() == SerializerNodeObject ? SerializerNodeObjectProperty : SerializerNodeArrayItem, current, key, value)); @@ -262,6 +294,11 @@ class SerializerJson { value = SerializerNodeParam::FromValue(ch == 't' ? true : false); +#ifdef __debug__ + Print("SerializerJson: Value " + (value.ToBool() ? "true" : "false") + " for key " + + (key != NULL ? ("\"" + key.ToString() + "\"") : "")); +#endif + // Skipping value. i += ch == 't' ? 3 : 4; diff --git a/tests/ConfigTest.mq5 b/tests/ConfigTest.mq5 index 036a86698..88ab0510a 100644 --- a/tests/ConfigTest.mq5 +++ b/tests/ConfigTest.mq5 @@ -98,6 +98,11 @@ int OnInit() { // @todo // assertTrueOrFail(config.SaveToFile("config.ini", CONFIG_FORMAT_INI), "Cannot save config into the file!"); assertTrueOrFail(config.LoadFromFile("config.json"), "Cannot load config from the file!"); + + Print("There are ", config.Size(), " properites in config."); + Print("config[\"pair\"].type = \"", EnumToString(config["pair"].type), "\""); + Print("config[\"pair\"].string_value = \"", config["pair"].string_value, "\""); + assertTrueOrFail(config.LoadFromFile("config-minified.json"), "Cannot save config into the file!"); // @todo @@ -109,10 +114,12 @@ int OnInit() { configs.Push(config); Print("There are ", configs[0].Size(), " properites in configs[0]!"); + Print("configs[0][\"pair\"].type = \"", EnumToString(configs[0]["pair"].type), "\""); + Print("configs[0][\"pair\"].string_value = \"", configs[0]["pair"].string_value, "\""); SerializerConverter stub = SerializerConverter::MakeStubObject>(0, 1, configs[0].Size()); - SerializerConverter::FromObject(configs, 0).ToFile("config.csv", SERIALIZER_CSV_INCLUDE_TITLES, &stub); + SerializerConverter::FromObject(configs).ToFile("config.csv", SERIALIZER_CSV_INCLUDE_TITLES, &stub); SerializerConverter::FromObject(configs, 0).ToFile("config_2.json"); diff --git a/tests/SerializerTest.mq5 b/tests/SerializerTest.mq5 index 357d0dd92..72c250afa 100644 --- a/tests/SerializerTest.mq5 +++ b/tests/SerializerTest.mq5 @@ -313,7 +313,7 @@ int OnInit() { buff_params.Add(limit, 5); buff_params.Add(doubleVal, 6); - SerializerConverter stub5 = SerializerConverter::MakeStubObject>(0); + SerializerConverter stub5 = SerializerConverter::MakeStubObject>(); SerializerConverter::FromObject(buff_params) .ToFile("buffer_struct.csv", SERIALIZER_CSV_INCLUDE_TITLES_TREE | SERIALIZER_CSV_INCLUDE_KEY, &stub5);