Progress toward complete implementation continues...
authorRyan C. Gordon <icculus@icculus.org>
Fri, 06 Jul 2001 08:47:23 +0000
changeset 11 677e01f5109e
parent 10 45bd486c0224
child 12 a4041c91d715
Progress toward complete implementation continues...
Makefile
dir.c
physfs.c
physfs_internal.h
unix.c
zip.c
--- a/Makefile	Fri Jul 06 02:33:21 2001 +0000
+++ b/Makefile	Fri Jul 06 08:47:23 2001 +0000
@@ -173,7 +173,7 @@
 $(BINDIR)/%.o: $(SRCDIR)/%.asm
 	$(ASM) $(ASMFLAGS) -o $@ $<
 
-.PHONY: all clean listobjs
+.PHONY: all clean distclean listobjs
 
 all: $(BINDIR) $(MAINLIB)
 
@@ -183,6 +183,8 @@
 $(BINDIR):
 	mkdir -p $(BINDIR)
 
+distclean: clean
+
 clean:
 	rm -f $(CLEANUP)
 	rm -rf $(BINDIR)
--- a/dir.c	Fri Jul 06 02:33:21 2001 +0000
+++ b/dir.c	Fri Jul 06 08:47:23 2001 +0000
@@ -12,11 +12,8 @@
 #define __PHYSICSFS_INTERNAL__
 #include "physfs_internal.h"
 
-/* template for filehandles. */
-const FileHandle __PHYSFS_FileHandle_DIR =
+static const FileFunctions __PHYSFS_FileHandle_DIR =
 {
-    NULL,       /* opaque         */
-    NULL,       /* dirReader      */
     DIR_read,   /* read() method  */
     NULL,       /* write() method */
     DIR_eof,    /* eof() method   */
@@ -25,15 +22,28 @@
     DIR_close,  /* close() method */
 };
 
-/* template for directories. */
-const DirReader __PHYSFS_DirReader_DIR =
+
+static const FileFunctions __PHYSFS_FileHandle_DIRW =
 {
-    NULL,              /* opaque                  */
+    NULL,       /* read() method  */
+    DIR_write,  /* write() method */
+    DIR_eof,    /* eof() method   */
+    DIR_tell,   /* tell() method  */
+    DIR_seek,   /* seek() method  */
+    DIR_close,  /* close() method */
+};
+
+
+const DirFunctions __PHYSFS_DirFunctions_DIR =
+{
+    DIR_isArchive,     /* isArchive() method      */
+    DIR_openArchive,   /* openArchive() method    */
     DIR_enumerate,     /* enumerateFiles() method */
     DIR_isDirectory,   /* isDirectory() method    */
     DIR_isSymLink,     /* isSymLink() method      */
     DIR_isOpenable,    /* isOpenable() method     */
     DIR_openRead,      /* openRead() method       */
+    DIR_openWrite,     /* openWrite() method      */
     DIR_dirClose,      /* close() method          */
 };
 
--- a/physfs.c	Fri Jul 06 02:33:21 2001 +0000
+++ b/physfs.c	Fri Jul 06 08:47:23 2001 +0000
@@ -25,7 +25,6 @@
     struct __PHYSFS_ERRMSGTYPE__ *next;
 } ErrMsg;
 
-
 typedef struct __PHYSFS_SEARCHDIRINFO__
 {
     char *dirName;
@@ -33,22 +32,23 @@
     struct __PHYSFS_SEARCHDIRINFO__ *next;
 } SearchDirInfo;
 
+typedef struct __PHYSFS_FILEHANDLELIST__
+{
+    FileHandle *handle;
+    struct __PHYSFS_FILEHANDLELIST__ *next;
+} FileHandleList;
 
-static int initialized = 0;
-static ErrMsg *errorMessages = NULL;
-static char *searchPath = NULL;
-static char *baseDir = NULL;
-static char *writeDir = NULL;
-static int allowSymLinks = 0;
+
+/* The various i/o drivers... */
 
 #if (defined PHYSFS_SUPPORTS_ZIP)
