Skip to content
Open
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
105 changes: 86 additions & 19 deletions src/importexport/tabledit/internal/importtef.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
#include "engraving/dom/text.h"
#include "engraving/dom/timesig.h"
#include "engraving/dom/volta.h"
#include "io/file.h"
#include "log.h"

using namespace mu::engraving;
Expand Down Expand Up @@ -1445,8 +1446,26 @@ void TablEdit::readTefTexts()
}
}

void TablEdit::readTefHeader()
//---------------------------------------------------------
// readTefHeader - read the header of a TablEdit format v3 file
// preconditions:
// - file has been opened and is readable
// - file size is at least the header size
// - file has correct v3 wFormat and signature
// first check if the file is protected (meaning import is not allowed)
// in that case, immediately return with FileBadFormat
//---------------------------------------------------------

mu::engraving::Err TablEdit::readTefHeader()
{
_file->seek(OFFSET_SECURITYCODE);
tefHeader.securityCode = readUInt32();
tefHeader.securityFlags = readUInt32();
if (tefHeader.securityCode != 0) {
_errorMessage = muse::mtrc("iex_tabledit", "The file is protected.");
return Err::FileBadFormat;
}
_file->seek(0);
readUInt16(); // skip private01
tefHeader.version = readUInt16();
tefHeader.subVersion = readUInt16();
Expand All @@ -1455,8 +1474,6 @@ void TablEdit::readTefHeader()
tefHeader.reverb = readUInt16();
readUInt16(); // todo syncope (is signed)
readUInt16(); // skip private02
tefHeader.securityCode = readUInt32();
tefHeader.securityFlags = readUInt32();
_file->seek(OFFSET_TBED);
tefHeader.tbed = readUInt32();
readUInt32(); // skip contents
Expand All @@ -1472,39 +1489,89 @@ void TablEdit::readTefHeader()
_file->seek(OFFSET_OLDNUM);
tefHeader.wOldNum = readUInt16();
tefHeader.wFormat = readUInt16();
return Err::NoError;
}

uint32_t TablEdit::readSignature()
{
_file->seek(OFFSET_TBED);
return readUInt32();
}

uint16_t TablEdit::readWFormat()
{
_file->seek(OFFSET_WFORMAT);
return readUInt16();
}

//---------------------------------------------------------
// import
//
// see src/importexport/guitarpro/internal/importgtp.cpp createLinkedTabs()
// for linked staves
//---------------------------------------------------------

