summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorjakob <jakob@memeware.net>2017-04-01 15:47:28 -0400
committerjakob <jakob@memeware.net>2017-04-01 15:47:28 -0400
commit5ac05edbb64b89741728ba006b0ce681a5d51595 (patch)
treed31d0f396181821bb5bd40fffd6e4c92bb025f7c /src
parent06ef3f15929b4de343f4f749bade08f6b4783d3a (diff)
Fixed segmentation fault on invalid paths, cleaned up code
Diffstat (limited to 'src')
-rw-r--r--src/cli.c50
-rw-r--r--src/cli.h10
-rw-r--r--src/crypto.h4
-rw-r--r--src/header.h10
-rw-r--r--src/io.h6
-rw-r--r--src/main.c67
-rw-r--r--src/table.h16
7 files changed, 88 insertions, 75 deletions
diff --git a/src/cli.c b/src/cli.c
index feb9718..b60454a 100644
--- a/src/cli.c
+++ b/src/cli.c
@@ -23,19 +23,46 @@
#include <getopt.h>
#include "cli.h"
-#include "crypto.h" /* New, maybe clean up the section on game crypto? */
+#include "crypto.h"
+
+
+/* Copies `optarg` into the out field of `p` and ensures that it ends in
+ a trailing path delimiter. */
+static void parse_output_path(const char *optarg, struct params *p) {
+ p->out_len = strlen(optarg);
+ p->out = malloc(p->out_len + 2);
+ strcpy(p->out, optarg);
+ if (p->out[p->out_len - 1] != '/') {
+ p->out[p->out_len] = '/';
+ p->out_len += 1;
+ }
+}
+
+
+/* Updates the game field of `p` to properly reflect the game ID
+ specified by the string, `optarg`. */
+static void parse_game_id(const char *optarg, struct params *p) {
+ if (!strcmp(optarg, "nekopara_volume_0"))
+ p->game = NEKOPARA_VOLUME_0;
+ else if (!strcmp(optarg, "nekopara_volume_0_steam"))
+ p->game = NEKOPARA_VOLUME_0_STEAM;
+ else if (!strcmp(optarg, "nekopara_volume_1"))
+ p->game = NEKOPARA_VOLUME_1;
+ else if (!strcmp(optarg, "nekopara_volume_1_steam"))
+ p->game = NEKOPARA_VOLUME_1_STEAM;
+}
/* Returns a params structure parsed from `argv`. */
struct params parse_args(int argc, char **argv) {
struct params p = {0};
-
+
if (argc < 2) {
p.mode = USAGE;
return p;
}
p.mode = EXTRACT;
-
+
int cur = 0, opt_index = 0, count = 0;
static struct option long_opts[] = {
{"help", no_argument, NULL, 'h'},
@@ -63,24 +90,11 @@ struct params parse_args(int argc, char **argv) {
break;
case 'o':
count++;
- p.out_len = strlen(optarg);
- p.out = malloc(p.out_len + 2);
- strcpy(p.out, optarg);
- if (p.out[p.out_len - 1] != '/') {
- p.out[p.out_len] = '/';
- p.out_len += 1;
- }
+ parse_output_path(optarg, &p);
break;
case 'g':
count++;
- if (!strcmp(optarg, "nekopara_volume_0"))
- p.game = NEKOPARA_VOLUME_0;
- else if (!strcmp(optarg, "nekopara_volume_0_steam"))
- p.game = NEKOPARA_VOLUME_0_STEAM;
- else if (!strcmp(optarg, "nekopara_volume_1"))
- p.game = NEKOPARA_VOLUME_1;
- else if (!strcmp(optarg, "nekopara_volume_1_steam"))
- p.game = NEKOPARA_VOLUME_1_STEAM;
+ parse_game_id(optarg, &p);
case 'e':
p.mode = EXTRACT;
break;
diff --git a/src/cli.h b/src/cli.h
index 8e16020..cf7a535 100644
--- a/src/cli.h
+++ b/src/cli.h
@@ -33,12 +33,12 @@ enum {
/* Structure for storing options set from the command-line. */
struct params {
- int mode; /* Current mode of operation. */
- int game; /* Which encryption keys to use. */
- bool verbose; /* Whether or not to output progress messages. */
+ int mode; /* Current mode of operation. */
+ int game; /* Which encryption keys to use. */
+ bool verbose; /* Whether or not to output progress messages. */
int vararg_index; /* Start index of paths in argv. */
- char *out; /* Path to extract files to. */
- size_t out_len; /* Length of the output path string. */
+ char *out; /* Path to extract files to. */
+ size_t out_len; /* Length of the output path string. */
};
/* Returns a params structure parsed from `argv`. */
diff --git a/src/crypto.h b/src/crypto.h
index 11b0fc5..e80531d 100644
--- a/src/crypto.h
+++ b/src/crypto.h
@@ -33,8 +33,8 @@ enum {
/* Structure containing game-specific encryption information. */
struct game_key {
- bool uses_initial; /* Whether or not to use an initial key. */
- uint32_t master; /* Master key specific to the game. */
+ bool uses_initial; /* Whether or not to use an initial key. */
+ uint32_t master; /* Master key specific to the game. */
uint8_t fallback_initial; /* Fallback if initial key is 0. */
uint8_t fallback_primary; /* Fallback if primary key is 0. */
};
diff --git a/src/header.h b/src/header.h
index d45d4b0..19f7fcd 100644
--- a/src/header.h
+++ b/src/header.h
@@ -27,11 +27,11 @@
/* Structure representing the header section of an XP3 archive. */
struct header {
- char magic[11]; /* Identifier for the archive. */
- uint64_t info_offset; /* Offset to `table_size`. */
- uint32_t version; /* Raw value containing the archive version. */
- uint64_t table_size; /* The size of the table section. (?) */
- uint8_t flags; /* A flags variable for the archive. (?) */
+ char magic[11]; /* Identifier for the archive. */
+ uint64_t info_offset; /* Offset to `table_size`. */
+ uint32_t version; /* Raw value containing the archive version. */
+ uint64_t table_size; /* The size of the table section. (?) */
+ uint8_t flags; /* A flags variable for the archive. (?) */
uint64_t table_offset; /* Offset to the archive table. */
};
diff --git a/src/io.h b/src/io.h
index 3caaa95..b37ec51 100644
--- a/src/io.h
+++ b/src/io.h
@@ -33,10 +33,10 @@ enum _location {
position. The structure additionally maintains a `length` variable
containing the stream's length. */
struct stream {
- size_t len; /* Length of the stream. */
+ size_t len; /* Length of the stream. */
char *_start; /* Pointer to the stream's start. */
- char *_cur; /* Pointer to the current position. */
- enum _location _loc; /* Location of the stream in memory. */
+ char *_cur; /* Pointer to the current position. */
+ enum _location _loc; /* Location of the stream in memory. */
};
/* Allocates `len` bytes of non-zeroed memory and returns a new stream
diff --git a/src/main.c b/src/main.c
index 9b24fe6..95b4ae3 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1,4 +1,4 @@
-/* main.c -- Entry point to the program.
+/* main.c -- Command-line entry point to the Nekopack.
Copyright (C) 2017 Jakob Kreuze, All Rights Reserved.
@@ -33,12 +33,7 @@
#define EXIT_FAILURE 1
#define EXIT_SUCCESS 0
-#define VERSION_STR "2.0.0a2"
-
-
-/* Pointer to a function to be mapped to entries in the table. */
-typedef void (*mapfn)(struct stream *archive, struct table_entry *e,
- struct params p);
+#define VERSION_STR "2.0.0"
/* Writes usage information to stderr. */
@@ -65,7 +60,7 @@ static void print_help(void) {
" -l, --list\t\tList the contents of the archive.\n\n"
" -o, --output\t\tPath to extract files to.\n"
" -g, --game\t\tGame the archive is from. Required for file "
- "decryption\n"
+ "decryption.\n"
" -q, --quiet\t\tDon't display information about extracted "
"files.\n\n"
"Supported games: nekopara_volume_0, nekopara_volume_0_steam,\n"
@@ -88,10 +83,9 @@ static struct stream *load_table(struct stream *s) {
/* Creates any directories that do not already exist in `path`. */
void make_dirs(char *path) {
- struct stat tmp = {0};
- char *buf = calloc(0x100, 1);
+ char *buf = calloc(0x100, 1);
char *buf_start = buf;
-
+ struct stat tmp = {0};
for (int i = 0; i < 0x100 && path[i] != '\0'; i++) {
if (path[i] == '/') {
*buf++ = '/';
@@ -116,26 +110,20 @@ static char *get_path(struct params p, char *name) {
}
-/* Basic mapfn for printing the filename of each entry. */
-static void list(struct stream *s, struct table_entry *e, struct params p) {
- if (e->filename == NULL) {
- fprintf(stderr, "Found File entry without matching eliF. Archive may "
- "be corrupted.\n");
+/* Prints the filename of the entry specified by `e` to stdout. */
+static void list(struct table_entry *e) {
+ if (e->filename == NULL || e->segments == NULL) {
+ fprintf(stderr, "Inconsistency detected. Archive may be corrupted.\n");
return;
}
printf("%s\n", e->filename);
}
-/* Mapfn for extracting the contents of the archive. */
+/* Extracts the archive entry specified by `e` to disk. */
static void extract(struct stream *s, struct table_entry *e, struct params p) {
- if (e->filename == NULL) {
- fprintf(stderr, "Found File entry without matching eliF. Archive may "
- "be corrupted.\n");
- return;
- } else if (e->segments == NULL) {
- fprintf(stderr, "Found eliF entry without matching File. Archive may "
- "be corrupted.\n");
+ if (e->filename == NULL || e->segments == NULL) {
+ fprintf(stderr, "Inconsistency detected. Archive may be corrupted.\n");
return;
}
@@ -177,17 +165,30 @@ static void extract(struct stream *s, struct table_entry *e, struct params p) {
}
-/* Maps `fn` to every table entry found in the archive at `path`. */
-static void map_entries(char *path, struct params p, mapfn fn) {
+/* Loads an XP3 archive and maps the function associated to the current
+ mode of operation to every entry. */
+static void map_entries(char *path, struct params p) {
struct stream *archive = stream_from_file(path);
- struct header *h = read_header(archive);
+ if (archive == NULL) {
+ perror(path);
+ return;
+ }
+
+ struct header *h = read_header(archive);
stream_seek(archive, h->table_offset, SEEK_SET);
struct stream *table = load_table(archive);
struct table_entry *root = read_table(table);
- for (struct table_entry *cur = root->next; cur != NULL; cur = cur->next)
- fn(archive, cur, p);
+ for (struct table_entry *cur = root->next; cur != NULL; cur = cur->next) {
+ switch (p.mode) {
+ case LIST:
+ list(cur);
+ break;
+ case EXTRACT:
+ extract(archive, cur, p);
+ }
+ }
entry_free(root);
stream_free(table);
@@ -201,7 +202,8 @@ int main(int argc, char **argv) {
switch (p.mode) {
case USAGE:
print_usage(argv[0]);
- return 1;
+ params_free(p);
+ return EXIT_FAILURE;
case VERSION:
print_version();
break;
@@ -209,12 +211,9 @@ int main(int argc, char **argv) {
print_help();
break;
case LIST:
- for (int i = p.vararg_index; i < argc; i++)
- map_entries(argv[i], p, list);
- break;
case EXTRACT:
for (int i = p.vararg_index; i < argc; i++)
- map_entries(argv[i], p, extract);
+ map_entries(argv[i], p);
}
params_free(p);
return EXIT_SUCCESS;
diff --git a/src/table.h b/src/table.h
index 1f40390..80ad099 100644
--- a/src/table.h
+++ b/src/table.h
@@ -27,20 +27,20 @@
/* Structure representing one segment associated with a File entry. */
struct segment {
- bool compressed; /* Whether or not the segment is compressed. */
- uint64_t offset; /* Offset to the segment's beginning. */
- uint64_t compressed_size; /* Size of compressed segment. */
+ bool compressed; /* Whether or not the segment is compressed. */
+ uint64_t offset; /* Offset to the segment's beginning. */
+ uint64_t compressed_size; /* Size of compressed segment. */
uint64_t decompressed_size; /* Size of decompressed segment. */
};
/* Structure representing an entry in the archive's table section. */
struct table_entry {
- uint32_t key; /* File-specific key for encryption. */
- uint64_t ctime; /* Timestamp of creation time. */
+ uint32_t key; /* File-specific key for encryption. */
+ uint64_t ctime; /* Timestamp of creation time. */
uint64_t segment_count; /* Number of segments. */
- struct segment **segments; /* Array of associated segments. */
- char *filename; /* String containing file's name. */
- struct table_entry *next; /* Pointer to the next entry. */
+ char *filename; /* String containing file's name. */
+ struct segment **segments; /* Array of associated segments. */
+ struct table_entry *next; /* Pointer to the next entry. */
};