From 6d844032442f36b924e1c270a123dc970ddd96a6 Mon Sep 17 00:00:00 2001 From: jakob Date: Tue, 17 Jan 2017 15:29:07 -0500 Subject: Improved readability. --- src/cli.c | 9 +++++---- src/cli.h | 2 +- src/decompress.c | 25 ++++++++++--------------- src/extract.c | 35 +++++++++++++++++++---------------- src/file.c | 15 ++++++++++----- src/file.h | 2 +- src/main.c | 48 +++++++++++++++++++++++++++--------------------- src/write.h | 2 ++ 8 files changed, 75 insertions(+), 63 deletions(-) (limited to 'src') diff --git a/src/cli.c b/src/cli.c index 0c8dce8..0025141 100644 --- a/src/cli.c +++ b/src/cli.c @@ -90,7 +90,7 @@ struct configuration parse_args(int argc, char *argv[]) { break; case 'a': count++; - parsed.archive_path = optarg; + parsed.archive = optarg; break; case 'g': count++; @@ -108,7 +108,8 @@ struct configuration parse_args(int argc, char *argv[]) { parsed.game = NO_CRYPTO; break; case 'e': - /* '-e' is still parsed to provide consisency. */ + /* Despite being the default, '-e' is + still parsed to provide consisency. */ parsed.mode = EXTRACT; break; case 'l': @@ -119,12 +120,12 @@ struct configuration parse_args(int argc, char *argv[]) { /* getopt "sorts" the argument array such that all of the flags come first. argv[count] is the first positional argument encountered. */ - if (parsed.archive_path == NULL) { + if (parsed.archive == NULL) { if (argv[count] == NULL) { fprintf(stderr, "No archive path provided.\n"); exit(EXIT_FAILURE); } - parsed.archive_path = argv[count]; + parsed.archive = argv[count]; } return parsed; diff --git a/src/cli.h b/src/cli.h index 5874fb2..d02bca7 100644 --- a/src/cli.h +++ b/src/cli.h @@ -40,7 +40,7 @@ struct configuration { int quiet; /* Level of output verbosity. */ game_type game; /* Which decryption key to use. */ mode_type mode; /* What to do after initial sanity checks. */ - const char *archive_path; /* Path to archive to extract. */ + const char *archive; /* Path to archive to extract. */ }; /* General subroutine for parsing command-line arguments. Returns a diff --git a/src/decompress.c b/src/decompress.c index dd19958..9a8ec64 100644 --- a/src/decompress.c +++ b/src/decompress.c @@ -24,8 +24,8 @@ #include "extract.h" -/* Returns a pointer to a buffer containing the - inflated contents of a given memory chunk. */ +/* 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); @@ -55,7 +55,6 @@ Bytef *inflate_chunk(Bytef *chunk, uint64_t chunk_size, if (data_stream.avail_in == 0) break; data_stream.next_in = chunk; - // Flushing probably isn't required here. do { data_stream.avail_out = decompressed_size; data_stream.next_out = decompressed_data; @@ -64,26 +63,22 @@ Bytef *inflate_chunk(Bytef *chunk, uint64_t chunk_size, } while (status_code != Z_STREAM_END); inflateEnd(&data_stream); - return decompressed_data; } -/* Decompresses a memory_stream data structure into a new one. */ +/* 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) { - Bytef *decompressed_data = malloc(size); - /* This is a pretty shitty way of handling it. */ + 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) { - fprintf(stderr, "Insufficient memory to decompress archive.\n"); - free(compressed_data.start); - free(decompressed_data); + free(chunk); exit(EXIT_FAILURE); } - decompressed_data = inflate_chunk(compressed_data.start, - compressed_data.stream_length, - size); - if (decompressed_data == NULL) - exit(EXIT_FAILURE); + return (memory_stream) {size, decompressed_data, decompressed_data}; } diff --git a/src/extract.c b/src/extract.c index 261d84a..e6476ce 100644 --- a/src/extract.c +++ b/src/extract.c @@ -38,8 +38,9 @@ elif_node *read_elif_entry(memory_stream *data_stream); void read_stream(void *destination, Bytef **source, size_t size); -/* Decrypts and writes files in the XP3 archive - to disk according to table entries. */ +/* 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 @@ -94,7 +95,7 @@ void extract(memory_stream data_stream, FILE *archive) { } -/* Simply lists the contents of an archive, ignoring File entries. */ +/* 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; @@ -123,16 +124,17 @@ 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. */ +/* 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; } -/* Returns a pointer to a elif_node containing the filename - and key, which can be deferred in a linked list. */ +/* 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; @@ -141,8 +143,8 @@ elif_node *read_elif_entry(memory_stream *data_stream) { char *file_name; if (name_size < 0x100) { - /* Strings are terminated by null bytes, - which aren't counted in the name size. */ + /* 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) @@ -168,18 +170,19 @@ elif_node *read_elif_entry(memory_stream *data_stream) { free(input_buffer); } else { - /* It's safe to assume too large is the copyright notice. */ + /* 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 *current = malloc(sizeof(elif_node)); - if (current == NULL) { + elif_node *parsed = malloc(sizeof(elif_node)); + if (parsed == NULL) { free(file_name); return NULL; } - current->key = file_key; - current->file_name = file_name; - current->next = NULL; - return current; + parsed->key = file_key; + parsed->file_name = file_name; + parsed->next = NULL; + return parsed; } diff --git a/src/file.c b/src/file.c index 3274859..d2a9b72 100644 --- a/src/file.c +++ b/src/file.c @@ -35,7 +35,9 @@ void read_segm_chunk(memory_stream *data_stream, file_node *parsed, uint64_t segment_count); -/* Creates a file node by parsing a file entry. */ +/* 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; @@ -50,9 +52,11 @@ file_node *read_file_entry(memory_stream *data_stream, Bytef *section_end) { read_adlr_chunk(data_stream, parsed); break; case SEGM_MAGIC: - /* Segments are 28 bytes each. */ + /* 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); - /* Check if segments was successfully allocated. */ + /* 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; @@ -72,7 +76,7 @@ file_node *read_file_entry(memory_stream *data_stream, Bytef *section_end) { } -/* Reads the contents of an info chunk int a file_node. */ +/* 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; @@ -89,13 +93,14 @@ void read_info_chunk(memory_stream *data_stream, file_node *parsed) { } -/* Reads the contents of a segm chunk into a file_node. */ +/* 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, diff --git a/src/file.h b/src/file.h index 046cd48..46b6dc0 100644 --- a/src/file.h +++ b/src/file.h @@ -19,7 +19,7 @@ #include -/* Structure representing a 28-byte segment in a file. */ +/* 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. */ diff --git a/src/main.c b/src/main.c index bbe4690..d166733 100644 --- a/src/main.c +++ b/src/main.c @@ -40,12 +40,14 @@ struct configuration arguments; int main(int argc, char *argv[]) { arguments = parse_args(argc, argv); - FILE *archive = fopen(arguments.archive_path, "rb"); + FILE *archive = fopen(arguments.archive, "rb"); if (archive == NULL) { - perror(arguments.archive_path); + /* Including the expanded path in the error message is + much more useful to the user than `perror("fopen")`. */ + perror(arguments.archive); exit(EXIT_FAILURE); } else if (!is_xp3_archive(archive)) { - fprintf(stderr, "File is not an XP3 archive.\n"); + fprintf(stderr, "%s is not an XP3 archive.\n", arguments.archive); fclose(archive); exit(EXIT_FAILURE); } @@ -60,9 +62,9 @@ int main(int argc, char *argv[]) { 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. */ + /* 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) { @@ -79,34 +81,34 @@ int main(int argc, char *argv[]) { case LIST: list(data_stream); } + free(data_stream.start); fclose(archive); return 0; } -/* Simple check of the archive's magic number to decide - whether or not it represents a valid XP3 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) { - char* magic_buffer = malloc(11); + int ret = 1; + char* buffer = malloc(11); rewind(archive); - fread(magic_buffer, 11, 1, archive); - if (memcmp(magic_buffer, XP3_MAGIC, 11)) { - free(magic_buffer); - return 0; - } - free(magic_buffer); - return 1; + 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_word; + uint32_t version; fseek(archive, XP3_VERSION_OFFSET, SEEK_SET); - fread(&version_word, sizeof(uint32_t), 1, archive); + fread(&version, sizeof(uint32_t), 1, archive); /* 0x00 indicates version 1, and 0x01 indicates version 2. */ - return version_word == 1 ? 2 : 1; + return version == 1 ? 2 : 1; } @@ -118,6 +120,7 @@ uint64_t get_table_offset(FILE *archive, uint8_t archive_version) { 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); @@ -126,9 +129,12 @@ uint64_t get_table_offset(FILE *archive, uint8_t archive_version) { fclose(archive); exit(EXIT_FAILURE); } - /* The read table_offset is an offset to the real table offset. */ + + /* 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. */ + /* 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.h b/src/write.h index 7bd1fdc..51a847e 100644 --- a/src/write.h +++ b/src/write.h @@ -15,6 +15,8 @@ You should have received a copy of the GNU General Public License along with Nekopack. If not, see . */ +#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 { -- cgit v1.3