diff --git a/NavmeshList/main.c b/NavmeshList/main.c index c396c37..8cd0b35 100644 --- a/NavmeshList/main.c +++ b/NavmeshList/main.c @@ -28,8 +28,11 @@ int main(void) { size_t read = fread(buffer, sizeof(char), size, fp); assert(read == size); + struct sized_buf esp = { .data = buffer, .size = size }; + struct esp_stats stats = espr_stats(buffer, size); + /* char *decompressed = malloc(stats.decompressed_size); if (!decompressed) return errno; @@ -37,12 +40,21 @@ int main(void) { // espr_print(buffer, size); espr_decompress(buffer, size, decompressed, stats.decompressed_size); + */ + + size_t tree_size = espr_tree_size(stats); + char *tree_data = malloc(tree_size); + struct sized_buf tree = { .data = tree_data, .size = tree_size }; + + MetaNode *root = espr_create_tree(esp, tree); free(buffer); + /* espr_print(decompressed, stats.decompressed_size); free(decompressed); + */ return 0; } diff --git a/espReader/ESPReader.h b/espReader/ESPReader.h index afa891b..1f58b63 100644 --- a/espReader/ESPReader.h +++ b/espReader/ESPReader.h @@ -24,6 +24,9 @@ */ #include +#undef NDEBUG +#include +#define NDEBUG #include "msh.h" // Guards for C++ usage @@ -320,6 +323,13 @@ extern "C" { return rth2rt[uint32_t_msh(type, RT_HASH_BITS, RT_HASH_SEED)]; } + // Updates a sized_buf after using `size` bytes + inline void sized_buf_update(struct sized_buf *sb, size_t size) { + assert(sb->size >= size); + sb->data += size; + sb->size -= size; + } + /* `espr_walk` walks through the tree structure of the esp/esm binary * data starting at `data` of `size` bytes. * @@ -329,7 +339,12 @@ extern "C" { * Data is walked sequentially. Nodes passed to `cb` will be strictly * increasing in terms of memory location within the buffer. */ - void espr_walk(char *data, size_t size, struct walker_callbacks cb); + void espr_walk( + char *data, + size_t size, + struct walker_callbacks cb, + void *from_parent + ); /* `espr_print` prints the header of every group and record in the given * esp/esm binary data. @@ -355,15 +370,26 @@ extern "C" { // Calculates the size of a MetaNode tree constructed over the esp/esm // for which the stats were generated. inline size_t espr_tree_size(struct esp_stats stats) { - return sizeof(MetaNode) * espr_node_count(stats); + return sizeof(MetaNode) * ((size_t)espr_node_count(stats) + 1); } /* Copies the data from `data` to `buf` decompressing compressed fields * as it does so. buf_size should be the value returned from * `espr_decompressed_size`, and `buf` should be at least of that size. */ - void espr_decompress(char *data, size_t size, char *buf, size_t buf_size); + void espr_decompress( + char *data, + size_t size, + char *buf, + size_t buf_size + ); + /* Constructs a MetaNode tree in `tree` over the esp/esm data in `in`. + * + * MetaNode trees allows for easier programatic traversal of the esp/esm + * data, and also allow for modifications that add, remove, or change + * the size of groups/records/fields. + */ MetaNode *espr_create_tree(struct sized_buf in, struct sized_buf tree); // End C++ guard diff --git a/espReader/Reader.c b/espReader/Reader.c index fbbeec5..016debc 100644 --- a/espReader/Reader.c +++ b/espReader/Reader.c @@ -117,8 +117,12 @@ void asserts(void) assert(sizeof(Bytef) == sizeof(char)); } -void espr_walk(char *data, size_t size, struct walker_callbacks cb) -{ +void espr_walk( + char *data, + size_t size, + struct walker_callbacks cb, + void *from_parent +) { // check assertions that cannot be checked at compile time asserts(); @@ -128,7 +132,7 @@ void espr_walk(char *data, size_t size, struct walker_callbacks cb) const Type4 type = *(const Type4 *)data; assert(type.uint == rt[TES4]); - data = walk_concat(data, size, cb, NULL); + data = walk_concat(data, size, cb, from_parent); assert(data == data_start + size); } @@ -236,7 +240,7 @@ char *walk_record(char *data, struct walker_callbacks cb, void *from_parent) void espr_print(char *data, size_t size) { struct walker_callbacks cb = { .pre = print_cb }; - espr_walk(data, size, cb); + espr_walk(data, size, cb, NULL); } void print_cb( @@ -266,7 +270,7 @@ struct esp_stats espr_stats(char *data, size_t size) { struct esp_stats stats = { 0 }; struct walker_callbacks cb = { .pre = stats_cb, .data = &stats }; - espr_walk(data, size, cb); + espr_walk(data, size, cb, NULL); return stats; } @@ -320,7 +324,7 @@ void espr_decompress(char *data, size_t size, char *buf, size_t buf_size) .post = decompress_post, .data = &s }; - espr_walk(data, size, cb); + espr_walk(data, size, cb, NULL); } /* Handles the copying of groups and records, and the decompression of @@ -639,10 +643,18 @@ Timestamp convert_ts(uint16_t ts) MetaNode *espr_create_tree(struct sized_buf in, struct sized_buf tree) { - const struct sized_buf tree_pre = tree; + // create root node + MetaNode *root = (MetaNode *)tree.data; + *root = (MetaNode){ 0 }; + + // update tree + sized_buf_update(&tree, sizeof(MetaNode)); + + // walk struct walker_callbacks cb = { .pre = create_tree_cb, .data = &tree }; - espr_walk(in.data, in.size, cb); - return (MetaNode *)tree_pre.data; + espr_walk(in.data, in.size, cb, root); + + return root; } void create_tree_cb( @@ -656,18 +668,22 @@ void create_tree_cb( // add new metanode to tree struct sized_buf *tree = data; - assert(tree->size >= sizeof(MetaNode)); MetaNode *m = (MetaNode *)tree->data; - tree->data += sizeof(MetaNode); - tree->size -= sizeof(MetaNode); + sized_buf_update(tree, sizeof(MetaNode)); + // parent passes their MetaNode to children MetaNode *p = from_parent; // construct new node + *m = (MetaNode){ 0 }; // zero/null unused m->n = n; m->parent = p; m->prev = p->last_child; - p->last_child->next = m; + // the linked list of children may not already exist + if (p->last_child) + p->last_child->next = m; + else + p->first_child = m; p->last_child = m; // send self to children