diff --git a/lib/Epub/Epub.cpp b/lib/Epub/Epub.cpp index cb0b18017..a5befe5b3 100644 --- a/lib/Epub/Epub.cpp +++ b/lib/Epub/Epub.cpp @@ -155,6 +155,7 @@ bool Epub::parseTocNcxFile() const { return false; } readItemContentsToStream(tocNcxItem, tempNcxFile, 1024); + // Explicitly close() file before reopening for reading tempNcxFile.close(); if (!Storage.openFileForRead("EBP", tmpNcxPath, tempNcxFile)) { return false; @@ -165,14 +166,12 @@ bool Epub::parseTocNcxFile() const { if (!ncxParser.setup()) { LOG_ERR("EBP", "Could not setup toc ncx parser"); - tempNcxFile.close(); return false; } const auto ncxBuffer = static_cast(malloc(1024)); if (!ncxBuffer) { LOG_ERR("EBP", "Could not allocate memory for toc ncx parser"); - tempNcxFile.close(); return false; } @@ -184,12 +183,12 @@ bool Epub::parseTocNcxFile() const { if (processedSize != readSize) { LOG_ERR("EBP", "Could not process all toc ncx data"); free(ncxBuffer); - tempNcxFile.close(); return false; } } free(ncxBuffer); + // Explicitly close() file before calling Storage.remove() tempNcxFile.close(); Storage.remove(tmpNcxPath.c_str()); @@ -212,6 +211,7 @@ bool Epub::parseTocNavFile() const { return false; } readItemContentsToStream(tocNavItem, tempNavFile, 1024); + // Explicitly close() file before reopening for reading tempNavFile.close(); if (!Storage.openFileForRead("EBP", tmpNavPath, tempNavFile)) { return false; @@ -241,12 +241,12 @@ bool Epub::parseTocNavFile() const { if (processedSize != readSize) { LOG_ERR("EBP", "Could not process all toc nav data"); free(navBuffer); - tempNavFile.close(); return false; } } free(navBuffer); + // Explicitly close() file before calling Storage.remove() tempNavFile.close(); Storage.remove(tmpNavPath.c_str()); @@ -304,10 +304,12 @@ void Epub::parseCssFiles() const { } if (!readItemContentsToStream(cssPath, tempCssFile, 1024)) { LOG_ERR("EBP", "Could not read CSS file: %s", cssPath.c_str()); + // Explicitly close() file before calling Storage.remove() tempCssFile.close(); Storage.remove(tmpCssPath.c_str()); continue; } + // Explicitly close() file before reopening for reading tempCssFile.close(); // Parse the CSS file @@ -317,6 +319,7 @@ void Epub::parseCssFiles() const { continue; } cssParser->loadFromStream(tempCssFile); + // Explicitly close() file before calling Storage.remove() tempCssFile.close(); Storage.remove(tmpCssPath.c_str()); } @@ -547,6 +550,7 @@ bool Epub::generateCoverBmp(bool cropped) const { return false; } readItemContentsToStream(coverImageHref, coverJpg, 1024); + // Explicitly close() file before reopening for reading coverJpg.close(); if (!Storage.openFileForRead("EBP", coverJpgTempPath, coverJpg)) { @@ -555,10 +559,10 @@ bool Epub::generateCoverBmp(bool cropped) const { FsFile coverBmp; if (!Storage.openFileForWrite("EBP", getCoverBmpPath(cropped), coverBmp)) { - coverJpg.close(); return false; } const bool success = JpegToBmpConverter::jpegFileToBmpStream(coverJpg, coverBmp, cropped); + // Explicitly close() files before calling Storage.remove() coverJpg.close(); coverBmp.close(); Storage.remove(coverJpgTempPath.c_str()); @@ -580,6 +584,7 @@ bool Epub::generateCoverBmp(bool cropped) const { return false; } readItemContentsToStream(coverImageHref, coverPng, 1024); + // Explicitly close() file before reopening for reading coverPng.close(); if (!Storage.openFileForRead("EBP", coverPngTempPath, coverPng)) { @@ -588,10 +593,10 @@ bool Epub::generateCoverBmp(bool cropped) const { FsFile coverBmp; if (!Storage.openFileForWrite("EBP", getCoverBmpPath(cropped), coverBmp)) { - coverPng.close(); return false; } const bool success = PngToBmpConverter::pngFileToBmpStream(coverPng, coverBmp, cropped); + // Explicitly close() files before calling Storage.remove() coverPng.close(); coverBmp.close(); Storage.remove(coverPngTempPath.c_str()); @@ -634,6 +639,7 @@ bool Epub::generateThumbBmp(int height) const { return false; } readItemContentsToStream(coverImageHref, coverJpg, 1024); + // Explicitly close() file before reopening for reading coverJpg.close(); if (!Storage.openFileForRead("EBP", coverJpgTempPath, coverJpg)) { @@ -642,7 +648,6 @@ bool Epub::generateThumbBmp(int height) const { FsFile thumbBmp; if (!Storage.openFileForWrite("EBP", getThumbBmpPath(height), thumbBmp)) { - coverJpg.close(); return false; } // Use smaller target size for Continue Reading card (half of screen: 240x400) @@ -651,6 +656,7 @@ bool Epub::generateThumbBmp(int height) const { int THUMB_TARGET_HEIGHT = height; const bool success = JpegToBmpConverter::jpegFileTo1BitBmpStreamWithSize(coverJpg, thumbBmp, THUMB_TARGET_WIDTH, THUMB_TARGET_HEIGHT); + // Explicitly close() files before calling Storage.remove() coverJpg.close(); thumbBmp.close(); Storage.remove(coverJpgTempPath.c_str()); @@ -670,6 +676,7 @@ bool Epub::generateThumbBmp(int height) const { return false; } readItemContentsToStream(coverImageHref, coverPng, 1024); + // Explicitly close() file before reopening for reading coverPng.close(); if (!Storage.openFileForRead("EBP", coverPngTempPath, coverPng)) { @@ -678,13 +685,13 @@ bool Epub::generateThumbBmp(int height) const { FsFile thumbBmp; if (!Storage.openFileForWrite("EBP", getThumbBmpPath(height), thumbBmp)) { - coverPng.close(); return false; } int THUMB_TARGET_WIDTH = height * 0.6; int THUMB_TARGET_HEIGHT = height; const bool success = PngToBmpConverter::pngFileTo1BitBmpStreamWithSize(coverPng, thumbBmp, THUMB_TARGET_WIDTH, THUMB_TARGET_HEIGHT); + // Explicitly close() files before calling Storage.remove() coverPng.close(); thumbBmp.close(); Storage.remove(coverPngTempPath.c_str()); @@ -702,7 +709,6 @@ bool Epub::generateThumbBmp(int height) const { // Write an empty bmp file to avoid generation attempts in the future FsFile thumbBmp; Storage.openFileForWrite("EBP", getThumbBmpPath(height), thumbBmp); - thumbBmp.close(); return false; } diff --git a/lib/Epub/Epub/BookMetadataCache.cpp b/lib/Epub/Epub/BookMetadataCache.cpp index ffc456cad..8985776b0 100644 --- a/lib/Epub/Epub/BookMetadataCache.cpp +++ b/lib/Epub/Epub/BookMetadataCache.cpp @@ -33,6 +33,7 @@ bool BookMetadataCache::beginContentOpfPass() { } bool BookMetadataCache::endContentOpfPass() { + // Explicit close() required: member variable persists beyond function scope spineFile.close(); return true; } @@ -44,6 +45,7 @@ bool BookMetadataCache::beginTocPass() { return false; } if (!Storage.openFileForWrite("BMC", cachePath + tmpTocBinFile, tocFile)) { + // Explicit close() required: member variable persists beyond function scope spineFile.close(); return false; } @@ -75,6 +77,7 @@ bool BookMetadataCache::beginTocPass() { } bool BookMetadataCache::endTocPass() { + // Explicit close() required: member variables persist beyond function scope tocFile.close(); spineFile.close(); @@ -103,11 +106,13 @@ bool BookMetadataCache::buildBookBin(const std::string& epubPath, const BookMeta } if (!Storage.openFileForRead("BMC", cachePath + tmpSpineBinFile, spineFile)) { + // Explicit close() required: member variable persists beyond function scope bookFile.close(); return false; } if (!Storage.openFileForRead("BMC", cachePath + tmpTocBinFile, tocFile)) { + // Explicit close() required: member variables persist beyond function scope bookFile.close(); spineFile.close(); return false; @@ -168,6 +173,7 @@ bool BookMetadataCache::buildBookBin(const std::string& epubPath, const BookMeta // Pre-open zip file to speed up size calculations if (!zip.open()) { LOG_ERR("BMC", "Could not open EPUB zip for size calculations"); + // Explicit close() required: member variables persist beyond function scope bookFile.close(); spineFile.close(); tocFile.close(); @@ -265,6 +271,7 @@ bool BookMetadataCache::buildBookBin(const std::string& epubPath, const BookMeta writeTocEntry(bookFile, tocEntry); } + // Explicit close() required: member variables persist beyond function scope bookFile.close(); spineFile.close(); tocFile.close(); @@ -373,6 +380,7 @@ bool BookMetadataCache::load() { serialization::readPod(bookFile, version); if (version != BOOK_CACHE_VERSION) { LOG_DBG("BMC", "Cache version mismatch: expected %d, got %d", BOOK_CACHE_VERSION, version); + // Explicit close() required: member variable persists beyond function scope bookFile.close(); return false; } diff --git a/lib/Epub/Epub/Section.cpp b/lib/Epub/Epub/Section.cpp index 7c0b3c12b..da74ce648 100644 --- a/lib/Epub/Epub/Section.cpp +++ b/lib/Epub/Epub/Section.cpp @@ -74,6 +74,7 @@ bool Section::loadSectionFile(const int fontId, const float lineCompression, con uint8_t version; serialization::readPod(file, version); if (version != SECTION_FILE_VERSION) { + // Explicit close() required: member variable persists beyond function scope file.close(); LOG_ERR("SCT", "Deserialization failed: Unknown version %u", version); clearCache(); @@ -103,6 +104,7 @@ bool Section::loadSectionFile(const int fontId, const float lineCompression, con viewportWidth != fileViewportWidth || viewportHeight != fileViewportHeight || hyphenationEnabled != fileHyphenationEnabled || embeddedStyle != fileEmbeddedStyle || imageRendering != fileImageRendering) { + // Explicit close() required: member variable persists beyond function scope file.close(); LOG_ERR("SCT", "Deserialization failed: Parameters do not match"); clearCache(); @@ -111,6 +113,7 @@ bool Section::loadSectionFile(const int fontId, const float lineCompression, con } serialization::readPod(file, pageCount); + // Explicit close() required: member variable persists beyond function scope file.close(); LOG_DBG("SCT", "Deserialization succeeded: %d pages", pageCount); return true; @@ -165,6 +168,7 @@ bool Section::createSectionFile(const int fontId, const float lineCompression, c } success = epub->readItemContentsToStream(localPath, tmpHtml, 1024); fileSize = tmpHtml.size(); + // Explicitly close() file before calling Storage.remove() tmpHtml.close(); // If streaming failed, remove the incomplete file immediately @@ -214,6 +218,7 @@ bool Section::createSectionFile(const int fontId, const float lineCompression, c Storage.remove(tmpHtmlPath.c_str()); if (!success) { LOG_ERR("SCT", "Failed to parse XML and build pages"); + // Explicitly close() file before calling Storage.remove() file.close(); Storage.remove(filePath.c_str()); if (cssParser) { @@ -235,6 +240,7 @@ bool Section::createSectionFile(const int fontId, const float lineCompression, c if (hasFailedLutRecords) { LOG_ERR("SCT", "Failed to write LUT due to invalid page positions"); + // Explicitly close() file before calling Storage.remove() file.close(); Storage.remove(filePath.c_str()); return false; @@ -254,6 +260,7 @@ bool Section::createSectionFile(const int fontId, const float lineCompression, c serialization::writePod(file, pageCount); serialization::writePod(file, lutOffset); serialization::writePod(file, anchorMapOffset); + // Explicit close() required: member variable persists beyond function scope file.close(); if (cssParser) { cssParser->clear(); @@ -275,6 +282,7 @@ std::unique_ptr Section::loadPageFromSectionFile() { file.seek(pagePos); auto page = Page::deserialize(file); + // Explicit close() required: member variable persists beyond function scope file.close(); return page; } @@ -290,7 +298,6 @@ std::optional Section::getPageForAnchor(const std::string& anchor) con uint32_t anchorMapOffset; serialization::readPod(f, anchorMapOffset); if (anchorMapOffset == 0 || anchorMapOffset >= fileSize) { - f.close(); return std::nullopt; } @@ -303,11 +310,9 @@ std::optional Section::getPageForAnchor(const std::string& anchor) con serialization::readString(f, key); serialization::readPod(f, page); if (key == anchor) { - f.close(); return page; } } - f.close(); return std::nullopt; } diff --git a/lib/Epub/Epub/blocks/ImageBlock.cpp b/lib/Epub/Epub/blocks/ImageBlock.cpp index 9a958d11c..1b71817a8 100644 --- a/lib/Epub/Epub/blocks/ImageBlock.cpp +++ b/lib/Epub/Epub/blocks/ImageBlock.cpp @@ -37,7 +37,6 @@ bool renderFromCache(GfxRenderer& renderer, const std::string& cachePath, int x, uint16_t cachedWidth, cachedHeight; if (cacheFile.read(&cachedWidth, 2) != 2 || cacheFile.read(&cachedHeight, 2) != 2) { - cacheFile.close(); return false; } @@ -47,7 +46,6 @@ bool renderFromCache(GfxRenderer& renderer, const std::string& cachePath, int x, if (widthDiff > 1 || heightDiff > 1) { LOG_ERR("IMG", "Cache dimension mismatch: %dx%d vs %dx%d", cachedWidth, cachedHeight, expectedWidth, expectedHeight); - cacheFile.close(); return false; } @@ -62,7 +60,6 @@ bool renderFromCache(GfxRenderer& renderer, const std::string& cachePath, int x, uint8_t* rowBuffer = (uint8_t*)malloc(bytesPerRow); if (!rowBuffer) { LOG_ERR("IMG", "Failed to allocate row buffer"); - cacheFile.close(); return false; } @@ -73,7 +70,6 @@ bool renderFromCache(GfxRenderer& renderer, const std::string& cachePath, int x, if (cacheFile.read(rowBuffer, bytesPerRow) != bytesPerRow) { LOG_ERR("IMG", "Cache read error at row %d", row); free(rowBuffer); - cacheFile.close(); return false; } @@ -89,7 +85,6 @@ bool renderFromCache(GfxRenderer& renderer, const std::string& cachePath, int x, } free(rowBuffer); - cacheFile.close(); LOG_DBG("IMG", "Cache render complete"); return true; } diff --git a/lib/Epub/Epub/css/CssParser.cpp b/lib/Epub/Epub/css/CssParser.cpp index d2e679c36..8f7237e5c 100644 --- a/lib/Epub/Epub/css/CssParser.cpp +++ b/lib/Epub/Epub/css/CssParser.cpp @@ -743,7 +743,6 @@ bool CssParser::saveToCache() const { } LOG_DBG("CSS", "Saved %u rules to cache", ruleCount); - file.close(); return true; } @@ -765,6 +764,7 @@ bool CssParser::loadFromCache() { if (file.read(&version, 1) != 1 || version != CssParser::CSS_CACHE_VERSION) { LOG_DBG("CSS", "Cache version mismatch (got %u, expected %u), removing stale cache for rebuild", version, CssParser::CSS_CACHE_VERSION); + // Explicitly close() file before calling Storage.remove() file.close(); Storage.remove((cachePath + rulesCache).c_str()); return false; @@ -773,14 +773,12 @@ bool CssParser::loadFromCache() { // Read rule count uint16_t ruleCount = 0; if (file.read(&ruleCount, sizeof(ruleCount)) != sizeof(ruleCount)) { - file.close(); return false; } if (ruleCount > MAX_RULES) { LOG_DBG("CSS", "Invalid cache rule count (%u > %zu)", ruleCount, MAX_RULES); rulesBySelector_.clear(); - file.close(); return false; } @@ -799,19 +797,16 @@ bool CssParser::loadFromCache() { uint16_t selectorLen = 0; if (!hasRemainingBytes(sizeof(selectorLen))) { rulesBySelector_.clear(); - file.close(); return false; } if (file.read(&selectorLen, sizeof(selectorLen)) != sizeof(selectorLen)) { rulesBySelector_.clear(); - file.close(); return false; } if (selectorLen == 0 || selectorLen > MAX_SELECTOR_LENGTH || !hasRemainingBytes(selectorLen)) { LOG_DBG("CSS", "Invalid selector length in cache: %u", selectorLen); rulesBySelector_.clear(); - file.close(); return false; } @@ -819,14 +814,12 @@ bool CssParser::loadFromCache() { selector.resize(selectorLen); if (file.read(&selector[0], selectorLen) != selectorLen) { rulesBySelector_.clear(); - file.close(); return false; } if (!hasRemainingBytes(CSS_FIXED_STYLE_BYTES)) { LOG_DBG("CSS", "Truncated CSS cache while reading style payload"); rulesBySelector_.clear(); - file.close(); return false; } @@ -836,28 +829,24 @@ bool CssParser::loadFromCache() { if (file.read(&enumVal, 1) != 1) { rulesBySelector_.clear(); - file.close(); return false; } style.textAlign = static_cast(enumVal); if (file.read(&enumVal, 1) != 1) { rulesBySelector_.clear(); - file.close(); return false; } style.fontStyle = static_cast(enumVal); if (file.read(&enumVal, 1) != 1) { rulesBySelector_.clear(); - file.close(); return false; } style.fontWeight = static_cast(enumVal); if (file.read(&enumVal, 1) != 1) { rulesBySelector_.clear(); - file.close(); return false; } style.textDecoration = static_cast(enumVal); @@ -880,7 +869,6 @@ bool CssParser::loadFromCache() { !readLength(style.paddingBottom) || !readLength(style.paddingLeft) || !readLength(style.paddingRight) || !readLength(style.imageHeight) || !readLength(style.imageWidth)) { rulesBySelector_.clear(); - file.close(); return false; } @@ -888,7 +876,6 @@ bool CssParser::loadFromCache() { uint8_t displayVal; if (file.read(&displayVal, 1) != 1) { rulesBySelector_.clear(); - file.close(); return false; } style.display = static_cast(displayVal); @@ -897,7 +884,6 @@ bool CssParser::loadFromCache() { uint16_t definedBits = 0; if (file.read(&definedBits, sizeof(definedBits)) != sizeof(definedBits)) { rulesBySelector_.clear(); - file.close(); return false; } style.defined.textAlign = (definedBits & 1 << 0) != 0; @@ -921,6 +907,5 @@ bool CssParser::loadFromCache() { } LOG_DBG("CSS", "Loaded %u rules from cache", ruleCount); - file.close(); return true; } diff --git a/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.cpp b/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.cpp index 368a4c60d..957a6b0a3 100644 --- a/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.cpp +++ b/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.cpp @@ -1018,7 +1018,6 @@ bool ChapterHtmlSlimParser::parseAndBuildPages() { XML_SetElementHandler(parser, nullptr, nullptr); // Clear callbacks XML_SetCharacterDataHandler(parser, nullptr); XML_ParserFree(parser); - file.close(); return false; } @@ -1030,7 +1029,6 @@ bool ChapterHtmlSlimParser::parseAndBuildPages() { XML_SetElementHandler(parser, nullptr, nullptr); // Clear callbacks XML_SetCharacterDataHandler(parser, nullptr); XML_ParserFree(parser); - file.close(); return false; } @@ -1043,7 +1041,6 @@ bool ChapterHtmlSlimParser::parseAndBuildPages() { XML_SetElementHandler(parser, nullptr, nullptr); // Clear callbacks XML_SetCharacterDataHandler(parser, nullptr); XML_ParserFree(parser); - file.close(); return false; } } while (!done); @@ -1053,7 +1050,6 @@ bool ChapterHtmlSlimParser::parseAndBuildPages() { XML_SetElementHandler(parser, nullptr, nullptr); // Clear callbacks XML_SetCharacterDataHandler(parser, nullptr); XML_ParserFree(parser); - file.close(); // Process last page if there is still text if (currentTextBlock) { diff --git a/lib/I18n/I18n.cpp b/lib/I18n/I18n.cpp index 55cf8fc49..545e14360 100644 --- a/lib/I18n/I18n.cpp +++ b/lib/I18n/I18n.cpp @@ -71,7 +71,6 @@ void I18n::loadSettings() { serialization::readPod(file, version); if (version != SETTINGS_VERSION) { Serial.printf("[I18N] Settings version mismatch\n"); - file.close(); return; } @@ -81,8 +80,6 @@ void I18n::loadSettings() { _language = static_cast(lang); Serial.printf("[I18N] Loaded language: %d\n", static_cast(_language)); } - - file.close(); } // Generate character set for a specific language diff --git a/lib/KOReaderSync/KOReaderCredentialStore.cpp b/lib/KOReaderSync/KOReaderCredentialStore.cpp index 574f2b8e9..ce7132df2 100644 --- a/lib/KOReaderSync/KOReaderCredentialStore.cpp +++ b/lib/KOReaderSync/KOReaderCredentialStore.cpp @@ -82,7 +82,6 @@ bool KOReaderCredentialStore::loadFromBinaryFile() { serialization::readPod(file, version); if (version != KOREADER_FILE_VERSION) { LOG_DBG("KRS", "Unknown file version: %u", version); - file.close(); return false; } @@ -113,7 +112,6 @@ bool KOReaderCredentialStore::loadFromBinaryFile() { matchMethod = DocumentMatchMethod::FILENAME; } - file.close(); LOG_DBG("KRS", "Loaded KOReader credentials from binary for user: %s", username.c_str()); return true; } diff --git a/lib/KOReaderSync/KOReaderDocumentId.cpp b/lib/KOReaderSync/KOReaderDocumentId.cpp index efb18d1b7..887214191 100644 --- a/lib/KOReaderSync/KOReaderDocumentId.cpp +++ b/lib/KOReaderSync/KOReaderDocumentId.cpp @@ -84,8 +84,6 @@ std::string KOReaderDocumentId::calculate(const std::string& filePath) { } } - file.close(); - // Calculate final hash md5.calculate(); std::string result = md5.toString().c_str(); diff --git a/lib/Txt/Txt.cpp b/lib/Txt/Txt.cpp index 83ef123cc..0209923a8 100644 --- a/lib/Txt/Txt.cpp +++ b/lib/Txt/Txt.cpp @@ -120,7 +120,6 @@ bool Txt::generateCoverBmp() const { return false; } if (!Storage.openFileForWrite("TXT", getCoverBmpPath(), dst)) { - src.close(); return false; } uint8_t buffer[1024]; @@ -128,8 +127,6 @@ bool Txt::generateCoverBmp() const { size_t bytesRead = src.read(buffer, sizeof(buffer)); dst.write(buffer, bytesRead); } - src.close(); - dst.close(); LOG_DBG("TXT", "Copied BMP cover to cache"); return true; } else if (FsHelpers::hasJpgExtension(coverImagePath)) { @@ -140,12 +137,9 @@ bool Txt::generateCoverBmp() const { return false; } if (!Storage.openFileForWrite("TXT", getCoverBmpPath(), coverBmp)) { - coverJpg.close(); return false; } const bool success = JpegToBmpConverter::jpegFileToBmpStream(coverJpg, coverBmp); - coverJpg.close(); - coverBmp.close(); if (!success) { LOG_ERR("TXT", "Failed to generate BMP from JPG cover image"); @@ -172,12 +166,9 @@ bool Txt::readContent(uint8_t* buffer, size_t offset, size_t length) const { } if (!file.seek(offset)) { - file.close(); return false; } size_t bytesRead = file.read(buffer, length); - file.close(); - return bytesRead > 0; } diff --git a/lib/Xtc/Xtc.cpp b/lib/Xtc/Xtc.cpp index 71e5f28c2..893e8169c 100644 --- a/lib/Xtc/Xtc.cpp +++ b/lib/Xtc/Xtc.cpp @@ -199,7 +199,6 @@ bool Xtc::generateCoverBmp() const { uint8_t* rowBuffer = static_cast(malloc(dstRowSize)); if (!rowBuffer) { free(pageBuffer); - coverBmp.close(); return false; } @@ -255,7 +254,6 @@ bool Xtc::generateCoverBmp() const { } } - coverBmp.close(); free(pageBuffer); LOG_DBG("XTC", "Generated cover BMP: %s", getCoverBmpPath().c_str()); @@ -316,9 +314,7 @@ bool Xtc::generateThumbBmp(int height) const { size_t bytesRead = src.read(buffer, sizeof(buffer)); dst.write(buffer, bytesRead); } - dst.close(); } - src.close(); } LOG_DBG("XTC", "Copied cover to thumb (no scaling needed)"); return Storage.exists(getThumbBmpPath(height).c_str()); @@ -372,7 +368,6 @@ bool Xtc::generateThumbBmp(int height) const { uint8_t* rowBuffer = static_cast(malloc(rowSize)); if (!rowBuffer) { free(pageBuffer); - thumbBmp.close(); return false; } @@ -479,7 +474,6 @@ bool Xtc::generateThumbBmp(int height) const { } free(rowBuffer); - thumbBmp.close(); free(pageBuffer); LOG_DBG("XTC", "Generated thumb BMP (%dx%d): %s", thumbWidth, thumbHeight, getThumbBmpPath(height).c_str()); diff --git a/lib/Xtc/Xtc/XtcParser.cpp b/lib/Xtc/Xtc/XtcParser.cpp index 12e8a61db..183afea92 100644 --- a/lib/Xtc/Xtc/XtcParser.cpp +++ b/lib/Xtc/Xtc/XtcParser.cpp @@ -43,6 +43,7 @@ XtcError XtcParser::open(const char* filepath) { m_lastError = readHeader(); if (m_lastError != XtcError::OK) { LOG_DBG("XTC", "Failed to read header: %s", errorToString(m_lastError)); + // Explicit close() required: member variable persists beyond function scope m_file.close(); return m_lastError; } @@ -52,12 +53,14 @@ XtcError XtcParser::open(const char* filepath) { m_lastError = readTitle(); if (m_lastError != XtcError::OK) { LOG_DBG("XTC", "Failed to read title: %s", errorToString(m_lastError)); + // Explicit close() required: member variable persists beyond function scope m_file.close(); return m_lastError; } m_lastError = readAuthor(); if (m_lastError != XtcError::OK) { LOG_DBG("XTC", "Failed to read author: %s", errorToString(m_lastError)); + // Explicit close() required: member variable persists beyond function scope m_file.close(); return m_lastError; } @@ -67,6 +70,7 @@ XtcError XtcParser::open(const char* filepath) { m_lastError = readPageTable(); if (m_lastError != XtcError::OK) { LOG_DBG("XTC", "Failed to read page table: %s", errorToString(m_lastError)); + // Explicit close() required: member variable persists beyond function scope m_file.close(); return m_lastError; } @@ -75,6 +79,7 @@ XtcError XtcParser::open(const char* filepath) { m_lastError = readChapters(); if (m_lastError != XtcError::OK) { LOG_DBG("XTC", "Failed to read chapters: %s", errorToString(m_lastError)); + // Explicit close() required: member variable persists beyond function scope m_file.close(); return m_lastError; } @@ -86,6 +91,7 @@ XtcError XtcParser::open(const char* filepath) { void XtcParser::close() { if (m_isOpen) { + // Explicit close() required: member variable persists beyond function scope m_file.close(); m_isOpen = false; } diff --git a/lib/ZipFile/ZipFile.cpp b/lib/ZipFile/ZipFile.cpp index bdf5c0e25..fe59dfaa0 100644 --- a/lib/ZipFile/ZipFile.cpp +++ b/lib/ZipFile/ZipFile.cpp @@ -278,6 +278,7 @@ bool ZipFile::open() { bool ZipFile::close() { if (file) { + // Explicit close() required: member variable persists beyond function scope file.close(); } lastCentralDirPos = 0; diff --git a/src/CrossPointSettings.cpp b/src/CrossPointSettings.cpp index aca87bdc5..4ba71cfd7 100644 --- a/src/CrossPointSettings.cpp +++ b/src/CrossPointSettings.cpp @@ -126,7 +126,6 @@ bool CrossPointSettings::loadFromBinaryFile() { serialization::readPod(inputFile, version); if (version != SETTINGS_FILE_VERSION) { LOG_ERR("CPS", "Deserialization failed: Unknown version %u", version); - inputFile.close(); return false; } @@ -220,7 +219,6 @@ bool CrossPointSettings::loadFromBinaryFile() { applyLegacyFrontButtonLayout(*this); } - inputFile.close(); LOG_DBG("CPS", "Settings loaded from binary file"); return true; } diff --git a/src/CrossPointState.cpp b/src/CrossPointState.cpp index af8bdda59..7d084da6e 100644 --- a/src/CrossPointState.cpp +++ b/src/CrossPointState.cpp @@ -55,7 +55,6 @@ bool CrossPointState::loadFromBinaryFile() { serialization::readPod(inputFile, version); if (version > STATE_FILE_VERSION) { LOG_ERR("CPS", "Deserialization failed: Unknown version %u", version); - inputFile.close(); return false; } @@ -76,6 +75,5 @@ bool CrossPointState::loadFromBinaryFile() { lastSleepFromReader = false; } - inputFile.close(); return true; } diff --git a/src/RecentBooksStore.cpp b/src/RecentBooksStore.cpp index f5a2c0483..b34f8523b 100644 --- a/src/RecentBooksStore.cpp +++ b/src/RecentBooksStore.cpp @@ -163,6 +163,7 @@ bool RecentBooksStore::loadFromBinaryFile() { } if (omitted > 0) { + // Explicitly close() file before saveToFile() rewrites the same file inputFile.close(); saveToFile(); LOG_DBG("RBS", "Omitted %u recent book(s) with missing title", omitted); @@ -170,11 +171,9 @@ bool RecentBooksStore::loadFromBinaryFile() { } } else { LOG_ERR("RBS", "Deserialization failed: Unknown version %u", version); - inputFile.close(); return false; } - inputFile.close(); LOG_DBG("RBS", "Recent books loaded from binary file (%d entries)", static_cast(recentBooks.size())); return true; } diff --git a/src/WifiCredentialStore.cpp b/src/WifiCredentialStore.cpp index a95be3142..82102898d 100644 --- a/src/WifiCredentialStore.cpp +++ b/src/WifiCredentialStore.cpp @@ -76,7 +76,6 @@ bool WifiCredentialStore::loadFromBinaryFile() { serialization::readPod(file, version); if (version > WIFI_FILE_VERSION) { LOG_DBG("WCS", "Unknown file version: %u", version); - file.close(); return false; } @@ -98,7 +97,6 @@ bool WifiCredentialStore::loadFromBinaryFile() { credentials.push_back(cred); } - file.close(); // LOG_DBG("WCS", "Loaded %zu WiFi credentials from binary file", credentials.size()); return true; } diff --git a/src/activities/boot_sleep/SleepActivity.cpp b/src/activities/boot_sleep/SleepActivity.cpp index f89e7c3b5..64fa11d91 100644 --- a/src/activities/boot_sleep/SleepActivity.cpp +++ b/src/activities/boot_sleep/SleepActivity.cpp @@ -43,7 +43,6 @@ void SleepActivity::renderCustomSleepScreen() const { if (dir && dir.isDirectory()) { sleepDir = "/.sleep"; } else { - if (dir) dir.close(); dir = Storage.open("/sleep"); if (dir && dir.isDirectory()) { sleepDir = "/sleep"; @@ -56,29 +55,24 @@ void SleepActivity::renderCustomSleepScreen() const { // collect all valid BMP files for (auto file = dir.openNextFile(); file; file = dir.openNextFile()) { if (file.isDirectory()) { - file.close(); continue; } file.getName(name, sizeof(name)); auto filename = std::string(name); if (filename[0] == '.') { - file.close(); continue; } if (!FsHelpers::hasBmpExtension(filename)) { LOG_DBG("SLP", "Skipping non-.bmp file name: %s", name); - file.close(); continue; } Bitmap bitmap(file); if (bitmap.parseHeaders() != BmpReaderError::Ok) { LOG_DBG("SLP", "Skipping invalid BMP file: %s", name); - file.close(); continue; } files.emplace_back(filename); - file.close(); } const auto numFiles = files.size(); if (numFiles > 0) { @@ -98,16 +92,11 @@ void SleepActivity::renderCustomSleepScreen() const { Bitmap bitmap(file, true); if (bitmap.parseHeaders() == BmpReaderError::Ok) { renderBitmapSleepScreen(bitmap); - file.close(); - dir.close(); return; } - file.close(); } } } - if (dir) dir.close(); - // Look for sleep.bmp on the root of the sd card to determine if we should // render a custom sleep screen instead of the default. FsFile file; @@ -116,10 +105,8 @@ void SleepActivity::renderCustomSleepScreen() const { if (bitmap.parseHeaders() == BmpReaderError::Ok) { LOG_DBG("SLP", "Loading: /sleep.bmp"); renderBitmapSleepScreen(bitmap); - file.close(); return; } - file.close(); } renderDefaultSleepScreen(); @@ -286,10 +273,8 @@ void SleepActivity::renderCoverSleepScreen() const { if (bitmap.parseHeaders() == BmpReaderError::Ok) { LOG_DBG("SLP", "Rendering sleep cover: %s", coverBmpPath.c_str()); renderBitmapSleepScreen(bitmap); - file.close(); return; } - file.close(); } return (this->*renderNoCoverSleepScreen)(); diff --git a/src/activities/home/FileBrowserActivity.cpp b/src/activities/home/FileBrowserActivity.cpp index 6b16bf8ba..1a4b45513 100644 --- a/src/activities/home/FileBrowserActivity.cpp +++ b/src/activities/home/FileBrowserActivity.cpp @@ -75,7 +75,6 @@ void FileBrowserActivity::loadFiles() { auto root = Storage.open(basepath.c_str()); if (!root || !root.isDirectory()) { - if (root) root.close(); return; } @@ -85,7 +84,6 @@ void FileBrowserActivity::loadFiles() { for (auto file = root.openNextFile(); file; file = root.openNextFile()) { file.getName(name, sizeof(name)); if ((!SETTINGS.showHiddenFiles && name[0] == '.') || strcmp(name, "System Volume Information") == 0) { - file.close(); continue; } @@ -99,9 +97,7 @@ void FileBrowserActivity::loadFiles() { files.emplace_back(filename); } } - file.close(); } - root.close(); sortFileList(files); } @@ -115,7 +111,6 @@ void FileBrowserActivity::onEnter() { basepath = "/"; loadFiles(); } else if (!root.isDirectory()) { - root.close(); lockLongPressBack = mappedInput.isPressed(MappedInputManager::Button::Back); const std::string oldPath = basepath; @@ -126,7 +121,6 @@ void FileBrowserActivity::onEnter() { const std::string fileName = oldPath.substr(pos + 1); selectorIndex = findEntry(fileName); } else { - root.close(); loadFiles(); } diff --git a/src/activities/reader/EpubReaderActivity.cpp b/src/activities/reader/EpubReaderActivity.cpp index f6d58bfc4..21e6f82e2 100644 --- a/src/activities/reader/EpubReaderActivity.cpp +++ b/src/activities/reader/EpubReaderActivity.cpp @@ -69,7 +69,6 @@ void EpubReaderActivity::onEnter() { if (dataSize == 6) { cachedChapterTotalPageCount = data[4] + (data[5] << 8); } - f.close(); } // We may want a better condition to detect if we are opening for the first time. // This will trigger if the book is re-opened at Chapter 0. @@ -696,7 +695,6 @@ void EpubReaderActivity::saveProgress(int spineIndex, int currentPage, int pageC data[4] = pageCount & 0xFF; data[5] = (pageCount >> 8) & 0xFF; f.write(data, 6); - f.close(); LOG_DBG("ERS", "Progress saved: Chapter %d, Page %d", spineIndex, currentPage); } else { LOG_ERR("ERS", "Could not save progress!"); diff --git a/src/activities/reader/TxtReaderActivity.cpp b/src/activities/reader/TxtReaderActivity.cpp index 6bc3ba5ad..fba7bc0bc 100644 --- a/src/activities/reader/TxtReaderActivity.cpp +++ b/src/activities/reader/TxtReaderActivity.cpp @@ -405,7 +405,6 @@ void TxtReaderActivity::saveProgress() const { data[2] = 0; data[3] = 0; f.write(data, 4); - f.close(); } } @@ -423,7 +422,6 @@ void TxtReaderActivity::loadProgress() { } LOG_DBG("TRS", "Loaded progress: page %d/%d", currentPage, totalPages); } - f.close(); } } @@ -452,7 +450,6 @@ bool TxtReaderActivity::loadPageIndexCache() { serialization::readPod(f, magic); if (magic != CACHE_MAGIC) { LOG_DBG("TRS", "Cache magic mismatch, rebuilding"); - f.close(); return false; } @@ -460,7 +457,6 @@ bool TxtReaderActivity::loadPageIndexCache() { serialization::readPod(f, version); if (version != CACHE_VERSION) { LOG_DBG("TRS", "Cache version mismatch (%d != %d), rebuilding", version, CACHE_VERSION); - f.close(); return false; } @@ -468,7 +464,6 @@ bool TxtReaderActivity::loadPageIndexCache() { serialization::readPod(f, fileSize); if (fileSize != txt->getFileSize()) { LOG_DBG("TRS", "Cache file size mismatch, rebuilding"); - f.close(); return false; } @@ -476,7 +471,6 @@ bool TxtReaderActivity::loadPageIndexCache() { serialization::readPod(f, cachedWidth); if (cachedWidth != viewportWidth) { LOG_DBG("TRS", "Cache viewport width mismatch, rebuilding"); - f.close(); return false; } @@ -484,7 +478,6 @@ bool TxtReaderActivity::loadPageIndexCache() { serialization::readPod(f, cachedLines); if (cachedLines != linesPerPage) { LOG_DBG("TRS", "Cache lines per page mismatch, rebuilding"); - f.close(); return false; } @@ -492,7 +485,6 @@ bool TxtReaderActivity::loadPageIndexCache() { serialization::readPod(f, fontId); if (fontId != cachedFontId) { LOG_DBG("TRS", "Cache font ID mismatch (%d != %d), rebuilding", fontId, cachedFontId); - f.close(); return false; } @@ -500,7 +492,6 @@ bool TxtReaderActivity::loadPageIndexCache() { serialization::readPod(f, margin); if (margin != cachedScreenMargin) { LOG_DBG("TRS", "Cache screen margin mismatch, rebuilding"); - f.close(); return false; } @@ -508,7 +499,6 @@ bool TxtReaderActivity::loadPageIndexCache() { serialization::readPod(f, alignment); if (alignment != cachedParagraphAlignment) { LOG_DBG("TRS", "Cache paragraph alignment mismatch, rebuilding"); - f.close(); return false; } @@ -525,7 +515,6 @@ bool TxtReaderActivity::loadPageIndexCache() { pageOffsets.push_back(offset); } - f.close(); totalPages = pageOffsets.size(); LOG_DBG("TRS", "Loaded page index cache: %d pages", totalPages); return true; @@ -555,6 +544,5 @@ void TxtReaderActivity::savePageIndexCache() const { serialization::writePod(f, static_cast(offset)); } - f.close(); LOG_DBG("TRS", "Saved page index cache: %d pages", totalPages); } diff --git a/src/components/themes/BaseTheme.cpp b/src/components/themes/BaseTheme.cpp index 055b37a7a..6f7f84e40 100644 --- a/src/components/themes/BaseTheme.cpp +++ b/src/components/themes/BaseTheme.cpp @@ -422,7 +422,6 @@ void BaseTheme::drawRecentBookCover(GfxRenderer& renderer, Rect rect, const std: bookWidth = rect.width / 2; // Fallback } } - file.close(); } } @@ -476,7 +475,6 @@ void BaseTheme::drawRecentBookCover(GfxRenderer& renderer, Rect rect, const std: renderer.drawRect(bookX + 2, bookY + 2, bookWidth - 4, bookHeight - 4); } } - file.close(); } } diff --git a/src/network/CrossPointWebServer.cpp b/src/network/CrossPointWebServer.cpp index a745783d6..d18eebd13 100644 --- a/src/network/CrossPointWebServer.cpp +++ b/src/network/CrossPointWebServer.cpp @@ -193,6 +193,7 @@ void CrossPointWebServer::begin() { } void CrossPointWebServer::abortWsUpload(const char* tag) { + // Explicit close() required: file-scope global persists beyond function scope wsUploadFile.close(); String filePath = wsUploadPath; if (!filePath.endsWith("/")) filePath += "/"; @@ -1342,6 +1343,7 @@ void CrossPointWebServer::onWebSocketEvent(uint8_t num, WStype_t type, uint8_t* // Zero-byte upload: complete immediately without waiting for BIN frames if (wsUploadSize == 0) { + // Explicit close() required: file-scope global persists beyond function scope wsUploadFile.close(); wsLastCompleteName = wsUploadFileName; wsLastCompleteSize = 0; @@ -1397,6 +1399,7 @@ void CrossPointWebServer::onWebSocketEvent(uint8_t num, WStype_t type, uint8_t* // Check if upload complete if (wsUploadReceived >= wsUploadSize) { + // Explicit close() required: file-scope global persists beyond function scope wsUploadFile.close(); wsUploadInProgress = false; wsUploadClientNum = 255; diff --git a/src/util/ScreenshotUtil.cpp b/src/util/ScreenshotUtil.cpp index 1a564a61b..a152488d7 100644 --- a/src/util/ScreenshotUtil.cpp +++ b/src/util/ScreenshotUtil.cpp @@ -70,6 +70,7 @@ bool ScreenshotUtil::saveFramebufferAsBmp(const char* filename, const uint8_t* f } if (write_error) { + // Explicitly close() file before calling Storage.remove() file.close(); Storage.remove(filename); return false; @@ -80,6 +81,7 @@ bool ScreenshotUtil::saveFramebufferAsBmp(const char* filename, const uint8_t* f constexpr size_t kMaxRowSize = 68; if (rowSizePadded > kMaxRowSize) { LOG_ERR("SCR", "Row size %u exceeds buffer capacity", rowSizePadded); + // Explicitly close() file before calling Storage.remove() file.close(); Storage.remove(filename); return false; @@ -106,6 +108,7 @@ bool ScreenshotUtil::saveFramebufferAsBmp(const char* filename, const uint8_t* f memset(rowBuffer, 0, rowSizePadded); // Clear the buffer for the next row } + // Explicitly close() file before calling Storage.remove() file.close(); if (write_error) {