From a17c7e61ba8953301c28e94890e459e76f532687 Mon Sep 17 00:00:00 2001 From: jakob Date: Thu, 19 Jan 2017 18:54:37 -0500 Subject: Implemented the ability to specify an output path,. --- src/cli.c | 20 +++++++++++++++++++- src/cli.h | 1 + src/main.c | 1 + src/write.c | 19 ++++++++++++++++--- 4 files changed, 37 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/cli.c b/src/cli.c index 0025141..7d00434 100644 --- a/src/cli.c +++ b/src/cli.c @@ -36,6 +36,7 @@ " -l, --list\t\tList the contents of the archive.\n\n" \ " -a, --archive\tAlternate way of specifying archive" \ "to extract.\n" \ + " -o, --output\t\tPath to extract files to.\n" \ " -g, --game\t\tGame the archive is from. Required for " \ "file decryption\n" \ " -q, --quiet\t\tDon't display information about " \ @@ -68,12 +69,13 @@ struct configuration parse_args(int argc, char *argv[]) { {"extract", no_argument, NULL, 'e'}, {"list", no_argument, NULL, 'l'}, {"archive", required_argument, NULL, 'a'}, + {"output", required_argument, NULL, 'o'}, {"game", required_argument, NULL, 'g'}, {NULL, 0, NULL, 0} }; do { - current = getopt_long(argc, argv, "hvelqa:g:", long_options, + current = getopt_long(argc, argv, "hvelqa:o:g:", long_options, &option_index); switch (current) { case 'h': @@ -92,6 +94,14 @@ struct configuration parse_args(int argc, char *argv[]) { count++; parsed.archive = optarg; break; + case 'o': + count++; + size_t path_size = strlen(optarg); + parsed.output = malloc(path_size + 1); + strcpy(parsed.output, optarg); + if (parsed.output[path_size - 1] != PATH_DELIMITER) + parsed.output[path_size] = PATH_DELIMITER; + break; case 'g': count++; /* Out of concern for efficiency, string comparisons are @@ -128,5 +138,13 @@ struct configuration parse_args(int argc, char *argv[]) { parsed.archive = argv[count]; } + /* The output path is allocated on the heap to simplify freeing. */ + if (parsed.output == NULL) { + if ((parsed.output = strdup(".")) == NULL) { + fprintf(stderr, "Insufficient memory.\n"); + exit(EXIT_FAILURE); + } + } + return parsed; } diff --git a/src/cli.h b/src/cli.h index d02bca7..3f96f28 100644 --- a/src/cli.h +++ b/src/cli.h @@ -40,6 +40,7 @@ struct configuration { int quiet; /* Level of output verbosity. */ game_type game; /* Which decryption key to use. */ mode_type mode; /* What to do after initial sanity checks. */ + char *output; /* Path to extract files to. */ const char *archive; /* Path to archive to extract. */ }; diff --git a/src/main.c b/src/main.c index d166733..dc23460 100644 --- a/src/main.c +++ b/src/main.c @@ -82,6 +82,7 @@ int main(int argc, char *argv[]) { list(data_stream); } + free(arguments.output); free(data_stream.start); fclose(archive); return 0; diff --git a/src/write.c b/src/write.c index b9efafb..5d9cbad 100644 --- a/src/write.c +++ b/src/write.c @@ -90,6 +90,18 @@ void write_files(file_node *file_root, elif_node *elif_root, FILE *archive) { if (file_name == NULL) continue; + /* strcpy is used rather than strcat to prevent the file + name from being appended after garbage data. */ + size_t file_name_size = strlen(file_name); + size_t path_size = strlen(arguments.output); + char *output_path = malloc(path_size + file_name_size + 1); + if (output_path == NULL) { + fprintf(stderr, "Insufficient memory.\n"); + return; + } + strcpy(output_path, arguments.output); + strcpy(output_path + path_size, file_name); + if (!arguments.quiet) { printf("Inflating %s (%" PRIu64 " bytes)\n", file_name, current->file_size); @@ -127,14 +139,15 @@ void write_files(file_node *file_root, elif_node *elif_root, FILE *archive) { encryption_key, current->key); } - make_paths(file_name); - FILE *output = fopen(file_name, "wb+"); + make_paths(output_path); + FILE *output = fopen(output_path, "wb+"); if (output == NULL) { - perror(file_name); + perror(output_path); break; } fwrite(out_start, current->file_size, 1, output); fclose(output); + free(output_path); free(file_name); free(out_start); } -- cgit v1.3