summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/cli.c141
-rw-r--r--src/cli.h50
-rw-r--r--src/crypto.c77
-rw-r--r--src/crypto.h39
-rw-r--r--src/decompress.c98
-rw-r--r--src/decompress.h33
-rw-r--r--src/defs.h27
-rw-r--r--src/extract.c188
-rw-r--r--src/extract.h42
-rw-r--r--src/file.c137
-rw-r--r--src/file.h42
-rw-r--r--src/io.c69
-rw-r--r--src/io.h57
-rw-r--r--src/main.c137
-rw-r--r--src/write.c201
-rw-r--r--src/write.h42
16 files changed, 129 insertions, 1251 deletions
diff --git a/src/cli.c b/src/cli.c
deleted file mode 100644
index 3891032..0000000
--- a/src/cli.c
+++ /dev/null
@@ -1,141 +0,0 @@
-/* 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"
-#include "defs.h"
-
-#define VERSION "1.0.0.rc1"
-#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" \
- " -e, --extract\tExtract the contents of the archive. " \
- "This is the default.\n" \
- " -l, --list\t\tList the contents of the archive.\n\n" \
- " -o, --output\t\tPath to extract files to.\n" \
- " -g, --game\t\tGame the archive is from. Required for " \
- "file decryption\n" \
- " -q, --quiet\t\tDon't display information about " \
- "extracted files."
-#define GAME_CONSTANTS "none, nekopara_volume_0, nekopara_volume_0_steam, " \
- "nekopara_volume_1, nekopara_volume_1_steam"
-
-
-/* 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(EXIT_FAILURE);
- }
-
- /* 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));
-
- /* count represents the number of options parsed, regardless of
- whether or not they were "long." This is kept track of so that
- the user can supply an archive path as a positional argument. */
- int current = 0, option_index = 0, count = 0;
- static struct option long_options[] = {
- {"help", no_argument, NULL, 'h'},
- {"version", no_argument, NULL, 'v'},
- {"quiet", no_argument, NULL, 'q'},
- {"extract", no_argument, NULL, 'e'},
- {"list", no_argument, NULL, 'l'},
- {"output", required_argument, NULL, 'o'},
- {"game", required_argument, NULL, 'g'},
- {NULL, 0, NULL, 0}
- };
-
- do {
- current = getopt_long(argc, argv, "hvelqo:g:", long_options,
- &option_index);
- switch (current) {
- case 'h':
- printf("Usage: %s [OPTIONS] (ARCHIVE PATH)\n\n", argv[0]);
- printf("%s\n\n", HELP_TEXT);
- printf("Supported Game Crypto:\n%s\n", GAME_CONSTANTS);
- exit(EXIT_SUCCESS);
- case 'v':
- printf("Nekopack, version %s\nProgrammed by "
- "Jakob. <http://tsar-fox.com/>\n", VERSION);
- exit(EXIT_SUCCESS);
- case 'q':
- parsed.quiet = 1;
- break;
- case 'o':
- count++;
- size_t path_size = strlen(optarg);
- parsed.output = malloc(path_size + 1);
- strcpy(parsed.output, optarg);
- if (parsed.output[path_size - 1] != PATH_DELIMITER)
- parsed.output[path_size] = PATH_DELIMITER;
- break;
- case 'g':
- count++;
- /* Out of concern for efficiency, string comparisons are
- done here and the source game is stored in an enum. */
- if (!strcmp(optarg, "nekopara_volume_0"))
- parsed.game = NEKOPARA_VOLUME_0;
- else if (!strcmp(optarg, "nekopara_volume_0_steam"))
- parsed.game = NEKOPARA_VOLUME_0_STEAM;
- else if (!strcmp(optarg, "nekopara_volume_1"))
- parsed.game = NEKOPARA_VOLUME_1;
- else if (!strcmp(optarg, "nekopara_volume_1_steam"))
- parsed.game = NEKOPARA_VOLUME_1_STEAM;
- else
- parsed.game = NO_CRYPTO;
- break;
- case 'e':
- /* Despite being the default, '-e' is
- still parsed to provide consisency. */
- parsed.mode = EXTRACT;
- break;
- case 'l':
- parsed.mode = LIST;
- }
- count++;
- } while (current >= 0);
-
- /* getopt pushes non-flag arguments to the end of argv, and `count`
- is only incremented when a flag argument is parsed. */
- if (count == argc) {
- fprintf(stderr, "No archive path provided.\n");
- exit(EXIT_FAILURE);
- }
- parsed.vararg_index = count;
-
- /* The output path is allocated on the heap to simplify freeing. */
- if (parsed.output == NULL) {
- if ((parsed.output = strdup(".")) == NULL) {
- fprintf(stderr, "Insufficient memory.\n");
- exit(EXIT_FAILURE);
- }
- }
-
- return parsed;
-}
diff --git a/src/cli.h b/src/cli.h
deleted file mode 100644
index d16d4a7..0000000
--- a/src/cli.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/* 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
-
-/* Enumerable type representing Nekopara games, as they have different
- encryption keys. It's stored as an enum because multiple strcmp calls
- to figure out how to decrypt is a waste of processor cycles. */
-typedef enum game_type {
- NO_CRYPTO,
- NEKOPARA_VOLUME_0,
- NEKOPARA_VOLUME_0_STEAM,
- NEKOPARA_VOLUME_1,
- NEKOPARA_VOLUME_1_STEAM,
-} game_type;
-
-/* Enumerable type for mode of operation. Used in the main function
- to decide what to do after the initial XP3 sanity checks. */
-typedef enum mode_type {
- EXTRACT,
- LIST,
-} mode_type;
-
-/* Binary structure for storing command-line options. */
-struct configuration {
- int quiet; /* Level of output verbosity. */
- int vararg_index; /* Index of where a variadic list of paths starts. */
- game_type game; /* Which decryption key to use. */
- mode_type mode; /* What to do after initial sanity checks. */
- char *output; /* Path to extract files to. */
- const char *archive; /* Path to archive to extract. */
-};
-
-/* General subroutine for parsing command-line arguments. Returns a
- "configuration" structure containing everything parsed from argv. */
-struct configuration parse_args(int argc, char *argv[]);
diff --git a/src/crypto.c b/src/crypto.c
deleted file mode 100644
index 1172644..0000000
--- a/src/crypto.c
+++ /dev/null
@@ -1,77 +0,0 @@
-/* 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 "cli.h"
-#include "crypto.h"
-
-
-/* Returns the encryption keys for a given game value. */
-key get_encryption_key(game_type game) {
- key encryption_key;
- switch (game) {
- case NEKOPARA_VOLUME_0:
- encryption_key.master_key = 0x1548e29c;
- encryption_key.initial_fallback_key = 0x9c;
- encryption_key.primary_fallback_key = 0xd7;
- encryption_key.uses_initial_key = 1;
- break;
- case NEKOPARA_VOLUME_0_STEAM:
- encryption_key.master_key = 0x44528b87;
- encryption_key.initial_fallback_key = 0x87;
- encryption_key.primary_fallback_key = 0x23;
- encryption_key.uses_initial_key = 1;
- break;
- case NEKOPARA_VOLUME_1:
- encryption_key.master_key = 0x1548e29c;
- encryption_key.initial_fallback_key = 0x00;
- encryption_key.primary_fallback_key = 0xd7;
- encryption_key.uses_initial_key = 0;
- break;
- case NEKOPARA_VOLUME_1_STEAM:
- encryption_key.master_key = 0x44528b87;
- encryption_key.initial_fallback_key = 0x00;
- encryption_key.primary_fallback_key = 0x23;
- encryption_key.uses_initial_key = 0;
- break;
- default:
- encryption_key.master_key = 0x00000000;
- encryption_key.initial_fallback_key = 0x00;
- encryption_key.primary_fallback_key = 0x00;
- encryption_key.uses_initial_key = 0;
- }
- return encryption_key;
-}
-
-
-/* Decrypts the contents of a buffer according to a file key. */
-void decrypt_buffer(Bytef *encrypted_buffer, uint64_t buffer_length,
- key encryption_key, uint32_t file_key) {
- uint32_t xor_key = file_key ^ encryption_key.master_key;
- uint8_t initial_key = xor_key & 0xff;
- uint8_t primary_key = (xor_key >> 24 ^ xor_key >> 16 ^ \
- xor_key >> 8 ^ xor_key) & 0xff;
- if (primary_key == 0)
- primary_key = encryption_key.primary_fallback_key;
- if (encryption_key.uses_initial_key) {
- if (initial_key == 0)
- initial_key = encryption_key.initial_fallback_key;
- encrypted_buffer[0] ^= initial_key;
- }
- for (uint64_t i = 0; i < buffer_length; i++) {
- encrypted_buffer[i] ^= primary_key;
- }
-}
diff --git a/src/crypto.h b/src/crypto.h
deleted file mode 100644
index f8d5d86..0000000
--- a/src/crypto.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/* 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
-
-#include <stdint.h>
-
-#include <zlib.h>
-
-#include "cli.h"
-
-/* Struct for a game's encryption keys. */
-typedef struct {
- int uses_initial_key; /* Set if first byte uses a different key. */
- uint32_t master_key; /* Master key used to derive a key. */
- uint8_t initial_fallback_key; /* Fallback for the initial key. */
- uint8_t primary_fallback_key; /* Fallback for the primary key. */
-} key;
-
-/* Returns the encryption keys for a given game value. */
-key get_encryption_key(game_type game);
-
-/* Decrypts the contents of a buffer according to a file key. */
-void decrypt_buffer(Bytef *encrypted_buffer, uint64_t buffer_length,
- key encryption_key, uint32_t file_key);
diff --git a/src/decompress.c b/src/decompress.c
deleted file mode 100644
index 9a8ec64..0000000
--- a/src/decompress.c
+++ /dev/null
@@ -1,98 +0,0 @@
-/* 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 <zlib.h>
-
-#include "defs.h"
-#include "extract.h"
-
-
-/* Inflates a chunk into new space in memory. NULL is returned if not
- enough memory can be allocated to contain the decompressed data. */
-Bytef *inflate_chunk(Bytef *chunk, uint64_t chunk_size,
- uint64_t decompressed_size) {
- Bytef *decompressed_data = malloc(decompressed_size);
-
- if (decompressed_data == NULL) {
- fprintf(stderr, "Insufficient memory to decompress archive.\n");
- free(decompressed_data);
- return NULL;
- }
-
- z_stream data_stream;
- data_stream.zalloc = Z_NULL;
- data_stream.zfree = Z_NULL;
- data_stream.opaque = Z_NULL;
- data_stream.avail_in = 0;
- data_stream.next_in = Z_NULL;
-
- if (inflateInit(&data_stream) != Z_OK) {
- fprintf(stderr, "Could not initialize zlib.\n");
- free(decompressed_data);
- return NULL;
- }
-
- int status_code;
- do {
- data_stream.avail_in = chunk_size;
- if (data_stream.avail_in == 0)
- break;
- data_stream.next_in = chunk;
- do {
- data_stream.avail_out = decompressed_size;
- data_stream.next_out = decompressed_data;
- status_code = inflate(&data_stream, Z_NO_FLUSH);
- } while (data_stream.avail_out == 0);
- } while (status_code != Z_STREAM_END);
-
- inflateEnd(&data_stream);
- return decompressed_data;
-}
-
-
-/* Decompresses the contents of a memory_stream data structure.
- Program exits if not enough memory can be allocated. */
-memory_stream decompress_stream(memory_stream compressed_data, uint64_t size) {
- uint64_t chunk_size = compressed_data.stream_length;
- Bytef *decompressed_data, *chunk = compressed_data.start;
-
- decompressed_data = inflate_chunk(chunk, chunk_size, size);
- if (decompressed_data == NULL) {
- free(chunk);
- exit(EXIT_FAILURE);
- }
-
- return (memory_stream) {size, decompressed_data, decompressed_data};
-}
-
-
-/* Reads a FILE pointer into a memory_stream data structure. */
-memory_stream read_to_stream(FILE *archive, uint64_t buffer_size) {
- Bytef *buffer = malloc(buffer_size);
- /* This is a pretty shitty way of handling it. */
- if (buffer == NULL) {
- fprintf(stderr, "Insufficient memory to load archive.\n");
- free(buffer);
- fclose(archive);
- exit(EXIT_FAILURE);
- }
- fread(buffer, buffer_size, 1, archive);
- return (memory_stream) {buffer_size, buffer, buffer};
-}
diff --git a/src/decompress.h b/src/decompress.h
deleted file mode 100644
index dcb985b..0000000
--- a/src/decompress.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/* 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
-
-#include <zlib.h>
-
-#include "extract.h"
-
-/* Decompresses a memory_stream data structure into a new one. */
-memory_stream decompress_stream(memory_stream compressed_data, uint64_t size);
-
-/* Reads a FILE pointer into a memory_stream data structure. */
-memory_stream read_to_stream(FILE *archive, uint64_t buffer_size);
-
-/* Returns a pointer to a buffer containing the
- inflated contents of a given memory chunk. */
-Bytef *inflate_chunk(Bytef *chunk, uint64_t chunk_size,
- uint64_t decompressed_size);
diff --git a/src/defs.h b/src/defs.h
deleted file mode 100644
index 15ce5ee..0000000
--- a/src/defs.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/* 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
-
-#define EXIT_SUCCESS 0
-#define EXIT_FAILURE 1
-
-#ifdef WINDOWS
-#define PATH_DELIMITER '\\'
-#else
-#define PATH_DELIMITER '/'
-#endif
diff --git a/src/extract.c b/src/extract.c
deleted file mode 100644
index e6476ce..0000000
--- a/src/extract.c
+++ /dev/null
@@ -1,188 +0,0 @@
-/* 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 <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <iconv.h>
-#include <zlib.h>
-
-#include "cli.h"
-#include "defs.h"
-#include "extract.h"
-#include "file.h"
-#include "write.h"
-
-#define ELIF_MAGIC 0x46696c65
-#define FILE_MAGIC 0x656c6946
-#define HNFN_MAGIC 0x6e666e68
-#define NEKO_MAGIC 0x6f6b656e
-
-elif_node *read_elif_entry(memory_stream *data_stream);
-void read_stream(void *destination, Bytef **source, size_t size);
-
-
-/* Decompresses, decrypts, and writes files in the XP3 archive to disk
- according to entries in the table. Will return prematurely if there
- isn't enough memory to store the linked lists. */
-void extract(memory_stream data_stream, FILE *archive) {
- /* eliF and File entries are stored in a linked list as they're
- seen because the order of entries in XP3 archives is not
- guaranteed to be chronological. calloc is used to prevent the
- "next" pointer from being garbage and causing a segfault. */
- elif_node *elif_new, *elif_root = calloc(sizeof(elif_node), 1);
- file_node *file_new, *file_root = calloc(sizeof(file_node), 1);
-
- int stream_ended = 0;
- uint32_t entry_magic;
- uint64_t entry_size;
- do {
- read_stream(&entry_magic, &data_stream.data, sizeof(uint32_t));
- read_stream(&entry_size, &data_stream.data, sizeof(uint64_t));
-
- switch (entry_magic) {
- /* hnfn, neko, and eliF entries are all identical.
-
- The size given by the entry header doesn't match the
- actual entry size, so it isn't passed to the function. */
- case ELIF_MAGIC:
- case HNFN_MAGIC:
- case NEKO_MAGIC:
- elif_new = read_elif_entry(&data_stream);
- if (elif_new == NULL) {
- fprintf(stderr, "Insufficient memory.\n");
- free_elif_nodes(elif_root);
- free_file_nodes(file_root);
- return;
- }
- defer_elif_node(elif_new, elif_root);
- break;
- case FILE_MAGIC:
- file_new = read_file_entry(&data_stream,
- data_stream.data + entry_size);
- if (file_new == NULL) {
- fprintf(stderr, "Insufficient memory.\n");
- free_elif_nodes(elif_root);
- free_file_nodes(file_root);
- return;
- }
- defer_file_node(file_new, file_root);
- break;
- default:
- stream_ended = 1;
- }
- } while (!stream_ended);
-
- write_files(file_root, elif_root, archive);
- free_elif_nodes(elif_root);
- free_file_nodes(file_root);
-}
-
-
-/* Writes the associated filename for each eliF entry in the table. */
-void list(memory_stream data_stream) {
- int stream_ended = 0;
- uint32_t entry_magic;
- uint64_t entry_size;
- elif_node *temporary;
- do {
- read_stream(&entry_magic, &data_stream.data, sizeof(uint32_t));
- read_stream(&entry_size, &data_stream.data, sizeof(uint64_t));
-
- switch (entry_magic) {
- case ELIF_MAGIC:
- case HNFN_MAGIC:
- case NEKO_MAGIC:
- temporary = read_elif_entry(&data_stream);
- printf("%s\n", temporary->file_name);
- free(temporary->file_name);
- free(temporary);
- break;
- case FILE_MAGIC:
- data_stream.data += entry_size;
- break;
- default:
- stream_ended = 1;
- }
- } while (!stream_ended);
-}
-
-
-/* Wrapper for memcpy which increments the source operand
- by the amount of bytes read to simulate a file stream. */
-void read_stream(void *destination, Bytef **source, size_t size) {
- memcpy(destination, *source, size);
- *source += size;
-}
-
-
-/* Creates a node for an eliF entry, which can be deferred in a linked
- list. NULL will be returned if there isn't enough memory to contain
- the node structure or the filenames. */
-elif_node *read_elif_entry(memory_stream *data_stream) {
- uint32_t file_key;
- uint16_t name_size;
- read_stream(&file_key, &data_stream->data, sizeof(uint32_t));
- read_stream(&name_size, &data_stream->data, sizeof(uint16_t));
-
- char *file_name;
- if (name_size < 0x100) {
- /* The filenames are terminated by null bytes,
- but that isn't counted in the name size. */
- char *input_buffer = malloc(name_size * 2 + 2);
- read_stream(input_buffer, &data_stream->data, name_size * 2 + 2);
- if (input_buffer == NULL)
- return NULL;
-
- /* name_size + 1 is unreliable since we're going back to UTF-8
- and some characters (especially Japanese ones) can be wide.
- To compensate we just allocate a buffer that could fit the
- UTF-16LE data and utilize null-bytes to terminate names. */
- file_name = malloc(name_size * 2 + 2);
- if (file_name == NULL) {
- free(input_buffer);
- return NULL;
- }
-
- /* iconv is the less-portable glibc way of doing it. It seems to
- be in the OpenBSD manpages, though, so I'm not worried. */
- size_t in_size = name_size * 2 + 2, out_size = name_size * 2 + 2;
- char *in_start = input_buffer, *out_start = file_name;
- iconv_t conversion = iconv_open("UTF-8", "UTF-16LE");
- iconv(conversion, &in_start, &in_size, &out_start, &out_size);
- iconv_close(conversion);
-
- free(input_buffer);
- } else {
- /* It's safe to assume that a filename that
- large is the flashy copyright notice. */
- data_stream->data += name_size * 2 + 2;
- file_name = strdup("COPYING.txt");
- }
-
- elif_node *parsed = malloc(sizeof(elif_node));
- if (parsed == NULL) {
- free(file_name);
- return NULL;
- }
- parsed->key = file_key;
- parsed->file_name = file_name;
- parsed->next = NULL;
- return parsed;
-}
diff --git a/src/extract.h b/src/extract.h
deleted file mode 100644
index 10965a5..0000000
--- a/src/extract.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/* 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
-
-#include <stdio.h>
-#include <stdint.h>
-
-#include <zlib.h>
-
-/* Structure representing a "stream" in memory. A pointer to the
- start of the memory region is kept for freeing purposes. */
-typedef struct {
- uint64_t stream_length;
- Bytef *start;
- Bytef *data;
-} memory_stream;
-
-/* Decrypts and writes files in the XP3 archive
- to disk according to table entries. */
-void extract(memory_stream data_stream, FILE *archive);
-
-/* Simply lists the contents of an archive, ignoring File entries. */
-void list(memory_stream data_stream);
-
-/* Wrapper for memcpy which increments the source operand by
- the amount of bytes read to simulate a file stream. */
-void read_stream(void *destination, Bytef **source, size_t size);
diff --git a/src/file.c b/src/file.c
deleted file mode 100644
index d2a9b72..0000000
--- a/src/file.c
+++ /dev/null
@@ -1,137 +0,0 @@
-/* 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 <inttypes.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-
-#include "extract.h"
-#include "file.h"
-
-#define ADLR_MAGIC 0x726c6461
-#define SEGM_MAGIC 0x6d676573
-#define INFO_MAGIC 0x6f666e69
-#define TIME_MAGIC 0x656d6974
-
-void read_info_chunk(memory_stream *data_stream, file_node *parsed);
-void read_adlr_chunk(memory_stream *data_stream, file_node *parsed);
-void read_time_chunk(memory_stream *data_stream, file_node *parsed);
-void read_segm_chunk(memory_stream *data_stream, file_node *parsed,
- uint64_t segment_count);
-
-
-/* Creates a node for a File entry, which can be deferred in a linked
- list. NULL will be returned if there isn't enough memory to contain
- the node structure. */
-file_node *read_file_entry(memory_stream *data_stream, Bytef *section_end) {
- uint32_t entry_magic;
- uint64_t entry_size;
- file_node *parsed = calloc(sizeof(file_node), 1);
- if (parsed == NULL)
- return NULL;
- while (data_stream->data < section_end) {
- read_stream(&entry_magic, &data_stream->data, sizeof(uint32_t));
- read_stream(&entry_size, &data_stream->data, sizeof(uint64_t));
- switch (entry_magic) {
- case ADLR_MAGIC:
- read_adlr_chunk(data_stream, parsed);
- break;
- case SEGM_MAGIC:
- /* The segment count is not included in the table and
- has to be calculated. Segments are 28 bytes each. */
- read_segm_chunk(data_stream, parsed, entry_size / 28);
- /* There can't really be a check for this
- in read_segm_chunk, so it's done here. */
- if (parsed->segments == NULL) {
- free(parsed);
- return NULL;
- }
- break;
- case INFO_MAGIC:
- read_info_chunk(data_stream, parsed);
- break;
- case TIME_MAGIC:
- read_time_chunk(data_stream, parsed);
- break;
- default:
- printf("Unknown magic: %" PRIx32 "\n", entry_magic);
- }
- }
- return parsed;
-}
-
-
-/* Reads the contents of an info chunk into a file node. */
-void read_info_chunk(memory_stream *data_stream, file_node *parsed) {
- uint32_t encrypted;
- uint64_t decompressed_size, compressed_size;
- uint16_t file_name_size;
- read_stream(&encrypted, &data_stream->data, sizeof(uint32_t));
- read_stream(&decompressed_size, &data_stream->data, sizeof(uint64_t));
- read_stream(&compressed_size, &data_stream->data, sizeof(uint64_t));
- read_stream(&file_name_size, &data_stream->data, sizeof(uint16_t));
- parsed->encrypted = encrypted;
-
- char *file_name = malloc(file_name_size * 2 + 2);
- read_stream(file_name, &data_stream->data, file_name_size * 2 + 2);
- free(file_name);
-}
-
-
-/* Reads the contents of a segm chunk into a file node. */
-void read_segm_chunk(memory_stream *data_stream, file_node *parsed,
- uint64_t segment_count) {
- /* Segments are stored in an array of segment pointers. */
- segment **segments = malloc(sizeof(segment *) * segment_count);
- if (segments == NULL)
- return;
-
- for (uint64_t i = 0; i < segment_count; i++) {
- segments[i] = malloc(sizeof(segment));
- read_stream(&segments[i]->compressed,
- &data_stream->data,
- sizeof(uint32_t));
- read_stream(&segments[i]->offset,
- &data_stream->data,
- sizeof(uint64_t));
- read_stream(&segments[i]->decompressed_size,
- &data_stream->data,
- sizeof(uint64_t));
- read_stream(&segments[i]->compressed_size,
- &data_stream->data,
- sizeof(uint64_t));
- parsed->file_size += segments[i]->decompressed_size;
- }
- parsed->segment_count = segment_count;
- parsed->segments = segments;
-}
-
-
-/* Reads the contents of an adlr chunk into a file_node. */
-void read_adlr_chunk(memory_stream *data_stream, file_node *parsed) {
- uint32_t key;
- read_stream(&key, &data_stream->data, sizeof(uint32_t));
- parsed->key = key;
-}
-
-
-/* Reads the contents of a time chunk into a file_node. */
-void read_time_chunk(memory_stream *data_stream, file_node *parsed) {
- uint64_t timestamp;
- read_stream(&timestamp, &data_stream->data, sizeof(uint64_t));
-}
diff --git a/src/file.h b/src/file.h
deleted file mode 100644
index 46b6dc0..0000000
--- a/src/file.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/* 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
-
-#include <stdint.h>
-
-/* Structure representing a segment in a file. */
-typedef struct {
- uint32_t compressed; /* Whether or not the chunk is compressed. */
- uint64_t offset; /* Chunk's position in the file as an offset. */
- uint64_t compressed_size; /* Chunk's compressed size. */
- uint64_t decompressed_size; /* Chunk's decompressed size. */
-} segment;
-
-/* Node in a linked list of file entries to write to disk. */
-typedef struct file_node {
- int encrypted; /* Whether or not the entry is encrypted. */
- int compressed; /* Whether or not the entry is compressed. */
- uint32_t key; /* Key associated with matching eliF entry. */
- uint64_t file_size; /* Total size of decompressed file. */
- uint64_t segment_count; /* Number of segments in File entry. */
- segment **segments; /* Data segments associated with the entry. */
- struct file_node *next; /* Pointer to the next node. */
-} file_node;
-
-/* Creates a file node by parsing a file entry. */
-file_node *read_file_entry(memory_stream *data_stream, Bytef *section_end);
diff --git a/src/io.c b/src/io.c
new file mode 100644
index 0000000..2762180
--- /dev/null
+++ b/src/io.c
@@ -0,0 +1,69 @@
+/* io.c -- Code for file and memory I/O.
+
+ Copyright (C) 2017 Jakob Tsar-Fox, 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 <stdint.h>
+#include <string.h>
+
+#include "io.h"
+
+
+/* Allocates `len` bytes of memory and returns a new stream pointing to
+ it. The memory provided has not zeroed. */
+struct stream *stream_new(size_t len) {
+ stream *new = malloc(sizeof(stream));
+ new->len = len;
+ new->_start = malloc(len);
+ new->_cur = new->_start;
+ new->_location = HEAP;
+}
+
+
+/* Called to free or unmap the memory chunk associated with the given
+ stream, as well as the stream structure itself. */
+void stream_free(struct stream *s) {
+ switch (s->_loc) {
+ case HEAP:
+ free(s->_start);
+ }
+ free(s);
+}
+
+
+/* Copies `n` bytes from the given stream into the memory area specified
+ by `dest`. The stream is advanced appropriately. */
+void stream_read(void *dest, struct stream *s, size_t n) {
+ memcpy(dest, s->_cur, n);
+ (char *) s->_cur += n;
+}
+
+
+/* Copies `n` bytes into the given stream from the memory area specified
+ by `src`. The stream is advanced appropriately. */
+void stream_write(struct stream *s, void *src, size_t n) {
+ if (s->cur + n > s->start + s->len) {
+ ptrdiff_t dist = (uintptr_t) s->_cur - (uintptr_t) s->_start;
+ switch(s->_loc) {
+ case HEAP:
+ s->_start = realloc(s->_start, s->len * 2);
+ s->_cur = s->_start + dist;
+ }
+ }
+ memcpy(s->cur, src, n);
+ s->cur += n;
+}
diff --git a/src/io.h b/src/io.h
new file mode 100644
index 0000000..f07a421
--- /dev/null
+++ b/src/io.h
@@ -0,0 +1,57 @@
+/* io.h -- Code for file and memory I/O.
+
+ Copyright (C) 2017 Jakob Tsar-Fox, 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
+
+#include <stdbool.h>
+#include <stddef.h>
+
+/* Internal enumerable type for representing the location of a memory
+ segment. Used for freeing and unmapping purposes, if necessary. */
+enum _location {
+ HEAP,
+}
+
+/* Structure to emulate a stream of data that maintains a current
+ position. The structure additionally maintains a `length` variable
+ containing the stream's length. */
+struct stream {
+ size_t len; /* Length of the stream. */
+ void *_start; /* Pointer to the stream's start. */
+ void *_cur; /* Pointer to the current position. */
+ enum _location _loc; /* Location of the stream in memory. */
+}
+
+/* Allocates `len` bytes of memory and returns a new stream pointing to
+ it. The memory provided has not zeroed. */
+struct stream *stream_new(size_t len);
+
+/* Called to free or unmap the memory chunk 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
+ by `dest`. The stream is advanced appropriately. */
+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 is advanced appropriately. */
+void stream_write(struct stream *s, void *src, size_t n);
diff --git a/src/main.c b/src/main.c
index 2ba65db..892958e 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1,7 +1,9 @@
-/* This file is part of Nekopack.
+/* main.c -- Entry point to Nekopack.
Copyright (C) 2017 Jakob Tsar-Fox, 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
@@ -14,136 +16,3 @@
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 <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "cli.h"
-#include "decompress.h"
-#include "extract.h"
-
-#define XP3_MAGIC "XP3\x0d\x0a\x20\x0a\x1a\x8b\x67\x01"
-#define XP3_TABLE_OFFSET 11
-#define XP3_VERSION_OFFSET 19
-
-void handle_archive(char *path);
-int is_xp3_archive(FILE *archive);
-int get_archive_version(FILE *archive);
-uint64_t get_table_offset(FILE *archive, uint8_t archive_version);
-
-/* Global instance of the command-line configuration structure. */
-struct configuration arguments;
-
-
-int main(int argc, char *argv[]) {
- arguments = parse_args(argc, argv);
- for (int i = arguments.vararg_index; i < argc; i++)
- handle_archive(argv[i]);
- free(arguments.output);
- return 0;
-}
-
-
-/* Extracts the archive at the specified path. */
-void handle_archive(char *path) {
- FILE *archive = fopen(path, "rb");
- if (archive == NULL) {
- /* Including the expanded path in the error message is
- much more useful to the user than `perror("fopen")`. */
- perror(path);
- exit(EXIT_FAILURE);
- } else if (!is_xp3_archive(archive)) {
- fprintf(stderr, "%s is not an XP3 archive.\n", path);
- fclose(archive);
- exit(EXIT_FAILURE);
- }
-
- int archive_version = get_archive_version(archive);
- uint64_t table_offset = get_table_offset(archive, archive_version);
-
- uint8_t compressed;
- uint64_t compressed_size, decompressed_size;
- fseek(archive, table_offset, SEEK_SET);
- fread(&compressed, sizeof(uint8_t), 1, archive);
- fread(&compressed_size, sizeof(uint64_t), 1, archive);
- fread(&decompressed_size, sizeof(uint64_t), 1, archive);
-
- /* Every task that hasn't already been handled needs a
- decompressed instance of the archive table. Decompression
- done in memory because it's $CURRENT_YEAR. */
- memory_stream data_stream;
- memory_stream compressed_data = read_to_stream(archive, compressed_size);
- if (compressed) {
- data_stream = decompress_stream(compressed_data, decompressed_size);
- free(compressed_data.start);
- } else {
- data_stream = compressed_data;
- }
-
- switch (arguments.mode) {
- case EXTRACT:
- extract(data_stream, archive);
- break;
- case LIST:
- list(data_stream);
- }
-
- free(data_stream.start);
- fclose(archive);
-}
-
-
-/* Check of the file's magic number to decide
- whether or not the file a valid XP3 archive. */
-int is_xp3_archive(FILE *archive) {
- int ret = 1;
- char* buffer = malloc(11);
- rewind(archive);
- fread(buffer, 11, 1, archive);
- if (memcmp(buffer, XP3_MAGIC, 11))
- ret = 0;
- free(buffer);
- return ret;
-}
-
-
-/* Returns the version of XP3 used to pack the archive. */
-int get_archive_version(FILE *archive) {
- uint32_t version;
- fseek(archive, XP3_VERSION_OFFSET, SEEK_SET);
- fread(&version, sizeof(uint32_t), 1, archive);
- /* 0x00 indicates version 1, and 0x01 indicates version 2. */
- return version == 1 ? 2 : 1;
-}
-
-
-/* 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) {
- uint64_t table_offset;
- fseek(archive, XP3_TABLE_OFFSET, SEEK_SET);
- fread(&table_offset, sizeof(uint64_t), 1, archive);
- if (archive_version == 1)
- return table_offset;
-
- /* The minor version is only present in XP3 version 2. */
- uint32_t minor_version;
- fread(&minor_version, sizeof(uint32_t), 1, archive);
- if (minor_version != 1) {
- fprintf(stderr, "Archive version not implemented.\n");
- fclose(archive);
- exit(EXIT_FAILURE);
- }
-
- /* The value initally read as table_offset is actually an offset to
- the real table offset. (Try saying that five times fast.) */
- fseek(archive, table_offset, SEEK_SET);
- /* Table flags and size are ignored in the parsing process,
- but are read anyway to advance the FILE pointer. */
- fseek(archive, sizeof(uint8_t) + sizeof(uint64_t), SEEK_CUR);
- fread(&table_offset, sizeof(uint64_t), 1, archive);
- return table_offset;
-}
diff --git a/src/write.c b/src/write.c
deleted file mode 100644
index 7a0d90e..0000000
--- a/src/write.c
+++ /dev/null
@@ -1,201 +0,0 @@
-/* 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 <sys/types.h>
-#include <sys/stat.h>
-#include <inttypes.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "crypto.h"
-#include "decompress.h"
-#include "defs.h"
-#include "extract.h"
-#include "file.h"
-#include "write.h"
-
-/* Global instance of the command-line configuration structure. */
-extern struct configuration arguments;
-
-
-/* Finds an eliF entry with the given key in a linked list and returns
- the associated filename, removing it from the linked list. */
-char *pop_file_name(uint32_t key, elif_node *root) {
- char *file_name = NULL;
- elif_node *current = root->next, *last = root;
- for (;;) {
- if (current->key == key) {
- file_name = current->file_name;
- last->next = current->next;
- free(current);
- break;
- } else if (current->next == NULL) {
- break;
- } else {
- last = current;
- current = current->next;
- }
- }
- return file_name;
-}
-
-
-/* Creates all of the paths in a filename. */
-void make_paths(char *file_name) {
- /* This structure is only used for the stat call. */
- struct stat temp = {0};
-
- /* Max filename size. */
- char *buffer = calloc(0x100, 1);
- char *buffer_start = buffer;
- for (int i = 0; i < 0x100 && file_name[i] != '\0'; i++) {
- if (file_name[i] == '/') {
- *buffer++ = PATH_DELIMITER;
- *buffer = '\0';
- if (stat(buffer_start, &temp) == -1) {
- if (!arguments.quiet)
- printf("Creating directory %s\n", buffer_start);
- mkdir(buffer_start, 0777);
- }
- } else {
- *buffer++ = file_name[i];
- }
- }
- free(buffer_start);
-}
-
-
-/* Iterates through the linked list of file entries and writes every
- entry to disk, according to information specified by the node. */
-void write_files(file_node *file_root, elif_node *elif_root, FILE *archive) {
- file_node *current;
- key encryption_key = get_encryption_key(arguments.game);
- Bytef *compressed_buffer, *decompressed_buffer, *out_buffer, *out_start;
- for (current = file_root->next; current != NULL; current = current->next) {
- char *file_name = pop_file_name(current->key, elif_root);
- if (file_name == NULL)
- continue;
-
- /* strcpy is used rather than strcat to prevent the file
- name from being appended after garbage data. */
- size_t file_name_size = strlen(file_name);
- size_t path_size = strlen(arguments.output);
- char *output_path = malloc(path_size + file_name_size + 1);
- if (output_path == NULL) {
- fprintf(stderr, "Insufficient memory.\n");
- return;
- }
- strcpy(output_path, arguments.output);
- strcpy(output_path + path_size, file_name);
-
- if (!arguments.quiet) {
- printf("Inflating %s (%" PRIu64 " bytes)\n",
- file_name, current->file_size);
- }
-
- out_buffer = malloc(current->file_size);
- if (out_buffer == NULL) {
- fprintf(stderr, "Insufficient memory to decompress.\n");
- return;
- }
-
- /* out_start is kept so out_buffer can be incremented. */
- out_start = out_buffer;
- for (uint64_t i = 0; i < current->segment_count; i++) {
- segment *chunk = current->segments[i];
- fseek(archive, chunk->offset, SEEK_SET);
- compressed_buffer = malloc(chunk->compressed_size);
- fread(compressed_buffer, chunk->compressed_size, 1, archive);
-
- if (chunk->compressed) {
- decompressed_buffer = inflate_chunk(compressed_buffer,
- chunk->compressed_size,
- chunk->decompressed_size);
- free(compressed_buffer);
- } else {
- decompressed_buffer = compressed_buffer;
- }
- memcpy(out_buffer, decompressed_buffer, chunk->decompressed_size);
- out_buffer += chunk->decompressed_size;
- free(decompressed_buffer);
- }
-
- if (arguments.game != NO_CRYPTO) {
- decrypt_buffer(out_start, current->file_size,
- encryption_key, current->key);
- }
-
- make_paths(output_path);
- FILE *output = fopen(output_path, "wb+");
- if (output == NULL) {
- perror(output_path);
- break;
- }
- fwrite(out_start, current->file_size, 1, output);
- fclose(output);
- free(output_path);
- free(file_name);
- free(out_start);
- }
-}
-
-
-/* Inserts an eliF entry at the end of a linked list. */
-void defer_elif_node(elif_node *new, elif_node *root) {
- elif_node *current = root;
- for (;;) {
- if (current->next == NULL) {
- current->next = new;
- break;
- } else {
- current = current->next;
- }
- }
-}
-
-
-/* Inserts a File entry node at the end of a linked list. */
-void defer_file_node(file_node *new, file_node *root) {
- file_node *current = root;
- for (;;) {
- if (current->next == NULL) {
- current->next = new;
- break;
- } else {
- current = current->next;
- }
- }
-}
-
-
-/* Iterates through the linked list and frees all entries. */
-void free_elif_nodes(elif_node *base) {
- if (base->next != NULL) {
- free_elif_nodes(base->next);
- }
- free(base->file_name);
- free(base);
-}
-
-
-/* Iterates through the linked list and frees all entries. */
-void free_file_nodes(file_node *base) {
- if (base->next != NULL)
- free_file_nodes(base->next);
- free(base);
-}
diff --git a/src/write.h b/src/write.h
deleted file mode 100644
index 51a847e..0000000
--- a/src/write.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/* 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
-
-/* Because File entries won't necessarily follow the associated
- eliF entry, filenames and hashes are stored in a linked list. */
-typedef struct elif_node {
- uint32_t key; /* Key associated with matching File entry. */
- char *file_name; /* Name of file. */
- struct elif_node *next; /* Pointer to the next node. */
-} elif_node;
-
-/* Iterates through the linked list of file entries and writes every
- entry to disk, according to information specified by the node. */
-void write_files(file_node *file_root, elif_node *elif_root, FILE *archive);
-
-/* Inserts an eliF entry at the end of a linked list. */
-void defer_elif_node(elif_node *new, elif_node *root);
-
-/* Inserts a File entry node at the end of a linked list. */
-void defer_file_node(file_node *new, file_node *root);
-
-/* Iterates through the linked list and frees all entries. */
-void free_elif_nodes(elif_node *base);
-
-/* Iterates through the linked list and frees all entries. */
-void free_file_nodes(file_node *base);