diff options
Diffstat (limited to 'src/parse.c')
| -rw-r--r-- | src/parse.c | 264 |
1 files changed, 0 insertions, 264 deletions
diff --git a/src/parse.c b/src/parse.c deleted file mode 100644 index c53a627..0000000 --- a/src/parse.c +++ /dev/null @@ -1,264 +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> // Needed for debugging at this point. -#include <stdio.h> -#include <stdint.h> -#include <stdlib.h> -#include <string.h> - -#include <iconv.h> -#include <zlib.h> - -#include "defs.h" - -#define ELIF_MAGIC 0x46696c65 -#define FILE_MAGIC 0x656c6946 -#define ADLR_MAGIC 0x726c6461 -#define SEGM_MAGIC 0x6d676573 -#define INFO_MAGIC 0x6f666e69 -#define TIME_MAGIC 0x656d6974 - -/* A pointer to the start of the memory region - has to be kept for freeing purposes. */ -typedef struct { - uint64_t stream_length; - Bytef *start; - Bytef *data; -} memory_stream; - -/* typedef struct { */ -/* uint64_t timestamp; */ -/* uint32_t hash_key; */ -/* } file_entry; */ - -memory_stream decompress_stream(FILE *archive, uint64_t sizes_offset); -void read_stream(void *destination, Bytef **source, size_t size); -void read_file_entry(memory_stream *data_stream, Bytef *section_end); -void read_elif_entry(memory_stream *data_stream); -void read_info_chunk(memory_stream *data_stream); - - -/* Parses and extracts entries from the archive. */ -void extract(FILE *archive, uint64_t table_offset) { - /* An 8-bit unsigned integers at the table offset indicates - whether or not the archive has to be decompressed. */ - uint8_t compressed; - fseek(archive, table_offset, SEEK_SET); - fread(&compressed, sizeof(uint8_t), 1, archive); - - memory_stream data_stream; - if (compressed) { - data_stream = decompress_stream(archive, ftell(archive)); - } else { - fprintf(stderr, "Uncompressed archives not yet supported.\n"); - exit(EXIT_FAILURE); - } - - /* The header for every entry in the XP3 archive format contains - a magic number, followed by the size of the entry. */ - uint32_t entry_magic; - uint64_t entry_size; - for (;;) { - read_stream(&entry_magic, &data_stream.data, sizeof(uint32_t)); - read_stream(&entry_size, &data_stream.data, sizeof(uint64_t)); - printf("entry at 0x%lx\n", data_stream.data - data_stream.start - 12); - printf("Magic: %" PRIx32 " Size: %" PRIx64 "\n", entry_magic, entry_size); // Debug. - - switch (entry_magic) { - case ELIF_MAGIC: - /* The size given by the entry header doesn't match the - actual entry size, so it isn't passed to the function. */ - read_elif_entry(&data_stream); - break; - case FILE_MAGIC: - // printf("[File entry]\n"); - // data_stream.data += entry_size; - read_file_entry(&data_stream, data_stream.data + entry_size); - break; - default: // Debug. - printf("Unknown magic: %x\n", entry_magic); - exit(EXIT_FAILURE); - } - } - - free(data_stream.start); -} - - -/* Inflates the file pointer and returns a struct containing the - size and a pointer to the decompressed data in memory. */ -memory_stream decompress_stream(FILE *archive, uint64_t sizes_offset) { - uint64_t compressed_size, decompressed_size; - fseek(archive, sizes_offset, SEEK_SET); - fread(&compressed_size, sizeof(uint64_t), 1, archive); - fread(&decompressed_size, sizeof(uint64_t), 1, archive); - - /* Decompression is done in memory because it's $CURRENT_YEAR. */ - Bytef *compressed_data = malloc(compressed_size); - Bytef *decompressed_data = malloc(decompressed_size); - - /* This is a pretty shitty way of handling it, though. */ - if (compressed_data == NULL || decompressed_data == NULL) { - if (compressed_data != NULL) - free(compressed_data); - fprintf(stderr, "Insufficient memory to decompress archive.\n"); - fclose(archive); - exit(EXIT_FAILURE); - } - - 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(compressed_data); - free(decompressed_data); - fclose(archive); - exit(EXIT_FAILURE); - } - - int status_code; - do { - fread(compressed_data, compressed_size, 1, archive); - data_stream.avail_in = compressed_size; - - /* This really shouldn't happen. */ - if (ferror(archive)) { - fprintf(stderr, "File corrupt.\n"); - inflateEnd(&data_stream); - free(compressed_data); - free(decompressed_data); - exit(EXIT_FAILURE); - } - - if (data_stream.avail_in == 0) - break; - data_stream.next_in = compressed_data; - // Flushing probably isn't required here. - 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); - - /* The compressed data is irrelevant at this point. */ - free(compressed_data); - - return (memory_stream) {decompressed_size, decompressed_data, - decompressed_data}; -} - - -/* 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; -} - - -/* Document */ -void read_file_entry(memory_stream *data_stream, Bytef *section_end) { - uint32_t entry_magic; - uint64_t entry_size; - 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: - printf("[ADLR found at 0x%lx]\n", data_stream->data - data_stream->start); - data_stream->data += entry_size; - break; - case SEGM_MAGIC: - printf("[SEGM found at 0x%lx]\n", data_stream->data - data_stream->start); - data_stream->data += entry_size; - break; - case INFO_MAGIC: - printf("[INFO found at 0x%lx]\n", data_stream->data - data_stream->start); - read_info_chunk(data_stream); - /* data_stream->data += entry_size; */ - break; - case TIME_MAGIC: - printf("[TIME found at 0x%lx]\n", data_stream->data - data_stream->start); - data_stream->data += entry_size; - break; - default: - printf("New magic discovered: %" PRIx32 " size: %" PRIx64 "\n", entry_magic, entry_size); // Debug. - } - } - printf("\n\n\n\n"); // Debug. -} - - -/* Document */ -void read_elif_entry(memory_stream *data_stream) { - uint16_t name_size; - /* The first part of an ELIF entry is a 32-bit file name hash. */ - data_stream->data += sizeof(uint32_t); - read_stream(&name_size, &data_stream->data, sizeof(uint16_t)); - - char *input_buffer = malloc(name_size * 2); - char *file_name = malloc(name_size); - read_stream(input_buffer, &data_stream->data, name_size * 2); - - /* There seems to be an extra UTF-16 byte at the end of the entry. */ - data_stream->data += 2; - - printf("Filename (ASCII): "); - for (int i = 0; i < name_size * 2; i++) { - if (input_buffer[i] >= 0x20 && input_buffer[i] < 0x7f) - printf("%c", input_buffer[i]); - } - printf("\n"); - - free(input_buffer); - free(file_name); -} - - -/* Document */ -void read_info_chunk(memory_stream *data_stream) { - uint32_t flags; - uint64_t decompressed_size, compressed_size; - uint16_t file_name_size; - read_stream(&flags, &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)); - - char *file_name = malloc(file_name_size * 2); - read_stream(file_name, &data_stream->data, file_name_size * 2); - printf("\nINFO SEGMENT\n"); - printf("------------\n"); - printf("FLAGS: %" PRIx32 "\n", flags); - printf("DECOMPRESSED_SIZE: %" PRIx64 "\n", decompressed_size); - printf("COMPRESSED_SIZE: %" PRIx64 "\n", compressed_size); - printf("FILENAME (HASH?): "); - for (int i = 0; i < file_name_size * 2; i++) { - if (file_name[i] >= 0x20 && file_name[i] < 0x7f) - printf("%c", file_name[i]); - } - printf("\n"); - - data_stream->data += 2; -} |