/****************************************************************************** * MiniFFS : Mini Flat File System * miniffs.c: Shared code for all platforms. * * Copyright (c) 2008-2022 986-Studio. All rights reserved. * ******************************************************************************/ #include #include #define __miniffs_internal #include static miniffs_error_t last_error = MINIFFS_NOERROR; /* Public API */ file_t *miniffs_open(miniffs_t *fs, const char *filename) { file_t *ret = (file_t *)calloc(1, sizeof(file_t)); if (ret == NULL) { miniffs_seterror(MINIFFS_ALLOCATION_ERROR); goto exit; } ret->private_data = fs; ret->fent = miniffs_findfile(fs, filename); if (!ret->fent) { miniffs_seterror(MINIFFS_FILE_NOT_FOUND); goto free_and_exit; } ret->offset = 0; goto exit; free_and_exit: free(ret); ret = NULL; exit: return ret; } int miniffs_close(file_t *file) { /* Let's poison the struct */ file->private_data = NULL; file->offset = 0; file->fent = NULL; free(file); } void *miniffs_map(file_t *file) { miniffs_t *fs = (miniffs_t *)file->private_data; return miniffs_getfileaddr(fs, file->fent); } uint8_t miniffs_read(file_t *file) { miniffs_t *fs = (miniffs_t *) file->private_data; uint8_t *filePtr = miniffs_getfileaddr(fs, file->fent); uint8_t ret = filePtr[file->offset]; file->offset++; if (file->offset >= file->fent->size) { miniffs_seterror(MINIFFS_END_OF_FILE); file->offset = file->fent->size - 1; } return ret; } int miniffs_read_blocks(void *ptr, size_t size, size_t nmemb, file_t *file) { int i; miniffs_t *fs = (miniffs_t *) file->private_data; uint8_t *filePtr = miniffs_getfileaddr(fs, file->fent); size_t fileOffset = file->offset; size_t bufferOffset = 0; int blockCount = 0; for(i = 0; i < nmemb; i++) { if (file->fent->size > (fileOffset + size)) { memcpy(ptr + bufferOffset, &filePtr[fileOffset], size); bufferOffset += size; fileOffset += size; blockCount++; } } file->offset = fileOffset; return blockCount; } int miniffs_seek(file_t *file, size_t offset, int whence) { switch(whence) { default: miniffs_seterror(MINIFFS_INVALID_PARAMS); return -1; case MFFS_SEEK_SET: file->offset = offset; break; case MFFS_SEEK_CUR: file->offset += offset; break; case MFFS_SEEK_END: file->offset = file->fent->size - offset; break; } } size_t miniffs_tell(file_t *file) { return file->offset; } miniffs_error_t miniffs_geterror() { return last_error; } /* Private API */ bool miniffs_isvalidfs(miniffs_t *fs) { return (fs->header->magic == MINIFFS_MAGIC) && (fs->header->fs_version_major == MINIFFS_VERSION_MAJOR) && (fs->header->fs_version_minor == MINIFFS_VERSION_MINOR) && (fs->header->fs_filename_len == MINIFFS_FILENAME_LENGTH) && (fs->header->fs_extention_len == MINIFFS_EXTENSION_LENGTH); } static void make_fullname(char *name, char *ext, char *out) { uint8_t nameLen = strnlen(name, MINIFFS_FILENAME_LENGTH); uint8_t extLen = strnlen(ext, MINIFFS_EXTENSION_LENGTH); memcpy(out, name, nameLen); memcpy(out + nameLen, ".", 1); memcpy(out + nameLen + 1, ext, extLen); } fileentry_t *miniffs_findfile(miniffs_t *fs, const char *filename) { int i; char entryFullName[MINIFFS_FULLNAME_LENGTH]; uint8_t filenameLength = strlen(filename); fileentry_t *ret = NULL; if (filenameLength > MINIFFS_FULLNAME_LENGTH) { miniffs_seterror(MINIFFS_INVALID_NAME); goto exit; } for(i = 0; i < fs->header->entry_count; i++) { fileentry_t *cur = &fs->header->fent[i]; make_fullname(cur->name, cur->ext, entryFullName); if (memcmp(filename, entryFullName, filenameLength) == 0) { /* File found! */ ret = cur; break; } } exit: return ret; } void miniffs_seterror(miniffs_error_t err) { last_error = err; }