From 0e67a05edcc3ba01221a6bfd14750b5b8090887f Mon Sep 17 00:00:00 2001 From: jakob Date: Wed, 1 Mar 2017 19:03:20 -0500 Subject: First working commit of the rewrite. --- src/table.c | 140 ++++++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 122 insertions(+), 18 deletions(-) (limited to 'src/table.c') diff --git a/src/table.c b/src/table.c index a541ab9..37c6e81 100644 --- a/src/table.c +++ b/src/table.c @@ -31,11 +31,45 @@ #define HNFN_MAGIC 0x6e666e68 #define NEKO_MAGIC 0x6f6b656e +#define ADLR_MAGIC 0x726c6461 +#define SEGM_MAGIC 0x6d676573 +#define INFO_MAGIC 0x6f666e69 +#define TIME_MAGIC 0x656d6974 + + +/* Reads a segm chunk into the table_entry specified by `tmp`. */ +static void read_segm(struct stream *s, struct table_entry *tmp, uint64_t count) { + tmp->segment_count = count; + tmp->segments = malloc(sizeof(struct segment *) * count); + if (tmp->segments == NULL) return; + + for (uint64_t i = 0; i < count; i++) { + tmp->segments[i] = malloc(sizeof(struct segment)); + if (tmp->segments[i] == NULL) return; + stream_read(&tmp->segments[i]->compressed, s, sizeof(uint32_t)); + stream_read(&tmp->segments[i]->offset, s, sizeof(uint64_t)); + stream_read(&tmp->segments[i]->decompressed_size, s, sizeof(uint64_t)); + stream_read(&tmp->segments[i]->compressed_size, s, sizeof(uint64_t)); + } +} + + +/* Reads an adlr chunk into the table_entry specified by `tmp`. */ +static void read_adlr(struct stream *s, struct table_entry *tmp) { + stream_read(&tmp->key, s, sizeof(uint32_t)); +} + + +/* Reads a time chunk into the table_entry specified by `tmp`. */ +static void read_time(struct stream *s, struct table_entry *tmp) { + stream_read(&tmp->ctime, s, sizeof(uint64_t)); +} + /* Returns the root of a linked list containing all of the files listed in the archive's table section. */ -struct table_entry *parse_table(struct stream *s) { - struct table_entry *cur, *root = calloc(sizeof(struct table_entry), 1); +struct table_entry *read_table(struct stream *s) { + struct table_entry *root = calloc(sizeof(struct table_entry), 1); bool ended = false; uint32_t magic; @@ -50,12 +84,57 @@ struct table_entry *parse_table(struct stream *s) { case HNFN_MAGIC: case NEKO_MAGIC: read_elif(s, root); + break; case FILE_MAGIC: + read_file(s, root); break; default: ended = 1; } } while (!ended); + + return root; +} + + +/* Reads the contents of a File chunk. If there is an entry with a + matching key in the linked list specified by `root`, that structure + will be modified. Otherwise, a new entry will be created and appended + to the linked list. */ +void read_file(struct stream *s, struct table_entry *root) { + bool ended = false; + uint32_t magic; + uint64_t size; + struct table_entry *cur, *tmp = calloc(sizeof(struct table_entry), 1); + + do { + stream_read(&magic, s, sizeof(uint32_t)); + stream_read(&size, s, sizeof(uint64_t)); + + switch (magic) { + case ADLR_MAGIC: + read_adlr(s, tmp); + break; + case SEGM_MAGIC: + read_segm(s, tmp, size / 28); + break; + case INFO_MAGIC: + stream_seek(s, size, SEEK_CUR); + break; + case TIME_MAGIC: + read_time(s, tmp); + break; + default: + ended = true; + stream_seek(s, -sizeof(uint32_t) - sizeof(uint64_t), SEEK_CUR); + } + } while (!ended); + + cur = get_node(root, tmp->key); + cur->segment_count = tmp->segment_count; + cur->segments = tmp->segments; + cur->ctime = tmp->ctime; + free(tmp); } @@ -64,46 +143,64 @@ struct table_entry *parse_table(struct stream *s) { will be modified. Otherwise, a new entry will be created and appended to the linked list. */ void read_elif(struct stream *s, struct table_entry *root) { - char *name, *buf; - uint16_t name_size; + char *name, *buf, *tmp; + uint16_t name_len; uint32_t key; struct table_entry *cur; stream_read(&key, s, sizeof(uint32_t)); - stream_read(&name_size, s, sizeof(uint16_t)); + stream_read(&name_len, s, sizeof(uint16_t)); /* The value provided by the archive represents the number of UTF-16LE characters, not the number of bytes in the string. */ - name_size = name_size * 2 + 2; + name_len = name_len * 2 + 2; - for (cur = root; cur != NULL && cur->key != key; cur = cur->next); - if (cur == NULL) { - cur = calloc(sizeof(struct table_entry), 1); - if (cur == NULL) return; - entry_append(root, cur); + cur = get_node(root, key); + if (cur->filename != NULL) { + return; } - if (name_size < 0x100) { - buf = malloc(name_size); - name = malloc(name_size); + if (name_len < 0x100) { + buf = malloc(name_len); + name = malloc(name_len); if (buf == NULL || name == NULL) return; - stream_read(buf, s, name_size); - utf16le_decode(buf, name, name_size); + stream_read(buf, s, name_len); + utf16le_decode(buf, name, name_len); free(buf); - name = realloc(name, strlen(name) + 1); - if (name == NULL) return; + tmp = realloc(name, strlen(name) + 1); + if (tmp == NULL) { + free(name); + return; + } + name = tmp; } else { /* strdup isn't defined in ISO/IEC 9899:1999 C. */ name = malloc(14); if (name == NULL) return; strncpy(name, "COPYRIGHT.txt", 14); + stream_seek(s, name_len, SEEK_CUR); } cur->filename = name; } +/* Traverses `root` for a node with the given key. If the linked list + lacks a node with the key, a new node is created and appended. */ +struct table_entry *get_node(struct table_entry *root, uint32_t key) { + struct table_entry *cur; + for (cur = root; cur != NULL && cur->key != key; cur = cur->next); + if (cur == NULL) { + cur = calloc(sizeof(struct table_entry), 1); + if (cur == NULL) return NULL; + entry_append(root, cur); + cur->key = key; + } + return cur; +} + + /* Inserts `e` to the end of the linked list specified by `root`. */ void entry_append(struct table_entry *root, struct table_entry *e) { struct table_entry *cur; @@ -116,5 +213,12 @@ void entry_append(struct table_entry *root, struct table_entry *e) { void entry_free(struct table_entry *cur) { if (cur->next != NULL) entry_free(cur->next); + if (cur->filename != NULL) + free(cur->filename); + if (cur->segments != NULL) { + for (uint64_t i = 0; i < cur->segment_count; i++) + free(cur->segments[i]); + free(cur->segments); + } free(cur); } -- cgit v1.3