diff dmres.c @ 359:59045853853d

Make resource management re-entrant.
author Matti Hamalainen <ccr@tnsp.org>
date Tue, 16 Oct 2012 21:25:46 +0300
parents 6d9d43bb68eb
children a0160ffdf7e5
line wrap: on
line diff
--- a/dmres.c	Tue Oct 16 21:24:48 2012 +0300
+++ b/dmres.c	Tue Oct 16 21:25:46 2012 +0300
@@ -8,31 +8,13 @@
 #include <time.h>
 
 
-#define DMRES_LOCK(x) dmMutexLock(dfResourcesMutex)
-#define DMRES_UNLOCK(x) dmMutexUnlock(dfResourcesMutex)
-
-
-/* Global variables
- */
-static BOOL        dfResInitialized = FALSE;
-static int         dfResFlags = 0;
-static char *      dfResPath = NULL;
-DMResource *       dfResources = NULL;
-DMMutex *          dfResourcesMutex = NULL;
-
-
-#ifdef DM_USE_PACKFS
-static DMPackFile *dfResPackFile = NULL;
-static char *      dfResPackFilename = NULL;
-#endif
-
-
-DMResource *dmres_new(const char *filename, int flags, size_t size)
+DMResource *dmres_new(DMResourceLib *lib, const char *filename, int flags, size_t size)
 {
     DMResource *node = dmMalloc0(sizeof(DMResource));
     if (node == NULL)
         return NULL;
     
+    node->lib = lib;
     node->filename = dm_strdup(filename);
     node->flags = flags;
     node->dataSize = size;
@@ -84,44 +66,55 @@
 }
 
 
-static void dmres_insert(DMResource * node)
+void dmres_insert(DMResourceLib *lib, DMResource * node)
 {
-    if (dfResources != NULL)
+    if (lib == NULL)
+        return;
+    
+    node->lib = lib;
+
+    if (lib->resources != NULL)
     {
-        node->prev = dfResources->prev;
-        dfResources->prev->next = node;
-        dfResources->prev = node;
+        node->prev = lib->resources->prev;
+        lib->resources->prev->next = node;
+        lib->resources->prev = node;
     }
     else
     {
-        dfResources = node->prev = node;
+        lib->resources = node->prev = node;
     }
     
     node->next = NULL;
 }
 
 
-static void dmres_delete(DMResource * node)
+void dmres_delete(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
-        dfResources->prev = node->prev;
+        lib->resources->prev = node->prev;
 
     node->prev = node->next = NULL;
 }
 
 
-DMResource * dmres_find(const char *filename)
+DMResource * dmres_find(DMResourceLib *lib, const char *filename)
 {
     DMResource *node, *found = NULL;
 
-    DMRES_LOCK();
+    if (lib == NULL)
+        return NULL;
 
-    for (node = dfResources; node != NULL; node = node->next)
+    dmMutexLock(lib->mutex);
+
+    for (node = lib->resources; node != NULL; node = node->next)
     {
         if (strcmp(node->filename, filename) == 0)
         {
@@ -130,7 +123,7 @@
         }
     }
 
-    DMRES_UNLOCK();
+    dmMutexUnlock(lib->mutex);
 
     return found;
 }
@@ -322,8 +315,11 @@
     z_stream cstream;
     Uint8 *  cbuffer = NULL;
 
+    if (handle->lib == NULL || handle->lib->packFile == NULL)
+        return DMERR_NULLPTR;
+
     // Search PACK nodelist for file
-    if ((node = dm_pack_find(dfResPackFile->entries, handle->filename)) == NULL)
+    if ((node = dm_pack_find(handle->lib->packFile->entries, handle->filename)) == NULL)
     {
         dmError("Entry '%s' not found in PACK file.\n", handle->filename);
         res = DMERR_NOT_FOUND;
@@ -331,7 +327,7 @@
     }
 
     // Seek to entry
-    if (fseek(dfResPackFile->file, node->offset, SEEK_SET) == -1)
+    if (fseek(handle->lib->packFile->file, node->offset, SEEK_SET) == -1)
     {
         dmError("Could not seek node position in PACK file.\n");
         res = DMERR_FSEEK;
@@ -378,7 +374,7 @@
         cstream.avail_in = fread(
             cbuffer, sizeof(Uint8),
             (cdataLeft >= DPACK_TMPSIZE) ? DPACK_TMPSIZE : cdataLeft,
-            dfResPackFile->file);
+            handle->lib->packFile->file);
 
         cdataLeft -= cstream.avail_in;
         cstream.next_in = cbuffer;
