Rewrite archive utility (command line parsing, C++)master
authorThomas Perl <m@thp.io>
Sun, 28 Jul 2013 02:47:52 +0000 (28 04:47 +0200)
committerThomas Perl <m@thp.io>
Sun, 28 Jul 2013 02:47:52 +0000 (28 04:47 +0200)
makefile
src/archive.cc
src/archive.h
src/archivetool.cc

index 7d1891d..e478d6c 100644 (file)
--- a/makefile
+++ b/makefile
@@ -37,13 +37,10 @@ TENNIX_OBJ += src/tennix.o src/game.o src/graphics.o src/input.o
 TENNIX_OBJ += src/util.o src/sound.o src/animation.o src/archive.o
 TENNIX_OBJ += src/SDL_rotozoom.o src/network.o src/tennixpy.o
 
-# Object files for "archive"
-ARCHIVE_BIN := archive
+# Object files for "tnxar"
+ARCHIVE_BIN := tnxar
 ARCHIVE_OBJ += src/archivetool.o src/archive.o
 
-# Target filename for "dump"
-DUMP_BIN := dump
-
 # Data files for tennix.tnx
 TENNIX_TNX := tennix.tnx
 TENNIX_TNX_DATA += $(wildcard data/*.ogg)
@@ -63,7 +60,7 @@ TENNIX_PNG := data/tennix.png
 TENNIX_DESKTOP := data/tennix.desktop
 TENNIX_MAN := data/tennix.6
 
-all: $(TENNIX_BIN) $(ARCHIVE_BIN) $(DUMP_BIN) $(TENNIX_TNX)
+all: $(TENNIX_BIN) $(ARCHIVE_BIN) $(TENNIX_TNX)
 
 %.o: %.cc
        $(SILENTMSG) "  CXX     $@"
@@ -77,13 +74,9 @@ $(ARCHIVE_BIN): $(ARCHIVE_OBJ)
        $(SILENTMSG) "  LD      $@"
        $(SILENTCMD)$(CXX) -o $@ $^
 
-$(DUMP_BIN): $(ARCHIVE_BIN)
-       $(SILENTMSG) "  SYMLINK $@"
-       $(SILENTCMD)$(LN) -s $< $@
-
 $(TENNIX_TNX): $(ARCHIVE_BIN) $(TENNIX_TNX_DATA)
-       $(SILENTMSG) "  ARCHIVE $@"
-       $(SILENTCMD)./$(ARCHIVE_BIN) $@ $(TENNIX_TNX_DATA)
+       $(SILENTMSG) "  TNXAR   $@"
+       $(SILENTCMD)./$(ARCHIVE_BIN) -cf $@ $(TENNIX_TNX_DATA)
 
 install: $(TENNIX_BIN) $(TENNIX_TNX) $(TENNIX_PNG) $(TENNIX_DESKTOP) $(TENNIX_MAN)
        $(SILENTMSG) "  INSTALL $(TENNIX_BIN)"
@@ -106,7 +99,6 @@ clean:
        $(SILENTMSG) "  CLEAN"
        $(SILENTCMD)$(RM) -f $(TENNIX_BIN) $(TENNIX_OBJ)
        $(SILENTCMD)$(RM) -f $(ARCHIVE_BIN) $(ARCHIVE_OBJ)
-       $(SILENTCMD)$(RM) -f $(DUMP_BIN)
        $(SILENTCMD)$(RM) -f $(TENNIX_TNX)
 
 distclean: clean
index 962a950..921d1df 100644 (file)
 
 #include "archive.h"
 
+static void
+xormem(char* mem, uint32_t length, char key)
+{
+   char *i = mem, *end = mem+length;
+   for(; i != end; i++) {
+       *i ^= key;
+   }
+}
+
 TennixArchive::TennixArchive()
     : fp(NULL)
     , header()
@@ -64,7 +73,11 @@ TennixArchive::TennixArchive(const char* filename, const char* fallback)
     if (fp == NULL && fallback != NULL) {
         fp = fopen(fallback, "rb");
     }
-    tnx_assert(fp != NULL);
+
+    if (fp == NULL) {
+        fprintf(stderr, "Cannot open archive: %s\n", filename);
+        exit(1);
+    }
 
     offset = sizeof(TennixArchiveHeader)*fread(&(header), sizeof(TennixArchiveHeader), 1, fp);
     tnx_assert(offset == sizeof(TennixArchiveHeader));
@@ -139,16 +152,6 @@ TennixArchive::getItemBytes()
 }
 
 void
-TennixArchive::xormem(char* mem, uint32_t length, char key)
-{
-   char *i = mem, *end = mem+length;
-
-   for(; i != end; i++) {
-       *i ^= key;
-   }
-}
-
-void
 TennixArchive::appendItem(char* filename, char* data, uint32_t length)
 {
     TennixArchiveItem* item;
index 6e44c47..331a649 100644 (file)
@@ -76,8 +76,6 @@ class TennixArchive {
         int current_item;
         int building;
 
-        static void xormem(char* mem, uint32_t length, char key);
-
     public:
         TennixArchive();
         TennixArchive(const char* filename, const char* fallback=NULL);
dissimilarity index 74%
index 893c7b4..69b9a8e 100644 (file)
-
-/**
- *
- * Tennix Archive File Format
- * Copyright (C) 2009-2010 Thomas Perl <thp@thpinfo.com>
- * 
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 
- * MA  02110-1301, USA.
- *
- **/
-
-#include "tennix.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <libgen.h>
-#include <sys/stat.h>
-
-#include "archive.h"
-
-int main(int argc, char* argv[])
-{
-    TennixArchive* tnxar;
-    char* data;
-    FILE *fp;
-    const char* filename;
-    char *bn = (char*)basename(argv[0]);
-    int len, i;
-
-    if(strcmp(bn, "archive") == 0) {
-        if (argc < 2) {
-            fprintf(stderr, "Usage: %s archive.tnx file1 [....]\n", bn);
-            exit(EXIT_FAILURE);
-        } else if (argc == 2) {
-            fprintf(stderr, "Refusing to create an empty archive.\n");
-            exit(EXIT_FAILURE);
-        }
-
-        if (strcmp(".tnx", argv[1] + strlen(argv[1]) - 4) != 0) {
-            fprintf(stderr, "Wrong file extension: %s\n", argv[1]);
-            exit(EXIT_FAILURE);
-        }
-
-        TennixArchive archive;
-
-        //fprintf(stderr, "Creating %s with %d files\n", argv[1], argc-2);
-        for (i=2; i<argc; i++) {
-            fp = fopen(argv[i], "rb");
-            fseek(fp, 0, SEEK_END);
-            len = ftell(fp);
-            fseek(fp, 0, SEEK_SET);
-            data = (char*)malloc(len);
-            tnx_assert(fread(data, len, 1, fp) == 1);
-            fclose(fp);
-            char *filename = strdup(basename(argv[i]));
-            archive.appendItem(filename, data, len);
-        }
-        archive.buildFile(argv[1]);
-    } else if(strcmp(bn, "dump") == 0) {
-        if (argc < 2) {
-            fprintf(stderr, "Usage: %s archive.tnx\n", bn);
-            exit(EXIT_FAILURE);
-        }
-        TennixArchive archive(argv[1]);
-        std::cerr << archive << std::endl;
-    } else if(strcmp(bn, "extract") == 0) {
-        if (argc < 2 || argc > 3) {
-            fprintf(stderr, "Usage: %s archive.tnx [file]\n", bn);
-            exit(EXIT_FAILURE);
-        }
-        tnxar = new TennixArchive(argv[1]);
-        if (argc == 2) {
-            while (!tnxar->endOfFile()) {
-                filename = tnxar->getItemFilename();
-                data = tnxar->getItemBytes();
-                len = tnxar->getItemSize();
-                fprintf(stderr, "Extracting: %s", filename);
-                fprintf(stderr, " (%d bytes)", len);
-                fp = fopen(filename, "wb");
-                fputc('.', stderr);
-                tnx_assert(fwrite(data, len, 1, fp) == 1);
-                fputc('.', stderr);
-                fclose(fp);
-                fprintf(stderr, ".OK\n");
-                free(data);
-                tnxar->next();
-            }
-        } else if (argc == 3) {
-            filename = argv[2];
-            if (tnxar->setItemFilename(filename) != 0) {
-                fprintf(stderr, "Extracting: %s", filename);
-                data = tnxar->getItemBytes();
-                len = tnxar->getItemSize();
-                fprintf(stderr, " (%d bytes)", len);
-                fp = fopen(filename, "wb");
-                fputc('.', stderr);
-                tnx_assert(fwrite(data, len, 1, fp) == 1);
-                fputc('.', stderr);
-                fclose(fp);
-                fprintf(stderr, ".OK\n");
-                free(data);
-            } else {
-                fprintf(stderr, "File not found in %s: %s\n", argv[1], filename);
-                delete tnxar;
-                exit(EXIT_FAILURE);
-            }
-        }
-        delete tnxar;
-    }
-
-    return EXIT_SUCCESS;
-}
-
+
+/**
+ *
+ * Tennix Archive File Format
+ * Copyright (C) 2009-2010 Thomas Perl <thp@thpinfo.com>
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 
+ * MA  02110-1301, USA.
+ *
+ **/
+
+#include "tennix.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <libgen.h>
+#include <sys/stat.h>
+
+#include "archive.h"
+
+static int
+extract_file(TennixArchive *tnxar, bool verbose)
+{
+    char *data = tnxar->getItemBytes();
+
+    if (verbose) {
+        printf("%s\n", tnxar->getItemFilename());
+    }
+
+    FILE *fp = fopen(tnxar->getItemFilename(), "wb");
+    if (fp == NULL) {
+        return 1;
+    }
+    fwrite(data, tnxar->getItemSize(), 1, fp);
+    fclose(fp);
+
+    free(data);
+
+    return 0;
+}
+
+
+class ArchiveTool {
+    public:
+        ArchiveTool(int argc, char **argv);
+
+        int run();
+
+    private:
+        int usage();
+
+        int create(bool verbose);
+        int test(bool verbose);
+        int extract(bool verbose);
+
+        int argc;
+        char **argv;
+};
+
+ArchiveTool::ArchiveTool(int argc, char **argv)
+    : argc(argc)
+    , argv(argv)
+{
+}
+
+int
+ArchiveTool::run()
+{
+    bool do_create = false;
+    bool do_test = false;
+    bool do_extract = false;
+    bool verbose = false;
+
+    if (argc < 2) {
+        return usage();
+    }
+
+    char *opts = argv[1];
+    if (*opts == '-') opts++;
+
+    while (*opts) {
+        switch (*opts) {
+            case 'c':
+                do_create = true;
+                break;
+            case 't':
+                do_test = true;
+                break;
+            case 'x':
+                do_extract = true;
+                break;
+            case 'v':
+                verbose = true;
+                break;
+            case 'f':
+                if (opts[1]) {
+                    return usage();
+                }
+                break;
+            default:
+                return usage();
+                break;
+        }
+        opts++;
+    }
+
+    if (do_create && !do_test && !do_extract && argc > 3) {
+        return create(verbose);
+    } else if (do_test && !do_create && !do_extract && argc > 2) {
+        return test(verbose);
+    } else if (do_extract && !do_create && !do_test && argc > 2) {
+        return extract(verbose);
+    }
+
+    return usage();
+}
+
+int
+ArchiveTool::create(bool verbose)
+{
+    if (argc < 4) {
+        fprintf(stderr, "Refusing to create an empty archive.\n");
+        return 1;
+    }
+
+    char *archive = argv[2];
+    if (strcmp(".tnx", archive + strlen(archive) - 4) != 0) {
+        fprintf(stderr, "Wrong file extension: %s\n", archive);
+        return 1;
+    }
+
+    TennixArchive tnxar;
+    for (int i=3; i<argc; i++) {
+        FILE *fp = fopen(argv[i], "rb");
+        fseek(fp, 0, SEEK_END);
+        size_t len = ftell(fp);
+        fseek(fp, 0, SEEK_SET);
+        char *data = (char*)malloc(len);
+        tnx_assert(fread(data, len, 1, fp) == 1);
+        fclose(fp);
+        char *filename = strdup(basename(argv[i]));
+        if (verbose) {
+            printf("%s\n", filename);
+        }
+        tnxar.appendItem(filename, data, len);
+    }
+    tnxar.buildFile(archive);
+    return 0;
+}
+
+int
+ArchiveTool::test(bool verbose)
+{
+    TennixArchive tnxar(argv[2]);
+
+    while (!tnxar.endOfFile()) {
+        if (verbose) {
+            printf("%ld %s\n", tnxar.getItemSize(), tnxar.getItemFilename());
+        } else {
+            printf("%s\n", tnxar.getItemFilename());
+        }
+        tnxar.next();
+    }
+
+    return 0;
+}
+
+int
+ArchiveTool::extract(bool verbose)
+{
+    TennixArchive tnxar(argv[2]);
+
+    if (argc == 3) {
+        while (!tnxar.endOfFile()) {
+            if (extract_file(&tnxar, verbose) != 0) {
+                printf("Error extracting file\n");
+                return 1;
+            }
+            tnxar.next();
+        }
+        return 0;
+    }
+
+    for (int i=3; i<argc; i++) {
+        if (tnxar.setItemFilename(argv[i])) {
+            if (extract_file(&tnxar, verbose) != 0) {
+                printf("Error extracting file: %s\n", argv[i]);
+                return 1;
+            }
+        } else {
+            fprintf(stderr, "File not in archive: %s\n", argv[i]);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+int
+ArchiveTool::usage()
+{
+    fprintf(stderr, "Usage: %s [-ctxvf] <archive.tnx> file1 ...\n", argv[0]);
+    fprintf(stderr, "    -c ... Create archive\n");
+    fprintf(stderr, "    -t ... Test archive (list contents)\n");
+    fprintf(stderr, "    -x ... Extract archive\n");
+    fprintf(stderr, "    -v ... Verbose output\n");
+    fprintf(stderr, "    -f ... Filename of archive (optional)\n");
+    return 1;
+}
+
+int
+main(int argc, char **argv)
+{
+    ArchiveTool tool(argc, argv);
+    return tool.run();
+}
+