From 73d597a765aac9b2f4ee7f7ef465e9cabda649eb Mon Sep 17 00:00:00 2001 From: ChristianFeldmann Date: Sun, 1 Dec 2024 21:35:53 +0100 Subject: [PATCH 1/7] Move dataSource to new folder --- .../src/{filesource => dataSource}/DataSourceLocalFile.cpp | 0 YUViewLib/src/{filesource => dataSource}/DataSourceLocalFile.h | 0 YUViewLib/src/{filesource => dataSource}/IDataSource.h | 0 .../{filesource => dataSource}/DataSourceLocalFileTest.cpp | 2 +- 4 files changed, 1 insertion(+), 1 deletion(-) rename YUViewLib/src/{filesource => dataSource}/DataSourceLocalFile.cpp (100%) rename YUViewLib/src/{filesource => dataSource}/DataSourceLocalFile.h (100%) rename YUViewLib/src/{filesource => dataSource}/IDataSource.h (100%) rename YUViewUnitTest/{filesource => dataSource}/DataSourceLocalFileTest.cpp (99%) diff --git a/YUViewLib/src/filesource/DataSourceLocalFile.cpp b/YUViewLib/src/dataSource/DataSourceLocalFile.cpp similarity index 100% rename from YUViewLib/src/filesource/DataSourceLocalFile.cpp rename to YUViewLib/src/dataSource/DataSourceLocalFile.cpp diff --git a/YUViewLib/src/filesource/DataSourceLocalFile.h b/YUViewLib/src/dataSource/DataSourceLocalFile.h similarity index 100% rename from YUViewLib/src/filesource/DataSourceLocalFile.h rename to YUViewLib/src/dataSource/DataSourceLocalFile.h diff --git a/YUViewLib/src/filesource/IDataSource.h b/YUViewLib/src/dataSource/IDataSource.h similarity index 100% rename from YUViewLib/src/filesource/IDataSource.h rename to YUViewLib/src/dataSource/IDataSource.h diff --git a/YUViewUnitTest/filesource/DataSourceLocalFileTest.cpp b/YUViewUnitTest/dataSource/DataSourceLocalFileTest.cpp similarity index 99% rename from YUViewUnitTest/filesource/DataSourceLocalFileTest.cpp rename to YUViewUnitTest/dataSource/DataSourceLocalFileTest.cpp index c37f81a73..274bafcb9 100644 --- a/YUViewUnitTest/filesource/DataSourceLocalFileTest.cpp +++ b/YUViewUnitTest/dataSource/DataSourceLocalFileTest.cpp @@ -33,7 +33,7 @@ #include #include -#include +#include namespace { From b4beec91b1153cfa00bae9241e9f1e78f7382944 Mon Sep 17 00:00:00 2001 From: ChristianFeldmann Date: Sun, 1 Dec 2024 21:52:37 +0100 Subject: [PATCH 2/7] Update namespace --- YUViewLib/src/dataSource/DataSourceLocalFile.cpp | 4 ++-- YUViewLib/src/dataSource/DataSourceLocalFile.h | 4 ++-- YUViewLib/src/dataSource/IDataSource.h | 4 ++-- .../dataSource/DataSourceLocalFileTest.cpp | 14 +++++++------- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/YUViewLib/src/dataSource/DataSourceLocalFile.cpp b/YUViewLib/src/dataSource/DataSourceLocalFile.cpp index 889130f89..9cd3b04bd 100644 --- a/YUViewLib/src/dataSource/DataSourceLocalFile.cpp +++ b/YUViewLib/src/dataSource/DataSourceLocalFile.cpp @@ -32,7 +32,7 @@ #include "DataSourceLocalFile.h" -namespace filesource +namespace datasource { DataSourceLocalFile::DataSourceLocalFile(const std::filesystem::path &filePath) @@ -117,4 +117,4 @@ std::optional DataSourceLocalFile::fileSize() const return this->path; } -} // namespace filesource +} // namespace datasource diff --git a/YUViewLib/src/dataSource/DataSourceLocalFile.h b/YUViewLib/src/dataSource/DataSourceLocalFile.h index f7db45ff8..baec7d4d4 100644 --- a/YUViewLib/src/dataSource/DataSourceLocalFile.h +++ b/YUViewLib/src/dataSource/DataSourceLocalFile.h @@ -37,7 +37,7 @@ #include #include -namespace filesource +namespace datasource { class DataSourceLocalFile : public IDataSource @@ -64,4 +64,4 @@ class DataSourceLocalFile : public IDataSource std::int64_t filePosition{}; }; -} // namespace filesource +} // namespace datasource diff --git a/YUViewLib/src/dataSource/IDataSource.h b/YUViewLib/src/dataSource/IDataSource.h index 68cbcb094..b1d4b99ae 100644 --- a/YUViewLib/src/dataSource/IDataSource.h +++ b/YUViewLib/src/dataSource/IDataSource.h @@ -35,7 +35,7 @@ #include #include -namespace filesource +namespace datasource { /* The data source interface defines a something that can provide data. @@ -56,4 +56,4 @@ class IDataSource [[nodiscard]] virtual std::int64_t read(ByteVector &buffer, const std::int64_t nrBytes) = 0; }; -} // namespace filesource +} // namespace datasource diff --git a/YUViewUnitTest/dataSource/DataSourceLocalFileTest.cpp b/YUViewUnitTest/dataSource/DataSourceLocalFileTest.cpp index 274bafcb9..c6075e166 100644 --- a/YUViewUnitTest/dataSource/DataSourceLocalFileTest.cpp +++ b/YUViewUnitTest/dataSource/DataSourceLocalFileTest.cpp @@ -35,7 +35,7 @@ #include #include -namespace +namespace datasource::test { using namespace std::literals; @@ -44,7 +44,7 @@ const ByteVector DUMMY_DATA = {'t', 'e', 's', 't', 'd', 'a', 't', 'a'}; TEST(DataSourceLocalFileTest, OpenFileThatDoesNotExist) { - filesource::DataSourceLocalFile file("/path/to/file/that/does/not/exist"); + DataSourceLocalFile file("/path/to/file/that/does/not/exist"); EXPECT_FALSE(file.isOk()); EXPECT_FALSE(file); EXPECT_TRUE(file.filePath().empty()); @@ -63,7 +63,7 @@ TEST(DataSourceLocalFileTest, OpenFileThatExists_TestRetrievalOfFileInfo) { yuviewTest::TemporaryFile tempFile(DUMMY_DATA); - filesource::DataSourceLocalFile file(tempFile.getFilePath()); + DataSourceLocalFile file(tempFile.getFilePath()); EXPECT_TRUE(file); EXPECT_EQ(file.fileSize().value(), 8); @@ -80,7 +80,7 @@ TEST(DataSourceLocalFileTest, OpenFileThatExists_TestReadingOfData) { yuviewTest::TemporaryFile tempFile(DUMMY_DATA); - filesource::DataSourceLocalFile file(tempFile.getFilePath()); + DataSourceLocalFile file(tempFile.getFilePath()); EXPECT_TRUE(file.isOk()); EXPECT_TRUE(file); @@ -105,7 +105,7 @@ TEST(DataSourceLocalFileTest, OpenFileThatExists_TestSeekingBeforeReading) { yuviewTest::TemporaryFile tempFile(DUMMY_DATA); - filesource::DataSourceLocalFile file(tempFile.getFilePath()); + DataSourceLocalFile file(tempFile.getFilePath()); EXPECT_TRUE(file); EXPECT_TRUE(file.seek(4)); @@ -126,7 +126,7 @@ TEST(DataSourceLocalFileTest, OpenFileThatExists_TestSeekingFromEOF) yuviewTest::TemporaryFile tempFile(DUMMY_DATA); ByteVector buffer; - filesource::DataSourceLocalFile file(tempFile.getFilePath()); + DataSourceLocalFile file(tempFile.getFilePath()); EXPECT_TRUE(file); EXPECT_EQ(file.read(buffer, 100), 8); @@ -147,4 +147,4 @@ TEST(DataSourceLocalFileTest, OpenFileThatExists_TestSeekingFromEOF) EXPECT_FALSE(file.atEnd()); } -} // namespace +} // namespace datasource::test From b56de38ae4b8ee4b6626feaaa2d43759c7949902 Mon Sep 17 00:00:00 2001 From: ChristianFeldmann Date: Sun, 1 Dec 2024 22:03:57 +0100 Subject: [PATCH 3/7] Remove getAbsPathFromAbsAndRel from FileSource --- YUViewLib/src/common/Functions.cpp | 25 +++++++++++++++++++ YUViewLib/src/common/Functions.h | 7 ++++-- YUViewLib/src/filesource/FileSource.cpp | 23 ----------------- YUViewLib/src/filesource/FileSource.h | 4 --- .../playlistItemCompressedVideo.cpp | 4 +-- .../playlistitem/playlistItemImageFile.cpp | 4 ++- .../playlistItemImageFileSequence.cpp | 5 ++-- .../src/playlistitem/playlistItemRawFile.cpp | 3 ++- .../playlistItemStatisticsFile.cpp | 3 ++- 9 files changed, 42 insertions(+), 36 deletions(-) diff --git a/YUViewLib/src/common/Functions.cpp b/YUViewLib/src/common/Functions.cpp index 47ce90f0c..584450a3e 100644 --- a/YUViewLib/src/common/Functions.cpp +++ b/YUViewLib/src/common/Functions.cpp @@ -45,6 +45,8 @@ #include #include +#include +#include #include namespace functions @@ -120,6 +122,29 @@ QStringList getThemeColors(QString themeName) return QStringList(); } +// If you are loading a playlist and you have an absolute path and a relative path, this function +// will return the absolute path (if a file with that absolute path exists) or convert the relative +// path to an absolute one and return that (if that file exists). If neither exists the empty string +// is returned. +QString getAbsPathFromAbsAndRel(const QString ¤tPath, + const QString &absolutePath, + const QString &relativePath) +{ + QFileInfo checkAbsoluteFile(absolutePath); + if (checkAbsoluteFile.exists()) + return absolutePath; + + QFileInfo plFileInfo(currentPath); + auto combinePath = QDir(plFileInfo.path()).filePath(relativePath); + QFileInfo checkRelativeFile(combinePath); + if (checkRelativeFile.exists() && checkRelativeFile.isFile()) + { + return QDir::cleanPath(combinePath); + } + + return {}; +} + QString formatDataSize(double size, bool isBits) { unsigned divCounter = 0; diff --git a/YUViewLib/src/common/Functions.h b/YUViewLib/src/common/Functions.h index 33a115d6a..ee652fa32 100644 --- a/YUViewLib/src/common/Functions.h +++ b/YUViewLib/src/common/Functions.h @@ -58,6 +58,10 @@ QString getThemeFileName(QString themeName); // The values to replace them by are returned in this order. QStringList getThemeColors(QString themeName); +QString getAbsPathFromAbsAndRel(const QString ¤tPath, + const QString &absolutePath, + const QString &relativePath); + // Format the data size as a huma readable string. If isBits is set, assumes bits, oterwise bytes. // From Qt 5.10 there is a built in function (QLocale::formattedDataSize). But we want to be 5.9 // compatible. @@ -65,8 +69,7 @@ QString formatDataSize(double size, bool isBits = false); QStringList toQStringList(const std::vector &stringVec); -template -QStringList toQStringList(const std::array &stringArray) +template QStringList toQStringList(const std::array &stringArray) { QStringList list; for (const auto &s : stringArray) diff --git a/YUViewLib/src/filesource/FileSource.cpp b/YUViewLib/src/filesource/FileSource.cpp index dc3a2b8e1..ecc5df6ae 100644 --- a/YUViewLib/src/filesource/FileSource.cpp +++ b/YUViewLib/src/filesource/FileSource.cpp @@ -159,29 +159,6 @@ std::string FileSource::getAbsoluteFilePath() const return this->isFileOpened ? this->fullFilePath.string() : ""; } -// If you are loading a playlist and you have an absolute path and a relative path, this function -// will return the absolute path (if a file with that absolute path exists) or convert the relative -// path to an absolute one and return that (if that file exists). If neither exists the empty string -// is returned. -QString FileSource::getAbsPathFromAbsAndRel(const QString ¤tPath, - const QString &absolutePath, - const QString &relativePath) -{ - QFileInfo checkAbsoluteFile(absolutePath); - if (checkAbsoluteFile.exists()) - return absolutePath; - - QFileInfo plFileInfo(currentPath); - auto combinePath = QDir(plFileInfo.path()).filePath(relativePath); - QFileInfo checkRelativeFile(combinePath); - if (checkRelativeFile.exists() && checkRelativeFile.isFile()) - { - return QDir::cleanPath(combinePath); - } - - return {}; -} - bool FileSource::getAndResetFileChangedFlag() { bool b = this->fileChanged; diff --git a/YUViewLib/src/filesource/FileSource.h b/YUViewLib/src/filesource/FileSource.h index cf4efe89b..0a3e77d99 100644 --- a/YUViewLib/src/filesource/FileSource.h +++ b/YUViewLib/src/filesource/FileSource.h @@ -97,10 +97,6 @@ class FileSource : public QObject void readBytes(byteArrayAligned &data, int64_t startPos, int64_t nrBytes); #endif - static QString getAbsPathFromAbsAndRel(const QString ¤tPath, - const QString &absolutePath, - const QString &relativePath); - void updateFileWatchSetting(); void clearFileCache(); diff --git a/YUViewLib/src/playlistitem/playlistItemCompressedVideo.cpp b/YUViewLib/src/playlistitem/playlistItemCompressedVideo.cpp index 6d7a93754..0604fe53c 100644 --- a/YUViewLib/src/playlistitem/playlistItemCompressedVideo.cpp +++ b/YUViewLib/src/playlistitem/playlistItemCompressedVideo.cpp @@ -143,7 +143,7 @@ playlistItemCompressedVideo::playlistItemCompressedVideo(const QString &compress { // Open file DEBUG_COMPRESSED("playlistItemCompressedVideo::playlistItemCompressedVideo Open annexB file"); - const auto filePath = std::filesystem::path(compressedFilePath.toStdString()); + const auto filePath = std::filesystem::path(compressedFilePath.toStdString()); this->inputFileAnnexBLoading = std::make_unique(filePath); if (this->cachingEnabled) this->inputFileAnnexBCaching = std::make_unique(filePath); @@ -430,7 +430,7 @@ playlistItemCompressedVideo::newPlaylistItemCompressedVideo(const YUViewDomEleme int displaySignal = root.findChildValue("displayComponent").toInt(); // check if file with absolute path exists, otherwise check relative path - auto filePath = FileSource::getAbsPathFromAbsAndRel(playlistFilePath, absolutePath, relativePath); + const auto filePath = getAbsPathFromAbsAndRel(playlistFilePath, absolutePath, relativePath); if (filePath.isEmpty()) return nullptr; diff --git a/YUViewLib/src/playlistitem/playlistItemImageFile.cpp b/YUViewLib/src/playlistitem/playlistItemImageFile.cpp index fa2e8491b..5cc4794d0 100644 --- a/YUViewLib/src/playlistitem/playlistItemImageFile.cpp +++ b/YUViewLib/src/playlistitem/playlistItemImageFile.cpp @@ -38,6 +38,7 @@ #include #include +#include #include #include @@ -109,7 +110,8 @@ playlistItemImageFile::newplaylistItemImageFile(const YUViewDomElement &root, auto relativePath = root.findChildValue("relativePath"); // check if file with absolute path exists, otherwise check relative path - auto filePath = FileSource::getAbsPathFromAbsAndRel(playlistFilePath, absolutePath, relativePath); + const auto filePath = + functions::getAbsPathFromAbsAndRel(playlistFilePath, absolutePath, relativePath); if (filePath.isEmpty()) return nullptr; diff --git a/YUViewLib/src/playlistitem/playlistItemImageFileSequence.cpp b/YUViewLib/src/playlistitem/playlistItemImageFileSequence.cpp index b5491e98d..9712bc881 100644 --- a/YUViewLib/src/playlistitem/playlistItemImageFileSequence.cpp +++ b/YUViewLib/src/playlistitem/playlistItemImageFileSequence.cpp @@ -37,6 +37,7 @@ #include #include +#include #include #include @@ -231,8 +232,8 @@ playlistItemImageFileSequence::newplaylistItemImageFileSequence(const YUViewDomE break; // check if file with absolute path exists, otherwise check relative path - QString filePath = - FileSource::getAbsPathFromAbsAndRel(playlistFilePath, absolutePath, relativePath); + const auto filePath = + functions::getAbsPathFromAbsAndRel(playlistFilePath, absolutePath, relativePath); // Check if the file exists QFileInfo fileInfo(filePath); diff --git a/YUViewLib/src/playlistitem/playlistItemRawFile.cpp b/YUViewLib/src/playlistitem/playlistItemRawFile.cpp index e004ca131..1fc6b18a2 100644 --- a/YUViewLib/src/playlistitem/playlistItemRawFile.cpp +++ b/YUViewLib/src/playlistitem/playlistItemRawFile.cpp @@ -520,7 +520,8 @@ playlistItemRawFile *playlistItemRawFile::newplaylistItemRawFile(const YUViewDom auto type = root.findChildValue("type"); // check if file with absolute path exists, otherwise check relative path - auto filePath = FileSource::getAbsPathFromAbsAndRel(playlistFilePath, absolutePath, relativePath); + const auto filePath = + functions::getAbsPathFromAbsAndRel(playlistFilePath, absolutePath, relativePath); if (filePath.isEmpty()) return nullptr; diff --git a/YUViewLib/src/playlistitem/playlistItemStatisticsFile.cpp b/YUViewLib/src/playlistitem/playlistItemStatisticsFile.cpp index e14c6cfbf..4a08fe16d 100644 --- a/YUViewLib/src/playlistitem/playlistItemStatisticsFile.cpp +++ b/YUViewLib/src/playlistitem/playlistItemStatisticsFile.cpp @@ -108,7 +108,8 @@ playlistItemStatisticsFile *playlistItemStatisticsFile::newplaylistItemStatistic auto relativePath = root.findChildValue("relativePath"); // check if file with absolute path exists, otherwise check relative path - auto filePath = FileSource::getAbsPathFromAbsAndRel(playlistFilePath, absolutePath, relativePath); + const auto filePath = + functions::getAbsPathFromAbsAndRel(playlistFilePath, absolutePath, relativePath); if (filePath.isEmpty()) return nullptr; From eb15c5d4ca46b45fa2de09370e934b014777852d Mon Sep 17 00:00:00 2001 From: ChristianFeldmann Date: Tue, 3 Dec 2024 22:30:32 +0100 Subject: [PATCH 4/7] Add modification detection interface to dataSource --- .../src/dataSource/DataSourceLocalFile.cpp | 92 ++++++++++++++++--- .../src/dataSource/DataSourceLocalFile.h | 19 +++- YUViewLib/src/dataSource/IDataSource.h | 6 +- 3 files changed, 98 insertions(+), 19 deletions(-) diff --git a/YUViewLib/src/dataSource/DataSourceLocalFile.cpp b/YUViewLib/src/dataSource/DataSourceLocalFile.cpp index 9cd3b04bd..64da97d84 100644 --- a/YUViewLib/src/dataSource/DataSourceLocalFile.cpp +++ b/YUViewLib/src/dataSource/DataSourceLocalFile.cpp @@ -32,14 +32,37 @@ #include "DataSourceLocalFile.h" +#ifdef Q_OS_WIN +#include +#endif + namespace datasource { +namespace +{ + +std::optional +getLastWriteTime(const std::filesystem::path &filePath) noexcept +{ + try + { + return {std::filesystem::last_write_time(filePath)}; + } + catch (const std::exception &e) + { + return {}; + } +} + +} // namespace + DataSourceLocalFile::DataSourceLocalFile(const std::filesystem::path &filePath) { - this->file.open(filePath.string(), std::ios_base::in | std::ios_base::binary); + this->filePath = filePath; + this->file.open(this->filePath.string(), std::ios_base::in | std::ios_base::binary); if (this->isOk()) - this->path = filePath; + this->lastWriteTime = getLastWriteTime(this->filePath); } std::vector DataSourceLocalFile::getInfoList() const @@ -49,8 +72,8 @@ std::vector DataSourceLocalFile::getInfoList() const std::vector infoList; infoList.push_back( - InfoItem({"File Path", this->path.string(), "The absolute path of the local file"})); - if (const auto size = this->fileSize()) + InfoItem({"File Path", this->filePath.string(), "The absolute path of the local file"})); + if (const auto size = this->getFileSize()) infoList.push_back(InfoItem({"File Size", std::to_string(*size)})); return infoList; @@ -68,11 +91,52 @@ bool DataSourceLocalFile::isOk() const return true; } -std::int64_t DataSourceLocalFile::position() const +std::int64_t DataSourceLocalFile::getPosition() const { return this->filePosition; } +void DataSourceLocalFile::clearFileCache() +{ + if (!this->isOk()) + return; + +#ifdef Q_OS_WIN + // Currently, we only support this on windows. But this is only used in performance testing. + // We will close the QFile, open it using the FILE_FLAG_NO_BUFFERING flags, close it and reopen + // the QFile. Suggested: + // http://stackoverflow.com/questions/478340/clear-file-cache-to-repeat-performance-testing + const std::lock_guard readLock(this->readingMutex); + this->file.close(); + + LPCWSTR file = this->filePath.wstring().c_str(); + HANDLE hFile = + CreateFile(file, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING, NULL); + CloseHandle(hFile); + + this->file.open(this->filePath.string(), std::ios_base::in | std::ios_base::binary); +#endif +} + +bool DataSourceLocalFile::wasSourceModified() const +{ + if (!this->isOk()) + return false; + + if (const auto newTime = getLastWriteTime(this->filePath)) + return *newTime > *this->lastWriteTime; + + return false; +} + +void DataSourceLocalFile::reloadAndResetDataSource() +{ + this->file.close(); + this->file.open(this->filePath.string(), std::ios_base::in | std::ios_base::binary); + if (this->isOk()) + this->lastWriteTime = getLastWriteTime(this->filePath); +} + bool DataSourceLocalFile::seek(const std::int64_t pos) { if (!this->isOk()) @@ -90,11 +154,13 @@ std::int64_t DataSourceLocalFile::read(ByteVector &buffer, const std::int64_t nr if (!this->isOk()) return 0; - const auto usize = static_cast(nrBytes); + const std::lock_guard readLock(this->readingMutex); + + const auto size = static_cast(nrBytes); if (static_cast(buffer.size()) < nrBytes) - buffer.resize(usize); + buffer.resize(size); - this->file.read(reinterpret_cast(buffer.data()), usize); + this->file.read(reinterpret_cast(buffer.data()), size); const auto bytesRead = this->file.gcount(); buffer.resize(bytesRead); @@ -103,18 +169,18 @@ std::int64_t DataSourceLocalFile::read(ByteVector &buffer, const std::int64_t nr return static_cast(bytesRead); } -std::optional DataSourceLocalFile::fileSize() const +std::optional DataSourceLocalFile::getFileSize() const { - if (this->path.empty()) + if (this->filePath.empty()) return {}; - const auto size = std::filesystem::file_size(this->path); + const auto size = std::filesystem::file_size(this->filePath); return static_cast(size); } -[[nodiscard]] std::filesystem::path DataSourceLocalFile::filePath() const +[[nodiscard]] std::filesystem::path DataSourceLocalFile::getFilePath() const { - return this->path; + return this->filePath; } } // namespace datasource diff --git a/YUViewLib/src/dataSource/DataSourceLocalFile.h b/YUViewLib/src/dataSource/DataSourceLocalFile.h index baec7d4d4..9a0185815 100644 --- a/YUViewLib/src/dataSource/DataSourceLocalFile.h +++ b/YUViewLib/src/dataSource/DataSourceLocalFile.h @@ -36,6 +36,7 @@ #include #include +#include namespace datasource { @@ -43,25 +44,33 @@ namespace datasource class DataSourceLocalFile : public IDataSource { public: + DataSourceLocalFile() = delete; DataSourceLocalFile(const std::filesystem::path &filePath); [[nodiscard]] std::vector getInfoList() const override; [[nodiscard]] bool atEnd() const override; [[nodiscard]] bool isOk() const override; - [[nodiscard]] std::int64_t position() const override; + [[nodiscard]] std::int64_t getPosition() const override; + + void clearFileCache() override; + [[nodiscard]] bool wasSourceModified() const override; + void reloadAndResetDataSource() override; [[nodiscard]] bool seek(const std::int64_t pos) override; [[nodiscard]] std::int64_t read(ByteVector &buffer, const std::int64_t nrBytes) override; - [[nodiscard]] std::optional fileSize() const; - [[nodiscard]] std::filesystem::path filePath() const; + [[nodiscard]] std::optional getFileSize() const; + [[nodiscard]] std::filesystem::path getFilePath() const; protected: - std::filesystem::path path{}; - bool isFileOpened{}; + std::filesystem::path filePath{}; + std::optional lastWriteTime{}; + bool isFileOpened{}; std::ifstream file{}; std::int64_t filePosition{}; + + std::mutex readingMutex; }; } // namespace datasource diff --git a/YUViewLib/src/dataSource/IDataSource.h b/YUViewLib/src/dataSource/IDataSource.h index b1d4b99ae..322657ca9 100644 --- a/YUViewLib/src/dataSource/IDataSource.h +++ b/YUViewLib/src/dataSource/IDataSource.h @@ -48,7 +48,11 @@ class IDataSource [[nodiscard]] virtual std::vector getInfoList() const = 0; [[nodiscard]] virtual bool atEnd() const = 0; [[nodiscard]] virtual bool isOk() const = 0; - [[nodiscard]] virtual std::int64_t position() const = 0; + [[nodiscard]] virtual std::int64_t getPosition() const = 0; + + virtual void clearFileCache() = 0; + [[nodiscard]] virtual bool wasSourceModified() const = 0; + virtual void reloadAndResetDataSource() = 0; explicit operator bool() const { return this->isOk(); } From 0a3c5fe8b6d0e3bfd594cdacb7808b3b066dab96 Mon Sep 17 00:00:00 2001 From: ChristianFeldmann Date: Tue, 3 Dec 2024 22:44:09 +0100 Subject: [PATCH 5/7] Add test for detection of file change --- .../dataSource/DataSourceLocalFileTest.cpp | 58 ++++++++++++++----- 1 file changed, 45 insertions(+), 13 deletions(-) diff --git a/YUViewUnitTest/dataSource/DataSourceLocalFileTest.cpp b/YUViewUnitTest/dataSource/DataSourceLocalFileTest.cpp index c6075e166..8b5717e21 100644 --- a/YUViewUnitTest/dataSource/DataSourceLocalFileTest.cpp +++ b/YUViewUnitTest/dataSource/DataSourceLocalFileTest.cpp @@ -35,6 +35,8 @@ #include #include +#include + namespace datasource::test { @@ -47,12 +49,13 @@ TEST(DataSourceLocalFileTest, OpenFileThatDoesNotExist) DataSourceLocalFile file("/path/to/file/that/does/not/exist"); EXPECT_FALSE(file.isOk()); EXPECT_FALSE(file); - EXPECT_TRUE(file.filePath().empty()); + EXPECT_TRUE(file.getFilePath().empty()); EXPECT_EQ(file.getInfoList().size(), 0u); EXPECT_FALSE(file.atEnd()); - EXPECT_EQ(file.position(), 0); - EXPECT_FALSE(file.fileSize().has_value()); + EXPECT_EQ(file.getPosition(), 0); + EXPECT_FALSE(file.getFileSize().has_value()); EXPECT_FALSE(file.seek(252)); + EXPECT_FALSE(file.wasSourceModified()); ByteVector dummyVector; EXPECT_EQ(file.read(dummyVector, 378), 0); @@ -66,7 +69,7 @@ TEST(DataSourceLocalFileTest, OpenFileThatExists_TestRetrievalOfFileInfo) DataSourceLocalFile file(tempFile.getFilePath()); EXPECT_TRUE(file); - EXPECT_EQ(file.fileSize().value(), 8); + EXPECT_EQ(file.getFileSize().value(), 8); const auto debugTest = file.getInfoList(); EXPECT_THAT(file.getInfoList(), @@ -84,21 +87,24 @@ TEST(DataSourceLocalFileTest, OpenFileThatExists_TestReadingOfData) EXPECT_TRUE(file.isOk()); EXPECT_TRUE(file); - EXPECT_EQ(file.filePath(), tempFile.getFilePath()); + EXPECT_EQ(file.getFilePath(), tempFile.getFilePath()); EXPECT_FALSE(file.atEnd()); - EXPECT_EQ(file.position(), 0); + EXPECT_EQ(file.getPosition(), 0); + EXPECT_FALSE(file.wasSourceModified()); ByteVector buffer; EXPECT_EQ(file.read(buffer, 5), 5); EXPECT_TRUE(file); EXPECT_THAT(buffer, ElementsAre('t', 'e', 's', 't', 'd')); - EXPECT_EQ(file.position(), 5); + EXPECT_EQ(file.getPosition(), 5); + EXPECT_FALSE(file.wasSourceModified()); EXPECT_EQ(file.read(buffer, 36282), 3); EXPECT_TRUE(file); EXPECT_THAT(buffer, ElementsAre('a', 't', 'a')); - EXPECT_EQ(file.position(), 8); + EXPECT_EQ(file.getPosition(), 8); EXPECT_TRUE(file.atEnd()); + EXPECT_FALSE(file.wasSourceModified()); } TEST(DataSourceLocalFileTest, OpenFileThatExists_TestSeekingBeforeReading) @@ -110,14 +116,14 @@ TEST(DataSourceLocalFileTest, OpenFileThatExists_TestSeekingBeforeReading) EXPECT_TRUE(file.seek(4)); EXPECT_TRUE(file); - EXPECT_EQ(file.position(), 4); + EXPECT_EQ(file.getPosition(), 4); EXPECT_FALSE(file.atEnd()); ByteVector buffer; EXPECT_EQ(file.read(buffer, 100), 4); EXPECT_TRUE(file); EXPECT_THAT(buffer, ElementsAre('d', 'a', 't', 'a')); - EXPECT_EQ(file.position(), 8); + EXPECT_EQ(file.getPosition(), 8); EXPECT_TRUE(file.atEnd()); } @@ -132,19 +138,45 @@ TEST(DataSourceLocalFileTest, OpenFileThatExists_TestSeekingFromEOF) EXPECT_EQ(file.read(buffer, 100), 8); EXPECT_THAT(buffer, ElementsAre('t', 'e', 's', 't', 'd', 'a', 't', 'a')); EXPECT_TRUE(file.atEnd()); - EXPECT_EQ(file.position(), 8); + EXPECT_EQ(file.getPosition(), 8); EXPECT_TRUE(file); EXPECT_TRUE(file.seek(2)); EXPECT_TRUE(file); - EXPECT_EQ(file.position(), 2); + EXPECT_EQ(file.getPosition(), 2); EXPECT_FALSE(file.atEnd()); EXPECT_EQ(file.read(buffer, 3), 3); EXPECT_TRUE(file); EXPECT_THAT(buffer, ElementsAre('s', 't', 'd')); - EXPECT_EQ(file.position(), 5); + EXPECT_EQ(file.getPosition(), 5); EXPECT_FALSE(file.atEnd()); } +TEST(DataSourceLocalFileTest, ModifyOpenedFileExternally_ShouldBeDetected) +{ + yuviewTest::TemporaryFile tempFile(DUMMY_DATA); + ByteVector buffer; + + DataSourceLocalFile file(tempFile.getFilePath()); + + EXPECT_TRUE(file); + EXPECT_FALSE(file.wasSourceModified()); + EXPECT_EQ(file.read(buffer, 4), 4); + EXPECT_THAT(buffer, ElementsAre('t', 'e', 's', 't')); + + std::ofstream tempFileWriter(tempFile.getFilePath(), std::iostream::out | std::iostream::binary); + tempFileWriter << 'm' << 'o' << 'd' << 'i' << 'f' << 'i' << 'e' << 'd'; + tempFileWriter.close(); + + std::this_thread::sleep_for(std::chrono::seconds(1)); + + EXPECT_TRUE(file.wasSourceModified()); + + file.reloadAndResetDataSource(); + + EXPECT_EQ(file.read(buffer, 100), 8); + EXPECT_THAT(buffer, ElementsAre('m', 'o', 'd', 'i', 'f', 'i', 'e', 'd')); +} + } // namespace datasource::test From cba6c640ec3af16ac134acffb6379c2040f6de35 Mon Sep 17 00:00:00 2001 From: ChristianFeldmann Date: Tue, 3 Dec 2024 22:58:02 +0100 Subject: [PATCH 6/7] Fix test case --- YUViewLib/src/dataSource/DataSourceLocalFile.cpp | 2 +- YUViewUnitTest/dataSource/DataSourceLocalFileTest.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/YUViewLib/src/dataSource/DataSourceLocalFile.cpp b/YUViewLib/src/dataSource/DataSourceLocalFile.cpp index 64da97d84..34becf6a1 100644 --- a/YUViewLib/src/dataSource/DataSourceLocalFile.cpp +++ b/YUViewLib/src/dataSource/DataSourceLocalFile.cpp @@ -171,7 +171,7 @@ std::int64_t DataSourceLocalFile::read(ByteVector &buffer, const std::int64_t nr std::optional DataSourceLocalFile::getFileSize() const { - if (this->filePath.empty()) + if (!this->isOk()) return {}; const auto size = std::filesystem::file_size(this->filePath); diff --git a/YUViewUnitTest/dataSource/DataSourceLocalFileTest.cpp b/YUViewUnitTest/dataSource/DataSourceLocalFileTest.cpp index 8b5717e21..1a790162a 100644 --- a/YUViewUnitTest/dataSource/DataSourceLocalFileTest.cpp +++ b/YUViewUnitTest/dataSource/DataSourceLocalFileTest.cpp @@ -49,7 +49,7 @@ TEST(DataSourceLocalFileTest, OpenFileThatDoesNotExist) DataSourceLocalFile file("/path/to/file/that/does/not/exist"); EXPECT_FALSE(file.isOk()); EXPECT_FALSE(file); - EXPECT_TRUE(file.getFilePath().empty()); + EXPECT_FALSE(file.getFilePath().empty()); EXPECT_EQ(file.getInfoList().size(), 0u); EXPECT_FALSE(file.atEnd()); EXPECT_EQ(file.getPosition(), 0); From 7d476f8be408afbeb3fa24e1918928fd04885f8d Mon Sep 17 00:00:00 2001 From: Christian Feldmann Date: Wed, 4 Dec 2024 15:25:37 +0100 Subject: [PATCH 7/7] Also wait before modifying the file a bit. --- YUViewUnitTest/dataSource/DataSourceLocalFileTest.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/YUViewUnitTest/dataSource/DataSourceLocalFileTest.cpp b/YUViewUnitTest/dataSource/DataSourceLocalFileTest.cpp index 1a790162a..5039aa212 100644 --- a/YUViewUnitTest/dataSource/DataSourceLocalFileTest.cpp +++ b/YUViewUnitTest/dataSource/DataSourceLocalFileTest.cpp @@ -165,6 +165,8 @@ TEST(DataSourceLocalFileTest, ModifyOpenedFileExternally_ShouldBeDetected) EXPECT_EQ(file.read(buffer, 4), 4); EXPECT_THAT(buffer, ElementsAre('t', 'e', 's', 't')); + std::this_thread::sleep_for(std::chrono::seconds(1)); + std::ofstream tempFileWriter(tempFile.getFilePath(), std::iostream::out | std::iostream::binary); tempFileWriter << 'm' << 'o' << 'd' << 'i' << 'f' << 'i' << 'e' << 'd'; tempFileWriter.close();