diff --git a/lib/Epub/Epub/Page.cpp b/lib/Epub/Epub/Page.cpp index fe24b36..b36b698 100644 --- a/lib/Epub/Epub/Page.cpp +++ b/lib/Epub/Epub/Page.cpp @@ -7,12 +7,12 @@ void PageLine::render(GfxRenderer& renderer, const int fontId, const int xOffset block->render(renderer, fontId, xPos + xOffset, yPos + yOffset); } -void PageLine::serialize(File& file) { +bool PageLine::serialize(File &file) { serialization::writePod(file, xPos); serialization::writePod(file, yPos); // serialize TextBlock pointed to by PageLine - block->serialize(file); + return block->serialize(file); } std::unique_ptr PageLine::deserialize(File& file) { @@ -31,15 +31,19 @@ void Page::render(GfxRenderer& renderer, const int fontId, const int xOffset, co } } -void Page::serialize(File& file) const { +bool Page::serialize(File& file) const { const uint32_t count = elements.size(); serialization::writePod(file, count); for (const auto& el : elements) { // Only PageLine exists currently serialization::writePod(file, static_cast(TAG_PageLine)); - el->serialize(file); + if (!el->serialize(file)) { + return false; + } } + + return true; } std::unique_ptr Page::deserialize(File& file) { diff --git a/lib/Epub/Epub/Page.h b/lib/Epub/Epub/Page.h index f43e498..e7eeca7 100644 --- a/lib/Epub/Epub/Page.h +++ b/lib/Epub/Epub/Page.h @@ -18,7 +18,7 @@ class PageElement { explicit PageElement(const int16_t xPos, const int16_t yPos) : xPos(xPos), yPos(yPos) {} virtual ~PageElement() = default; virtual void render(GfxRenderer& renderer, int fontId, int xOffset, int yOffset) = 0; - virtual void serialize(File& file) = 0; + virtual bool serialize(File &file) = 0; }; // a line from a block element @@ -29,7 +29,7 @@ class PageLine final : public PageElement { PageLine(std::shared_ptr block, const int16_t xPos, const int16_t yPos) : PageElement(xPos, yPos), block(std::move(block)) {} void render(GfxRenderer& renderer, int fontId, int xOffset, int yOffset) override; - void serialize(File& file) override; + bool serialize(File &file) override; static std::unique_ptr deserialize(File& file); }; @@ -38,6 +38,6 @@ class Page { // the list of block index and line numbers on this page std::vector> elements; void render(GfxRenderer& renderer, int fontId, int xOffset, int yOffset) const; - void serialize(File& file) const; + bool serialize(File& file) const; static std::unique_ptr deserialize(File& file); }; diff --git a/lib/Epub/Epub/Section.cpp b/lib/Epub/Epub/Section.cpp index 10b3cd5..9cc19ea 100644 --- a/lib/Epub/Epub/Section.cpp +++ b/lib/Epub/Epub/Section.cpp @@ -18,8 +18,12 @@ size_t Section::onPageComplete(std::unique_ptr page) { Serial.printf("[%lu] [SCT] File not open for writing page %d\n", millis(), pageCount); return 0; } + const auto position = file.position(); - page->serialize(file); + if (!page->serialize(file)) { + Serial.printf("[%lu] [SCT] Failed to serialize page %d\n", millis(), pageCount); + return 0; + } Serial.printf("[%lu] [SCT] Page %d processed\n", millis(), pageCount); pageCount++; @@ -174,10 +178,23 @@ bool Section::createSectionFile(const int fontId, const float lineCompression, c } const auto lutOffset = file.position(); + bool hasFailedLutRecords = false; // Write LUT for (const auto& pos : lut) { + if (pos == 0) { + hasFailedLutRecords = true; + break; + } serialization::writePod(file, pos); } + + if (hasFailedLutRecords) { + Serial.printf("[%lu] [SCT] Failed to write LUT due to invalid page positions\n", millis()); + file.close(); + SD.remove(filePath.c_str()); + return false; + } + // Go back and write LUT offset file.seek(HEADER_SIZE - sizeof(size_t) - sizeof(pageCount)); serialization::writePod(file, pageCount); diff --git a/lib/Epub/Epub/blocks/TextBlock.cpp b/lib/Epub/Epub/blocks/TextBlock.cpp index ef6fdb5..ff8cfb4 100644 --- a/lib/Epub/Epub/blocks/TextBlock.cpp +++ b/lib/Epub/Epub/blocks/TextBlock.cpp @@ -24,34 +24,33 @@ void TextBlock::render(const GfxRenderer& renderer, const int fontId, const int } } -void TextBlock::serialize(File& file) const { - // words - const uint32_t wc = words.size(); - serialization::writePod(file, wc); +bool TextBlock::serialize(File &file) const { + if (words.size() != wordXpos.size() || words.size() != wordStyles.size()) { + Serial.printf("[%lu] [TXB] Serialization failed: size mismatch (words=%u, xpos=%u, styles=%u)\n", millis(), + words.size(), wordXpos.size(), wordStyles.size()); + return false; + } + + // Word data + serialization::writePod(file, static_cast(words.size())); for (const auto& w : words) serialization::writeString(file, w); - - // wordXpos - const uint32_t xc = wordXpos.size(); - serialization::writePod(file, xc); for (auto x : wordXpos) serialization::writePod(file, x); - - // wordStyles - const uint32_t sc = wordStyles.size(); - serialization::writePod(file, sc); for (auto s : wordStyles) serialization::writePod(file, s); - // style + // Block style serialization::writePod(file, style); + + return true; } std::unique_ptr TextBlock::deserialize(File& file) { - uint32_t wc, xc, sc; + uint32_t wc; std::list words; std::list wordXpos; std::list wordStyles; BLOCK_STYLE style; - // words + // Word count serialization::readPod(file, wc); // Sanity check: prevent allocation of unreasonably large lists (max 10000 words per block) @@ -60,27 +59,15 @@ std::unique_ptr TextBlock::deserialize(File& file) { return nullptr; } + // Word data words.resize(wc); + wordXpos.resize(wc); + wordStyles.resize(wc); for (auto& w : words) serialization::readString(file, w); - - // wordXpos - serialization::readPod(file, xc); - wordXpos.resize(xc); for (auto& x : wordXpos) serialization::readPod(file, x); - - // wordStyles - serialization::readPod(file, sc); - wordStyles.resize(sc); 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 + // Block style serialization::readPod(file, style); return std::unique_ptr(new TextBlock(std::move(words), std::move(wordXpos), std::move(wordStyles), style)); diff --git a/lib/Epub/Epub/blocks/TextBlock.h b/lib/Epub/Epub/blocks/TextBlock.h index 46e320e..807c802 100644 --- a/lib/Epub/Epub/blocks/TextBlock.h +++ b/lib/Epub/Epub/blocks/TextBlock.h @@ -36,6 +36,6 @@ class TextBlock final : public Block { // given a renderer works out where to break the words into lines void render(const GfxRenderer& renderer, int fontId, int x, int y) const; BlockType getType() override { return TEXT_BLOCK; } - void serialize(File& file) const; + bool serialize(File &file) const; static std::unique_ptr deserialize(File& file); };