From 0dd1451e48deeadafea87ad4f5cd905df9302d21 Mon Sep 17 00:00:00 2001 From: Igor Korsukov Date: Fri, 13 May 2022 19:41:28 +0300 Subject: [PATCH] added XmlStreamWriter (hidden Qt QTextStream) --- src/engraving/libmscore/figuredbass.cpp | 3 + src/engraving/libmscore/instrtemplate.cpp | 2 + src/engraving/libmscore/property.cpp | 4 + src/engraving/property/propertyvalue.h | 1 + src/engraving/rw/compat/read114.cpp | 2 +- src/engraving/rw/compat/read206.cpp | 2 +- src/engraving/rw/compat/read302.cpp | 6 +- src/engraving/rw/read400.cpp | 4 +- src/engraving/rw/scorereader.cpp | 2 +- src/engraving/rw/xmlwriter.cpp | 399 ++++-------------- src/engraving/rw/xmlwriter.h | 26 +- src/engraving/style/style.cpp | 7 +- src/engraving/types/typesconv.cpp | 3 +- src/framework/global/CMakeLists.txt | 2 + .../global/serialization/xmlstreamreader.h | 3 +- .../global/serialization/xmlstreamwriter.cpp | 157 +++++++ .../global/serialization/xmlstreamwriter.h | 70 +++ .../musicxml/internal/musicxml/exportxml.cpp | 10 +- 18 files changed, 359 insertions(+), 344 deletions(-) create mode 100644 src/framework/global/serialization/xmlstreamwriter.cpp create mode 100644 src/framework/global/serialization/xmlstreamwriter.h diff --git a/src/engraving/libmscore/figuredbass.cpp b/src/engraving/libmscore/figuredbass.cpp index cd3d209bb3..ac40fdd301 100644 --- a/src/engraving/libmscore/figuredbass.cpp +++ b/src/engraving/libmscore/figuredbass.cpp @@ -21,6 +21,9 @@ */ #include "figuredbass.h" + +#include + #include "draw/fontmetrics.h" #include "rw/xml.h" #include "score.h" diff --git a/src/engraving/libmscore/instrtemplate.cpp b/src/engraving/libmscore/instrtemplate.cpp index ff616f31a0..a8026ab20f 100644 --- a/src/engraving/libmscore/instrtemplate.cpp +++ b/src/engraving/libmscore/instrtemplate.cpp @@ -22,6 +22,8 @@ #include "instrtemplate.h" +#include + #include "translation.h" #include "containers.h" #include "style/style.h" diff --git a/src/engraving/libmscore/property.cpp b/src/engraving/libmscore/property.cpp index 0a3ff396e2..1e6752ea4f 100644 --- a/src/engraving/libmscore/property.cpp +++ b/src/engraving/libmscore/property.cpp @@ -620,12 +620,16 @@ QString propertyToString(Pid id, const PropertyValue& value, bool mscx) switch (propertyType(id)) { case P_TYPE::DURATION_TYPE_WITH_DOTS: ASSERT_X("unknown: TDURATION"); + break; case P_TYPE::TEMPO: ASSERT_X("unknown: TEMPO"); + break; case P_TYPE::GROUPS: ASSERT_X("unknown: GROUPS"); + break; case P_TYPE::INT_VEC: ASSERT_X("unknown: INT_VEC"); + break; default: { break; } diff --git a/src/engraving/property/propertyvalue.h b/src/engraving/property/propertyvalue.h index 44eb8882b9..94d4025152 100644 --- a/src/engraving/property/propertyvalue.h +++ b/src/engraving/property/propertyvalue.h @@ -257,6 +257,7 @@ public: bool isValid() const; P_TYPE type() const; + bool isEnum() const { return m_data ? m_data->isEnum() : false; } template T value() const diff --git a/src/engraving/rw/compat/read114.cpp b/src/engraving/rw/compat/read114.cpp index 25958d5674..f58e7088bd 100644 --- a/src/engraving/rw/compat/read114.cpp +++ b/src/engraving/rw/compat/read114.cpp @@ -2914,7 +2914,7 @@ Score::FileError Read114::read114(MasterScore* masterScore, XmlReader& e, ReadCo } } - if (e.error() != QXmlStreamReader::NoError) { + if (e.error() != XmlStreamReader::NoError) { LOGD("%lld %lld: %s ", e.lineNumber(), e.columnNumber(), qPrintable(e.errorString())); return Score::FileError::FILE_BAD_FORMAT; } diff --git a/src/engraving/rw/compat/read206.cpp b/src/engraving/rw/compat/read206.cpp index d8328fb14a..f7e05b7e82 100644 --- a/src/engraving/rw/compat/read206.cpp +++ b/src/engraving/rw/compat/read206.cpp @@ -3342,7 +3342,7 @@ bool Read206::readScore206(Score* score, XmlReader& e, ReadContext& ctx) e.unknown(); } } - if (e.error() != QXmlStreamReader::NoError) { + if (e.error() != XmlStreamReader::NoError) { LOGD("%s: xml read error at line %lld col %lld: %s", qPrintable(e.getDocName()), e.lineNumber(), e.columnNumber(), e.name().toUtf8().data()); diff --git a/src/engraving/rw/compat/read302.cpp b/src/engraving/rw/compat/read302.cpp index ee0ad3e5b6..fef627f146 100644 --- a/src/engraving/rw/compat/read302.cpp +++ b/src/engraving/rw/compat/read302.cpp @@ -225,11 +225,11 @@ bool Read302::readScore302(Ms::Score* score, XmlReader& e, ReadContext& ctx) } } e.context()->reconnectBrokenConnectors(); - if (e.error() != QXmlStreamReader::NoError) { + if (e.error() != XmlStreamReader::NoError) { LOGD("%s: xml read error at line %lld col %lld: %s", qPrintable(e.getDocName()), e.lineNumber(), e.columnNumber(), e.name().toUtf8().data()); - if (e.error() == QXmlStreamReader::CustomError) { + if (e.error() == XmlStreamReader::CustomError) { MScore::lastError = e.errorString(); } else { MScore::lastError = QObject::tr("XML read error at line %1, column %2: %3").arg(e.lineNumber()).arg(e.columnNumber()).arg( @@ -277,7 +277,7 @@ Score::FileError Read302::read302(Ms::MasterScore* masterScore, XmlReader& e, Re masterScore->setMscoreRevision(e.readIntHex()); } else if (tag == "Score") { if (!readScore302(masterScore, e, ctx)) { - if (e.error() == QXmlStreamReader::CustomError) { + if (e.error() == XmlStreamReader::CustomError) { return Score::FileError::FILE_CRITICALLY_CORRUPTED; } return Score::FileError::FILE_BAD_FORMAT; diff --git a/src/engraving/rw/read400.cpp b/src/engraving/rw/read400.cpp index 4d9e135549..419e407e17 100644 --- a/src/engraving/rw/read400.cpp +++ b/src/engraving/rw/read400.cpp @@ -221,11 +221,11 @@ bool Read400::readScore400(Ms::Score* score, XmlReader& e, ReadContext& ctx) } } ctx.reconnectBrokenConnectors(); - if (e.error() != QXmlStreamReader::NoError) { + if (e.error() != XmlStreamReader::NoError) { LOGD("%s: xml read error at line %lld col %lld: %s", qPrintable(e.getDocName()), e.lineNumber(), e.columnNumber(), e.name().toUtf8().data()); - if (e.error() == QXmlStreamReader::CustomError) { + if (e.error() == XmlStreamReader::CustomError) { MScore::lastError = e.errorString(); } else { MScore::lastError = QObject::tr("XML read error at line %1, column %2: %3").arg(e.lineNumber()).arg(e.columnNumber()).arg( diff --git a/src/engraving/rw/scorereader.cpp b/src/engraving/rw/scorereader.cpp index d8ba93dfab..998e1c0336 100644 --- a/src/engraving/rw/scorereader.cpp +++ b/src/engraving/rw/scorereader.cpp @@ -210,7 +210,7 @@ Err ScoreReader::doRead(MasterScore* score, XmlReader& e, ReadContext& ctx) score->setMscoreRevision(e.readIntHex()); } else if (tag == "Score") { if (!Read400::readScore400(score, e, ctx)) { - if (e.error() == QXmlStreamReader::CustomError) { + if (e.error() == XmlStreamReader::CustomError) { return Err::FileCriticalCorrupted; } return Err::FileBadFormat; diff --git a/src/engraving/rw/xmlwriter.cpp b/src/engraving/rw/xmlwriter.cpp index 445015f130..acaf07a80e 100644 --- a/src/engraving/rw/xmlwriter.cpp +++ b/src/engraving/rw/xmlwriter.cpp @@ -40,13 +40,11 @@ namespace Ms { XmlWriter::XmlWriter() { - setCodec("UTF-8"); } XmlWriter::XmlWriter(QIODevice* device) - : QTextStream(device) + : XmlStreamWriter(device) { - setCodec("UTF-8"); } XmlWriter::~XmlWriter() @@ -56,27 +54,6 @@ XmlWriter::~XmlWriter() } } -//--------------------------------------------------------- -// putLevel -//--------------------------------------------------------- - -void XmlWriter::putLevel() -{ - size_t level = stack.size(); - for (size_t i = 0; i < level * 2; ++i) { - *this << ' '; - } -} - -//--------------------------------------------------------- -// header -//--------------------------------------------------------- - -void XmlWriter::writeHeader() -{ - *this << "\n"; -} - //--------------------------------------------------------- // stag // @@ -84,9 +61,7 @@ void XmlWriter::writeHeader() void XmlWriter::startObject(const QString& s) { - putLevel(); - *this << '<' << s << '>' << Qt::endl; - stack.push_back(s.split(' ')[0]); + XmlStreamWriter::writeStartElement(s); } //--------------------------------------------------------- @@ -106,13 +81,7 @@ void XmlWriter::startObject(const EngravingObject* se, const QString& attributes void XmlWriter::startObject(const QString& name, const EngravingObject* se, const QString& attributes) { - putLevel(); - *this << '<' << name; - if (!attributes.isEmpty()) { - *this << ' ' << attributes; - } - *this << '>' << Qt::endl; - stack.push_back(name); + XmlStreamWriter::writeStartElement(name, attributes); if (_recordElements) { _elements.emplace_back(se, name); @@ -126,26 +95,7 @@ void XmlWriter::startObject(const QString& name, const EngravingObject* se, cons void XmlWriter::endObject() { - putLevel(); - *this << "' << Qt::endl; -} - -//--------------------------------------------------------- -// tagE -// -//--------------------------------------------------------- - -void XmlWriter::tagE(const char* format, ...) -{ - va_list args; - va_start(args, format); - putLevel(); - *this << '<'; - char buffer[BS]; - vsnprintf(buffer, BS, format, args); - *this << buffer; - va_end(args); - *this << "/>" << Qt::endl; + XmlStreamWriter::writeEndElement(); } //--------------------------------------------------------- @@ -154,29 +104,7 @@ void XmlWriter::tagE(const char* format, ...) void XmlWriter::tagE(const QString& s) { - putLevel(); - *this << '<' << s << "/>\n"; -} - -//--------------------------------------------------------- -// ntag -// without newline -//--------------------------------------------------------- - -void XmlWriter::ntag(const char* name) -{ - putLevel(); - *this << "<" << name << ">"; -} - -//--------------------------------------------------------- -// netag -// without indentation -//--------------------------------------------------------- - -void XmlWriter::netag(const char* s) -{ - *this << "' << Qt::endl; + XmlStreamWriter::writeElement(s); } //--------------------------------------------------------- @@ -220,38 +148,33 @@ void XmlWriter::tag(Pid id, const PropertyValue& val, const PropertyValue& def) } } -void XmlWriter::tagProperty(const char* name, P_TYPE type, const PropertyValue& data) +void XmlWriter::tagProperty(const QString& name, const PropertyValue& val, const PropertyValue& def) { - QString ename(QString(name).split(' ')[0]); + if (val == def) { + return; + } + tagProperty(name, val.type(), val); +} + +void XmlWriter::tagProperty(const QString& name, P_TYPE type, const PropertyValue& data) +{ switch (type) { case P_TYPE::UNDEFINED: UNREACHABLE; break; // base case P_TYPE::BOOL: - putLevel(); - *this << "<" << name << ">"; - *this << int(data.value()); - *this << "\n"; + XmlStreamWriter::writeElement(name, int(data.value())); break; case P_TYPE::INT: - putLevel(); - *this << "<" << name << ">"; - *this << data.value(); - *this << "\n"; + XmlStreamWriter::writeElement(name, data.value()); break; case P_TYPE::REAL: - putLevel(); - *this << "<" << name << ">"; - *this << data.value(); - *this << "\n"; + XmlStreamWriter::writeElement(name, data.value()); break; case P_TYPE::STRING: - putLevel(); - *this << "<" << name << ">"; - *this << xmlString(data.value()); - *this << "\n"; + XmlStreamWriter::writeElement(name, xmlString(data.value())); break; // geometry case P_TYPE::POINT: { @@ -260,9 +183,8 @@ void XmlWriter::tagProperty(const char* name, P_TYPE type, const PropertyValue& } break; case P_TYPE::SIZE: { - putLevel(); SizeF s = data.value(); - *this << QString("<%1 w=\"%2\" h=\"%3\"/>\n").arg(name).arg(s.width()).arg(s.height()); + XmlStreamWriter::writeElement(QString("%1 w=\"%2\" h=\"%3\"").arg(name).arg(s.width()).arg(s.height())); } break; case P_TYPE::DRAW_PATH: @@ -272,92 +194,54 @@ void XmlWriter::tagProperty(const char* name, P_TYPE type, const PropertyValue& UNREACHABLE; //! TODO break; case P_TYPE::SPATIUM: - putLevel(); - *this << "<" << name << ">"; - *this << data.value().val(); - *this << "\n"; + XmlStreamWriter::writeElement(name, data.value().val()); break; case P_TYPE::MILLIMETRE: - putLevel(); - *this << "<" << name << ">"; - *this << qreal(data.value()); - *this << "\n"; - break; + XmlStreamWriter::writeElement(name, data.value().val()); break; // draw case P_TYPE::SYMID: { - putLevel(); - *this << "<" << name << ">"; - *this << TConv::toXml(data.value()); - *this << "\n"; + XmlStreamWriter::writeElement(name, TConv::toXml(data.value())); } break; case P_TYPE::COLOR: { - putLevel(); Color color(data.value()); - *this << QString("<%1 r=\"%2\" g=\"%3\" b=\"%4\" a=\"%5\"/>\n") - .arg(name).arg(color.red()).arg(color.green()).arg(color.blue()).arg(color.alpha()); + XmlStreamWriter::writeElement(QString("%1 r=\"%2\" g=\"%3\" b=\"%4\" a=\"%5\"") + .arg(name).arg(color.red()).arg(color.green()).arg(color.blue()).arg(color.alpha())); } break; case P_TYPE::ORNAMENT_STYLE: { - putLevel(); - *this << "<" << name << ">"; - *this << XmlValue::toXml(data.value()); - *this << "\n"; + XmlStreamWriter::writeElement(name, XmlValue::toXml(data.value())); } break; case P_TYPE::GLISS_STYLE: { - putLevel(); - *this << "<" << name << ">"; - *this << XmlValue::toXml(data.value()); - *this << "\n"; + XmlStreamWriter::writeElement(name, XmlValue::toXml(data.value())); } break; case P_TYPE::ALIGN: { - putLevel(); - *this << "<" << name << ">"; - *this << TConv::toXml(data.value()); - *this << "\n"; + XmlStreamWriter::writeElement(name, TConv::toXml(data.value())); } break; case P_TYPE::PLACEMENT_V: { - putLevel(); - *this << "<" << name << ">"; - *this << XmlValue::toXml(data.value()); - *this << "\n"; + XmlStreamWriter::writeElement(name, XmlValue::toXml(data.value())); } break; case P_TYPE::PLACEMENT_H: { - putLevel(); - *this << "<" << name << ">"; - *this << XmlValue::toXml(data.value()); - *this << "\n"; + XmlStreamWriter::writeElement(name, XmlValue::toXml(data.value())); } break; case P_TYPE::TEXT_PLACE: { - putLevel(); - *this << "<" << name << ">"; - *this << XmlValue::toXml(data.value()); - *this << "\n"; + XmlStreamWriter::writeElement(name, XmlValue::toXml(data.value())); } break; case P_TYPE::DIRECTION_V: { - putLevel(); - *this << "<" << name << ">"; - *this << XmlValue::toXml(data.value()); - *this << "\n"; + XmlStreamWriter::writeElement(name, XmlValue::toXml(data.value())); } break; case P_TYPE::DIRECTION_H: { - putLevel(); - *this << "<" << name << ">"; - *this << XmlValue::toXml(data.value()); - *this << "\n"; + XmlStreamWriter::writeElement(name, XmlValue::toXml(data.value())); } break; case P_TYPE::ORIENTATION: { - putLevel(); - *this << "<" << name << ">"; - *this << TConv::toXml(data.value()); - *this << "\n"; + XmlStreamWriter::writeElement(name, TConv::toXml(data.value())); } break; // time @@ -367,106 +251,55 @@ void XmlWriter::tagProperty(const char* name, P_TYPE type, const PropertyValue& } break; case P_TYPE::LAYOUTBREAK_TYPE: { - putLevel(); - *this << "<" << name << ">"; - *this << XmlValue::toXml(data.value()); - *this << "\n"; + XmlStreamWriter::writeElement(name, XmlValue::toXml(data.value())); } break; case P_TYPE::VELO_TYPE: { - putLevel(); - *this << "<" << name << ">"; - *this << XmlValue::toXml(data.value()); - *this << "\n"; + XmlStreamWriter::writeElement(name, XmlValue::toXml(data.value())); } break; case P_TYPE::BARLINE_TYPE: { - putLevel(); - *this << "<" << name << ">"; - *this << XmlValue::toXml(data.value()); - *this << "\n"; + XmlStreamWriter::writeElement(name, XmlValue::toXml(data.value())); } break; case P_TYPE::NOTEHEAD_TYPE: { - putLevel(); - *this << "<" << name << ">"; - *this << TConv::toXml(data.value()); - *this << "\n"; + XmlStreamWriter::writeElement(name, TConv::toXml(data.value())); } break; case P_TYPE::NOTEHEAD_SCHEME: { - putLevel(); - *this << "<" << name << ">"; - *this << TConv::toXml(data.value()); - *this << "\n"; + XmlStreamWriter::writeElement(name, TConv::toXml(data.value())); } break; case P_TYPE::NOTEHEAD_GROUP: { - putLevel(); - *this << "<" << name << ">"; - *this << TConv::toXml(data.value()); - *this << "\n"; + XmlStreamWriter::writeElement(name, TConv::toXml(data.value())); } break; case P_TYPE::CLEF_TYPE: { - putLevel(); - *this << "<" << name << ">"; - *this << TConv::toXml(data.value()); - *this << "\n"; + XmlStreamWriter::writeElement(name, TConv::toXml(data.value())); } break; case P_TYPE::DYNAMIC_TYPE: { - putLevel(); - *this << "<" << name << ">"; - *this << TConv::toXml(data.value()); - *this << "\n"; + XmlStreamWriter::writeElement(name, TConv::toXml(data.value())); } break; case P_TYPE::DYNAMIC_RANGE: { - putLevel(); - *this << "<" << name << ">"; - *this << TConv::toXml(data.value()); - *this << "\n"; + XmlStreamWriter::writeElement(name, TConv::toXml(data.value())); } break; case P_TYPE::DYNAMIC_SPEED: { - putLevel(); - *this << "<" << name << ">"; - *this << TConv::toXml(data.value()); - *this << "\n"; + XmlStreamWriter::writeElement(name, TConv::toXml(data.value())); } break; case P_TYPE::HOOK_TYPE: { - putLevel(); - *this << "<" << name << ">"; - *this << TConv::toXml(data.value()); - *this << "\n"; + XmlStreamWriter::writeElement(name, TConv::toXml(data.value())); } break; case P_TYPE::KEY_MODE: { - putLevel(); - *this << "<" << name << ">"; - *this << TConv::toXml(data.value()); - *this << "\n"; + XmlStreamWriter::writeElement(name, TConv::toXml(data.value())); } break; case P_TYPE::TEXT_STYLE: { - putLevel(); - *this << "<" << name << ">"; - *this << TConv::toXml(data.value()); - *this << "\n"; + XmlStreamWriter::writeElement(name, TConv::toXml(data.value())); } break; case P_TYPE::CHANGE_METHOD: { - putLevel(); - *this << "<" << name << ">"; - *this << TConv::toXml(data.value()); - *this << "\n"; + XmlStreamWriter::writeElement(name, TConv::toXml(data.value())); } break; case P_TYPE::ACCIDENTAL_ROLE: { - putLevel(); - *this << "<" << name << ">"; - *this << TConv::toXml(data.value()); - *this << "\n"; + XmlStreamWriter::writeElement(name, TConv::toXml(data.value())); } break; case P_TYPE::PLAYTECH_TYPE: { - putLevel(); - *this << "<" << name << ">"; - *this << TConv::toXml(data.value()); - *this << "\n"; + XmlStreamWriter::writeElement(name, TConv::toXml(data.value())); } break; case P_TYPE::TEMPOCHANGE_TYPE: { - putLevel(); - *this << "<" << name << ">"; - *this << TConv::toXml(data.value()); - *this << "\n"; + XmlStreamWriter::writeElement(name, TConv::toXml(data.value())); } break; default: { UNREACHABLE; //! TODO @@ -475,26 +308,23 @@ void XmlWriter::tagProperty(const char* name, P_TYPE type, const PropertyValue& } } -void XmlWriter::tag(const char* name, const mu::PointF& p) +void XmlWriter::tag(const QString& name, const mu::PointF& p) { - putLevel(); - *this << QString("<%1 x=\"%2\" y=\"%3\"/>\n").arg(name).arg(p.x()).arg(p.y()); + XmlStreamWriter::writeElement(QString("%1 x=\"%2\" y=\"%3\"").arg(name).arg(p.x()).arg(p.y())); } void XmlWriter::tag(const char* name, const CustDef& cd) { - putLevel(); - *this << QString("<%1 degree=\"%2\" xAlt=\"%3\" octAlt=\"%4\"/>\n").arg(name).arg(cd.degree).arg(cd.xAlt).arg(cd.octAlt); + XmlStreamWriter::writeElement(QString("%1 degree=\"%2\" xAlt=\"%3\" octAlt=\"%4\"").arg(name).arg(cd.degree).arg(cd.xAlt).arg(cd.octAlt)); } -void XmlWriter::tag(const char* name, const Fraction& v, const Fraction& def) +void XmlWriter::tag(const QString& name, const Fraction& v, const Fraction& def) { if (v == def) { return; } - putLevel(); - *this << QString("<%1>%2/%3\n").arg(name).arg(v.numerator()).arg(v.denominator()); + XmlStreamWriter::writeElement(name, QString("%1/%2").arg(v.numerator()).arg(v.denominator())); } //--------------------------------------------------------- @@ -511,66 +341,55 @@ void XmlWriter::tag(const char* name, QVariant data, QVariant defaultData) void XmlWriter::tag(const QString& name, QVariant data) { - QString ename(name.split(' ')[0]); - - putLevel(); switch (data.type()) { case QVariant::Bool: case QVariant::Char: case QVariant::Int: case QVariant::UInt: - *this << "<" << name << ">"; - *this << data.toInt(); - *this << "\n"; + XmlStreamWriter::writeElement(name, data.toInt()); break; case QVariant::LongLong: - *this << "<" << name << ">"; - *this << data.toLongLong(); - *this << "\n"; + XmlStreamWriter::writeElement(name, data.toLongLong()); break; case QVariant::Double: - *this << "<" << name << ">"; - *this << data.value(); - *this << "\n"; + XmlStreamWriter::writeElement(name, data.value()); break; case QVariant::String: - *this << "<" << name << ">"; - *this << xmlString(data.value()); - *this << "\n"; + XmlStreamWriter::writeElement(name, xmlString(data.value())); break; #ifndef NO_QT_SUPPORT - case QVariant::Color: - { - QColor color(data.value()); - *this << QString("<%1 r=\"%2\" g=\"%3\" b=\"%4\" a=\"%5\"/>\n") - .arg(name).arg(color.red()).arg(color.green()).arg(color.blue()).arg(color.alpha()); - } - break; - case QVariant::Rect: - { - const QRect& r(data.value()); - *this << QString("<%1 x=\"%2\" y=\"%3\" w=\"%4\" h=\"%5\"/>\n").arg(name).arg(r.x()).arg(r.y()).arg(r.width()).arg(r.height()); - } - break; - case QVariant::RectF: - { - const QRectF& r(data.value()); - *this << QString("<%1 x=\"%2\" y=\"%3\" w=\"%4\" h=\"%5\"/>\n").arg(name).arg(r.x()).arg(r.y()).arg(r.width()).arg(r.height()); - } - break; - case QVariant::PointF: - { - const QPointF& p(data.value()); - *this << QString("<%1 x=\"%2\" y=\"%3\"/>\n").arg(name).arg(p.x()).arg(p.y()); - } - break; - case QVariant::SizeF: - { - const QSizeF& p(data.value()); - *this << QString("<%1 w=\"%2\" h=\"%3\"/>\n").arg(name).arg(p.width()).arg(p.height()); - } - break; +// case QVariant::Color: +// { +// QColor color(data.value()); +// *this << QString("<%1 r=\"%2\" g=\"%3\" b=\"%4\" a=\"%5\"/>\n") +// .arg(name).arg(color.red()).arg(color.green()).arg(color.blue()).arg(color.alpha()); +// } +// break; +// case QVariant::Rect: +// { +// const QRect& r(data.value()); +// *this << QString("<%1 x=\"%2\" y=\"%3\" w=\"%4\" h=\"%5\"/>\n").arg(name).arg(r.x()).arg(r.y()).arg(r.width()).arg(r.height()); +// } +// break; +// case QVariant::RectF: +// { +// const QRectF& r(data.value()); +// *this << QString("<%1 x=\"%2\" y=\"%3\" w=\"%4\" h=\"%5\"/>\n").arg(name).arg(r.x()).arg(r.y()).arg(r.width()).arg(r.height()); +// } +// break; +// case QVariant::PointF: +// { +// const QPointF& p(data.value()); +// *this << QString("<%1 x=\"%2\" y=\"%3\"/>\n").arg(name).arg(p.x()).arg(p.y()); +// } +// break; +// case QVariant::SizeF: +// { +// const QSizeF& p(data.value()); +// *this << QString("<%1 w=\"%2\" h=\"%3\"/>\n").arg(name).arg(p.width()).arg(p.height()); +// } +// break; #endif default: { UNREACHABLE; @@ -585,8 +404,7 @@ void XmlWriter::tag(const QString& name, QVariant data) void XmlWriter::comment(const QString& text) { - putLevel(); - *this << "" << Qt::endl; + XmlStreamWriter::writeComment(text); } //--------------------------------------------------------- @@ -628,34 +446,6 @@ QString XmlWriter::xmlString(const QString& s) return escaped; } -//--------------------------------------------------------- -// dump -//--------------------------------------------------------- - -void XmlWriter::dump(int len, const unsigned char* p) -{ - putLevel(); - int col = 0; - setFieldWidth(5); - setNumberFlags(numberFlags() | QTextStream::ShowBase); - setIntegerBase(16); - for (int i = 0; i < len; ++i, ++col) { - if (col >= 16) { - setFieldWidth(0); - *this << Qt::endl; - col = 0; - putLevel(); - setFieldWidth(5); - } - *this << (p[i] & 0xff); - } - if (col) { - *this << Qt::endl << Qt::dec; - } - setFieldWidth(0); - setIntegerBase(10); -} - //--------------------------------------------------------- // writeXml // string s is already escaped (& -> "&") @@ -663,17 +453,14 @@ void XmlWriter::dump(int len, const unsigned char* p) void XmlWriter::writeXml(const QString& name, QString s) { - QString ename(name.split(' ')[0]); - putLevel(); for (int i = 0; i < s.size(); ++i) { ushort c = s.at(i).unicode(); if (c < 0x20 && c != 0x09 && c != 0x0A && c != 0x0D) { s[i] = '?'; } } - *this << "<" << name << ">"; - *this << s; - *this << "\n"; + + XmlStreamWriter::writeElement(name, s); } mu::engraving::WriteContext* XmlWriter::context() const diff --git a/src/engraving/rw/xmlwriter.h b/src/engraving/rw/xmlwriter.h index b2222f1e95..3970d32a1d 100644 --- a/src/engraving/rw/xmlwriter.h +++ b/src/engraving/rw/xmlwriter.h @@ -23,9 +23,7 @@ #define MU_ENGRAVING_XMLWRITER_H #include -#include #include -#include #include @@ -37,25 +35,21 @@ #include "libmscore/interval.h" #include "libmscore/engravingitem.h" +#include "serialization/xmlstreamwriter.h" + namespace mu::engraving { class WriteContext; } namespace Ms { -class XmlWriter : public QTextStream +class XmlWriter : public mu::XmlStreamWriter { - static const int BS = 2048; - - std::list stack; - std::vector > _elements; bool _recordElements = false; mutable mu::engraving::WriteContext* m_context = nullptr; mutable bool m_selfContext = false; - void putLevel(); - public: XmlWriter(); XmlWriter(QIODevice* dev); @@ -64,8 +58,6 @@ public: const std::vector >& elements() const { return _elements; } void setRecordElements(bool record) { _recordElements = record; } - void writeHeader(); - void startObject(const QString&); void endObject(); @@ -73,25 +65,23 @@ public: void startObject(const QString& name, const EngravingObject* se, const QString& attributes = QString()); void tagE(const QString&); - void tagE(const char* format, ...); - void ntag(const char* name); - void netag(const char* name); void tag(Pid id, const mu::engraving::PropertyValue& data, const mu::engraving::PropertyValue& def = mu::engraving::PropertyValue()); - void tagProperty(const char* name, mu::engraving::P_TYPE type, const mu::engraving::PropertyValue& data); + void tagProperty(const QString&, const mu::engraving::PropertyValue& data, + const mu::engraving::PropertyValue& def = mu::engraving::PropertyValue()); + void tagProperty(const QString& name, mu::engraving::P_TYPE type, const mu::engraving::PropertyValue& data); void tag(const char* name, QVariant data, QVariant defaultData = QVariant()); void tag(const QString&, QVariant data); void tag(const char* name, const char* s) { tag(name, QVariant(s)); } void tag(const char* name, const QString& s) { tag(name, QVariant(s)); } - void tag(const char* name, const mu::PointF& v); - void tag(const char* name, const Fraction& v, const Fraction& def = Fraction()); + void tag(const QString& name, const mu::PointF& v); + void tag(const QString& name, const Fraction& v, const Fraction& def = Fraction()); void tag(const char* name, const CustDef& cd); void comment(const QString&); void writeXml(const QString&, QString s); - void dump(int len, const unsigned char* p); mu::engraving::WriteContext* context() const; void setContext(mu::engraving::WriteContext* context); diff --git a/src/engraving/style/style.cpp b/src/engraving/style/style.cpp index d9d3e0ac92..7ca0fefd66 100644 --- a/src/engraving/style/style.cpp +++ b/src/engraving/style/style.cpp @@ -357,7 +357,12 @@ void MStyle::save(XmlWriter& xml, bool optimize) } xml.tag(st.name(), TConv::toXml(a)); } else { - xml.tag(st.name(), value(idx).toQVariant()); + PropertyValue val = value(idx); + //! NOTE for compatibility + if (val.isEnum()) { + val = val.value(); + } + xml.tagProperty(st.name(), val); } } diff --git a/src/engraving/types/typesconv.cpp b/src/engraving/types/typesconv.cpp index f43d03e2e5..2eec9e0736 100644 --- a/src/engraving/types/typesconv.cpp +++ b/src/engraving/types/typesconv.cpp @@ -912,8 +912,7 @@ ChangeMethod TConv::fromXml(const QString& tag, ChangeMethod def) QString TConv::toXml(const PitchValue& v) { - return QString("point time=\"%1\" pitch=\"%2\" vibrato=\"%3\"") - .arg(v.time).arg(v.pitch).arg(v.vibrato); + return QString("point time=\"%1\" pitch=\"%2\" vibrato=\"%3\"").arg(v.time).arg(v.pitch).arg(v.vibrato); } QString TConv::toXml(AccidentalRole v) diff --git a/src/framework/global/CMakeLists.txt b/src/framework/global/CMakeLists.txt index 5ccc18730c..e186d3c011 100644 --- a/src/framework/global/CMakeLists.txt +++ b/src/framework/global/CMakeLists.txt @@ -97,6 +97,8 @@ set(MODULE_SRC ${CMAKE_CURRENT_LIST_DIR}/serialization/xmlstreamreader.cpp ${CMAKE_CURRENT_LIST_DIR}/serialization/xmlstreamreader.h + ${CMAKE_CURRENT_LIST_DIR}/serialization/xmlstreamwriter.cpp + ${CMAKE_CURRENT_LIST_DIR}/serialization/xmlstreamwriter.h ) if (NOT NO_GLOBAL_INTERNAL) diff --git a/src/framework/global/serialization/xmlstreamreader.h b/src/framework/global/serialization/xmlstreamreader.h index 87b5a889f4..3aec0f48e0 100644 --- a/src/framework/global/serialization/xmlstreamreader.h +++ b/src/framework/global/serialization/xmlstreamreader.h @@ -64,8 +64,7 @@ public: explicit XmlStreamReader(QIODevice* device); explicit XmlStreamReader(const QByteArray& data); - - ~XmlStreamReader(); + virtual ~XmlStreamReader(); void setData(const QByteArray& data); diff --git a/src/framework/global/serialization/xmlstreamwriter.cpp b/src/framework/global/serialization/xmlstreamwriter.cpp new file mode 100644 index 0000000000..2d4922ec15 --- /dev/null +++ b/src/framework/global/serialization/xmlstreamwriter.cpp @@ -0,0 +1,157 @@ +/* + * SPDX-License-Identifier: GPL-3.0-only + * MuseScore-CLA-applies + * + * MuseScore + * Music Composition & Notation + * + * Copyright (C) 2021 MuseScore BVBA and others + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "xmlstreamwriter.h" + +#include + +#include "containers.h" + +using namespace mu; + +XmlStreamWriter::XmlStreamWriter() +{ + m_stream = new QTextStream(); + m_stream->setCodec("UTF-8"); +} + +XmlStreamWriter::XmlStreamWriter(QIODevice* dev) +{ + m_stream = new QTextStream(dev); + m_stream->setCodec("UTF-8"); +} + +XmlStreamWriter::~XmlStreamWriter() +{ + delete m_stream; +} + +void XmlStreamWriter::setDevice(QIODevice* dev) +{ + m_stream->setDevice(dev); +} + +void XmlStreamWriter::setString(QString* string, QIODevice::OpenMode openMode) +{ + m_stream->setString(string, openMode); +} + +void XmlStreamWriter::flush() +{ + m_stream->flush(); +} + +void XmlStreamWriter::putLevel() +{ + size_t level = m_stack.size(); + for (size_t i = 0; i < level * 2; ++i) { + *m_stream << ' '; + } +} + +void XmlStreamWriter::writeHeader() +{ + *m_stream << "\n"; +} + +void XmlStreamWriter::writeDoctype(const QString& type) +{ + *m_stream << "\n"; +} + +void XmlStreamWriter::writeStartElement(const QString& name) +{ + putLevel(); + *m_stream << '<' << name << '>' << Qt::endl; + m_stack.push_back(name.split(' ')[0]); +} + +void XmlStreamWriter::writeStartElement(const QString& name, const QString& attributes) +{ + putLevel(); + *m_stream << '<' << name; + if (!attributes.isEmpty()) { + *m_stream << ' ' << attributes; + } + *m_stream << '>' << Qt::endl; + m_stack.push_back(name); +} + +void XmlStreamWriter::writeEndElement() +{ + putLevel(); + *m_stream << "' << Qt::endl; +} + +void XmlStreamWriter::writeElement(const QString& name, const QString& val) +{ + if (name == "measureNumberVPlacement") { + int k = -1; + } + + QString ename(QString(name).split(' ')[0]); + putLevel(); + *m_stream << "<" << name << ">"; + *m_stream << val; + *m_stream << "\n"; +} + +void XmlStreamWriter::writeElement(const QString& name, int val) +{ + if (name == "measureNumberVPlacement") { + int k = -1; + } + QString ename(QString(name).split(' ')[0]); + putLevel(); + *m_stream << "<" << name << ">"; + *m_stream << val; + *m_stream << "\n"; +} + +void XmlStreamWriter::writeElement(const QString& name, qint64 val) +{ + QString ename(QString(name).split(' ')[0]); + putLevel(); + *m_stream << "<" << name << ">"; + *m_stream << val; + *m_stream << "\n"; +} + +void XmlStreamWriter::writeElement(const QString& name, double val) +{ + QString ename(QString(name).split(' ')[0]); + putLevel(); + *m_stream << "<" << name << ">"; + *m_stream << val; + *m_stream << "\n"; +} + +void XmlStreamWriter::writeElement(const QString& nameWithAttributes) +{ + putLevel(); + *m_stream << '<' << nameWithAttributes << "/>\n"; +} + +void XmlStreamWriter::writeComment(const QString& text) +{ + putLevel(); + *m_stream << "\n"; +} diff --git a/src/framework/global/serialization/xmlstreamwriter.h b/src/framework/global/serialization/xmlstreamwriter.h new file mode 100644 index 0000000000..81763f9e90 --- /dev/null +++ b/src/framework/global/serialization/xmlstreamwriter.h @@ -0,0 +1,70 @@ +/* + * SPDX-License-Identifier: GPL-3.0-only + * MuseScore-CLA-applies + * + * MuseScore + * Music Composition & Notation + * + * Copyright (C) 2021 MuseScore BVBA and others + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef MU_GLOBAL_XMLSTREAMWRITER_H +#define MU_GLOBAL_XMLSTREAMWRITER_H + +#include +#include +#include + +class QTextStream; + +namespace mu { +class XmlStreamWriter +{ +public: + XmlStreamWriter(); + explicit XmlStreamWriter(QIODevice* dev); + virtual ~XmlStreamWriter(); + + void setDevice(QIODevice* dev); + void setString(QString* string, QIODevice::OpenMode openMode = QIODevice::ReadWrite); + void flush(); + + void writeHeader(); + void writeDoctype(const QString& type); + + void writeStartElement(const QString& name); + void writeStartElement(const QString& name, const QString& attributes); + void writeEndElement(); + + void writeElement(const QString& name, const QString& val); + void writeElement(const QString& name, int val); + void writeElement(const QString& name, qint64 val); + void writeElement(const QString& name, double val); + + void writeElement(const QString& nameWithAttributes); + + void writeComment(const QString& text); + +private: + + void putLevel(); + + std::list m_stack; + + //! NOTE Temporary implementation + QTextStream* m_stream = nullptr; +}; +} + +#endif // MU_GLOBAL_XMLSTREAMWRITER_H diff --git a/src/importexport/musicxml/internal/musicxml/exportxml.cpp b/src/importexport/musicxml/internal/musicxml/exportxml.cpp index edaae4b965..daa63db99d 100644 --- a/src/importexport/musicxml/internal/musicxml/exportxml.cpp +++ b/src/importexport/musicxml/internal/musicxml/exportxml.cpp @@ -7260,11 +7260,8 @@ void ExportMusicXml::write(QIODevice* dev) _jumpElements = findJumpElements(_score); _xml.setDevice(dev); - _xml.setCodec("UTF-8"); - _xml << "\n"; - _xml - << - "\n"; + _xml.writeHeader(); + _xml.writeDoctype("score-partwise PUBLIC \"-//Recordare//DTD MusicXML 4.0 Partwise//EN\" \"http://www.musicxml.org/dtds/partwise.dtd\""); _xml.startObject("score-partwise version=\"4.0\""); @@ -7343,8 +7340,7 @@ static void writeMxlArchive(Score* score, MQZipWriter& zipwriter, const QString& XmlWriter xml; xml.setDevice(&cbuf); - xml.setCodec("UTF-8"); - xml << "\n"; + xml.writeHeader(); xml.startObject("container"); xml.startObject("rootfiles"); xml.startObject(QString("rootfile full-path=\"%1\"").arg(XmlWriter::xmlString(filename)));