From 5bb9477b5b598164e37f757c3e37df9e9ef3633d Mon Sep 17 00:00:00 2001 From: peri4 Date: Wed, 30 Nov 2022 22:40:28 +0300 Subject: [PATCH] PIVariant string conversions, PIDateTime::fromString --- .../serialization/pivaluetree_conversions.cpp | 93 +++++++++++++++++++ .../serialization/pivaluetree_conversions.h | 1 + libs/main/types/pidatetime.cpp | 92 ++++++++++++++++++ libs/main/types/pidatetime.h | 12 +++ libs/main/types/pivaluetree.cpp | 33 +++++-- libs/main/types/pivaluetree.h | 6 +- libs/main/types/pivariant.cpp | 19 +++- main.cpp | 11 ++- 8 files changed, 254 insertions(+), 13 deletions(-) diff --git a/libs/main/serialization/pivaluetree_conversions.cpp b/libs/main/serialization/pivaluetree_conversions.cpp index c5c411b1..cc275542 100644 --- a/libs/main/serialization/pivaluetree_conversions.cpp +++ b/libs/main/serialization/pivaluetree_conversions.cpp @@ -19,7 +19,9 @@ #include "pivaluetree_conversions.h" #include "pipropertystorage.h" #include "pijson.h" +#include "pifile.h" #include "piiostring.h" +#include "piiostream.h" PIValueTree PIValueTreeConversions::fromPropertyStorage(const PIPropertyStorage & ps) { @@ -35,6 +37,18 @@ PIValueTree PIValueTreeConversions::fromPropertyStorage(const PIPropertyStorage } +PIValueTree PIValueTreeConversions::fromVariantMap(const PIVariantMap & vm) { + PIValueTree ret; + for (const auto & i: vm) { + PIValueTree v; + v.setName(i.first); + v.setValue(i.second); + ret.addChild(v); + } + return ret; +} + + PIValueTree fromJSONTree(const PIJSON & json) { PIValueTree ret; ret.setName(json["name"].toString()); @@ -76,6 +90,85 @@ PIValueTree PIValueTreeConversions::fromJSON(const PIJSON & json) { PIValueTree PIValueTreeConversions::fromText(PIIODevice * device) { PIValueTree ret; + if (!device) return ret; + PIString base_path; + if (device->isTypeOf()) base_path = PIFile::FileInfo(device->path()).dir(); + PIIOTextStream ts(device); + PIString line, comm; + PIVariant value; + PIChar type; + PIStringList prefix, path; + while (!ts.isEnd()) { + PIString l = ts.readLine().trim(); + if (l.endsWith(" \\")) { + line += l.cutRight(2).trim() + "\n"; + continue; + } + line += l; + //piCout << line.replacedAll("\n", "\\n"); + if (line.size() < 2) { + line.clear(); + continue; + } + if (line.startsWith('[')) { + prefix = line.inBrackets('[', ']').trim().split('.'); + line.clear(); + continue; + } + type = 's'; + comm.clear(); + int ind = line.find('#'); + if (ind >= 0) { + comm = line.takeMid(ind + 1); + bool typed = false; + if (comm.isNotEmpty()) { + if (comm.size() == 1) typed = true; + else if (comm[0].isAlpha() && comm[1].isSpace()) typed = true; + } + if (typed) { + type = comm.takeLeft(1)[0]; + } + comm.trim(); + line.cutRight(1).trim(); + } + ind = line.find('='); + if ((ind > 0) && (line[0] != '#')) { + path = prefix; + path << line.takeLeft(ind).trim().split('.'); + line.cutLeft(1).trim(); + if (path.front() == "include") { + /*name = line.mid(ind + 1).trimmed(); + PIConfig * iconf = new PIConfig(name, incdirs); + //piCout << "include" << name << iconf->dev; + if (!iconf->dev) { + delete iconf; + } else { + inc_devs << iconf; + includes << iconf << iconf->includes; + updateIncludes(); + } + other.back() = src;*/ + } + } + //piCout << path << line << comm; + switch (type.toAscii()) { + case 'b': value = line.toBool(); break; + case 'n': value = line.toInt(); break; + case 'f': value = line.toDouble(); break; + case 'l': value = line.split("%|%"); break; + case 'c': value = PIVariantTypes::Color(line.toUInt()); break; + case 'p': + case 'v': value = PIVariant(line).toPoint(); break; + case 'r': + case 'a': value = PIVariant(line).toRect(); break; + default: value = line; + } + PIValueTree & leaf(ret[path]); + value.setValueFromString(line); + leaf.setComment(comm); + leaf.setValue(value); + line.clear(); + } return ret; } diff --git a/libs/main/serialization/pivaluetree_conversions.h b/libs/main/serialization/pivaluetree_conversions.h index 826a71a2..429b917b 100644 --- a/libs/main/serialization/pivaluetree_conversions.h +++ b/libs/main/serialization/pivaluetree_conversions.h @@ -34,6 +34,7 @@ class PIIODevice; namespace PIValueTreeConversions { PIP_EXPORT PIValueTree fromPropertyStorage(const PIPropertyStorage & ps); + PIP_EXPORT PIValueTree fromVariantMap(const PIVariantMap & vm); PIP_EXPORT PIValueTree fromJSON(const PIJSON & json); PIP_EXPORT PIValueTree fromText(PIIODevice * device); PIP_EXPORT PIJSON toJSON(const PIValueTree & root); diff --git a/libs/main/types/pidatetime.cpp b/libs/main/types/pidatetime.cpp index bab5d856..b865a7ee 100644 --- a/libs/main/types/pidatetime.cpp +++ b/libs/main/types/pidatetime.cpp @@ -45,6 +45,30 @@ //! \} +PIPair extractComponent(PIString & str) { + static PIString valid = "zsmhdMy"; + PIPair ret; + if (str.isEmpty()) return ret; + int ind = str.findAny(valid); + if (ind < 0) return ret; + ret.first = str.takeLeft(ind); + ret.second = str.takeLeft(1)[0]; + while (str.isNotEmpty()) { + if (str[0] == ret.second) + str.cutLeft(1); + else break; + } + return ret; +} +PIString extractInteger(PIString & str) { + PIString ret; + while (str.isNotEmpty()) { + if (str[0].isDigit()) + ret += str.takeLeft(1); + else break; + } + return ret; +} bool operator ==(const PITime & t0, const PITime & t1) { @@ -132,6 +156,28 @@ PISystemTime PITime::toSystemTime() const { } +PITime PITime::fromString(PIString string, PIString format) { + PITime ret; + for (;;) { + auto comp = extractComponent(format); + if (comp.second == PIChar()) break; + if (comp.first.isNotEmpty()) { + if (!string.startsWith(comp.first)) break; + string.cutLeft(comp.first.size_s()); + } + int cv = extractInteger(string).toInt(); + switch (comp.second.toAscii()) { + case 'z': ret.milliseconds = cv; break; + case 's': ret.seconds = cv; break; + case 'm': ret.minutes = cv; break; + case 'h': ret.hours = cv; break; + default: break; + } + } + return ret; +} + + PITime PITime::current() { time_t rt = ::time(0); tm * pt = localtime(&rt); @@ -211,6 +257,27 @@ PIString PIDate::toString(const PIString & format) const { } +PIDate PIDate::fromString(PIString string, PIString format) { + PIDate ret; + for (;;) { + auto comp = extractComponent(format); + if (comp.second == PIChar()) break; + if (comp.first.isNotEmpty()) { + if (!string.startsWith(comp.first)) break; + string.cutLeft(comp.first.size_s()); + } + int cv = extractInteger(string).toInt(); + switch (comp.second.toAscii()) { + case 'd': ret.day = cv; break; + case 'M': ret.month = cv; break; + case 'y': ret.year = cv; break; + default: break; + } + } + return ret; +} + + PIString PIDateTime::toString(const PIString & format) const { PIString ts = format; ts.replace("yyyy", PIString::fromNumber(year).expandLeftTo(4, '0')); @@ -250,6 +317,31 @@ time_t PIDateTime::toSecondSinceEpoch() const { } +PIDateTime PIDateTime::fromString(PIString string, PIString format) { + PIDateTime ret; + for (;;) { + auto comp = extractComponent(format); + if (comp.second == PIChar()) break; + if (comp.first.isNotEmpty()) { + if (!string.startsWith(comp.first)) break; + string.cutLeft(comp.first.size_s()); + } + int cv = extractInteger(string).toInt(); + switch (comp.second.toAscii()) { + case 'z': ret.milliseconds = cv; break; + case 's': ret.seconds = cv; break; + case 'm': ret.minutes = cv; break; + case 'h': ret.hours = cv; break; + case 'd': ret.day = cv; break; + case 'M': ret.month = cv; break; + case 'y': ret.year = cv; break; + default: break; + } + } + return ret; +} + + PIDateTime PIDateTime::fromSecondSinceEpoch(const time_t sec) { tm * pt = localtime(&sec); PIDateTime dt; diff --git a/libs/main/types/pidatetime.h b/libs/main/types/pidatetime.h index 6d23a7e9..d6d27df5 100644 --- a/libs/main/types/pidatetime.h +++ b/libs/main/types/pidatetime.h @@ -48,6 +48,10 @@ public: //! \~russian Возвращает время как %PISystemTime PISystemTime toSystemTime() const; + //! \~english Returns %PITime from string representation + //! \~russian Возвращает %PITime из строкового представления + static PITime fromString(PIString string, PIString format = "h:mm:ss"); + //! \~english Returns current time //! \~russian Возвращает текущее время static PITime current(); @@ -120,6 +124,10 @@ public: //! \~russian Возвращает строковое представление PIString toString(const PIString & format = "d.MM.yyyy") const; + //! \~english Returns %PIDate from string representation + //! \~russian Возвращает %PIDate из строкового представления + static PIDate fromString(PIString string, PIString format = "d.MM.yyyy"); + //! \~english Returns current date //! \~russian Возвращает текущую дату static PIDate current(); @@ -209,6 +217,10 @@ public: //! \~russian Возвращает секунды от 1 Янв 1970 time_t toSecondSinceEpoch() const; + //! \~english Returns %PIDateTime from string representation + //! \~russian Возвращает %PIDateTime из строкового представления + static PIDateTime fromString(PIString string, PIString format = "h:mm:ss d.MM.yyyy"); + //! \~english Returns time as %PISystemTime //! \~russian Возвращает время как %PISystemTime PISystemTime toSystemTime() const {return PISystemTime(int(toSecondSinceEpoch()), milliseconds * 1000000);} diff --git a/libs/main/types/pivaluetree.cpp b/libs/main/types/pivaluetree.cpp index 484d1b60..594a488d 100644 --- a/libs/main/types/pivaluetree.cpp +++ b/libs/main/types/pivaluetree.cpp @@ -106,17 +106,17 @@ bool PIValueTree::contains(const PIString & name) const { } -PIValueTree PIValueTree::child(const PIString & name) const { - if (_is_null) return PIValueTree(); +const PIValueTree & PIValueTree::child(const PIString & name) const { + if (_is_null) return *this; for (const auto & c: _children) if (c.name() == name) return c; - return PIValueTree(); + return nullValue(); } PIValueTree & PIValueTree::child(const PIString & name) { - if (_is_null) return nullValue(); + if (_is_null) return *this; for (auto & c: _children) if (c.name() == name) return c; @@ -125,7 +125,7 @@ PIValueTree & PIValueTree::child(const PIString & name) { PIValueTree & PIValueTree::addChild(const PIValueTree & n) { - if (_is_null) return nullValue(); + if (_is_null) return *this; for (auto & c: _children) if (c.name() == n.name()) { c = n; @@ -137,7 +137,7 @@ PIValueTree & PIValueTree::addChild(const PIValueTree & n) { PIValueTree & PIValueTree::addChildren(const PIVector & n) { - if (_is_null) return nullValue(); + if (_is_null) return *this; for (const auto & c: n) addChild(c); return *this; @@ -145,12 +145,31 @@ PIValueTree & PIValueTree::addChildren(const PIVector & n) { PIValueTree & PIValueTree::remove(const PIString & name) { - if (_is_null) return nullValue(); + if (_is_null) return *this; _children.removeWhere([name](const PIValueTree & i){return i.name() == name;}); return *this; } +PIValueTree & PIValueTree::operator[](const PIString & name) { + if (_is_null) return *this; + for (auto & c: _children) + if (c.name() == name) + return c; + _children << PIValueTree(name, PIVariant()); + return _children.back(); +} + + +PIValueTree & PIValueTree::operator[](const PIStringList & path) { + if (_is_null || path.isEmpty()) return *this; + PIValueTree * ret = &((*this)[path[0]]); + for (int i = 1; i < path.size_s(); ++i) + ret = &((*ret)[path[i]]); + return *ret; +} + + void PIValueTree::print(PIString & s, const PIValueTree & v, PIString tab) { PIString ntab = tab + " ", nntab = ntab + " "; s += tab + v.name() + " {\n"; diff --git a/libs/main/types/pivaluetree.h b/libs/main/types/pivaluetree.h index c30c9fd3..d417cfe2 100644 --- a/libs/main/types/pivaluetree.h +++ b/libs/main/types/pivaluetree.h @@ -80,12 +80,16 @@ public: void clearChildren() {_children.clear();} bool contains(const PIString & name) const; - PIValueTree child(const PIString & name) const; + const PIValueTree & child(const PIString & name) const; PIValueTree & child(const PIString & name); PIValueTree & addChild(const PIValueTree & n); PIValueTree & addChildren(const PIVector & n); PIValueTree & remove(const PIString & name); + PIValueTree & operator[](const PIString & name); + PIValueTree & operator[](const PIStringList & path); + const PIValueTree & operator[](const PIString & name) const {return child(name);} + private: static void print(PIString & s, const PIValueTree & v, PIString tab); static PIValueTree & nullValue(); diff --git a/libs/main/types/pivariant.cpp b/libs/main/types/pivariant.cpp index 2210961f..328750c4 100644 --- a/libs/main/types/pivariant.cpp +++ b/libs/main/types/pivariant.cpp @@ -102,9 +102,9 @@ void PIVariant::setValueFromString(const PIString & v) { case PIVariant::pivFloat: {setValue(v.toFloat());} break; case PIVariant::pivDouble: {setValue(v.toDouble());} break; case PIVariant::pivLDouble: {setValue(v.toLDouble());} break; - case PIVariant::pivTime: {} break; // TODO - case PIVariant::pivDate: {} break; // TODO - case PIVariant::pivDateTime: {} break; // TODO + case PIVariant::pivTime: {setValue(PITime::fromString(v));} break; + case PIVariant::pivDate: {setValue(PIDate::fromString(v));} break; + case PIVariant::pivDateTime: {setValue(PIDateTime::fromString(v));} break; case PIVariant::pivString: {setValue(v);} break; case PIVariant::pivStringList: {setValue(v.split("%|%"));} break; case PIVariant::pivEnum: {PIVariantTypes::Enum r = toEnum(); r.selectName(v); setValue(r);} break; @@ -112,6 +112,9 @@ void PIVariant::setValueFromString(const PIString & v) { case PIVariant::pivDir: {PIVariantTypes::Dir r = toDir(); r.dir = v; setValue(r);} break; case PIVariant::pivColor: {setValue(PIVariantTypes::Color(v.mid(1).toUInt(16)));} break; case PIVariant::pivIODevice: {setValue(PIVariantTypes::IODevice());} break; // TODO + case PIVariant::pivPoint: {PIStringList l = v.split(';'); if (l.size() >= 2) setValue(PIPointd(l[0].toDouble(), l[1].toDouble()));} break; + case PIVariant::pivRect: {PIStringList l = v.split(';'); if (l.size() >= 4) setValue(PIRectd(l[0].toDouble(), l[1].toDouble(), l[2].toDouble(), l[3].toDouble()));} break; + case PIVariant::pivLine: {PIStringList l = v.split(';'); if (l.size() >= 4) setValue(PILined(l[0].toDouble(), l[1].toDouble(), l[2].toDouble(), l[3].toDouble()));} break; case PIVariant::pivCustom: { #ifdef CUSTOM_PIVARIANT __PIVariantInfo__ * vi = __PIVariantInfoStorage__::get()->map->value(__PIVariantFunctions__::typeIDHelper()); @@ -690,6 +693,7 @@ ldouble PIVariant::toLDouble() const { //! PITime PIVariant::toTime() const { PIByteArray ba(_content); + if (_type == PIVariant::pivString) {PIString r; ba >> r; return PITime::fromString(r);} if (_type == PIVariant::pivTime) {PITime r; ba >> r; return r;} if (_type == PIVariant::pivDateTime) {PIDateTime r; ba >> r; return r.time();} if (_type == PIVariant::pivCustom) {return getAsValue(*this);} @@ -714,6 +718,7 @@ PITime PIVariant::toTime() const { //! PIDate PIVariant::toDate() const { PIByteArray ba(_content); + if (_type == PIVariant::pivString) {PIString r; ba >> r; return PIDate::fromString(r);} if (_type == PIVariant::pivDate) {PIDate r; ba >> r; return r;} if (_type == PIVariant::pivDateTime) {PIDateTime r; ba >> r; return r.date();} if (_type == PIVariant::pivCustom) {return getAsValue(*this);} @@ -740,6 +745,7 @@ PIDate PIVariant::toDate() const { //! PIDateTime PIVariant::toDateTime() const { PIByteArray ba(_content); + if (_type == PIVariant::pivString) {PIString r; ba >> r; return PIDateTime::fromString(r);} if (_type == PIVariant::pivTime) {PITime r; ba >> r; return PIDateTime(r);} if (_type == PIVariant::pivDate) {PIDate r; ba >> r; return PIDateTime(r);} if (_type == PIVariant::pivDateTime) {PIDateTime r; ba >> r; return r;} @@ -818,6 +824,9 @@ PIString PIVariant::toString() const { case PIVariant::pivDir: {PIVariantTypes::Dir r; ba >> r; return r.dir;} case PIVariant::pivColor: {PIVariantTypes::Color r; ba >> r; return "#" + PIString::fromNumber(r.rgba, 16);} case PIVariant::pivIODevice: {PIVariantTypes::IODevice r; ba >> r; return "IODevice";} // TODO + case PIVariant::pivPoint: {PIPointd r; ba >> r; return PIString::fromNumber(r.x) + ";" + PIString::fromNumber(r.y);} break; + case PIVariant::pivRect: {PIRectd r; ba >> r; return PIString::fromNumber(r.left()) + ";" + PIString::fromNumber(r.bottom()) + ";" + PIString::fromNumber(r.width()) + ";" + PIString::fromNumber(r.height());} break; + case PIVariant::pivLine: {PILined r; ba >> r; return PIString::fromNumber(r.p0.x) + ";" + PIString::fromNumber(r.p0.y) + ";" + PIString::fromNumber(r.p1.x) + ";" + PIString::fromNumber(r.p1.y);} break; case PIVariant::pivCustom: return getAsValue(*this); default: break; } @@ -981,6 +990,7 @@ PIVariantTypes::Dir PIVariant::toDir() const { //! PIVariantTypes::Color PIVariant::toColor() const { PIByteArray ba(_content); + if (_type == PIVariant::pivString) {PIString r; ba >> r; return PIVariantTypes::Color(r.mid(1).toUInt(16));} if (_type == PIVariant::pivColor) {PIVariantTypes::Color r; ba >> r; return r;} if (_type == PIVariant::pivInt) {int v; ba >> v; return PIVariantTypes::Color(v);} if (_type == PIVariant::pivCustom) {return getAsValue(*this);} @@ -1023,6 +1033,7 @@ PIVariantTypes::IODevice PIVariant::toIODevice() const { //! PIPointd PIVariant::toPoint() const { PIByteArray ba(_content); + if (_type == PIVariant::pivString) {PIString r; ba >> r; PIStringList l = r.split(';'); if (l.size() >= 2) return PIPointd(l[0].toDouble(), l[1].toDouble());} if (_type == PIVariant::pivPoint) {PIPointd r; ba >> r; return r;} return PIPointd(); } @@ -1043,6 +1054,7 @@ PIPointd PIVariant::toPoint() const { //! PIRectd PIVariant::toRect() const { PIByteArray ba(_content); + if (_type == PIVariant::pivString) {PIString r; ba >> r; PIStringList l = r.split(';'); if (l.size() >= 4) return PIRectd(l[0].toDouble(), l[1].toDouble(), l[2].toDouble(), l[3].toDouble());} if (_type == PIVariant::pivRect) {PIRectd r; ba >> r; return r;} return PIRectd(); } @@ -1063,6 +1075,7 @@ PIRectd PIVariant::toRect() const { //! PILined PIVariant::toLine() const { PIByteArray ba(_content); + if (_type == PIVariant::pivString) {PIString r; ba >> r; PIStringList l = r.split(';'); if (l.size() >= 4) return PILined(l[0].toDouble(), l[1].toDouble(), l[2].toDouble(), l[3].toDouble());} if (_type == PIVariant::pivLine) {PILined r; ba >> r; return r;} return PILined(); } diff --git a/main.cpp b/main.cpp index d61ba89f..b4870c57 100644 --- a/main.cpp +++ b/main.cpp @@ -27,14 +27,14 @@ REGISTER_VARIANT_CAST(PIString, SomeType) { } int main(int argc, char * argv[]) { - PIValueTree root; + /*PIValueTree root; root.addChild({"bool", PIVariant(false)}); root.addChild({"integer", PIVariant(256)}); root.addChild({"string", PIVariant("str")}); for (auto it: root.children()) { piCout << it.name() << it.value(); } - piCout << piSerialize(root); + piCout << piSerialize(root);*/ //PIVariant v = PIVariant::fromType(PIVariant::typeID()); //piCout << v; //piCout << v.toString(); @@ -42,5 +42,12 @@ int main(int argc, char * argv[]) { //piCout << v.value(); //piCout << v.toString(); + piCout << PITime(); + piCout << PITime::fromString("05:12:56"); + piCout << PITime::fromString("05: 12:56"); + piCout << PITime::fromString("05.12:56"); + piCout << PITime::fromString("05.12:56:333", "h.m.s"); + piCout << PIDateTime::fromString(PIDateTime::current().toString("__yyyy_MM_d__hh_mm_ss__"), "__yyyy_MM_d__hh_mm_ss__"); + return 0; }