refactor: Drop FsFile alias, use HalFile in downstream code (#2141)
This commit is contained in:
+4
-5
@@ -152,20 +152,19 @@ These flags in `platformio.ini` fundamentally affect firmware behavior:
|
||||
#include <HalStorage.h>
|
||||
|
||||
// Use Storage singleton (defined via macro)
|
||||
FsFile file;
|
||||
HalFile file;
|
||||
if (Storage.openFileForRead("MODULE", "/path/to/file.bin", file)) {
|
||||
// Read from file
|
||||
// No file.close() needed — DESTRUCTOR_CLOSES_FILE=1 handles it at scope exit
|
||||
}
|
||||
```
|
||||
|
||||
**Usage**: See example above. Uses `FsFile` (SdFat), NOT Arduino `File`. Do NOT add `file.close()` for local variables (see DESTRUCTOR_CLOSES_FILE above).
|
||||
**Usage**: Use `HalFile` (the mutex-wrapping handle), NOT raw SdFat `FsFile` or Arduino `File`. Do NOT add `file.close()` for local variables (see DESTRUCTOR_CLOSES_FILE above).
|
||||
|
||||
**SdFat is not thread-safe; all SD access MUST go through HalStorage**:
|
||||
- SdFat's `SdSpiCard` tracks SPI bus state with an unsynchronized `m_spiActive` bool. Two tasks calling SdFat concurrently can confuse that state machine and end with one task calling `SPIClass::endTransaction()` against a paramLock the *other* task is holding. That trips FreeRTOS's `xTaskPriorityDisinherit` assert (`tasks.c:5156, pxTCB == pxCurrentTCBs[0]`) and panics the system. See SdFat issue #518.
|
||||
- `HalStorage` serializes everything via `storageMutex`. Downstream code includes `<HalStorage.h>`, which transparently `using FsFile = HalFile;`; every method call (read, write, seek, close) takes the mutex. `HalFile`'s destructor also takes the mutex before letting the underlying SdFat `FsFile` close.
|
||||
- **Never** call into `SdFat` / `SdSpiCard` / `FsBaseFile` / `SDCardManager` directly. **Never** define `HAL_STORAGE_IMPL` outside `HalStorage.cpp`; that disables the `FsFile -> HalFile` typedef and you'll get a raw SdFat handle that bypasses the mutex.
|
||||
- If you're storing a raw `FsFile` in a place that won't transitively include `<HalStorage.h>` (rare), include the header explicitly so the typedef applies.
|
||||
- `HalStorage` serializes everything via `storageMutex`. Downstream code uses `HalFile` (declared in `<HalStorage.h>`); every method call (read, write, seek, close) takes the mutex. `HalFile`'s destructor also takes the mutex before letting the underlying SdFat `FsFile` close.
|
||||
- **Never** call into `SdFat` / `SdSpiCard` / `FsBaseFile` / `SDCardManager` / raw `FsFile` directly — that bypasses the mutex.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -168,7 +168,7 @@ bool SdCardFont::loadStyleKernLigatureData(PerStyle& s) {
|
||||
return true;
|
||||
}
|
||||
|
||||
FsFile file;
|
||||
HalFile file;
|
||||
if (!Storage.openFileForRead("SDCF", filePath_, file)) {
|
||||
LOG_ERR("SDCF", "Failed to open .cpfont for kern/lig: %s", filePath_);
|
||||
return false;
|
||||
@@ -345,7 +345,7 @@ bool SdCardFont::buildMiniKernMatrix(PerStyle& s, const uint32_t* codepoints, ui
|
||||
// Step 6: read the full matrix's rows for each used left class, keep only
|
||||
// columns for used right classes. One SD seek + one read per used left class;
|
||||
// a row is kernRightClassCount bytes (~200 for Literata).
|
||||
FsFile file;
|
||||
HalFile file;
|
||||
if (!Storage.openFileForRead("SDCF", filePath_, file)) {
|
||||
LOG_ERR("SDCF", "Failed to open .cpfont for mini kern: %s", filePath_);
|
||||
freeStyleMiniKern(s);
|
||||
@@ -425,7 +425,7 @@ bool SdCardFont::load(const char* path) {
|
||||
strncpy(filePath_, path, sizeof(filePath_) - 1);
|
||||
filePath_[sizeof(filePath_) - 1] = '\0';
|
||||
|
||||
FsFile file;
|
||||
HalFile file;
|
||||
if (!Storage.openFileForRead("SDCF", path, file)) {
|
||||
LOG_ERR("SDCF", "Failed to open .cpfont: %s", path);
|
||||
return false;
|
||||
@@ -798,7 +798,7 @@ int SdCardFont::prewarmStyle(uint8_t styleIdx, const uint32_t* codepoints, uint3
|
||||
std::sort(readOrder, readOrder + validCount,
|
||||
[&](uint32_t a, uint32_t b) { return mappings[a].globalIndex < mappings[b].globalIndex; });
|
||||
|
||||
FsFile file;
|
||||
HalFile file;
|
||||
if (!Storage.openFileForRead("SDCF", filePath_, file)) {
|
||||
LOG_ERR("SDCF", "Failed to reopen .cpfont for prewarm (style %u)", styleIdx);
|
||||
delete[] readOrder;
|
||||
@@ -1104,7 +1104,7 @@ int SdCardFont::fetchAdvancesForCodepoints(uint32_t* codepoints, uint32_t cpCoun
|
||||
[](const CpIdx& a, const CpIdx& b) { return a.glyphIndex < b.glyphIndex; });
|
||||
|
||||
// Open file once and read advanceX for each needed glyph.
|
||||
FsFile file;
|
||||
HalFile file;
|
||||
if (!Storage.openFileForRead("SDCF", filePath_, file)) {
|
||||
LOG_ERR("SDCF", "buildAdvanceTable: failed to open .cpfont for style %u", si);
|
||||
continue;
|
||||
@@ -1277,7 +1277,7 @@ const EpdGlyph* SdCardFont::onGlyphMiss(void* ctx, uint32_t codepoint) {
|
||||
bool wasAtCapacity = (self->overflowCount_ == OVERFLOW_CAPACITY);
|
||||
|
||||
// Read glyph metadata into temporary
|
||||
FsFile file;
|
||||
HalFile file;
|
||||
if (!Storage.openFileForRead("SDCF", self->filePath_, file)) {
|
||||
LOG_ERR("SDCF", "Overflow: failed to open .cpfont");
|
||||
return nullptr;
|
||||
|
||||
@@ -77,12 +77,12 @@ bool SdCardFontRegistry::parseFilename(const char* filename, uint8_t& size, uint
|
||||
}
|
||||
|
||||
void SdCardFontRegistry::scanDirectory(const char* dirPath, SdCardFontFamilyInfo& family) {
|
||||
FsFile dir = Storage.open(dirPath);
|
||||
HalFile dir = Storage.open(dirPath);
|
||||
if (!dir || !dir.isDirectory()) return;
|
||||
|
||||
char nameBuffer[128];
|
||||
while (true) {
|
||||
FsFile entry = dir.openNextFile();
|
||||
HalFile entry = dir.openNextFile();
|
||||
if (!entry) break;
|
||||
if (entry.isDirectory()) {
|
||||
entry.close();
|
||||
@@ -126,7 +126,7 @@ void SdCardFontRegistry::scanDirectory(const char* dirPath, SdCardFontFamilyInfo
|
||||
// Skips families whose names already exist in `out` (de-duplicates between
|
||||
// the hidden and visible roots — first scan wins).
|
||||
void SdCardFontRegistry::scanRoot(const char* rootPath, std::vector<SdCardFontFamilyInfo>& out) {
|
||||
FsFile root = Storage.open(rootPath);
|
||||
HalFile root = Storage.open(rootPath);
|
||||
if (!root) {
|
||||
LOG_DBG("SDREG", "Fonts directory not found: %s", rootPath);
|
||||
return;
|
||||
@@ -138,7 +138,7 @@ void SdCardFontRegistry::scanRoot(const char* rootPath, std::vector<SdCardFontFa
|
||||
|
||||
char nameBuffer[128];
|
||||
while (true) {
|
||||
FsFile entry = root.openNextFile();
|
||||
HalFile entry = root.openNextFile();
|
||||
if (!entry) break;
|
||||
if (entry.isDirectory()) {
|
||||
entry.getName(nameBuffer, sizeof(nameBuffer));
|
||||
|
||||
+12
-12
@@ -150,7 +150,7 @@ bool Epub::parseTocNcxFile() const {
|
||||
LOG_DBG("EBP", "Parsing toc ncx file: %s", tocNcxItem.c_str());
|
||||
|
||||
const auto tmpNcxPath = getCachePath() + "/toc.ncx";
|
||||
FsFile tempNcxFile;
|
||||
HalFile tempNcxFile;
|
||||
if (!Storage.openFileForWrite("EBP", tmpNcxPath, tempNcxFile)) {
|
||||
return false;
|
||||
}
|
||||
@@ -206,7 +206,7 @@ bool Epub::parseTocNavFile() const {
|
||||
LOG_DBG("EBP", "Parsing toc nav file: %s", tocNavItem.c_str());
|
||||
|
||||
const auto tmpNavPath = getCachePath() + "/toc.nav";
|
||||
FsFile tempNavFile;
|
||||
HalFile tempNavFile;
|
||||
if (!Storage.openFileForWrite("EBP", tmpNavPath, tempNavFile)) {
|
||||
return false;
|
||||
}
|
||||
@@ -297,7 +297,7 @@ void Epub::parseCssFiles() const {
|
||||
|
||||
// Extract CSS file to temp location
|
||||
const auto tmpCssPath = getCachePath() + "/.tmp.css";
|
||||
FsFile tempCssFile;
|
||||
HalFile tempCssFile;
|
||||
if (!Storage.openFileForWrite("EBP", tmpCssPath, tempCssFile)) {
|
||||
LOG_ERR("EBP", "Could not create temp CSS file");
|
||||
continue;
|
||||
@@ -545,7 +545,7 @@ bool Epub::generateCoverBmp(bool cropped) const {
|
||||
LOG_DBG("EBP", "Generating BMP from JPG cover image (%s mode)", cropped ? "cropped" : "fit");
|
||||
const auto coverJpgTempPath = getCachePath() + "/.cover.jpg";
|
||||
|
||||
FsFile coverJpg;
|
||||
HalFile coverJpg;
|
||||
if (!Storage.openFileForWrite("EBP", coverJpgTempPath, coverJpg)) {
|
||||
return false;
|
||||
}
|
||||
@@ -557,7 +557,7 @@ bool Epub::generateCoverBmp(bool cropped) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
FsFile coverBmp;
|
||||
HalFile coverBmp;
|
||||
if (!Storage.openFileForWrite("EBP", getCoverBmpPath(cropped), coverBmp)) {
|
||||
return false;
|
||||
}
|
||||
@@ -579,7 +579,7 @@ bool Epub::generateCoverBmp(bool cropped) const {
|
||||
LOG_DBG("EBP", "Generating BMP from PNG cover image (%s mode)", cropped ? "cropped" : "fit");
|
||||
const auto coverPngTempPath = getCachePath() + "/.cover.png";
|
||||
|
||||
FsFile coverPng;
|
||||
HalFile coverPng;
|
||||
if (!Storage.openFileForWrite("EBP", coverPngTempPath, coverPng)) {
|
||||
return false;
|
||||
}
|
||||
@@ -591,7 +591,7 @@ bool Epub::generateCoverBmp(bool cropped) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
FsFile coverBmp;
|
||||
HalFile coverBmp;
|
||||
if (!Storage.openFileForWrite("EBP", getCoverBmpPath(cropped), coverBmp)) {
|
||||
return false;
|
||||
}
|
||||
@@ -634,7 +634,7 @@ bool Epub::generateThumbBmp(int height) const {
|
||||
LOG_DBG("EBP", "Generating thumb BMP from JPG cover image");
|
||||
const auto coverJpgTempPath = getCachePath() + "/.cover.jpg";
|
||||
|
||||
FsFile coverJpg;
|
||||
HalFile coverJpg;
|
||||
if (!Storage.openFileForWrite("EBP", coverJpgTempPath, coverJpg)) {
|
||||
return false;
|
||||
}
|
||||
@@ -646,7 +646,7 @@ bool Epub::generateThumbBmp(int height) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
FsFile thumbBmp;
|
||||
HalFile thumbBmp;
|
||||
if (!Storage.openFileForWrite("EBP", getThumbBmpPath(height), thumbBmp)) {
|
||||
return false;
|
||||
}
|
||||
@@ -671,7 +671,7 @@ bool Epub::generateThumbBmp(int height) const {
|
||||
LOG_DBG("EBP", "Generating thumb BMP from PNG cover image");
|
||||
const auto coverPngTempPath = getCachePath() + "/.cover.png";
|
||||
|
||||
FsFile coverPng;
|
||||
HalFile coverPng;
|
||||
if (!Storage.openFileForWrite("EBP", coverPngTempPath, coverPng)) {
|
||||
return false;
|
||||
}
|
||||
@@ -683,7 +683,7 @@ bool Epub::generateThumbBmp(int height) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
FsFile thumbBmp;
|
||||
HalFile thumbBmp;
|
||||
if (!Storage.openFileForWrite("EBP", getThumbBmpPath(height), thumbBmp)) {
|
||||
return false;
|
||||
}
|
||||
@@ -707,7 +707,7 @@ bool Epub::generateThumbBmp(int height) const {
|
||||
}
|
||||
|
||||
// Write an empty bmp file to avoid generation attempts in the future
|
||||
FsFile thumbBmp;
|
||||
HalFile thumbBmp;
|
||||
Storage.openFileForWrite("EBP", getThumbBmpPath(height), thumbBmp);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -292,7 +292,7 @@ bool BookMetadataCache::cleanupTmpFiles() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t BookMetadataCache::writeSpineEntry(FsFile& file, const SpineEntry& entry) const {
|
||||
uint32_t BookMetadataCache::writeSpineEntry(HalFile& file, const SpineEntry& entry) const {
|
||||
const uint32_t pos = file.position();
|
||||
serialization::writeString(file, entry.href);
|
||||
serialization::writePod(file, entry.cumulativeSize);
|
||||
@@ -300,7 +300,7 @@ uint32_t BookMetadataCache::writeSpineEntry(FsFile& file, const SpineEntry& entr
|
||||
return pos;
|
||||
}
|
||||
|
||||
uint32_t BookMetadataCache::writeTocEntry(FsFile& file, const TocEntry& entry) const {
|
||||
uint32_t BookMetadataCache::writeTocEntry(HalFile& file, const TocEntry& entry) const {
|
||||
const uint32_t pos = file.position();
|
||||
serialization::writeString(file, entry.title);
|
||||
serialization::writeString(file, entry.href);
|
||||
@@ -438,7 +438,7 @@ BookMetadataCache::TocEntry BookMetadataCache::getTocEntry(const int index) {
|
||||
return readTocEntry(bookFile);
|
||||
}
|
||||
|
||||
BookMetadataCache::SpineEntry BookMetadataCache::readSpineEntry(FsFile& file) const {
|
||||
BookMetadataCache::SpineEntry BookMetadataCache::readSpineEntry(HalFile& file) const {
|
||||
SpineEntry entry;
|
||||
serialization::readString(file, entry.href);
|
||||
serialization::readPod(file, entry.cumulativeSize);
|
||||
@@ -446,7 +446,7 @@ BookMetadataCache::SpineEntry BookMetadataCache::readSpineEntry(FsFile& file) co
|
||||
return entry;
|
||||
}
|
||||
|
||||
BookMetadataCache::TocEntry BookMetadataCache::readTocEntry(FsFile& file) const {
|
||||
BookMetadataCache::TocEntry BookMetadataCache::readTocEntry(HalFile& file) const {
|
||||
TocEntry entry;
|
||||
serialization::readString(file, entry.title);
|
||||
serialization::readString(file, entry.href);
|
||||
|
||||
@@ -50,10 +50,10 @@ class BookMetadataCache {
|
||||
bool loaded;
|
||||
bool buildMode;
|
||||
|
||||
FsFile bookFile;
|
||||
HalFile bookFile;
|
||||
// Temp file handles during build
|
||||
FsFile spineFile;
|
||||
FsFile tocFile;
|
||||
HalFile spineFile;
|
||||
HalFile tocFile;
|
||||
|
||||
// Index for fast href→spineIndex lookup (used only for large EPUBs)
|
||||
struct SpineHrefIndexEntry {
|
||||
@@ -76,10 +76,10 @@ class BookMetadataCache {
|
||||
return hash;
|
||||
}
|
||||
|
||||
uint32_t writeSpineEntry(FsFile& file, const SpineEntry& entry) const;
|
||||
uint32_t writeTocEntry(FsFile& file, const TocEntry& entry) const;
|
||||
SpineEntry readSpineEntry(FsFile& file) const;
|
||||
TocEntry readTocEntry(FsFile& file) const;
|
||||
uint32_t writeSpineEntry(HalFile& file, const SpineEntry& entry) const;
|
||||
uint32_t writeTocEntry(HalFile& file, const TocEntry& entry) const;
|
||||
SpineEntry readSpineEntry(HalFile& file) const;
|
||||
TocEntry readTocEntry(HalFile& file) const;
|
||||
|
||||
public:
|
||||
BookMetadata coreMetadata;
|
||||
|
||||
@@ -10,7 +10,7 @@ void PageLine::render(GfxRenderer& renderer, const int fontId, const int xOffset
|
||||
block->render(renderer, fontId, xPos + xOffset, yPos + yOffset);
|
||||
}
|
||||
|
||||
bool PageLine::serialize(FsFile& file) {
|
||||
bool PageLine::serialize(HalFile& file) {
|
||||
serialization::writePod(file, xPos);
|
||||
serialization::writePod(file, yPos);
|
||||
|
||||
@@ -18,7 +18,7 @@ bool PageLine::serialize(FsFile& file) {
|
||||
return block->serialize(file);
|
||||
}
|
||||
|
||||
std::unique_ptr<PageLine> PageLine::deserialize(FsFile& file) {
|
||||
std::unique_ptr<PageLine> PageLine::deserialize(HalFile& file) {
|
||||
int16_t xPos;
|
||||
int16_t yPos;
|
||||
serialization::readPod(file, xPos);
|
||||
@@ -33,7 +33,7 @@ void PageImage::render(GfxRenderer& renderer, const int fontId, const int xOffse
|
||||
imageBlock->render(renderer, xPos + xOffset, yPos + yOffset);
|
||||
}
|
||||
|
||||
bool PageImage::serialize(FsFile& file) {
|
||||
bool PageImage::serialize(HalFile& file) {
|
||||
serialization::writePod(file, xPos);
|
||||
serialization::writePod(file, yPos);
|
||||
|
||||
@@ -41,7 +41,7 @@ bool PageImage::serialize(FsFile& file) {
|
||||
return imageBlock->serialize(file);
|
||||
}
|
||||
|
||||
std::unique_ptr<PageImage> PageImage::deserialize(FsFile& file) {
|
||||
std::unique_ptr<PageImage> PageImage::deserialize(HalFile& file) {
|
||||
int16_t xPos;
|
||||
int16_t yPos;
|
||||
serialization::readPod(file, xPos);
|
||||
@@ -60,7 +60,7 @@ void PageHorizontalRule::render(GfxRenderer& renderer, const int fontId, const i
|
||||
renderer.drawLine(xPos + xOffset, yPos + yOffset, xPos + xOffset + width - 1, yPos + yOffset, thickness, true);
|
||||
}
|
||||
|
||||
bool PageHorizontalRule::serialize(FsFile& file) {
|
||||
bool PageHorizontalRule::serialize(HalFile& file) {
|
||||
serialization::writePod(file, xPos);
|
||||
serialization::writePod(file, yPos);
|
||||
serialization::writePod(file, width);
|
||||
@@ -68,7 +68,7 @@ bool PageHorizontalRule::serialize(FsFile& file) {
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<PageHorizontalRule> PageHorizontalRule::deserialize(FsFile& file) {
|
||||
std::unique_ptr<PageHorizontalRule> PageHorizontalRule::deserialize(HalFile& file) {
|
||||
int16_t xPos = 0;
|
||||
int16_t yPos = 0;
|
||||
uint16_t width = 0;
|
||||
@@ -98,7 +98,7 @@ void Page::render(GfxRenderer& renderer, const int fontId, const int xOffset, co
|
||||
}
|
||||
}
|
||||
|
||||
bool Page::serialize(FsFile& file) const {
|
||||
bool Page::serialize(HalFile& file) const {
|
||||
const uint16_t count = elements.size();
|
||||
serialization::writePod(file, count);
|
||||
|
||||
@@ -126,7 +126,7 @@ bool Page::serialize(FsFile& file) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<Page> Page::deserialize(FsFile& file) {
|
||||
std::unique_ptr<Page> Page::deserialize(HalFile& file) {
|
||||
auto page = std::unique_ptr<Page>(new Page());
|
||||
|
||||
uint16_t count;
|
||||
|
||||
@@ -24,7 +24,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 bool serialize(FsFile& file) = 0;
|
||||
virtual bool serialize(HalFile& file) = 0;
|
||||
virtual PageElementTag getTag() const = 0; // Add type identification
|
||||
};
|
||||
|
||||
@@ -37,9 +37,9 @@ class PageLine final : public PageElement {
|
||||
: PageElement(xPos, yPos), block(std::move(block)) {}
|
||||
const std::shared_ptr<TextBlock>& getBlock() const { return block; }
|
||||
void render(GfxRenderer& renderer, int fontId, int xOffset, int yOffset) override;
|
||||
bool serialize(FsFile& file) override;
|
||||
bool serialize(HalFile& file) override;
|
||||
PageElementTag getTag() const override { return TAG_PageLine; }
|
||||
static std::unique_ptr<PageLine> deserialize(FsFile& file);
|
||||
static std::unique_ptr<PageLine> deserialize(HalFile& file);
|
||||
};
|
||||
|
||||
// New PageImage class
|
||||
@@ -50,9 +50,9 @@ class PageImage final : public PageElement {
|
||||
PageImage(std::shared_ptr<ImageBlock> block, const int16_t xPos, const int16_t yPos)
|
||||
: PageElement(xPos, yPos), imageBlock(std::move(block)) {}
|
||||
void render(GfxRenderer& renderer, int fontId, int xOffset, int yOffset) override;
|
||||
bool serialize(FsFile& file) override;
|
||||
bool serialize(HalFile& file) override;
|
||||
PageElementTag getTag() const override { return TAG_PageImage; }
|
||||
static std::unique_ptr<PageImage> deserialize(FsFile& file);
|
||||
static std::unique_ptr<PageImage> deserialize(HalFile& file);
|
||||
const ImageBlock& getImageBlock() const { return *imageBlock; }
|
||||
};
|
||||
|
||||
@@ -65,9 +65,9 @@ class PageHorizontalRule final : public PageElement {
|
||||
: PageElement(xPos, yPos), width(width), thickness(thickness) {}
|
||||
|
||||
void render(GfxRenderer& renderer, int fontId, int xOffset, int yOffset) override;
|
||||
bool serialize(FsFile& file) override;
|
||||
bool serialize(HalFile& file) override;
|
||||
PageElementTag getTag() const override { return TAG_PageHorizontalRule; }
|
||||
static std::unique_ptr<PageHorizontalRule> deserialize(FsFile& file);
|
||||
static std::unique_ptr<PageHorizontalRule> deserialize(HalFile& file);
|
||||
};
|
||||
|
||||
class Page {
|
||||
@@ -88,8 +88,8 @@ class Page {
|
||||
}
|
||||
|
||||
void render(GfxRenderer& renderer, int fontId, int xOffset, int yOffset) const;
|
||||
bool serialize(FsFile& file) const;
|
||||
static std::unique_ptr<Page> deserialize(FsFile& file);
|
||||
bool serialize(HalFile& file) const;
|
||||
static std::unique_ptr<Page> deserialize(HalFile& file);
|
||||
|
||||
// Check if page contains any images (used to force full refresh)
|
||||
bool hasImages() const {
|
||||
|
||||
@@ -176,7 +176,7 @@ bool Section::createSectionFile(const int fontId, const float lineCompression, c
|
||||
Storage.remove(tmpHtmlPath.c_str());
|
||||
}
|
||||
|
||||
FsFile tmpHtml;
|
||||
HalFile tmpHtml;
|
||||
if (!Storage.openFileForWrite("SCT", tmpHtmlPath, tmpHtml)) {
|
||||
continue;
|
||||
}
|
||||
@@ -317,7 +317,7 @@ std::unique_ptr<Page> Section::loadPageFromSectionFile() {
|
||||
}
|
||||
|
||||
std::optional<uint16_t> Section::getPageForAnchor(const std::string& anchor) const {
|
||||
FsFile f;
|
||||
HalFile f;
|
||||
if (!Storage.openFileForRead("SCT", filePath, f)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
@@ -347,7 +347,7 @@ std::optional<uint16_t> Section::getPageForAnchor(const std::string& anchor) con
|
||||
}
|
||||
|
||||
std::optional<uint16_t> Section::getPageForParagraphIndex(const uint16_t pIndex) const {
|
||||
FsFile f;
|
||||
HalFile f;
|
||||
if (!Storage.openFileForRead("SCT", filePath, f)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
@@ -386,7 +386,7 @@ std::optional<uint16_t> Section::getPageForParagraphIndex(const uint16_t pIndex)
|
||||
}
|
||||
|
||||
std::optional<uint16_t> Section::getParagraphIndexForPage(const uint16_t page) const {
|
||||
FsFile f;
|
||||
HalFile f;
|
||||
if (!Storage.openFileForRead("SCT", filePath, f)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
@@ -418,7 +418,7 @@ std::optional<uint16_t> Section::getParagraphIndexForPage(const uint16_t page) c
|
||||
}
|
||||
|
||||
std::optional<uint16_t> Section::getPageForListItemIndex(const uint16_t liIndex) const {
|
||||
FsFile f;
|
||||
HalFile f;
|
||||
if (!Storage.openFileForRead("SCT", filePath, f)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ class Section {
|
||||
const int spineIndex;
|
||||
GfxRenderer& renderer;
|
||||
std::string filePath;
|
||||
FsFile file;
|
||||
HalFile file;
|
||||
|
||||
void writeSectionFileHeader(int fontId, float lineCompression, bool extraParagraphSpacing, uint8_t paragraphAlignment,
|
||||
uint16_t viewportWidth, uint16_t viewportHeight, bool hyphenationEnabled,
|
||||
|
||||
@@ -30,7 +30,7 @@ std::string getCachePath(const std::string& imagePath) {
|
||||
|
||||
bool renderFromCache(GfxRenderer& renderer, const std::string& cachePath, int x, int y, int expectedWidth,
|
||||
int expectedHeight) {
|
||||
FsFile cacheFile;
|
||||
HalFile cacheFile;
|
||||
if (!Storage.openFileForRead("IMG", cachePath, cacheFile)) {
|
||||
return false;
|
||||
}
|
||||
@@ -112,7 +112,7 @@ void ImageBlock::render(GfxRenderer& renderer, const int x, const int y) {
|
||||
|
||||
// No cache - need to decode the image
|
||||
// Check if image file exists
|
||||
FsFile file;
|
||||
HalFile file;
|
||||
if (!Storage.openFileForRead("IMG", imagePath, file)) {
|
||||
LOG_ERR("IMG", "Image file not found: %s", imagePath.c_str());
|
||||
return;
|
||||
@@ -155,14 +155,14 @@ void ImageBlock::render(GfxRenderer& renderer, const int x, const int y) {
|
||||
LOG_DBG("IMG", "Decode successful");
|
||||
}
|
||||
|
||||
bool ImageBlock::serialize(FsFile& file) {
|
||||
bool ImageBlock::serialize(HalFile& file) {
|
||||
serialization::writeString(file, imagePath);
|
||||
serialization::writePod(file, width);
|
||||
serialization::writePod(file, height);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<ImageBlock> ImageBlock::deserialize(FsFile& file) {
|
||||
std::unique_ptr<ImageBlock> ImageBlock::deserialize(HalFile& file) {
|
||||
std::string path;
|
||||
serialization::readString(file, path);
|
||||
int16_t w, h;
|
||||
|
||||
@@ -21,8 +21,8 @@ class ImageBlock final : public Block {
|
||||
bool isEmpty() override { return false; }
|
||||
|
||||
void render(GfxRenderer& renderer, const int x, const int y);
|
||||
bool serialize(FsFile& file);
|
||||
static std::unique_ptr<ImageBlock> deserialize(FsFile& file);
|
||||
bool serialize(HalFile& file);
|
||||
static std::unique_ptr<ImageBlock> deserialize(HalFile& file);
|
||||
|
||||
private:
|
||||
std::string imagePath;
|
||||
|
||||
@@ -67,7 +67,7 @@ void TextBlock::render(const GfxRenderer& renderer, const int fontId, const int
|
||||
}
|
||||
}
|
||||
|
||||
bool TextBlock::serialize(FsFile& file) const {
|
||||
bool TextBlock::serialize(HalFile& file) const {
|
||||
// Focus annotations are optional; vectors are either empty (no splits in this block)
|
||||
// or sized in lockstep with words[].
|
||||
const bool hasFocus = !wordFocusBoundary.empty();
|
||||
@@ -110,7 +110,7 @@ bool TextBlock::serialize(FsFile& file) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<TextBlock> TextBlock::deserialize(FsFile& file) {
|
||||
std::unique_ptr<TextBlock> TextBlock::deserialize(HalFile& file) {
|
||||
uint16_t wc;
|
||||
std::vector<std::string> words;
|
||||
std::vector<int16_t> wordXpos;
|
||||
|
||||
@@ -47,6 +47,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; }
|
||||
bool serialize(FsFile& file) const;
|
||||
static std::unique_ptr<TextBlock> deserialize(FsFile& file);
|
||||
bool serialize(HalFile& file) const;
|
||||
static std::unique_ptr<TextBlock> deserialize(HalFile& file);
|
||||
};
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace {
|
||||
|
||||
// Context struct passed through JPEGDEC callbacks to avoid global mutable state.
|
||||
// The draw callback receives this via pDraw->pUser (set by setUserPointer()).
|
||||
// The file I/O callbacks receive the FsFile* via pFile->fHandle (set by jpegOpen()).
|
||||
// The file I/O callbacks receive the HalFile* via pFile->fHandle (set by jpegOpen()).
|
||||
struct JpegContext {
|
||||
GfxRenderer* renderer{nullptr};
|
||||
const RenderConfig* config{nullptr};
|
||||
@@ -48,10 +48,10 @@ struct JpegContext {
|
||||
bool caching{false};
|
||||
};
|
||||
|
||||
// File I/O callbacks use pFile->fHandle to access the FsFile*,
|
||||
// File I/O callbacks use pFile->fHandle to access the HalFile*,
|
||||
// avoiding the need for global file state.
|
||||
void* jpegOpen(const char* filename, int32_t* size) {
|
||||
FsFile* f = new FsFile();
|
||||
HalFile* f = new HalFile();
|
||||
if (!Storage.openFileForRead("JPG", std::string(filename), *f)) {
|
||||
delete f;
|
||||
return nullptr;
|
||||
@@ -61,7 +61,7 @@ void* jpegOpen(const char* filename, int32_t* size) {
|
||||
}
|
||||
|
||||
void jpegClose(void* handle) {
|
||||
FsFile* f = reinterpret_cast<FsFile*>(handle);
|
||||
HalFile* f = reinterpret_cast<HalFile*>(handle);
|
||||
if (f) {
|
||||
f->close();
|
||||
delete f;
|
||||
@@ -73,7 +73,7 @@ void jpegClose(void* handle) {
|
||||
// MUST maintain iPos to match the actual file position, otherwise progressive
|
||||
// JPEGs with large headers fail during parsing.
|
||||
int32_t jpegRead(JPEGFILE* pFile, uint8_t* pBuf, int32_t len) {
|
||||
FsFile* f = reinterpret_cast<FsFile*>(pFile->fHandle);
|
||||
HalFile* f = reinterpret_cast<HalFile*>(pFile->fHandle);
|
||||
if (!f) return 0;
|
||||
int32_t bytesRead = f->read(pBuf, len);
|
||||
if (bytesRead < 0) return 0;
|
||||
@@ -82,7 +82,7 @@ int32_t jpegRead(JPEGFILE* pFile, uint8_t* pBuf, int32_t len) {
|
||||
}
|
||||
|
||||
int32_t jpegSeek(JPEGFILE* pFile, int32_t pos) {
|
||||
FsFile* f = reinterpret_cast<FsFile*>(pFile->fHandle);
|
||||
HalFile* f = reinterpret_cast<HalFile*>(pFile->fHandle);
|
||||
if (!f) return -1;
|
||||
if (!f->seek(pos)) return -1;
|
||||
pFile->iPos = pos;
|
||||
|
||||
@@ -56,7 +56,7 @@ struct PixelCache {
|
||||
bool writeToFile(const std::string& cachePath) {
|
||||
if (!buffer) return false;
|
||||
|
||||
FsFile cacheFile;
|
||||
HalFile cacheFile;
|
||||
if (!Storage.openFileForWrite("IMG", cachePath, cacheFile)) {
|
||||
LOG_ERR("IMG", "Failed to open cache file for writing: %s", cachePath.c_str());
|
||||
return false;
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace {
|
||||
|
||||
// Context struct passed through PNGdec callbacks to avoid global mutable state.
|
||||
// The draw callback receives this via pDraw->pUser (set by png.decode()).
|
||||
// The file I/O callbacks receive the FsFile* via pFile->fHandle (set by pngOpen()).
|
||||
// The file I/O callbacks receive the HalFile* via pFile->fHandle (set by pngOpen()).
|
||||
struct PngContext {
|
||||
GfxRenderer* renderer{nullptr};
|
||||
const RenderConfig* config{nullptr};
|
||||
@@ -40,10 +40,10 @@ struct PngContext {
|
||||
uint8_t* grayLineBuffer{nullptr};
|
||||
};
|
||||
|
||||
// File I/O callbacks use pFile->fHandle to access the FsFile*,
|
||||
// File I/O callbacks use pFile->fHandle to access the HalFile*,
|
||||
// avoiding the need for global file state.
|
||||
void* pngOpenWithHandle(const char* filename, int32_t* size) {
|
||||
FsFile* f = new FsFile();
|
||||
HalFile* f = new HalFile();
|
||||
if (!Storage.openFileForRead("PNG", std::string(filename), *f)) {
|
||||
delete f;
|
||||
return nullptr;
|
||||
@@ -53,7 +53,7 @@ void* pngOpenWithHandle(const char* filename, int32_t* size) {
|
||||
}
|
||||
|
||||
void pngCloseWithHandle(void* handle) {
|
||||
FsFile* f = reinterpret_cast<FsFile*>(handle);
|
||||
HalFile* f = reinterpret_cast<HalFile*>(handle);
|
||||
if (f) {
|
||||
f->close();
|
||||
delete f;
|
||||
@@ -61,13 +61,13 @@ void pngCloseWithHandle(void* handle) {
|
||||
}
|
||||
|
||||
int32_t pngReadWithHandle(PNGFILE* pFile, uint8_t* pBuf, int32_t len) {
|
||||
FsFile* f = reinterpret_cast<FsFile*>(pFile->fHandle);
|
||||
HalFile* f = reinterpret_cast<HalFile*>(pFile->fHandle);
|
||||
if (!f) return 0;
|
||||
return f->read(pBuf, len);
|
||||
}
|
||||
|
||||
int32_t pngSeekWithHandle(PNGFILE* pFile, int32_t pos) {
|
||||
FsFile* f = reinterpret_cast<FsFile*>(pFile->fHandle);
|
||||
HalFile* f = reinterpret_cast<HalFile*>(pFile->fHandle);
|
||||
if (!f) return -1;
|
||||
return f->seek(pos);
|
||||
}
|
||||
|
||||
@@ -460,7 +460,7 @@ void CssParser::processRuleBlockWithStyle(const std::string& selectorGroup, cons
|
||||
|
||||
// Main parsing entry point
|
||||
|
||||
bool CssParser::loadFromStream(FsFile& source) {
|
||||
bool CssParser::loadFromStream(HalFile& source) {
|
||||
if (!source) {
|
||||
LOG_ERR("CSS", "Cannot read from invalid file");
|
||||
return false;
|
||||
@@ -676,7 +676,7 @@ bool CssParser::saveToCache() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
FsFile file;
|
||||
HalFile file;
|
||||
if (!Storage.openFileForWrite("CSS", cachePath + rulesCache, file)) {
|
||||
return false;
|
||||
}
|
||||
@@ -751,7 +751,7 @@ bool CssParser::loadFromCache() {
|
||||
return false;
|
||||
}
|
||||
|
||||
FsFile file;
|
||||
HalFile file;
|
||||
if (!Storage.openFileForRead("CSS", cachePath + rulesCache, file)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ class CssParser {
|
||||
* @param source Open file handle to read from
|
||||
* @return true if parsing completed (even if no rules found)
|
||||
*/
|
||||
bool loadFromStream(FsFile& source);
|
||||
bool loadFromStream(HalFile& source);
|
||||
|
||||
/**
|
||||
* Look up the style for an HTML element, considering tag name and class attributes.
|
||||
|
||||
@@ -380,7 +380,7 @@ void XMLCALL ChapterHtmlSlimParser::startElement(void* userData, const XML_Char*
|
||||
std::string cachedImagePath = self->imageBasePath + std::to_string(self->imageCounter++) + ext;
|
||||
|
||||
// Extract image to cache file
|
||||
FsFile cachedImageFile;
|
||||
HalFile cachedImageFile;
|
||||
bool extractSuccess = false;
|
||||
if (Storage.openFileForWrite("EHP", cachedImagePath, cachedImageFile)) {
|
||||
extractSuccess = self->epub->readItemContentsToStream(resolvedPath, cachedImageFile, 4096);
|
||||
@@ -1150,7 +1150,7 @@ bool ChapterHtmlSlimParser::parseAndBuildPages() {
|
||||
// Using DefaultHandlerExpand preserves normal entity expansion from DOCTYPE
|
||||
XML_SetDefaultHandlerExpand(parser, defaultHandlerExpand);
|
||||
|
||||
FsFile file;
|
||||
HalFile file;
|
||||
if (!Storage.openFileForRead("EHP", filepath, file)) {
|
||||
destroyXmlParser(parser);
|
||||
return false;
|
||||
|
||||
@@ -29,7 +29,7 @@ class ContentOpfParser final : public Print {
|
||||
XML_Parser parser = nullptr;
|
||||
ParserState state = START;
|
||||
BookMetadataCache* cache;
|
||||
FsFile tempItemStore;
|
||||
HalFile tempItemStore;
|
||||
std::string coverItemId;
|
||||
|
||||
// Index for fast idref→href lookup (used only for large EPUBs)
|
||||
|
||||
@@ -21,7 +21,7 @@ Bitmap::~Bitmap() {
|
||||
delete fsDitherer;
|
||||
}
|
||||
|
||||
uint16_t Bitmap::readLE16(FsFile& f) {
|
||||
uint16_t Bitmap::readLE16(HalFile& f) {
|
||||
const int c0 = f.read();
|
||||
const int c1 = f.read();
|
||||
const auto b0 = static_cast<uint8_t>(c0 < 0 ? 0 : c0);
|
||||
@@ -29,7 +29,7 @@ uint16_t Bitmap::readLE16(FsFile& f) {
|
||||
return static_cast<uint16_t>(b0) | (static_cast<uint16_t>(b1) << 8);
|
||||
}
|
||||
|
||||
uint32_t Bitmap::readLE32(FsFile& f) {
|
||||
uint32_t Bitmap::readLE32(HalFile& f) {
|
||||
const int c0 = f.read();
|
||||
const int c1 = f.read();
|
||||
const int c2 = f.read();
|
||||
|
||||
@@ -64,7 +64,7 @@ class Bitmap {
|
||||
public:
|
||||
static const char* errorToString(BmpReaderError err);
|
||||
|
||||
explicit Bitmap(FsFile& file, bool dithering = false) : file(file), dithering(dithering) {}
|
||||
explicit Bitmap(HalFile& file, bool dithering = false) : file(file), dithering(dithering) {}
|
||||
~Bitmap();
|
||||
BmpReaderError parseHeaders();
|
||||
BmpReaderError readNextRow(uint8_t* data, uint8_t* rowBuffer) const;
|
||||
@@ -78,10 +78,10 @@ class Bitmap {
|
||||
uint16_t getBpp() const { return bpp; }
|
||||
|
||||
private:
|
||||
static uint16_t readLE16(FsFile& f);
|
||||
static uint32_t readLE32(FsFile& f);
|
||||
static uint16_t readLE16(HalFile& f);
|
||||
static uint32_t readLE32(HalFile& f);
|
||||
|
||||
FsFile& file;
|
||||
HalFile& file;
|
||||
bool dithering = false;
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
|
||||
@@ -25,7 +25,7 @@ enum class InflateStatus {
|
||||
//
|
||||
// struct MyCtx {
|
||||
// InflateReader reader; // must be first
|
||||
// FsFile* file;
|
||||
// HalFile* file;
|
||||
// // ...
|
||||
// };
|
||||
// static int myCb(struct uzlib_uncomp* u) {
|
||||
|
||||
@@ -167,7 +167,7 @@ constexpr size_t MIN_FREE_HEAP = JPEG_DECODER_SIZE + 32 * 1024;
|
||||
|
||||
// Static file pointer for JPEGDEC open callback.
|
||||
// Safe in single-threaded embedded context; never accessed concurrently.
|
||||
static FsFile* s_jpegFile = nullptr;
|
||||
static HalFile* s_jpegFile = nullptr;
|
||||
|
||||
void* bmpJpegOpen(const char* /*filename*/, int32_t* size) {
|
||||
if (!s_jpegFile || !*s_jpegFile) return nullptr;
|
||||
@@ -181,7 +181,7 @@ void bmpJpegClose(void* /*handle*/) {
|
||||
}
|
||||
|
||||
int32_t bmpJpegRead(JPEGFILE* pFile, uint8_t* pBuf, int32_t len) {
|
||||
auto* f = reinterpret_cast<FsFile*>(pFile->fHandle);
|
||||
auto* f = reinterpret_cast<HalFile*>(pFile->fHandle);
|
||||
if (!f) return 0;
|
||||
int32_t n = f->read(pBuf, len);
|
||||
if (n < 0) n = 0;
|
||||
@@ -190,7 +190,7 @@ int32_t bmpJpegRead(JPEGFILE* pFile, uint8_t* pBuf, int32_t len) {
|
||||
}
|
||||
|
||||
int32_t bmpJpegSeek(JPEGFILE* pFile, int32_t pos) {
|
||||
auto* f = reinterpret_cast<FsFile*>(pFile->fHandle);
|
||||
auto* f = reinterpret_cast<HalFile*>(pFile->fHandle);
|
||||
if (!f || !f->seek(pos)) return -1;
|
||||
pFile->iPos = pos;
|
||||
return pos;
|
||||
@@ -376,8 +376,8 @@ int bmpDrawCallback(JPEGDRAW* pDraw) {
|
||||
} // namespace
|
||||
|
||||
// Internal implementation with configurable target size and bit depth
|
||||
bool JpegToBmpConverter::jpegFileToBmpStreamInternal(FsFile& jpegFile, Print& bmpOut, int targetWidth, int targetHeight,
|
||||
bool oneBit, bool crop) {
|
||||
bool JpegToBmpConverter::jpegFileToBmpStreamInternal(HalFile& jpegFile, Print& bmpOut, int targetWidth,
|
||||
int targetHeight, bool oneBit, bool crop) {
|
||||
LOG_DBG("JPG", "Converting JPEG to %s BMP (target: %dx%d)", oneBit ? "1-bit" : "2-bit", targetWidth, targetHeight);
|
||||
|
||||
if (ESP.getFreeHeap() < MIN_FREE_HEAP) {
|
||||
@@ -532,7 +532,7 @@ bool JpegToBmpConverter::jpegFileToBmpStreamInternal(FsFile& jpegFile, Print& bm
|
||||
}
|
||||
|
||||
// Core function: Convert JPEG file to 2-bit BMP (uses default target size)
|
||||
bool JpegToBmpConverter::jpegFileToBmpStream(FsFile& jpegFile, Print& bmpOut, bool crop) {
|
||||
bool JpegToBmpConverter::jpegFileToBmpStream(HalFile& jpegFile, Print& bmpOut, bool crop) {
|
||||
// Use runtime display dimensions (swapped for portrait cover sizing)
|
||||
const int targetWidth = display.getDisplayHeight();
|
||||
const int targetHeight = display.getDisplayWidth();
|
||||
@@ -540,13 +540,13 @@ bool JpegToBmpConverter::jpegFileToBmpStream(FsFile& jpegFile, Print& bmpOut, bo
|
||||
}
|
||||
|
||||
// Convert with custom target size (for thumbnails, 2-bit)
|
||||
bool JpegToBmpConverter::jpegFileToBmpStreamWithSize(FsFile& jpegFile, Print& bmpOut, int targetMaxWidth,
|
||||
bool JpegToBmpConverter::jpegFileToBmpStreamWithSize(HalFile& jpegFile, Print& bmpOut, int targetMaxWidth,
|
||||
int targetMaxHeight) {
|
||||
return jpegFileToBmpStreamInternal(jpegFile, bmpOut, targetMaxWidth, targetMaxHeight, false);
|
||||
}
|
||||
|
||||
// Convert to 1-bit BMP (black and white only, no grays) for fast home screen rendering
|
||||
bool JpegToBmpConverter::jpegFileTo1BitBmpStreamWithSize(FsFile& jpegFile, Print& bmpOut, int targetMaxWidth,
|
||||
bool JpegToBmpConverter::jpegFileTo1BitBmpStreamWithSize(HalFile& jpegFile, Print& bmpOut, int targetMaxWidth,
|
||||
int targetMaxHeight) {
|
||||
return jpegFileToBmpStreamInternal(jpegFile, bmpOut, targetMaxWidth, targetMaxHeight, true, true);
|
||||
}
|
||||
|
||||
@@ -6,13 +6,14 @@ class Print;
|
||||
class ZipFile;
|
||||
|
||||
class JpegToBmpConverter {
|
||||
static bool jpegFileToBmpStreamInternal(FsFile& jpegFile, Print& bmpOut, int targetWidth, int targetHeight,
|
||||
static bool jpegFileToBmpStreamInternal(HalFile& jpegFile, Print& bmpOut, int targetWidth, int targetHeight,
|
||||
bool oneBit, bool crop = true);
|
||||
|
||||
public:
|
||||
static bool jpegFileToBmpStream(FsFile& jpegFile, Print& bmpOut, bool crop = true);
|
||||
static bool jpegFileToBmpStream(HalFile& jpegFile, Print& bmpOut, bool crop = true);
|
||||
// Convert with custom target size (for thumbnails)
|
||||
static bool jpegFileToBmpStreamWithSize(FsFile& jpegFile, Print& bmpOut, int targetMaxWidth, int targetMaxHeight);
|
||||
static bool jpegFileToBmpStreamWithSize(HalFile& jpegFile, Print& bmpOut, int targetMaxWidth, int targetMaxHeight);
|
||||
// Convert to 1-bit BMP (black and white only, no grays) for fast home screen rendering
|
||||
static bool jpegFileTo1BitBmpStreamWithSize(FsFile& jpegFile, Print& bmpOut, int targetMaxWidth, int targetMaxHeight);
|
||||
static bool jpegFileTo1BitBmpStreamWithSize(HalFile& jpegFile, Print& bmpOut, int targetMaxWidth,
|
||||
int targetMaxHeight);
|
||||
};
|
||||
|
||||
@@ -73,7 +73,7 @@ bool KOReaderCredentialStore::loadFromFile() {
|
||||
}
|
||||
|
||||
bool KOReaderCredentialStore::loadFromBinaryFile() {
|
||||
FsFile file;
|
||||
HalFile file;
|
||||
if (!Storage.openFileForRead("KRS", KOREADER_FILE_BIN, file)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ size_t KOReaderDocumentId::getOffset(int i) {
|
||||
}
|
||||
|
||||
std::string KOReaderDocumentId::calculate(const std::string& filePath) {
|
||||
FsFile file;
|
||||
HalFile file;
|
||||
if (!Storage.openFileForRead("KODoc", filePath, file)) {
|
||||
LOG_DBG("KODoc", "Failed to open file: %s", filePath.c_str());
|
||||
return "";
|
||||
|
||||
@@ -73,7 +73,7 @@ enum PngFilter : uint8_t {
|
||||
};
|
||||
|
||||
// Read a big-endian 32-bit value from file
|
||||
bool readBE32(FsFile& file, uint32_t& value) {
|
||||
bool readBE32(HalFile& file, uint32_t& value) {
|
||||
uint8_t buf[4];
|
||||
if (file.read(buf, 4) != 4) return false;
|
||||
value = (static_cast<uint32_t>(buf[0]) << 24) | (static_cast<uint32_t>(buf[1]) << 16) |
|
||||
@@ -177,7 +177,7 @@ void writeBmpHeader2bit(Print& bmpOut, const int width, const int height) {
|
||||
// IMPORTANT: reader must be the first field - the uzlib callback casts uzlib_uncomp* to PngDecodeContext*
|
||||
struct PngDecodeContext {
|
||||
InflateReader reader; // Must be first — callback casts uzlib_uncomp* to PngDecodeContext*
|
||||
FsFile* file;
|
||||
HalFile* file;
|
||||
|
||||
// PNG image properties
|
||||
uint32_t width;
|
||||
@@ -395,7 +395,7 @@ static void convertScanlineToGray(const PngDecodeContext& ctx, uint8_t* grayRow)
|
||||
}
|
||||
}
|
||||
|
||||
bool PngToBmpConverter::pngFileToBmpStreamInternal(FsFile& pngFile, Print& bmpOut, int targetWidth, int targetHeight,
|
||||
bool PngToBmpConverter::pngFileToBmpStreamInternal(HalFile& pngFile, Print& bmpOut, int targetWidth, int targetHeight,
|
||||
bool oneBit, bool crop) {
|
||||
LOG_DBG("PNG", "Converting PNG to %s BMP (target: %dx%d)", oneBit ? "1-bit" : "2-bit", targetWidth, targetHeight);
|
||||
|
||||
@@ -820,19 +820,19 @@ bool PngToBmpConverter::pngFileToBmpStreamInternal(FsFile& pngFile, Print& bmpOu
|
||||
return success;
|
||||
}
|
||||
|
||||
bool PngToBmpConverter::pngFileToBmpStream(FsFile& pngFile, Print& bmpOut, bool crop) {
|
||||
bool PngToBmpConverter::pngFileToBmpStream(HalFile& pngFile, Print& bmpOut, bool crop) {
|
||||
// Use runtime display dimensions (swapped for portrait cover sizing)
|
||||
const int targetWidth = display.getDisplayHeight();
|
||||
const int targetHeight = display.getDisplayWidth();
|
||||
return pngFileToBmpStreamInternal(pngFile, bmpOut, targetWidth, targetHeight, false, crop);
|
||||
}
|
||||
|
||||
bool PngToBmpConverter::pngFileToBmpStreamWithSize(FsFile& pngFile, Print& bmpOut, int targetMaxWidth,
|
||||
bool PngToBmpConverter::pngFileToBmpStreamWithSize(HalFile& pngFile, Print& bmpOut, int targetMaxWidth,
|
||||
int targetMaxHeight) {
|
||||
return pngFileToBmpStreamInternal(pngFile, bmpOut, targetMaxWidth, targetMaxHeight, false);
|
||||
}
|
||||
|
||||
bool PngToBmpConverter::pngFileTo1BitBmpStreamWithSize(FsFile& pngFile, Print& bmpOut, int targetMaxWidth,
|
||||
bool PngToBmpConverter::pngFileTo1BitBmpStreamWithSize(HalFile& pngFile, Print& bmpOut, int targetMaxWidth,
|
||||
int targetMaxHeight) {
|
||||
return pngFileToBmpStreamInternal(pngFile, bmpOut, targetMaxWidth, targetMaxHeight, true, true);
|
||||
}
|
||||
|
||||
@@ -5,11 +5,11 @@
|
||||
class Print;
|
||||
|
||||
class PngToBmpConverter {
|
||||
static bool pngFileToBmpStreamInternal(FsFile& pngFile, Print& bmpOut, int targetWidth, int targetHeight, bool oneBit,
|
||||
bool crop = true);
|
||||
static bool pngFileToBmpStreamInternal(HalFile& pngFile, Print& bmpOut, int targetWidth, int targetHeight,
|
||||
bool oneBit, bool crop = true);
|
||||
|
||||
public:
|
||||
static bool pngFileToBmpStream(FsFile& pngFile, Print& bmpOut, bool crop = true);
|
||||
static bool pngFileToBmpStreamWithSize(FsFile& pngFile, Print& bmpOut, int targetMaxWidth, int targetMaxHeight);
|
||||
static bool pngFileTo1BitBmpStreamWithSize(FsFile& pngFile, Print& bmpOut, int targetMaxWidth, int targetMaxHeight);
|
||||
static bool pngFileToBmpStream(HalFile& pngFile, Print& bmpOut, bool crop = true);
|
||||
static bool pngFileToBmpStreamWithSize(HalFile& pngFile, Print& bmpOut, int targetMaxWidth, int targetMaxHeight);
|
||||
static bool pngFileTo1BitBmpStreamWithSize(HalFile& pngFile, Print& bmpOut, int targetMaxWidth, int targetMaxHeight);
|
||||
};
|
||||
|
||||
@@ -10,7 +10,7 @@ void writePod(std::ostream& os, const T& value) {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void writePod(FsFile& file, const T& value) {
|
||||
void writePod(HalFile& file, const T& value) {
|
||||
file.write(reinterpret_cast<const uint8_t*>(&value), sizeof(T));
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ void readPod(std::istream& is, T& value) {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void readPod(FsFile& file, T& value) {
|
||||
void readPod(HalFile& file, T& value) {
|
||||
file.read(reinterpret_cast<uint8_t*>(&value), sizeof(T));
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ inline void writeString(std::ostream& os, const std::string& s) {
|
||||
os.write(s.data(), len);
|
||||
}
|
||||
|
||||
inline void writeString(FsFile& file, const std::string& s) {
|
||||
inline void writeString(HalFile& file, const std::string& s) {
|
||||
const uint32_t len = s.size();
|
||||
writePod(file, len);
|
||||
file.write(reinterpret_cast<const uint8_t*>(s.data()), len);
|
||||
@@ -43,7 +43,7 @@ inline void readString(std::istream& is, std::string& s) {
|
||||
is.read(&s[0], len);
|
||||
}
|
||||
|
||||
inline void readString(FsFile& file, std::string& s) {
|
||||
inline void readString(HalFile& file, std::string& s) {
|
||||
uint32_t len;
|
||||
readPod(file, len);
|
||||
s.resize(len);
|
||||
|
||||
+4
-4
@@ -21,7 +21,7 @@ bool Txt::load() {
|
||||
return false;
|
||||
}
|
||||
|
||||
FsFile file;
|
||||
HalFile file;
|
||||
if (!Storage.openFileForRead("TXT", filepath, file)) {
|
||||
LOG_ERR("TXT", "Failed to open file: %s", filepath.c_str());
|
||||
return false;
|
||||
@@ -115,7 +115,7 @@ bool Txt::generateCoverBmp() const {
|
||||
if (FsHelpers::hasBmpExtension(coverImagePath)) {
|
||||
// Copy BMP file to cache
|
||||
LOG_DBG("TXT", "Copying BMP cover image to cache");
|
||||
FsFile src, dst;
|
||||
HalFile src, dst;
|
||||
if (!Storage.openFileForRead("TXT", coverImagePath, src)) {
|
||||
return false;
|
||||
}
|
||||
@@ -132,7 +132,7 @@ bool Txt::generateCoverBmp() const {
|
||||
} else if (FsHelpers::hasJpgExtension(coverImagePath)) {
|
||||
// Convert JPG/JPEG to BMP (same approach as Epub)
|
||||
LOG_DBG("TXT", "Generating BMP from JPG cover image");
|
||||
FsFile coverJpg, coverBmp;
|
||||
HalFile coverJpg, coverBmp;
|
||||
if (!Storage.openFileForRead("TXT", coverImagePath, coverJpg)) {
|
||||
return false;
|
||||
}
|
||||
@@ -175,7 +175,7 @@ bool Txt::readContent(uint8_t* buffer, size_t offset, size_t length) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
FsFile file;
|
||||
HalFile file;
|
||||
if (!Storage.openFileForRead("TXT", filepath, file)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
+3
-3
@@ -166,7 +166,7 @@ bool Xtc::generateCoverBmp() const {
|
||||
}
|
||||
|
||||
// Create BMP file
|
||||
FsFile coverBmp;
|
||||
HalFile coverBmp;
|
||||
if (!Storage.openFileForWrite("XTC", getCoverBmpPath(), coverBmp)) {
|
||||
LOG_DBG("XTC", "Failed to create cover BMP file");
|
||||
free(pageBuffer);
|
||||
@@ -306,7 +306,7 @@ bool Xtc::generateThumbBmp(int height) const {
|
||||
// Page is already small enough, just use cover.bmp
|
||||
// Copy cover.bmp to thumb.bmp
|
||||
if (generateCoverBmp()) {
|
||||
FsFile src, dst;
|
||||
HalFile src, dst;
|
||||
if (Storage.openFileForRead("XTC", getCoverBmpPath(), src)) {
|
||||
if (Storage.openFileForWrite("XTC", getThumbBmpPath(height), dst)) {
|
||||
uint8_t buffer[512];
|
||||
@@ -350,7 +350,7 @@ bool Xtc::generateThumbBmp(int height) const {
|
||||
}
|
||||
|
||||
// Create thumbnail BMP file - use 1-bit format for fast home screen rendering (no gray passes)
|
||||
FsFile thumbBmp;
|
||||
HalFile thumbBmp;
|
||||
if (!Storage.openFileForWrite("XTC", getThumbBmpPath(height), thumbBmp)) {
|
||||
LOG_DBG("XTC", "Failed to create thumb BMP file");
|
||||
free(pageBuffer);
|
||||
|
||||
@@ -530,7 +530,7 @@ XtcError XtcParser::loadPageStreaming(uint32_t pageIndex,
|
||||
}
|
||||
|
||||
bool XtcParser::isValidXtcFile(const char* filepath) {
|
||||
FsFile file;
|
||||
HalFile file;
|
||||
if (!Storage.openFileForRead("XTC", filepath, file)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ class XtcParser {
|
||||
XtcError getLastError() const { return m_lastError; }
|
||||
|
||||
private:
|
||||
FsFile m_file;
|
||||
HalFile m_file;
|
||||
std::string m_filepath;
|
||||
bool m_isOpen;
|
||||
XtcHeader m_header;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
struct ZipInflateCtx {
|
||||
InflateReader reader; // Must be first — callback casts uzlib_uncomp* to ZipInflateCtx*
|
||||
FsFile* file = nullptr;
|
||||
HalFile* file = nullptr;
|
||||
size_t fileRemaining = 0;
|
||||
uint8_t* readBuf = nullptr;
|
||||
size_t readBufSize = 0;
|
||||
|
||||
@@ -39,7 +39,7 @@ class ZipFile {
|
||||
|
||||
private:
|
||||
const std::string& filePath;
|
||||
FsFile file;
|
||||
HalFile file;
|
||||
ZipDetails zipDetails = {0, 0, false};
|
||||
std::unordered_map<std::string, FileStatSlim> fileStatSlimCache;
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#define HAL_STORAGE_IMPL
|
||||
#include "HalStorage.h"
|
||||
|
||||
#include <FS.h> // need to be included before SdFat.h for compatibility with FS.h's File class
|
||||
|
||||
@@ -96,13 +96,6 @@ class HalFile : public Print {
|
||||
operator bool() const;
|
||||
};
|
||||
|
||||
// Only do renaming FsFile to HalFile if this header is included by downstream code
|
||||
// The renaming is to allow using the thread-safe HalFile instead of the raw FsFile, without needing to change the
|
||||
// downstream code
|
||||
#ifndef HAL_STORAGE_IMPL
|
||||
using FsFile = HalFile;
|
||||
#endif
|
||||
|
||||
// Downstream code must use Storage instead of SdMan
|
||||
#ifdef SdMan
|
||||
#undef SdMan
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
// Initialize the static instance
|
||||
CrossPointSettings CrossPointSettings::instance;
|
||||
|
||||
void readAndValidate(FsFile& file, uint8_t& member, const uint8_t maxValue) {
|
||||
void readAndValidate(HalFile& file, uint8_t& member, const uint8_t maxValue) {
|
||||
uint8_t tempValue;
|
||||
serialization::readPod(file, tempValue);
|
||||
if (tempValue < maxValue) {
|
||||
@@ -127,7 +127,7 @@ bool CrossPointSettings::migrateLanguageBinaryFile() {
|
||||
// frozen enum order from 2f969a9.
|
||||
if (!Storage.exists(LANG_FILE_BIN)) return false;
|
||||
|
||||
FsFile f;
|
||||
HalFile f;
|
||||
if (Storage.openFileForRead("CPS", LANG_FILE_BIN, f)) {
|
||||
uint8_t version;
|
||||
serialization::readPod(f, version);
|
||||
@@ -146,7 +146,7 @@ bool CrossPointSettings::migrateLanguageBinaryFile() {
|
||||
}
|
||||
|
||||
bool CrossPointSettings::loadFromBinaryFile() {
|
||||
FsFile inputFile;
|
||||
HalFile inputFile;
|
||||
if (!Storage.openFileForRead("CPS", SETTINGS_FILE_BIN, inputFile)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -269,7 +269,7 @@ class CrossPointSettings {
|
||||
int getReaderFontId() const;
|
||||
|
||||
// If count_only is true, returns the number of settings items that would be written.
|
||||
uint8_t writeSettings(FsFile& file, bool count_only = false) const;
|
||||
uint8_t writeSettings(HalFile& file, bool count_only = false) const;
|
||||
|
||||
bool saveToFile() const;
|
||||
bool loadFromFile();
|
||||
|
||||
@@ -63,7 +63,7 @@ bool CrossPointState::loadFromFile() {
|
||||
}
|
||||
|
||||
bool CrossPointState::loadFromBinaryFile() {
|
||||
FsFile inputFile;
|
||||
HalFile inputFile;
|
||||
if (!Storage.openFileForRead("CPS", STATE_FILE_BIN, inputFile)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ bool FontInstaller::ensureFamilyDir(const char* familyName) {
|
||||
}
|
||||
|
||||
bool FontInstaller::validateCpfontFile(const char* path) {
|
||||
FsFile file;
|
||||
HalFile file;
|
||||
if (!Storage.openFileForRead("FONT", path, file)) {
|
||||
LOG_ERR("FONT", "Cannot open for validation: %s", path);
|
||||
return false;
|
||||
|
||||
@@ -148,7 +148,7 @@ bool RecentBooksStore::loadFromFile() {
|
||||
}
|
||||
|
||||
bool RecentBooksStore::loadFromBinaryFile() {
|
||||
FsFile inputFile;
|
||||
HalFile inputFile;
|
||||
if (!Storage.openFileForRead("RBS", RECENT_BOOKS_FILE_BIN, inputFile)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ bool WifiCredentialStore::loadFromFile() {
|
||||
}
|
||||
|
||||
bool WifiCredentialStore::loadFromBinaryFile() {
|
||||
FsFile file;
|
||||
HalFile file;
|
||||
if (!Storage.openFileForRead("WCS", WIFI_FILE_BIN, file)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ void SleepActivity::renderCustomSleepScreen() const {
|
||||
// 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.
|
||||
// This takes priority over the /sleep folder.
|
||||
FsFile file;
|
||||
HalFile file;
|
||||
if (Storage.openFileForRead("SLP", "/sleep.bmp", file)) {
|
||||
Bitmap bitmap(file, true);
|
||||
if (bitmap.parseHeaders() == BmpReaderError::Ok) {
|
||||
@@ -129,7 +129,7 @@ void SleepActivity::renderCustomSleepScreen() const {
|
||||
APP_STATE.pushRecentSleep(randomFileIndex);
|
||||
APP_STATE.saveToFile();
|
||||
const auto filename = std::string(sleepDir) + "/" + files[randomFileIndex];
|
||||
FsFile randFile;
|
||||
HalFile randFile;
|
||||
if (Storage.openFileForRead("SLP", filename, randFile)) {
|
||||
LOG_DBG("SLP", "Randomly loading: %s/%s", sleepDir, files[randomFileIndex].c_str());
|
||||
delay(100);
|
||||
@@ -304,7 +304,7 @@ void SleepActivity::renderCoverSleepScreen() const {
|
||||
return (this->*renderNoCoverSleepScreen)();
|
||||
}
|
||||
|
||||
FsFile file;
|
||||
HalFile file;
|
||||
if (Storage.openFileForRead("SLP", coverBmpPath, file)) {
|
||||
Bitmap bitmap(file);
|
||||
if (bitmap.parseHeaders() == BmpReaderError::Ok) {
|
||||
|
||||
@@ -123,7 +123,7 @@ void EpubReaderActivity::onEnter() {
|
||||
|
||||
epub->setupCacheDir();
|
||||
|
||||
FsFile f;
|
||||
HalFile f;
|
||||
if (Storage.openFileForRead("ERS", epub->getCachePath() + "/progress.bin", f)) {
|
||||
uint8_t data[6];
|
||||
int dataSize = f.read(data, 6);
|
||||
|
||||
@@ -13,7 +13,7 @@ inline bool saveProgress(Epub& epub, int spineIndex, int pageNumber, int pageCou
|
||||
LOG_ERR("ERS", "Progress values out of range: spine=%d page=%d count=%d", spineIndex, pageNumber, pageCount);
|
||||
return false;
|
||||
}
|
||||
FsFile f;
|
||||
HalFile f;
|
||||
if (!Storage.openFileForWrite("ERS", epub.getCachePath() + "/progress.bin", f)) {
|
||||
LOG_ERR("ERS", "Could not open progress file for write!");
|
||||
return false;
|
||||
|
||||
@@ -415,7 +415,7 @@ void TxtReaderActivity::renderStatusBar() const {
|
||||
}
|
||||
|
||||
void TxtReaderActivity::saveProgress() const {
|
||||
FsFile f;
|
||||
HalFile f;
|
||||
if (Storage.openFileForWrite("TRS", txt->getCachePath() + "/progress.bin", f)) {
|
||||
uint8_t data[4];
|
||||
data[0] = currentPage & 0xFF;
|
||||
@@ -427,7 +427,7 @@ void TxtReaderActivity::saveProgress() const {
|
||||
}
|
||||
|
||||
void TxtReaderActivity::loadProgress() {
|
||||
FsFile f;
|
||||
HalFile f;
|
||||
if (Storage.openFileForRead("TRS", txt->getCachePath() + "/progress.bin", f)) {
|
||||
uint8_t data[4];
|
||||
if (f.read(data, 4) == 4) {
|
||||
@@ -457,7 +457,7 @@ bool TxtReaderActivity::loadPageIndexCache() {
|
||||
// - N * uint32_t: page offsets
|
||||
|
||||
std::string cachePath = txt->getCachePath() + "/index.bin";
|
||||
FsFile f;
|
||||
HalFile f;
|
||||
if (!Storage.openFileForRead("TRS", cachePath, f)) {
|
||||
LOG_DBG("TRS", "No page index cache found");
|
||||
return false;
|
||||
@@ -540,7 +540,7 @@ bool TxtReaderActivity::loadPageIndexCache() {
|
||||
|
||||
void TxtReaderActivity::savePageIndexCache() const {
|
||||
std::string cachePath = txt->getCachePath() + "/index.bin";
|
||||
FsFile f;
|
||||
HalFile f;
|
||||
if (!Storage.openFileForWrite("TRS", cachePath, f)) {
|
||||
LOG_ERR("TRS", "Failed to save page index cache");
|
||||
return;
|
||||
|
||||
@@ -375,7 +375,7 @@ void XtcReaderActivity::renderPage() {
|
||||
}
|
||||
|
||||
void XtcReaderActivity::saveProgress() const {
|
||||
FsFile f;
|
||||
HalFile f;
|
||||
if (Storage.openFileForWrite("XTR", xtc->getCachePath() + "/progress.bin", f)) {
|
||||
uint8_t data[4];
|
||||
data[0] = currentPage & 0xFF;
|
||||
@@ -388,7 +388,7 @@ void XtcReaderActivity::saveProgress() const {
|
||||
}
|
||||
|
||||
void XtcReaderActivity::loadProgress() {
|
||||
FsFile f;
|
||||
HalFile f;
|
||||
if (Storage.openFileForRead("XTR", xtc->getCachePath() + "/progress.bin", f)) {
|
||||
uint8_t data[4];
|
||||
if (f.read(data, 4) == 4) {
|
||||
|
||||
@@ -82,7 +82,7 @@ bool FontDownloadActivity::fetchAndParseManifest() {
|
||||
}
|
||||
|
||||
// HTTP client is now closed — TLS buffers freed. Parse JSON from file.
|
||||
FsFile manifestFile;
|
||||
HalFile manifestFile;
|
||||
if (!Storage.openFileForRead("FONT", MANIFEST_TMP, manifestFile)) {
|
||||
LOG_ERR("FONT", "Failed to open temp manifest");
|
||||
Storage.remove(MANIFEST_TMP);
|
||||
@@ -149,7 +149,7 @@ bool FontDownloadActivity::fetchAndParseManifest() {
|
||||
for (const auto& file : family.files) {
|
||||
char path[128];
|
||||
FontInstaller::buildFontPath(family.name.c_str(), file.name.c_str(), path, sizeof(path));
|
||||
FsFile f;
|
||||
HalFile f;
|
||||
if (Storage.openFileForRead("FONT", path, f)) {
|
||||
size_t actual = f.fileSize();
|
||||
f.close();
|
||||
@@ -248,7 +248,7 @@ size_t FontDownloadActivity::totalUpdateSize() const {
|
||||
|
||||
// Standard CRC32 matching zlib/Python zlib.crc32().
|
||||
bool FontDownloadActivity::computeFileCrc32(const char* path, uint32_t& outCrc) {
|
||||
FsFile f;
|
||||
HalFile f;
|
||||
if (!Storage.openFileForRead("FONT", path, f)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ void BmpViewerActivity::onEnter() {
|
||||
loadSiblingImages();
|
||||
}
|
||||
|
||||
FsFile file;
|
||||
HalFile file;
|
||||
|
||||
const auto pageWidth = renderer.getScreenWidth();
|
||||
const auto pageHeight = renderer.getScreenHeight();
|
||||
@@ -147,7 +147,7 @@ void BmpViewerActivity::doSetSleepCover() {
|
||||
GUI.drawPopup(renderer, tr(STR_LOADING_POPUP));
|
||||
|
||||
bool success = false;
|
||||
FsFile inFile, outFile;
|
||||
HalFile inFile, outFile;
|
||||
if (Storage.openFileForRead("BMP", filePath, inFile)) {
|
||||
if (Storage.openFileForWrite("BMP", "/sleep.bmp", outFile)) {
|
||||
char buffer[2048];
|
||||
|
||||
@@ -426,7 +426,7 @@ void BaseTheme::drawRecentBookCover(GfxRenderer& renderer, Rect rect, const std:
|
||||
const std::string coverBmpPath =
|
||||
UITheme::getCoverThumbPath(recentBooks[0].coverBmpPath, BaseMetrics::values.homeCoverHeight);
|
||||
|
||||
FsFile file;
|
||||
HalFile file;
|
||||
if (Storage.openFileForRead("HOME", coverBmpPath, file)) {
|
||||
Bitmap bitmap(file);
|
||||
if (bitmap.parseHeaders() == BmpReaderError::Ok) {
|
||||
@@ -476,7 +476,7 @@ void BaseTheme::drawRecentBookCover(GfxRenderer& renderer, Rect rect, const std:
|
||||
UITheme::getCoverThumbPath(recentBooks[0].coverBmpPath, BaseMetrics::values.homeCoverHeight);
|
||||
|
||||
// First time: load cover from SD and render
|
||||
FsFile file;
|
||||
HalFile file;
|
||||
if (Storage.openFileForRead("HOME", coverBmpPath, file)) {
|
||||
Bitmap bitmap(file);
|
||||
if (bitmap.parseHeaders() == BmpReaderError::Ok) {
|
||||
|
||||
@@ -42,7 +42,7 @@ void Lyra3CoversTheme::drawRecentBookCover(GfxRenderer& renderer, Rect rect, con
|
||||
UITheme::getCoverThumbPath(coverPath, Lyra3CoversMetrics::values.homeCoverHeight);
|
||||
|
||||
// First time: load cover from SD and render
|
||||
FsFile file;
|
||||
HalFile file;
|
||||
if (Storage.openFileForRead("HOME", coverBmpPath, file)) {
|
||||
Bitmap bitmap(file);
|
||||
if (bitmap.parseHeaders() == BmpReaderError::Ok) {
|
||||
|
||||
@@ -423,7 +423,7 @@ void LyraTheme::drawRecentBookCover(GfxRenderer& renderer, Rect rect, const std:
|
||||
const std::string coverBmpPath = UITheme::getCoverThumbPath(coverPath, LyraMetrics::values.homeCoverHeight);
|
||||
|
||||
// First time: load cover from SD and render
|
||||
FsFile file;
|
||||
HalFile file;
|
||||
if (Storage.openFileForRead("HOME", coverBmpPath, file)) {
|
||||
Bitmap bitmap(file);
|
||||
if (bitmap.parseHeaders() == BmpReaderError::Ok) {
|
||||
|
||||
@@ -140,7 +140,7 @@ void RoundedRaffTheme::drawRecentBookCover(GfxRenderer& renderer, Rect rect, con
|
||||
UITheme::getCoverThumbPath(coverPath, RoundedRaffMetrics::values.homeCoverHeight);
|
||||
|
||||
// First time: load cover from SD and render
|
||||
FsFile file;
|
||||
HalFile file;
|
||||
if (Storage.openFileForRead("HOME", coverBmpPath, file)) {
|
||||
Bitmap bitmap(file);
|
||||
if (bitmap.parseHeaders() == BmpReaderError::Ok) {
|
||||
|
||||
+2
-2
@@ -237,14 +237,14 @@ void waitForPowerRelease() {
|
||||
constexpr char SLEEP_FRAME_FILE[] = "/.crosspoint/sleep_frame.bin";
|
||||
|
||||
static void saveSleepFrameBuffer() {
|
||||
FsFile file;
|
||||
HalFile file;
|
||||
if (!Storage.openFileForWrite("SLP", SLEEP_FRAME_FILE, file)) return;
|
||||
file.write(renderer.getFrameBuffer(), renderer.getBufferSize());
|
||||
file.close();
|
||||
}
|
||||
|
||||
static bool loadSleepFrameBuffer() {
|
||||
FsFile file;
|
||||
HalFile file;
|
||||
if (!Storage.openFileForRead("SLP", SLEEP_FRAME_FILE, file)) return false;
|
||||
const size_t bufferSize = display.getBufferSize();
|
||||
const size_t bytesRead = file.read(display.getFrameBuffer(), bufferSize);
|
||||
|
||||
@@ -35,7 +35,7 @@ constexpr uint16_t LOCAL_UDP_PORT = 8134;
|
||||
CrossPointWebServer* wsInstance = nullptr;
|
||||
|
||||
// WebSocket upload state
|
||||
FsFile wsUploadFile;
|
||||
HalFile wsUploadFile;
|
||||
String wsUploadFileName;
|
||||
String wsUploadPath;
|
||||
size_t wsUploadSize = 0;
|
||||
@@ -374,7 +374,7 @@ void CrossPointWebServer::handleStatus() const {
|
||||
}
|
||||
|
||||
void CrossPointWebServer::scanFiles(const char* path, const std::function<void(FileInfo)>& callback) const {
|
||||
FsFile root = Storage.open(path);
|
||||
HalFile root = Storage.open(path);
|
||||
if (!root) {
|
||||
LOG_DBG("WEB", "Failed to open directory: %s", path);
|
||||
return;
|
||||
@@ -388,7 +388,7 @@ void CrossPointWebServer::scanFiles(const char* path, const std::function<void(F
|
||||
|
||||
LOG_DBG("WEB", "Scanning files in: %s", path);
|
||||
|
||||
FsFile file = root.openNextFile();
|
||||
HalFile file = root.openNextFile();
|
||||
char name[500];
|
||||
while (file) {
|
||||
file.getName(name, sizeof(name));
|
||||
@@ -519,7 +519,7 @@ void CrossPointWebServer::handleDownload() const {
|
||||
return;
|
||||
}
|
||||
|
||||
FsFile file = Storage.open(itemPath.c_str());
|
||||
HalFile file = Storage.open(itemPath.c_str());
|
||||
if (!file) {
|
||||
server->send(500, "text/plain", "Failed to open file");
|
||||
return;
|
||||
@@ -842,7 +842,7 @@ void CrossPointWebServer::handleRename() const {
|
||||
return;
|
||||
}
|
||||
|
||||
FsFile file = Storage.open(itemPath.c_str());
|
||||
HalFile file = Storage.open(itemPath.c_str());
|
||||
if (!file) {
|
||||
server->send(500, "text/plain", "Failed to open file");
|
||||
return;
|
||||
@@ -918,7 +918,7 @@ void CrossPointWebServer::handleMove() const {
|
||||
return;
|
||||
}
|
||||
|
||||
FsFile file = Storage.open(itemPath.c_str());
|
||||
HalFile file = Storage.open(itemPath.c_str());
|
||||
if (!file) {
|
||||
server->send(500, "text/plain", "Failed to open file");
|
||||
return;
|
||||
@@ -934,7 +934,7 @@ void CrossPointWebServer::handleMove() const {
|
||||
server->send(404, "text/plain", "Destination not found");
|
||||
return;
|
||||
}
|
||||
FsFile destDir = Storage.open(destPath.c_str());
|
||||
HalFile destDir = Storage.open(destPath.c_str());
|
||||
if (!destDir || !destDir.isDirectory()) {
|
||||
if (destDir) {
|
||||
destDir.close();
|
||||
@@ -1064,10 +1064,10 @@ void CrossPointWebServer::handleDelete() const {
|
||||
|
||||
// Decide whether it's a directory or file by opening it
|
||||
bool success = false;
|
||||
FsFile f = Storage.open(itemPath.c_str());
|
||||
HalFile f = Storage.open(itemPath.c_str());
|
||||
if (f && f.isDirectory()) {
|
||||
// For folders, ensure empty before removing
|
||||
FsFile entry = f.openNextFile();
|
||||
HalFile entry = f.openNextFile();
|
||||
if (entry) {
|
||||
entry.close();
|
||||
f.close();
|
||||
@@ -1741,7 +1741,7 @@ void CrossPointWebServer::handleFontList() const {
|
||||
fileObj["name"] = name ? name + 1 : file.path.c_str();
|
||||
|
||||
// Stat the file for size
|
||||
FsFile f;
|
||||
HalFile f;
|
||||
if (Storage.openFileForRead("WEB", file.path.c_str(), f)) {
|
||||
fileObj["size"] = static_cast<unsigned long>(f.size());
|
||||
f.close();
|
||||
@@ -1848,7 +1848,9 @@ void CrossPointWebServer::handleFontUploadData() {
|
||||
fontUpload.bytesWritten += fontUpload.bufferPos;
|
||||
fontUpload.bufferPos = 0;
|
||||
}
|
||||
fontUpload.file.close();
|
||||
if (fontUpload.file) {
|
||||
fontUpload.file.close();
|
||||
}
|
||||
|
||||
if (!fontUpload.valid && !fontUpload.filePath.empty()) {
|
||||
Storage.remove(fontUpload.filePath.c_str());
|
||||
@@ -1859,7 +1861,9 @@ void CrossPointWebServer::handleFontUploadData() {
|
||||
}
|
||||
|
||||
case UPLOAD_FILE_ABORTED: {
|
||||
fontUpload.file.close();
|
||||
if (fontUpload.file) {
|
||||
fontUpload.file.close();
|
||||
}
|
||||
if (!fontUpload.filePath.empty()) {
|
||||
Storage.remove(fontUpload.filePath.c_str());
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ class CrossPointWebServer {
|
||||
|
||||
// Used by POST upload handler
|
||||
struct UploadState {
|
||||
FsFile file;
|
||||
HalFile file;
|
||||
String fileName;
|
||||
String path = "/";
|
||||
size_t size = 0;
|
||||
@@ -117,7 +117,7 @@ class CrossPointWebServer {
|
||||
|
||||
// Font upload state
|
||||
struct FontUploadState {
|
||||
FsFile file;
|
||||
HalFile file;
|
||||
std::string familyName;
|
||||
std::string filePath;
|
||||
bool valid = false;
|
||||
|
||||
@@ -179,7 +179,7 @@ HttpDownloader::DownloadError HttpDownloader::downloadToFile(const std::string&
|
||||
if (Storage.exists(destPath.c_str())) {
|
||||
Storage.remove(destPath.c_str());
|
||||
}
|
||||
FsFile file;
|
||||
HalFile file;
|
||||
if (!Storage.openFileForWrite("HTTP", destPath.c_str(), file)) {
|
||||
LOG_ERR("HTTP", "Failed to open file for writing");
|
||||
return FILE_ERROR;
|
||||
|
||||
@@ -67,7 +67,7 @@ void WebDAVHandler::raw(WebServer& server, const String& uri, HTTPRaw& raw) {
|
||||
_putExisted = Storage.exists(_putPath.c_str());
|
||||
|
||||
if (_putExisted) {
|
||||
FsFile existing = Storage.open(_putPath.c_str());
|
||||
HalFile existing = Storage.open(_putPath.c_str());
|
||||
if (existing && existing.isDirectory()) {
|
||||
existing.close();
|
||||
_putOk = false;
|
||||
@@ -96,7 +96,7 @@ void WebDAVHandler::raw(WebServer& server, const String& uri, HTTPRaw& raw) {
|
||||
if (_putOk) {
|
||||
String tempPath = _putPath + ".davtmp";
|
||||
if (_putExisted) Storage.remove(_putPath.c_str());
|
||||
FsFile tmp = Storage.open(tempPath.c_str());
|
||||
HalFile tmp = Storage.open(tempPath.c_str());
|
||||
if (tmp) {
|
||||
_putOk = tmp.rename(_putPath.c_str());
|
||||
tmp.close();
|
||||
@@ -182,7 +182,7 @@ void WebDAVHandler::handlePropfind(WebServer& s) {
|
||||
return;
|
||||
}
|
||||
|
||||
FsFile root = Storage.open(path.c_str());
|
||||
HalFile root = Storage.open(path.c_str());
|
||||
if (!root) {
|
||||
if (path == "/") {
|
||||
// Root should always work — send minimal response
|
||||
@@ -221,7 +221,7 @@ void WebDAVHandler::handlePropfind(WebServer& s) {
|
||||
|
||||
// If depth > 0 and it's a directory, list children
|
||||
if (depth > 0) {
|
||||
FsFile file = root.openNextFile();
|
||||
HalFile file = root.openNextFile();
|
||||
char name[500];
|
||||
while (file) {
|
||||
file.getName(name, sizeof(name));
|
||||
@@ -311,7 +311,7 @@ void WebDAVHandler::handleGet(WebServer& s) {
|
||||
return;
|
||||
}
|
||||
|
||||
FsFile file = Storage.open(path.c_str());
|
||||
HalFile file = Storage.open(path.c_str());
|
||||
if (!file) {
|
||||
s.send(500, "text/plain", "Failed to open file");
|
||||
return;
|
||||
@@ -348,7 +348,7 @@ void WebDAVHandler::handleHead(WebServer& s) {
|
||||
return;
|
||||
}
|
||||
|
||||
FsFile file = Storage.open(path.c_str());
|
||||
HalFile file = Storage.open(path.c_str());
|
||||
if (!file) {
|
||||
s.send(500, "text/plain", "");
|
||||
return;
|
||||
@@ -411,7 +411,7 @@ void WebDAVHandler::handleDelete(WebServer& s) {
|
||||
return;
|
||||
}
|
||||
|
||||
FsFile file = Storage.open(path.c_str());
|
||||
HalFile file = Storage.open(path.c_str());
|
||||
if (!file) {
|
||||
s.send(500, "text/plain", "Failed to open");
|
||||
return;
|
||||
@@ -419,7 +419,7 @@ void WebDAVHandler::handleDelete(WebServer& s) {
|
||||
|
||||
if (file.isDirectory()) {
|
||||
// Check if directory is empty
|
||||
FsFile entry = file.openNextFile();
|
||||
HalFile entry = file.openNextFile();
|
||||
if (entry) {
|
||||
entry.close();
|
||||
file.close();
|
||||
@@ -537,7 +537,7 @@ void WebDAVHandler::handleMove(WebServer& s) {
|
||||
Storage.remove(dstPath.c_str());
|
||||
}
|
||||
|
||||
FsFile file = Storage.open(srcPath.c_str());
|
||||
HalFile file = Storage.open(srcPath.c_str());
|
||||
if (!file) {
|
||||
s.send(500, "text/plain", "Failed to open source");
|
||||
return;
|
||||
@@ -583,7 +583,7 @@ void WebDAVHandler::handleCopy(WebServer& s) {
|
||||
return;
|
||||
}
|
||||
|
||||
FsFile srcFile = Storage.open(srcPath.c_str());
|
||||
HalFile srcFile = Storage.open(srcPath.c_str());
|
||||
if (!srcFile) {
|
||||
s.send(500, "text/plain", "Failed to open source");
|
||||
return;
|
||||
@@ -617,7 +617,7 @@ void WebDAVHandler::handleCopy(WebServer& s) {
|
||||
Storage.remove(dstPath.c_str());
|
||||
}
|
||||
|
||||
FsFile dstFile;
|
||||
HalFile dstFile;
|
||||
if (!Storage.openFileForWrite("DAV", dstPath, dstFile)) {
|
||||
srcFile.close();
|
||||
s.send(500, "text/plain", "Failed to create destination");
|
||||
|
||||
@@ -13,7 +13,7 @@ class WebDAVHandler : public RequestHandler {
|
||||
|
||||
private:
|
||||
// PUT streaming state (raw() is called in chunks)
|
||||
FsFile _putFile;
|
||||
HalFile _putFile;
|
||||
String _putPath;
|
||||
bool _putOk = false;
|
||||
bool _putExisted = false;
|
||||
|
||||
@@ -121,7 +121,7 @@ bool ScreenshotUtil::saveFramebufferAsBmp(const char* filename, const uint8_t* f
|
||||
}
|
||||
}
|
||||
|
||||
FsFile file;
|
||||
HalFile file;
|
||||
if (!Storage.openFileForWrite("SCR", filename, file)) {
|
||||
LOG_ERR("SCR", "Failed to save screenshot");
|
||||
return false;
|
||||
|
||||
Reference in New Issue
Block a user