perf: stream NCX/NAV TOC into parser, drop temp-file round-trip (#2440)

Co-authored-by: Erica Jensen <erica@mailershaven.com>
This commit is contained in:
hooligan333
2026-07-11 22:57:48 -04:00
committed by GitHub
co-authored by Erica Jensen
parent 5fbc657aeb
commit b596f21e61
+14 -59
View File
@@ -153,18 +153,11 @@ bool Epub::parseTocNcxFile() const {
LOG_DBG("EBP", "Parsing toc ncx file: %s", tocNcxItem.c_str()); LOG_DBG("EBP", "Parsing toc ncx file: %s", tocNcxItem.c_str());
const auto tmpNcxPath = getCachePath() + "/toc.ncx"; size_t ncxSize;
HalFile tempNcxFile; if (!getItemSize(tocNcxItem, &ncxSize)) {
if (!Storage.openFileForWrite("EBP", tmpNcxPath, tempNcxFile)) { LOG_ERR("EBP", "Could not get size of toc ncx file");
return false; return false;
} }
readItemContentsToStream(tocNcxItem, tempNcxFile, 1024);
// Explicitly close() file before reopening for reading
tempNcxFile.close();
if (!Storage.openFileForRead("EBP", tmpNcxPath, tempNcxFile)) {
return false;
}
const auto ncxSize = tempNcxFile.size();
TocNcxParser ncxParser(contentBasePath, ncxSize, bookMetadataCache.get()); TocNcxParser ncxParser(contentBasePath, ncxSize, bookMetadataCache.get());
@@ -173,29 +166,13 @@ bool Epub::parseTocNcxFile() const {
return false; return false;
} }
const auto ncxBuffer = static_cast<uint8_t*>(malloc(1024)); // Stream the decompressed NCX straight into the parser instead of round-tripping
if (!ncxBuffer) { // through a temp file on the SD card (decompress -> write -> reopen -> reread -> delete).
LOG_ERR("EBP", "Could not allocate memory for toc ncx parser"); if (!readItemContentsToStream(tocNcxItem, ncxParser, 1024)) {
LOG_ERR("EBP", "Could not read toc ncx file");
return false; return false;
} }
while (tempNcxFile.available()) {
const auto readSize = tempNcxFile.read(ncxBuffer, 1024);
if (readSize == 0) break;
const auto processedSize = ncxParser.write(ncxBuffer, readSize);
if (processedSize != readSize) {
LOG_ERR("EBP", "Could not process all toc ncx data");
free(ncxBuffer);
return false;
}
}
free(ncxBuffer);
// Explicitly close() file before calling Storage.remove()
tempNcxFile.close();
Storage.remove(tmpNcxPath.c_str());
LOG_DBG("EBP", "Parsed TOC items"); LOG_DBG("EBP", "Parsed TOC items");
return true; return true;
} }
@@ -209,18 +186,11 @@ bool Epub::parseTocNavFile() const {
LOG_DBG("EBP", "Parsing toc nav file: %s", tocNavItem.c_str()); LOG_DBG("EBP", "Parsing toc nav file: %s", tocNavItem.c_str());
const auto tmpNavPath = getCachePath() + "/toc.nav"; size_t navSize;
HalFile tempNavFile; if (!getItemSize(tocNavItem, &navSize)) {
if (!Storage.openFileForWrite("EBP", tmpNavPath, tempNavFile)) { LOG_ERR("EBP", "Could not get size of toc nav file");
return false; return false;
} }
readItemContentsToStream(tocNavItem, tempNavFile, 1024);
// Explicitly close() file before reopening for reading
tempNavFile.close();
if (!Storage.openFileForRead("EBP", tmpNavPath, tempNavFile)) {
return false;
}
const auto navSize = tempNavFile.size();
// Note: We can't use `contentBasePath` here as the nav file may be in a different folder to the content.opf // Note: We can't use `contentBasePath` here as the nav file may be in a different folder to the content.opf
// and the HTMLX nav file will have hrefs relative to itself // and the HTMLX nav file will have hrefs relative to itself
@@ -232,28 +202,13 @@ bool Epub::parseTocNavFile() const {
return false; return false;
} }
const auto navBuffer = static_cast<uint8_t*>(malloc(1024)); // Stream the decompressed nav document straight into the parser instead of round-tripping
if (!navBuffer) { // through a temp file on the SD card (decompress -> write -> reopen -> reread -> delete).
LOG_ERR("EBP", "Could not allocate memory for toc nav parser"); if (!readItemContentsToStream(tocNavItem, navParser, 1024)) {
LOG_ERR("EBP", "Could not read toc nav file");
return false; return false;
} }
while (tempNavFile.available()) {
const auto readSize = tempNavFile.read(navBuffer, 1024);
const auto processedSize = navParser.write(navBuffer, readSize);
if (processedSize != readSize) {
LOG_ERR("EBP", "Could not process all toc nav data");
free(navBuffer);
return false;
}
}
free(navBuffer);
// Explicitly close() file before calling Storage.remove()
tempNavFile.close();
Storage.remove(tmpNavPath.c_str());
LOG_DBG("EBP", "Parsed TOC nav items"); LOG_DBG("EBP", "Parsed TOC nav items");
return true; return true;
} }