From c37696133d77573a1e3d22531ffe26ea93428998 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Mon, 26 Feb 2018 16:54:26 +0100 Subject: [PATCH] [escher] Create class File and FileSystem --- escher/Makefile | 2 + escher/include/escher.h | 2 + escher/include/escher/file.h | 47 +++++++++ escher/include/escher/file_system.h | 39 +++++++ escher/src/file.cpp | 67 ++++++++++++ escher/src/file_system.cpp | 152 ++++++++++++++++++++++++++++ 6 files changed, 309 insertions(+) create mode 100644 escher/include/escher/file.h create mode 100644 escher/include/escher/file_system.h create mode 100644 escher/src/file.cpp create mode 100644 escher/src/file_system.cpp diff --git a/escher/Makefile b/escher/Makefile index 6723110b5..c9dcf100a 100644 --- a/escher/Makefile +++ b/escher/Makefile @@ -21,6 +21,8 @@ objs += $(addprefix escher/src/,\ expression_table_cell.o\ expression_table_cell_with_pointer.o\ expression_view.o\ + file.o\ + file_system.o\ highlight_cell.o\ gauge_view.o\ image_view.o\ diff --git a/escher/include/escher.h b/escher/include/escher.h index 9a31e8d8c..7749514a4 100644 --- a/escher/include/escher.h +++ b/escher/include/escher.h @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include #include #include diff --git a/escher/include/escher/file.h b/escher/include/escher/file.h new file mode 100644 index 000000000..0a4fa4359 --- /dev/null +++ b/escher/include/escher/file.h @@ -0,0 +1,47 @@ +#ifndef ESCHER_FILE_H +#define ESCHER_FILE_H + +#include +#include + +/* File : | Total Size | Type | Name | Body | */ + +class File { +public: + enum class Type : uint8_t { + Null, + Script + }; + enum class ErrorStatus { + None = 0, + NameTaken = 1, + NameTooLong = 2, + NoEnoughSpaceAvailable = 3 + }; + File(size_t * totalSize = nullptr, char * name = nullptr, Type type = Type::Null, char * body = nullptr); + + bool isNull() const; + + const char * name() const; + ErrorStatus rename(const char * newName); // May fail if name taken or name too long + + const char * read() const; + ErrorStatus write(const char * data, size_t size = 0); // May fail if no more space is available + + Type type(); + + void remove(); // Will always succeed + constexpr static size_t k_nameSize = 50; + constexpr static size_t k_sizeSize = sizeof(size_t); + constexpr static size_t k_typeSize = sizeof(Type); +protected: + size_t bodySize() const; + char * start(); + char * m_body; + size_t * m_size; +private: + char * m_name; + Type m_type; +}; + +#endif diff --git a/escher/include/escher/file_system.h b/escher/include/escher/file_system.h new file mode 100644 index 000000000..312193177 --- /dev/null +++ b/escher/include/escher/file_system.h @@ -0,0 +1,39 @@ +#ifndef ESCHER_FILE_SYSTEM_H +#define ESCHER_FILE_SYSTEM_H + +/* FileSystem : | Magic | File1 | File2 | ... | MagicĀ | + * | Magic | Size1 | Type1 | Name1 | BodySize1 | Body1 | Size2 | Type2 | Name2 | BodySize2 | Body2 | ... | Magic */ + +class FileSystem { +public: + FileSystem(); + static FileSystem * sharedFileSystem(); + int numberOfFileOfType(File::Type type); + File fileOfTypeAtIndex(File::Type type, int index); + File getFile(File::Type type, const char * name); + + File addFile(const char * name, File::Type type, const char * content); + + // availableSize takes into account the the size of the last File must be 0. + size_t availableSize(); + + bool isNameTaken(const char * name, File::Type type); + bool moveNextFile(char * start, int delta); + size_t sizeOfFileWithBody(const char * body) const; +private: + // lastUsedData takes into account the the size of the last File must be 0. + char * lastUsedData(); + size_t * sizeAddressOfFileStarting(char * start) const; + size_t sizeOfFileStarting(char * start) const; + File::Type typeOfFileStarting(char * start) const; + char * nameOfFileStarting(char * start); + char * bodyOfFileStarting(char * start); + constexpr static size_t k_totalSize = 4096; + constexpr static uint32_t Magic = 0xDEC00DF0; + uint32_t m_dataHeader; + char m_data[k_totalSize]; + uint32_t m_dataFooter; +}; + +#endif + diff --git a/escher/src/file.cpp b/escher/src/file.cpp new file mode 100644 index 000000000..fd8ca2e41 --- /dev/null +++ b/escher/src/file.cpp @@ -0,0 +1,67 @@ +#include +#include +#include +#include + +File::File(size_t * size, char * name, Type type, char * body) : + m_body(body), + m_size(size), + m_name(name), + m_type(type) +{ +} + +bool File::isNull() const { + if (m_type == Type::Null) { + assert(m_size == nullptr); + return true; + } + return false; +} + + +const char * File::name() const { + return m_name; +} + +File::ErrorStatus File::rename(const char * newName) { + if (FileSystem::sharedFileSystem()->isNameTaken(newName, m_type)) { + return ErrorStatus::NameTaken; + } + if (strlen(newName) >= k_nameSize) { + return ErrorStatus::NameTooLong; + } + strlcpy(m_name, newName, k_nameSize); + return ErrorStatus::None; +} + +const char * File::read() const { + return m_body; +} + +File::ErrorStatus File::write(const char * data, size_t size) { + int deltaSize = (int)size - (int)bodySize(); + // TODO: if this fails because deltaSize is too big, return an error? + if (FileSystem::sharedFileSystem()->moveNextFile(start(), deltaSize)) { + *m_size += deltaSize; + strlcpy(m_body, data, size); + return ErrorStatus::None; + } + return ErrorStatus::NoEnoughSpaceAvailable; +} + +File::Type File::type() { + return m_type; +} + +void File::remove() { + FileSystem::sharedFileSystem()->moveNextFile(start(), -*(m_size)); +} + +char * File::start() { + return m_name - k_typeSize - k_sizeSize; +} + +size_t File::bodySize() const { + return *m_size - k_nameSize - k_typeSize - k_sizeSize; +} diff --git a/escher/src/file_system.cpp b/escher/src/file_system.cpp new file mode 100644 index 000000000..58d5c5c1d --- /dev/null +++ b/escher/src/file_system.cpp @@ -0,0 +1,152 @@ +#include +#include +#include +#include + +FileSystem::FileSystem() : + m_dataHeader(Magic), + m_data(), + m_dataFooter(Magic) +{ + size_t * p = (size_t *)m_data; + p[0] = 0; +} + +FileSystem * FileSystem::sharedFileSystem() { + static FileSystem f; + return &f; +} + +int FileSystem::numberOfFileOfType(File::Type type) { + assert(m_dataHeader == Magic); + assert(m_dataFooter == Magic); + int count = 0; + char * currentPointer = m_data; + size_t size = sizeOfFileStarting(currentPointer); + while (size != 0 && currentPointer < m_data + k_totalSize) { + if (typeOfFileStarting(currentPointer) == type) { + count++; + } + currentPointer += size; + size = sizeOfFileStarting(currentPointer); + } + return count; +} + +File FileSystem::fileOfTypeAtIndex(File::Type type, int index) { + int currentIndex = -1; + char * currentPointer = m_data; + size_t size = sizeOfFileStarting(currentPointer); + while (size != 0 && currentPointer < m_data + k_totalSize) { + if (typeOfFileStarting(currentPointer) == type) { + currentIndex++; + if (currentIndex == index) { + break; + } + } + currentPointer += size; + size = sizeOfFileStarting(currentPointer); + } + return File(sizeAddressOfFileStarting(currentPointer), nameOfFileStarting(currentPointer), type, bodyOfFileStarting(currentPointer)); +} + +File FileSystem::getFile(File::Type type, const char * name) { + for (int i = 0; i < numberOfFileOfType(type); i++) { + File currentFile = fileOfTypeAtIndex(type, i); + if (strcmp(currentFile.name(), name) == 0) { + return currentFile; + } + } + return File(); +} + +File FileSystem::addFile(const char * name, File::Type type, const char * body) { + // assert name is short enough and there is enough space to add the file + assert(strlen(name) < File::k_nameSize); + assert(availableSize() >= sizeOfFileWithBody(body)); + // Find the end of data + char * currentPointer = m_data; + size_t size = sizeOfFileStarting(currentPointer); + while (size != 0 && currentPointer < m_data + k_totalSize) { + currentPointer += size; + size = sizeOfFileStarting(currentPointer); + } + size_t fileSize = sizeOfFileWithBody(body); + // Fill totalSize + *((size_t *)currentPointer) = fileSize; + // Fill type + *(currentPointer+File::k_sizeSize) = (uint8_t)type; + // Fill name + strlcpy(currentPointer+File::k_sizeSize+File::k_typeSize, name, File::k_nameSize); + // Fill body + strlcpy(currentPointer+File::k_sizeSize+File::k_typeSize+File::k_nameSize, body, strlen(body)+1); + char * nextPointer = currentPointer + fileSize; + *((size_t *)nextPointer) = 0; + return File(sizeAddressOfFileStarting(currentPointer), nameOfFileStarting(currentPointer), type, bodyOfFileStarting(currentPointer)); +} + +char * FileSystem::lastUsedData() { + size_t usedSize = 0; + char * currentPointer = m_data; + size_t size = sizeOfFileStarting(currentPointer); + while (size != 0 && currentPointer < m_data + k_totalSize) { + usedSize += size; + currentPointer += size; + size = sizeOfFileStarting(currentPointer); + } + return currentPointer + File::k_sizeSize; +} + + +size_t FileSystem::availableSize() { + return k_totalSize-(lastUsedData()-m_data); +} + +bool FileSystem::isNameTaken(const char * name, File::Type type) { + char * currentPointer = m_data; + size_t size = sizeOfFileStarting(currentPointer); + while (size != 0 && currentPointer < m_data + k_totalSize) { + if (typeOfFileStarting(currentPointer) == type && strcmp(nameOfFileStarting(currentPointer), name) == 0) { + return true; + } + currentPointer += size; + size = sizeOfFileStarting(currentPointer); + } + return false; +} + +bool FileSystem::moveNextFile(char * start, int delta) { + if (delta > (int)availableSize()) { + return false; + } + char * nextFile = start + sizeOfFileStarting(start); + memmove(nextFile+delta, nextFile, lastUsedData()-nextFile); + return true; +} + +size_t * FileSystem::sizeAddressOfFileStarting(char * start) const { + return (size_t *)start; +} + +size_t FileSystem::sizeOfFileStarting(char * start) const { + if (start >= m_data + k_totalSize) { + return 0; + } + return *(sizeAddressOfFileStarting(start)); +} + +File::Type FileSystem::typeOfFileStarting(char * start) const { + return (File::Type)*((uint8_t *)start+File::k_sizeSize); +} + +char * FileSystem::nameOfFileStarting(char * start) { + return start+File::k_sizeSize+File::k_typeSize; +} + +char * FileSystem::bodyOfFileStarting(char * start) { + return start+File::k_sizeSize+File::k_typeSize+File::k_nameSize; +} + +size_t FileSystem::sizeOfFileWithBody(const char * body) const { + return File::k_sizeSize+File::k_typeSize+File::k_nameSize+strlen(body)+1; +}