Err TablEdit::import()
Err TablEdit::import(const muse::io::path_t& path)
{
readTefHeader();
muse::io::File tefFile(path);
if (!tefFile.exists()) {
LOGN("file '%s' not found", path.toStdString().c_str());
return Err::FileNotFound;
}

if (!tefFile.open(muse::io::IODevice::ReadOnly)) {
LOGN("file '%s' not accessible", path.toStdString().c_str());
return Err::FileOpenError;
}

// do checks to verify this is a file type and version we can handle
const size_t fileSize { tefFile.size() };
if (fileSize < HEADER_SIZE) {
// a TablEdit file cannot be smaller than HEADER_SIZE
_errorMessage = muse::mtrc("iex_tabledit", "The file size is too small (%1 bytes).").arg(fileSize);
return Err::FileBadFormat;
}

_file = &tefFile; // all TablEdit's file handling functions depend on _file

const int wFormatHiByte { readWFormat() >> 8 };
if (wFormatHiByte < 10) {
_errorMessage = muse::mtrc("iex_tabledit", "The file is in an older TablEdit format (version %1)."
" The importer does not support this version.").arg(wFormatHiByte);
return Err::FileBadFormat;
}
if (wFormatHiByte > 10) {
_errorMessage = muse::mtrc("iex_tabledit", "The file is in a newer TablEdit format (version %1)."
" The importer does not support this version.").arg(wFormatHiByte);
return Err::FileBadFormat;
}

// Format v10 files contain either "debt" or "tbed" in ASCII as signature, imported as a 32-bit integer
const int64_t actualSignature { readSignature() }; // String::arg() does not support uit32_t
const int signature1 { 0x64656274 };
const int signature2 { 0x74626564 };
if (actualSignature != signature1 && actualSignature != signature2) {
_errorMessage = muse::mtrc("iex_tabledit", "The file signature is incorrect (%1).").arg(actualSignature);
return Err::FileBadFormat;
}

// do actual import
const Err err { readTefHeader() };
if (err == Err::FileBadFormat) {
_errorMessage = muse::mtrc("iex_tabledit", "The file is protected.");
return err;
} else if (err != Err::NoError) {
_errorMessage = muse::mtrc("iex_tabledit", "Unexpected error reading header.");
return err;
}
LOGN("version %d subversion %d", tefHeader.version, tefHeader.subVersion);
LOGN("tempo %d chorus %d reverb %d", tefHeader.tempo, tefHeader.chorus, tefHeader.reverb);
LOGN("securityCode %d securityFlags %d", tefHeader.securityCode, tefHeader.securityFlags);
LOGN("tbed %d", tefHeader.tbed);
LOGN("title '%s'", tefHeader.title.c_str());
LOGN("subTitle '%s'", tefHeader.subTitle.c_str());
LOGN("comment '%s'", tefHeader.comment.c_str());
LOGN("notes '%s'", tefHeader.notes.c_str());
LOGN("internetLink '%s'", tefHeader.internetLink.c_str());
LOGN("copyright '%s'", tefHeader.copyright.c_str());
LOGN("tbed %d wOldNum %d wFormat %d", tefHeader.tbed, tefHeader.wOldNum, tefHeader.wFormat);
if ((tefHeader.wFormat >> 8) < 10) {
return Err::FileBadFormat;
//return Err::FileTooOld; // TODO: message is too specific for MuseScore format
}
if ((tefHeader.wFormat >> 8) > 10) {
return Err::FileBadFormat;
//return Err::FileTooNew;
}
if (tefHeader.securityCode != 0) {
return Err::FileBadFormat; // todo "file is protected" message ?
}
readTefTexts();
for (const auto& text : tefTexts) {
LOGN("text: '%s'", text.c_str());
Expand Down
17 changes: 13 additions & 4 deletions src/importexport/tabledit/internal/importtef.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,11 @@
namespace mu::iex::tabledit {
class MeasureHandler;

// header size
static const size_t HEADER_SIZE = 256;

// offsets into the file header
static const uint8_t OFFSET_SECURITYCODE = 0x10;
static const uint8_t OFFSET_TBED = 0x38;
static const uint8_t OFFSET_CONTENTS = 0x3C;
static const uint8_t OFFSET_TITLE = 0x40;
Expand All @@ -49,6 +53,7 @@ static const uint8_t OFFSET_READINGLIST = 0x80;
static const uint8_t OFFSET_INTERNETLINK = 0x84;
static const uint8_t OFFSET_COPYRIGHT = 0x8C;
static const uint8_t OFFSET_OLDNUM = 0xCA;
static const uint8_t OFFSET_WFORMAT = 0xCC;

struct TefMeasure {
int flag { 0 };
Expand All @@ -67,6 +72,7 @@ struct TefReadingListItem {

class TablEdit
{
muse::String _errorMessage;
muse::io::IODevice* _file = nullptr;
mu::engraving::MasterScore* score = nullptr;

Expand Down Expand Up @@ -138,12 +144,14 @@ class TablEdit
void initializeVoiceAllocators(std::vector<VoiceAllocator>& allocators);
engraving::part_idx_t partIdx(size_t stringIdx, bool& ok) const;
int stringNumberPreviousParts(engraving::part_idx_t partIdx) const;
uint32_t readSignature();
void readTefContents();
void readTefHeader();
mu::engraving::Err readTefHeader();
void readTefInstruments();
void readTefMeasures();
void readTefReadingList();
void readTefTexts();
uint16_t readWFormat();

TefHeader tefHeader;
std::vector<TefTextMarker> tefTextMarkers;
Expand All @@ -156,8 +164,9 @@ class TablEdit
std::map<const TefNote* const, mu::engraving::Note*> effectMap;

public:
TablEdit(muse::io::IODevice* f, mu::engraving::MasterScore* s)
: _file(f), score(s) {}
mu::engraving::Err import();
TablEdit(mu::engraving::MasterScore* s)
: score(s) {}
mu::engraving::Err import(const muse::io::path_t& path);
muse::String errorMessage() { return _errorMessage; }
};
} // namespace mu::iex::tabledit
21 changes: 9 additions & 12 deletions src/importexport/tabledit/internal/tableditreader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@

#include "engraving/dom/score.h"
#include "engraving/engravingerrors.h"
#include "io/file.h"

#include "importtef.h"
#include "tableditreader.h"
Expand All @@ -32,22 +31,20 @@ using namespace mu::engraving;

muse::Ret TablEditReader::read(MasterScore* score, const muse::io::path_t& path, const Options&)
{
Err err = import(score, path);
TablEdit tablEdit{ score };
Err err = tablEdit.import(path);
if (err == Err::FileBadFormat) {
// Give a specific reason instead of the generic "Bad format" text.
return make_ret(err, tablEdit.errorMessage());
}

return make_ret(err, path);
}

Err TablEditReader::import(MasterScore* score, const muse::io::path_t& path, const Options&)
{
if (!fileSystem()->exists(path)) {
return Err::FileNotFound;
}

muse::io::File file(path);
if (!file.open(muse::io::IODevice::ReadOnly)) {
return Err::FileOpenError;
}
TablEdit tablEdit{ &file, score };
Err err = tablEdit.import();
TablEdit tablEdit{ score };
Err err = tablEdit.import(path);

return err;
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
148 changes: 148 additions & 0 deletions src/importexport/tabledit/tests/data/header_signature_1.mscx
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
<?xml version="1.0" encoding="UTF-8"?>
<museScore version="5.00">
<Score>
<eid>B_B</eid>
<Division>480</Division>
<Style>
<spatium>1.75</spatium>
</Style>
<showInvisible>1</showInvisible>
<showUnprintable>1</showUnprintable>
<showFrames>1</showFrames>
<showMargins>0</showMargins>
<metaTag name="arranger"></metaTag>
<metaTag name="comment">TablEdited by </metaTag>
<metaTag name="composer"></metaTag>
<metaTag name="copyright"></metaTag>
<metaTag name="lyricist"></metaTag>
<metaTag name="movementNumber"></metaTag>
<metaTag name="movementTitle"></metaTag>
<metaTag name="originalFormat">tef</metaTag>
<metaTag name="source"></metaTag>
<metaTag name="translator"></metaTag>
<metaTag name="workNumber"></metaTag>
<metaTag name="workTitle"></metaTag>
<Part id="1">
<eid>C_C</eid>
<Staff>
<eid>D_D</eid>
<StaffType group="pitched">
<name>stdNormal</name>
</StaffType>
<defaultClef>G8vb</defaultClef>
</Staff>
<Staff>
<eid>E_E</eid>
<linkedTo>D_D</linkedTo>
<StaffType group="tablature">
<name>tab6StrSimple</name>
<lines>6</lines>
<lineDistance>1.5</lineDistance>
<stemless>1</stemless>
<timesig>0</timesig>
<durations>0</durations>
<durationFontName>MuseScore Tab Modern</durationFontName>
<durationFontSize>15</durationFontSize>
<durationFontY>0</durationFontY>
<fretUseTextStyle>1</fretUseTextStyle>
<fretTextStyle>tab_fret_number</fretTextStyle>
<linesThrough>0</linesThrough>
<minimStyle>0</minimStyle>
<onLines>1</onLines>
<showRests>0</showRests>
<stemsDown>1</stemsDown>
<stemsThrough>0</stemsThrough>
<upsideDown>0</upsideDown>
<useNumbers>1</useNumbers>
</StaffType>
</Staff>
<Instrument id="cavaquinho">
<InstrumentLabel>
<longName>Guitar Standard</longName>
</InstrumentLabel>
<trackName></trackName>
<instrumentId>pluck.guitar</instrumentId>
<StringData>
<frets>25</frets>
<string>38</string>
<string>45</string>
<string>50</string>
<string>55</string>
<string>59</string>
<string>64</string>
</StringData>
<Channel>
<program value="24"/>
</Channel>
</Instrument>
</Part>
<Staff id="1">
<VBox>
<height>10</height>
<eid>F_F</eid>
</VBox>
<Measure>
<eid>G_G</eid>
<voice>
<KeySig>
<eid>H_H</eid>
<concertKey>0</concertKey>
</KeySig>
<TimeSig>
<eid>I_I</eid>
<sigN>4</sigN>
<sigD>4</sigD>
</TimeSig>
<Tempo>
<tempo>2</tempo>
<followText>1</followText>
<eid>J_J</eid>
<text><sym>metNoteQuarterUp</sym> = 120</text>
</Tempo>
<Chord>
<eid>K_K</eid>
<durationType>whole</durationType>
<Note>
<eid>L_L</eid>
<pitch>48</pitch>
<tpc>14</tpc>
<fret>3</fret>
<string>4</string>
</Note>
</Chord>
<BarLine>
<eid>M_M</eid>
</BarLine>
</voice>
</Measure>
</Staff>
<Staff id="2">
<Measure>
<voice>
<KeySig>
<eid>N_N</eid>
<linkedTo>H_H</linkedTo>
<concertKey>0</concertKey>
</KeySig>
<Chord>
<eid>O_O</eid>
<linkedTo>K_K</linkedTo>
<durationType>whole</durationType>
<Note>
<eid>P_P</eid>
<linkedTo>L_L</linkedTo>
<pitch>48</pitch>
<tpc>14</tpc>
<fret>3</fret>
<string>4</string>
</Note>
</Chord>
<BarLine>
<eid>Q_Q</eid>
<linkedTo>M_M</linkedTo>
</BarLine>
</voice>
</Measure>
</Staff>
</Score>
</museScore>
Binary file not shown.
Loading
Loading