summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorjakob <jakob@memeware.net>2017-06-03 19:00:07 -0400
committerjakob <jakob@memeware.net>2017-06-03 19:00:07 -0400
commit17b658ceadd08d693f23448c276958e2eea5970e (patch)
tree8d0f62709646de856373a0ffa4fc2513f717f770 /src
parent6adad1bfad91274aad030cf6167c1f19fb602d62 (diff)
Fully working repacker, no bugs related to the encoded output being larger than the buffer, and filenames are properly encoded.
Diffstat (limited to 'src')
-rw-r--r--src/cli.c11
-rw-r--r--src/cli.h1
-rw-r--r--src/compress.c10
-rw-r--r--src/crypto.c1
-rw-r--r--src/header.c2
-rw-r--r--src/io.c23
-rw-r--r--src/io.h3
-rw-r--r--src/main.c45
-rw-r--r--src/table.c11
9 files changed, 89 insertions, 18 deletions
diff --git a/src/cli.c b/src/cli.c
index 8df6539..7f2703e 100644
--- a/src/cli.c
+++ b/src/cli.c
@@ -78,6 +78,7 @@ struct params parse_args(int argc, char **argv) {
{"extract", no_argument, NULL, 'e'},
{"list", no_argument, NULL, 'l'},
{"create", no_argument, NULL, 'c'},
+ {"debug", no_argument, NULL, 'd'},
{"output", no_argument, NULL, 'o'},
{"game", no_argument, NULL, 'g'},
{NULL, 0, NULL, 0}
@@ -85,7 +86,7 @@ struct params parse_args(int argc, char **argv) {
do {
count++;
- cur = getopt_long(argc, argv, "hVvelcqo:g:", long_opts, &opt_index);
+ cur = getopt_long(argc, argv, "hVvelcdqo:g:", long_opts, &opt_index);
switch (cur) {
case 'h':
p.mode = HELP;
@@ -119,6 +120,10 @@ struct params parse_args(int argc, char **argv) {
case 'c':
p.mode = CREATE;
+ break;
+
+ case 'd':
+ p.mode = DEBUG;
}
} while (cur >= 0);
@@ -126,6 +131,7 @@ struct params parse_args(int argc, char **argv) {
p.mode = USAGE;
return p;
}
+
p.vararg_index = count;
if (p.out == NULL) {
@@ -157,7 +163,8 @@ void print_help(void) {
" -e, --extract\tExtract the contents of the archive. This is "
"the default\n\t\t\taction if no mode argument is provided.\n"
" -l, --list\t\tList the contents of the archive.\n"
- " -c, --create\t\tCreate a new XP3 archive.\n\n"
+ " -c, --create\t\tCreate a new XP3 archive.\n"
+ " -d, --debug\t\tDisplay the archive's table and metadata.\n\n"
" -o, --output\t\tPath to extract files to.\n"
" -g, --game\t\tGame the archive is from. Required for file "
"decryption.\n"
diff --git a/src/cli.h b/src/cli.h
index dfc8ef4..00e33fa 100644
--- a/src/cli.h
+++ b/src/cli.h
@@ -30,6 +30,7 @@ enum {
LIST,
EXTRACT,
CREATE,
+ DEBUG,
};
/* Structure for storing options set from the command-line. */
diff --git a/src/compress.c b/src/compress.c
index 71e0ae3..e61780d 100644
--- a/src/compress.c
+++ b/src/compress.c
@@ -82,9 +82,17 @@ struct stream *stream_deflate(struct stream *s, size_t len) {
strm.avail_out = len;
strm.next_out = (unsigned char *) new->_cur;
deflate(&strm, Z_FINISH);
+
+ /* This means that the compressed data is larger than the
+ decompressed, and that the buffer needs to be expanded. */
+ if (strm.avail_out == 0) {
+ new->_cur += len;
+ stream_expand(new, s->len);
+ }
} while (strm.avail_out == 0);
- new->len = len - strm.avail_out;
+ new->len -= strm.avail_out;
+ new->_cur = new->_start;
deflateEnd(&strm);
return new;
diff --git a/src/crypto.c b/src/crypto.c
index 5a91f39..958fb06 100644
--- a/src/crypto.c
+++ b/src/crypto.c
@@ -67,6 +67,7 @@ uint8_t derive_initial(struct game_key k, uint64_t file_key) {
/* Generates a primary key for the given key structure and file key. */
uint8_t derive_primary(struct game_key k, uint64_t file_key) {
+ if (!k.master) return 0x00;
uint32_t tmp = k.master ^ file_key;
uint8_t primary = (tmp >> 24 ^ tmp >> 16 ^ tmp >> 8 ^ tmp) & 0xff;
return primary == 0 ? k.fallback_primary : primary;
diff --git a/src/header.c b/src/header.c
index a5b6477..86f5e25 100644
--- a/src/header.c
+++ b/src/header.c
@@ -70,7 +70,7 @@ struct header *create_header(void) {
return NULL;
memcpy(h->magic, XP3_MAGIC, 11);
- h->info_offset = 17;
+ h->info_offset = 0x17;
h->version = 1;
h->flags = 0x80;
h->table_size = 0;
diff --git a/src/io.c b/src/io.c
index 759902c..fcc5602 100644
--- a/src/io.c
+++ b/src/io.c
@@ -110,20 +110,25 @@ void stream_read(void *dest, struct stream *s, size_t n) {
/* Copies `n` bytes into the given stream from the memory area specified
by `src`. The stream's cursor is advanced appropriately. */
void stream_write(struct stream *s, void *src, size_t n) {
- while (s->_cur + n > s->_start + s->len) {
- ptrdiff_t dist = (uintptr_t) s->_cur - (uintptr_t) s->_start;
- switch(s->_loc) {
- case HEAP:
- s->len *= 2;
- s->_start = realloc(s->_start, s->len);
- s->_cur = s->_start + dist;
- }
- }
+ while (s->_cur + n > s->_start + s->len)
+ stream_expand(s, s->len);
memcpy(s->_cur, src, n);
s->_cur += n;
}
+/* Increases the length of `s` by `n` bytes. */
+void stream_expand(struct stream *s, size_t n) {
+ ptrdiff_t dist = (uintptr_t) s->_cur - (uintptr_t) s->_start;
+ switch(s->_loc) {
+ case HEAP:
+ s->len += n;
+ s->_start = realloc(s->_start, s->len);
+ s->_cur = s->_start + dist;
+ }
+}
+
+
/* Concatenates the contents of `src` onto `dst`. */
void stream_concat(struct stream *dst, struct stream *src, size_t n) {
stream_write(dst, src->_cur, n);
diff --git a/src/io.h b/src/io.h
index c5c1f56..9f39930 100644
--- a/src/io.h
+++ b/src/io.h
@@ -66,6 +66,9 @@ void stream_read(void *dest, struct stream *s, size_t n);
by `src`. The stream's cursor is advanced appropriately. */
void stream_write(struct stream *s, void *src, size_t n);
+/* Increases the length of `s` by `n` bytes. */
+void stream_expand(struct stream *s, size_t n);
+
/* Concatenates the contents of `src` onto `dst`. */
void stream_concat(struct stream *dst, struct stream *src, size_t n);
diff --git a/src/main.c b/src/main.c
index 2a96b21..ac21bb4 100644
--- a/src/main.c
+++ b/src/main.c
@@ -17,6 +17,7 @@
You should have received a copy of the GNU General Public License
along with Nekopack. If not, see <http://www.gnu.org/licenses/>. */
+#include <inttypes.h> /* Only used for debug mode. */
#include <errno.h>
#include <sys/stat.h>
#include <stdint.h>
@@ -34,6 +35,9 @@
#define EXIT_FAILURE 1
#define EXIT_SUCCESS 0
+#define ANSI_TITLE "\x1b[36m\x1b[4m"
+#define ANSI_END "\x1b[0m"
+
static struct stream *load_table(struct stream *s) {
uint8_t compressed;
@@ -243,7 +247,7 @@ static void create_archive(char **paths, int argc, struct params p) {
/* TODO: Separate into own function. */
table_size += 20 + strlen(cur->filename) * 2;
- table_size += 28 * cur->segment_count + 56;
+ table_size += 28 * cur->segment_count + 60;
cur->segments = malloc(sizeof(struct segment *));
if (cur->segments == NULL) {
@@ -278,7 +282,7 @@ static void create_archive(char **paths, int argc, struct params p) {
return;
}
- h->table_size = data->len; // This isn't right <:^)
+ h->table_size = table_size;
h->table_offset = 40 + data->len;
dump_header(fp, h);
@@ -296,6 +300,38 @@ static void create_archive(char **paths, int argc, struct params p) {
}
+/* The name is not particularly fitting to its function. */
+static void display_table(char *path, struct params p) {
+ /* Replicated code. Could this be in map_entries? */
+ struct stream *archive = stream_from_file(path);
+ if (archive == NULL) {
+ if (errno == ENOENT) {
+ perror(path);
+ } else {
+ fprintf(stderr, "Error allocating memory.\n");
+ }
+ return;
+ }
+
+ struct header *h = read_header(archive);
+ if (h == NULL) {
+ fprintf(stderr, "File is not an XP3 archive.\n");
+ return;
+ }
+
+ printf(ANSI_TITLE "Archive Header\n" ANSI_END);
+ printf("Magic: ");
+ for (int i = 0; i < 11; i++)
+ printf("%x", h->magic[i]);
+ printf("\n");
+ printf("Info Offset: 0x%"PRIx64"\n", h->info_offset);
+ printf("Version: 0x%"PRIx32"\n", h->version);
+ printf("Flags: 0x%"PRIx8"\n", h->flags);
+ printf("Table Size: 0x%"PRIx64"\n", h->table_size);
+ printf("Table Offset: 0x%"PRIx64"\n", h->table_offset);
+}
+
+
int main(int argc, char **argv) {
struct params p = parse_args(argc, argv);
switch (p.mode) {
@@ -318,6 +354,11 @@ int main(int argc, char **argv) {
map_entries(argv[i], p);
break;
+ case DEBUG:
+ for (int i = p.vararg_index; i < argc; i++)
+ display_table(argv[i], p);
+ break;
+
case CREATE:
create_archive(argv + p.vararg_index, argc, p);
}
diff --git a/src/table.c b/src/table.c
index 12daff5..421a04d 100644
--- a/src/table.c
+++ b/src/table.c
@@ -246,6 +246,10 @@ struct table_entry *read_table(struct stream *s) {
uint32_t magic;
uint64_t size;
+ FILE *fp = fopen("/tmp/dump.bin", "wb+");
+ stream_dump(fp, s, s->len);
+ fclose(fp);
+
do {
stream_read(&magic, s, sizeof(uint32_t));
stream_read(&size, s, sizeof(uint64_t));
@@ -286,12 +290,13 @@ struct table_entry *add_file(struct table_entry *root, char *path) {
return NULL;
size_t name_len = strlen(path);
- new->filename = malloc(name_len);
+ new->filename = malloc(name_len + 1);
if (new->filename == NULL)
return NULL;
- strncpy(new->filename, path, name_len);
- new->key = 0xffffffff;
+ strncpy(new->filename, path, name_len + 1);
+ /* TODO: Replace this with something more deterministic. */
+ new->key = rand();
new->ctime = 0;
new->segment_count = 1;
entry_append(root, new);