From 3eced66dcd8f9741de82dfc1098cdacaac96b087 Mon Sep 17 00:00:00 2001 From: mikee47 Date: Thu, 18 Oct 2018 22:23:33 +0100 Subject: [PATCH] Changes to FileStream class * Add close() method * Change size, pos to size_t * Handle value < 0 if invalid * bugfix: available() returned wrong value * Remove write(uint8_t) method, implemented in ReadWriteStream * Add getLastError() method and track file error code internally * Additional file API error checks * Don't prevent negative offsets in seek() method, perfectly legitimate * Track file position in write() method --- Sming/SmingCore/Data/Stream/FileStream.cpp | 118 +++++++++++---------- Sming/SmingCore/Data/Stream/FileStream.h | 108 +++++++++++++++---- 2 files changed, 151 insertions(+), 75 deletions(-) diff --git a/Sming/SmingCore/Data/Stream/FileStream.cpp b/Sming/SmingCore/Data/Stream/FileStream.cpp index 55aa2fdf6f..5e2512dc47 100644 --- a/Sming/SmingCore/Data/Stream/FileStream.cpp +++ b/Sming/SmingCore/Data/Stream/FileStream.cpp @@ -9,100 +9,105 @@ /* FileStream */ -FileStream::FileStream() +void FileStream::attach(file_t file, size_t size) { - handle = -1; - size = -1; - pos = 0; + close(); + if(file >= 0) { + handle = file; + this->size = size; + fileSeek(handle, 0, eSO_FileStart); + pos = 0; + debug_d("attached file: '%s' (%u bytes) #0x%08X", fileName().c_str(), size, this); + } } -FileStream::FileStream(const String& filename) +bool FileStream::open(const String& fileName, FileOpenFlags openFlags) { - attach(filename, eFO_ReadOnly); -} + lastError = SPIFFS_OK; -bool FileStream::attach(const String& fileName, FileOpenFlags openFlags) -{ - handle = fileOpen(fileName.c_str(), openFlags); - if(handle == -1) { + file_t file = fileOpen(fileName, openFlags); + if(!check(file)) { debug_w("File wasn't found: %s", fileName.c_str()); - size = -1; - pos = 0; return false; } // Get size - fileSeek(handle, 0, eSO_FileEnd); - size = fileTell(handle); - - fileSeek(handle, 0, eSO_FileStart); - pos = 0; + if(check(fileSeek(file, 0, eSO_FileEnd))) { + int size = fileTell(file); + if(check(size)) { + attach(file, size); + return true; + } + } - debug_d("attached file: %s (%d bytes)", fileName.c_str(), size); - return true; + fileClose(file); + return false; } -FileStream::~FileStream() +void FileStream::close() { - fileClose(handle); - handle = 0; + if(handle >= 0) { + fileClose(handle); + handle = -1; + } + size = 0; pos = 0; + lastError = SPIFFS_OK; } uint16_t FileStream::readMemoryBlock(char* data, int bufSize) { - int len = std::min(bufSize, size - pos); - int available = fileRead(handle, data, len); - fileSeek(handle, pos, eSO_FileStart); // Don't move cursor now (waiting seek) - if(available < 0) { - available = 0; + if(data == nullptr || bufSize <= 0 || pos >= size) { + return 0; } - return available; -} -size_t FileStream::write(uint8_t charToWrite) -{ - uint8_t tempbuf[1]{charToWrite}; - return write(tempbuf, 1); + int available = fileRead(handle, data, std::min(size - pos, size_t(bufSize))); + check(available); + + // Don't move cursor now (waiting seek) + fileSeek(handle, pos, eSO_FileStart); + + return available > 0 ? available : 0; } size_t FileStream::write(const uint8_t* buffer, size_t size) { - if(!fileExist()) + if(!fileExist()) { return 0; + } + + int pos = fileSeek(handle, 0, eSO_FileEnd); + if(!check(pos)) { + return 0; + } - fileSeek(handle, 0, eSO_FileEnd); - return fileWrite(handle, buffer, size); + this->pos = size_t(pos); + + int written = fileWrite(handle, buffer, size); + if(check(written)) { + this->pos += size_t(written); + } + + return written; } bool FileStream::seek(int len) { - if(len < 0) + int newpos = fileSeek(handle, len, eSO_CurrentPos); + if(!check(newpos)) { return false; + } - bool result = fileSeek(handle, len, eSO_CurrentPos) >= 0; - if(result) - pos += len; - return result; -} + pos = newpos; -bool FileStream::isFinished() -{ - return fileIsEOF(handle); + return true; } String FileStream::fileName() const { spiffs_stat stat; - if(fileStats(handle, &stat) < 0) - return nullptr; - else - return String((char*)stat.name); -} - -bool FileStream::fileExist() const -{ - return size != -1; + fileStats(handle, &stat); + return String(reinterpret_cast(stat.name)); } String FileStream::id() const @@ -112,7 +117,8 @@ String FileStream::id() const #define ETAG_SIZE 16 char buf[ETAG_SIZE]; - m_snprintf(buf, ETAG_SIZE, _F("00f-%x-%x0-%x"), stat.obj_id, stat.size, strlen((char*)stat.name)); + m_snprintf(buf, ETAG_SIZE, _F("00f-%x-%x0-%x"), stat.obj_id, stat.size, + strlen(reinterpret_cast(stat.name))); return String(buf); } diff --git a/Sming/SmingCore/Data/Stream/FileStream.h b/Sming/SmingCore/Data/Stream/FileStream.h index febbe575c5..005c4b5526 100644 --- a/Sming/SmingCore/Data/Stream/FileStream.h +++ b/Sming/SmingCore/Data/Stream/FileStream.h @@ -21,21 +21,53 @@ class FileStream : public ReadWriteStream { public: + FileStream() + { + } + /** @brief Create a file stream * @param fileName Name of file to open */ - FileStream(); - FileStream(const String& fileName); - virtual ~FileStream(); + FileStream(const String& fileName, FileOpenFlags openFlags = eFO_ReadOnly) + { + open(fileName, openFlags); + } + + virtual ~FileStream() + { + close(); + } + + /** @brief Attach this stream object to an open file handle + * @param file + * @param size + */ + void attach(file_t file, size_t size); + + /* @deprecated: use open() method */ + bool attach(const String& fileName, FileOpenFlags openFlags = eFO_ReadOnly) + { + return open(fileName, openFlags); + } + + /** @brief Open a file and attach this stream object to it + * @param fileName + * @param openFlags + * @retval bool true on success, false on error + * @note call getLastError() to determine cause of failure + */ + bool open(const String& fileName, FileOpenFlags openFlags = eFO_ReadOnly); + + /** @brief Close file + */ + void close(); - virtual bool attach(const String& fileName, FileOpenFlags openFlags); //Use base class documentation virtual StreamType getStreamType() const { return eSST_File; } - virtual size_t write(uint8_t charToWrite); virtual size_t write(const uint8_t* buffer, size_t size); //Use base class documentation @@ -45,10 +77,24 @@ class FileStream : public ReadWriteStream virtual bool seek(int len); //Use base class documentation - virtual bool isFinished(); + virtual bool isFinished() + { + return fileIsEOF(handle); + } + + /** @brief Filename of file stream is attached to + * @retval String invalid if stream isn't open + */ + String fileName() const; + + /** @brief Determine if file exists + * @retval bool true if stream contains valid file + */ + bool fileExist() const + { + return handle >= 0; + } - String fileName() const; ///< Filename of file stream is attached to - bool fileExist() const; ///< True if file exists virtual String getName() const { return fileName(); @@ -60,30 +106,54 @@ class FileStream : public ReadWriteStream } /** @brief Get the offset of cursor from beginning of data - * @retval int Cursor offset + * @retval size_t Cursor offset */ - inline int getPos() + size_t getPos() const { return pos; } - /** - * @brief Return the total length of the stream - * @retval int -1 is returned when the size cannot be determined + /** @brief Return the total length of the stream + * @retval int -1 is returned when the size cannot be determined */ - int available() + virtual int available() { - return size; + return size - pos; } virtual String id() const; + /** @brief determine if an error occurred during operation + * @retval int filesystem error code + */ + int getLastError() + { + return lastError; + } + +private: + /** @brief Check file operation result and note error code + * @param res result of fileXXX() operation to check + * @retval bool true if operation was successful, false if error occurred + */ + bool check(int res) + { + if(res >= 0) { + return true; + } + + if(lastError >= 0) { + lastError = res; + } + return false; + } + private: - file_t handle; - int pos; - int size; + file_t handle = -1; + size_t pos = 0; + size_t size = 0; + int lastError = SPIFFS_OK; }; -/** @} */ /** @} */