summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/cli.c20
-rw-r--r--src/cli.h1
-rw-r--r--src/main.c1
-rw-r--r--src/write.c19
4 files changed, 37 insertions, 4 deletions
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);
}