diff packed.c @ 0:32250b436bca

Initial re-import.
author Matti Hamalainen <ccr@tnsp.org>
date Fri, 28 Sep 2012 01:54:23 +0300
parents
children 7ad2c6b57932
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/packed.c	Fri Sep 28 01:54:23 2012 +0300
@@ -0,0 +1,451 @@
+/*
+ * PACKed - PACKfile EDitor
+ * Programmed and designed by Matti 'ccr' Hamalainen
+ * (C) Copyright 2011 Tecnic Software productions (TNSP)
+ */
+#include "dmlib.h"
+#include "dmargs.h"
+#include "dmpack.h"
+#include "dmpackutil.h"
+#include <errno.h>
+
+#define	SET_MAX_FILES	  (4096)
+#define SET_DEFAULT_PACK  "data.pak"
+
+enum
+{
+    CMD_NONE = 0,
+    CMD_CREATE,
+    CMD_ADD,
+    CMD_LIST,
+    CMD_EXTRACT
+} DCOMMAND;
+
+enum
+{
+    PACK_EXTRACTED = 0x0001,
+};
+
+int    nsrcFilenames = 0;
+char * srcFilenames[SET_MAX_FILES];
+char * optPackFilename = NULL;
+BOOL   optCompress = TRUE;
+int    optCommand = CMD_NONE;
+int    optDefResFlags = 0;
+
+
+static DMOptArg optList[] =
+{
+    { 0, '?', "help",        "Show this help", OPT_NONE },
+    { 1, 'p', "pack",        "Set pack filename (default: " SET_DEFAULT_PACK ")", OPT_ARGREQ },
+    { 2, 'c', "create",      "Create and add files to PACK", OPT_NONE },
+    { 3, 'a', "add",         "Add files to PACK", OPT_NONE },
+    { 4, 'l', "list",        "List files in PACK", OPT_NONE },
+    { 5, 'e', "extract",     "Extract files from PACK", OPT_NONE },
+    { 6, 'n', "nocompress",  "No compression", OPT_NONE },
+    { 7, 'v', "verbose",     "Increase verbosity", OPT_NONE },
+    { 8, 'f', "resflags",    "Set default resource flags (-f 0xff)", OPT_ARGREQ },
+};
+
+static const int optListN = sizeof(optList) / sizeof(optList[0]);
+
+
+void argShowHelp()
+{
+    dmPrintBanner(stdout, dmProgName, "[options] <packfile> [filename[s]]");
+    dmArgsPrintHelp(stdout, optList, optListN);
+    fprintf(stdout,
+    "\n"
+    "Examples:\n"
+    "$ %s -p test.pak -l         -- list files in test.pak\n"
+    "$ %s -a foobar.jpg          -- add foobar.jpg in " SET_DEFAULT_PACK "\n"
+    "$ %s -x foobar.jpg          -- extract foobar.jpg from " SET_DEFAULT_PACK "\n",
+    dmProgName, dmProgName, dmProgName);
+}
+
+
+BOOL argHandleOpt(const int optN, char *optArg, char *currArg)
+{
+    (void) optArg;
+    switch (optN)
+    {
+    case 0:
+        argShowHelp();
+        exit(0);
+        break;
+
+    case 1:
+        optPackFilename = optArg;
+        break;
+    case 2:
+        optCommand = CMD_CREATE;
+        break;
+    case 3:
+        optCommand = CMD_ADD;
+        break;
+    case 4:
+        optCommand = CMD_LIST;
+        break;
+    case 5:
+        optCommand = CMD_EXTRACT;
+        break;
+
+    case 6:
+        optCompress = FALSE;
+        break;
+
+    case 7:
+        dmVerbosity++;
+        break;
+
+    case 8:
+        {
+            int i;
+            if (!dmGetIntVal(optArg, &i))
+            {
+                dmError("Invalid flags value '%s'.\n", optArg);
+                return FALSE;
+            }
+            optDefResFlags = i;
+        }
+        break;
+
+    default:
+        dmError("Unknown argument '%s'.\n", currArg);
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+
+BOOL argHandleFile(char *currArg)
+{
+    if (nsrcFilenames < SET_MAX_FILES)
+    {
+        srcFilenames[nsrcFilenames] = currArg;
+        nsrcFilenames++;
+    }
+    else
+    {
+        dmError("Maximum number of input files (%i) exceeded!\n",
+              SET_MAX_FILES);
+        return FALSE;
+    }
+    return TRUE;
+}
+
+
+/* Compare a string to a pattern. Case-SENSITIVE version.
+ * The matching pattern can consist of any normal characters plus
+ * wildcards ? and *. "?" matches any character and "*" matches
+ * any number of characters.
+ */
+BOOL dm_strmatch(const char *str, const char *pattern)
+{
+    BOOL didMatch = TRUE, isAnyMode = FALSE, isEnd = FALSE;
+    const char *tmpPattern = NULL;
+
+    // Check given pattern and string
+    if (str == NULL || pattern == NULL)
+        return FALSE;
+
+    // Start comparision
+    do {
+        didMatch = FALSE;
+        switch (*pattern)
+        {
+        case '?':
+            // Any single character matches
+            if (*str)
+            {
+                didMatch = TRUE;
+                pattern++;
+                str++;
+            }
+            break;
+
+        case '*':
+            didMatch = TRUE;
+            pattern++;
+            if (!*pattern)
+                isEnd = TRUE;
+            isAnyMode = TRUE;
+            tmpPattern = pattern;
+            break;
+
+        case 0:
+            if (isAnyMode)
+            {
+                if (*str)
+                    str++;
+                else
+                    isEnd = TRUE;
+            }
+            else
+            {
+                if (*str)
+                {
+                    if (tmpPattern)
+                    {
+                        isAnyMode = TRUE;
+                        pattern = tmpPattern;
+                    }
+                    else
+                        didMatch = FALSE;
+                }
+                else
+                    isEnd = TRUE;
+            }
+            break;
+        default:
+            if (isAnyMode)
+            {
+                if (*pattern == *str)
+                {
+                    isAnyMode = FALSE;
+                    didMatch = TRUE;
+                }
+                else
+                {
+                    if (*str)
+                    {
+                        didMatch = TRUE;
+                        str++;
+                    }
+                }
+            }
+            else
+            {
+                if (*pattern == *str)
+                {
+                    didMatch = TRUE;
+                    if (*pattern)
+                        pattern++;
+                    if (*str)
+                        str++;
+                }
+                else
+                {
+                    if (tmpPattern)
+                    {
+                        didMatch = TRUE;
+                        isAnyMode = TRUE;
+                        pattern = tmpPattern;
+                    }
+                }
+            }
+
+            if (!*str && !*pattern)
+                isEnd = TRUE;
+            break;
+
+        }        // switch
+
+    } while (didMatch && !isEnd);
+
+    return didMatch;
+}
+
+
+int dmAddFileToPack(DMPackFile *pack, const char *filename, int compression, int resFlags)
+{
+    DMPackEntry *node;
+    int res = dm_pack_add_file(pack, filename, compression, resFlags, &node);
+
+    if (res != DMERR_OK)
+    {
+        dmPrint(1, "%-32s [ERROR:%i]\n",
+            filename, res);
+    }
+    else
+    {
+        dmPrint(1, "%-32s ['%s', s=%d, c=%d, o=%ld, f=0x%04x]\n",
+            filename, node->filename,
+            node->size, node->length, node->offset,
+            node->resFlags);
+    }
+
+    return res;
+}
+
+
+int main(int argc, char *argv[])
+{
+    int i, res = 0;
+    DMPackFile *pack = NULL;
+
+    stderr = stdout;
+
+    // Parse arguments
+    dmInitProg("packed", "Pack File Editor", "0.4", NULL, NULL);
+    dmVerbosity = 1;
+    
+    if (!dmArgsProcess(argc, argv, optList, optListN,
+        argHandleOpt, argHandleFile, TRUE))
+        exit(1);
+
+    // Check PACK filename
+    if (optPackFilename == NULL)
+        optPackFilename = SET_DEFAULT_PACK;
+
+    if (optCommand == CMD_NONE)
+    {
+        argShowHelp();
+        dmError("Nothing to do.\n");
+        exit(0);
+        return 0;
+    }
+    
+    dmMsg(1, "Processing %s ...\n", optPackFilename);
+
+    // Execute command
+    switch (optCommand)
+    {
+    case CMD_CREATE:
+    case CMD_ADD:
+        switch (optCommand)
+        {
+        case CMD_CREATE:
+            dmMsg(1, "Creating new PACK\n");
+            res = dm_pack_create(optPackFilename, &pack);
+            break;
+
+        case CMD_ADD:
+            dmMsg(1, "Opening existing PACK\n");
+            res = dm_pack_open(optPackFilename, &pack, FALSE);
+            break;
+        }
+
+        // Add files into PACK
+        if (res == DMERR_OK)
+        {
+            dmMsg(1, "Adding %d files...\n", nsrcFilenames);
+
+            for (i = 0; i < nsrcFilenames; i++)
+            {
+                // Handle resource definition files
+                if (srcFilenames[i][0] == '@')
+                {
+                }
+                else
+                {
+                    dmAddFileToPack(pack, srcFilenames[i], optCompress, optDefResFlags);
+                }
+            }
+
+            dmMsg(1, "w=%i\n", dm_pack_write(pack));
+            dmMsg(1, "c=%i\n", dm_pack_close(pack));
+        }
+        else
+        {
+            dmError("Could not open packfile, error #%i: %s\n", res,
+                  dmErrorStr(res));
+        }
+        break;
+
+    case CMD_LIST:
+        // List files in PACK
+        res = dm_pack_open(optPackFilename, &pack, TRUE);
+        if (res == DMERR_OK)
+        {
+            DMPackEntry *node;
+            for (i = 0, node = pack->entries; node; i++)
+                node = node->next;
+            dmMsg(1, "%d files total\n", i);
+
+            for (node = pack->entries; node != NULL; node = node->next)
+            {
+                BOOL match;
+                
+                // Check for matches
+                if (nsrcFilenames > 0)
+                {
+                    match = FALSE;
+                    for (i = 0; i < nsrcFilenames && !match; i++)
+                    {
+                        match = dm_strmatch(node->filename, srcFilenames[i]);
+                    }
+                }
+                else
+                    match = TRUE;
+
+                if (match)
+                {
+                    // Print one entry
+                    dmPrint(0, "Extracting: %-32s [siz=%d, cmp=%d, offs=0x%08x, flags=0x%04x]\n",
+                            node->filename, node->size, node->length,
+                            node->offset, node->resFlags);
+                }
+            }
+
+            dmMsg(1, "c=%i\n", dm_pack_close(pack));
+        }
+        else
+            dmError("Could not open packfile, error #%i: %s\n", res,
+                  dmErrorStr(res));
+        break;
+
+    case CMD_EXTRACT:
+        // Extract files from PACK
+        res = dm_pack_open(optPackFilename, &pack, TRUE);
+        if (res == DMERR_OK)
+        {
+            DMPackEntry *node;
+            FILE *resFile = fopen(DMRES_RES_FILE, "w");
+            if (resFile == NULL)
+            {
+                dmError("Could not create resource output file '%s' #%i: %s\n",
+                    DMRES_RES_FILE, errno, strerror(errno));
+            }
+
+            for (node = pack->entries; node != NULL; node = node->next)
+            {
+                BOOL match;
+                
+                // Check for matches
+                if (nsrcFilenames > 0)
+                {
+                    match = FALSE;
+                    for (i = 0; (i < nsrcFilenames) && !match; i++)
+                    {
+                        match = dm_strmatch(node->filename, srcFilenames[i]);
+                    }
+                }
+                else
+                    match = TRUE;
+
+                if (match && (node->privFlags & PACK_EXTRACTED) == 0)
+                {
+                    // Mark as done
+                    node->privFlags |= PACK_EXTRACTED;
+
+                    // Print one entry
+                    dmPrint(0, "Extracting: %-32s [siz=%d, cmp=%d, offs=0x%08x, flags=0x%04x]\n",
+                            node->filename, node->size, node->length,
+                            node->offset, node->resFlags);
+
+                    dm_pack_extract_file(pack, node);
+                    
+                    if (resFile != NULL)
+                    {
+                        fprintf(resFile,
+                        "%s|%04x", node->filename, node->resFlags);
+                    }
+                }
+            }
+
+            dmMsg(1, "c=%i\n", dm_pack_close(pack));
+            
+            if (resFile != NULL)
+                fclose(resFile);
+        }
+        else
+            dmError("Could not open packfile, error #%i: %s\n", res,
+                  dmErrorStr(res));
+        break;
+
+    }
+
+    return 0;
+}