summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/cli.c33
-rw-r--r--src/cli.h12
-rw-r--r--src/decompress.c20
-rw-r--r--src/decompress.h5
-rw-r--r--src/extract.c105
-rw-r--r--src/extract.h1
-rw-r--r--src/file.c99
-rw-r--r--src/file.h25
-rw-r--r--src/main.c1
-rw-r--r--src/write.c104
-rw-r--r--src/write.h14
11 files changed, 290 insertions, 129 deletions
diff --git a/src/cli.c b/src/cli.c
index 481aaea..2713fed 100644
--- a/src/cli.c
+++ b/src/cli.c
@@ -24,13 +24,20 @@
#include "cli.h"
#include "defs.h"
-#define VERSION "0.1.0"
+#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"
+ "version and exit.\n\n" \
+ " -l, --list\t\tList games supported by Nekopack.\n" \
+ " -a, --archive\tAlternate way of specifying archive" \
+ "to extract.\n" \
+ " -g, --game\t\tGame the archive is from. Required for " \
+ "file decryption"
+#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
@@ -57,7 +64,8 @@ struct configuration parse_args(int argc, char *argv[]) {
};
do {
- current = getopt_long(argc, argv, "hv", long_options, &option_index);
+ current = getopt_long(argc, argv, "hvla:g:", long_options,
+ &option_index);
switch (current) {
case 'h':
printf("Usage: %s [OPTIONS] (ARCHIVE PATH)\n\n", argv[0]);
@@ -67,6 +75,25 @@ struct configuration parse_args(int argc, char *argv[]) {
printf("Nekopack, version %s\nProgrammed by "
"Jakob. <http://tsar-fox.com/>\n", VERSION);
exit(EXIT_SUCCESS);
+ case 'l':
+ printf("%s\n", GAME_CONSTANTS);
+ exit(EXIT_SUCCESS);
+ case 'a':
+ count++;
+ parsed.archive_path = optarg;
+ break;
+ case 'g':
+ count++;
+ if (!strcmp(optarg, "nekopara_volume_0"))
+ parsed.source = NEKOPARA_VOLUME_0;
+ else if (!strcmp(optarg, "nekopara_volume_0_steam"))
+ parsed.source = NEKOPARA_VOLUME_0_STEAM;
+ else if (!strcmp(optarg, "nekopara_volume_1"))
+ parsed.source = NEKOPARA_VOLUME_1;
+ else if (!strcmp(optarg, "nekopara_volume_1_steam"))
+ parsed.source = NEKOPARA_VOLUME_1_STEAM;
+ else
+ parsed.source = NO_CRYPTO;
}
count++;
} while (current >= 0);
diff --git a/src/cli.h b/src/cli.h
index 0008d63..43d9465 100644
--- a/src/cli.h
+++ b/src/cli.h
@@ -17,8 +17,20 @@
#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 {
+ NO_CRYPTO,
+ NEKOPARA_VOLUME_0,
+ NEKOPARA_VOLUME_0_STEAM,
+ NEKOPARA_VOLUME_1,
+ NEKOPARA_VOLUME_1_STEAM,
+} game;
+
/* Binary structure for storing command-line options. */
struct configuration {
+ game source; /* Which decryption key to use. */
const char *archive_path; /* Path to archive to extract. */
};
diff --git a/src/decompress.c b/src/decompress.c
index dba637f..0301cc8 100644
--- a/src/decompress.c
+++ b/src/decompress.c
@@ -24,7 +24,8 @@
#include "extract.h"
-/* Document and put in header. */
+/* 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) {
Bytef *decompressed_data = malloc(decompressed_size);
@@ -77,7 +78,7 @@ memory_stream decompress_file(FILE *archive, uint64_t sizes_offset) {
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, *compressed_data = malloc(compressed_size);
/* This is a pretty shitty way of handling it, though. */
if (compressed_data == NULL) {
@@ -88,22 +89,13 @@ memory_stream decompress_file(FILE *archive, uint64_t sizes_offset) {
}
fread(compressed_data, compressed_size, 1, archive);
- /* if (ferror(archive)) { */
- /* fprintf(stderr, "File corrupt.\n"); */
- /* inflateEnd(&data_stream); */
- /* free(compressed_data); */
- /* free(decompressed_data); */
- /* exit(EXIT_FAILURE); */
- /* } */
- Bytef *decompressed_data = inflate_chunk(compressed_data, compressed_size,
- decompressed_size);
-
+ decompressed_data = inflate_chunk(compressed_data, compressed_size,
+ decompressed_size);
/* The compressed data is irrelevant at this point. */
free(compressed_data);
if (decompressed_data == NULL)
exit(EXIT_FAILURE);
- return (memory_stream) {decompressed_size,
- decompressed_data,
+ return (memory_stream) {decompressed_size, decompressed_data,
decompressed_data};
}
diff --git a/src/decompress.h b/src/decompress.h
index 184b0f8..a625f5e 100644
--- a/src/decompress.h
+++ b/src/decompress.h
@@ -24,3 +24,8 @@
/* Wrapper for inflate_chunk which operates on FILE pointers. The file
pointer's contents are inflated into a memory stream and returned. */
memory_stream decompress_file(FILE *archive, uint64_t sizes_offset);
+
+/* 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/extract.c b/src/extract.c
index 8a1eec0..f452eaf 100644
--- a/src/extract.c
+++ b/src/extract.c
@@ -24,6 +24,7 @@
#include <iconv.h>
#include <zlib.h>
+#include "cli.h"
#include "defs.h"
#include "decompress.h"
#include "extract.h"
@@ -33,18 +34,23 @@
#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);
-void read_file_entry(memory_stream *data_stream, Bytef *section_end);
-node *read_elif_entry(memory_stream *data_stream);
/* Handles decompression of the archive, as well as
parsing, decrypting and writing the table entries. */
void extract(FILE *archive, uint64_t table_offset) {
- /* Filenames are stored in a linked list as they're seen.
- calloc is used to prevent the next pointer from being junk. */
- node *root = calloc(sizeof(node), 1);
+ /* 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_root = calloc(sizeof(elif_node), 1);
+ elif_node *elif_new;
+ file_node *file_root = calloc(sizeof(file_node), 1);
+ file_node *file_new;
uint8_t compressed;
fseek(archive, table_offset, SEEK_SET);
@@ -55,16 +61,19 @@ void extract(FILE *archive, uint64_t table_offset) {
if (compressed) {
data_stream = decompress_file(archive, ftell(archive));
} else {
- fprintf(stderr, "This archive is not supported.\n");
- exit(EXIT_FAILURE);
+ uint64_t decompressed_size;
+ fread(&decompressed_size, sizeof(uint64_t), 1, archive);
+ /* The second size is irrelevant and therefore ignored. */
+ fseek(archive, sizeof(uint64_t), SEEK_CUR);
+ data_stream.stream_length = decompressed_size;
+ data_stream.data = malloc(decompressed_size);
+ data_stream.start = data_stream.data;
+ fread(data_stream.data, decompressed_size, 1, archive);
+ fclose(archive);
}
- /* 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;
- /* Implement "last filename" variable, which gets freed
- and reallocated every time an elif entry is read. */
do {
read_stream(&entry_magic, &data_stream.data, sizeof(uint32_t));
read_stream(&entry_size, &data_stream.data, sizeof(uint64_t));
@@ -72,15 +81,20 @@ void extract(FILE *archive, uint64_t table_offset) {
printf("Magic: %" PRIx32 " Size: %" PRIx64 "\n", entry_magic, entry_size);
switch (entry_magic) {
- /* hnfn and eliF entries are identical. The size given by
- the entry header doesn't match the actual entry size,
- so it isn't passed to the function. */
- case HNFN_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:
- defer_node(read_elif_entry(&data_stream), root);
+ case HNFN_MAGIC:
+ case NEKO_MAGIC:
+ elif_new = read_elif_entry(&data_stream);
+ defer_elif_node(elif_new, elif_root);
break;
case FILE_MAGIC:
- read_file_entry(&data_stream, data_stream.data + entry_size);
+ file_new = read_file_entry(&data_stream,
+ data_stream.data + entry_size);
+ defer_file_node(file_new, file_root);
break;
default:
printf("End of archive reached.\n");
@@ -88,9 +102,11 @@ void extract(FILE *archive, uint64_t table_offset) {
}
} while (!stream_ended);
- test_linked_list(root);
- free_node(root);
-
+ write_files(file_root, elif_root, data_stream.start);
+ test_elif_linked_list(elif_root);
+ test_file_linked_list(file_root);
+ free_elif_nodes(elif_root);
+ free_file_nodes(file_root);
free(data_stream.start);
}
@@ -103,32 +119,41 @@ void read_stream(void *destination, Bytef **source, size_t size) {
}
-/* Document */
-node *read_elif_entry(memory_stream *data_stream) {
+/* Returns a pointer to a elif_node containing the filename
+ and key, which can be deferred in a linked list. */
+elif_node *read_elif_entry(memory_stream *data_stream) {
+ uint32_t file_key;
uint16_t name_size;
- uint32_t name_hash;
- read_stream(&name_hash, &data_stream->data, sizeof(uint32_t));
+ read_stream(&file_key, &data_stream->data, sizeof(uint32_t));
read_stream(&name_size, &data_stream->data, sizeof(uint16_t));
- /* Strings are terminated by null bytes,
- which aren't counted in the name size. */
- char *input_buffer = malloc(name_size * 2 + 2);
- char *file_name = malloc(name_size + 1);
- read_stream(input_buffer, &data_stream->data, name_size * 2 + 2);
+ char *file_name;
+ if (name_size < 0x100) {
+ /* Strings are terminated by null bytes, but
+ they aren't counted in the name size. */
+ char *input_buffer = malloc(name_size * 2 + 2);
+ file_name = malloc(name_size + 1);
+ read_stream(input_buffer, &data_stream->data, name_size * 2 + 2);
- /* iconv is the non-portable glibc way of doing it. */
- char *in_start = input_buffer, *out_start = file_name;
- size_t in_size = name_size * 2 + 2, out_size = name_size + 1;
- iconv_t conversion = iconv_open("UTF-8", "UTF-16LE");
- iconv(conversion, &in_start, &in_size, &out_start, &out_size);
- iconv_close(conversion);
+ /* iconv is the less-portable glibc way of doing it. It seems to
+ be in the OpenBSD manpages, though, so I'm not worried. */
+ char *in_start = input_buffer, *out_start = file_name;
+ size_t in_size = name_size * 2 + 2, out_size = name_size + 1;
+ iconv_t conversion = iconv_open("UTF-8", "UTF-16LE");
+ iconv(conversion, &in_start, &in_size, &out_start, &out_size);
+ iconv_close(conversion);
- node *current = malloc(sizeof(node));
- current->key = name_hash;
+ free(input_buffer);
+ } else {
+ /* It's pretty safe to assume anything
+ larger is the copyright notice. */
+ data_stream->data += name_size * 2 + 2;
+ file_name = strdup("COPYING.txt");
+ }
+
+ elif_node *current = malloc(sizeof(elif_node));
+ current->key = file_key;
current->file_name = file_name;
current->next = NULL;
-
- free(input_buffer);
-
return current;
}
diff --git a/src/extract.h b/src/extract.h
index 1972af2..0247ea9 100644
--- a/src/extract.h
+++ b/src/extract.h
@@ -17,6 +17,7 @@
#pragma once
+#include <stdio.h>
#include <stdint.h>
#include <zlib.h>
diff --git a/src/file.c b/src/file.c
index 1d4dc74..aa7e00d 100644
--- a/src/file.c
+++ b/src/file.c
@@ -21,56 +21,60 @@
#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);
-void read_segm_chunk(memory_stream *data_stream);
-void read_adlr_chunk(memory_stream *data_stream);
-void read_time_chunk(memory_stream *data_stream);
+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);
-/* Document and update documentation in header file. */
-void read_file_entry(memory_stream *data_stream, Bytef *section_end) {
+/* Creates a file node by parsing a file entry. */
+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);
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);
- read_adlr_chunk(data_stream);
+ printf("[ADLR found at 0x%lx]\n", data_stream->data - data_stream->start - 12);
+ read_adlr_chunk(data_stream, parsed);
break;
case SEGM_MAGIC:
- printf("[SEGM found at 0x%lx]\n", data_stream->data - data_stream->start);
- read_segm_chunk(data_stream);
+ printf("[SEGM found at 0x%lx]\n", data_stream->data - data_stream->start - 12);
+ read_segm_chunk(data_stream, parsed, entry_size);
break;
case INFO_MAGIC:
- printf("[INFO found at 0x%lx]\n", data_stream->data - data_stream->start);
- read_info_chunk(data_stream);
+ printf("[INFO found at 0x%lx]\n", data_stream->data - data_stream->start - 12);
+ read_info_chunk(data_stream, parsed);
break;
case TIME_MAGIC:
- printf("[TIME found at 0x%lx]\n", data_stream->data - data_stream->start);
- read_time_chunk(data_stream);
+ printf("[TIME found at 0x%lx]\n", data_stream->data - data_stream->start - 12);
+ read_time_chunk(data_stream, parsed);
break;
default:
- printf("New magic discovered: %" PRIx32 " size: %" PRIx64 "\n", entry_magic, entry_size); // Debug.
+ printf("Unknown magic: %" PRIx32 " size: %" PRIx64 "\n", entry_magic, entry_size); // Debug.
}
}
printf("\n\n\n\n"); // Debug.
+ return parsed;
}
/* Document */
-void read_info_chunk(memory_stream *data_stream) {
- uint32_t flags;
+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(&flags, &data_stream->data, sizeof(uint32_t));
+ 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));
@@ -79,7 +83,7 @@ void read_info_chunk(memory_stream *data_stream) {
read_stream(file_name, &data_stream->data, file_name_size * 2);
printf("\nINFO SEGMENT\n");
printf("------------\n");
- printf("FLAGS: %" PRIx32 "\n", flags);
+ printf("%s\n", encrypted ? "ENCRYPTED": "PLAINTEXT");
printf("COMPRESSED_SIZE: %" PRIx64 "\n", compressed_size);
printf("DECOMPRESSED_SIZE: %" PRIx64 "\n", decompressed_size);
printf("MD5: ");
@@ -94,36 +98,53 @@ void read_info_chunk(memory_stream *data_stream) {
/* Document */
-void read_segm_chunk(memory_stream *data_stream) {
- uint32_t flags;
- uint64_t offset, compressed_size, decompressed_size;
- read_stream(&flags, &data_stream->data, sizeof(uint32_t));
- read_stream(&offset, &data_stream->data, sizeof(uint64_t));
- read_stream(&compressed_size, &data_stream->data, sizeof(uint64_t));
- read_stream(&decompressed_size, &data_stream->data, sizeof(uint64_t));
- printf("\nSEGM SEGMENT\n");
- printf("------------\n");
- printf("FLAGS: %" PRIx32 "\n", flags);
- printf("MEM_OFFSET: %" PRIx64 "\n", offset);
- printf("DECOMPRESSED_SIZE: %" PRIx64 "\n", decompressed_size);
- printf("COMPRESSED_SIZE: %" PRIx64 "\n\n", compressed_size);
- /* Entries can be between the segment chunk and the actual file
- data, so processing the file has to be deferred for later. */
+void read_segm_chunk(memory_stream *data_stream, file_node *parsed,
+ uint64_t segment_count) {
+ /* The segment_count is in bytes, with each
+ segment being 28 bytes in length. */
+ segment_count /= 28;
+
+ /* Segments are stored in an array of segment pointers. */
+ segment **segments = malloc(sizeof(segment *) * segment_count);
+ for (int 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));
+ }
+ printf("\nSEGMENT SECTION\n---------------\n\n");
+ printf("SEGMENT_COUNT: %" PRIu64 "\n", segment_count);
+ for (int i = 0; i < segment_count; i++) {
+ printf("\SEGMENT %d\n----------\n", i);
+ printf("%s\n", segments[i]->compressed ? "COMPRESSED" : "DECOMPRESSED");
+ printf("FILE_OFFSET: %" PRIu64 "\n", segments[i]->offset);
+ printf("COMPRESSED_SIZE: %" PRIu64 "\n", segments[i]->compressed_size);
+ printf("DECOMPRESSED_SIZE: %" PRIu64 "\n", segments[i]->decompressed_size);
+ }
+ parsed->segment_count = segment_count;
+ parsed->segments = segments;
}
/* Document */
-void read_adlr_chunk(memory_stream *data_stream) {
+void read_adlr_chunk(memory_stream *data_stream, file_node *parsed) {
uint32_t key;
read_stream(&key, &data_stream->data, sizeof(uint32_t));
- printf("\nADLR SEGMENT\n");
- printf("------------\n");
- printf("KEY: %" PRIx32 "\n\n", key);
+ parsed->key = key;
}
/* Document */
-void read_time_chunk(memory_stream *data_stream) {
+void read_time_chunk(memory_stream *data_stream, file_node *parsed) {
uint64_t timestamp;
read_stream(&timestamp, &data_stream->data, sizeof(uint64_t));
printf("\nTIME SEGMENT\n");
diff --git a/src/file.h b/src/file.h
index c8dcc1d..dc96154 100644
--- a/src/file.h
+++ b/src/file.h
@@ -19,11 +19,24 @@
#include <stdint.h>
+/* Structure representing a 28-byte segment in a file. */
typedef struct {
- uint32_t filename_key;
- uint64_t timestamp, compressed_size, decompressed_size, offset;
-} file_entry;
-// Decompressed/compressed size same in info/segm?
+ 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;
-/* Document and update documentation in header file. */
-void read_file_entry(memory_stream *data_stream, Bytef *section_end);
+/* Node in a linked list of file entries to write to disk. */
+typedef struct file_node {
+ int compressed; /* Whether or not the archive is compressed. */
+ uint32_t key; /* Key associated with matching eliF entry. */
+ uint64_t compressed_size; /* Size of compressed chunk. */
+ uint64_t decompressed_size; /* Size of decompressed data. */
+ 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_node(memory_stream *data_stream, Bytef *section_end);
diff --git a/src/main.c b/src/main.c
index efda3bc..9effc9e 100644
--- a/src/main.c
+++ b/src/main.c
@@ -16,7 +16,6 @@
along with Nekopack. If not, see <http://www.gnu.org/licenses/>. */
#include <errno.h>
-#include <inttypes.h> // Needed for debugging at this point.
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
diff --git a/src/write.c b/src/write.c
index 3cf04ca..1bd83da 100644
--- a/src/write.c
+++ b/src/write.c
@@ -19,23 +19,23 @@
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
+#include <string.h>
+#include "decompress.h"
+#include "extract.h"
+#include "file.h"
#include "write.h"
-/* Document */
-char *pop_file_name(uint32_t key, node *root) {
- /* The root node shouldn't contain anything. */
- if (root->next == NULL)
- return NULL;
-
- const char *file_name = NULL;
- node *current = root->next, *last = root;
+/* 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->file_name);
free(current);
break;
} else if (current->next == NULL) {
@@ -49,9 +49,42 @@ char *pop_file_name(uint32_t key, node *root) {
}
-/* Document */
-void defer_node(node *new, node *root) {
- node *current = root;
+/* 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, Bytef *start) {
+ FILE *output;
+ file_node *current;
+ Bytef *compressed_buffer, *decompressed_buffer;
+ for (current = file_root->next; current != NULL; current = current->next) {
+ char *file_name = pop_file_name(current->key, elif_root);
+ if (file_name == NULL) {
+ fprintf(stderr, "File found without matching eliF entry.\n");
+ continue;
+ }
+ compressed_buffer = malloc(current->compressed_size);
+ for (int i = 0; i < current->segment_count; i++)
+ free(current->segments[i]);
+ free(current->segments);
+ /* memcpy(compressed_buffer, start + current->offset, */
+ /* current->decompressed_size); */
+ /* if (current->compressed) { */
+ /* fprintf(stderr, "Not implemented :^)\n"); // don't leave this in lol */
+ /* continue; */
+ /* } else { */
+ /* output = fopen(file_name, "wb+"); */
+ /* fwrite(compressed_buffer, current->compressed_size, 1, output); */
+ /* fclose(output); */
+ /* } */
+
+ free(compressed_buffer);
+ break;
+ }
+}
+
+
+/* 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;
@@ -63,20 +96,49 @@ void defer_node(node *new, node *root) {
}
-void test_linked_list(node *root) {
- for (node *current = root; current != NULL; current = current->next) {
- printf("NODE\n----\n");
+/* 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);
+}
+
+
+void test_elif_linked_list(elif_node *root) {
+ for (elif_node *current = root; current != NULL; current = current->next) {
+ printf("ELIF NODE\n---------\n");
printf("KEY: %" PRIx32 "\n", current->key);
printf("FILE_NAME: %s\n\n", current->file_name);
}
}
-/* Document */
-void free_node(node *base) {
- if (base->next != NULL) {
- free_node(base->next);
- return;
+void test_file_linked_list(file_node *root) {
+ for (file_node *current = root; current != NULL; current = current->next) {
+ printf("FILE NODE\n---------\n");
+ printf("KEY: %" PRIx32 "\n\n", current->key);
}
- free(base);
}
diff --git a/src/write.h b/src/write.h
index 4b8c717..d37adda 100644
--- a/src/write.h
+++ b/src/write.h
@@ -17,8 +17,12 @@
/* Because File entries won't necessarily follow the associated
eliF entry, filenames and hashes are stored in a linked list. */
-typedef struct node {
- uint32_t key;
- char *file_name;
- struct node *next;
-} node;
+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, Bytef *start);