Tree builder not crashing, need to check functional correctness.
This commit is contained in:
@@ -28,8 +28,11 @@ int main(void) {
|
|||||||
size_t read = fread(buffer, sizeof(char), size, fp);
|
size_t read = fread(buffer, sizeof(char), size, fp);
|
||||||
assert(read == size);
|
assert(read == size);
|
||||||
|
|
||||||
|
struct sized_buf esp = { .data = buffer, .size = size };
|
||||||
|
|
||||||
struct esp_stats stats = espr_stats(buffer, size);
|
struct esp_stats stats = espr_stats(buffer, size);
|
||||||
|
|
||||||
|
/*
|
||||||
char *decompressed = malloc(stats.decompressed_size);
|
char *decompressed = malloc(stats.decompressed_size);
|
||||||
if (!decompressed)
|
if (!decompressed)
|
||||||
return errno;
|
return errno;
|
||||||
@@ -37,12 +40,21 @@ int main(void) {
|
|||||||
// espr_print(buffer, size);
|
// espr_print(buffer, size);
|
||||||
|
|
||||||
espr_decompress(buffer, size, decompressed, stats.decompressed_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);
|
free(buffer);
|
||||||
|
|
||||||
|
/*
|
||||||
espr_print(decompressed, stats.decompressed_size);
|
espr_print(decompressed, stats.decompressed_size);
|
||||||
|
|
||||||
free(decompressed);
|
free(decompressed);
|
||||||
|
*/
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#undef NDEBUG
|
||||||
|
#include <assert.h>
|
||||||
|
#define NDEBUG
|
||||||
#include "msh.h"
|
#include "msh.h"
|
||||||
|
|
||||||
// Guards for C++ usage
|
// Guards for C++ usage
|
||||||
@@ -320,6 +323,13 @@ extern "C" {
|
|||||||
return rth2rt[uint32_t_msh(type, RT_HASH_BITS, RT_HASH_SEED)];
|
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
|
/* `espr_walk` walks through the tree structure of the esp/esm binary
|
||||||
* data starting at `data` of `size` bytes.
|
* data starting at `data` of `size` bytes.
|
||||||
*
|
*
|
||||||
@@ -329,7 +339,12 @@ extern "C" {
|
|||||||
* Data is walked sequentially. Nodes passed to `cb` will be strictly
|
* Data is walked sequentially. Nodes passed to `cb` will be strictly
|
||||||
* increasing in terms of memory location within the buffer.
|
* 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
|
/* `espr_print` prints the header of every group and record in the given
|
||||||
* esp/esm binary data.
|
* esp/esm binary data.
|
||||||
@@ -355,15 +370,26 @@ extern "C" {
|
|||||||
// Calculates the size of a MetaNode tree constructed over the esp/esm
|
// Calculates the size of a MetaNode tree constructed over the esp/esm
|
||||||
// for which the stats were generated.
|
// for which the stats were generated.
|
||||||
inline size_t espr_tree_size(struct esp_stats stats) {
|
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
|
/* Copies the data from `data` to `buf` decompressing compressed fields
|
||||||
* as it does so. buf_size should be the value returned from
|
* as it does so. buf_size should be the value returned from
|
||||||
* `espr_decompressed_size`, and `buf` should be at least of that size.
|
* `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);
|
MetaNode *espr_create_tree(struct sized_buf in, struct sized_buf tree);
|
||||||
|
|
||||||
// End C++ guard
|
// End C++ guard
|
||||||
|
|||||||
@@ -117,8 +117,12 @@ void asserts(void)
|
|||||||
assert(sizeof(Bytef) == sizeof(char));
|
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
|
// check assertions that cannot be checked at compile time
|
||||||
asserts();
|
asserts();
|
||||||
|
|
||||||
@@ -128,7 +132,7 @@ void espr_walk(char *data, size_t size, struct walker_callbacks cb)
|
|||||||
const Type4 type = *(const Type4 *)data;
|
const Type4 type = *(const Type4 *)data;
|
||||||
assert(type.uint == rt[TES4]);
|
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);
|
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)
|
void espr_print(char *data, size_t size)
|
||||||
{
|
{
|
||||||
struct walker_callbacks cb = { .pre = print_cb };
|
struct walker_callbacks cb = { .pre = print_cb };
|
||||||
espr_walk(data, size, cb);
|
espr_walk(data, size, cb, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_cb(
|
void print_cb(
|
||||||
@@ -266,7 +270,7 @@ struct esp_stats espr_stats(char *data, size_t size)
|
|||||||
{
|
{
|
||||||
struct esp_stats stats = { 0 };
|
struct esp_stats stats = { 0 };
|
||||||
struct walker_callbacks cb = { .pre = stats_cb, .data = &stats };
|
struct walker_callbacks cb = { .pre = stats_cb, .data = &stats };
|
||||||
espr_walk(data, size, cb);
|
espr_walk(data, size, cb, NULL);
|
||||||
return stats;
|
return stats;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -320,7 +324,7 @@ void espr_decompress(char *data, size_t size, char *buf, size_t buf_size)
|
|||||||
.post = decompress_post,
|
.post = decompress_post,
|
||||||
.data = &s
|
.data = &s
|
||||||
};
|
};
|
||||||
espr_walk(data, size, cb);
|
espr_walk(data, size, cb, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handles the copying of groups and records, and the decompression of
|
/* 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)
|
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 };
|
struct walker_callbacks cb = { .pre = create_tree_cb, .data = &tree };
|
||||||
espr_walk(in.data, in.size, cb);
|
espr_walk(in.data, in.size, cb, root);
|
||||||
return (MetaNode *)tree_pre.data;
|
|
||||||
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
void create_tree_cb(
|
void create_tree_cb(
|
||||||
@@ -656,18 +668,22 @@ void create_tree_cb(
|
|||||||
|
|
||||||
// add new metanode to tree
|
// add new metanode to tree
|
||||||
struct sized_buf *tree = data;
|
struct sized_buf *tree = data;
|
||||||
assert(tree->size >= sizeof(MetaNode));
|
|
||||||
MetaNode *m = (MetaNode *)tree->data;
|
MetaNode *m = (MetaNode *)tree->data;
|
||||||
tree->data += sizeof(MetaNode);
|
sized_buf_update(tree, sizeof(MetaNode));
|
||||||
tree->size -= sizeof(MetaNode);
|
|
||||||
|
|
||||||
|
// parent passes their MetaNode to children
|
||||||
MetaNode *p = from_parent;
|
MetaNode *p = from_parent;
|
||||||
|
|
||||||
// construct new node
|
// construct new node
|
||||||
|
*m = (MetaNode){ 0 }; // zero/null unused
|
||||||
m->n = n;
|
m->n = n;
|
||||||
m->parent = p;
|
m->parent = p;
|
||||||
m->prev = p->last_child;
|
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;
|
p->last_child = m;
|
||||||
|
|
||||||
// send self to children
|
// send self to children
|
||||||
|
|||||||
Reference in New Issue
Block a user