From 395f3769cbb16e7ccc85c0830e6bc0b99121bc99 Mon Sep 17 00:00:00 2001 From: Gavin MacGregor Date: Sun, 25 May 2025 12:54:14 +0100 Subject: [PATCH] Separate metadata loading "Metadata" is data which is stored in a teletext file format but is not part of the page itself, such as DE description and CT cycle time in the TTI file format. --- src/qteletextmaker/document.cpp | 34 ++++++++++++ src/qteletextmaker/document.h | 2 + src/qteletextmaker/loadformats.cpp | 84 +++++++++++++++--------------- src/qteletextmaker/loadformats.h | 10 ++-- src/qteletextmaker/mainwindow.cpp | 7 ++- 5 files changed, 89 insertions(+), 48 deletions(-) diff --git a/src/qteletextmaker/document.cpp b/src/qteletextmaker/document.cpp index 5b140d8..3ebaf2e 100644 --- a/src/qteletextmaker/document.cpp +++ b/src/qteletextmaker/document.cpp @@ -19,6 +19,7 @@ #include #include +#include #include "document.h" @@ -200,6 +201,39 @@ void TeletextDocument::unDeleteSubPageFromRecycle(int subPage) m_recycleSubPages.removeLast(); } +void TeletextDocument::loadMetaData(QVariantHash const &metadata) +{ + bool valueOk; + + if (const QString description = metadata.value("description").toString(); !description.isEmpty()) + m_description = description; + + if (const int pageNumber = metadata.value("pageNumber").toInt(&valueOk); valueOk) + m_pageNumber = pageNumber; + + if (metadata.value("fastextAbsolute").toBool()) { + const int magazineFlip = m_pageNumber & 0x700; + + for (auto &subPage : m_subPages) + for (int i=0; i<6; i++) + subPage->setFastTextLinkPageNumber(i, subPage->fastTextLinkPageNumber(i) ^ magazineFlip); + } + + for (int i=0; isetDefaultCharSet(region); + if (int cycleValue = metadata.value("cycleValue" + subPageStr).toInt(&valueOk); valueOk) + subPage(i)->setCycleValue(cycleValue); + QChar cycleType = metadata.value("cycleType" + subPageStr).toChar(); + if (cycleType == 'C') + subPage(i)->setCycleType(LevelOnePage::CTcycles); + else if (cycleType == 'T') + subPage(i)->setCycleType(LevelOnePage::CTseconds); + } +} + void TeletextDocument::setPageNumber(int pageNumber) { // If the magazine number was changed, we need to update the relative magazine numbers in FastText diff --git a/src/qteletextmaker/document.h b/src/qteletextmaker/document.h index 653c938..8b49bd6 100644 --- a/src/qteletextmaker/document.h +++ b/src/qteletextmaker/document.h @@ -24,6 +24,7 @@ #include #include #include +#include #include "levelonepage.h" @@ -74,6 +75,7 @@ public: void deleteSubPage(int subPageToDelete); void deleteSubPageToRecycle(int subPageToRecycle); void unDeleteSubPageFromRecycle(int subPage); + void loadMetaData(QVariantHash const &metadata); int pageNumber() const { return m_pageNumber; } void setPageNumber(int pageNumber); void setPageNumberFromString(QString pageNumberString); diff --git a/src/qteletextmaker/loadformats.cpp b/src/qteletextmaker/loadformats.cpp index 80820be..af25752 100644 --- a/src/qteletextmaker/loadformats.cpp +++ b/src/qteletextmaker/loadformats.cpp @@ -24,24 +24,23 @@ #include #include #include -#include +#include #include "document.h" #include "hamming.h" #include "levelonepage.h" #include "pagebase.h" -bool LoadTTIFormat::load(QFile *inFile, TeletextDocument *document) +bool LoadTTIFormat::load(QFile *inFile, TeletextDocument *document, QVariantHash *metadata) { m_warnings.clear(); m_error.clear(); QByteArray inLine; + int pageNum = 0; + int currentSubPageNum = 0; bool firstSubPageAlreadyFound = false; bool pageBodyPacketsFound = false; - int cycleCommandsFound = 0; - int mostRecentCycleValue = -1; - LevelOnePage::CycleTypeEnum mostRecentCycleType; LevelOnePage* loadingPage = document->subPage(0); @@ -49,17 +48,27 @@ bool LoadTTIFormat::load(QFile *inFile, TeletextDocument *document) inLine = inFile->readLine(160).trimmed(); if (inLine.isEmpty()) break; - if (inLine.startsWith("DE,")) - document->setDescription(QString(inLine.remove(0, 3))); + if (inLine.startsWith("DE,") && metadata != nullptr) + metadata->insert("description", QString(inLine.remove(0, 3))); if (inLine.startsWith("PN,")) { - // When second and subsequent PN commands are found, firstSubPageAlreadyFound==true at this point - // This assumes that PN is the first command of a new subpage... - if (firstSubPageAlreadyFound) { + if (!firstSubPageAlreadyFound) { + // First PN command found, set the page number + bool valueOk; + + if (int pageNumRead = inLine.mid(3, 3).toInt(&valueOk, 16); valueOk) + if (pageNumRead >= 0x100 && pageNumRead <= 0x8ff) { + // Keep page number: to check if page is xFF if we load M/29 + pageNum = pageNumRead; + if (metadata != nullptr) + metadata->insert("pageNumber", pageNum); + } + + firstSubPageAlreadyFound = true; + } else { + // Subsequent PN command found; this assumes that PN is the first command of a new subpage + currentSubPageNum++; document->insertSubPage(document->numberOfSubPages(), false); loadingPage = document->subPage(document->numberOfSubPages()-1); - } else { - document->setPageNumberFromString(inLine.mid(3,3)); - firstSubPageAlreadyFound = true; } } /* if (lineType == "SC,") { @@ -82,37 +91,34 @@ bool LoadTTIFormat::load(QFile *inFile, TeletextDocument *document) if (inLine.startsWith("RE,")) { bool regionValueOk; int regionValueRead = inLine.remove(0, 3).toInt(®ionValueOk); - if (regionValueOk) - loadingPage->setDefaultCharSet(regionValueRead); + if (regionValueOk && metadata != nullptr) + metadata->insert(QString("region%1").arg(currentSubPageNum, 3, QChar('0')), regionValueRead); } if (inLine.startsWith("CT,") && (inLine.endsWith(",C") || inLine.endsWith(",T"))) { bool cycleValueOk; int cycleValueRead = inLine.mid(3, inLine.size()-5).toInt(&cycleValueOk); - if (cycleValueOk) { - cycleCommandsFound++; - // House-keep CT command values, in case it's the only one within multiple subpages - mostRecentCycleValue = cycleValueRead; - loadingPage->setCycleValue(cycleValueRead); - mostRecentCycleType = inLine.endsWith("C") ? LevelOnePage::CTcycles : LevelOnePage::CTseconds; - loadingPage->setCycleType(mostRecentCycleType); + if (cycleValueOk && metadata != nullptr) { + metadata->insert(QString("cycleValue%1").arg(currentSubPageNum, 3, QChar('0')), cycleValueRead); + metadata->insert(QString("cycleType%1").arg(currentSubPageNum, 3, QChar('0')), inLine.at(inLine.size()-1)); } } if (inLine.startsWith("FL,")) { bool fastTextLinkOk; int fastTextLinkRead; QString flLine = QString(inLine.remove(0, 3)); - if (flLine.count(',') == 5) + if (flLine.count(',') == 5) { for (int i=0; i<6; i++) { fastTextLinkRead = flLine.section(',', i, i).toInt(&fastTextLinkOk, 16); if (fastTextLinkOk) { if (fastTextLinkRead == 0) fastTextLinkRead = 0x8ff; - // Stored as page link with relative magazine number, convert from absolute page number that was read - fastTextLinkRead ^= document->pageNumber() & 0x700; - fastTextLinkRead &= 0x7ff; // Fixes magazine 8 to 0 - loadingPage->setFastTextLinkPageNumber(i, fastTextLinkRead); + else if (fastTextLinkRead >= 0x100 && fastTextLinkRead <= 0x8ff) + loadingPage->setFastTextLinkPageNumber(i, fastTextLinkRead); } } + if (metadata != nullptr) + metadata->insert(QString("fastextAbsolute"), true); + } } if (inLine.startsWith("OL,")) { bool lineNumberOk; @@ -162,7 +168,7 @@ bool LoadTTIFormat::load(QFile *inFile, TeletextDocument *document) inLine[i] = inLine.at(i) & 0x3f; // Import M/29 whole-magazine packets as X/28 per-page packets if (lineNumber == 29) { - if ((document->pageNumber() & 0xff) != 0xff) + if ((pageNum & 0xff) != 0xff) m_warnings.append(QString("M/29/%1 packet found, but page number was not xFF.").arg(designationCode)); lineNumber = 28; } @@ -177,14 +183,6 @@ bool LoadTTIFormat::load(QFile *inFile, TeletextDocument *document) return false; } - // If there's more than one subpage but only one valid CT command was found, apply it to all subpages - // I don't know if this is correct - if (cycleCommandsFound == 1 && document->numberOfSubPages()>1) - for (int i=0; inumberOfSubPages(); i++) { - document->subPage(i)->setCycleValue(mostRecentCycleValue); - document->subPage(i)->setCycleType(mostRecentCycleType); - } - return true; } @@ -194,7 +192,7 @@ bool LoadT42Format::readPacket() return m_inFile->read((char *)m_inLine, 42) == 42; } -bool LoadT42Format::load(QFile *inFile, TeletextDocument *document) +bool LoadT42Format::load(QFile *inFile, TeletextDocument *document, QVariantHash *metadata) { int readMagazineNumber, readPacketNumber; int foundMagazineNumber = -1; @@ -259,10 +257,12 @@ bool LoadT42Format::load(QFile *inFile, TeletextDocument *document) foundPageNumber = readPageNumber; firstPacket0Found = true; - if (foundMagazineNumber == 0) - document->setPageNumber(0x800 | foundPageNumber); - else - document->setPageNumber((foundMagazineNumber << 8) | foundPageNumber); + if (metadata != nullptr) { + if (foundMagazineNumber == 0) + metadata->insert("pageNumber", 0x800 | foundPageNumber); + else + metadata->insert("pageNumber", (foundMagazineNumber << 8) | foundPageNumber); + } document->subPage(0)->setControlBit(PageBase::C4ErasePage, m_inLine[5] & 0x08); document->subPage(0)->setControlBit(PageBase::C5Newsflash, m_inLine[7] & 0x04); @@ -435,7 +435,7 @@ bool LoadHTTFormat::readPacket() } -bool LoadEP1Format::load(QFile *inFile, TeletextDocument *document) +bool LoadEP1Format::load(QFile *inFile, TeletextDocument *document, QVariantHash *metadata) { m_warnings.clear(); m_error.clear(); diff --git a/src/qteletextmaker/loadformats.h b/src/qteletextmaker/loadformats.h index 318db04..0bb2a62 100644 --- a/src/qteletextmaker/loadformats.h +++ b/src/qteletextmaker/loadformats.h @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include "document.h" #include "levelonepage.h" @@ -36,7 +36,7 @@ class LoadFormat public: virtual ~LoadFormat() {}; - virtual bool load(QFile *inFile, TeletextDocument *document) =0; + virtual bool load(QFile *inFile, TeletextDocument *document, QVariantHash *metadata = nullptr) =0; virtual QString description() const =0; virtual QStringList extensions() const =0; @@ -55,7 +55,7 @@ protected: class LoadTTIFormat : public LoadFormat { public: - bool load(QFile *inFile, TeletextDocument *document) override; + bool load(QFile *inFile, TeletextDocument *document, QVariantHash *metadata = nullptr) override; QString description() const override { return QString("MRG Systems TTI"); }; QStringList extensions() const override { return QStringList { "tti", "ttix" }; }; @@ -64,7 +64,7 @@ public: class LoadT42Format : public LoadFormat { public: - bool load(QFile *inFile, TeletextDocument *document) override; + bool load(QFile *inFile, TeletextDocument *document, QVariantHash *metadata = nullptr) override; QString description() const override { return QString("t42 packet stream"); }; QStringList extensions() const override { return QStringList { "t42" }; }; @@ -89,7 +89,7 @@ protected: class LoadEP1Format : public LoadFormat { public: - bool load(QFile *inFile, TeletextDocument *document) override; + bool load(QFile *inFile, TeletextDocument *document, QVariantHash *metadata = nullptr) override; QString description() const override { return QString("Softel EP1"); }; QStringList extensions() const override { return QStringList { "ep1", "epx" }; }; diff --git a/src/qteletextmaker/mainwindow.cpp b/src/qteletextmaker/mainwindow.cpp index 9036047..0fef08c 100644 --- a/src/qteletextmaker/mainwindow.cpp +++ b/src/qteletextmaker/mainwindow.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include "mainwindow.h" @@ -1068,7 +1069,11 @@ void MainWindow::loadFile(const QString &fileName) QApplication::setOverrideCursor(Qt::WaitCursor); - if (loadingFormat->load(&file, m_textWidget->document())) { + QVariantHash metadata; + + if (loadingFormat->load(&file, m_textWidget->document(), &metadata)) { + m_textWidget->document()->loadMetaData(metadata); + if (m_saveFormats.isExportOnly(QFileInfo(file).suffix())) m_exportAutoFileName = fileName; else