From ed613db39eefa111141b49581fc22fbed5803d2c Mon Sep 17 00:00:00 2001 From: William Miles Date: Mon, 5 Sep 2022 21:01:26 +1000 Subject: [PATCH] Half implemented decompression. Need to figure out how to handle group size adjustment on decompressed data. --- NavmeshList/main.c | 13 ++++++++-- espReader/ESPReader.h | 6 +++++ espReader/Reader.c | 59 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 2 deletions(-) diff --git a/NavmeshList/main.c b/NavmeshList/main.c index c9602b6..ede5f43 100644 --- a/NavmeshList/main.c +++ b/NavmeshList/main.c @@ -23,8 +23,17 @@ int main(void) { size_t read = fread(buffer, sizeof(char), size, fp); assert(read == size); - size_t formids = espr_formid_count(buffer, size); - printf("FormID Count: %zu\n", formids); + size_t dc_size = espr_decompressed_size(buffer, size); + + char *decompressed = malloc(dc_size); + if (!decompressed) + return errno; + + espr_decompress(buffer, size, decompressed, dc_size); + + size_t formid_count = espr_formid_count(decompressed, dc_size); + + printf("FormID Count: %zu\n", formid_count); return 0; } diff --git a/espReader/ESPReader.h b/espReader/ESPReader.h index 17a1240..3f41784 100644 --- a/espReader/ESPReader.h +++ b/espReader/ESPReader.h @@ -277,6 +277,12 @@ extern "C" { */ size_t espr_formid_count(char *data, size_t size); + /* 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); + // End C++ guard #ifdef __cplusplus } diff --git a/espReader/Reader.c b/espReader/Reader.c index 36b00bb..bbc99dc 100644 --- a/espReader/Reader.c +++ b/espReader/Reader.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include "zlib.h" @@ -45,6 +46,7 @@ Timestamp convert_ts(uint16_t ts); void print_callback(Node n, void *_); void dc_size_cb(Node n, void *dc_size_ptr); void formid_count_cb(Node n, void *count_ptr); +void decompress_cb(Node n, void *decom_ptr); // // === FUNCTIONS === @@ -135,6 +137,63 @@ void formid_count_cb(Node n, void *count_ptr) { } } +struct decom { + char *buf; + char *start; + size_t remaining; +}; + +void espr_decompress(char *data, size_t size, char *buf, size_t buf_size) { + struct decom s = { .buf = buf, .start = data, .remaining = buf_size }; + espr_walk(data, size, decompress_cb, &s); + + // handle final segment + size_t remaining = buf_size - (s.buf - buf); + assert(remaining == s.remaining); + memcpy(s.buf, s.start, remaining); +} + +void decompress_cb(Node n, void *decom_ptr) { + struct decom *d = decom_ptr; + + // only need to do anything when we find a compressed flag + if (n.type == NT_RECORD && n.header.record->flags & COMPRESSED_FLAG) { + // uncompressed segment copy + size_t size = n.data - d->start; + assert(size < d->remaining); + memcpy(d->buf, d->start, size); + + // update decom struct + d->remaining -= size; + d->buf += size; + + // copied header + Record *header = (Record *)(d->buf) - 1; + + // decompress directly into buffer + const size_t dc_size = *((uint32_t *)n.data); + size_t to_copy = dc_size; + size_t cur_size = n.header.record->size - sizeof(uint32_t); + char *data_start = n.data + sizeof(uint32_t); + int ret = uncompress(d->buf, &to_copy, data_start, cur_size); + assert(ret == Z_OK); + assert(to_copy == dc_size); + + // update decom struct + d->remaining -= dc_size; + d->buf += dc_size; + + // update start to start of next record/group + d->start = n.data + n.header.record->size; + + // update header data size + header->size = dc_size; + + // unset compressed flag + header->flags &= ~COMPRESSED_FLAG; + } +} + /* Unknown data will be some concatenation of groups and records. * * `walk_concat` will call the appropriate walking function