diff options
Diffstat (limited to 'src/extract.c')
| -rw-r--r-- | src/extract.c | 188 |
1 files changed, 0 insertions, 188 deletions
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; -} |