diff options
| -rw-r--r-- | GNUmakefile | 4 | ||||
| -rw-r--r-- | src/cli.c | 71 | ||||
| -rw-r--r-- | src/cli.h | 27 | ||||
| -rw-r--r-- | src/main.c | 92 |
4 files changed, 151 insertions, 43 deletions
diff --git a/GNUmakefile b/GNUmakefile index 087d2df..9ffc063 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -5,8 +5,8 @@ SHELL = /bin/sh CC := gcc LD := gcc -CFLAGS := -Wall -Wextra -Os -funroll-all-loops -g -LDFLAGS := -flto -lncurses +CFLAGS := -Wall -Wextra -Os -funroll-all-loops +LDFLAGS := -lz STRIPARGS := -s -p SRCDIR = src diff --git a/src/cli.c b/src/cli.c new file mode 100644 index 0000000..9394424 --- /dev/null +++ b/src/cli.c @@ -0,0 +1,71 @@ +/* This file is part of Nekopack. + + Copyright (C) 2017 Jakob Tsar-Fox, All Rights Reserved. + + 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 <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <getopt.h> + +#include "cli.h" + +#define VERSION "0.1.0" +#define HELP_TEXT "A tool for decompressing the XP3 archives used by " \ + "Nekopara.\n\n" \ + " -h, --help\t\tDisplay this help page and " \ + "exit.\n" \ + " -v, --version\tDisplay the currently installed " \ + "version and exit.\n\n" + + +/* General subroutine for parsing command-line arguments. Returns a + "configuration" structure containing everything parsed from argv. */ +struct configuration parse_args(int argc, char *argv[]) { + if (argc != 2) { + fprintf(stderr, "Usage: %s [OPTIONS] (ARCHIVE PATH)\n", argv[0]); + exit(1); + } + + /* The struct has to be zeroed out, otherwise argument parsing + becomes irrelevant and the program will not act as expected. */ + struct configuration parsed; + memset(&parsed, 0, sizeof(parsed)); + + int current = 0, option_index = 0; + static struct option long_options[] = { + {"help", no_argument, NULL, 'h'}, + {"version", no_argument, NULL, 'v'}, + {NULL, 0, NULL, 0} + }; + + while (current >= 0) { + current = getopt_long(argc, argv, "hv", long_options, &option_index); + + switch (current) { + case 'h': + printf("Usage: %s [OPTIONS] (ARCHIVE PATH)\n\n", argv[0]); + printf("%s\n", HELP_TEXT); + exit(0); + case 'v': + printf("Nekopack, version %s\nProgrammed by " + "Jakob. <http://tsar-fox.com/>\n", VERSION); + exit(0); + } + } + + return parsed; +} diff --git a/src/cli.h b/src/cli.h new file mode 100644 index 0000000..7fac33b --- /dev/null +++ b/src/cli.h @@ -0,0 +1,27 @@ +/* This file is part of Nekopack. + + Copyright (C) 2017 Jakob Tsar-Fox, All Rights Reserved. + + 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 + +/* Binary structure for storing command-line options. */ +struct configuration { + long long padding; +}; + +/* General subroutine for parsing command-line arguments. Returns a + "configuration" structure containing everything parsed from argv. */ +struct configuration parse_args(int argc, char *argv[]); @@ -1,10 +1,6 @@ -/* main.c +/* This file is part of Nekopack. - The entry point to Nekopack. - - Copyright (C) 2013 Jakob Tsar-Fox, All Rights Reserved. - - This file is part of Nekopack. + Copyright (C) 2017 Jakob Tsar-Fox, All Rights Reserved. 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 @@ -19,35 +15,38 @@ 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> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <zlib.h> + +#include "cli.h" + #define XP3_MAGIC "XP3\x0d\x0a\x20\x0a\x1a\x8b\x67\x01" #define XP3_VERSION_1_TABLE_OFFSET 11 #define XP3_VERSION_OFFSET 19 +#define EXIT_SUCCESS 0 +#define EXIT_FAILURE 1 + int is_xp3_archive(FILE *archive); int get_archive_version(FILE *archive); -int get_table_offset(FILE *archive, uint8_t archive_version); -int table_is_compressed(FILE *archive, uint8_t table_offset); +uint8_t table_is_compressed(FILE *archive, uint8_t table_offset); +uint64_t get_table_offset(FILE *archive, uint8_t archive_version); int main(int argc, char *argv[]) { - if (argc != 2) { - fprintf(stderr, "Usage: %s (PATH TO ARCHIVE)\n", argv[0]); - exit(1); - } - uint8_t archive_version; + struct configuration arguments = parse_args(argc, argv); + FILE *archive = fopen(argv[1], "rb"); if (!is_xp3_archive(archive)) { fprintf(stderr, "File is not an XP3 archive.\n"); fclose(archive); - exit(1); + exit(EXIT_FAILURE); } - archive_version = get_archive_version(archive); /* After the table_is_compressed byte is 8 bytes containing the compressed size followed by 8 bytes containing the original size (if the archive is compressed). Use zlib's inflate function to @@ -67,50 +66,61 @@ int main(int argc, char *argv[]) { } -/* Returns whether or not the stream represents an XP3 archive. */ +/* Very simple check of the archive's magic number to decide + whether or not it really is a valid XP3 archive. */ int is_xp3_archive(FILE *archive) { - char *magic_buffer = malloc(12); - if (magic_buffer == NULL) { - perror("calloc"); - fclose(archive); - exit(1); - } + char magic_buffer[12] = {0}; rewind(archive); - fread(magic_buffer, 11, 1, archive); - if (strcmp(magic_buffer, XP3_MAGIC)) { - printf("Not an XP3 archive\n"); + fread(magic_buffer, sizeof(magic_buffer) - 1, 1, archive); + if (strcmp(magic_buffer, XP3_MAGIC)) return 0; - } return 1; } -/* Returns the version of (???) used to pack the archive. */ +/* Returns the version of XP3 used to pack the archive. */ int get_archive_version(FILE *archive) { - uint8_t archive_version; + uint32_t version_word; fseek(archive, XP3_VERSION_OFFSET, SEEK_SET); - fread(&archive_version, 1, 1, archive); - return archive_version; + fread(&version_word, sizeof(uint32_t), 1, archive); + return version_word == 1 ? 2 : 1; } -/* Returns the table offset for the archive. */ -int get_table_offset(FILE *archive, uint8_t archive_version) { +/* Subroutine for finding the archive's table offset. If the + minor_version is invalid, the program will exit. */ +uint64_t get_table_offset(FILE *archive, uint8_t archive_version) { + fseek(archive, XP3_VERSION_1_TABLE_OFFSET, SEEK_SET); if (archive_version == 1) { - uint8_t table_offset; - fseek(archive, XP3_VERSION_1_TABLE_OFFSET, SEEK_SET); - fread(&table_offset, 1, 1, archive); + uint64_t table_offset; + fread(&table_offset, sizeof(uint64_t), 1, archive); return table_offset; } - fprintf(stderr, "Not implemented.\n"); - exit(1); + uint64_t additional_header_offset, table_offset; + uint32_t minor_version; + fread(&additional_header_offset, sizeof(uint64_t), 1, archive); + fread(&minor_version, sizeof(uint32_t), 1, archive); + if (minor_version != 1) { + fprintf(stderr, "Version not implemented.\n"); + exit(EXIT_FAILURE); + } + fseek(archive, additional_header_offset, SEEK_CUR); + fseek(archive, sizeof(uint8_t) + sizeof(uint64_t), SEEK_CUR); + fread(&table_offset, sizeof(uint64_t), 1, archive); + return table_offset; } -/* Returns whether or not the archive is compressed. */ -int table_is_compressed(FILE *archive, uint8_t table_offset) { +/* Function that returns the byte representing + whether or not the archive was compressed. */ +uint8_t table_is_compressed(FILE *archive, uint8_t table_offset) { uint8_t is_compressed; fseek(archive, table_offset, SEEK_SET); - fread(&is_compressed, 1, 1, archive); + fread(&is_compressed, sizeof(uint8_t), 1, archive); return is_compressed; } + + +void *inflate_table(FILE *archive, uint8_t table_offset) { + return 0x0; +} |