From 481b8210fbe840d592797766373023619062676a Mon Sep 17 00:00:00 2001 From: Daniel Date: Tue, 20 Jan 2026 12:34:51 -0800 Subject: [PATCH] fix: prevent OOM crash when loading large EPUBs (2000+ chapters) Remove the call to loadAllFileStatSlims() which pre-loads all ZIP central directory entries into memory. For EPUBs with 2000+ chapters (like webnovels), this exhausts the ESP32-C3's ~380KB RAM and causes abort(). The existing loadFileStatSlim() function already handles individual lookups by scanning the central directory per-file when the cache is empty. This is O(n*m) instead of O(n), but prevents memory exhaustion. Fixes #134 --- lib/Epub/Epub/BookMetadataCache.cpp | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/lib/Epub/Epub/BookMetadataCache.cpp b/lib/Epub/Epub/BookMetadataCache.cpp index 47ba227..bc5ff52 100644 --- a/lib/Epub/Epub/BookMetadataCache.cpp +++ b/lib/Epub/Epub/BookMetadataCache.cpp @@ -143,17 +143,12 @@ bool BookMetadataCache::buildBookBin(const std::string& epubPath, const BookMeta tocFile.close(); return false; } - // TODO: For large ZIPs loading the all localHeaderOffsets will crash. - // However not having them loaded is extremely slow. Need a better solution here. - // Perhaps only a cache of spine items or a better way to speedup lookups? - if (!zip.loadAllFileStatSlims()) { - Serial.printf("[%lu] [BMC] Could not load zip local header offsets for size calculations\n", millis()); - bookFile.close(); - spineFile.close(); - tocFile.close(); - zip.close(); - return false; - } + // NOTE: We intentionally skip calling loadAllFileStatSlims() here. + // For large EPUBs (2000+ chapters), pre-loading all ZIP central directory entries + // into memory causes OOM crashes on ESP32-C3's limited ~380KB RAM. + // Instead, we let loadFileStatSlim() do individual lookups per spine item. + // This is O(n*m) instead of O(n) for lookups, but avoids memory exhaustion. + // See: https://github.com/crosspoint-reader/crosspoint-reader/issues/134 uint32_t cumSize = 0; spineFile.seek(0); int lastSpineTocIndex = -1;