Mercurial > hg > dmlib
view src/dmres.c @ 2208:90ec1ec89c56
Revamp the palette handling in lib64gfx somewhat, add helper functions to
lib64util for handling external palette file options and add support for
specifying one of the "internal" palettes or external (.act) palette file to
gfxconv and 64vw.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Fri, 14 Jun 2019 05:01:12 +0300 |
parents | 8962901faf5d |
children | 972d56ad2b78 |
line wrap: on
line source
/* * dmlib * -- Resource management * Programmed and designed by Matti 'ccr' Hamalainen * (C) Copyright 2003-2015 Tecnic Software productions (TNSP) */ #include "dmres.h" #include <time.h> #ifdef DM_USE_PACKFS # ifdef DM_USE_ZLIB # include <zlib.h> # else # include "dmzlib.h" # endif #endif #ifdef DM_USE_STDIO # include <sys/types.h> # include <sys/stat.h> # include <unistd.h> # include <dirent.h> #endif static inline int dmLockLibMutex(DMResourceLib *lib) { if (lib != NULL) return dmMutexLock(lib->mutex); else return DMERR_OK; } static inline int dmUnlockLibMutex(DMResourceLib *lib) { if (lib != NULL) return dmMutexUnlock(lib->mutex); else return DMERR_OK; } DMResource *dmResourceNew(DMResourceLib *lib, const char *filename, const size_t size, const int flags) { DMResource *node = dmMalloc0(sizeof(DMResource)); if (node == NULL) return NULL; node->lib = lib; node->filename = dm_strdup(filename); node->rawSize = size; node->flags = flags; return node; } void dmResourceFreeResData(DMResource *node) { if (node->resData != NULL) { if (node->rops != NULL && node->rops->free != NULL) node->rops->free(node); else dmFree(node->resData); node->resData = NULL; } node->flags &= ~DMF_LOADED_RES; } void dmResourceFreeRawData(DMResource *node) { if ((node->flags & DMF_UNALLOCATED) == 0) { dmFree(node->rawData); node->rawData = NULL; node->flags &= ~DMF_LOADED_RAW; } } void dmResourceFree(DMResource *node) { if (node != NULL) { #ifdef DM_DEBUG dmLockLibMutex(node->lib); if (node->refcount > 0) { dmErrorMsg( "Attempting to dmResourceFree(%p) node that has resfs %d > 0: '%s'.\n" "FOPS=%p, fops->name=%s\n", node, node->refcount, node->filename, node->fops, (node->fops != NULL) ? node->fops->name : "UNDEF"); } dmUnlockLibMutex(node->lib); #endif dmResourceFreeResData(node); dmResourceFreeRawData(node); dmFree(node->filename); dmFree(node); } } void dmResourceInsert(DMResourceLib *lib, DMResource * node) { if (lib == NULL || node == NULL) return; node->lib = lib; if (lib->resources != NULL) { node->prev = lib->resources->prev; lib->resources->prev->next = node; lib->resources->prev = node; } else { lib->resources = node->prev = node; } node->next = NULL; } void dmResourceDelete(DMResourceLib *lib, DMResource * node) { if (lib == NULL) return; if (node->prev) node->prev->next = node->next; if (node->next) node->next->prev = node->prev; else lib->resources->prev = node->prev; node->prev = node->next = NULL; } DMResource * dmResourceFind(DMResourceLib *lib, const char *filename) { DMResource *node, *found = NULL; if (lib == NULL) return NULL; dmLockLibMutex(lib); for (node = lib->resources; node != NULL; node = node->next) { if (strcmp(node->filename, filename) == 0) { found = node; break; } } dmUnlockLibMutex(lib); return found; } #ifdef DM_USE_STDIO /* Basic stdio file routines */ static int dm_stdio_fopen(DMResource *handle) { char *dpath = handle->lib != NULL ? handle->lib->resPath : NULL; char *rfilename = dm_strdup_printf("%s%s", dpath != NULL ? dpath : "", handle->filename); if (rfilename == NULL) return DMERR_MALLOC; handle->fh = fopen(rfilename, "rb"); dmFree(rfilename); handle->error = dmGetErrno(); return (handle->fh != NULL) ? DMERR_OK : DMERR_FOPEN; } static void dm_stdio_fclose(DMResource *fh) { if (fh->fh != NULL) { fclose(fh->fh); fh->fh = NULL; } } static int dm_stdio_ferror(DMResource *fh) { return fh->error; } static off_t dm_stdio_ftell(DMResource *fh) { return ftello(fh->fh); } static int dm_stdio_fseek(DMResource *fh, const off_t pos, const int whence) { int ret = fseeko(fh->fh, pos, whence); fh->error = dmGetErrno(); return ret; } static int dm_stdio_freset(DMResource *fh) { if (fh->fh != NULL) return dm_stdio_fseek(fh, 0, SEEK_SET); else return DMERR_OK; } static off_t dm_stdio_fsize(DMResource *fh) { off_t savePos, fileSize; // Check if the size is cached if (fh->rawSize != 0) return fh->rawSize; // Get file size if ((savePos = dm_stdio_ftell(fh)) < 0) return -1; if (dm_stdio_fseek(fh, 0, SEEK_END) != 0) return -1; if ((fileSize = dm_stdio_ftell(fh)) < 0) return -1; if (dm_stdio_fseek(fh, savePos, SEEK_SET) != 0) return -1; fh->rawSize = fileSize; return fileSize; } static BOOL dm_stdio_feof(DMResource *fh) { return feof(fh->fh); } static int dm_stdio_fgetc(DMResource *fh) { int ret = fgetc(fh->fh); fh->error = dmGetErrno(); return ret; } static int dm_stdio_fputc(int v, DMResource *fh) { int ret = fputc(v, fh->fh); fh->error = dmGetErrno(); return ret; } static size_t dm_stdio_fread(void *ptr, size_t size, size_t nmemb, DMResource *fh) { size_t ret = fread(ptr, size, nmemb, fh->fh); fh->error = dmGetErrno(); return ret; } static size_t dm_stdio_fwrite(const void *ptr, size_t size, size_t nmemb, DMResource *fh) { size_t ret = fwrite(ptr, size, nmemb, fh->fh); fh->error = dmGetErrno(); return ret; } static int dm_stdio_preload(DMResource *handle) { int ret = dm_stdio_fopen(handle); if (ret != DMERR_OK) return ret; dm_stdio_fsize(handle); handle->rawData = dmMalloc(handle->rawSize); if (handle->rawData == NULL) return DMERR_MALLOC; if (dm_stdio_fread(handle->rawData, sizeof(Uint8), handle->rawSize, handle) != handle->rawSize) return DMERR_FREAD; return DMERR_OK; } DMResourceOps dfStdioFileOps = { "Stdio", dm_stdio_freset, dm_stdio_ferror, dm_stdio_fseek, dm_stdio_fsize, dm_stdio_ftell, dm_stdio_feof, dm_stdio_fgetc, dm_stdio_fputc, dm_stdio_fread, dm_stdio_fwrite, dm_stdio_fopen, dm_stdio_fclose, dm_stdio_preload }; DMResourceOps dfStdioFHOps = { "StdioFH", dm_stdio_freset, dm_stdio_ferror, dm_stdio_fseek, dm_stdio_fsize, dm_stdio_ftell, dm_stdio_feof, dm_stdio_fgetc, dm_stdio_fputc, dm_stdio_fread, dm_stdio_fwrite, NULL, NULL, NULL }; #endif // Some mingw/windows headers define these as macros, which is bad for us #ifdef DM_WINDOWS # undef ferror # undef feof #endif /* * PACK file routines */ #ifdef DM_USE_PACKFS #ifdef DM_USE_ZLIB #define DMRES_TMPBUF_SIZE (128 * 1024) static int dm_pack_decompress(DMResource *handle, DMPackEntry *node) { int ret = DMERR_OK, zret, cdataLeft; Uint8 * cbuffer = NULL; z_stream zstr; BOOL zinit = FALSE; // Allocate a structures and buffers if ((cbuffer = dmMalloc(DMRES_TMPBUF_SIZE)) == NULL) { ret = DMERR_MALLOC; goto out; } // Initialize decompression dmMemset(&zstr, 0, sizeof(zstr)); zstr.next_out = handle->rawData; zstr.avail_out = handle->rawSize; cdataLeft = node->length; if ((zret = inflateInit(&zstr)) != Z_OK) { ret = dmErrorDBG(DMERR_INIT_FAIL, "Could not initialize zlib stream decompression.\n"); goto out; } zinit = TRUE; // Uncompress the data while (cdataLeft > 0 && zstr.avail_out > 0 && zret == Z_OK) { zstr.avail_in = fread( cbuffer, sizeof(Uint8), (cdataLeft >= DMRES_TMPBUF_SIZE) ? DMRES_TMPBUF_SIZE : cdataLeft, handle->lib->packFile->file); cdataLeft -= zstr.avail_in; zstr.next_in = cbuffer; zret = inflate(&zstr, Z_FULL_FLUSH); } out: // Cleanup if (zinit) inflateEnd(&zstr); dmFree(cbuffer); return ret; } #else static int dm_pack_decompress(DMResource *handle, DMPackEntry *node) { DMZLibContext ctx; Uint8 *inBuf = NULL; int ret; // Allocate buffer for compressed data if ((inBuf = dmMalloc(node->length)) == NULL) { ret = DMERR_MALLOC; goto out; } // Read compressed data if (fread(inBuf, sizeof(Uint8), node->length, handle->lib->packFile->file) != node->length) { ret = DMERR_FREAD; goto out; } // Initialize decompression structures if ((ret = dmZLibInitInflate(&ctx)) != DMERR_OK) goto out; ctx.inBuffer = ctx.inBufferStart = inBuf; ctx.inBufferEnd = inBuf + node->length; ctx.outBuffer = ctx.outBufferStart = handle->rawData; ctx.outBufferEnd = handle->rawData + node->size; ctx.expandable = FALSE; // Attempt decompression if ((ret = dmZLibParseHeader(&ctx, TRUE)) != DMERR_OK) goto out; if ((ret = dmZLibInflate(&ctx)) != DMERR_OK) goto out; handle->rawData = ctx.outBufferStart; handle->rawSize = ctx.outBuffer - ctx.outBufferStart; out: dmZLibCloseInflate(&ctx); dmFree(inBuf); return ret; } #endif static int dm_pack_preload(DMResource *handle) { DMPackEntry *node; int ret = DMERR_OK; if (handle->lib == NULL || handle->lib->packFile == NULL) return DMERR_NULLPTR; // Search PACK nodelist for file if ((node = dmPackFind(handle->lib->packFile->entries, handle->filename)) == NULL) { ret = dmErrorDBG(DMERR_NOT_FOUND, "Entry '%s' not found in PACK file.\n", handle->filename); goto out; } // Seek to entry if (fseeko(handle->lib->packFile->file, node->offset, SEEK_SET) != 0) { ret = dmErrorDBG(DMERR_FSEEK, "Could not seek node position in PACK file.\n"); goto out; } // Allocate memory for the node if ((handle->rawData = dmMalloc(node->size)) == NULL) { ret = dmErrorDBG(DMERR_MALLOC, "Failed to allocate node data for '%s' (%d bytes).\n", handle->filename, node->size); goto out; } // Check if the entry is compressed if (handle->flags & DMF_COMPRESSED) { if ((ret = dm_pack_decompress(handle, node)) != DMERR_OK) goto out; if (handle->rawSize != node->size) { ret = dmErrorDBG(DMERR_COMPRESSION, "Decompressed data size for '%s' does not match size stored in PACK entry (%d <> %d).\n", handle->filename, handle->rawSize, node->size); } } else { if (node->size != node->length) { ret = dmErrorDBG(DMERR_INVALID_DATA, "Node '%s' raw size and length fields differ for uncompressed node: %d <> %d.\n", handle->filename, node->size, node->length); goto out; } if (fread(handle->rawData, sizeof(Uint8), node->size, handle->lib->packFile->file) != node->size) { ret = dmErrorDBG(DMERR_FREAD, "Error reading raw node data '%s', %d bytes.\n", handle->filename, node->size); goto out; } } out: return ret; } static int dm_pack_fopen(DMResource *fh) { if ((fh->flags & DMF_LOADED_RAW) == 0) { int ret = dm_pack_preload(fh); if (ret == DMERR_OK) fh->flags |= DMF_LOADED_RAW; return ret; } else return DMERR_OK; } static void dm_pack_fclose(DMResource *fh) { if ((fh->flags & DMF_PERSIST) == 0) dmResourceFreeRawData(fh); } #endif static int dm_mem_freset(DMResource *fh) { fh->rawOffset = 0; return DMERR_OK; } static int dm_mem_ferror(DMResource *fh) { return fh->error; } static int dm_mem_fseek(DMResource *fh, const off_t offset, const int whence) { off_t newPos; // Calculate the new position switch (whence) { case SEEK_SET: newPos = offset; break; case SEEK_CUR: newPos = fh->rawOffset + offset; break; case SEEK_END: newPos = fh->rawSize + offset; break; default: return -1; } // Set the new position fh->rawOffset = newPos; // Check the new position if (newPos < 0 && (size_t) newPos >= fh->rawSize) return -1; return 0; } static off_t dm_mem_fsize(DMResource *fh) { return fh->rawSize; } static off_t dm_mem_ftell(DMResource *fh) { return fh->rawOffset; } static BOOL dm_mem_feof(DMResource *fh) { // Check for EOF if ((size_t) fh->rawOffset <= fh->rawSize) return FALSE; else return TRUE; } static int dm_mem_fgetc(DMResource *fh) { // Check for EOF if ((size_t) fh->rawOffset < fh->rawSize) return fh->rawData[fh->rawOffset++]; else return EOF; } static size_t dm_mem_fread(void *buf, size_t size, size_t nmemb, DMResource *fh) { size_t length = (size * nmemb); // Check if we can read the whole chunk if (((size_t) fh->rawOffset + length) >= fh->rawSize) { nmemb = (fh->rawSize - fh->rawOffset) / size; length = size * nmemb; } memcpy(buf, fh->rawData + fh->rawOffset, length); fh->rawOffset += length; return nmemb; } static int dm_mem_fputc(int ch, DMResource *fh) { // Check for EOF if ((size_t) fh->rawOffset < fh->rawSize) { fh->rawData[fh->rawOffset++] = ch; return ch; } else return EOF; } static size_t dm_mem_fwrite(const void *buf, size_t size, size_t nmemb, DMResource *fh) { size_t length = (size * nmemb); // Check if we can write the whole chunk if (((size_t) fh->rawOffset + length) >= fh->rawSize) { nmemb = (fh->rawSize - fh->rawOffset) / size; length = size * nmemb; } if (length > 0) { memcpy(fh->rawData + fh->rawOffset, buf, length); fh->rawOffset += length; } return nmemb; } #ifdef DM_USE_PACKFS DMResourceOps dfPackFileOps = { "PackFS", dm_mem_freset, dm_mem_ferror, dm_mem_fseek, dm_mem_fsize, dm_mem_ftell, dm_mem_feof, dm_mem_fgetc, NULL, dm_mem_fread, NULL, dm_pack_fopen, dm_pack_fclose, dm_pack_preload, }; #endif DMResourceOps dfMemIOFileOps = { "MemIO", dm_mem_freset, dm_mem_ferror, dm_mem_fseek, dm_mem_fsize, dm_mem_ftell, dm_mem_feof, dm_mem_fgetc, dm_mem_fputc, dm_mem_fread, dm_mem_fwrite, NULL, NULL, NULL }; /* FS file handling functions. These functions call the actual * functions depending on where the file is located. */ static int dmResourcePreload(DMResource *handle) { int ret = DMERR_OK; // Check if we want to preload raw data? if ((handle->lib->flags & DRF_PRELOAD_RAW) || handle->rops == NULL || handle->rops->load == NULL) { if (handle->flags & DMF_LOADED_RAW) ret = DMERR_OK; else if (handle->fops->preload != NULL) { ret = handle->fops->preload(handle); if (ret == DMERR_OK) handle->flags |= DMF_LOADED_RAW | DMF_PERSIST; } else ret = DMERR_INIT_FAIL; dmfreset(handle); } // Check if resource data is to be preloaded if (ret == DMERR_OK && (handle->lib->flags & DRF_PRELOAD_RES)) { if (handle->flags & DMF_LOADED_RES) ret = DMERR_OK; else if (handle->rops != NULL && handle->rops->load != NULL) { if ((ret = handle->fops->fopen(handle)) == DMERR_OK) { ret = handle->rops->load(handle); handle->fops->fclose(handle); } if (ret == DMERR_OK) handle->flags |= DMF_LOADED_RES; } dmfreset(handle); } return ret; } int dmf_open(DMResourceLib *lib, const char *filename, DMResource **phandle) { DMResource *handle; int ret; // Check master directory for resource if ((*phandle = handle = dmResourceFind(lib, filename)) == NULL) { #ifdef DM_USE_STDIO if (lib->flags & DRF_USE_STDIO) { // Hmm.. does not exist? Fall back to a stdio file *phandle = handle = dmResourceNew(lib, filename, 0, 0); if (handle == NULL) return DMERR_MALLOC; handle->fops = &dfStdioFileOps; } else return DMERR_INIT_FAIL; #else // Stdio not enabled, fail return DMERR_INIT_FAIL; #endif } // Check if the data is preloaded if ((ret = handle->fops->fopen(handle)) == DMERR_OK) { dmResourceRef(handle); if (handle->flags & DMF_TEMPORARY) { handle->flags &= ~DMF_TEMPORARY; dmResourceInsert(lib, handle); } } else if (handle->flags & DMF_TEMPORARY) { dmResourceFree(handle); *phandle = handle = NULL; } dmfreset(handle); return ret; } int dmf_open_memio(DMResourceLib *lib, const char *filename, Uint8 *buf, const size_t size, DMResource **phandle) { DMResource *handle; // Check master directory for resource if ((*phandle = handle = dmResourceFind(lib, filename)) == NULL) { if ((*phandle = handle = dmResourceNew( lib, filename, size, DMF_LOADED_RAW | DMF_UNALLOCATED)) == NULL) return DMERR_MALLOC; handle->fops = &dfMemIOFileOps; handle->rawData = buf; dmResourceInsert(lib, handle); } // Increase refcount dmResourceRef(handle); dmfreset(handle); return DMERR_OK; } #ifdef DM_USE_STDIO int dmf_open_stdio(const char *filename, const char *mode, DMResource **phandle) { DMResource *handle; if ((*phandle = handle = dmResourceNew(NULL, filename, 0, 0)) == NULL) return DMERR_MALLOC; handle->fops = &dfStdioFileOps; handle->fh = fopen(filename, mode); handle->error = dmGetErrno(); if (handle->fh == NULL) { int error = handle->error; dmResourceFree(handle); return error; } dmResourceRef(handle); return DMERR_OK; } int dmf_open_stdio_stream(FILE *fh, DMResource **phandle) { DMResource *handle; if ((*phandle = handle = dmResourceNew(NULL, "", 0, 0)) == NULL) return DMERR_MALLOC; handle->fops = &dfStdioFHOps; handle->fh = fh; dmResourceRef(handle); return DMERR_OK; } #endif void dmf_close(DMResource *handle) { if (handle == NULL) return; dmResourceUnref(handle); if (handle->fops->fclose != NULL) handle->fops->fclose(handle); if (handle->lib == NULL) dmResourceFree(handle); } int dmfreset(DMResource *fh) { if (fh == NULL) return DMERR_NULLPTR; if (fh->fops == NULL || fh->fops->freset == NULL) return DMERR_OK; return fh->fops->freset(fh); } int dmferror(DMResource *fh) { fh->atime = time(NULL); return fh->fops->ferror(fh); } int dmfseek(DMResource *fh, const off_t offset, const int whence) { fh->atime = time(NULL); return fh->fops->fseek(fh, offset, whence); } off_t dmfsize(DMResource *fh) { fh->atime = time(NULL); return fh->fops->fsize(fh); } off_t dmftell(DMResource *fh) { fh->atime = time(NULL); return fh->fops->ftell(fh); } BOOL dmfeof(DMResource *fh) { fh->atime = time(NULL); return fh->fops->feof(fh); } int dmfgetc(DMResource *fh) { fh->atime = time(NULL); return fh->fops->fgetc(fh); } int dmfputc(const int val, DMResource *fh) { fh->atime = time(NULL); return fh->fops->fputc(val, fh); } size_t dmfread(void *ptr, size_t size, size_t nmemb, DMResource *fh) { fh->atime = time(NULL); return fh->fops->fread(ptr, size, nmemb, fh); } size_t dmfwrite(const void *ptr, size_t size, size_t nmemb, DMResource *fh) { fh->atime = time(NULL); return fh->fops->fwrite(ptr, size, nmemb, fh); } char *dmfgets(char *str, const int size, DMResource *fh) { char *ptr = str, *end = str + size - 1; int c; if (size <= 0) return NULL; while (ptr < end && (c = fh->fops->fgetc(fh)) != EOF) { *ptr++ = c; if (c == '\n') break; } *ptr = 0; return (ptr > str) ? str : NULL; } int dmfputs(const char *str, DMResource *fh) { return dmfwrite(str, strlen(str), 1, fh) == 1 ? 1 : EOF; } int dmResourceRef(DMResource *node) { dmLockLibMutex(node->lib); node->atime = time(NULL); node->refcount++; dmUnlockLibMutex(node->lib); return node->refcount; } int dmResourceUnref(DMResource *node) { dmLockLibMutex(node->lib); node->refcount--; dmUnlockLibMutex(node->lib); return node->refcount; } #ifdef DM_USE_STDIO static int dmResourcesLoadDirectory(DMResourceLib *lib, const char *path) { int ret = DMERR_OK; struct dirent *dh; DIR *hdir = opendir(path); if (hdir == NULL) return dmGetErrno(); dmLockLibMutex(lib); do { DMResource *node = NULL; dh = readdir(hdir); if (dh != NULL) { struct stat sbuf; char *fname = dm_strdup_printf("%s/%s", path, dh->d_name); if (stat(fname, &sbuf) == -1) { ret = dmErrorDBG(dmGetErrno(), "Could not stat() %s, #%d: %s\n", fname, ret, dmErrorStr(ret)); dmFree(fname); goto out; } if (S_ISREG(sbuf.st_mode)) node = dmResourceNew(lib, dh->d_name, sbuf.st_size, 0); } if (node != NULL) { node->fops = &dfStdioFileOps; dmResourceInsert(lib, node); } } while (dh != NULL); out: dmUnlockLibMutex(lib); #ifdef __WIN32 #else closedir(hdir); #endif return ret; } #endif /* Resources subsystem initialization and shutdown routines */ int dmResourcesInit(DMResourceLib **plib, const char *filename, const char *path, const int flags, int (*classifier)(DMResource *)) { DMResourceLib *lib; BOOL initialized = FALSE; // Allocate the resource library structure if ((*plib = lib = dmMalloc0(sizeof(DMResourceLib))) == NULL) return DMERR_MALLOC; // Basic data lib->mutex = dmCreateMutex(); lib->flags = flags; lib->resPath = dm_strdup(path); #ifdef DM_USE_PACKFS if (flags & DRF_USE_PACK) { int ret; DMPackEntry *node; lib->packFilename = dm_strdup(filename); // Initialize PACK, open as read-only ret = dmPackOpen(lib->packFilename, &lib->packFile, TRUE); if (ret != DMERR_OK) { if ((flags & DRF_USE_STDIO) == 0) { return dmErrorDBG(DMERR_INIT_FAIL, "Error opening PACK file '%s', #%d: %s\n", lib->packFilename, ret, dmErrorStr(ret)); } else { // Non-fatal dmErrorDBGMsg( "Failed to open PACK '%s' %d: %s\n", lib->packFilename, ret, dmErrorStr(ret)); } } else { // Initialize resources from a PACK file for (node = lib->packFile->entries; node != NULL; node = node->next) { DMResource *res = dmResourceNew(lib, node->filename, node->size, node->flags & DMF_PACK_MASK); if (res == NULL) { return dmErrorDBG(DMERR_INIT_FAIL, "Could not allocate memory for resource node '%s' [0x%08x], %d bytes.\n", node->filename, node->flags, node->size); } res->fops = &dfPackFileOps; dmResourceInsert(lib, res); } initialized = TRUE; } } #else (void) filename; #endif #ifdef DM_USE_STDIO if (!initialized && (flags & DRF_USE_STDIO)) { // Initialize resources from a resource directory int ret = dmResourcesLoadDirectory(lib, lib->resPath); if (ret != DMERR_OK) return ret; initialized = TRUE; } #endif if (!initialized) return dmErrorDBG(DMERR_INIT_FAIL, "Failed all resource initialization modes.\n"); // Okay, classify resources if (lib->resources != NULL && classifier != NULL) { DMResource *node; for (node = lib->resources; node != NULL; node = node->next) { int ret = classifier(node); if (ret != DMERR_OK) return ret; } } // Initialization complete return DMERR_OK; } int dmResourcesClose(DMResourceLib *lib) { DMResource *node; if (lib == NULL) return DMERR_NULLPTR; dmLockLibMutex(lib); // Shutdown possible subsystems #ifdef DM_USE_PACKFS if (lib->flags & DRF_USE_PACK) { int ret = dmPackClose(lib->packFile); if (ret != DMERR_OK) { dmErrorDBGMsg( "Error closing PACK, #%i: %s\n", ret, dmErrorStr(ret)); } dmFree(lib->packFilename); } #endif // Free resource entries node = lib->resources; while (node != NULL) { DMResource *next = node->next; dmResourceFree(node); node = next; } // Etc. dmFree(lib->resPath); dmUnlockLibMutex(lib); dmDestroyMutex(lib->mutex); return DMERR_OK; } int dmResourcesPreload(DMResourceLib *lib, BOOL start, int *loaded, int *total) { int ret = DMERR_OK; dmLockLibMutex(lib); // Initialize preloading if (lib->preload == NULL || start) { DMResource *node; lib->preload = lib->resources; *loaded = 0; *total = 0; // Calculate total number of resources to be preloaded if (lib->flags & (DRF_PRELOAD_RAW | DRF_PRELOAD_RES)) { for (node = lib->resources; node != NULL; node = node->next) (*total)++; } } else if (lib->preload != NULL) { // Attempt to preload the resource if ((ret = dmResourcePreload(lib->preload)) != DMERR_OK) { dmErrorDBGMsg("Error preloading '%s', %d: %s\n", lib->preload->filename, ret, dmErrorStr(ret)); goto error; } (*loaded)++; lib->preload = lib->preload->next; } dmUnlockLibMutex(lib); return (lib->preload == NULL) ? DMERR_OK : DMERR_PROGRESS; error: dmUnlockLibMutex(lib); return ret; } void dmResourcePrune(DMResourceLib *lib, const int agems, int const flags) { DMResource *node; const int stamp = time(NULL); dmLockLibMutex(lib); for (node = lib->resources; node != NULL; node = node->next) { // Check if node has refcount of 0 and is // not marked as persistent resource if (node->refcount == 0 && (node->flags & DMF_PERSIST) == 0 && (node->flags & (DMF_LOADED_RES | DMF_LOADED_RAW))) { if (((flags & DMPRUNE_ATIME) && stamp - node->atime >= agems) || ((flags & DMPRUNE_MTIME) && stamp - node->mtime >= agems)) { dmResourceFreeResData(node); dmResourceFreeRawData(node); } } } dmUnlockLibMutex(lib); } /* Helper resource access routines */ int dmvfprintf(DMResource *fh, const char *fmt, va_list ap) { int len, res; char *str = dm_strdup_vprintf_len(fmt, ap, &len); if (str == NULL) { fh->error = DMERR_MALLOC; return -1; } res = dmfwrite(str, 1, len, fh); dmFree(str); return res; } int dmfprintf(DMResource *fh, const char *fmt, ...) { int res; va_list ap; va_start(ap, fmt); res = dmvfprintf(fh, fmt, ap); va_end(ap); return res; } BOOL dmf_read_str(DMResource *fh, void *ptr, const size_t len) { return dmfread(ptr, len, 1, fh) == 1; } BOOL dmf_read_byte(DMResource *fh, Uint8 *val) { int tmp = dmfgetc(fh); *val = tmp; return tmp != EOF; } #define DM_DEFINE_FFUNC(xname, xtype, xmacro) \ BOOL dmf_read_ ## xname (DMResource *fh, xtype *val) { \ xtype result; \ if (dmfread(&result, sizeof( xtype ), 1, fh) != 1) \ return FALSE; \ *val = DM_ ## xmacro ## _TO_NATIVE (result); \ return TRUE; \ } #include "dmfiletmpl.h" #undef DM_DEFINE_FFUNC