fix(epub): prevent blank pages from corrupted index files
- Clean up incomplete temp files before retry attempts in Section.cpp - Remove failed stream files immediately to prevent corruption - Add data consistency validation in TextBlock deserialization (wc == xc == sc) - Add sanity check for unreasonably large word counts (max 10000) - Add iterator bounds validation before rendering to prevent overflow This fixes an issue where pages after a certain point would appear blank due to corrupted .bin files from failed SD card streaming retries.
This commit is contained in:
parent
f41e7496ad
commit
abe3e6c6db
@ -127,12 +127,23 @@ bool Section::persistPageDataToSD(const int fontId, const float lineCompression,
|
|||||||
delay(50); // Brief delay before retry
|
delay(50); // Brief delay before retry
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove any incomplete file from previous attempt before retrying
|
||||||
|
if (SD.exists(tmpHtmlPath.c_str())) {
|
||||||
|
SD.remove(tmpHtmlPath.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
File tmpHtml;
|
File tmpHtml;
|
||||||
if (!FsHelpers::openFileForWrite("SCT", tmpHtmlPath, tmpHtml)) {
|
if (!FsHelpers::openFileForWrite("SCT", tmpHtmlPath, tmpHtml)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
success = epub->readItemContentsToStream(localPath, tmpHtml, 1024);
|
success = epub->readItemContentsToStream(localPath, tmpHtml, 1024);
|
||||||
tmpHtml.close();
|
tmpHtml.close();
|
||||||
|
|
||||||
|
// If streaming failed, remove the incomplete file immediately
|
||||||
|
if (!success && SD.exists(tmpHtmlPath.c_str())) {
|
||||||
|
SD.remove(tmpHtmlPath.c_str());
|
||||||
|
Serial.printf("[%lu] [SCT] Removed incomplete temp file after failed attempt\n", millis());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
|
|||||||
@ -4,11 +4,18 @@
|
|||||||
#include <Serialization.h>
|
#include <Serialization.h>
|
||||||
|
|
||||||
void TextBlock::render(const GfxRenderer& renderer, const int fontId, const int x, const int y) const {
|
void TextBlock::render(const GfxRenderer& renderer, const int fontId, const int x, const int y) const {
|
||||||
|
// Validate iterator bounds before rendering
|
||||||
|
if (words.size() != wordXpos.size() || words.size() != wordStyles.size()) {
|
||||||
|
Serial.printf("[%lu] [TXB] Render skipped: size mismatch (words=%u, xpos=%u, styles=%u)\n", millis(),
|
||||||
|
(uint32_t)words.size(), (uint32_t)wordXpos.size(), (uint32_t)wordStyles.size());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
auto wordIt = words.begin();
|
auto wordIt = words.begin();
|
||||||
auto wordStylesIt = wordStyles.begin();
|
auto wordStylesIt = wordStyles.begin();
|
||||||
auto wordXposIt = wordXpos.begin();
|
auto wordXposIt = wordXpos.begin();
|
||||||
|
|
||||||
for (int i = 0; i < words.size(); i++) {
|
for (size_t i = 0; i < words.size(); i++) {
|
||||||
renderer.drawText(fontId, *wordXposIt + x, y, wordIt->c_str(), true, *wordStylesIt);
|
renderer.drawText(fontId, *wordXposIt + x, y, wordIt->c_str(), true, *wordStylesIt);
|
||||||
|
|
||||||
std::advance(wordIt, 1);
|
std::advance(wordIt, 1);
|
||||||
@ -46,6 +53,13 @@ std::unique_ptr<TextBlock> TextBlock::deserialize(File& file) {
|
|||||||
|
|
||||||
// words
|
// words
|
||||||
serialization::readPod(file, wc);
|
serialization::readPod(file, wc);
|
||||||
|
|
||||||
|
// Sanity check: prevent allocation of unreasonably large lists (max 10000 words per block)
|
||||||
|
if (wc > 10000) {
|
||||||
|
Serial.printf("[%lu] [TXB] Deserialization failed: word count %u exceeds maximum\n", millis(), wc);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
words.resize(wc);
|
words.resize(wc);
|
||||||
for (auto& w : words) serialization::readString(file, w);
|
for (auto& w : words) serialization::readString(file, w);
|
||||||
|
|
||||||
@ -59,6 +73,13 @@ std::unique_ptr<TextBlock> TextBlock::deserialize(File& file) {
|
|||||||
wordStyles.resize(sc);
|
wordStyles.resize(sc);
|
||||||
for (auto& s : wordStyles) serialization::readPod(file, s);
|
for (auto& s : wordStyles) serialization::readPod(file, s);
|
||||||
|
|
||||||
|
// Validate data consistency: all three lists must have the same size
|
||||||
|
if (wc != xc || wc != sc) {
|
||||||
|
Serial.printf("[%lu] [TXB] Deserialization failed: size mismatch (words=%u, xpos=%u, styles=%u)\n", millis(), wc, xc,
|
||||||
|
sc);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
// style
|
// style
|
||||||
serialization::readPod(file, style);
|
serialization::readPod(file, style);
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user