Initial structure for replacable allocator work.
authorRyan C. Gordon <icculus@icculus.org>
Thu, 23 Sep 2004 06:45:36 +0000
changeset 644 1cb5533d369c
parent 643 95824caf2dbf
child 645 d7db48f2b9c8
Initial structure for replacable allocator work.
archivers/zip.c
physfs.c
physfs.h
physfs_internal.h
platform/posix.c
--- a/archivers/zip.c	Thu Sep 23 06:38:51 2004 +0000
+++ b/archivers/zip.c	Thu Sep 23 06:45:36 2004 +0000
@@ -182,6 +182,47 @@
 };
 
 
+
+/*
+ * Bridge physfs allocation functions to zlib's format...
+ */
+static voidpf zlibPhysfsAlloc(voidpf opaque, uInt items, uInt size)
+{
+    /* must lock the whole time, since zlib doesn't deal with that. :( */
+    PHYSFS_allocator *allocator = __PHYSFS_getAllocator();
+    size_t total = (items * size) + sizeof (PHYSFS_memhandle);
+    PHYSFS_memhandle h = allocator->malloc(total);
+    char *ptr = (char *) allocator->lock(h);
+    PHYSFS_memhandle *ph = (PHYSFS_memhandle *) ptr;
+    *ph = h; /* tuck the memhandle in front of the memory block... */
+    return(ptr + sizeof (PHYSFS_memhandle));
+} /* zlibPhysfsAlloc */
+
+
+/*
+ * Bridge physfs allocation functions to zlib's format...
+ */
+static void zlibPhysfsFree(voidpf opaque, voidpf address)
+{
+    char *ptr = ((char *) address) - (sizeof (PHYSFS_memhandle));
+    PHYSFS_allocator *allocator = __PHYSFS_getAllocator();
+    PHYSFS_memhandle *ph = (PHYSFS_memhandle *) ptr;
+    allocator->unlock(*ph);
+    allocator->free(*ph);
+} /* zlibPhysfsFree */
+
+
+/*
+ * Construct a new z_stream to a sane state.
+ */
+static void initializeZStream(z_stream *pstr)
+{
+    memset(pstr, '\0', sizeof (z_stream));
+    pstr->zalloc = zlibPhysfsAlloc;
+    pstr->zfree = zlibPhysfsFree;
+} /* initializeZStream */
+
+
 static const char *zlib_error_string(int rc)
 {
     switch (rc)
@@ -360,7 +401,7 @@
         {
             /* we do a copy so state is sane if inflateInit2() fails. */
             z_stream str;
-            memset(&str, '\0', sizeof (z_stream));
+            initializeZStream(&str);
             if (zlib_err(inflateInit2(&str, -MAX_WBITS)) != Z_OK)
                 return(0);
 
@@ -728,7 +769,7 @@
         {
             if (__PHYSFS_platformRead(in, compressed, compsize, 1) == 1)
             {
-                memset(&stream, '\0', sizeof (z_stream));
+                initializeZStream(&stream);
                 stream.next_in = compressed;
                 stream.avail_in = compsize;
                 stream.next_out = (unsigned char *) path;
@@ -1404,6 +1445,7 @@
     memset(finfo, '\0', sizeof (ZIPfileinfo));
     finfo->handle = in;
     finfo->entry = ((entry->symlink != NULL) ? entry->symlink : entry);
+    initializeZStream(&finfo->stream);
     if (finfo->entry->compression_method != COMPMETH_NONE)
     {
         if (zlib_err(inflateInit2(&finfo->stream, -MAX_WBITS)) != Z_OK)
--- a/physfs.c	Thu Sep 23 06:38:51 2004 +0000
+++ b/physfs.c	Thu Sep 23 06:45:36 2004 +0000
@@ -171,6 +171,10 @@
 static void *errorLock = NULL;     /* protects error message list.        */
 static void *stateLock = NULL;     /* protects other PhysFS static state. */
 
+/* allocator ... */
+static int externalAllocator = 0;
+static PHYSFS_allocator allocator;
+
 
 /* functions ... */
 
@@ -752,11 +756,17 @@
 } /* initializeMutexes */
 
 
+static void setDefaultAllocator(void);
+
 int PHYSFS_init(const char *argv0)
 {
     char *ptr;
 
     BAIL_IF_MACRO(initialized, ERR_IS_INITIALIZED, 0);
+
+    if (!externalAllocator)
+        setDefaultAllocator();
+
     BAIL_IF_MACRO(!__PHYSFS_platformInit(), NULL, 0);
 
     BAIL_IF_MACRO(!initializeMutexes(), NULL, 0);
@@ -1995,5 +2005,34 @@
     return(retval);
 } /* __PHYSFS_addToLinkedStringList */
 
+
+int PHYSFS_setAllocator(PHYSFS_allocator *a)
+{
+    BAIL_IF_MACRO(initialized, ERR_IS_INITIALIZED, 0);
+    externalAllocator = (a != NULL);
+    if (externalAllocator)
+        memcpy(&allocator, a, sizeof (PHYSFS_allocator));
+
+    return(1);
+} /* PHYSFS_setAllocator */
+
+
+static void setDefaultAllocator(void)
+{
+    assert(!externalAllocator);
+    allocator.malloc = __PHYSFS_platformMalloc;
+    allocator.realloc = __PHYSFS_platformRealloc;
+    allocator.free = __PHYSFS_platformFree;
+    allocator.lock = __PHYSFS_platformLock;
+    allocator.unlock = __PHYSFS_platformUnlock;
+} /* setDefaultAllocator */
+
+
+PHYSFS_allocator *__PHYSFS_getAllocator(void)
+{
+    return(&allocator);
+} /* __PHYFS_getAllocator */
+
+
 /* end of physfs.c ... */
 
--- a/physfs.h	Thu Sep 23 06:38:51 2004 +0000
+++ b/physfs.h	Thu Sep 23 06:45:36 2004 +0000
@@ -1820,6 +1820,92 @@
 __EXPORT__ int PHYSFS_writeUBE64(PHYSFS_file *file, PHYSFS_uint64 val);
 
 
+/* Everything above this line is part of the PhysicsFS 1.0 API. */
+
+
+/**
+ * \typedef PHYSFS_memhandle
+ * \brief Used to represent memory blocks.
+ *
+ * (This is for limited, hardcore use. If you don't immediately see a need
+ *  for it, you can probably ignore this forever.)
+ *
+ * The allocator routines will pass these around. They are void pointers
+ *  because it's convenient for systems to have handles be the same size
+ *  as a pointer, but they shouldn't be assumed to point to valid memory
+ *  (or to memory at all). The allocator in use will convert from memhandles
+ *  to valid pointers to allocated memory.
+ *
+ * \sa PHYSFS_allocator
+ * \sa PHYSFS_setAllocator
+ */
+typedef void *PHYSFS_memhandle;
+
+
+/**
+ * \struct PHYSFS_allocator
+ * \brief PhysicsFS allocation function pointers.
+ *
+ * (This is for limited, hardcore use. If you don't immediately see a need
+ *  for it, you can probably ignore this forever.)
+ *
+ * You create one of these structures for use with PHYSFS_setAllocator.
+ *  It should be noted that, in order to accomodate platforms like PalmOS,
+ *  we don't just ask for a block of memory and get a pointer. We work on
+ *  a "handle" system, which requires PhysicsFS to "lock" before accessing,
+ *  and "unlock" when not using. This is also useful for systems that are
+ *  concerned about memory fragmentation; you can rearrange unlocked memory
+ *  blocks in your address space, since PhysicsFS will re-request the pointer
+ *  by relocking the block.
+ *
+ * Locked memory is assumed to be non-reentrant, and locking an already-locked
+ *  handle (and unlocking an unlocked handle) has undefined results. Use
+ *  mutexes if not sure.
+ *
+ * \sa PHYSFS_memhandle
+ * \sa PHYSFS_setAllocator
+ */
+typedef struct
+{
+    PHYSFS_memhandle (*malloc)(size_t);
+    PHYSFS_memhandle (*realloc)(PHYSFS_memhandle, size_t);
+    void (*free)(PHYSFS_memhandle);
+    void *(*lock)(PHYSFS_memhandle);
+    void *(*unlock)(PHYSFS_memhandle);
+} PHYSFS_allocator;
+
+
+/**
+ * \fn int PHYSFS_setAllocator(PHYSFS_allocator *allocator)
+ * \brief Hook your own allocation routines into PhysicsFS.
+ *
+ * (This is for limited, hardcore use. If you don't immediately see a need
+ *  for it, you can probably ignore this forever.)
+ *
+ * By default, PhysicsFS will use ANSI C malloc/realloc/calloc/free calls
+ *  to manage dynamic memory, but in some uncommon cases, the app might want
+ *  more control over the library's memory management. This lets you redirect
+ *  physfs to use your own allocation routines instead. You can only call this
+ *  function before PHYSFS_init(); if the library is initialized, it'll
+ *  reject your efforts to change the allocator mid-stream. You may call this
+ *  function after PHYSFS_deinit() if you are willing to shutdown the library
+ *  and restart it with a new allocator; this is a safe and supported
+ *  operation. The allocator remains intact between deinit/init calls.
+ *  If you want to return to the default allocator, pass a NULL in here.
+ *
+ * If you aren't immediately sure what to do with this function, you can
+ *  safely ignore it altogether.
+ *
+ *    \param allocator Structure containing your allocator's entry points.
+ *   \return zero on failure, non-zero on success. This call only fails
+ *           when used between PHYSFS_init() and PHYSFS_deinit() calls.
+ */
+__EXPORT__ int PHYSFS_setAllocator(PHYSFS_allocator *allocator);
+
+
+/* Everything above this line is part of the PhysicsFS 2.0 API. */
+
+
 #ifdef __cplusplus
 }
 #endif
--- a/physfs_internal.h	Thu Sep 23 06:38:51 2004 +0000
+++ b/physfs_internal.h	Thu Sep 23 06:45:36 2004 +0000
@@ -1295,6 +1295,10 @@
 #define BAIL_IF_MACRO_MUTEX(c, e, m, r) if (c) { __PHYSFS_setError(e); __PHYSFS_platformReleaseMutex(m); return r; }
 
 
+/*
+ * Get the current allocator. Not valid before PHYSFS_init is called!
+ */
+PHYSFS_allocator *__PHYSFS_getAllocator(void);
 
 
 /*--------------------------------------------------------------------------*/
@@ -1694,6 +1698,35 @@
  */
 void __PHYSFS_platformReleaseMutex(void *mutex);
 
+/*
+ * Implement malloc. It's safe to just pass through from the C runtime.
+ */
+PHYSFS_memhandle __PHYSFS_platformMalloc(size_t s);
+
+/*
+ * Implement realloc. It's safe to just pass through from the C runtime.
+ */
+PHYSFS_memhandle __PHYSFS_platformRealloc(PHYSFS_memhandle h, size_t s);
+
+/*
+ * Implement free. It's safe to just pass through from the C runtime.
+ */
+void __PHYSFS_platformFree(PHYSFS_memhandle h);
+
+/*
+ * Lock a memhandle. If you are just passing through from the C runtime,
+ *  it is safe to make this a no-op. Otherwise, convert to a real pointer
+ *  in the address space and return it.
+ */
+void *__PHYSFS_platformLock(PHYSFS_memhandle h);
+
+/*
+ * Unlock a memhandle. If you are just passing through from the C runtime,
+ *  it is safe to make this a no-op. Otherwise, you can consider the data in
+ *  the address space safe to move around until the handle is relocked.
+ */
+void __PHYSFS_platformUnlock(PHYSFS_memhandle h);
+
 #ifdef __cplusplus
 }
 #endif
--- a/platform/posix.c	Thu Sep 23 06:38:51 2004 +0000
+++ b/platform/posix.c	Thu Sep 23 06:45:36 2004 +0000
@@ -500,6 +500,37 @@
     return statbuf.st_mtime;
 } /* __PHYSFS_platformGetLastModTime */
 
+
+PHYSFS_memhandle __PHYSFS_platformMalloc(size_t s)
+{
+    assert(sizeof (h) == sizeof (void *));
+    return((PHYSFS_memhandle) malloc(s));
+} /* __PHYSFS_platformMalloc */
+
+
+PHYSFS_memhandle __PHYSFS_platformRealloc(PHYSFS_memhandle h, size_t s)
+{
+    return((PHYSFS_memhandle) realloc((void *) h, s));
+} /* __PHYSFS_platformRealloc */
+
+
+void __PHYSFS_platformFree(PHYSFS_memhandle h)
+{
+    free((void *) h);
+} /* __PHYSFS_platformFree */
+
+
+void *__PHYSFS_platformLock(PHYSFS_memhandle h)
+{
+    return((void *) h);
+} /* __PHYSFS_platformLock */
+
+
+void __PHYSFS_platformUnlock(PHYSFS_memhandle h)
+{
+    /* no-op. */
+} /* __PHYSFS_platformUnlock */
+
 #endif /* !defined WIN32 */
 
 /* end of posix.c ... */