@@ -540,7 +536,7 @@
     if (handle->fops == NULL)
     {
 #ifdef DM_USE_PACKFS
-        if (dfResFlags & DRF_USE_PACK)
+        if (handle->lib->flags & DRF_USE_PACK)
             handle->fops = &dfPackFileOps;
 #ifdef DM_USE_STDIO
         else
@@ -562,7 +558,7 @@
 
     // Check if we want to preload raw data?
     if (((handle->flags & DMF_PRELOAD_RAW) ||
-        (dfResFlags & DRF_PRELOAD_ALL)) &&
+        (handle->lib->flags & DRF_PRELOAD_ALL)) &&
         (handle->flags & DMF_LOADED_RAW) == 0 &&
         handle->fops->preload != NULL)
     {
@@ -588,7 +584,7 @@
     }
 
     // Check if resource data is to be preloaded
-    if (((handle->flags & DMF_PRELOAD_RES) || (dfResFlags & DRF_PRELOAD_RES)) &&
+    if (((handle->flags & DMF_PRELOAD_RES) || (handle->lib->flags & DRF_PRELOAD_RES)) &&
         (handle->flags & DMF_LOADED_RES) == 0 &&
         handle->rops != NULL &&
         handle->rops->load != NULL)
@@ -609,22 +605,22 @@
 }
 
 
