diff --git a/lib/Epub/Epub/FsHelpers.cpp b/lib/Epub/Epub/FsHelpers.cpp index 867278f..6c2400f 100644 --- a/lib/Epub/Epub/FsHelpers.cpp +++ b/lib/Epub/Epub/FsHelpers.cpp @@ -1,6 +1,7 @@ #include "FsHelpers.h" #include + #include bool FsHelpers::removeDir(const char* path) { diff --git a/lib/Epub/Epub/FsHelpers.h b/lib/Epub/Epub/FsHelpers.h index b5e0dc5..0f75bf8 100644 --- a/lib/Epub/Epub/FsHelpers.h +++ b/lib/Epub/Epub/FsHelpers.h @@ -4,5 +4,5 @@ class FsHelpers { public: static bool removeDir(const char* path); - static std::string normalisePath(const std::string &path); + static std::string normalisePath(const std::string& path); }; diff --git a/lib/Epub/Epub/SpineTocCache.cpp b/lib/Epub/Epub/SpineTocCache.cpp index e51bc28..0ad05e4 100644 --- a/lib/Epub/Epub/SpineTocCache.cpp +++ b/lib/Epub/Epub/SpineTocCache.cpp @@ -14,6 +14,24 @@ constexpr uint8_t SPINE_TOC_CACHE_VERSION = 1; constexpr char spineTocMetaBinFile[] = "/spine_toc_meta.bin"; constexpr char spineBinFile[] = "/spine.bin"; constexpr char tocBinFile[] = "/toc.bin"; + +bool openFileForRead(const std::string& path, File& file) { + file = SD.open(path.c_str(), FILE_READ); + if (!file) { + Serial.printf("[%lu] [STC] Failed to open file for reading: %s\n", millis(), path.c_str()); + return false; + } + return true; +} + +bool openFileForWrite(const std::string& path, File& file) { + file = SD.open(path.c_str(), FILE_WRITE, true); + if (!file) { + Serial.printf("[%lu] [STC] Failed to open spine file for writing: %s\n", millis(), path.c_str()); + return false; + } + return true; +} } // namespace bool SpineTocCache::beginWrite() { @@ -24,20 +42,12 @@ bool SpineTocCache::beginWrite() { Serial.printf("[%lu] [STC] Beginning write to cache path: %s\n", millis(), cachePath.c_str()); // Open spine file for writing - const std::string spineFilePath = cachePath + spineBinFile; - Serial.printf("[%lu] [STC] Opening spine file: %s\n", millis(), spineFilePath.c_str()); - spineFile = SD.open(spineFilePath.c_str(), FILE_WRITE, true); - if (!spineFile) { - Serial.printf("[%lu] [STC] Failed to open spine file for writing: %s\n", millis(), spineFilePath.c_str()); + if (!openFileForWrite(cachePath + spineBinFile, spineFile)) { return false; } // Open TOC file for writing - const std::string tocFilePath = cachePath + tocBinFile; - Serial.printf("[%lu] [STC] Opening toc file: %s\n", millis(), tocFilePath.c_str()); - tocFile = SD.open(tocFilePath.c_str(), FILE_WRITE, true); - if (!tocFile) { - Serial.printf("[%lu] [STC] Failed to open toc file for writing: %s\n", millis(), tocFilePath.c_str()); + if (!openFileForWrite(cachePath + tocBinFile, tocFile)) { spineFile.close(); return false; } @@ -93,10 +103,8 @@ bool SpineTocCache::endWrite() { tocFile.close(); // Write metadata files with counts - const auto spineTocMetaPath = cachePath + spineTocMetaBinFile; - File metaFile = SD.open(spineTocMetaPath.c_str(), FILE_WRITE, true); - if (!metaFile) { - Serial.printf("[%lu] [STC] Failed to write spine metadata\n", millis()); + File metaFile; + if (!openFileForWrite(cachePath + spineTocMetaBinFile, metaFile)) { return false; } serialization::writePod(metaFile, SPINE_TOC_CACHE_VERSION); @@ -109,25 +117,25 @@ bool SpineTocCache::endWrite() { return true; } -SpineTocCache::SpineEntry SpineTocCache::readSpineEntry(std::ifstream& is) const { +SpineTocCache::SpineEntry SpineTocCache::readSpineEntry(File& file) const { SpineEntry entry; - serialization::readString(is, entry.href); - serialization::readPod(is, entry.cumulativeSize); - serialization::readPod(is, entry.tocIndex); + serialization::readString(file, entry.href); + serialization::readPod(file, entry.cumulativeSize); + serialization::readPod(file, entry.tocIndex); return entry; } -SpineTocCache::TocEntry SpineTocCache::readTocEntry(std::ifstream& is) const { +SpineTocCache::TocEntry SpineTocCache::readTocEntry(File& file) const { TocEntry entry; - serialization::readString(is, entry.title); - serialization::readString(is, entry.href); - serialization::readString(is, entry.anchor); - serialization::readPod(is, entry.level); - serialization::readPod(is, entry.spineIndex); + serialization::readString(file, entry.title); + serialization::readString(file, entry.href); + serialization::readString(file, entry.anchor); + serialization::readPod(file, entry.level); + serialization::readPod(file, entry.spineIndex); return entry; } -bool SpineTocCache::updateMappingsAndSizes(const std::string& epubPath) const { +bool SpineTocCache::updateMappingsAndSizes(const std::string& epubPath) { Serial.printf("[%lu] [STC] Computing mappings and sizes for %d spine, %d TOC entries\n", millis(), spineCount, tocCount); @@ -141,32 +149,24 @@ bool SpineTocCache::updateMappingsAndSizes(const std::string& epubPath) const { // Read spine entries { - const auto spineFilePath = "/sd" + cachePath + spineBinFile; - std::ifstream spineStream(spineFilePath.c_str(), std::ios::binary); - if (!spineStream) { - Serial.printf("[%lu] [STC] Failed to open spine file for reading\n", millis()); + if (!openFileForRead(cachePath + spineBinFile, spineFile)) { return false; } - for (int i = 0; i < spineCount; i++) { - spineEntries.push_back(readSpineEntry(spineStream)); + spineEntries.push_back(readSpineEntry(spineFile)); } - spineStream.close(); + spineFile.close(); } // Read TOC entries { - const auto tocFilePath = "/sd" + cachePath + tocBinFile; - std::ifstream tocStream(tocFilePath.c_str(), std::ios::binary); - if (!tocStream) { - Serial.printf("[%lu] [STC] Failed to open toc file for reading\n", millis()); + if (!openFileForRead(cachePath + tocBinFile, tocFile)) { return false; } - for (int i = 0; i < tocCount; i++) { - tocEntries.push_back(readTocEntry(tocStream)); + tocEntries.push_back(readTocEntry(tocFile)); } - tocStream.close(); + tocFile.close(); } // Compute cumulative sizes @@ -199,13 +199,9 @@ bool SpineTocCache::updateMappingsAndSizes(const std::string& epubPath) const { // Rewrite spine file with updated data { - const auto spineFilePath = cachePath + spineBinFile; - File spineFile = SD.open(spineFilePath.c_str(), FILE_WRITE, true); - if (!spineFile) { - Serial.printf("[%lu] [STC] Failed to reopen spine file for writing\n", millis()); + if (!openFileForWrite(cachePath + spineBinFile, spineFile)) { return false; } - for (const auto& entry : spineEntries) { writeSpineEntry(spineFile, entry); } @@ -214,13 +210,9 @@ bool SpineTocCache::updateMappingsAndSizes(const std::string& epubPath) const { // Rewrite TOC file with updated data { - const auto tocFilePath = cachePath + tocBinFile; - File tocFile = SD.open(tocFilePath.c_str(), FILE_WRITE, true); - if (!tocFile) { - Serial.printf("[%lu] [STC] Failed to reopen toc file for writing\n", millis()); + if (!openFileForWrite(cachePath + tocBinFile, tocFile)) { return false; } - for (const auto& entry : tocEntries) { writeTocEntry(tocFile, entry); } @@ -239,15 +231,8 @@ bool SpineTocCache::updateMappingsAndSizes(const std::string& epubPath) const { bool SpineTocCache::load() { // Load metadata - const auto spineTocMetaPath = cachePath + spineTocMetaBinFile; - if (!SD.exists(spineTocMetaPath.c_str())) { - Serial.printf("[%lu] [STC] Cache metadata does not exist: %s\n", millis(), spineTocMetaPath.c_str()); - return false; - } - - File metaFile = SD.open(spineTocMetaPath.c_str(), FILE_READ); - if (!metaFile) { - Serial.printf("[%lu] [STC] Failed to open cache metadata\n", millis()); + File metaFile; + if (!openFileForRead(cachePath + spineTocMetaBinFile, metaFile)) { return false; } @@ -270,61 +255,55 @@ bool SpineTocCache::load() { return true; } -SpineTocCache::SpineEntry SpineTocCache::getSpineEntry(const int index) const { +SpineTocCache::SpineEntry SpineTocCache::getSpineEntry(const int index) { if (!loaded) { Serial.printf("[%lu] [STC] getSpineEntry called but cache not loaded\n", millis()); - return SpineEntry(); + return {}; } if (index < 0 || index >= static_cast(spineCount)) { Serial.printf("[%lu] [STC] getSpineEntry index %d out of range\n", millis(), index); - return SpineEntry(); + return {}; } - const auto spineFilePath = "/sd" + cachePath + spineBinFile; - std::ifstream spineStream(spineFilePath.c_str(), std::ios::binary); - if (!spineStream) { - Serial.printf("[%lu] [STC] Failed to open spine file for reading entry\n", millis()); - return SpineEntry(); + if (!openFileForRead(cachePath + spineBinFile, spineFile)) { + return {}; } // Seek to the correct entry - need to read entries sequentially until we reach the index // TODO: This could/should be based on a look up table/fixed sizes for (int i = 0; i < index; i++) { - readSpineEntry(spineStream); // Skip entries + readSpineEntry(spineFile); // Skip entries } - auto entry = readSpineEntry(spineStream); - spineStream.close(); + auto entry = readSpineEntry(spineFile); + spineFile.close(); return entry; } -SpineTocCache::TocEntry SpineTocCache::getTocEntry(const int index) const { +SpineTocCache::TocEntry SpineTocCache::getTocEntry(const int index) { if (!loaded) { Serial.printf("[%lu] [STC] getTocEntry called but cache not loaded\n", millis()); - return TocEntry(); + return {}; } if (index < 0 || index >= static_cast(tocCount)) { Serial.printf("[%lu] [STC] getTocEntry index %d out of range\n", millis(), index); - return TocEntry(); + return {}; } - const auto tocFilePath = "/sd" + cachePath + tocBinFile; - std::ifstream tocStream(tocFilePath.c_str(), std::ios::binary); - if (!tocStream) { - Serial.printf("[%lu] [STC] Failed to open toc file for reading entry\n", millis()); - return TocEntry(); + if (!openFileForRead(cachePath + tocBinFile, tocFile)) { + return {}; } // Seek to the correct entry - need to read entries sequentially until we reach the index // TODO: This could/should be based on a look up table/fixed sizes for (int i = 0; i < index; i++) { - readTocEntry(tocStream); // Skip entries + readTocEntry(tocFile); // Skip entries } - auto entry = readTocEntry(tocStream); - tocStream.close(); + auto entry = readTocEntry(tocFile); + tocFile.close(); return entry; } diff --git a/lib/Epub/Epub/SpineTocCache.h b/lib/Epub/Epub/SpineTocCache.h index b0c8d64..469b94d 100644 --- a/lib/Epub/Epub/SpineTocCache.h +++ b/lib/Epub/Epub/SpineTocCache.h @@ -2,7 +2,6 @@ #include -#include #include class SpineTocCache { @@ -13,7 +12,7 @@ class SpineTocCache { int16_t tocIndex; SpineEntry() : cumulativeSize(0), tocIndex(-1) {} - SpineEntry(std::string href, size_t cumulativeSize, int16_t tocIndex) + SpineEntry(std::string href, const size_t cumulativeSize, const int16_t tocIndex) : href(std::move(href)), cumulativeSize(cumulativeSize), tocIndex(tocIndex) {} }; @@ -25,7 +24,7 @@ class SpineTocCache { int16_t spineIndex; TocEntry() : level(0), spineIndex(-1) {} - TocEntry(std::string title, std::string href, std::string anchor, uint8_t level, int16_t spineIndex) + TocEntry(std::string title, std::string href, std::string anchor, const uint8_t level, const int16_t spineIndex) : title(std::move(title)), href(std::move(href)), anchor(std::move(anchor)), @@ -46,8 +45,8 @@ class SpineTocCache { void writeSpineEntry(File& file, const SpineEntry& entry) const; void writeTocEntry(File& file, const TocEntry& entry) const; - SpineEntry readSpineEntry(std::ifstream& is) const; - TocEntry readTocEntry(std::ifstream& is) const; + SpineEntry readSpineEntry(File& file) const; + TocEntry readTocEntry(File& file) const; public: explicit SpineTocCache(std::string cachePath) @@ -61,12 +60,12 @@ class SpineTocCache { bool endWrite(); // Post-processing to update mappings and sizes - bool updateMappingsAndSizes(const std::string& epubPath) const; + bool updateMappingsAndSizes(const std::string& epubPath); // Reading phase (read mode) bool load(); - SpineEntry getSpineEntry(int index) const; - TocEntry getTocEntry(int index) const; + SpineEntry getSpineEntry(int index); + TocEntry getTocEntry(int index); int getSpineCount() const; int getTocCount() const; bool isLoaded() const; diff --git a/lib/Serialization/Serialization.h b/lib/Serialization/Serialization.h index a424c4b..e6bcbf2 100644 --- a/lib/Serialization/Serialization.h +++ b/lib/Serialization/Serialization.h @@ -1,4 +1,6 @@ #pragma once +#include + #include namespace serialization { @@ -17,7 +19,7 @@ static void readPod(std::istream& is, T& value) { is.read(reinterpret_cast(&value), sizeof(T)); } - template +template static void readPod(File& file, T& value) { file.read(reinterpret_cast(&value), sizeof(T)); } @@ -31,7 +33,7 @@ static void writeString(std::ostream& os, const std::string& s) { static void writeString(File& file, const std::string& s) { const uint32_t len = s.size(); writePod(file, len); - file.write(reinterpret_cast(s.data()), len); + file.write(reinterpret_cast(s.data()), len); } static void readString(std::istream& is, std::string& s) { @@ -40,4 +42,11 @@ static void readString(std::istream& is, std::string& s) { s.resize(len); is.read(&s[0], len); } + +static void readString(File& file, std::string& s) { + uint32_t len; + readPod(file, len); + s.resize(len); + file.read(reinterpret_cast(&s[0]), len); +} } // namespace serialization