changeset 26:2f463a59d732

Implement rudimentary resource system.
author Matti Hamalainen <ccr@tnsp.org>
date Sat, 29 Sep 2012 05:29:38 +0300
parents 372b68c0752a
children 21c14afbf63d
files dmlib.h dmres.c dmres.h
diffstat 3 files changed, 155 insertions(+), 52 deletions(-) [+]
line wrap: on
line diff
--- a/dmlib.h	Fri Sep 28 15:45:50 2012 +0300
+++ b/dmlib.h	Sat Sep 29 05:29:38 2012 +0300
@@ -35,20 +35,22 @@
 enum {
 	// General error codes
 	DMERR_OK = 0,
+	DMERR_PROGRESS,     // Status OK, but operation in progress
+	
 	DMERR_FOPEN,
 	DMERR_FREAD,
 	DMERR_FWRITE,
 	DMERR_FSEEK,
-	DMERR_NOT_FOUND,
+	DMERR_NOT_FOUND,    // Resource/data not found
 
-	DMERR_INVALID_DATA,
-	DMERR_MALLOC,
-	DMERR_ALREADY_INIT,
-	DMERR_INIT_FAIL,
+	DMERR_INVALID_DATA, // Some data was invalid
+	DMERR_MALLOC,       // Memory allocation failure
+	DMERR_ALREADY_INIT, // Resource has already been initialized
+	DMERR_INIT_FAIL,    // General initialization failure
 	DMERR_INVALID_ARGS,
 
-	DMERR_NULLPTR,
-	DMERR_NOT_SUPPORTED,
+	DMERR_NULLPTR,      // NULL pointer specified in critical argument
+	DMERR_NOT_SUPPORTED,// Operation not supported
 	DMERR_OUT_OF_DATA,
 	DMERR_EXTRA_DATA,
 	DMERR_BOUNDS,
--- a/dmres.c	Fri Sep 28 15:45:50 2012 +0300
+++ b/dmres.c	Sat Sep 29 05:29:38 2012 +0300
@@ -48,6 +48,14 @@
 {
     if (res != NULL)
     {
+        if (res->rdata != NULL &&
+            res->rops != NULL &&
+            res->rops->free != NULL)
+        {
+            res->rops->free(res);
+            res->rdata = NULL;
+        }
+
         dmFree(res->filename);
         dmFree(res->data);
         dmFree(res);
@@ -479,6 +487,28 @@
 /* FS file handling functions. These functions call the actual
  * functions depending on where the file is located.
  */
+static void dmf_init_fops(DMResource *handle)
+{
+    // Check fops
+    if (handle->fops == NULL)
+    {
+#ifdef DMRES_PACKFS
+        if (dfResFlags & DRF_USE_PACK)
+            handle->fops = &dfPackFileOps;
+#ifdef DMRES_STDIO
+        else
+            handle->fops = &dfStdioFileOps;
+#else
+        handle->fops = &dfPackFileOps;
+#endif
+
+#else
+        handle->fops = &dfStdioFileOps;
+#endif
+    }
+}
+
+
 DMResource *dmf_open(const char *filename)
 {
     int ret;
@@ -501,26 +531,10 @@
 #endif
     }
 
-    // Check fops
-    if (handle->fops == NULL)
-    {
-#ifdef DMRES_PACKFS
-        if (dfResFlags & DRF_USE_PACK)
-            handle->fops = &dfPackFileOps;
-#ifdef DMRES_STDIO
-        else
-            handle->fops = &dfStdioFileOps;
-#else
-        handle->fops = &dfPackFileOps;
-#endif
-
-#else
-        handle->fops = &dfStdioFileOps;
-#endif
-    }
+    dmf_init_fops(handle);
 
     // Check if the data is preloaded
-    if (handle->flags & DMF_LOADED)
+    if (handle->flags & DMF_LOADED_RAW)
     {
         dmres_ref(handle);
         return handle;
@@ -528,7 +542,8 @@
 
     // Check if we want to preload ..
     ret = DMERR_INIT_FAIL;
-    if ((handle->flags & DMF_PRELOAD) &&
+    if (((handle->flags & DMF_PRELOAD_RAW) || (dfResFlags & DRF_PRELOAD_ALL)) &&
+        (handle->flags & DMF_LOADED_RAW) == 0 &&
         handle->fops->preload != NULL)
         ret = handle->fops->preload(handle);
     else
@@ -539,11 +554,20 @@
         if (handle->fops->preload != NULL)
             ret = handle->fops->preload(handle);
     }
+
+    if (((handle->flags & DMF_PRELOAD_RES) || (dfResFlags & DRF_PRELOAD_RES)) &&
+        (handle->flags & DMF_LOADED_RES) == 0 &&
+        handle->rops != NULL &&
+        handle->rops->load != NULL)
+        ret = handle->rops->load(handle);
+
     
     if (ret == DMERR_OK)
+    {
+        dmres_ref(handle);
         return handle;
+    }
 
-    dmres_ref(handle);
     return NULL;
 }
 
@@ -556,7 +580,7 @@
     if ((handle = dmres_find(filename)) == NULL)
     {
         // Hmm.. does not exist? Fall back to a stdio file
-        handle = dmres_new(filename, DMF_LOADED, len);
+        handle = dmres_new(filename, DMF_LOADED_RAW, len);
         if (handle == NULL)
             return NULL;
 
@@ -752,7 +776,7 @@
 
 /* Resources subsystem initialization and shutdown routines
  */
-int dmres_init(const char *filename, const char *path, int flags)
+int dmres_init(const char *filename, const char *path, int flags, int (*classifier)(DMResource *))
 {
     // Check if we are already initialized
     if (dfResInitialized)
@@ -810,6 +834,17 @@
             return DMERR_INIT_FAIL;
     }
 
+    // Okay, classify resources
+    if (dfResources != NULL && classifier != NULL)
+    {
+        DMResource *node;
+        for (node = dfResources; node != NULL; node = node->next)
+        {
+            int ret = classifier(node);
+            if (ret != DMERR_OK)
+                return DMERR_INIT_FAIL;
+        }
+    }
 
     // Initialization complete
     dfResInitialized = TRUE;
@@ -857,54 +892,90 @@
 }
 
 
-BOOL dmres_preload(int *loaded, int *total)
+int dmres_preload(BOOL start, int *loaded, int *total)
 {
     static DMResource *dfPreload = NULL;
+    int ret = DMERR_OK;
 
     DMRES_LOCK();
     
-    if (dfPreload == NULL)
+    // Initialize preloading 
+    if (dfPreload == NULL || start)
     {
         DMResource *node;
+        
         dfPreload = dfResources;
         *loaded = 0;
         *total = 0;
+
+        // Calculate total number of resources to be preloaded
         for (node = dfResources; node != NULL; node = node->next)
         {
-            if (node->flags & DMF_PRELOAD)
+            if ((dfResFlags & (DRF_PRELOAD_ALL | DRF_PRELOAD_RES)) ||
+                (node->flags & (DMF_PRELOAD_RAW | DMF_PRELOAD_RES)))
                 (*total)++;
         }
     }
-
+    else
     if (dfPreload != NULL)
     {
-        if ((dfPreload->flags & DMF_PRELOAD) && (dfPreload->flags & DMF_LOADED) == 0)
+        // Check if the raw resource wants to be preloaded
+        if (((dfPreload->flags & DMF_PRELOAD_RAW) || (dfResFlags & DRF_PRELOAD_ALL)) &&
+            (dfPreload->flags & DMF_LOADED_RAW) == 0)
         {
-            (*loaded)++;
+            dmf_init_fops(dfPreload);
+            if (dfPreload->fops->preload != NULL)
+            {
+                ret = dfPreload->fops->preload(dfPreload);
+                if (ret == DMERR_OK)
+                {
+                    dfPreload->flags |= DMF_LOADED_RAW;
+                    (*loaded)++;
+                }
+                else
+                    goto error;
+            }
+        }
+
+        // Preload actual resource, if requested
+        if (((dfPreload->flags & DMF_PRELOAD_RES) || (dfResFlags & DRF_PRELOAD_RES)) &&
+            (dfPreload->flags & DMF_LOADED_RES) == 0 &&
+            dfPreload->rops != NULL &&
+            dfPreload->rops->load != NULL)
+        {
+            dmf_init_fops(dfPreload);
+            ret = dfPreload->rops->load(dfPreload);
+            if (ret != DMERR_OK)
+                goto error;
+
+            dfPreload->flags |= DMF_LOADED_RES;
         }
 
         dfPreload = dfPreload->next;
     }
 
     DMRES_UNLOCK();
-    
-    return (*total) == (*loaded);
+    return (dfPreload == NULL) ? DMERR_OK : DMERR_PROGRESS;
+
+error:
+    DMRES_UNLOCK();
+    return ret;
 }
 
 
 void dmres_prune(int agems, int flags)
 {
-    DMResource *node, *next;
+    DMResource *node;
     int currtime = time(NULL);
     DMRES_LOCK();
 
-    node = dfResources;
-    while (node != NULL)
+    for (node = dfResources; node != NULL; node = node->next)
     {
-        next = 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)
+        if (node->refcount == 0 &&
+            (node->flags & DMF_PERSIST) == 0 &&
+            (node->flags & (DMF_LOADED_RES | DMF_LOADED_RAW)))
         {
             // Check if we match either one of atime or mtime
             if (((flags & DMPRUNE_ATIME) &&
@@ -912,10 +983,24 @@
                 ((flags & DMPRUNE_MTIME) &&
                 currtime - node->mtime >= agems))
             {
-                dmres_delete(node);
+                // Check if resource data is loaded
+                if (node->rdata != NULL &&
+                    node->rops != NULL &&
+                    node->rops->free != NULL)
+                {
+                    node->rops->free(node);
+                    node->flags &= !DMF_LOADED_RES;
+                }
+                
+                // Check if raw data is loaded
+                if (node->flags & DMF_LOADED_RAW)
+                {
+                    dmFree(node->data);
+                    node->data = NULL;
+                    node->flags &= !DMF_LOADED_RAW;
+                }    
             }
         }
-        node = next;
     }
 
     DMRES_UNLOCK();
--- a/dmres.h	Fri Sep 28 15:45:50 2012 +0300
+++ b/dmres.h	Sat Sep 29 05:29:38 2012 +0300
@@ -30,24 +30,30 @@
 enum
 {
     DRF_USE_PACK    = 0x0001,
+    DRF_PRELOAD_ALL = 0x0002,
+    DRF_PRELOAD_RES = 0x0004,
 };
 
 enum
 {
-    DMF_PRELOAD     = 0x0001, // Preload this resource
-    DMF_PERSIST     = 0x0002, // Persist loaded resource (only freed at shutdown/explicit prune)
-    //DMF_STREAM      = 0x0004, // This resource is streamed
+    DMF_PRELOAD_RAW = 0x0001, // Preload raw data
+    DMF_PRELOAD_RES = 0x0002, // Perform resource preloading (not 
+    DMF_PERSIST     = 0x0004, // Persist loaded resource (only freed at shutdown/explicit prune)
+    DMF_STREAM      = 0x0008, // This resource is streamed (UNSUPPORTED FOR NOW)
     DMF_MASK        = 0x0fff,
 
-    DMF_LOADED      = 0x1000, // Resource has been loaded
+    DMF_LOADED_RAW  = 0x1000, // Raw data has been loaded
+    DMF_LOADED_RES  = 0x2000, // Resource has been loaded
 };
 
 
 /* Typedefs and structures
  */
+struct DMResourceDataOps;
 struct DMResourceOps;
+struct DMResource;
 
-typedef struct _DMResource
+typedef struct DMResource
 {
     // Timestamps (in seconds from time())
     int    mtime,              // When resource was loaded
@@ -64,12 +70,22 @@
     int    error;              // Error code
 
     struct DMResourceOps *fops;    // Pointer to file handling functions struct
-    struct _DMResource *next, *prev;
+    struct DMResource *next, *prev;
+
+    void   *rdata;
+    struct DMResourceDataOps *rops;
 
     FILE * fh;
 } DMResource;
 
 
+typedef struct DMResourceDataOps
+{
+    int    (*load)(DMResource *res);
+    void   (*free)(DMResource *res);
+} DMResourceDataOps;
+
+
 typedef struct DMResourceOps
 {
     int     (*ferror)(DMResource *);
@@ -88,11 +104,11 @@
 
 /* Functions
  */
-int          dmres_init(const char *filename, const char *path, int flags);
+int          dmres_init(const char *filename, const char *path, int flags, int (*classifier)(DMResource *));
 void         dmres_close(void);
 
 void         dmres_prune(int agems, int flags);
-int          dmres_preload();
+int          dmres_preload(BOOL start, int *loaded, int *total);
 
 int          dmres_load_resfile(const char *filename);
 int          dmres_write_resfile(const char *filename);