diff --git a/libs/main/core/pijson.cpp b/libs/main/core/pijson.cpp
new file mode 100644
index 00000000..7b93a102
--- /dev/null
+++ b/libs/main/core/pijson.cpp
@@ -0,0 +1,340 @@
+/*
+ PIP - Platform Independent Primitives
+ JSON class
+ Ivan Pelipenko peri4ko@yandex.ru
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see .
+*/
+#include "pijson.h"
+
+
+//! \~\class PIJSON pijson.h
+//! \~\details
+//! \~english \section PIJSON_sec0 Synopsis
+//! \~russian \section PIJSON_sec0 Краткий обзор
+//! \~english
+//!
+//! \~russian
+//!
+
+
+PIJSON PIJSON::newObject() {
+ PIJSON ret;
+ ret.c_type = Object;
+ return ret;
+}
+
+
+PIJSON PIJSON::newArray() {
+ PIJSON ret;
+ ret.c_type = Array;
+ return ret;
+}
+
+
+void PIJSON::setValue(const PIVariant & v) {
+ c_value = v;
+ switch (v.type()) {
+ case PIVariant::pivBool: c_type = Boolean; break;
+ case PIVariant::pivUChar:
+ case PIVariant::pivShort:
+ case PIVariant::pivUShort:
+ case PIVariant::pivInt:
+ case PIVariant::pivUInt:
+ case PIVariant::pivLLong:
+ case PIVariant::pivULLong:
+ case PIVariant::pivFloat:
+ case PIVariant::pivDouble:
+ case PIVariant::pivLDouble: c_type = Number; break;
+ case PIVariant::pivString: c_type = String; break;
+ default: c_type = Invalid; break;
+ }
+}
+
+
+void PIJSON::clear() {
+ c_type = Invalid;
+ c_value = PIVariant();
+ c_name.clear();
+ c_object.clear();
+ c_array.clear();
+}
+
+
+int PIJSON::size() const {
+ if (!isArray())
+ return 0;
+ return c_array.size_s();
+}
+
+
+bool PIJSON::contains(const PIString & key) const {
+ if (!isObject()) return false;
+ return c_object.contains(key);
+}
+
+
+void PIJSON::resize(int new_size) {
+ c_array.resize(new_size);
+ c_type = Array;
+}
+
+
+const PIJSON & PIJSON::operator[](int index) const {
+ if (!isArray())
+ return nullEntry();
+ return c_array[index];
+}
+
+
+PIJSON & PIJSON::operator[](int index) {
+ c_type = Array;
+ PIJSON & ret(c_array[index]);
+ return ret;
+}
+
+
+PIJSON & PIJSON::operator=(const PIJSON & v) {
+ c_type = v.c_type;
+ c_value = v.c_value;
+ c_object = v.c_object;
+ c_array = v.c_array;
+ return *this;
+}
+
+
+PIJSON PIJSON::operator[](const PIString & key) const {
+ if (!isObject())
+ return nullEntry();
+ if (!c_object.contains(key))
+ return nullEntry();
+ return c_object.value(key);
+}
+
+
+PIJSON & PIJSON::operator[](const PIString & key) {
+ c_type = Object;
+ PIJSON & ret(c_object[key]);
+ ret.c_name = key;
+ return ret;
+}
+
+
+PIString PIJSON::toJSON() const {
+ PIString ret;
+ print(ret, *this, "", true);
+ return ret;
+}
+
+
+PIJSON PIJSON::fromJSON(PIString str) {
+ return parseValue(str);
+}
+
+
+PIJSON & PIJSON::nullEntry() {
+ static PIJSON ret;
+ ret.clear();
+ return ret;
+}
+
+
+PIString PIJSON::parseName(PIString & s) {
+ //piCout << "\n\n\n parseName" << s;
+ PIString ret;
+ ret = s.takeRange('"', '"');
+ s.trim();
+ if (s.isEmpty()) return PIString();
+ if (s[0] != ':') return PIString();
+ s.remove(0).trim();
+ return PIJSON::stringUnmask(ret);
+}
+
+
+PIJSON PIJSON::parseValue(PIString & s) {
+ PIJSON ret;
+ //piCout << "\n\n\n parseValue" << s;
+ s.trim();
+ if (s.isEmpty()) return ret;
+ if (s[0] == '{')
+ ret = parseObject(s.takeRange('{', '}'));
+ else if (s[0] == '[')
+ ret = parseArray(s.takeRange('[', ']'));
+ else {
+ s.trim();
+ if (s.startsWith('"')) {
+ ret.c_type = PIJSON::String;
+ ret.c_value = PIJSON::stringUnmask(s.takeRange('"', '"'));
+ } else {
+ PIString value;
+ int ind = s.find(',');
+ if (ind >= 0) {
+ value = s.takeLeft(ind).trim().toLowerCase();
+ } else {
+ value = s;
+ s.clear();
+ }
+ //piCout << "\n\n\n parseValue value = \"" << value << "\"";
+ if (value == "null") {
+ ret.c_type = PIJSON::Null;
+ } else if (value == "true") {
+ ret.c_type = PIJSON::Boolean;
+ ret.c_value = true;
+ } else if (value == "false") {
+ ret.c_type = PIJSON::Boolean;
+ ret.c_value = false;
+ } else {
+ ret.c_type = PIJSON::Number;
+ ret.c_value = value;
+ }
+ }
+ }
+ return ret;
+}
+
+
+PIJSON PIJSON::parseObject(PIString s) {
+ //piCout << "\n\n\n parseObject" << s;
+ PIJSON ret;
+ ret.c_type = PIJSON::Object;
+ while (s.isNotEmpty()) {
+ PIString name = PIJSON::stringUnmask(parseName(s));
+ PIJSON value = parseValue(s);
+ auto & child(ret.c_object[name]);
+ child = value;
+ child.c_name = name;
+ s.trim();
+ if (s.isEmpty()) break;
+ if (s[0] != ',') break;
+ s.remove(0);
+ }
+ return ret;
+}
+
+
+PIJSON PIJSON::parseArray(PIString s) {
+ //piCout << "\n\n\n parseArray" << s;
+ PIJSON ret;
+ ret.c_type = PIJSON::Array;
+ while (s.isNotEmpty()) {
+ PIJSON value = parseValue(s);
+ ret.c_array << value;
+ s.trim();
+ if (s.isEmpty()) break;
+ if (s[0] != ',') break;
+ s.remove(0);
+ }
+ return ret;
+}
+
+
+PIString PIJSON::stringMask(const PIString & s) {
+ PIString ret;
+ for (auto c: s) {
+ if (!c.isAscii()) {
+ ret += "\\u" + PIString::fromNumber(c.unicode16Code(), 16).expandLeftTo(4, '0');
+ } else {
+ char ca = c.toAscii();
+ switch (ca) {
+ case '"' : ret += "\\\""; break;
+ case '\\': ret += "\\\\"; break;
+ case '/' : ret += "\\/" ; break;
+ case '\b': ret += "\\b" ; break;
+ case '\f': ret += "\\f" ; break;
+ case '\n': ret += "\\n" ; break;
+ case '\r': ret += "\\r" ; break;
+ case '\t': ret += "\\t" ; break;
+ default: ret += ca;
+ }
+ }
+ }
+ return ret;
+}
+
+
+PIString PIJSON::stringUnmask(const PIString & s) {
+ PIString ret;
+ for (int i = 0; i < s.size_s(); ++i) {
+ char ca = s[i].toAscii();
+ if (ca == '\\') {
+ if (i == s.size_s() - 1) continue;
+ ++i;
+ char na = s[i].toAscii();
+ switch (na) {
+ case '"' : ret += '\"'; break;
+ case '\\': ret += '\\'; break;
+ case '/' : ret += '/' ; break;
+ case 'b' : ret += '\b'; break;
+ case 'f' : ret += '\f'; break;
+ case 'n' : ret += '\n'; break;
+ case 'r' : ret += '\r'; break;
+ case 't' : ret += '\t'; break;
+ case 'u' :
+ ret += PIChar(s.mid(i + 1, 4).toUShort(16));
+ i += 4;
+ break;
+ default: break;
+ }
+ } else {
+ ret += s[i];
+ }
+ }
+ return ret;
+}
+
+
+void PIJSON::print(PIString & s, const PIJSON & v, PIString tab, bool transform, bool comma) {
+ s += tab;
+/*
+ switch (v.c_type) {
+ case JSONEntry::Invalid: s << "(Invalid)"; break;
+ case JSONEntry::Null: s << "(Null)"; break;
+ case JSONEntry::Boolean: s << "(Boolean)"; break;
+ case JSONEntry::Number: s << "(Number)"; break;
+ case JSONEntry::String: s << "(String)"; break;
+ case JSONEntry::Object: s << "(Object)"; break;
+ case JSONEntry::Array: s << "(Array)"; break;
+ }
+*/
+ if (v.name().isNotEmpty()) s += '"' + (transform ? stringMask(v.name()) : v.name()) + "\": ";
+ switch (v.c_type) {
+ case PIJSON::Invalid: break;
+ case PIJSON::Null: s += "null"; break;
+ case PIJSON::Boolean: s += PIString::fromBool(v.c_value.toBool()); break;
+ case PIJSON::Number: s += v.c_value.toString(); break;
+ case PIJSON::String: s += '"' + (transform ? stringMask(v.c_value.toString()) : v.c_value.toString()) + '"'; break;
+ case PIJSON::Object:
+ s += "{\n";
+ {
+ PIString ntab = tab + " ";
+ auto it = v.c_object.makeIterator();
+ int cnt = 0;
+ while (it.next())
+ print(s, it.value(), ntab, transform, ++cnt < v.c_object.size_s());
+ }
+ s += tab + "}";
+ break;
+ case PIJSON::Array:
+ s += "[\n";
+ {
+ PIString ntab = tab + " ";
+ for (int i = 0; i < v.c_array.size_s(); ++i)
+ print(s, v.c_array[i], ntab, transform, i < v.c_array.size_s() - 1);
+ }
+ s += tab + "]";
+ break;
+ }
+ if (comma) s += ',';
+ s += "\n";
+}
diff --git a/libs/main/core/pijson.h b/libs/main/core/pijson.h
new file mode 100644
index 00000000..4b2f6344
--- /dev/null
+++ b/libs/main/core/pijson.h
@@ -0,0 +1,122 @@
+/*! \file pijson.h
+ * \ingroup Core
+ * \brief
+ * \~english JSON class
+ * \~russian Класс JSON
+*/
+/*
+ PIP - Platform Independent Primitives
+ JSON class
+ Ivan Pelipenko peri4ko@yandex.ru
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see .
+*/
+
+#ifndef PIJSON_H
+#define PIJSON_H
+
+#include "pivariant.h"
+
+
+//! \ingroup Core
+//! \~\brief
+//! \~english JSON class.
+//! \~russian Класс JSON.
+class PIP_EXPORT PIJSON {
+ friend PICout operator <<(PICout s, const PIJSON & v);
+public:
+ enum Type {
+ Invalid,
+ Null,
+ Boolean,
+ Number,
+ String,
+ Object,
+ Array
+ };
+ enum PrintType {
+ Compact,
+ Tree
+ };
+ PIJSON() {}
+ PIJSON(const PIJSON & o) = default;
+
+ static PIJSON newObject();
+ static PIJSON newArray();
+
+ const PIString & name() const {return c_name;}
+ const PIVector & array() const {return c_array;}
+ const PIMap & object() const {return c_object;}
+ const PIVariant & value() const {return c_value;}
+ bool toBool() const {return c_value.toBool();}
+ int toInt() const {return c_value.toInt();}
+ double toDouble() const {return c_value.toDouble();}
+ PIString toString() const {return c_value.toString();}
+ Type type() const {return c_type;}
+ bool isValid() const {return c_type != Invalid;}
+ bool isObject() const {return c_type == Object;}
+ bool isArray() const {return c_type == Array;}
+ void setValue(const PIVariant & v);
+ void clear();
+ int size() const;
+ bool contains(const PIString & key) const;
+ void resize(int new_size);
+
+ const PIJSON & operator[](int index) const;
+ PIJSON & operator[](int index);
+ PIJSON & operator=(const PIVariant & v) {setValue(v); return *this;}
+ PIJSON & operator=(const PIJSON & v);
+
+ PIJSON operator[](const PIString & key) const;
+ PIJSON & operator[](const PIString & key);
+ PIJSON operator[](const char * key) const {return (*this)[PIString::fromUTF8(key)];}
+ PIJSON & operator[](const char * key) {return (*this)[PIString::fromUTF8(key)];}
+
+ PIString toJSON() const;
+ static PIJSON fromJSON(PIString str);
+
+private:
+ static PIJSON & nullEntry();
+ static PIString parseName(PIString & s);
+ static PIJSON parseValue(PIString & s);
+ static PIJSON parseObject(PIString s);
+ static PIJSON parseArray(PIString s);
+ static PIString stringMask(const PIString & s);;
+ static PIString stringUnmask(const PIString & s);;
+ static void print(PIString & s, const PIJSON & v, PIString tab, bool transform = false, bool comma = false);
+
+ PIString c_name;
+ PIVariant c_value;
+ PIVector c_array;
+ PIMap c_object;
+ Type c_type = Invalid;
+};
+
+
+
+//! \relatesalso PICout
+//! \~english Output operator to \a PICout.
+//! \~russian Оператор вывода в \a PICout.
+inline PICout operator <<(PICout s, const PIJSON & v) {
+ s.space();
+ s.saveAndSetControls(0);
+ PIString str;
+ PIJSON::print(str, v, "");
+ s << str;
+ s.restoreControls();
+ return s;
+}
+
+
+#endif // PICONSTCHARS_H
diff --git a/main.cpp b/main.cpp
index 22dad5b9..b2db81f4 100644
--- a/main.cpp
+++ b/main.cpp
@@ -2,178 +2,61 @@
#include "piiostream.h"
#include "pibytearray.h"
#include "pimathbase.h"
+#include "pijson.h"
using namespace PICoutManipulators;
-template
-T toDecimal(const PIString & s) {
- int part = 0, exp = 0;
- bool negative = false, negative_exp = false, err = false, has_digit = false;
- T ret = 0., frac = 0., frac_delim = 1.;
- for (const PIChar pc: s) {
- char c = pc.toAscii();
- switch (part) {
- case 0: // sign
- if (pc.isSpace()) continue;
- if (c >= '0' && c <= '9') {
- has_digit = true;
- ret = c - '0';
- part = 1;
- continue;
- }
- if (c == '+') {
- part = 1;
- continue;
- }
- if (c == '-') {
- negative = true;
- part = 1;
- continue;
- }
- if (c == '.' || c == ',') {
- part = 2;
- continue;
- }
- err = true;
- break;
- case 1: // integer
- if (c >= '0' && c <= '9') {
- has_digit = true;
- ret = ret * 10 + (c - '0');
- continue;
- }
- if (c == '.' || c == ',') {
- part = 2;
- continue;
- }
- if ((c == 'e' || c == 'E') && has_digit) {
- part = 3;
- continue;
- }
- err = true;
- break;
- case 2: // fractional
- if (c >= '0' && c <= '9') {
- has_digit = true;
- frac = frac * 10 + (c - '0');
- frac_delim *= 10.;
- //piCout << frac << frac_delim;
- //printf("%.20f %.20f\n", frac, T(c - '0') / frac_delim);
- continue;
- }
- if ((c == 'e' || c == 'E') && has_digit) {
- part = 3;
- continue;
- }
- err = true;
- break;
- case 3: // exponent with sign
- if (c == '+') {
- part = 4;
- continue;
- }
- if (c == '-') {
- negative_exp = true;
- part = 4;
- continue;
- }
- case 4: // exponent
- if (c >= '0' && c <= '9') {
- exp = (exp * 10) + (c - '0');
- continue;
- }
- err = true;
- break;
- }
- if (err) break;
- }
- frac /= frac_delim;
- ret += frac;
- if (negative && has_digit) ret = -ret;
- if (exp > 0) {
- if (negative_exp) ret /= pow10((T)exp);
- else ret *= pow10((T)exp);
- }
- return ret;
-}
+typedef PIMap PIVariantMap;
+typedef PIVector PIVariantVector;
+
+REGISTER_VARIANT(PIVariantMap);
+REGISTER_VARIANT(PIVariantVector);
+
+const char J[] =
+ "[ \n"
+ "{ \n"
+ " \"idFligth\":\"456123\", \n"
+ " \"FligthPath\": \"d:/orders/nicirt/BSK-52(BBR)/219031.001/EBN-NM-BBR.IMG\",\n"
+ " \"FligthDataPath\": \"\", \n"
+ " \"Passport\": \n"
+ " { \n"
+ " \"id\": \"\", \n"
+ " \"TypePlane\": \"\", \n"
+ " \"FA_PLANEBORT\": \"Ka52-10\" \n"
+ " } \n"
+ " }, [1.1,2,3,4,{\"a\":null},{\"bool\":true,\"bool2\":false}] \n"
+ "] \n"
+;
-inline void test(const PIString & s) {
- double av = atof(s.dataAscii());
- double v = toDecimal(s);
- printf("\n");
- piCout << s << "=" << v << av;
- printf("atof = %.20f\n", av);
- printf(" PIP = %.20f\n", v);
-}
int main(int argc, char * argv[]) {
- /*test(" 123 ");
- test("\n123 ");
- test("\t123 ");
- test(" +123 ");
- test(" ++123 ");
- test(" + 123 ");
- test(" -123 ");
- test(" --123 ");
- test(" - 123 ");
- test("123.1");
- test("123 .1");
- test("123 . 1");
- test("123.+1");
- test("123.-1");
- test("123E2");
- test("123E+2");
- test("123E +2");
- test("123E+ 2");
- test("123E + 2");
- test("123 E+2");
- test("123 E +2");
- test("123 E+ 2");
- test("123 E + 2");
- test("123E+2.5");
- test("123.4E+2");
- test("123.4.5E+2");
- test("123EE+2");
- test("123e+2");
- test("123e++2");
- test("E+2");
- test("1E+2");
- test("1.E+2");
- test(".E+2");
- test(".1E-2");
- test("+E2");
- test("nan");
- test("inf");*/
- test("-");
- test("-0");
- test("-.");
- test("-.0");
- test(".23456123456789987654");
- test("-E+100");
-
- return 0;
-
- PITimeMeasurer tm;
- PIString s("1.23456789");
- int cnt = 10000000;
- int el_o = 0, el_n = 0;
- double v = 0.;
- NO_UNUSED(v);
-
- tm.reset();
- piForTimes (cnt) {
- v = s.toDouble();
- }
- el_o = tm.elapsed_u();
- piCout << v << el_o;
-
- tm.reset();
- piForTimes (cnt) {
- v = toDecimal(s);
- }
- el_n = tm.elapsed_u();
- piCout << v << el_n;
-
- piCout << (double)el_o / el_n;
+ PIString s;
+ s = PIString::fromUTF8(J).trim();
+ s = PIString::fromUTF8("{\"st\\u0426r\":\"\\\\ \\\" \\u0425\\u0430\\n\"}");
+ //s = PIString::fromUTF8("{\"str\":\"Ха\"}");
+ PIJSON json = PIJSON::fromJSON(s);
+ piCout << json;
+ piCout << json.toJSON();
+ //json.resize(3);
+ //json["0"].setValue(123);
+ //json["1"].setValue("sec");
+ //json["2"]["f"].setValue(true);
+ //json["2"]["s"].setValue(-1);*/
+ //json[0]["Passport"]["id"] = 0xFF;
+ //piCout << json;
+ json = PIJSON::newObject();
+ json["num"] = 123;
+ json["str__"] = PIString::fromUTF8("string русский ℃ 😆 ");
+ json["obj"]["b"] = true;
+ json["obj"]["i"] = -1;
+ auto & arr(json["obj"]["arr"]);
+ arr.resize(3);
+ arr[0] = 10;
+ arr[1] = 11.2E-1;
+ arr[2] = "!!!";
+ json["obj2"] = json["obj"];
+ //piCout << json;
+ piCout << json.toJSON();
+ piCout << json["str__"].toString().toUTF8();
return 0;
}