diff --git a/src/engraving/compat/mscxcompat.cpp b/src/engraving/compat/mscxcompat.cpp index 89334e62624f1..1b9794cfbc13d 100644 --- a/src/engraving/compat/mscxcompat.cpp +++ b/src/engraving/compat/mscxcompat.cpp @@ -35,7 +35,7 @@ using namespace muse; using namespace muse::io; using namespace mu::engraving; -Ret mu::engraving::compat::mscxToMscz(const String& mscxFilePath, ByteArray* msczData) +Ret mu::engraving::compat::mscxToMscz(const io::path_t& mscxFilePath, ByteArray* msczData) { File mscxFile(mscxFilePath); if (!mscxFile.open(IODevice::ReadOnly)) { @@ -56,16 +56,18 @@ Ret mu::engraving::compat::mscxToMscz(const String& mscxFilePath, ByteArray* msc return muse::make_ok(); } -Ret mu::engraving::compat::loadMsczOrMscx(MasterScore* score, const String& path, bool ignoreVersionError) +Ret mu::engraving::compat::loadMsczOrMscx(MasterScore* score, const io::path_t& path, bool ignoreVersionError) { + std::string suffix = io::suffix(path); + ByteArray msczData; - if (path.endsWith(u".mscx", muse::CaseInsensitive)) { + if (suffix == MSCX) { //! NOTE Convert mscx -> mscz Ret ret = mscxToMscz(path, &msczData); if (!ret) { return ret; } - } else if (path.endsWith(u".mscz", muse::CaseInsensitive)) { + } else if (suffix == MSCZ) { File msczFile(path); if (!msczFile.open(IODevice::ReadOnly)) { return make_ret(Err::FileOpenError, path); @@ -92,18 +94,18 @@ Ret mu::engraving::compat::loadMsczOrMscx(MasterScore* score, const String& path return scoreReader.loadMscz(score, reader, audioSettings, ignoreVersionError); } -Ret mu::engraving::compat::loadMsczOrMscx(EngravingProjectPtr project, const String& path, bool ignoreVersionError) +Ret mu::engraving::compat::loadMsczOrMscx(EngravingProjectPtr project, const io::path_t& path, bool ignoreVersionError) { + std::string suffix = io::suffix(path); + ByteArray msczData; - String filePath = path; - if (path.endsWith(u".mscx", muse::CaseInsensitive)) { + if (suffix == MSCX) { //! NOTE Convert mscx -> mscz - Ret ret = mscxToMscz(path, &msczData); if (!ret) { return ret; } - } else if (path.endsWith(u".mscz", muse::CaseInsensitive)) { + } else if (suffix == MSCZ) { File msczFile(path); if (!msczFile.open(IODevice::ReadOnly)) { return make_ret(Err::FileOpenError, path); @@ -119,7 +121,7 @@ Ret mu::engraving::compat::loadMsczOrMscx(EngravingProjectPtr project, const Str Buffer msczBuf(&msczData); MscReader::Params params; params.device = &msczBuf; - params.filePath = filePath; + params.filePath = path; params.mode = MscIoMode::Zip; MscReader reader(params); diff --git a/src/engraving/compat/mscxcompat.h b/src/engraving/compat/mscxcompat.h index ced40fb3585c5..5b14ef086927b 100644 --- a/src/engraving/compat/mscxcompat.h +++ b/src/engraving/compat/mscxcompat.h @@ -26,9 +26,9 @@ #include "../engravingproject.h" namespace mu::engraving::compat { -muse::Ret mscxToMscz(const muse::String& mscxFilePath, muse::ByteArray* msczData); -muse::Ret loadMsczOrMscx(MasterScore* score, const muse::String& path, bool ignoreVersionError = false); -muse::Ret loadMsczOrMscx(EngravingProjectPtr project, const muse::String& path, bool ignoreVersionError = false); +muse::Ret mscxToMscz(const muse::io::path_t& mscxFilePath, muse::ByteArray* msczData); +muse::Ret loadMsczOrMscx(MasterScore* score, const muse::io::path_t& path, bool ignoreVersionError = false); +muse::Ret loadMsczOrMscx(EngravingProjectPtr project, const muse::io::path_t& path, bool ignoreVersionError = false); } #endif // MU_ENGRAVING_MSCXCOMPAT_H diff --git a/src/engraving/engravingerrors.h b/src/engraving/engravingerrors.h index e63f8d251ff8f..996f6851e2048 100644 --- a/src/engraving/engravingerrors.h +++ b/src/engraving/engravingerrors.h @@ -50,7 +50,12 @@ enum class Err { IgnoreError = 2012 }; -inline muse::Ret make_ret(Err err, const muse::io::path_t& filePath = "") +inline muse::Ret make_ret(Err err, const muse::String& text) +{ + return muse::Ret(static_cast(err), text.toStdString()); +} + +inline muse::Ret make_ret(Err err, const muse::io::path_t& filePath = {}) { muse::String text; diff --git a/src/engraving/rw/ireader.h b/src/engraving/rw/ireader.h index 708aca9099b42..ec3692be9d43d 100644 --- a/src/engraving/rw/ireader.h +++ b/src/engraving/rw/ireader.h @@ -60,7 +60,7 @@ class IReader public: virtual ~IReader() = default; - virtual Err readScore(Score* score, XmlReader& xml, rw::ReadInOutData* out) = 0; + virtual muse::Ret readScore(Score* score, XmlReader& xml, rw::ReadInOutData* out) = 0; using Supported = std::variantreadScore(partScore, xml, &partReadInData); - ret = make_ret(err); + ret = reader.val->readScore(partScore, xml, &partReadInData); if (!ret) { break; } @@ -258,15 +257,15 @@ Ret MscLoader::readMasterScore(MasterScore* score, XmlReader& e, bool ignoreVers score->checkChordList(); } - Err err = reader.val->readScore(score, e, out); + Ret ret = reader.val->readScore(score, e, out); score->setExcerptsChanged(false); - return make_ret(err); + return ret; } else { e.unknown(); } } - return Ret(static_cast(Err::FileCorrupted), e.errorString().toStdString()); + return make_ret(Err::FileCriticallyCorrupted, e.errorString()); } diff --git a/src/engraving/rw/read114/read114.cpp b/src/engraving/rw/read114/read114.cpp index f14d1cc7773d0..913621290c257 100644 --- a/src/engraving/rw/read114/read114.cpp +++ b/src/engraving/rw/read114/read114.cpp @@ -2722,10 +2722,10 @@ static void readStyle(MStyle* style, XmlReader& e, ReadChordListHook& readChordL // import old version <= 1.3 files //--------------------------------------------------------- -Err Read114::readScore(Score* score, XmlReader& e, ReadInOutData* out) +muse::Ret Read114::readScore(Score* score, XmlReader& e, ReadInOutData* out) { IF_ASSERT_FAILED(score->isMaster()) { - return Err::FileUnknownError; + return make_ret(Err::FileUnknownError); } ReadContext ctx(score); @@ -2915,7 +2915,7 @@ Err Read114::readScore(Score* score, XmlReader& e, ReadInOutData* out) if (e.error() != muse::XmlStreamReader::NoError) { LOGD() << e.lineNumber() << " " << e.columnNumber() << ": " << e.errorString(); - return Err::FileBadFormat; + return make_ret(Err::FileBadFormat, e.errorString()); } for (Staff* s : masterScore->staves()) { @@ -3172,7 +3172,7 @@ Err Read114::readScore(Score* score, XmlReader& e, ReadInOutData* out) score->removeElement(invalidSpanner); } - return Err::NoError; + return muse::make_ok(); } bool Read114::pasteStaff(XmlReader&, Segment*, staff_idx_t, Fraction) diff --git a/src/engraving/rw/read114/read114.h b/src/engraving/rw/read114/read114.h index 40bee7a73a931..823ce00c13495 100644 --- a/src/engraving/rw/read114/read114.h +++ b/src/engraving/rw/read114/read114.h @@ -33,7 +33,7 @@ class Read114 : public rw::IReader // read114 // import old version <= 1.3 files //--------------------------------------------------------- - Err readScore(Score* masterScore, XmlReader& e, rw::ReadInOutData* out) override; + muse::Ret readScore(Score* masterScore, XmlReader& e, rw::ReadInOutData* out) override; bool pasteStaff(XmlReader& e, Segment* dst, staff_idx_t dstStaff, Fraction scale) override; void pasteSymbols(XmlReader& e, ChordRest* dst) override; diff --git a/src/engraving/rw/read206/read206.cpp b/src/engraving/rw/read206/read206.cpp index 382483399d38f..d8aaec4a1af1f 100644 --- a/src/engraving/rw/read206/read206.cpp +++ b/src/engraving/rw/read206/read206.cpp @@ -3413,7 +3413,7 @@ bool Read206::readScore206(Score* score, XmlReader& e, ReadContext& ctx) return true; } -Err Read206::readScore(Score* score, XmlReader& e, ReadInOutData* out) +Ret Read206::readScore(Score* score, XmlReader& e, ReadInOutData* out) { ReadContext ctx(score); if (out && out->overriddenSpatium.has_value()) { @@ -3434,7 +3434,10 @@ Err Read206::readScore(Score* score, XmlReader& e, ReadInOutData* out) score->setMscoreRevision(e.readInt(nullptr, 16)); } else if (tag == "Score") { if (!readScore206(score, e, ctx)) { - return Err::FileBadFormat; + if (e.error() == muse::XmlStreamReader::CustomError) { + return make_ret(Err::FileCriticallyCorrupted, e.errorString()); + } + return make_ret(Err::FileBadFormat, e.errorString()); } if (ctx.overrideSpatium() && out) { @@ -3494,7 +3497,7 @@ Err Read206::readScore(Score* score, XmlReader& e, ReadInOutData* out) compat::CompatUtils::doCompatibilityConversions(score->masterScore()); - return Err::NoError; + return make_ok(); } bool Read206::pasteStaff(XmlReader&, Segment*, staff_idx_t, Fraction) diff --git a/src/engraving/rw/read206/read206.h b/src/engraving/rw/read206/read206.h index dd84832f16d87..ffe2d8dff1172 100644 --- a/src/engraving/rw/read206/read206.h +++ b/src/engraving/rw/read206/read206.h @@ -65,7 +65,7 @@ class Read206 : public rw::IReader // read206 // import old version > 1.3 and < 3.x files //--------------------------------------------------------- - Err readScore(Score* score, XmlReader& e, rw::ReadInOutData* out) override; + muse::Ret readScore(Score* score, XmlReader& e, rw::ReadInOutData* out) override; bool pasteStaff(XmlReader& e, Segment* dst, staff_idx_t dstStaff, Fraction scale) override; void pasteSymbols(XmlReader& e, ChordRest* dst) override; diff --git a/src/engraving/rw/read302/read302.cpp b/src/engraving/rw/read302/read302.cpp index 6672ae48383e3..65bfa786c49aa 100644 --- a/src/engraving/rw/read302/read302.cpp +++ b/src/engraving/rw/read302/read302.cpp @@ -251,7 +251,7 @@ bool Read302::readScore302(Score* score, XmlReader& e, ReadContext& ctx) return true; } -Err Read302::readScore(Score* score, XmlReader& e, ReadInOutData* out) +muse::Ret Read302::readScore(Score* score, XmlReader& e, ReadInOutData* out) { ReadContext ctx(score); if (out && out->overriddenSpatium.has_value()) { @@ -274,9 +274,9 @@ Err Read302::readScore(Score* score, XmlReader& e, ReadInOutData* out) } else if (tag == "Score") { if (!readScore302(score, e, ctx)) { if (e.error() == muse::XmlStreamReader::CustomError) { - return Err::FileCriticallyCorrupted; + return make_ret(Err::FileCriticallyCorrupted, e.errorString()); } - return Err::FileBadFormat; + return make_ret(Err::FileBadFormat, e.errorString()); } if (ctx.overrideSpatium() && out) { @@ -287,7 +287,7 @@ Err Read302::readScore(Score* score, XmlReader& e, ReadInOutData* out) } } - return Err::NoError; + return muse::make_ok(); } void Read302::fixInstrumentId(Instrument* instrument) diff --git a/src/engraving/rw/read302/read302.h b/src/engraving/rw/read302/read302.h index 58f8ce139818c..602caac6fcdb3 100644 --- a/src/engraving/rw/read302/read302.h +++ b/src/engraving/rw/read302/read302.h @@ -46,7 +46,7 @@ class Read302 : public rw::IReader { public: - Err readScore(Score* score, XmlReader& e, rw::ReadInOutData* out) override; + muse::Ret readScore(Score* score, XmlReader& e, rw::ReadInOutData* out) override; bool pasteStaff(XmlReader& e, Segment* dst, staff_idx_t dstStaff, Fraction scale) override; void pasteSymbols(XmlReader& e, ChordRest* dst) override; diff --git a/src/engraving/rw/read400/measurerw.cpp b/src/engraving/rw/read400/measurerw.cpp index 3901cc0aaf4a2..c67ed6bf40a0e 100644 --- a/src/engraving/rw/read400/measurerw.cpp +++ b/src/engraving/rw/read400/measurerw.cpp @@ -86,24 +86,18 @@ void MeasureRead::readMeasure(Measure* measure, XmlReader& e, ReadContext& ctx, measure->m_mstaves.push_back(s); } - bool irregular; + bool irregular = false; if (e.hasAttribute("len")) { - StringList sl = e.attribute("len").split(u'/'); - if (sl.size() == 2) { - measure->m_len = Fraction(sl.at(0).toInt(), sl.at(1).toInt()); - } else { - LOGD("illegal measure size <%s>", muPrintable(e.attribute("len"))); - } - irregular = true; - if (measure->m_len.numerator() <= 0 || measure->m_len.denominator() <= 0 || measure->m_len.denominator() > 128) { - e.raiseError(muse::mtrc("engraving", - "MSCX error at line %1: invalid measure length: %2").arg(e.lineNumber()).arg(measure->m_len.toString())); + bool ok = true; + measure->m_len = Fraction::fromString(e.attribute("len"), &ok); + if (!ok || measure->m_len < Fraction(1, 128)) { + e.raiseError(muse::mtrc("engraving", "MSCX error at line %1: invalid measure length: %2") + .arg(e.lineNumber()).arg(e.attribute("len"))); return; } + irregular = true; ctx.compatTimeSigMap()->add(measure->tick().ticks(), SigEvent(measure->m_len, measure->m_timesig)); ctx.compatTimeSigMap()->add((measure->tick() + measure->ticks()).ticks(), SigEvent(measure->m_timesig)); - } else { - irregular = false; } while (e.readNextStartElement()) { diff --git a/src/engraving/rw/read400/read400.cpp b/src/engraving/rw/read400/read400.cpp index ea9be7f0ceeea..591141bb3c625 100644 --- a/src/engraving/rw/read400/read400.cpp +++ b/src/engraving/rw/read400/read400.cpp @@ -55,7 +55,7 @@ using namespace mu::engraving; using namespace mu::engraving::read400; -Err Read400::readScore(Score* score, XmlReader& e, rw::ReadInOutData* data) +muse::Ret Read400::readScore(Score* score, XmlReader& e, rw::ReadInOutData* data) { ReadContext ctx(score); if (data && data->overriddenSpatium.has_value()) { @@ -83,9 +83,9 @@ Err Read400::readScore(Score* score, XmlReader& e, rw::ReadInOutData* data) } else if (tag == "Score") { if (!readScore400(score, e, ctx)) { if (e.error() == muse::XmlStreamReader::CustomError) { - return Err::FileCriticallyCorrupted; + return make_ret(Err::FileCriticallyCorrupted, e.errorString()); } - return Err::FileBadFormat; + return make_ret(Err::FileBadFormat, e.errorString()); } } else if (tag == "museScore") { // pass @@ -106,7 +106,7 @@ Err Read400::readScore(Score* score, XmlReader& e, rw::ReadInOutData* data) data->settingsCompat = ctx.settingCompat(); } - return Err::NoError; + return muse::make_ok(); } bool Read400::readScore400(Score* score, XmlReader& e, ReadContext& ctx) diff --git a/src/engraving/rw/read400/read400.h b/src/engraving/rw/read400/read400.h index bed6850920b13..9390fd8e292ef 100644 --- a/src/engraving/rw/read400/read400.h +++ b/src/engraving/rw/read400/read400.h @@ -35,7 +35,7 @@ class Read400 : public rw::IReader { public: - Err readScore(Score* score, XmlReader& e, rw::ReadInOutData* data) override; + muse::Ret readScore(Score* score, XmlReader& e, rw::ReadInOutData* data) override; static bool readScore400(Score* score, XmlReader& e, ReadContext& ctx); diff --git a/src/engraving/rw/read410/measureread.cpp b/src/engraving/rw/read410/measureread.cpp index 476991bd924b0..d73240719311a 100644 --- a/src/engraving/rw/read410/measureread.cpp +++ b/src/engraving/rw/read410/measureread.cpp @@ -84,24 +84,18 @@ void MeasureRead::readMeasure(Measure* measure, XmlReader& e, ReadContext& ctx, measure->m_mstaves.push_back(s); } - bool irregular; + bool irregular = false; if (e.hasAttribute("len")) { - StringList sl = e.attribute("len").split(u'/'); - if (sl.size() == 2) { - measure->m_len = Fraction(sl.at(0).toInt(), sl.at(1).toInt()); - } else { - LOGD("illegal measure size <%s>", muPrintable(e.attribute("len"))); - } - irregular = true; - if (measure->m_len.numerator() <= 0 || measure->m_len.denominator() <= 0 || measure->m_len.denominator() > 128) { - e.raiseError(muse::mtrc("engraving", - "MSCX error at line %1: invalid measure length: %2").arg(e.lineNumber()).arg(measure->m_len.toString())); + bool ok = true; + measure->m_len = Fraction::fromString(e.attribute("len"), &ok); + if (!ok || measure->m_len < Fraction(1, 128)) { + e.raiseError(muse::mtrc("engraving", "MSCX error at line %1: invalid measure length: %2") + .arg(e.lineNumber()).arg(e.attribute("len"))); return; } + irregular = true; ctx.compatTimeSigMap()->add(measure->tick().ticks(), SigEvent(measure->m_len, measure->m_timesig)); ctx.compatTimeSigMap()->add((measure->tick() + measure->ticks()).ticks(), SigEvent(measure->m_timesig)); - } else { - irregular = false; } while (e.readNextStartElement()) { diff --git a/src/engraving/rw/read410/read410.cpp b/src/engraving/rw/read410/read410.cpp index 080c4ec06031c..779169ced56f5 100644 --- a/src/engraving/rw/read410/read410.cpp +++ b/src/engraving/rw/read410/read410.cpp @@ -59,7 +59,7 @@ using namespace mu::engraving; using namespace mu::engraving::read410; -Err Read410::readScore(Score* score, XmlReader& e, rw::ReadInOutData* data) +muse::Ret Read410::readScore(Score* score, XmlReader& e, rw::ReadInOutData* data) { ReadContext ctx(score); if (data && data->overriddenSpatium.has_value()) { @@ -89,9 +89,9 @@ Err Read410::readScore(Score* score, XmlReader& e, rw::ReadInOutData* data) } else if (tag == "Score") { if (!readScore410(score, e, ctx)) { if (e.error() == muse::XmlStreamReader::CustomError) { - return Err::FileCriticallyCorrupted; + return make_ret(Err::FileCriticallyCorrupted, e.errorString()); } - return Err::FileBadFormat; + return make_ret(Err::FileBadFormat, e.errorString()); } } else if (tag == "museScore") { // pass @@ -112,7 +112,7 @@ Err Read410::readScore(Score* score, XmlReader& e, rw::ReadInOutData* data) data->settingsCompat = ctx.settingCompat(); } - return Err::NoError; + return muse::make_ok(); } bool Read410::readScore410(Score* score, XmlReader& e, ReadContext& ctx) diff --git a/src/engraving/rw/read410/read410.h b/src/engraving/rw/read410/read410.h index 4164b2b837d96..94f18bf43bb08 100644 --- a/src/engraving/rw/read410/read410.h +++ b/src/engraving/rw/read410/read410.h @@ -35,7 +35,7 @@ class Read410 : public rw::IReader { public: - Err readScore(Score* score, XmlReader& e, rw::ReadInOutData* data) override; + muse::Ret readScore(Score* score, XmlReader& e, rw::ReadInOutData* data) override; static bool readScore410(Score* score, XmlReader& e, ReadContext& ctx); diff --git a/src/engraving/types/fraction.h b/src/engraving/types/fraction.h index 6e407c9cfb3e2..3c7eb652c2a10 100644 --- a/src/engraving/types/fraction.h +++ b/src/engraving/types/fraction.h @@ -258,10 +258,24 @@ class Fraction static constexpr Fraction eps() { return Fraction(1, Constants::DIVISION * 4); } muse::String toString() const { return muse::String(u"%1/%2").arg(m_numerator, m_denominator); } - static Fraction fromString(const muse::String& str) + static Fraction fromString(const muse::String& str, bool* ok = nullptr) { const size_t i = str.indexOf(u'/'); - return (i == muse::nidx) ? Fraction(str.toInt(), 1) : Fraction(str.left(i).toInt(), str.mid(i + 1).toInt()); + if (i == muse::nidx) { + return Fraction(str.toInt(ok), 1); + } + + int numerator = str.left(i).toInt(ok); + if (ok && !*ok) { + return Fraction(); + } + + int denominator = str.mid(i + 1).toInt(ok); + if (ok && !*ok) { + return Fraction(); + } + + return Fraction(numerator, denominator); } constexpr double toDouble() const { return static_cast(m_numerator) / static_cast(m_denominator); } diff --git a/src/framework/global/serialization/xmlstreamreader.cpp b/src/framework/global/serialization/xmlstreamreader.cpp index dafb02b2a9029..5f24fa558d100 100644 --- a/src/framework/global/serialization/xmlstreamreader.cpp +++ b/src/framework/global/serialization/xmlstreamreader.cpp @@ -458,6 +458,10 @@ double XmlStreamReader::readDouble(bool* ok) int64_t XmlStreamReader::lineNumber() const { + if (!m_xml->doc.Error() && m_xml->node) { + return m_xml->node->GetLineNum(); + } + return m_xml->doc.ErrorLineNum(); } diff --git a/src/importexport/midi/tests/testbase.cpp b/src/importexport/midi/tests/testbase.cpp index 8ad1e833f7cc9..1979fbc02fdb5 100644 --- a/src/importexport/midi/tests/testbase.cpp +++ b/src/importexport/midi/tests/testbase.cpp @@ -44,7 +44,7 @@ using namespace mu::engraving; namespace mu::engraving { MasterScore* MTest::readScore(const QString& name) { - QString path = root + "/" + name; + muse::io::path_t path = root + "/" + name; MasterScore* score = compat::ScoreAccess::createMasterScoreWithBaseStyle(nullptr); score->setFileInfoProvider(std::make_shared(path)); std::string suffix = muse::io::suffix(path);