Cleanup SpineTocCache

This commit is contained in:
Dave Allie 2025-12-22 21:43:01 +11:00
parent dc3869ac1c
commit 05fce6b818
No known key found for this signature in database
GPG Key ID: F2FDDB3AD8D0276F
5 changed files with 79 additions and 91 deletions

View File

@ -1,6 +1,7 @@
#include "FsHelpers.h"
#include <SD.h>
#include <vector>
bool FsHelpers::removeDir(const char* path) {

View File

@ -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<int>(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<int>(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;
}

View File

@ -2,7 +2,6 @@
#include <SD.h>
#include <fstream>
#include <string>
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;

View File

@ -1,4 +1,6 @@
#pragma once
#include <FS.h>
#include <iostream>
namespace serialization {
@ -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<uint8_t*>(&s[0]), len);
}
} // namespace serialization