summaryrefslogtreecommitdiff
path: root/src/table.c
diff options
context:
space:
mode:
authorjakob <jakob@memeware.net>2017-03-01 19:03:20 -0500
committerjakob <jakob@memeware.net>2017-03-01 19:03:20 -0500
commit0e67a05edcc3ba01221a6bfd14750b5b8090887f (patch)
tree94729dcef273244164d6b84d72d17481818baa7f /src/table.c
parentd65a3ae8790ae28a90f0ebcf0bc4dc078c67dc35 (diff)
First working commit of the rewrite.
Diffstat (limited to 'src/table.c')
-rw-r--r--src/table.c140
1 files changed, 122 insertions, 18 deletions
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);
}