-DMResource *dmf_open(const char *filename)
+DMResource *dmf_open(DMResourceLib *lib, const char *filename)
 {
     int ret;
     DMResource *handle;
 
     // Check master directory for resource
-    if ((handle = dmres_find(filename)) == NULL)
+    if ((handle = dmres_find(lib, filename)) == NULL)
     {
 #ifdef DM_USE_STDIO
         // Hmm.. does not exist? Fall back to a stdio file
-        handle = dmres_new(filename, 0, 0);
+        handle = dmres_new(lib, filename, 0, 0);
         if (handle == NULL)
             return NULL;
 
         handle->fops = &dfStdioFileOps;
-        dmres_insert(handle);
+        dmres_insert(lib, handle);
 #else
         // Stdio not enabled, fail
         return NULL;
@@ -654,21 +650,21 @@
 }
 
 
-DMResource * dmf_open_memio(const char *filename, Uint8 *buf, size_t len)
+DMResource * dmf_create_memio(DMResourceLib *lib, const char *filename, Uint8 *buf, size_t len)
 {
     DMResource *handle;
 
     // Check master directory for resource
-    if ((handle = dmres_find(filename)) == NULL)
+    if ((handle = dmres_find(lib, filename)) == NULL)
     {
         // Hmm.. does not exist? Fall back to a stdio file
-        handle = dmres_new(filename, DMF_LOADED_RAW, len);
+        handle = dmres_new(lib, filename, DMF_LOADED_RAW, len);
         if (handle == NULL)
             return NULL;
 
         handle->fops = &dfMemIOFileOps;
         handle->data = buf;
-        dmres_insert(handle);
+        dmres_insert(lib, handle);
     }
 
     // Increase refcount
@@ -681,7 +677,7 @@
 #ifdef DM_USE_STDIO
 DMResource * dmf_create_stdio(const char *filename, const char *mode)
 {
-    DMResource *handle = dmres_new(filename, 0, 0);
+    DMResource *handle = dmres_new(NULL, filename, 0, 0);
     if (handle == NULL)
         return NULL;
 
@@ -705,7 +701,7 @@
 
 DMResource * dmf_create_stdio_stream(FILE *fh)
 {
-    DMResource *handle = dmres_new("", 0, 0);
+    DMResource *handle = dmres_new(NULL, "", 0, 0);
     if (handle == NULL)
         return NULL;
 
@@ -803,13 +799,12 @@
 }
 
 
-
 int dmres_ref(DMResource *node)
 {
-    DMRES_LOCK();
+    if (node->lib != NULL) dmMutexLock(node->lib->mutex);
     node->atime = time(NULL);
     node->refcount++;
-    DMRES_UNLOCK();
+    if (node->lib != NULL) dmMutexUnlock(node->lib->mutex);
 
     return node->refcount;
 }
@@ -817,9 +812,9 @@
 
 int dmres_unref(DMResource *node)
 {
-    DMRES_LOCK();
+    if (node->lib != NULL) dmMutexLock(node->lib->mutex);
     node->refcount--;
-    DMRES_UNLOCK();
+    if (node->lib != NULL) dmMutexUnlock(node->lib->mutex);
 
     return node->refcount;
 }
@@ -861,7 +856,7 @@
 }
 
 
-int dmres_load_resfile(const char *filename)
+int dmres_load_resfile(DMResourceLib *lib, const char *filename)
 {
     int ret = DMERR_OK;
     char line[256];
@@ -869,7 +864,7 @@
     if (f == NULL)
         return DMERR_FOPEN;
 
-    DMRES_LOCK();
+    dmMutexLock(lib->mutex);
 
     while (fgets(line, sizeof(line) - 1, f) != NULL)
     {
@@ -883,23 +878,17 @@
                 line[i] = 0;
 
             for (i = fsep; isspace(line[i]); i++);
-            
-            if (sscanf(&line[i], "%x", &flags) == 1 &&
-                strlen(&line[fnstart]) > 0)
-            {
-                
-            }
         }
     }
 
-    DMRES_UNLOCK();
+    dmMutexUnlock(lib->mutex);
     fclose(f);
 
     return ret;
 }
 
 
-int dmres_write_resfile(const char *filename)
+int dmres_write_resfile(DMResourceLib *lib, const char *filename)
 {
     int ret;
     DMResource *node;
@@ -907,11 +896,13 @@
     if (f == NULL)
         return DMERR_FOPEN;
 
-    DMRES_LOCK();
+    dmMutexLock(lib->mutex);
     
-    for (node = dfResources; node != NULL; node = node->next)
+    for (node = lib->resources; node != NULL; node = node->next)
     {
-        if (fprintf(f, "%s|%08x\n", node->filename, node->flags) < 0)
+        char tmp[64];
+        dmres_flags_to_symbolic(tmp, sizeof(tmp), node->flags);
+        if (fprintf(f, "%s|%s\n", node->filename, tmp) < 0)
         {
             ret = DMERR_FWRITE;
             goto error;
@@ -919,7 +910,7 @@
     }
 
 error:
-    DMRES_UNLOCK();
+    dmMutexUnlock(lib->mutex);
     fclose(f);
     return ret;
 }
@@ -927,15 +918,18 @@
 
 /* Resources subsystem initialization and shutdown routines
  */
-int dmres_init(const char *filename, const char *path, const int flags, int (*classifier)(DMResource *))
+int dmres_init(DMResourceLib **plib, const char *filename, const char *path, const int flags, int (*classifier)(DMResource *))
 {
-    // Check if we are already initialized
-    if (dfResInitialized)
-        return DMERR_ALREADY_INIT;
+    DMResourceLib *lib;
+    
+    // Allocate the resource library structure
+    if ((*plib = lib = dmMalloc0(sizeof(DMResourceLib))) == NULL)
+        return DMERR_MALLOC;
 
-    dfResFlags        = flags; 
-    dfResPath         = dm_strdup((path != NULL) ? path : DMRES_DATA_PATH);
-    dfResourcesMutex  = dmCreateMutex();
+    // Basic data
+    lib->mutex    = dmCreateMutex();
+    lib->flags    = flags; 
+    lib->resPath  = dm_strdup((path != NULL) ? path : DMRES_DATA_PATH);
 
 
     if (flags & DRF_USE_PACK)
@@ -944,22 +938,22 @@
         int ret;
         DMPackEntry *node;
 
-        dfResPackFilename = dm_strdup((filename != NULL) ? filename : DMRES_DATA_PACK);
+        lib->packFilename = dm_strdup((filename != NULL) ? filename : DMRES_DATA_PACK);
 
         // Initialize PACK, open as read-only
-        ret = dm_pack_open(dfResPackFilename, &dfResPackFile, TRUE);
+        ret = dm_pack_open(lib->packFilename, &lib->packFile, TRUE);
         if (ret != DMERR_OK)
         {
             dmError("Error opening PACK file '%s', #%i: %s\n",
-                dfResPackFilename, ret, dmErrorStr(ret));
+                lib->packFilename, ret, dmErrorStr(ret));
 
             return DMERR_INIT_FAIL;
         }
         
         // Initialize resources from a PACK file
-        for (node = dfResPackFile->entries; node != NULL; node = node->next)
+        for (node = lib->packFile->entries; node != NULL; node = node->next)
         {
-            DMResource *res = dmres_new(node->filename, node->resFlags & DMF_MASK, node->size);
+            DMResource *res = dmres_new(lib, node->filename, node->resFlags & DMF_MASK, node->size);
             if (res == NULL)
             {
                 dmError("Could not allocate memory for resource node '%s' [0x%08x], %d.\n",
@@ -967,7 +961,7 @@
                 return DMERR_INIT_FAIL;
             }
 
-            dmres_insert(res);
+            dmres_insert(lib, res);
         }
         
 #else
@@ -978,8 +972,8 @@
     else
     {
         // Initialize resources from a resource directory
-        char *resFilename = dm_strdup_printf("%s%s", dfResPath, DMRES_RES_FILE);
-        int ret = dmres_load_resfile(resFilename);
+        char *resFilename = dm_strdup_printf("%s%s", lib->resPath, DMRES_RES_FILE);
+        int ret = dmres_load_resfile(lib, resFilename);
         dmFree(resFilename);
         
         if (ret != DMERR_OK)
@@ -987,10 +981,10 @@
     }
 
     // Okay, classify resources
-    if (dfResources != NULL && classifier != NULL)
+    if (lib->resources != NULL && classifier != NULL)
     {
         DMResource *node;
-        for (node = dfResources; node != NULL; node = node->next)
+        for (node = lib->resources; node != NULL; node = node->next)
         {
             int ret = classifier(node);
             if (ret != DMERR_OK)
@@ -999,36 +993,36 @@
     }
 
     // Initialization complete
-    dfResInitialized = TRUE;
     return DMERR_OK;
 }
 
 
-void dmres_close(void)
+int dmres_close(DMResourceLib *lib)
 {
     DMResource *node;
-    DMRES_LOCK();
+    
+    if (lib == NULL)
+        return DMERR_NULLPTR;
+    
+    dmMutexLock(lib->mutex);
 
-    if (!dfResInitialized)
-        return;
-    
     // Shutdown possible subsystems
 #ifdef DM_USE_PACKFS
-    if (dfResFlags & DRF_USE_PACK)
+    if (lib->flags & DRF_USE_PACK)
     {
-        int res = dm_pack_close(dfResPackFile);
+        int res = dm_pack_close(lib->packFile);
         if (res != DMERR_OK)
         {
             dmError("Error closing PACK, #%i: %s\n",
                         res, dmErrorStr(res));
         }
 
-        dmFree(dfResPackFilename);
+        dmFree(lib->packFilename);
     }
 #endif
 
     // Free resource entries
-    node = dfResources;
+    node = lib->resources;
     while (node != NULL)
     {
         DMResource *next = node->next;
@@ -1037,65 +1031,64 @@
     }
 
     // Etc.
-    dmFree(dfResPath);
-    DMRES_UNLOCK();
-    dmDestroyMutex(dfResourcesMutex);
-    dfResInitialized = FALSE;
+    dmFree(lib->resPath);
+    dmMutexUnlock(lib->mutex);
+    dmDestroyMutex(lib->mutex);
+    return DMERR_OK;
 }
 
 
-int dmres_preload(BOOL start, int *loaded, int *total)
+int dmres_preload(DMResourceLib *lib, BOOL start, int *loaded, int *total)
 {
-    static DMResource *dfPreload = NULL;
     int ret = DMERR_OK;
 
-    DMRES_LOCK();
+    dmMutexLock(lib->mutex);
     
     // Initialize preloading 
-    if (dfPreload == NULL || start)
+    if (lib->preload == NULL || start)
     {
         DMResource *node;
         
-        dfPreload = dfResources;
+        lib->preload = lib->resources;
         *loaded = 0;
         *total = 0;
 
         // Calculate total number of resources to be preloaded
-        for (node = dfResources; node != NULL; node = node->next)
+        for (node = lib->resources; node != NULL; node = node->next)
         {
-            if ((dfResFlags & (DRF_PRELOAD_ALL | DRF_PRELOAD_RES)) ||
+            if ((lib->flags & (DRF_PRELOAD_ALL | DRF_PRELOAD_RES)) ||
                 (node->flags & (DMF_PRELOAD_RAW | DMF_PRELOAD_RES)))
                 (*total)++;
         }
     }
     else
-    if (dfPreload != NULL)
+    if (lib->preload != NULL)
     {
         // Initialize fops and preload
-        dmf_init_fops(dfPreload);
-        if ((ret = dmf_preload(dfPreload)) != DMERR_OK)
+        dmf_init_fops(lib->preload);
+        if ((ret = dmf_preload(lib->preload)) != DMERR_OK)
             goto error;
 
         (*loaded)++;
-        dfPreload = dfPreload->next;
+        lib->preload = lib->preload->next;
     }
 
-    DMRES_UNLOCK();
-    return (dfPreload == NULL) ? DMERR_OK : DMERR_PROGRESS;
+    dmMutexUnlock(lib->mutex);
+    return (lib->preload == NULL) ? DMERR_OK : DMERR_PROGRESS;
 
 error:
-    DMRES_UNLOCK();
+    dmMutexUnlock(lib->mutex);
     return ret;
 }
 
 
-void dmres_prune(int agems, int flags)
+void dmres_prune(DMResourceLib *lib, int agems, int flags)
 {
     DMResource *node;
     int currtime = time(NULL);
-    DMRES_LOCK();
+    dmMutexLock(lib->mutex);
 
-    for (node = dfResources; node != NULL; node = node->next)
+    for (node = lib->resources; node != NULL; node = node->next)
     {
         // Check if node has refcount of 0 and is
         // not marked as persistent resource
@@ -1115,7 +1108,7 @@
         }
     }
 
-    DMRES_UNLOCK();
+    dmMutexUnlock(lib->mutex);
 }