Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

File format: store excerpts by a unique and safe name #20210

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 5 additions & 11 deletions src/engraving/compat/writescorehook.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,18 +60,12 @@ void WriteScoreHook::onWriteExcerpts302(Score* score, XmlWriter& xml, WriteConte
isWriteExcerpts = true;
}

if (isWriteExcerpts) {
if (score->isMaster()) {
if (!selectionOnly) {
MasterScore* mScore = static_cast<MasterScore*>(score);
for (const Excerpt* excerpt : mScore->excerpts()) {
if (excerpt->excerptScore() != score) {
write::Writer::write(excerpt->excerptScore(), xml, ctx, selectionOnly, *this); // recursion write
}
}
if (isWriteExcerpts && score->isMaster() && !selectionOnly) {
MasterScore* mScore = static_cast<MasterScore*>(score);
for (const Excerpt* excerpt : mScore->excerpts()) {
if (excerpt->excerptScore() != score) {
write::Writer::write(excerpt->excerptScore(), xml, ctx, selectionOnly, *this); // recursion write
}
} else {
xml.tag("name", score->excerpt()->name());
}
}
}
62 changes: 59 additions & 3 deletions src/engraving/dom/excerpt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,15 +127,18 @@ const String& Excerpt::name() const
return m_name;
}

void Excerpt::setName(const String& name)
void Excerpt::setName(const String& name, bool saveAndNotify)
{
if (m_name == name) {
return;
}

m_name = name;
writeNameToMetaTags();
m_nameChanged.notify();

if (saveAndNotify) {
writeNameToMetaTags();
m_nameChanged.notify();
}
}

void Excerpt::writeNameToMetaTags()
Expand All @@ -153,6 +156,59 @@ async::Notification Excerpt::nameChanged() const
return m_nameChanged;
}

const String& Excerpt::fileName() const
{
IF_ASSERT_FAILED(!m_fileName.empty()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here it aborts when opening a Mu3 score with parts

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(in Debug builds only)

const_cast<Excerpt*>(this)->updateFileName();
}

return m_fileName;
}

void Excerpt::setFileName(const String& fileName)
{
m_fileName = fileName;
}

static inline bool isValidExcerptFileNameCharacter(char16_t c)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's better to use mu::io::isAllowedFileName / io::path_t mu::io::escapeFileName

{
return (u'a' <= c && c <= u'z')
|| (u'A' <= c && c <= 'Z')
|| (u'0' <= c && c <= '9')
|| c == u'_' || c == u'-' || c == u' ';
}

static inline String escapeExcerptFileName(const String& name)
{
String result;
result.reserve(name.size());

for (const char16_t& c : name.toStdU16String()) {
if (isValidExcerptFileNameCharacter(c)) {
result.append(c);
} else {
result.append(u'_');
}
}

return result;
}

void Excerpt::updateFileName(size_t index)
{
if (index == mu::nidx && m_masterScore) {
index = mu::indexOf(m_masterScore->excerpts(), this);
}

const String escapedName = escapeExcerptFileName(m_name);

if (index == mu::nidx) {
m_fileName = escapedName;
} else {
m_fileName = String(u"%1_%2").arg(String::number(index), escapedName);
}
}

