diff options
| author | jakob <jakob@memeware.net> | 2017-06-06 15:40:40 -0400 |
|---|---|---|
| committer | jakob <jakob@memeware.net> | 2017-06-06 15:40:40 -0400 |
| commit | cfd5fb6e6fb47e084e66e1e4e2d6a99f19be661e (patch) | |
| tree | 5fcfe91127c67f6dbb94a81848e8c1b9e6ddea7d | |
| parent | 17b658ceadd08d693f23448c276958e2eea5970e (diff) | |
Cleaned up
| -rw-r--r-- | README.md | 5 | ||||
| -rw-r--r-- | src/cli.c | 18 | ||||
| -rw-r--r-- | src/cli.h | 1 | ||||
| -rw-r--r-- | src/compress.c | 16 | ||||
| -rw-r--r-- | src/compress.h | 8 | ||||
| -rw-r--r-- | src/header.c | 32 | ||||
| -rw-r--r-- | src/main.c | 44 | ||||
| -rw-r--r-- | test/test_cli.c | 16 | ||||
| -rw-r--r-- | test/test_compress.c | 72 | ||||
| -rw-r--r-- | test/test_compress.h | 23 | ||||
| -rw-r--r-- | test/test_run.c | 3 | ||||
| -rw-r--r-- | test/vectors/test.bin | bin | 0 -> 176569 bytes | |||
| -rwxr-xr-x | test/vectors/test.png | bin | 0 -> 176608 bytes |
13 files changed, 150 insertions, 88 deletions
@@ -18,7 +18,8 @@ You can add specific flags to the Makefile with `USER_CFLAGS` and/or `USER_LDFLA ## TODO -* Full unit testing. +* Full unit testing, test static functions. * Clean up `main.c`, move functions like `load_table` and `make_dirs` into more appropriate files. +* Clean up `create_archive`. * Strict warnings. - +* Game-compatible file encryption on created archives. @@ -26,15 +26,20 @@ #include "cli.h" #include "crypto.h" -#define NEKOPACK_VERSION "2.1.0b1" +#define NEKOPACK_VERSION "2.1.0" -/* Copies `optarg` into the out field of `p` and ensures that it ends in - a trailing path delimiter. */ +/* Copies `optarg` into the out member of `p` and ensures that it has 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); + + if (p->out == NULL) + return; + strcpy(p->out, optarg); + if (p->out[p->out_len - 1] != '/') { p->out[p->out_len] = '/'; p->out_len += 1; @@ -78,7 +83,6 @@ 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} @@ -86,7 +90,7 @@ struct params parse_args(int argc, char **argv) { do { count++; - cur = getopt_long(argc, argv, "hVvelcdqo:g:", long_opts, &opt_index); + cur = getopt_long(argc, argv, "hVvelcqo:g:", long_opts, &opt_index); switch (cur) { case 'h': p.mode = HELP; @@ -120,10 +124,6 @@ struct params parse_args(int argc, char **argv) { case 'c': p.mode = CREATE; - break; - - case 'd': - p.mode = DEBUG; } } while (cur >= 0); @@ -30,7 +30,6 @@ 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 e61780d..4df5ef7 100644 --- a/src/compress.c +++ b/src/compress.c @@ -26,7 +26,10 @@ #define LEVEL -1 -/* Inflates `s` into a newly allocated stream structure. */ +/* Inflates `len` bytes from the current position of `s` to a new stream + structure of size `decompressed_len` bytes. Stream inflation will not + work if `decompressed_len` does not represent the actual size of the + original data. */ struct stream *stream_inflate(struct stream *s, size_t len, size_t decompressed_len) { z_stream strm; @@ -40,17 +43,17 @@ struct stream *stream_inflate(struct stream *s, size_t len, return NULL; int ret; - struct stream *n = stream_new(decompressed_len); + struct stream *new = stream_new(decompressed_len); do { strm.avail_in = len; strm.next_in = (Bytef *) s->_cur; do { strm.avail_out = decompressed_len; - strm.next_out = (Bytef *) n->_cur; + strm.next_out = (Bytef *) new->_cur; ret = inflate(&strm, Z_NO_FLUSH); if (ret == Z_STREAM_ERROR) { - stream_free(n); + stream_free(new); inflateEnd(&strm); return NULL; } @@ -58,11 +61,12 @@ struct stream *stream_inflate(struct stream *s, size_t len, } while (ret != Z_STREAM_END); inflateEnd(&strm); - return n; + return new; } -/* Deflates `s` into a newly allocated stream structure. */ +/* Deflates `len` bytes from the current position of `s` to a new stream + structure, where the `len` member represents the decompressed size. */ struct stream *stream_deflate(struct stream *s, size_t len) { struct stream *new = stream_new(len); if (new == NULL) diff --git a/src/compress.h b/src/compress.h index cfb2487..e885231 100644 --- a/src/compress.h +++ b/src/compress.h @@ -21,9 +21,13 @@ #include "io.h" -/* Inflates `s` into a newly allocated stream structure. */ +/* Inflates `len` bytes from the current position of `s` to a new stream + structure of size `decompressed_len` bytes. Stream inflation will not + work if `decompressed_len` does not represent the actual size of the + original data. */ struct stream *stream_inflate(struct stream *s, size_t len, size_t decompressed_len); -/* Deflates `s` into a newly allocated stream structure. */ +/* Deflates `len` bytes from the current position of `s` to a new stream + structure, where the `len` member represents the decompressed size. */ struct stream *stream_deflate(struct stream *s, size_t len); diff --git a/src/header.c b/src/header.c index 86f5e25..11dc654 100644 --- a/src/header.c +++ b/src/header.c @@ -39,6 +39,22 @@ static bool is_supported(struct header *h) { } +/* Generates an XP3 header structure readable by Nekopara. */ +struct header *create_header(void) { + struct header *h = malloc(sizeof(struct header)); + if (h == NULL) + return NULL; + + memcpy(h->magic, XP3_MAGIC, 11); + h->info_offset = 0x17; + h->version = 1; + h->flags = 0x80; + h->table_size = 0; + h->table_offset = 0; + return h; +} + + /* Reads from the given stream into a newly allocated header structure. NULL is returned if the header contains an invalid magic number, or if the archive's version is not supported. */ @@ -63,22 +79,6 @@ struct header *read_header(struct stream *s) { } -/* Generates an XP3 header structure readable by Nekopara. */ -struct header *create_header(void) { - struct header *h = malloc(sizeof(struct header)); - if (h == NULL) - return NULL; - - memcpy(h->magic, XP3_MAGIC, 11); - h->info_offset = 0x17; - h->version = 1; - h->flags = 0x80; - h->table_size = 0; - h->table_offset = 0; - return h; -} - - /* Dumps the XP3 header specified by `h` into `fp`. */ void dump_header(FILE *fp, struct header *h) { fwrite(h->magic, 11, 1, fp); @@ -17,7 +17,6 @@ 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> @@ -35,9 +34,6 @@ #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; @@ -245,7 +241,6 @@ static void create_archive(char **paths, int argc, struct params p) { return; } - /* TODO: Separate into own function. */ table_size += 20 + strlen(cur->filename) * 2; table_size += 28 * cur->segment_count + 60; @@ -286,11 +281,9 @@ static void create_archive(char **paths, int argc, struct params p) { h->table_offset = 40 + data->len; dump_header(fp, h); - /* FIXME: Formatting and this initial seek might not be necessary. */ stream_seek(data, 0, SEEK_SET); stream_dump(fp, data, data->len); - /* FIXME: May be an incompatible value. Also, move this shitty hack. */ uint8_t compressed = 1; fwrite(&compressed, sizeof(uint8_t), 1, fp); fwrite(&table_compressed->len, sizeof(uint64_t), 1, fp); @@ -300,38 +293,6 @@ 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) { @@ -354,11 +315,6 @@ 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/test/test_cli.c b/test/test_cli.c index eed7e30..86d6a2e 100644 --- a/test/test_cli.c +++ b/test/test_cli.c @@ -37,19 +37,19 @@ char *test_out_path(void) { } -char *test_vararg_index(void) { - char *argv[] = {"nekopack", "-l", "a.xp3"}; - struct params p = parse_args(3, argv); - mu_assert("Invalid vararg index", !strcmp("a.xp3", argv[p.vararg_index])); +char *test_game_id(void) { + char *argv[] = {"nekopack", "-g", "nekopara_volume_1", "a.xp3"}; + struct params p = parse_args(4, argv); + mu_assert("Incorrect game ID", p.game == NEKOPARA_VOLUME_1); free(p.out); return NULL; } -char *test_game_id(void) { - char *argv[] = {"nekopack", "-g", "nekopara_volume_1", "a.xp3"}; - struct params p = parse_args(4, argv); - mu_assert("Incorrect game ID", p.game == NEKOPARA_VOLUME_1); +char *test_vararg_index(void) { + char *argv[] = {"nekopack", "-l", "a.xp3"}; + struct params p = parse_args(3, argv); + mu_assert("Invalid vararg index", !strcmp("a.xp3", argv[p.vararg_index])); free(p.out); return NULL; } diff --git a/test/test_compress.c b/test/test_compress.c new file mode 100644 index 0000000..583dd8b --- /dev/null +++ b/test/test_compress.c @@ -0,0 +1,72 @@ +/* test_compress.c -- MinUnit test cases for compress.c + + Copyright (C) 2017 Jakob Kreuze, All Rights Reserved. + + This file is part of Nekopack. + + Nekopack is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation, either version 3 of the License, or (at + your option) any later version. + + Nekopack is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Nekopack. If not, see <http://www.gnu.org/licenses/>. */ + +#include <stdbool.h> + +#include "minunit.h" + +#include "compress.h" +#include "io.h" + +extern int tests_run; + +/* FIXME: This won't hold up for the future. Even if it works across + different versions of zlib, if the compression rate is ever changed + this test will fail. */ + +/* TODO: Replace with a proper stream comparison and put it in io.c? */ +static bool streams_eq(struct stream *a, struct stream *b) { + if (a->len != b->len) + return false; + for (unsigned long i = 0; i < a->len; i++) { + if (a->_start[i] != b->_start[i]) + return false; + } + return true; +} + + +char *test_compress(void) { + struct stream *s = stream_from_file("test/vectors/test.png"); + struct stream *expected = stream_from_file("test/vectors/test.bin"); + mu_assert("Could not open test vectors", s != NULL && expected != NULL); + + struct stream *res = stream_deflate(s, s->len); + mu_assert("Expected compression not met", streams_eq(res, expected)); + + stream_free(s); + stream_free(expected); + stream_free(res); + return NULL; +} + + +char *test_decompress(void) { + struct stream *s = stream_from_file("test/vectors/test.bin"); + struct stream *expected = stream_from_file("test/vectors/test.png"); + mu_assert("Could not open test vectors", s != NULL && expected != NULL); + + struct stream *res = stream_inflate(s, s->len, 176608); + mu_assert("Expected compression not met", streams_eq(res, expected)); + + stream_free(s); + stream_free(expected); + stream_free(res); + return NULL; +} diff --git a/test/test_compress.h b/test/test_compress.h new file mode 100644 index 0000000..0a1f3ea --- /dev/null +++ b/test/test_compress.h @@ -0,0 +1,23 @@ +/* test_compress.h -- MinUnit test cases for compress.c + + Copyright (C) 2017 Jakob Kreuze, All Rights Reserved. + + This file is part of Nekopack. + + Nekopack is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation, either version 3 of the License, or (at + your option) any later version. + + Nekopack is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Nekopack. If not, see <http://www.gnu.org/licenses/>. */ + +#pragma once + +char *test_compress(void); +char *test_decompress(void); diff --git a/test/test_run.c b/test/test_run.c index f1dc80e..4263c7f 100644 --- a/test/test_run.c +++ b/test/test_run.c @@ -22,6 +22,7 @@ #include "minunit.h" #include "test_cli.h" +#include "test_compress.h" #include "test_crypto.h" #include "test_encoding.h" #include "test_header.h" @@ -35,6 +36,8 @@ static char *run_all_tests(void) { mu_run_test(test_out_path); mu_run_test(test_vararg_index); mu_run_test(test_game_id); + mu_run_test(test_compress); + mu_run_test(test_decompress); mu_run_test(test_derive_initial); mu_run_test(test_derive_primary); mu_run_test(test_stream_obj); diff --git a/test/vectors/test.bin b/test/vectors/test.bin Binary files differnew file mode 100644 index 0000000..19fd87b --- /dev/null +++ b/test/vectors/test.bin diff --git a/test/vectors/test.png b/test/vectors/test.png Binary files differnew file mode 100755 index 0000000..8fee322 --- /dev/null +++ b/test/vectors/test.png |