diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/cli.c | 11 | ||||
| -rw-r--r-- | src/cli.h | 1 | ||||
| -rw-r--r-- | src/compress.c | 10 | ||||
| -rw-r--r-- | src/crypto.c | 1 | ||||
| -rw-r--r-- | src/header.c | 2 | ||||
| -rw-r--r-- | src/io.c | 23 | ||||
| -rw-r--r-- | src/io.h | 3 | ||||
| -rw-r--r-- | src/main.c | 45 | ||||
| -rw-r--r-- | src/table.c | 11 |
9 files changed, 89 insertions, 18 deletions
@@ -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" @@ -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; @@ -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); @@ -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); @@ -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); |