Added a simple unpacker example.
authorRyan C. Gordon <icculus@icculus.org>
Sat, 31 Mar 2007 06:34:51 +0000
changeset 868 87ea5fcab4e9
parent 867 ff3343429cb5
child 869 1c0138d6ce45
Added a simple unpacker example.
CHANGELOG.txt
extras/physfsunpack.c
--- a/CHANGELOG.txt	Thu Mar 29 05:39:16 2007 +0000
+++ b/CHANGELOG.txt	Sat Mar 31 06:34:51 2007 +0000
@@ -2,6 +2,7 @@
  * CHANGELOG.
  */
 
+03312007 - Added a quick'n'dirty unpack utility to the extras directory.
 03282007 - Logic bug in MVL/HOG/GRP archivers: only enumerated files when
            looking in a directory other than the root, instead of enumerating
            only for the root (thanks, Chris!). Minor fix for compilers that
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/extras/physfsunpack.c	Sat Mar 31 06:34:51 2007 +0000
@@ -0,0 +1,181 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "physfs.h"
+
+
+static int failure = 0;
+
+static void modTimeToStr(PHYSFS_sint64 modtime, char *modstr, size_t strsize)
+{
+    const char *str = "unknown modtime";
+    if (modtime != -1)
+    {
+        time_t t = (time_t) modtime;
+        str = ctime(&t);
+    } /* if */
+
+    strncpy(modstr, str, strsize);
+    modstr[strsize-1] = '\0';
+    strsize = strlen(modstr);
+    while ((modstr[strsize-1] == '\n') || (modstr[strsize-1] == '\r'))
+        modstr[--strsize] = '\0';
+} /* modTimeToStr */
+
+
+static void fail(const char *what, const char *why)
+{
+    if (why == NULL)
+        why = PHYSFS_getLastError();
+    fprintf(stderr, "%s failed: %s\n", what, why);
+    failure = 1;
+} /* fail */
+
+
+static void dumpFile(const char *fname)
+{
+    const int origfailure = failure;
+    PHYSFS_File *out = NULL;
+    PHYSFS_File *in = NULL;
+
+    failure = 0;
+
+    if ((in = PHYSFS_openRead(fname)) == NULL)
+        fail("\nPHYSFS_openRead", NULL);
+    else if ((out = PHYSFS_openWrite(fname)) == NULL)
+        fail("\nPHYSFS_openWrite", NULL);
+    else
+    {
+        char modstr[64];
+        PHYSFS_sint64 size = PHYSFS_fileLength(in);
+
+        printf("(");
+        if (size == -1)
+            printf("?");
+        else
+            printf("%lld", (long long) size);
+        printf(" bytes");
+
+        modTimeToStr(PHYSFS_getLastModTime(fname), modstr, sizeof (modstr));
+        printf(", %s)\n", modstr);
+
+        while ( (!failure) && (!PHYSFS_eof(in)) )
+        {
+            static char buf[64 * 1024];
+            PHYSFS_sint64 br = PHYSFS_read(in, buf, 1, sizeof (buf));
+            if (br == -1)
+                fail("PHYSFS_read", NULL);
+            else
+            {
+                PHYSFS_sint64 bw = PHYSFS_write(out, buf, 1, br);
+                if (bw != br)
+                    fail("PHYSFS_write", NULL);
+                else
+                    size -= bw;
+            } /* else */
+        } /* while */
+
+        if ((!failure) && (size != 0))
+            fail("PHYSFS_eof", "BUG! eof != PHYSFS_fileLength bytes!");
+    } /* else */
+
+    if (in != NULL)
+        PHYSFS_close(in);
+
+    if (out != NULL)
+    {
+        if (!PHYSFS_close(out))
+            fail("PHYSFS_close", NULL);
+    } /* if */
+
+    if (failure)
+        PHYSFS_delete(fname);
+    else
+        failure = origfailure;
+} /* dumpFile */
+
+
+static void unpackCallback(void *_depth, const char *origdir, const char *str)
+{
+    int depth = *((int *) _depth);
+    const int len = strlen(origdir) + strlen(str) + 2;
+    char *fname = (char *) malloc(len);
+    if (fname == NULL)
+        fail("malloc", "Out of memory!");
+    else
+    {
+        if (strcmp(origdir, "/") == 0)
+            origdir = "";
+
+        snprintf(fname, len, "%s/%s", origdir, str);
+
+        printf("%s ", fname);
+        if (PHYSFS_isDirectory(fname))
+        {
+            depth++;
+            printf("(directory)\n");
+            if (!PHYSFS_mkdir(fname))
+                fail("PHYSFS_mkdir", NULL);
+            else
+                PHYSFS_enumerateFilesCallback(fname, unpackCallback, &depth);
+        } /* if */
+
+        else if (PHYSFS_isSymbolicLink(fname))
+        {
+            printf("(symlink)\n");
+            /* !!! FIXME: ?  if (!symlink(fname, */
+        } /* else if */
+
+        else  /* ...file. */
+        {
+            dumpFile(fname);
+        } /* else */
+
+        free(fname);
+    } /* else */
+} /* unpackCallback */
+
+
+int main(int argc, char **argv)
+{
+    int zero = 0;
+
+    if (argc != 3)
+    {
+        fprintf(stderr, "USAGE: %s <archive> <unpackDirectory>\n", argv[0]);
+        return 1;
+    } /* if */
+
+    if (!PHYSFS_init(argv[0]))
+    {
+        fprintf(stderr, "PHYSFS_init() failed: %s\n", PHYSFS_getLastError());
+        return 2;
+    } /* if */
+
+    if (!PHYSFS_setWriteDir(argv[2]))
+    {
+        fprintf(stderr, "PHYSFS_setWriteDir('%s') failed: %s\n",
+                argv[2], PHYSFS_getLastError());
+        return 3;
+    } /* if */
+
+    if (!PHYSFS_mount(argv[1], NULL, 1))
+    {
+        fprintf(stderr, "PHYSFS_mount('%s') failed: %s\n",
+                argv[1], PHYSFS_getLastError());
+        return 4;
+    } /* if */
+
+    PHYSFS_permitSymbolicLinks(1);
+    PHYSFS_enumerateFilesCallback("/", unpackCallback, &zero);
+    PHYSFS_deinit();
+    if (failure)
+        return 5;
+
+    return 0;
+} /* main */
+
+/* end of physfsunpack.c ... */
+