mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-01-19 00:37:25 +01:00
[poincare] Ion::Storage handles fullnames and basenames with extensions
This commit is contained in:
@@ -5,19 +5,24 @@
|
||||
|
||||
namespace Ion {
|
||||
|
||||
/* Storage : | Magic | Record1 | Record2 | ... | Magic |
|
||||
* | Magic | Size1(uint16_t) | Name1 | Body1 | Size2(uint16_t) | Name2 | Body2 | ... | Magic */
|
||||
/* Storage : | Magic | Record1 | Record2 | ... | Magic |
|
||||
* | Magic | Size1(uint16_t) | FullName1 | Body1 | Size2(uint16_t) | FullName2 | Body2 | ... | Magic |
|
||||
*
|
||||
* A record's fullName is baseName.extension. */
|
||||
|
||||
class Storage {
|
||||
public:
|
||||
typedef uint16_t record_size_t;
|
||||
constexpr static size_t k_storageSize = 16384;
|
||||
static Storage * sharedStorage();
|
||||
|
||||
class Record {
|
||||
/* A Record is identified by the CRC32 on his name because:
|
||||
* - a record is identified by its name which is unique
|
||||
* - we cannot keep the address pointing to the name because if another
|
||||
* record is modified, it might alter our record name address and keeping
|
||||
* a buffer with the name will waste memory as we cannot forsee the size
|
||||
* of the name. */
|
||||
/* A Record is identified by the CRC32 on its fullName because:
|
||||
* - A record is identified by its fullName, which is unique
|
||||
* - We cannot keep the address pointing to the fullName because if another
|
||||
* record is modified, it might alter our record's fullName address.
|
||||
* Keeping a buffer with the fullNames will waste memory as we cannot
|
||||
* forsee the size of the fullNames. */
|
||||
friend class Storage;
|
||||
public:
|
||||
enum class ErrorStatus {
|
||||
@@ -31,18 +36,19 @@ public:
|
||||
const void * buffer;
|
||||
size_t size;
|
||||
};
|
||||
Record(const char * name = nullptr);
|
||||
Record(const char * fullName = nullptr);
|
||||
Record(const char * basename, const char * extension);
|
||||
bool operator==(const Record & other) const {
|
||||
return m_nameCRC32 == other.m_nameCRC32;
|
||||
return m_fullNameCRC32 == other.m_fullNameCRC32;
|
||||
}
|
||||
bool isNull() const {
|
||||
return m_nameCRC32 == 0;
|
||||
return m_fullNameCRC32 == 0;
|
||||
}
|
||||
const char * name() const {
|
||||
return Storage::sharedStorage()->nameOfRecord(*this);
|
||||
const char * fullName() const {
|
||||
return Storage::sharedStorage()->fullNameOfRecord(*this);
|
||||
}
|
||||
ErrorStatus setName(const char * name) {
|
||||
return Storage::sharedStorage()->setNameOfRecord(*this, name);
|
||||
ErrorStatus setName(const char * fullName) {
|
||||
return Storage::sharedStorage()->setFullNameOfRecord(*this, fullName);
|
||||
}
|
||||
Data value() const {
|
||||
return Storage::sharedStorage()->valueOfRecord(*this);
|
||||
@@ -54,41 +60,55 @@ public:
|
||||
return Storage::sharedStorage()->destroyRecord(*this);
|
||||
}
|
||||
private:
|
||||
uint32_t m_nameCRC32;
|
||||
Record(const char * basename, int basenameLength, const char * extension, int extensionLength);
|
||||
uint32_t m_fullNameCRC32;
|
||||
};
|
||||
|
||||
Storage();
|
||||
size_t availableSize();
|
||||
Record::ErrorStatus createRecord(const char * name, const void * data, size_t size);
|
||||
int numberOfRecordsWithExtension(const char * extension);
|
||||
|
||||
// Record creation
|
||||
Record::ErrorStatus createRecordWithExtension(const char * baseName, const char * extension, const void * data, size_t size);
|
||||
|
||||
// Record getters
|
||||
Record recordWithExtensionAtIndex(const char * extension, int index);
|
||||
Record recordNamed(const char * name);
|
||||
typedef uint16_t record_size_t;
|
||||
constexpr static size_t k_storageSize = 16384;
|
||||
Record recordNamed(const char * fullName);
|
||||
Record recordBaseNamedWithExtension(const char * baseName, const char * extension);
|
||||
Record recordBaseNamedWithExtensions(const char * baseName, const char * extension[], size_t numberOfExtensions);
|
||||
|
||||
private:
|
||||
constexpr static uint32_t Magic = 0xEE0BDDBA;
|
||||
constexpr static size_t k_maxRecordSize = (1 << sizeof(record_size_t)*8);
|
||||
constexpr static char k_dotChar = '.';
|
||||
|
||||
/* Getters/Setters on recordID */
|
||||
const char * nameOfRecord(const Record record);
|
||||
Record::ErrorStatus setNameOfRecord(const Record record, const char * name);
|
||||
const char * fullNameOfRecord(const Record record);
|
||||
Record::ErrorStatus setFullNameOfRecord(const Record record, const char * fullName);
|
||||
Record::ErrorStatus setBaseNameWithExtensionOfRecord(const Record record, const char * baseName, const char * extension);
|
||||
Record::Data valueOfRecord(const Record record);
|
||||
Record::ErrorStatus setValueOfRecord(const Record record, Record::Data data);
|
||||
void destroyRecord(const Record record);
|
||||
|
||||
/* Getters on address in buffer */
|
||||
record_size_t sizeOfRecordStarting(char * start) const;
|
||||
const char * nameOfRecordStarting(char * start) const;
|
||||
const char * fullNameOfRecordStarting(char * start) const;
|
||||
const void * valueOfRecordStarting(char * start) const;
|
||||
|
||||
/* Overriders */
|
||||
size_t overrideSizeAtPosition(char * position, record_size_t size);
|
||||
size_t overrideNameAtPosition(char * position, const char * name);
|
||||
size_t overrideFullNameAtPosition(char * position, const char * fullName);
|
||||
size_t overrideBaseNameWithExtensionAtPosition(char * position, const char * baseName, const char * extension);
|
||||
size_t overrideValueAtPosition(char * position, const void * data, record_size_t size);
|
||||
|
||||
bool isNameTaken(const char * name, Record * recordToExclude = nullptr);
|
||||
static bool nameCompliant(const char * name);
|
||||
bool isFullNameTaken(const char * fullName, const Record * recordToExclude = nullptr);
|
||||
bool isBaseNameWithExtensionTaken(const char * baseName, const char * extension, Record * recordToExclude = nullptr);
|
||||
static bool fullNameCompliant(const char * name);
|
||||
bool fullNameHasExtension(const char * fullName, const char * extension, size_t extensionLength);
|
||||
char * endBuffer();
|
||||
size_t sizeOfRecord(const char * name, size_t size) const;
|
||||
size_t sizeOfBaseNameAndExtension(const char * baseName, const char * extension) const;
|
||||
size_t sizeOfRecordWithBaseNameAndExtension(const char * baseName, const char * extension, size_t size) const;
|
||||
size_t sizeOfRecordWithFullName(const char * fullName, size_t size) const;
|
||||
bool slideBuffer(char * position, int delta);
|
||||
class RecordIterator {
|
||||
public:
|
||||
|
||||
@@ -27,32 +27,60 @@ Storage * Storage::sharedStorage() {
|
||||
return storage;
|
||||
}
|
||||
|
||||
Storage::Record::Record(const char * name) {
|
||||
if (name == nullptr) {
|
||||
m_nameCRC32 = 0;
|
||||
// RECORD
|
||||
|
||||
Storage::Record::Record(const char * fullName) {
|
||||
if (fullName == nullptr) {
|
||||
m_fullNameCRC32 = 0;
|
||||
return;
|
||||
}
|
||||
/* name is a char table. Its length in Bytes is not necessarilly a multiple
|
||||
* of 4. However, crc32 method awaits input in a form of uint32_t table. To
|
||||
* limit the use of additional memory, we compute 2 crc32:
|
||||
* - one corresponding to name with a byte length truncated to be a multiple
|
||||
* of 4
|
||||
* - the other corresponds to the remaining chars in name padded with 0 to be
|
||||
* 4 bytes length
|
||||
* The name CRC32 is the crc32 of both. */
|
||||
uint32_t crc32Results[2];
|
||||
// CRC32 of the truncated name
|
||||
size_t length = strlen(name);
|
||||
size_t crc32TruncatedInputSize = length*sizeof(char)/sizeof(uint32_t);
|
||||
crc32Results[0] = Ion::crc32((const uint32_t *)name, crc32TruncatedInputSize);
|
||||
|
||||
// CRC32 of the tail of name
|
||||
uint32_t tailName = 0;
|
||||
strlcpy((char *)&tailName, name+crc32TruncatedInputSize*sizeof(uint32_t), sizeof(uint32_t)/sizeof(char));
|
||||
crc32Results[1] = Ion::crc32(&tailName, 1);
|
||||
m_nameCRC32 = Ion::crc32(crc32Results, 2);
|
||||
const char * dotChar = strchr(fullName, k_dotChar);
|
||||
assert(dotChar != nullptr);
|
||||
assert(*(dotChar+1) != 0); // Assert there is an extension
|
||||
new (this) Record(fullName, dotChar - fullName + 1, dotChar+1, (fullName + strlen(fullName)) - (dotChar+1) +1);
|
||||
}
|
||||
|
||||
Storage::Record::Record(const char * baseName, const char * extension) {
|
||||
if (baseName == nullptr) {
|
||||
assert(extension == nullptr);
|
||||
m_fullNameCRC32 = 0;
|
||||
return;
|
||||
}
|
||||
new (this) Record(baseName, strlen(baseName), extension, strlen(extension));
|
||||
}
|
||||
|
||||
void Crc32PaddedString(const char * s, int length, uint32_t * crcStore) {
|
||||
/* s is a char array. Its length in Bytes is not necessarily a multiple of 4.
|
||||
* However, crc32 method awaits input in a form of uint32_t table. To limit
|
||||
* the use of additional memory, we compute 2 crc32:
|
||||
* - one corresponding to s with a byte length truncated to be a multiple of 4
|
||||
* - the other corresponds to the remaining chars in s padded with 0 to be 4
|
||||
* bytes long
|
||||
* The CRC32 of s is the crc32 of both. */
|
||||
|
||||
// CRC32 of the truncated string
|
||||
size_t crc32TruncatedInputSize = length*sizeof(char)/sizeof(uint32_t);
|
||||
*crcStore = Ion::crc32((const uint32_t *)s, crc32TruncatedInputSize);
|
||||
|
||||
// CRC32 of the tail of the string
|
||||
uint32_t tailName = 0;
|
||||
strlcpy((char *)&tailName, s+crc32TruncatedInputSize*sizeof(uint32_t), sizeof(uint32_t)/sizeof(char));
|
||||
*(crcStore+1) = Ion::crc32(&tailName, 1);
|
||||
}
|
||||
|
||||
Storage::Record::Record(const char * basename, int basenameLength, const char * extension, int extensionLength) {
|
||||
assert(basename != nullptr);
|
||||
assert(extension != nullptr);
|
||||
|
||||
// We compute the CRC32 of the CRC32s of the basename and the extension
|
||||
uint32_t crc32Results[4];
|
||||
Crc32PaddedString(basename, basenameLength, &crc32Results[0]);
|
||||
Crc32PaddedString(extension, extensionLength, &crc32Results[2]);
|
||||
m_fullNameCRC32 = Ion::crc32(crc32Results, 4);
|
||||
}
|
||||
|
||||
// STORAGE
|
||||
|
||||
Storage::Storage() :
|
||||
m_magicHeader(Magic),
|
||||
m_buffer(),
|
||||
@@ -68,15 +96,12 @@ size_t Storage::availableSize() {
|
||||
return k_storageSize-(endBuffer()-m_buffer)-sizeof(record_size_t);
|
||||
}
|
||||
|
||||
Storage::Record::ErrorStatus Storage::createRecord(const char * name, const void * data, size_t size) {
|
||||
if (!nameCompliant(name)) {
|
||||
return Record::ErrorStatus::NonCompliantName;
|
||||
}
|
||||
size_t recordSize = sizeOfRecord(name, size);
|
||||
Storage::Record::ErrorStatus Storage::createRecordWithExtension(const char * baseName, const char * extension, const void * data, size_t size) {
|
||||
size_t recordSize = sizeOfRecordWithBaseNameAndExtension(baseName, extension, size);
|
||||
if (recordSize >= k_maxRecordSize || recordSize > availableSize()) {
|
||||
return Record::ErrorStatus::NotEnoughSpaceAvailable;
|
||||
}
|
||||
if (isNameTaken(name)) {
|
||||
if (isBaseNameWithExtensionTaken(baseName, extension)) {
|
||||
return Record::ErrorStatus::NameTaken;
|
||||
}
|
||||
// Find the end of data
|
||||
@@ -84,7 +109,7 @@ Storage::Record::ErrorStatus Storage::createRecord(const char * name, const void
|
||||
// Fill totalSize
|
||||
newRecord += overrideSizeAtPosition(newRecord, (record_size_t)recordSize);
|
||||
// Fill name
|
||||
newRecord += overrideNameAtPosition(newRecord, name);
|
||||
newRecord += overrideBaseNameWithExtensionAtPosition(newRecord, baseName, extension);
|
||||
// Fill data
|
||||
newRecord += overrideValueAtPosition(newRecord, data, size);
|
||||
// Next Record is null-sized
|
||||
@@ -94,10 +119,10 @@ Storage::Record::ErrorStatus Storage::createRecord(const char * name, const void
|
||||
|
||||
int Storage::numberOfRecordsWithExtension(const char * extension) {
|
||||
int count = 0;
|
||||
size_t extensionLength = strlen(extension);
|
||||
for (char * p : *this) {
|
||||
const char * name = nameOfRecordStarting(p);
|
||||
const char * ext = name+strlen(name)-strlen(extension);
|
||||
if (strcmp(ext, extension) == 0) {
|
||||
const char * name = fullNameOfRecordStarting(p);
|
||||
if (fullNameHasExtension(name, extension, extensionLength)) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
@@ -107,10 +132,10 @@ int Storage::numberOfRecordsWithExtension(const char * extension) {
|
||||
Storage::Record Storage::recordWithExtensionAtIndex(const char * extension, int index) {
|
||||
int currentIndex = -1;
|
||||
const char * name = nullptr;
|
||||
size_t extensionLength = strlen(extension);
|
||||
for (char * p : *this) {
|
||||
const char * currentName = nameOfRecordStarting(p);
|
||||
const char * currentExtension = currentName+strlen(currentName)-strlen(extension);
|
||||
if (strcmp(currentExtension, extension) == 0) {
|
||||
const char * currentName = fullNameOfRecordStarting(p);
|
||||
if (fullNameHasExtension(currentName, extension, extensionLength)) {
|
||||
currentIndex++;
|
||||
}
|
||||
if (currentIndex == index) {
|
||||
@@ -124,45 +149,87 @@ Storage::Record Storage::recordWithExtensionAtIndex(const char * extension, int
|
||||
return Record(name);
|
||||
}
|
||||
|
||||
Storage::Record Storage::recordNamed(const char * name) {
|
||||
Storage::Record Storage::recordNamed(const char * fullName) {
|
||||
for (char * p : *this) {
|
||||
const char * currentName = nameOfRecordStarting(p);
|
||||
if (strcmp(currentName, name) == 0) {
|
||||
return Record(name);
|
||||
const char * currentName = fullNameOfRecordStarting(p);
|
||||
if (strcmp(currentName, fullName) == 0) {
|
||||
return Record(fullName);
|
||||
}
|
||||
}
|
||||
return Record();
|
||||
}
|
||||
|
||||
const char * Storage::nameOfRecord(const Record record) {
|
||||
Storage::Record Storage::recordBaseNamedWithExtension(const char * baseName, const char * extension) {
|
||||
const char * extensions[1] = {extension};
|
||||
return recordBaseNamedWithExtensions(baseName, extensions, 1);
|
||||
}
|
||||
|
||||
Storage::Record Storage::recordBaseNamedWithExtensions(const char * baseName, const char * extensions[], size_t numberOfExtensions) {
|
||||
size_t nameLength = strlen(baseName);
|
||||
for (char * p : *this) {
|
||||
Record currentRecord(nameOfRecordStarting(p));
|
||||
const char * currentName = fullNameOfRecordStarting(p);
|
||||
if (strncmp(currentName, baseName, nameLength) == 0) {
|
||||
for (size_t i = 0; i < numberOfExtensions; i++) {
|
||||
if (strcmp(currentName+nameLength+1 /*+1 to pass the dot*/, extensions[i]) == 0) {
|
||||
return Record(currentName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return Record();
|
||||
}
|
||||
|
||||
const char * Storage::fullNameOfRecord(const Record record) {
|
||||
for (char * p : *this) {
|
||||
Record currentRecord(fullNameOfRecordStarting(p));
|
||||
if (record == currentRecord) {
|
||||
return nameOfRecordStarting(p);
|
||||
return fullNameOfRecordStarting(p);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Storage::Record::ErrorStatus Storage::setNameOfRecord(Record record, const char * name) {
|
||||
if (!nameCompliant(name)) {
|
||||
Storage::Record::ErrorStatus Storage::setFullNameOfRecord(const Record record, const char * fullName) {
|
||||
if (!fullNameCompliant(fullName)) {
|
||||
return Record::ErrorStatus::NonCompliantName;
|
||||
}
|
||||
if (isNameTaken(name, &record)) {
|
||||
if (isFullNameTaken(fullName, &record)) {
|
||||
return Record::ErrorStatus::NameTaken;
|
||||
}
|
||||
size_t nameSize = strlen(name)+1;
|
||||
size_t nameSize = strlen(fullName) + 1;
|
||||
for (char * p : *this) {
|
||||
Record currentRecord(nameOfRecordStarting(p));
|
||||
Record currentRecord(fullNameOfRecordStarting(p));
|
||||
if (record == currentRecord) {
|
||||
size_t previousNameSize = strlen(nameOfRecordStarting(p))+1;
|
||||
size_t previousNameSize = strlen(fullNameOfRecordStarting(p))+1;
|
||||
record_size_t previousRecordSize = sizeOfRecordStarting(p);
|
||||
size_t newRecordSize = previousRecordSize-previousNameSize+nameSize;
|
||||
if (newRecordSize >= k_maxRecordSize || !slideBuffer(p+sizeof(record_size_t)+previousNameSize, nameSize-previousNameSize)) {
|
||||
return Record::ErrorStatus::NotEnoughSpaceAvailable;
|
||||
}
|
||||
overrideSizeAtPosition(p, newRecordSize);
|
||||
overrideNameAtPosition(p+sizeof(record_size_t), name);
|
||||
overrideFullNameAtPosition(p+sizeof(record_size_t), fullName);
|
||||
return Record::ErrorStatus::None;
|
||||
}
|
||||
}
|
||||
return Record::ErrorStatus::RecordDoesNotExist;
|
||||
}
|
||||
|
||||
Storage::Record::ErrorStatus Storage::setBaseNameWithExtensionOfRecord(Record record, const char * baseName, const char * extension) {
|
||||
if (isBaseNameWithExtensionTaken(baseName, extension, &record)) {
|
||||
return Record::ErrorStatus::NameTaken;
|
||||
}
|
||||
size_t nameSize = sizeOfBaseNameAndExtension(baseName, extension);
|
||||
for (char * p : *this) {
|
||||
Record currentRecord(fullNameOfRecordStarting(p));
|
||||
if (record == currentRecord) {
|
||||
size_t previousNameSize = strlen(fullNameOfRecordStarting(p))+1;
|
||||
record_size_t previousRecordSize = sizeOfRecordStarting(p);
|
||||
size_t newRecordSize = previousRecordSize-previousNameSize+nameSize;
|
||||
if (newRecordSize >= k_maxRecordSize || !slideBuffer(p+sizeof(record_size_t)+previousNameSize, nameSize-previousNameSize)) {
|
||||
return Record::ErrorStatus::NotEnoughSpaceAvailable;
|
||||
}
|
||||
overrideSizeAtPosition(p, newRecordSize);
|
||||
overrideBaseNameWithExtensionAtPosition(p+sizeof(record_size_t), baseName, extension);
|
||||
return Record::ErrorStatus::None;
|
||||
}
|
||||
}
|
||||
@@ -171,12 +238,12 @@ Storage::Record::ErrorStatus Storage::setNameOfRecord(Record record, const char
|
||||
|
||||
Storage::Record::Data Storage::valueOfRecord(const Record record) {
|
||||
for (char * p : *this) {
|
||||
Record currentRecord(nameOfRecordStarting(p));
|
||||
Record currentRecord(fullNameOfRecordStarting(p));
|
||||
if (record == currentRecord) {
|
||||
const char * name = nameOfRecordStarting(p);
|
||||
const char * fullName = fullNameOfRecordStarting(p);
|
||||
record_size_t size = sizeOfRecordStarting(p);
|
||||
const void * value = valueOfRecordStarting(p);
|
||||
return {.buffer= value, .size= size-strlen(name)-1-sizeof(record_size_t)};
|
||||
return {.buffer= value, .size= size-strlen(fullName)-1-sizeof(record_size_t)};
|
||||
}
|
||||
}
|
||||
return {.buffer= nullptr, .size= 0};
|
||||
@@ -184,17 +251,17 @@ Storage::Record::Data Storage::valueOfRecord(const Record record) {
|
||||
|
||||
Storage::Record::ErrorStatus Storage::setValueOfRecord(Record record, Record::Data data) {
|
||||
for (char * p : *this) {
|
||||
Record currentRecord(nameOfRecordStarting(p));
|
||||
Record currentRecord(fullNameOfRecordStarting(p));
|
||||
if (record == currentRecord) {
|
||||
record_size_t previousRecordSize = sizeOfRecordStarting(p);
|
||||
const char * name = nameOfRecordStarting(p);
|
||||
size_t newRecordSize = sizeOfRecord(name, data.size);
|
||||
const char * fullName = fullNameOfRecordStarting(p);
|
||||
size_t newRecordSize = sizeOfRecordWithFullName(fullName, data.size);
|
||||
if (newRecordSize >= k_maxRecordSize || !slideBuffer(p+previousRecordSize, newRecordSize-previousRecordSize)) {
|
||||
return Record::ErrorStatus::NotEnoughSpaceAvailable;
|
||||
}
|
||||
record_size_t nameSize = strlen(name)+1;
|
||||
record_size_t fullNameSize = strlen(fullName)+1;
|
||||
overrideSizeAtPosition(p, newRecordSize);
|
||||
overrideValueAtPosition(p+sizeof(record_size_t)+nameSize, data.buffer, data.size);
|
||||
overrideValueAtPosition(p+sizeof(record_size_t)+fullNameSize, data.buffer, data.size);
|
||||
return Record::ErrorStatus::None;
|
||||
}
|
||||
}
|
||||
@@ -203,7 +270,7 @@ Storage::Record::ErrorStatus Storage::setValueOfRecord(Record record, Record::Da
|
||||
|
||||
void Storage::destroyRecord(Record record) {
|
||||
for (char * p : *this) {
|
||||
Record currentRecord(nameOfRecordStarting(p));
|
||||
Record currentRecord(fullNameOfRecordStarting(p));
|
||||
if (record == currentRecord) {
|
||||
record_size_t previousRecordSize = sizeOfRecordStarting(p);
|
||||
slideBuffer(p+previousRecordSize, -previousRecordSize);
|
||||
@@ -235,7 +302,7 @@ Storage::record_size_t Storage::sizeOfRecordStarting(char * start) const {
|
||||
return unalignedShort(start);
|
||||
}
|
||||
|
||||
const char * Storage::nameOfRecordStarting(char * start) const {
|
||||
const char * Storage::fullNameOfRecordStarting(char * start) const {
|
||||
return start+sizeof(record_size_t);
|
||||
}
|
||||
|
||||
@@ -252,8 +319,16 @@ size_t Storage::overrideSizeAtPosition(char * position, record_size_t size) {
|
||||
return sizeof(record_size_t);
|
||||
}
|
||||
|
||||
size_t Storage::overrideNameAtPosition(char * position, const char * name) {
|
||||
return strlcpy(position, name, strlen(name)+1)+1;
|
||||
size_t Storage::overrideFullNameAtPosition(char * position, const char * fullName) {
|
||||
return strlcpy(position, fullName, strlen(fullName)+1) + 1;
|
||||
}
|
||||
|
||||
size_t Storage::overrideBaseNameWithExtensionAtPosition(char * position, const char * baseName, const char * extension) {
|
||||
size_t result = strlcpy(position, baseName, strlen(baseName));
|
||||
*(position+result) = k_dotChar;
|
||||
result++;
|
||||
result += strlcpy(position+result, extension, strlen(extension)+1);
|
||||
return result+1;
|
||||
}
|
||||
|
||||
size_t Storage::overrideValueAtPosition(char * position, const void * data, record_size_t size) {
|
||||
@@ -261,13 +336,16 @@ size_t Storage::overrideValueAtPosition(char * position, const void * data, reco
|
||||
return size;
|
||||
}
|
||||
|
||||
bool Storage::isNameTaken(const char * name, Record * recordToExclude) {
|
||||
Record r = Record(name);
|
||||
bool Storage::isFullNameTaken(const char * fullName, const Record * recordToExclude) {
|
||||
Record r = Record(fullName);
|
||||
if (r == Record()) {
|
||||
/* If the CRC32 of fullName is 0, we want to refuse the name as it would
|
||||
* interfere with our escape case in the Record contructor, when the given
|
||||
* name is nullptr. */
|
||||
return true;
|
||||
}
|
||||
for (char * p : *this) {
|
||||
Record s(nameOfRecordStarting(p));
|
||||
Record s(fullNameOfRecordStarting(p));
|
||||
if (recordToExclude && s == *recordToExclude) {
|
||||
continue;
|
||||
}
|
||||
@@ -278,22 +356,27 @@ bool Storage::isNameTaken(const char * name, Record * recordToExclude) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Storage::nameCompliant(const char * name) {
|
||||
/* The name format is [^.]*\.[a-z]* */
|
||||
bool dot = false;
|
||||
const char * currentChar = name;
|
||||
while (*currentChar != 0) {
|
||||
if (*currentChar == '.') {
|
||||
dot = true;
|
||||
currentChar++;
|
||||
}
|
||||
if (!dot || (*currentChar >= 'a' && *currentChar <= 'z')) {
|
||||
currentChar++;
|
||||
continue;
|
||||
}
|
||||
bool Storage::fullNameCompliant(const char * fullName) {
|
||||
// We check that there is one dot and one dot only.
|
||||
const char * dotChar = strchr(fullName, k_dotChar);
|
||||
if (dotChar == nullptr) {
|
||||
return false;
|
||||
}
|
||||
return name != currentChar && dot;
|
||||
if (strchr(dotChar, k_dotChar) == nullptr) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Storage::fullNameHasExtension(const char * fullName, const char * extension, size_t extensionLength) {
|
||||
size_t fullNameLength = strlen(fullName);
|
||||
if (fullNameLength > extensionLength) {
|
||||
const char * ext = fullName + fullNameLength - extensionLength;
|
||||
if (*(ext-1) == k_dotChar && strcmp(ext, extension) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
char * Storage::endBuffer() {
|
||||
@@ -304,8 +387,17 @@ char * Storage::endBuffer() {
|
||||
return currentBuffer;
|
||||
}
|
||||
|
||||
size_t Storage::sizeOfRecord(const char * name, size_t dataSize) const {
|
||||
size_t nameSize = strlen(name)+1;
|
||||
size_t Storage::sizeOfBaseNameAndExtension(const char * baseName, const char * extension) const {
|
||||
// +1 for the dot and +1 for the null terminating char
|
||||
return strlen(baseName)+1+strlen(extension)+1;
|
||||
}
|
||||
|
||||
size_t Storage::sizeOfRecordWithBaseNameAndExtension(const char * baseName, const char * extension, size_t dataSize) const {
|
||||
return sizeOfBaseNameAndExtension(baseName, extension) + dataSize + sizeof(record_size_t);
|
||||
}
|
||||
|
||||
size_t Storage::sizeOfRecordWithFullName(const char * fullName, size_t dataSize) const {
|
||||
size_t nameSize = strlen(fullName)+1;
|
||||
return nameSize+dataSize+sizeof(record_size_t);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user