diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/cli.c | 9 | ||||
| -rw-r--r-- | src/cli.h | 4 | ||||
| -rw-r--r-- | src/compress.c | 2 | ||||
| -rw-r--r-- | src/io.c | 67 | ||||
| -rw-r--r-- | src/io.h | 22 | ||||
| -rw-r--r-- | src/main.c | 48 | ||||
| -rw-r--r-- | src/table.c | 37 |
7 files changed, 119 insertions, 70 deletions
@@ -39,8 +39,6 @@ static void parse_output_path(const char *optarg, struct params *p) { } -/* 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; @@ -53,7 +51,6 @@ static void parse_game_id(const char *optarg, struct params *p) { } -/* Returns a params structure parsed from `argv`. */ struct params parse_args(int argc, char **argv) { /* getopt maintains external state which needs to be reset each time `parse_args` is called, otherwise strange things will occur. */ @@ -127,9 +124,3 @@ struct params parse_args(int argc, char **argv) { return p; } - - -/* Frees allocated memory associated with `p`. */ -void params_free(struct params p) { - free(p.out); -} @@ -42,8 +42,4 @@ struct params { int vararg_index; /* Start index of paths in argv. */ }; -/* Returns a params structure parsed from `argv`. */ struct params parse_args(int argc, char **argv); - -/* Frees allocated memory associated with `p`. */ -void params_free(struct params p); diff --git a/src/compress.c b/src/compress.c index 9b6607d..3137145 100644 --- a/src/compress.c +++ b/src/compress.c @@ -78,7 +78,7 @@ struct stream *stream_deflate(struct stream *s, size_t len) { do { strm.avail_out = len; strm.next_out = (unsigned char *) new->_cur; - deflate(&strm, Z_NO_FLUSH); // Flush param may cause issues. + deflate(&strm, Z_FINISH); } while (strm.avail_out == 0); new->len = len - strm.avail_out; @@ -26,45 +26,70 @@ /* Allocates `len` bytes of non-zeroed memory and returns a new stream - structure pointing to it. */ + structure pointing to it, or NULL if any allocations fail. The stream + returned is guaranteed to be positioned at the beginning. */ struct stream *stream_new(size_t len) { struct stream *new = malloc(sizeof(struct stream)); - new->len = len; + if (new == NULL) + return NULL; + new->_start = malloc(len); - new->_cur = new->_start; - new->_loc = HEAP; + if (new->_start == NULL) + return NULL; + + new->_cur = new->_start; + new->len = len; + new->_loc = HEAP; return new; } -/* Copies `n` bytes from `s` into a new stream structure. */ +/* Copies `n` bytes from `s` into a new stream structure, returning NULL + if any allocations fail. The stream returned is guaranteed to be + positioned at the beginning. */ struct stream *stream_clone(struct stream *s, size_t n) { struct stream *new = stream_new(n); + if (new == NULL) + return NULL; + stream_write(new, s->_cur, n); stream_rewind(new); return new; } -/* Maps the file at the given `path` into a stream structure. */ +/* Maps the file at the given `path` into a stream structure, returning + NULL if the path does not exist or if any allocations fail. The + stream returned is guaranteed to be positioned at the beginning. */ struct stream *stream_from_file(char *path) { FILE *fp = fopen(path, "rb"); - if (fp == NULL) return NULL; + if (fp == NULL) + return NULL; + struct stream *new = malloc(sizeof(struct stream)); + if (new == NULL) + return NULL; + fseek(fp, 0, SEEK_END); new->len = ftell(fp); fseek(fp, 0, SEEK_SET); + new->_start = malloc(new->len); - new->_cur = new->_start; + if (new->_start == NULL) { + free(new); + return NULL; + } + fread(new->_start, new->len, 1, fp); + new->_cur = new->_start; new->_loc = HEAP; fclose(fp); return new; } -/* Called to free or unmap the memory chunk associated with the given - stream, as well as the stream structure itself. */ +/* Called to free memory associated with the given stream, as well as + the stream structure itself. */ void stream_free(struct stream *s) { switch (s->_loc) { case HEAP: @@ -82,12 +107,6 @@ void stream_read(void *dest, struct stream *s, size_t n) { } -/* Dumps the contents of `s` into the file specified by `fp`. */ -void stream_dump(FILE *fp, struct stream *s, size_t n) { - fwrite(s->_cur, n, 1, fp); -} - - /* 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) { @@ -105,12 +124,18 @@ void stream_write(struct stream *s, void *src, size_t n) { } -/* Concatenats the contents of `src` onto `dst`. */ +/* 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); } +/* Dumps the contents of `s` into the file specified by `fp`. */ +void stream_dump(FILE *fp, struct stream *s, size_t n) { + fwrite(s->_cur, n, 1, fp); +} + + /* Applies an initial and primary key to the given stream, effectively encrypting or decrypting it. */ void stream_xor(struct stream *s, uint8_t initial, uint8_t primary) { @@ -125,10 +150,10 @@ size_t stream_tell(struct stream *s) { } -/* Sets the stream's position indicator to the given `pos`. If `whence` - is set to SEEK_SET, SEEK_CUR, or SEEK_END, the offset is relative to - the start of the file, the current position indicator, or - end-of-file, respectively. */ +/* Sets the stream's position indicator to the given `pos`. A `whence` + value of SEEK_SET indicates seeking relative to the beginning of the + file, SEEK_CUR indicates seeking relative to the current position, + and SEEK_END indicates seeking from the end of the file. */ void stream_seek(struct stream *s, size_t pos, int whence) { switch (whence) { case SEEK_SET: @@ -40,17 +40,22 @@ struct stream { }; /* Allocates `len` bytes of non-zeroed memory and returns a new stream - structure pointing to it. */ + structure pointing to it, or NULL if any allocations fail. The stream + returned is guaranteed to be positioned at the beginning. */ struct stream *stream_new(size_t len); -/* Copies `n` bytes from `s` into a new stream structure. */ +/* Copies `n` bytes from `s` into a new stream structure, returning NULL + if any allocations fail. The stream returned is guaranteed to be + positioned at the beginning. */ struct stream *stream_clone(struct stream *s, size_t n); -/* Maps the file at the given `path` into a stream structure. */ +/* Maps the file at the given `path` into a stream structure, returning + NULL if the path does not exist or if any allocations fail. The + stream returned is guaranteed to be positioned at the beginning. */ struct stream *stream_from_file(char *path); -/* Called to free or unmap the memory chunk associated with the given - stream, as well as the stream structure itself. */ +/* Called to free memory associated with the given stream, as well as + the stream structure itself. */ void stream_free(struct stream *s); /* Copies `n` bytes from the given stream into the memory area specified @@ -61,7 +66,7 @@ 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); -/* Concatenats the contents of `src` onto `dst`. */ +/* Concatenates the contents of `src` onto `dst`. */ void stream_concat(struct stream *dst, struct stream *src, size_t n); /* Dumps the contents of `s` into the file specified by `fp`. */ @@ -74,7 +79,10 @@ void stream_xor(struct stream *s, uint8_t initial, uint8_t primary); /* Obtains the current value of the stream's position indicator. */ size_t stream_tell(struct stream *s); -/* Sets the stream's position indicator to the given `pos`. */ +/* Sets the stream's position indicator to the given `pos`. A `whence` + value of SEEK_SET indicates seeking relative to the beginning of the + file, SEEK_CUR indicates seeking relative to the current position, + and SEEK_END indicates seeking from the end of the file. */ void stream_seek(struct stream *s, size_t pos, int whence); /* Sets the stream's position indicator to the beginning. */ @@ -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 <errno.h> #include <sys/stat.h> #include <stdint.h> #include <stdio.h> @@ -33,23 +34,20 @@ #define EXIT_FAILURE 1 #define EXIT_SUCCESS 0 -#define VERSION_STR "2.1.0b1" +#define NEKOPACK_VERSION "2.1.0b1" -/* Writes usage information to stderr. */ static void print_usage(char *progn) { fprintf(stderr, "Usage: %s [OPTIONS] (ARCHIVES) [PATHS]\n", progn); } -/* Writes versioning information to stdout. */ static void print_version(void) { printf("Nekopack version %s\nProgrammed by Jakob. " - "<http://jakob.space>\n", VERSION_STR); + "<http://jakob.space>\n", NEKOPACK_VERSION); } -/* Writes help information to stdout. */ static void print_help(void) { printf("A tool for decompressing the XP3 archives used by Nekopara.\n\n" " -h, --help\t\tDisplay this help page and exit.\n" @@ -69,7 +67,6 @@ static void print_help(void) { } -/* Inflates the table according to information in the header. */ static struct stream *load_table(struct stream *s) { uint8_t compressed; uint64_t len, decompressed_len; @@ -102,7 +99,7 @@ void make_dirs(char *path) { } -/* Concatenates `name` and the output path specified in `p`. */ +/* Joins `name` and the output path specified in `p`. */ static char *get_path(struct params p, char *name) { size_t name_len = strlen(name); char *path = malloc(p.out_len + name_len + 2); @@ -112,7 +109,6 @@ static char *get_path(struct params p, char *name) { } -/* 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, "Unpaired entries found. Archive may be corrupted.\n"); @@ -122,7 +118,6 @@ static void list(struct table_entry *e) { } -/* 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 || e->segments == NULL) { fprintf(stderr, "Unpaired entries found. Archive may be corrupted.\n"); @@ -172,15 +167,31 @@ static void extract(struct stream *s, struct table_entry *e, struct params p) { static void map_entries(char *path, struct params p) { struct stream *archive = stream_from_file(path); if (archive == NULL) { - perror(path); + 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; + } stream_seek(archive, h->table_offset, SEEK_SET); - struct stream *table = load_table(archive); - struct table_entry *root = read_table(table); + struct stream *table = load_table(archive); + if (table == NULL) { + fprintf(stderr, "Error allocating memory.\n"); + return; + } + + struct table_entry *root = read_table(table); + if (root == NULL) { + fprintf(stderr, "Error allocating memory.\n"); + } for (struct table_entry *cur = root->next; cur != NULL; cur = cur->next) { switch (p.mode) { @@ -199,8 +210,9 @@ static void map_entries(char *path, struct params p) { } -/* Creates a new XP3 archive at the first path specified by `paths`, and - flattens files specified by any following paths into the archive. */ +/* Creates a new XP3 archive. The destination of the archive is the + first string in `paths`, and the files at any following paths will be + flattened into the archive. */ static void create_archive(char **paths, int argc, struct params p) { FILE *fp = fopen(paths[0], "wb+"); if (fp == NULL) { @@ -237,7 +249,7 @@ static void create_archive(char **paths, int argc, struct params p) { h->table_offset = 40 + data_size; dump_table(table, root); - + data_compressed = stream_deflate(data, data_size); table_compressed = stream_deflate(table, table_size); stream_free(data); @@ -254,7 +266,7 @@ static void create_archive(char **paths, int argc, struct params p) { fwrite(&compressed, sizeof(uint8_t), 1, fp); fwrite(&len, sizeof(uint64_t), 1, fp); fwrite(&decompressed_len, sizeof(uint64_t), 1, fp); - + stream_dump(fp, table_compressed, table_size); } @@ -264,7 +276,7 @@ int main(int argc, char **argv) { switch (p.mode) { case USAGE: print_usage(argv[0]); - params_free(p); + free(p.out); return EXIT_FAILURE; case VERSION: print_version(); @@ -280,6 +292,6 @@ int main(int argc, char **argv) { case CREATE: create_archive(argv + p.vararg_index, argc, p); } - params_free(p); + free(p.out); return EXIT_SUCCESS; } diff --git a/src/table.c b/src/table.c index 1bb14cc..7e11668 100644 --- a/src/table.c +++ b/src/table.c @@ -41,11 +41,14 @@ static void read_segm(struct stream *s, struct table_entry *tmp, uint64_t count) { tmp->segment_count = count; tmp->segments = malloc(sizeof(struct segment *) * count); - if (tmp->segments == NULL) return; + if (tmp->segments == NULL) + return; for (uint64_t i = 0; i < count; i++) { tmp->segments[i] = malloc(sizeof(struct segment)); - if (tmp->segments[i] == NULL) return; + if (tmp->segments[i] == NULL) + return; + stream_read(&tmp->segments[i]->compressed, s, sizeof(uint32_t)); stream_read(&tmp->segments[i]->offset, s, sizeof(uint64_t)); stream_read(&tmp->segments[i]->decompressed_size, s, sizeof(uint64_t)); @@ -108,11 +111,14 @@ static void dump_time(struct stream *s, uint64_t timestamp) { will be modified. Otherwise, a new entry will be created and appended to the linked list. */ void read_file(struct stream *s, struct table_entry *root) { - bool ended = false; - uint32_t magic; - uint64_t size; + bool ended = false; + uint32_t magic; + uint64_t size; struct table_entry *cur, *tmp = calloc(sizeof(struct table_entry), 1); + if (tmp == NULL) + return; + do { stream_read(&magic, s, sizeof(uint32_t)); stream_read(&size, s, sizeof(uint64_t)); @@ -137,6 +143,11 @@ void read_file(struct stream *s, struct table_entry *root) { } while (!ended); cur = get_node(root, tmp->key); + if (cur == NULL) { + free(tmp); + return; + } + cur->segment_count = tmp->segment_count; cur->segments = tmp->segments; cur->ctime = tmp->ctime; @@ -179,14 +190,15 @@ void read_elif(struct stream *s, struct table_entry *root) { name_len = name_len * 2 + 2; cur = get_node(root, key); - if (cur->filename != NULL) { + if (cur == NULL || cur->filename != NULL) { return; } if (name_len < 0x100) { buf = malloc(name_len); name = malloc(name_len); - if (buf == NULL || name == NULL) return; + if (buf == NULL || name == NULL) + return; stream_read(buf, s, name_len); utf16le_decode(buf, name, name_len); @@ -199,12 +211,13 @@ void read_elif(struct stream *s, struct table_entry *root) { } name = tmp; } else { - /* strdup isn't defined in ISO/IEC 9899:1999 C. */ name = malloc(14); - if (name == NULL) return; + if (name == NULL) + return; strncpy(name, "COPYRIGHT.txt", 14); stream_seek(s, name_len, SEEK_CUR); } + cur->filename = name; } @@ -229,6 +242,8 @@ static void dump_elif(struct stream *s, struct table_entry *cur) { in the archive's table section. */ struct table_entry *read_table(struct stream *s) { struct table_entry *root = calloc(sizeof(struct table_entry), 1); + if (root == NULL) + return NULL; bool ended = false; uint32_t magic; @@ -292,7 +307,9 @@ struct table_entry *get_node(struct table_entry *root, uint32_t key) { for (cur = root; cur != NULL && cur->key != key; cur = cur->next); if (cur == NULL) { cur = calloc(sizeof(struct table_entry), 1); - if (cur == NULL) return NULL; + if (cur == NULL) + return NULL; + entry_append(root, cur); cur->key = key; } |