-extern const __PHYSFS_ArchiveInfo __PHYSFS_ArchiveInfo_ZIP;
-extern const __PHYSFS_DirReader   __PHYSFS_DirReader_ZIP;
-extern const __PHYSFS_FileHandle  __PHYSFS_FileHandle_ZIP;
+extern const PHYSFS_ArchiveInfo   __PHYSFS_ArchiveInfo_ZIP;
+extern const DirFunctions         __PHYSFS_DirFunctions_ZIP;
 #endif
 
+extern const DirFunctions  __PHYSFS_DirFunctions_DIR;
 
-static const __PHYSFS_ArchiveInfo *supported_types[] =
+static const PHYSFS_ArchiveInfo *supported_types[] =
 {
 #if (defined PHYSFS_SUPPORTS_ZIP)
     &__PHYSFS_ArchiveInfo_ZIP,
@@ -57,8 +57,33 @@
     NULL
 };
 
+static const DirFunctions *dirFunctions[] =
+{
+#if (defined PHYSFS_SUPPORTS_ZIP)
+    &__PHYSFS_DirFunctions_ZIP,
+#endif
+
+    &__PHYSFS_DirFunctions_DIR,
+    NULL
+};
+
 
 
+/* General PhysicsFS state ... */
+
+static int initialized = 0;
+static ErrMsg *errorMessages = NULL;
+static SearchDirInfo *searchPath = NULL;
+static FileHandleList *openWriteList = NULL;
+static FileHandleList *openReadList = NULL;
+static char *baseDir = NULL;
+static char *userDir = NULL;
+static char *writeDir = NULL;
+static int allowSymLinks = 0;
+
+
+
+/* functions ... */
 
 static ErrMsg *findErrorForCurrentThread(void)
 {
@@ -124,12 +149,53 @@
 } /* PHYSFS_getLinkedVersion */
 
 
+static const char *calculateUserDir(void)
+{
+    char *retval = NULL;
+    const char *str = NULL;
+
+    str = __PHYSFS_platformGetUserDir();
+    if (str != NULL)
+        retval = str;
+    else
+    {
+        const char *dirsep = PHYSFS_getDirSeparator();
+        const char *uname = __PHYSFS_platformGetUserName();
+
+        str = (uname != NULL) ? uname : "default";
+        retval = malloc(strlen(baseDir) + strlen(str) +
+                        (strlen(dirsep) * 2) + 6);
+
+        if (retval == NULL)
+            __PHYSFS_setError(ERR_OUT_OF_MEMORY);
+        else
+            sprintf(retval, "%s%susers%s%s", baseDir, dirsep, dirsep, str);
+
+        if (uname != NULL)
+            free(uname);
+    } /* else */
+
+    return(retval);
+} /* calculateUserDir */
+
+
 int PHYSFS_init(const char *argv0)
 {
     BAIL_IF_MACRO(initialized, ERR_IS_INITIALIZED, 0);
     BAIL_IF_MACRO(argv0 == NULL, ERR_INVALID_ARGUMENT, 0);
 
-    baseDir = calculateBaseDir();
+    baseDir = calculateBaseDir(argv0);
+    if (baseDir == NULL)
+        return(0);
+
+    userDir = calculateUserDir();
+    if (userDir == NULL)
+    {
+        free(baseDir);
+        baseDir = NULL;
+        return(0);
+    } /* if */
+
     initialized = 1;
     return(1);
 } /* PHYSFS_init */
@@ -137,9 +203,14 @@
 
 static void freeSearchDir(SearchDirInfo *sdi)
 {
-    assert(sdi != NULL);
+    FileHandleList *i;
 
-    /* !!! make sure all files in search dir are closed. */
+    assert(sdi != NULL);
+    for (i = openReadList; i != NULL; i = i->next)
+    {
+        BAIL_IF_MACRO(i->handle->dirReader == sdi->reader,
+                        ERR_FILES_OPEN_READ, 0);
+    } /* for */
 
     sdi->reader->close(sdi->reader);
     free(sdi->dirName);
@@ -147,11 +218,28 @@
 } /* freeSearchDir */
 
 
