[escher] Create class File and FileSystem

This commit is contained in:
Émilie Feral
2018-02-26 16:54:26 +01:00
committed by EmilieNumworks
parent 4c796d404f
commit c37696133d
6 changed files with 309 additions and 0 deletions

View File

@@ -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\

View File

@@ -22,6 +22,8 @@
#include <escher/expression_table_cell.h>
#include <escher/expression_table_cell_with_pointer.h>
#include <escher/expression_view.h>
#include <escher/file.h>
#include <escher/file_system.h>
#include <escher/gauge_view.h>
#include <escher/highlight_cell.h>
#include <escher/image.h>

View File

@@ -0,0 +1,47 @@
#ifndef ESCHER_FILE_H
#define ESCHER_FILE_H
#include <stdint.h>
#include <stddef.h>
/* 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

View File

@@ -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

67
escher/src/file.cpp Normal file
View File

@@ -0,0 +1,67 @@
#include <escher/file.h>
#include <escher/file_system.h>
#include <string.h>
#include <assert.h>
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;
}

152
escher/src/file_system.cpp Normal file
View File

@@ -0,0 +1,152 @@
#include <escher/file.h>
#include <escher/file_system.h>
#include <string.h>
#include <assert.h>
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;
}