/* Copyright (c) 2021 Alex Diener This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. Alex Diener alex@ludobloom.com */ #ifndef __FileBundle_H__ #define __FileBundle_H__ #ifdef __cplusplus extern "C" { #endif #include #include #include #include #define FILE_BUNDLE_FORMAT_SIGNATURE "StFB" #define FILE_BUNDLE_FORMAT_VERSION 0 #define FILE_BUNDLE_IDENTIFIER_MAX 255 // These values are suggestions; any arbitrary value can be used by caller (other than FILE_TYPE_INVALID) #define FILE_TYPE_INVALID INT32_MIN #define FILE_TYPE_NONE 0 #define FILE_TYPE_TEXT 1 #define FILE_TYPE_JSON 2 #define FILE_TYPE_BINARY 3 #define FILE_TYPE_BUNDLE 4 #define FILE_TYPE_PNG 100 #define FILE_TYPE_OGG 200 typedef int32_t FileBundle_fileType; struct FileBundle_entry { // Written to bundle files FileBundle_fileType type; uint32_t offset; uint32_t size; char * identifier; // In memory only void * data; bool dataOwned; }; typedef struct FileBundle { unsigned int entryCount; struct FileBundle_entry * entries; FILE * file; void * data; size_t dataSize; bool dataOwned; } FileBundle; FileBundle * FileBundle_create(void); void FileBundle_dispose(FileBundle * bundle); unsigned int FileBundle_getFileCount(FileBundle * bundle); // Returns NULL if fileIndex is out of range const char * FileBundle_getFileIdentifier(FileBundle * bundle, unsigned int fileIndex); // Returns UINT_MAX if the file is not found unsigned int FileBundle_getFileIndex(FileBundle * bundle, const char * fileIdentifier); // Returns FILE_TYPE_INVALID if file doesn't exist FileBundle_fileType FileBundle_getFileType(FileBundle * bundle, const char * fileIdentifier); FileBundle_fileType FileBundle_getFileTypeAtIndex(FileBundle * bundle, unsigned int fileIndex); unsigned int FileBundle_getFileCountOfType(FileBundle * bundle, FileBundle_fileType type); // Searches beginning from startIndex for a file of the specified type, returning its index if found, and UINT_MAX if not. // To continue a search, pass a startIndex of 1 greater than the previous return value of FileBundle_getNextFileOfType. unsigned int FileBundle_getNextFileIndexOfType(FileBundle * bundle, FileBundle_fileType type, unsigned int startIndex); // Returns NULL if file doesn't exist const void * FileBundle_getFile(FileBundle * bundle, const char * fileIdentifier, uint32_t * outSize); const void * FileBundle_getFileAtIndex(FileBundle * bundle, unsigned int fileIndex, uint32_t * outSize); void FileBundle_addFile(FileBundle * bundle, const char * fileIdentifier, FileBundle_fileType type, void * data, uint32_t size, bool takeOwnership, bool copy); // Returns true on success, and false on failure due to file not being found or index out of range bool FileBundle_removeFile(FileBundle * bundle, const char * fileIdentifier); bool FileBundle_removeFileAtIndex(FileBundle * bundle, unsigned int fileIndex); // These functions have no effect if the specified file doesn't exist void FileBundle_replaceFileContents(FileBundle * bundle, const char * fileIdentifier, void * newData, uint32_t newSize, bool takeOwnership, bool copy); void FileBundle_replaceFileContentsAtIndex(FileBundle * bundle, unsigned int fileIndex, void * newData, uint32_t newSize, bool takeOwnership, bool copy); void FileBundle_setFileType(FileBundle * bundle, const char * fileIdentifier, FileBundle_fileType newType); void FileBundle_setFileTypeAtIndex(FileBundle * bundle, unsigned int fileIndex, FileBundle_fileType newType); void FileBundle_renameFile(FileBundle * bundle, const char * fileIdentifier, const char * newFileIdentifier); void FileBundle_renameFileAtIndex(FileBundle * bundle, unsigned int fileIndex, const char * newFileIdentifier); // Returns the new index of the specified file, which may be less than newFileIndex if newFileIndex was beyond the bundle's current file count (or UINT_MAX if the file doesn't exist). unsigned int FileBundle_reorderFile(FileBundle * bundle, const char * fileIdentifier, unsigned int newFileIndex); unsigned int FileBundle_reorderFileAtIndex(FileBundle * bundle, unsigned int fileIndex, unsigned int newFileIndex); // All entries will be loaded into memory immediately FileBundle * FileBundle_loadData(const void * data, size_t size); FileBundle * FileBundle_loadFile(const char * filePath); // Entries will be loaded only when accessed FileBundle * FileBundle_referenceDataNonImmediate(void * data, size_t size, bool takeOwnership, bool copy); FileBundle * FileBundle_referenceFileNonImmediate(const char * filePath); void * FileBundle_writeData(FileBundle * bundle, size_t * outSize); bool FileBundle_writeFile(FileBundle * bundle, const char * filePath); bool FileBundle_writeFileAtomic(FileBundle * bundle, const char * filePath); #ifdef __cplusplus } #endif #endif