view 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 source

/*
 * 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;
}