bool Excerpt::containsPart(const Part* part) const
{
for (Part* _part : m_parts) {
Expand Down
12 changes: 9 additions & 3 deletions src/engraving/dom/excerpt.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@
#ifndef MU_ENGRAVING_EXCERPT_H
#define MU_ENGRAVING_EXCERPT_H

#include <map>

#include "types/fraction.h"
#include "types/types.h"
#include "types/string.h"
Expand Down Expand Up @@ -59,9 +57,16 @@ class Excerpt
void setExcerptScore(Score* s);

const String& name() const;
void setName(const String& name);
void setName(const String& name, bool saveAndNotify = true);
async::Notification nameChanged() const;

// The name used to store this excerpt in the msc file/folder.
// When reading/writing, the engraving module sets this value, so that other
// modules can also read/write data about this excerpt using the correct name.
const String& fileName() const;
void setFileName(const String& fileName);
void updateFileName(size_t index = mu::nidx);

std::vector<Part*>& parts() { return m_parts; }
const std::vector<Part*>& parts() const { return m_parts; }
void setParts(const std::vector<Part*>& parts) { m_parts = parts; }
Expand Down Expand Up @@ -99,6 +104,7 @@ class Excerpt
MasterScore* m_masterScore = nullptr;
Score* m_excerptScore = nullptr;
String m_name;
String m_fileName;
async::Notification m_nameChanged;
std::vector<Part*> m_parts;
TracksMap m_tracksMapping;
Expand Down
14 changes: 7 additions & 7 deletions src/engraving/infrastructure/mscreader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ ByteArray MscReader::readScoreFile() const
return fileData(mscxFileName);
}

std::vector<String> MscReader::excerptNames() const
std::vector<String> MscReader::excerptFileNames() const
{
if (!reader()->isContainer()) {
NOT_SUPPORTED << " not container";
Expand All @@ -180,16 +180,16 @@ std::vector<String> MscReader::excerptNames() const
return names;
}

ByteArray MscReader::readExcerptStyleFile(const String& name) const
ByteArray MscReader::readExcerptStyleFile(const String& excerptFileName) const
{
String fileName = name + u".mss";
return fileData(u"Excerpts/" + name + u"/" + fileName);
String fileName = excerptFileName + u".mss";
return fileData(u"Excerpts/" + excerptFileName + u"/" + fileName);
}

ByteArray MscReader::readExcerptFile(const String& name) const
ByteArray MscReader::readExcerptFile(const String& excerptFileName) const
{
String fileName = name + u".mscx";
return fileData(u"Excerpts/" + name + u"/" + fileName);
String fileName = excerptFileName + u".mscx";
return fileData(u"Excerpts/" + excerptFileName + u"/" + fileName);
}

ByteArray MscReader::readChordListFile() const
Expand Down
6 changes: 3 additions & 3 deletions src/engraving/infrastructure/mscreader.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,9 @@ class MscReader
ByteArray readStyleFile() const;
ByteArray readScoreFile() const;

std::vector<String> excerptNames() const;
ByteArray readExcerptStyleFile(const String& name) const;
ByteArray readExcerptFile(const String& name) const;
std::vector<String> excerptFileNames() const;
ByteArray readExcerptStyleFile(const String& excerptFileName) const;
ByteArray readExcerptFile(const String& excerptFileName) const;

ByteArray readChordListFile() const;
ByteArray readThumbnailFile() const;
Expand Down
12 changes: 6 additions & 6 deletions src/engraving/infrastructure/mscwriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -160,16 +160,16 @@ void MscWriter::writeScoreFile(const ByteArray& data)
addFileData(mainFileName(), data);
}

void MscWriter::addExcerptStyleFile(const String& name, const ByteArray& data)
void MscWriter::addExcerptStyleFile(const String& excerptFileName, const ByteArray& data)
{
String fileName = name + u".mss";
addFileData(u"Excerpts/" + name + u"/" + fileName, data);
String fileName = excerptFileName + u".mss";
addFileData(u"Excerpts/" + excerptFileName + u"/" + fileName, data);
}

void MscWriter::addExcerptFile(const String& name, const ByteArray& data)
void MscWriter::addExcerptFile(const String& excerptFileName, const ByteArray& data)
{
String fileName = name + u".mscx";
addFileData(u"Excerpts/" + name + u"/" + fileName, data);
String fileName = excerptFileName + u".mscx";
addFileData(u"Excerpts/" + excerptFileName + u"/" + fileName, data);
}

void MscWriter::writeChordListFile(const ByteArray& data)
Expand Down
4 changes: 2 additions & 2 deletions src/engraving/infrastructure/mscwriter.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ class MscWriter

void writeStyleFile(const ByteArray& data);
void writeScoreFile(const ByteArray& data);
void addExcerptStyleFile(const String& name, const ByteArray& data);
void addExcerptFile(const String& name, const ByteArray& data);
void addExcerptStyleFile(const String& excerptFileName, const ByteArray& data);
void addExcerptFile(const String& excerptFileName, const ByteArray& data);
void writeChordListFile(const ByteArray& data);
void writeThumbnailFile(const ByteArray& data);
void addImageFile(const String& fileName, const ByteArray& data);
Expand Down
23 changes: 17 additions & 6 deletions src/engraving/rw/mscloader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -133,24 +133,25 @@ mu::Ret MscLoader::loadMscz(MasterScore* masterScore, const MscReader& mscReader

// Read excerpts
if (ret && masterScore->mscVersion() >= 400) {
std::vector<String> excerptNames = mscReader.excerptNames();
for (const String& excerptName : excerptNames) {
std::vector<String> excerptFileNames = mscReader.excerptFileNames();
for (const String& excerptFileName : excerptFileNames) {
Score* partScore = masterScore->createScore();

compat::ReadStyleHook::setupDefaultStyle(partScore);

Excerpt* ex = new Excerpt(masterScore);
ex->setExcerptScore(partScore);
ex->setFileName(excerptFileName);

ByteArray excerptStyleData = mscReader.readExcerptStyleFile(excerptName);
ByteArray excerptStyleData = mscReader.readExcerptStyleFile(excerptFileName);
Buffer excerptStyleBuf(&excerptStyleData);
excerptStyleBuf.open(IODevice::ReadOnly);
partScore->style().read(&excerptStyleBuf);

ByteArray excerptData = mscReader.readExcerptFile(excerptName);
ByteArray excerptData = mscReader.readExcerptFile(excerptFileName);

XmlReader xml(excerptData);
xml.setDocName(excerptName);
xml.setDocName(excerptFileName);

ReadInOutData partReadInData;
partReadInData.links = masterReadOutData.links;
Expand All @@ -169,7 +170,17 @@ mu::Ret MscLoader::loadMscz(MasterScore* masterScore, const MscReader& mscReader

partScore->linkMeasures(masterScore);

ex->setName(excerptName);
if (ex->name().empty()) {
// If no excerpt name tag was found while reading, try the "partName" meta tag
const String nameFromMeta = partScore->metaTag(u"partName");

if (nameFromMeta.empty()) {
// If that's also empty, fall back to the filename
ex->setName(excerptFileName, /*saveAndNotify=*/ false);
} else {
ex->setName(nameFromMeta, /*saveAndNotify=*/ false);
}
}

masterScore->addExcerpt(ex);
}
Expand Down
53 changes: 31 additions & 22 deletions src/engraving/rw/mscsaver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@

#include "log.h"

using namespace mu;
using namespace mu::io;
using namespace mu::engraving;
using namespace mu::engraving::rw;
Expand Down Expand Up @@ -72,29 +73,37 @@ bool MscSaver::writeMscz(MasterScore* score, MscWriter& mscWriter, bool onlySele
// Write Excerpts
{
if (!onlySelection) {
for (const Excerpt* excerpt : score->excerpts()) {
const std::vector<Excerpt*>& excerpts = score->excerpts();

for (size_t excerptIndex = 0; excerptIndex < excerpts.size(); ++excerptIndex) {
Excerpt* excerpt = excerpts.at(excerptIndex);

Score* partScore = excerpt->excerptScore();
if (partScore != score) {
// Write excerpt style
{
ByteArray excerptStyleData;
Buffer styleStyleBuf(&excerptStyleData);
styleStyleBuf.open(IODevice::WriteOnly);
partScore->style().write(&styleStyleBuf);

mscWriter.addExcerptStyleFile(excerpt->name(), excerptStyleData);
}

// Write excerpt
{
ByteArray excerptData;
Buffer excerptBuf(&excerptData);
excerptBuf.open(IODevice::ReadWrite);

RWRegister::writer()->writeScore(excerpt->excerptScore(), &excerptBuf, onlySelection, &masterWriteOutData);

mscWriter.addExcerptFile(excerpt->name(), excerptData);
}
IF_ASSERT_FAILED(partScore && partScore != score) {
continue;
}

excerpt->updateFileName(excerptIndex);

// Write excerpt style
{
ByteArray excerptStyleData;
Buffer styleStyleBuf(&excerptStyleData);
styleStyleBuf.open(IODevice::WriteOnly);
partScore->style().write(&styleStyleBuf);

mscWriter.addExcerptStyleFile(excerpt->fileName(), excerptStyleData);
}

// Write excerpt
{
ByteArray excerptData;
Buffer excerptBuf(&excerptData);
excerptBuf.open(IODevice::ReadWrite);

RWRegister::writer()->writeScore(excerpt->excerptScore(), &excerptBuf, onlySelection, &masterWriteOutData);

mscWriter.addExcerptFile(excerpt->fileName(), excerptData);
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/engraving/rw/read206/read206.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3359,7 +3359,7 @@ bool Read206::readScore206(Score* score, XmlReader& e, ReadContext& ctx)
} else if (tag == "name") {
String n = e.readText();
if (!score->isMaster()) { //ignore the name if it's not a child score
score->excerpt()->setName(n);
score->excerpt()->setName(n, /*saveAndNotify=*/ false);
}
} else if (tag == "layoutMode") {
String s = e.readText();
Expand Down
2 changes: 1 addition & 1 deletion src/engraving/rw/read302/read302.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ bool Read302::readScore302(Score* score, XmlReader& e, ReadContext& ctx)
} else if (tag == "name") {
String n = e.readText();
if (!score->isMaster()) { //ignore the name if it's not a child score
score->excerpt()->setName(n);
score->excerpt()->setName(n, /*saveAndNotify=*/ false);
}
} else if (tag == "layoutMode") {
String s = e.readText();
Expand Down
2 changes: 1 addition & 1 deletion src/engraving/rw/read400/read400.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ bool Read400::readScore400(Score* score, XmlReader& e, ReadContext& ctx)
} else if (tag == "name") {
String n = e.readText();
if (!score->isMaster()) { //ignore the name if it's not a child score
score->excerpt()->setName(n);
score->excerpt()->setName(n, /*saveAndNotify=*/ false);
}
} else if (tag == "layoutMode") {
String s = e.readText();
Expand Down
2 changes: 1 addition & 1 deletion src/engraving/rw/read410/read410.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ bool Read410::readScore410(Score* score, XmlReader& e, ReadContext& ctx)
} else if (tag == "name") {
String n = e.readText();
if (!score->isMaster()) { //ignore the name if it's not a child score
score->excerpt()->setName(n);
score->excerpt()->setName(n, /*saveAndNotify=*/ false);
}
} else if (tag == "layoutMode") {
String s = e.readText();
Expand Down
2 changes: 1 addition & 1 deletion src/engraving/rw/read410/tread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1398,7 +1398,7 @@ void TRead::read(Excerpt* item, XmlReader& e, ReadContext&)
while (e.readNextStartElement()) {
const AsciiStringView tag = e.name();
if (tag == "name" || tag == "title") {
item->setName(e.readText().trimmed());
item->setName(e.readText().trimmed(), /*saveAndNotify=*/ false);
} else if (tag == "part") {
size_t partIdx = static_cast<size_t>(e.readInt());
if (partIdx >= pl.size()) {
Expand Down
7 changes: 5 additions & 2 deletions src/engraving/rw/write/writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,11 @@ void Writer::write(Score* score, XmlWriter& xml, WriteContext& ctx, bool selecti

xml.startElement(score);

if (score->excerpt()) {
Excerpt* e = score->excerpt();
if (Excerpt* e = score->excerpt()) {
if (!e->name().empty()) {
xml.tag("name", e->name());
}

const TracksMap& tracks = e->tracksMapping();
if (!(tracks.size() == e->nstaves() * VOICES) && !tracks.empty()) {
for (auto it = tracks.begin(); it != tracks.end(); ++it) {
Expand Down
Loading