| 150 | } |
| 151 | |
| 152 | bool Section::createSectionFile(const int fontId, const float lineCompression, const bool extraParagraphSpacing, |
| 153 | const uint8_t paragraphAlignment, const uint16_t viewportWidth, |
| 154 | const uint16_t viewportHeight, const bool hyphenationEnabled, const bool embeddedStyle, |
| 155 | const uint8_t imageRendering, const bool focusReadingEnabled, |
| 156 | const std::function<void()>& popupFn) { |
| 157 | const auto localPath = epub->getSpineItem(spineIndex).href; |
| 158 | const auto tmpHtmlPath = epub->getCachePath() + "/.tmp_" + std::to_string(spineIndex) + ".html"; |
| 159 | |
| 160 | // Create cache directory if it doesn't exist |
| 161 | { |
| 162 | const auto sectionsDir = epub->getCachePath() + "/sections"; |
| 163 | Storage.mkdir(sectionsDir.c_str()); |
| 164 | } |
| 165 | |
| 166 | // Retry logic for SD card timing issues |
| 167 | bool success = false; |
| 168 | uint32_t fileSize = 0; |
| 169 | for (int attempt = 0; attempt < 3 && !success; attempt++) { |
| 170 | if (attempt > 0) { |
| 171 | LOG_DBG("SCT", "Retrying stream (attempt %d)...", attempt + 1); |
| 172 | delay(50); // Brief delay before retry |
| 173 | } |
| 174 | |
| 175 | // Remove any incomplete file from previous attempt before retrying |
| 176 | if (Storage.exists(tmpHtmlPath.c_str())) { |
| 177 | Storage.remove(tmpHtmlPath.c_str()); |
| 178 | } |
| 179 | |
| 180 | HalFile tmpHtml; |
| 181 | if (!Storage.openFileForWrite("SCT", tmpHtmlPath, tmpHtml)) { |
| 182 | continue; |
| 183 | } |
| 184 | success = epub->readItemContentsToStream(localPath, tmpHtml, 1024); |
| 185 | fileSize = tmpHtml.size(); |
| 186 | // Explicitly close() file before calling Storage.remove() |
| 187 | tmpHtml.close(); |
| 188 | |
| 189 | // If streaming failed, remove the incomplete file immediately |
| 190 | if (!success && Storage.exists(tmpHtmlPath.c_str())) { |
| 191 | Storage.remove(tmpHtmlPath.c_str()); |
| 192 | LOG_DBG("SCT", "Removed incomplete temp file after failed attempt"); |
| 193 | } |
| 194 | } |
| 195 | |
| 196 | if (!success) { |
| 197 | LOG_ERR("SCT", "Failed to stream item contents to temp file after retries"); |
| 198 | return false; |
| 199 | } |
| 200 | |
| 201 | LOG_DBG("SCT", "Streamed temp HTML to %s (%d bytes)", tmpHtmlPath.c_str(), fileSize); |
| 202 | |
| 203 | if (!Storage.openFileForWrite("SCT", filePath, file)) { |
| 204 | return false; |
| 205 | } |
| 206 | writeSectionFileHeader(fontId, lineCompression, extraParagraphSpacing, paragraphAlignment, viewportWidth, |
| 207 | viewportHeight, hyphenationEnabled, embeddedStyle, imageRendering, focusReadingEnabled); |
| 208 | std::vector<PageLutEntry> lut = {}; |
| 209 |
no test coverage detected