Mercurial > hg > dmlib
view packed.c @ 495:30145d17aebd
Move certain editor related targets to the actual TARGETS variable, and
remove them from being separately specified in the "make clean" target,
thusly cleaning them only when editor is enabled in build configuration.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Fri, 16 Nov 2012 19:18:03 +0200 |
parents | ec70ae5aaa1a |
children |
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 "dmres.h" #include "dmmutex.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] [-p <packfilename>] [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 (%d) 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:%d]\n", filename, res); } else { char tmp[16]; dmres_flags_to_symbolic(tmp, sizeof(tmp), node->resFlags); dmPrint(1, "%-32s ['%s', s=%d, c=%d, o=%ld, f=%s]\n", filename, node->filename, node->size, node->length, node->offset, tmp); } return res; } int main(int argc, char *argv[]) { int i, res = 0; DMPackFile *pack = NULL; #ifndef __WIN32 stderr = stdout; #endif // 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=%d\n", dm_pack_write(pack)); dmMsg(1, "c=%d\n", dm_pack_close(pack)); } else { dmError("Could not open packfile, error #%d: %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); dmPrint(0, "%-32s | %8s | %8s | %8s | %s\n", "Name", "Size", "CSize", "Offset", "ResFlags"); 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) { char flags[16]; dmres_flags_to_symbolic(flags, sizeof(flags), node->resFlags); dmPrint(0, "%-32s | %8d | %8d | %08x | %s\n", node->filename, node->size, node->length, node->offset, flags); } } dmMsg(1, "c=%d\n", dm_pack_close(pack)); } else dmError("Could not open packfile, error #%d: %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' #%d: %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) { char tmp[16]; // Mark as done node->privFlags |= PACK_EXTRACTED; // Print one entry dmres_flags_to_symbolic(tmp, sizeof(tmp), node->resFlags); dmPrint(0, "Extracting: %-32s [siz=%d, cmp=%d, offs=0x%08x, flags=%s]\n", node->filename, node->size, node->length, node->offset, tmp); dm_pack_extract_file(pack, node); if (resFile != NULL) { fprintf(resFile, "%s|%s\n", node->filename, tmp); } } } dmMsg(1, "c=%d\n", dm_pack_close(pack)); if (resFile != NULL) fclose(resFile); } else dmError("Could not open packfile, error #%d: %s\n", res, dmErrorStr(res)); break; } return 0; }