+static void closeFileHandleList(FileHandleList **list)
+{
+    FileHandleList *i;
+    FileHandleList *next = NULL;
+
+    for (i = *list; i != NULL; i = next)
+    {
+        next = i->next;
+        i->handle->close(i->handle);
+    } /* for */
+
+    *list = NULL;
+} /* closeAllFiles */
+
+
 static void freeSearchPath(void)
 {
     SearchDirInfo *i;
     SearchDirInfo *next = NULL;
 
+    closeFileHandleList(&openReadList);
+
     if (searchPath != NULL)
     {
         for (i = searchPath; i != NULL; i = next)
@@ -164,23 +252,26 @@
 } /* freeSearchPath */
 
 
-static void closeAllFiles(void)
-{
-} /* closeAllFiles */
-
-
 void PHYSFS_deinit(void)
 {
     BAIL_IF_MACRO(!initialized, ERR_NOT_INITIALIZED, 0);
 
-    closeAllFiles();
-
+    closeFileHandleList(&openWriteList);
     PHYSFS_setWriteDir(NULL);
     freeSearchPath();
     freeErrorMessages();
 
     if (baseDir != NULL)
+    {
         free(baseDir);
+        baseDir = NULL;
+    } /* if */
+
+    if (userDir != NULL)
+    {
+        free(userDir);
+        userDir = NULL;
+    } /* if */
 
     allowSymLinks = 0;
     initialized = 0;
@@ -224,40 +315,7 @@
 
 const char *PHYSFS_getUserDir(void)
 {
-    static char *retval = NULL;
-    const char *str = NULL;
-
-    if (retval != NULL)
-        return(retval);
-
-    str = __PHYSFS_platformGetUserDir();
-    if (str != NULL)
-        retval = str;
-    else
-    {
-        const char *dirsep = PHYSFS_getDirSeparator();
-        const char *uname;
-
-        str = getenv("HOME");  /* try a default. */
-        if (str != NULL)
-            retval = str;
-        else
-        {
-            uname = __PHYSFS_platformGetUserName();
-            str = (uname != NULL) ? uname : "default";
-            retval = malloc(strlen(baseDir) + strlen(str) +
-                            (strlen(dirsep) * 2) + 6);
-            if (retval == NULL)
-                retval = baseDir;  /* (*shrug*) */
-            else
-                sprintf(retval, "%s%susers%s%s", baseDir, dirsep, dirsep, uname);
-
-            if (uname != NULL)
-                free(uname);
-        } /* else */
-    } /* if */
-
-    return(baseDir);  /* just in case. */
+    return(userDir);   /* this is calculated in PHYSFS_init()... */
 } /* PHYSFS_getUserDir */
 
 
@@ -269,7 +327,7 @@
 
 int PHYSFS_setWriteDir(const char *newDir)
 {
-    BAIL_IF_MACRO(openWriteCount > 0, ERR_FILES_OPEN_WRITE, 0);
+    BAIL_IF_MACRO(openWriteList != NULL, ERR_FILES_OPEN_WRITE, 0);
 
     if (writeDir != NULL)
     {
@@ -291,6 +349,21 @@
 } /* PHYSFS_setWriteDir */
 
 
+static DirReader *getDirReader(const char *d)
+{
+    DirFunctions **i;
+
+    for (i = dirFunctions; *i != NULL; i++)
+    {
+        if ((*i)->isArchive(d))
+            return( (*i)->openArchive(d) );
+    } /* for */
+
+    __PHYSFS_setError(ERR_UNSUPPORTED_ARCHIVE);
+    return(NULL);
+} /* getDirReader */
+
+
 int PHYSFS_addToSearchPath(const char *newDir, int appendToPath)
 {
     char *str = NULL;
@@ -304,13 +377,15 @@
         return(0);
 
     sdi = (SearchDirInfo *) malloc(sizeof (SearchDirInfo));
+    if (sdi == NULL)
+        reader->close(reader);
     BAIL_IF_MACRO(sdi == NULL, ERR_OUT_OF_MEMORY, 0);
 
     sdi->dirName = (char *) malloc(strlen(newDir) + 1);
     if (sdi->dirName == NULL)
     {
         free(sdi);
-        freeReader(reader);
+        reader->close(reader);
         __PHYSFS_setError(ERR_OUT_OF_MEMORY);
         return(0);
     } /* if */
@@ -346,6 +421,7 @@
 {
     SearchDirInfo *i;
     SearchDirInfo *prev = NULL;
+    SearchDirInfo *next = NULL;
 
     BAIL_IF_MACRO(oldDir == NULL, ERR_INVALID_ARGUMENT, 0);
 
@@ -353,14 +429,15 @@
     {
         if (strcmp(i->dirName, oldDir) == 0)
         {
+            next = i->next;
+            if (!freeSearchDir(i))
+                return(0);
+
             if (prev == NULL)
-                searchPath = i->next;
+                searchPath = next;
             else
-                prev->next = i->next;
+                prev->next = next;
 
-            /* !!! make sure all files in search dir are closed. */
-
-            freeSearchDir(i);
             return(1);
         } /* if */
         prev = i;
@@ -409,55 +486,6 @@
 } /* PHYSFS_getSearchPath */
 
 
-/**
- * Helper function.
- *
- * Set up sane, default paths. The write path will be set to
- *  "userpath/.appName", which is created if it doesn't exist.
- *
- * The above is sufficient to make sure your program's configuration directory
- *  is separated from other clutter, and platform-independent. The period
- *  before "mygame" even hides the directory on Unix systems.
- *
- *  The search path will be:
- *
- *    - The Write Dir (created if it doesn't exist)
- *    - The Write Dir/appName (created if it doesn't exist)
- *    - The Base Dir (PHYSFS_getBaseDir())
- *    - The Base Dir/appName (if it exists)
- *    - All found CD-ROM paths (optionally)
- *    - All found CD-ROM paths/appName (optionally, and if they exist)
- *
- * These directories are then searched for files ending with the extension
- *  (archiveExt), which, if they are valid and supported archives, will also
- *  be added to the search path. If you specified "PKG" for (archiveExt), and
- *  there's a file named data.PKG in the base dir, it'll be checked. Archives
- *  can either be appended or prepended to the search path in alphabetical
- *  order, regardless of which directories they were found in.
- *
- * All of this can be accomplished from the application, but this just does it
- *  all for you. Feel free to add more to the search path manually, too.
- *
- *    @param appName Program-specific name of your program, to separate it
- *                   from other programs using PhysicsFS.
- *
- *    @param archiveExt File extention used by your program to specify an
- *                      archive. For example, Quake 3 uses "pk3", even though
- *                      they are just zipfiles. Specify NULL to not dig out
- *                      archives automatically.
- *
- *    @param includeCdRoms Non-zero to include CD-ROMs in the search path, and
- *                         (if (archiveExt) != NULL) search them for archives.
- *                         This may cause a significant amount of blocking
- *                         while discs are accessed, and if there are no discs
- *                         in the drive (or even not mounted on Unix systems),
- *                         then they may not be made available anyhow. You may
- *                         want to specify zero and handle the disc setup
- *                         yourself.
- *
- *    @param archivesFirst Non-zero to prepend the archives to the search path.
- *                          Zero to append them. Ignored if !(archiveExt).
- */
 int PHYSFS_setSaneConfig(const char *appName, const char *archiveExt,
                          int includeCdRoms, int archivesFirst)
 {
@@ -644,7 +672,6 @@
     free(str);
 
     rc = (rc == 0);
-
     if (!rc)
         __PHYSFS_setError(strerror(errno));
 
@@ -780,12 +807,37 @@
 int PHYSFS_close(PHYSFS_file *handle)
 {
     FileHandle *h = (FileHandle *) handle->opaque;
+    FileHandleList *i;
+    FileHandleList **lists[] = { &openWriteList, &openReadList, NULL };
+    int rc;
+
     assert(h != NULL);
-    BAIL_IF_MACRO(h->close == NULL, ERR_NOT_SUPPORTED, -1);
-    rc = h->close(h);
-    if (rc)
-        free(handle);
-    return(rc);
+    assert(h->funcs != NULL);
+    assert(h->funcs->close != NULL);
+
+    while (lists != NULL)
+    {
+        for (i = *(*lists); i != NULL; i = i->next)
+        {
+            if (i->handle == h)
+            {
+                rc = h->close(h);
+                if (!rc)
+                    return(0);
+
+                if (prev == NULL)
+                    *lists = i->next;
+                else
+                    prev->next = i->next;
+                free(i);
+                free(handle);
+                return(1);
+            } /* if */
+        } /* for */
+        lists++;
+    } /* while */
+
+    assert(0);  /* shouldn't EVER hit this. */
 } /* PHYSFS_close */
 
 
@@ -794,8 +846,9 @@
 {
     FileHandle *h = (FileHandle *) handle->opaque;
     assert(h != NULL);
-    BAIL_IF_MACRO(h->read == NULL, ERR_NOT_SUPPORTED, -1);
-    return(h->read(h, buffer, objSize, objCount));
+    assert(h->funcs != NULL);
+    BAIL_IF_MACRO(h->funcs->read == NULL, ERR_NOT_SUPPORTED, -1);
+    return(h->funcs->read(h, buffer, objSize, objCount));
 } /* PHYSFS_read */
 
 
@@ -804,8 +857,9 @@
 {
     FileHandle *h = (FileHandle *) handle->opaque;
     assert(h != NULL);
-    BAIL_IF_MACRO(h->write == NULL, ERR_NOT_SUPPORTED, -1);
-    return(h->write(h, buffer, objSize, objCount));
+    assert(h->funcs != NULL);
+    BAIL_IF_MACRO(h->funcs->write == NULL, ERR_NOT_SUPPORTED, -1);
+    return(h->funcs->write(h, buffer, objSize, objCount));
 } /* PHYSFS_write */
 
 
@@ -813,8 +867,9 @@
 {
     FileHandle *h = (FileHandle *) handle->opaque;
     assert(h != NULL);
-    BAIL_IF_MACRO(h->eof == NULL, ERR_NOT_SUPPORTED, -1);
-    return(h->eof(h));
+    assert(h->funcs != NULL);
+    BAIL_IF_MACRO(h->funcs->eof == NULL, ERR_NOT_SUPPORTED, -1);
+    return(h->funcs->eof(h));
 } /* PHYSFS_eof */
 
 
@@ -822,8 +877,9 @@
 {
     FileHandle *h = (FileHandle *) handle->opaque;
     assert(h != NULL);
-    BAIL_IF_MACRO(h->tell == NULL, ERR_NOT_SUPPORTED, -1);
-    return(h->tell(h));
+    assert(h->funcs != NULL);
+    BAIL_IF_MACRO(h->funcs->tell == NULL, ERR_NOT_SUPPORTED, -1);
+    return(h->funcs->tell(h));
 } /* PHYSFS_tell */
 
 
@@ -831,8 +887,9 @@
 {
     FileHandle *h = (FileHandle *) handle->opaque;
     assert(h != NULL);
-    BAIL_IF_MACRO(h->seek == NULL, ERR_NOT_SUPPORTED, 0);
-    return(h->seek(h, pos));
+    assert(h->funcs != NULL);
+    BAIL_IF_MACRO(h->funcs->seek == NULL, ERR_NOT_SUPPORTED, 0);
+    return(h->funcs->seek(h, pos));
 } /* PHYSFS_seek */
 
 /* end of physfs.c ... */
--- a/physfs_internal.h	Fri Jul 06 02:33:21 2001 +0000
+++ b/physfs_internal.h	Fri Jul 06 08:47:23 2001 +0000
@@ -15,6 +15,7 @@
 #endif
 
 struct __PHYSFS_DIRREADER__;
+struct __PHYSFS_FILEFUNCTIONS__;
 
 typedef struct __PHYSFS_FILEHANDLE__
 {
@@ -24,44 +25,53 @@
     void *opaque;
 
         /*
-         * This should be the DirReader that created this FileHandle.
+         * This should be the DirHandle that created this FileHandle.
+         */
+    const struct __PHYSFS_DIRREADER__ *dirReader;
+
+        /*
+         * Pointer to the file i/o functions for this filehandle.
          */
-    struct __PHYSFS_DIRREADER__ *dirReader;
+    const struct __PHYSFS_FILEFUNCTIONS__ *funcs;
+} FileHandle;
 
+
+typedef struct __PHYSFS_FILEFUNCTIONS__
+{
         /*
          * Read more from the file.
          */
-    int (*read)(struct __PHYSFS_FILEHANDLE__ *handle, void *buffer,
+    int (*read)(FileHandle *handle, void *buffer,
                 unsigned int objSize, unsigned int objCount);
 
         /*
          * Write more to the file. Archives don't have to implement this.
          *  (Set it to NULL if not implemented).
          */
-    int (*write)(struct __PHYSFS_FILEHANDLE__ *handle, void *buffer,
+    int (*write)(FileHandle *handle, void *buffer,
                  unsigned int objSize, unsigned int objCount);
 
         /*
          * Returns non-zero if at end of file.
          */
-    int (*eof)(struct __PHYSFS_FILEHANDLE__ *handle);
+    int (*eof)(FileHandle *handle);
 
         /*
          * Returns byte offset from start of file.
          */
-    int (*tell)(struct __PHYSFS_FILEHANDLE__ *handle);
+    int (*tell)(FileHandle *handle);
 
         /*
          * Move read/write pointer to byte offset from start of file.
          *  Returns non-zero on success, zero on error.
          */
-    int (*seek)(struct __PHYSFS_FILEHANDLE__ *handle, int offset);
+    int (*seek)(FileHandle *handle, int offset);
 
         /*
-         * Close the file, and free this structure (including "opaque").
+         * Close the file, and free the FileHandle structure (including "opaque").
          */
-    int (*close)(void);
-} FileHandle;
+    int (*close)(FileHandle *handle);
+} FileFunctions;
 
 
 typedef struct __PHYSFS_DIRREADER__
@@ -72,53 +82,98 @@
     void *opaque;
 
         /*
+         * Pointer to the directory i/o functions for this reader.
+         */
+    const struct __PHYSFS_DIRFUNCTIONS__ *funcs;
+} DirHandle;
+
+
+/*
+ * Symlinks should always be followed; PhysicsFS will use
+ *  DirFunctions->isSymLink() and make a judgement on whether to
+ *  continue to call other methods based on that.
+ */
+typedef struct __PHYSFS_DIRFUNCTIONS__
+{
+        /*
+         * Returns non-zero if (filename) is a valid archive that this
+         *  driver can handle. This filename is in platform-dependent
+         *  notation.
+         */
+    int (*isArchive)(const char *filename);
+
+        /*
+         * Return a DirHandle for dir/archive (name).
+         *  This filename is in platform-dependent notation.
+         *  return (NULL) on error.
+         */
+    DirHandle *(*openArchive)(const char *name);
+
+        /*
          * Returns a list (freeable via PHYSFS_freeList()) of
          *  all files in dirname.
-         *  Symlinks should be followed.
+         *  This dirname is in platform-independent notation.
          */
-    char **(*enumerateFiles)(struct __PHYSFS_DIRREADER__ *r, const char *dirname);
+    char **(*enumerateFiles)(DirHandle *r, const char *dirname);
 
         /*
          * Returns non-zero if filename is really a directory.
-         *  Symlinks should be followed.
+         *  This filename is in platform-independent notation.
          */
-    int (*isDirectory)(struct __PHYSFS_DIRREADER__ *r, const char *name);
+    int (*isDirectory)(DirHandle *r, const char *name);
 
         /*
          * Returns non-zero if filename is really a symlink.
+         *  This filename is in platform-independent notation.
          */
-    int (*isSymLink)(struct __PHYSFS_DIRREADER__ *r, const char *name);
+    int (*isSymLink)(DirHandle *r, const char *name);
 
         /*
          * Returns non-zero if filename can be opened for reading.
-         *  Symlinks should be followed.
+         *  This filename is in platform-independent notation.
          */
-    int (*isOpenable)(struct __PHYSFS_DIRREADER__ *r, const char *name);
+    int (*isOpenable)(DirHandle *r, const char *name);
 
         /*
          * Open file for reading, and return a FileHandle.
-         *  Symlinks should be followed.
+         *  This filename is in platform-independent notation.
          */
-    FileHandle *(*openRead)(struct __PHYSFS_DIRREADER__ *r, const char *filename);
+    FileHandle *(*openRead)(DirHandle *r, const char *filename);
+
+        /*
+         * Open file for writing, and return a FileHandle.
+         *  This filename is in platform-independent notation.
+         *  This method may be NULL.
+         */
+    FileHandle *(*openWrite)(DirHandle *r, const char *filename);
 
         /*
-         * Close directories/archives, and free this structure, including
+         * Open file for appending, and return a FileHandle.
+         *  This filename is in platform-independent notation.
+         *  This method may be NULL.
+         */
+    FileHandle *(*openAppend)(DirHandle *r, const char *filename);
+
+        /*
+         * Close directories/archives, and free the handle, including
          *  the "opaque" entry. This should assume that it won't be called if
-         *  there are still files open from this DirReader.
+         *  there are still files open from this DirHandle.
          */
-    void (*close)(struct __PHYSFS_DIRREADER__ *r);
-} DirReader;
+    void (*close)(DirHandle *r);
+} DirFunctions;
 
 
 /* error messages... */
 #define ERR_IS_INITIALIZED       "Already initialized"
 #define ERR_NOT_INITIALIZED      "Not initialized"
 #define ERR_INVALID_ARGUMENT     "Invalid argument"
+#define ERR_FILES_OPEN_READ      "Files still open for reading"
 #define ERR_FILES_OPEN_WRITE     "Files still open for writing"
 #define ERR_NO_DIR_CREATE        "Failed to create directories"
 #define ERR_OUT_OF_MEMORY        "Out of memory"
 #define ERR_NOT_IN_SEARCH_PATH   "No such entry in search path"
 #define ERR_NOT_SUPPORTED        "Operation not supported"
+#define ERR_UNSUPPORTED_ARCHIVE  "Archive type unsupported"
 
 
 /*
@@ -193,6 +248,11 @@
  */
 int __PHYSFS_platformStricmp(const char *str1, const char *str2);
 
+/*
+ * Return non-zero if filename (in platform-dependent notation) is a symlink.
+ */
+int __PHYSFS_platformIsSymlink(const char *fname);
+
 
 #ifdef __cplusplus
 extern "C" {
--- a/unix.c	Fri Jul 06 02:33:21 2001 +0000
+++ b/unix.c	Fri Jul 06 08:47:23 2001 +0000
@@ -38,5 +38,21 @@
     return(strcasecmp(str1, str2));
 } /* __PHYSFS_platformStricmp */
 
+
+int __PHYSFS_platformIsSymlink(const char *fname)
+{
+} /* __PHYSFS_platformIsSymlink */
+
+
+char *__PHYSFS_platformGetUserName(void)
+{
+} /* __PHYSFS_platformGetUserName */
+
+
+char *__PHYSFS_platformGetUserDir(void);
+{
+} /* __PHYSFS_platformGetUserDir */
+
+
 /* end of unix.c ... */
 
--- a/zip.c	Fri Jul 06 02:33:21 2001 +0000
+++ b/zip.c	Fri Jul 06 08:47:23 2001 +0000
@@ -12,11 +12,13 @@
 #define __PHYSICSFS_INTERNAL__
 #include "physfs_internal.h"
 
-/* template for filehandles. */
-const FileHandle __PHYSFS_FileHandle_ZIP =
+#if (!defined PHYSFS_SUPPORTS_ZIP)
+#error PHYSFS_SUPPORTS_ZIP must be defined.
+#endif
+
+
+static const FileFunctions __PHYSFS_FileHandle_ZIP =
 {
-    NULL,       /* opaque         */
-    NULL,       /* dirReader      */
     ZIP_read,   /* read() method  */
     NULL,       /* write() method */
     ZIP_eof,    /* eof() method   */
@@ -25,15 +27,17 @@
     ZIP_close,  /* close() method */
 };
 
-/* template for directories. */
-const DirReader __PHYSFS_DirReader_ZIP =
+
+const DirFunctions __PHYSFS_DirFunctions_ZIP =
 {
-    NULL,              /* opaque                  */
+    ZIP_isArchive,     /* isArchive() method      */
+    ZIP_openArchive,   /* openArchive() method    */
     ZIP_enumerate,     /* enumerateFiles() method */
     ZIP_isDirectory,   /* isDirectory() method    */
     ZIP_isSymLink,     /* isSymLink() method      */
     ZIP_isOpenable,    /* isOpenable() method     */
     ZIP_openRead,      /* openRead() method       */
+    NULL,              /* openWrite() method      */
     ZIP_dirClose,      /* close() method          */
 };