diff --git a/.gitignore b/.gitignore
index 7973d5d..a0a8eb0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,7 +3,7 @@
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
-NavmeshList/Skyrim.esm
+*.esm
# User-specific files
*.rsuser
diff --git a/NavmeshList/NavmeshList.vcxproj b/NavmeshList/NavmeshList.vcxproj
index b79e729..6d85c46 100644
--- a/NavmeshList/NavmeshList.vcxproj
+++ b/NavmeshList/NavmeshList.vcxproj
@@ -409,7 +409,8 @@
true
NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
true
- ../ESPReader
+ ..\SizedBuffer;..\ESPReader
+ Disabled
Console
@@ -427,7 +428,7 @@
true
NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
true
- ../ESPReader
+ ..\SizedBuffer;..\ESPReader
Console
diff --git a/Navmesher.sln b/Navmesher.sln
index edd55df..dea6d61 100644
--- a/Navmesher.sln
+++ b/Navmesher.sln
@@ -7,8 +7,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ESPReader", "espReader\espR
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NavmeshList", "NavmeshList\NavmeshList.vcxproj", "{4CE7E7FD-7FFF-4C42-AB16-C9C2B01E5D56}"
EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mph_gen", "mph_gen\mph_gen.vcxproj", "{385E9D8D-F3F4-4FD4-B182-D06F877CB090}"
-EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libz-static", "zlib-win-build\build-VS2022\libz-static\libz-static.vcxproj", "{B56D17BC-072B-42F3-844A-870A07AFBAAA}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{F2B93142-BC5A-4D28-8AAA-24D52FA59514}"
@@ -16,6 +14,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
.editorconfig = .editorconfig
EndProjectSection
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SizedBuffer", "SizedBuffer\SizedBuffer.vcxproj", "{CB1C8F66-5B90-4DE7-890B-F6430DAAF25F}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Itanium = Debug|Itanium
@@ -65,24 +65,6 @@ Global
{4CE7E7FD-7FFF-4C42-AB16-C9C2B01E5D56}.ReleaseWithoutAsm|x64.Build.0 = Release|x64
{4CE7E7FD-7FFF-4C42-AB16-C9C2B01E5D56}.ReleaseWithoutAsm|x86.ActiveCfg = Release|Win32
{4CE7E7FD-7FFF-4C42-AB16-C9C2B01E5D56}.ReleaseWithoutAsm|x86.Build.0 = Release|Win32
- {385E9D8D-F3F4-4FD4-B182-D06F877CB090}.Debug|Itanium.ActiveCfg = Debug|x64
- {385E9D8D-F3F4-4FD4-B182-D06F877CB090}.Debug|Itanium.Build.0 = Debug|x64
- {385E9D8D-F3F4-4FD4-B182-D06F877CB090}.Debug|x64.ActiveCfg = Debug|x64
- {385E9D8D-F3F4-4FD4-B182-D06F877CB090}.Debug|x64.Build.0 = Debug|x64
- {385E9D8D-F3F4-4FD4-B182-D06F877CB090}.Debug|x86.ActiveCfg = Debug|Win32
- {385E9D8D-F3F4-4FD4-B182-D06F877CB090}.Debug|x86.Build.0 = Debug|Win32
- {385E9D8D-F3F4-4FD4-B182-D06F877CB090}.Release|Itanium.ActiveCfg = Release|x64
- {385E9D8D-F3F4-4FD4-B182-D06F877CB090}.Release|Itanium.Build.0 = Release|x64
- {385E9D8D-F3F4-4FD4-B182-D06F877CB090}.Release|x64.ActiveCfg = Release|x64
- {385E9D8D-F3F4-4FD4-B182-D06F877CB090}.Release|x64.Build.0 = Release|x64
- {385E9D8D-F3F4-4FD4-B182-D06F877CB090}.Release|x86.ActiveCfg = Release|Win32
- {385E9D8D-F3F4-4FD4-B182-D06F877CB090}.Release|x86.Build.0 = Release|Win32
- {385E9D8D-F3F4-4FD4-B182-D06F877CB090}.ReleaseWithoutAsm|Itanium.ActiveCfg = Release|x64
- {385E9D8D-F3F4-4FD4-B182-D06F877CB090}.ReleaseWithoutAsm|Itanium.Build.0 = Release|x64
- {385E9D8D-F3F4-4FD4-B182-D06F877CB090}.ReleaseWithoutAsm|x64.ActiveCfg = Release|x64
- {385E9D8D-F3F4-4FD4-B182-D06F877CB090}.ReleaseWithoutAsm|x64.Build.0 = Release|x64
- {385E9D8D-F3F4-4FD4-B182-D06F877CB090}.ReleaseWithoutAsm|x86.ActiveCfg = Release|Win32
- {385E9D8D-F3F4-4FD4-B182-D06F877CB090}.ReleaseWithoutAsm|x86.Build.0 = Release|Win32
{B56D17BC-072B-42F3-844A-870A07AFBAAA}.Debug|Itanium.ActiveCfg = Debug|x64
{B56D17BC-072B-42F3-844A-870A07AFBAAA}.Debug|Itanium.Build.0 = Debug|x64
{B56D17BC-072B-42F3-844A-870A07AFBAAA}.Debug|x64.ActiveCfg = Debug|x64
@@ -101,6 +83,24 @@ Global
{B56D17BC-072B-42F3-844A-870A07AFBAAA}.ReleaseWithoutAsm|x64.Build.0 = Release|x64
{B56D17BC-072B-42F3-844A-870A07AFBAAA}.ReleaseWithoutAsm|x86.ActiveCfg = Release|Win32
{B56D17BC-072B-42F3-844A-870A07AFBAAA}.ReleaseWithoutAsm|x86.Build.0 = Release|Win32
+ {CB1C8F66-5B90-4DE7-890B-F6430DAAF25F}.Debug|Itanium.ActiveCfg = Debug|x64
+ {CB1C8F66-5B90-4DE7-890B-F6430DAAF25F}.Debug|Itanium.Build.0 = Debug|x64
+ {CB1C8F66-5B90-4DE7-890B-F6430DAAF25F}.Debug|x64.ActiveCfg = Debug|x64
+ {CB1C8F66-5B90-4DE7-890B-F6430DAAF25F}.Debug|x64.Build.0 = Debug|x64
+ {CB1C8F66-5B90-4DE7-890B-F6430DAAF25F}.Debug|x86.ActiveCfg = Debug|Win32
+ {CB1C8F66-5B90-4DE7-890B-F6430DAAF25F}.Debug|x86.Build.0 = Debug|Win32
+ {CB1C8F66-5B90-4DE7-890B-F6430DAAF25F}.Release|Itanium.ActiveCfg = Release|x64
+ {CB1C8F66-5B90-4DE7-890B-F6430DAAF25F}.Release|Itanium.Build.0 = Release|x64
+ {CB1C8F66-5B90-4DE7-890B-F6430DAAF25F}.Release|x64.ActiveCfg = Release|x64
+ {CB1C8F66-5B90-4DE7-890B-F6430DAAF25F}.Release|x64.Build.0 = Release|x64
+ {CB1C8F66-5B90-4DE7-890B-F6430DAAF25F}.Release|x86.ActiveCfg = Release|Win32
+ {CB1C8F66-5B90-4DE7-890B-F6430DAAF25F}.Release|x86.Build.0 = Release|Win32
+ {CB1C8F66-5B90-4DE7-890B-F6430DAAF25F}.ReleaseWithoutAsm|Itanium.ActiveCfg = Release|x64
+ {CB1C8F66-5B90-4DE7-890B-F6430DAAF25F}.ReleaseWithoutAsm|Itanium.Build.0 = Release|x64
+ {CB1C8F66-5B90-4DE7-890B-F6430DAAF25F}.ReleaseWithoutAsm|x64.ActiveCfg = Release|x64
+ {CB1C8F66-5B90-4DE7-890B-F6430DAAF25F}.ReleaseWithoutAsm|x64.Build.0 = Release|x64
+ {CB1C8F66-5B90-4DE7-890B-F6430DAAF25F}.ReleaseWithoutAsm|x86.ActiveCfg = Release|Win32
+ {CB1C8F66-5B90-4DE7-890B-F6430DAAF25F}.ReleaseWithoutAsm|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/SizedBuffer/SizedBuffer.h b/SizedBuffer/SizedBuffer.h
new file mode 100644
index 0000000..cf6b57f
--- /dev/null
+++ b/SizedBuffer/SizedBuffer.h
@@ -0,0 +1,81 @@
+#pragma once
+
+// Guards for C++ usage
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include
+#include
+
+/* A sized buffer abstraction.
+ *
+ * Functions that return int's will return 0 on success and nonzero otherwise.
+ */
+
+typedef struct sized_buf SizedBuf;
+
+struct sized_buf
+{
+ char *data;
+ size_t size;
+};
+
+// Returns 0 if the given buffer has at least size bytes available
+inline int sb_check(const SizedBuf sb, const size_t size)
+{
+ return !(sb.size >= size);
+}
+
+// Moves the buffer size bytes forward, makes no checks
+inline void sb_update(SizedBuf *const sb, const size_t size)
+{
+ sb->data += size;
+ sb->size -= size;
+}
+
+// Copies size bytes of data from the source to the buffer
+inline int sb_copyin(SizedBuf *const sb, const char *const source, const size_t size)
+{
+ int ret = sb_check(*sb, size);
+ if (!ret) {
+ memcpy(sb->data, source, size);
+ sb_update(sb, size);
+ }
+ return ret;
+}
+
+// "Recasts" size bytes of memory and returns a pointer to said memory in out
+inline int sb_recast(SizedBuf *const sb, const size_t size, const void **const out)
+{
+ int ret = sb_check(*sb, size);
+ if (!ret) {
+ *out = sb->data;
+ sb_update(sb, size);
+ }
+ return ret;
+}
+
+// "Recasts" size bytes of memory without actually consuming the buffer
+inline int sb_peek(const SizedBuf sb, const size_t size, const void **const out)
+{
+ *out = sb.data;
+ return sb_check(sb, size);
+}
+
+// Returns a pointer just after the end of the sized buffer
+inline char *sb_end(const SizedBuf sb)
+{
+ return sb.data + sb.size;
+}
+
+inline bool sb_empty(const SizedBuf sb)
+{
+ return sb.size == 0;
+}
+
+// End C++ guard
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/SizedBuffer/SizedBuffer.vcxproj b/SizedBuffer/SizedBuffer.vcxproj
new file mode 100644
index 0000000..ad56421
--- /dev/null
+++ b/SizedBuffer/SizedBuffer.vcxproj
@@ -0,0 +1,138 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ 16.0
+ Win32Proj
+ {cb1c8f66-5b90-4de7-890b-f6430daaf25f}
+ SizedBuffer
+ 10.0
+
+
+
+ Application
+ true
+ v143
+ Unicode
+
+
+ Application
+ false
+ v143
+ true
+ Unicode
+
+
+ Application
+ true
+ v143
+ Unicode
+
+
+ Application
+ false
+ v143
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Level3
+ true
+ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+ true
+ true
+
+
+
+
+ Level3
+ true
+ _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/SizedBuffer/SizedBuffer.vcxproj.filters b/SizedBuffer/SizedBuffer.vcxproj.filters
new file mode 100644
index 0000000..35bab92
--- /dev/null
+++ b/SizedBuffer/SizedBuffer.vcxproj.filters
@@ -0,0 +1,27 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+
+
+ Header Files
+
+
+
+
+ Source Files
+
+
+
\ No newline at end of file
diff --git a/SizedBuffer/SizedBufferTest.c b/SizedBuffer/SizedBufferTest.c
new file mode 100644
index 0000000..fe10ae5
--- /dev/null
+++ b/SizedBuffer/SizedBufferTest.c
@@ -0,0 +1,147 @@
+#include "SizedBuffer.h"
+
+#undef NDBEUG
+#include
+#define NDEBUG
+#include
+#include
+#include
+
+
+void test_sb_check(void) {
+ SizedBuf t = { .size = 0 };
+ assert(sb_check(t, 0) == 0);
+ assert(sb_check(t, 1) != 0);
+ assert(sb_check(t, SIZE_MAX) != 0);
+
+ t.size = 100;
+ assert(sb_check(t, 99) == 0);
+ assert(sb_check(t, 100) == 0);
+ assert(sb_check(t, 101) != 0);
+ assert(sb_check(t, SIZE_MAX) != 0);
+
+ t.size = SIZE_MAX;
+ assert(sb_check(t, 0) == 0);
+ assert(sb_check(t, 1) == 0);
+ assert(sb_check(t, SIZE_MAX) == 0);
+}
+
+void test_sb_update(void) {
+ SizedBuf t;
+
+ t = (SizedBuf){ .data = 0, .size = 0 };
+ sb_update(&t, 0);
+ assert(t.data == 0 && t.size == 0);
+
+ t.size = 100;
+ sb_update(&t, 25);
+ assert(t.data == (void *)25 && t.size == 75);
+
+ sb_update(&t, 75);
+ assert(t.data == (void *)100 && t.size == 0);
+}
+
+void test_sb_copyin(void) {
+#define TEST_SIZE 128
+ char buf[TEST_SIZE] = { 0 };
+ SizedBuf sb = { .data = buf, .size = TEST_SIZE };
+
+ char test_buf[TEST_SIZE] = { 0 };
+ memset(test_buf, 0xff, TEST_SIZE);
+
+ int ret = 0;
+
+ assert(sb_copyin(&sb, NULL, SIZE_MAX) != 0);
+ assert(sb_copyin(&sb, NULL, TEST_SIZE + 1) != 0);
+ assert(sb_copyin(&sb, test_buf, TEST_SIZE) == 0);
+ assert(memcmp(buf, test_buf, TEST_SIZE) == 0);
+ assert(sb.size == 0);
+ assert(sb.data == buf + TEST_SIZE);
+#undef TEST_SIZE
+}
+
+void test_sb_recast(void) {
+#define TEST_SIZE 33
+ char *const start = NULL;
+ SizedBuf t = { .data = start, .size = TEST_SIZE };
+ void *out = NULL;
+
+ assert(sb_recast(&t, SIZE_MAX, &out) != 0);
+ assert(sb_recast(&t, TEST_SIZE + 1, &out) != 0);
+ assert(sb_recast(&t, 13, &out) == 0);
+ assert(t.data == start + 13);
+ assert(t.size == TEST_SIZE - 13);
+ assert(out == NULL);
+ assert(sb_recast(&t, 8, &out) == 0);
+ assert(t.data == (void *)(13 + 8));
+ assert(t.size == TEST_SIZE - 13 - 8);
+ assert(out == (void *)13);
+#undef TEST_SIZE
+}
+
+void test_sb_end(void) {
+ SizedBuf sb = { .data = NULL, .size = SIZE_MAX };
+ assert(sb_end(sb) == (void *)SIZE_MAX);
+
+ sb = (SizedBuf){ .data = (void *)0xdeadbeefull, .size = 0x1337 };
+ assert(sb_end(sb) == (void *)(0xdeadbeefull + 0x1337ull));
+}
+
+void test_sb_empty(void) {
+ SizedBuf sb = { .data = NULL, .size = SIZE_MAX };
+ assert(!sb_empty(sb));
+ sb.size = 1;
+ assert(!sb_empty(sb));
+ sb.size = 0;
+ assert(sb_empty(sb));
+}
+
+void test_sb_peek(void) {
+#define TEST_SIZE 128
+ SizedBuf sb = { .data = NULL, .size = TEST_SIZE };
+ void *test = (void *)0xdeadbeefull;
+ assert(sb_peek(sb, SIZE_MAX, &test) != 0);
+ assert(sb_peek(sb, TEST_SIZE + 1, &test) != 0);
+ assert(sb_peek(sb, TEST_SIZE, &test) == 0);
+ assert(sb.data == test);
+ assert(sb.size == TEST_SIZE);
+ test = (void *)'FOUR';
+ assert(sb_peek(sb, 0, &test) == 0);
+ assert(sb.data == test);
+ assert(sb.size == TEST_SIZE);
+#undef TEST_SIZE
+}
+
+typedef struct {
+ void (*test)(void);
+ const char *const name;
+} Test;
+
+#define TEST(x) { x, #x }
+Test tests[] = {
+ TEST(test_sb_check),
+ TEST(test_sb_update),
+ TEST(test_sb_copyin),
+ TEST(test_sb_recast),
+ TEST(test_sb_end),
+ TEST(test_sb_empty),
+ TEST(test_sb_peek),
+};
+#undef TEST
+
+int main() {
+#ifdef DISABLE_STDOUT
+ fclose(stdout);
+#endif
+
+ // run all tests
+ size_t num_tests = sizeof(tests) / sizeof(tests[0]);
+ for (size_t i = 0; i < num_tests; i++) {
+ tests[i].test();
+ fprintf(stderr, "Test passed: %s\n", tests[i].name);
+ }
+
+ fprintf(stderr, "All tests passed.\n");
+
+ return 0;
+}
\ No newline at end of file
diff --git a/espReader/ESPReader.h b/espReader/ESPReader.h
index dcdecca..2c5abf5 100644
--- a/espReader/ESPReader.h
+++ b/espReader/ESPReader.h
@@ -24,10 +24,13 @@
*/
#include
+#include
#undef NDEBUG
#include
#define NDEBUG
+
#include "msh.h"
+#include "SizedBuffer.h"
// Guards for C++ usage
#ifdef __cplusplus
@@ -76,6 +79,7 @@ extern "C" {
typedef struct field Field;
typedef struct meta_node MetaNode;
typedef struct meta_tree MetaTree;
+ typedef struct esp_stats ESPStats;
//
@@ -113,11 +117,6 @@ extern "C" {
char _pad[4];
};
- struct sized_buf {
- char *data;
- size_t size;
- };
-
//
// === ENUMS ===
//
@@ -334,13 +333,6 @@ 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.
*
@@ -351,7 +343,7 @@ extern "C" {
* increasing in terms of memory location within the buffer.
*/
void espr_walk(
- struct sized_buf esp,
+ SizedBuf esp,
struct walker_callbacks cb,
void *from_parent
);
@@ -359,13 +351,13 @@ extern "C" {
/* `espr_print` prints the header of every group and record in the given
* esp/esm binary data.
*/
- void espr_print(struct sized_buf esp);
+ void espr_print(SizedBuf esp);
/* Calculates the number of groups and records in the esp/esm file and
* the size of the esp/esm if all of the compressed records were
* decompressed.
*/
- struct esp_stats espr_stats(struct sized_buf esp);
+ struct esp_stats espr_stats(SizedBuf esp);
// Calculates the number of formid's in an esm/esp from the stats
inline uint32_t espr_formid_count(struct esp_stats stats) {
@@ -387,10 +379,7 @@ extern "C" {
* 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(
- struct sized_buf esp,
- struct sized_buf decom
- );
+ void espr_decompress(SizedBuf esp, SizedBuf decom);
/* Constructs a MetaNode tree in `tree` over the esp/esm data in `in`.
*
@@ -398,13 +387,13 @@ extern "C" {
* data, and also allow for modifications that add, remove, or change
* the size of groups/records/fields.
*/
- MetaTree espr_create_tree(struct sized_buf in, struct sized_buf tree);
+ MetaTree espr_create_tree(SizedBuf in, SizedBuf tree);
void espr_meta_walk(MetaTree tree, struct meta_callbacks cb);
void espr_meta_node_walk(MetaNode *m, struct meta_callbacks cb);
- void espr_serialize(MetaTree tree, struct sized_buf out);
+ void espr_serialize(MetaTree tree, SizedBuf out);
// End C++ guard
#ifdef __cplusplus
diff --git a/espReader/Reader.c b/espReader/Reader.c
index 4298f1f..d401909 100644
--- a/espReader/Reader.c
+++ b/espReader/Reader.c
@@ -38,13 +38,9 @@ const int year_offset = 9;
void asserts(void);
// Tree walkers
-char *walk_concat(
- struct sized_buf tree,
- struct walker_callbacks cb,
- void *from_parent
-);
-char *walk_group(char *data, struct walker_callbacks cb, void *from_parent);
-char *walk_record(char *data, struct walker_callbacks cb, void *from_parent);
+void walk_concat(SizedBuf *tree, struct walker_callbacks cb, void *from_parent);
+void walk_group(SizedBuf *tree, struct walker_callbacks cb, void *from_parent);
+void walk_record(SizedBuf *tree, struct walker_callbacks cb, void *from_parent);
// Header printers
void print_group_header(Group *header);
@@ -118,21 +114,23 @@ void asserts(void)
}
void espr_walk(
- struct sized_buf esp,
+ SizedBuf esp,
struct walker_callbacks cb,
void *from_parent
) {
// check assertions that cannot be checked at compile time
asserts();
- char *data_start = esp.data;
-
// check that we are at the start of the file
- const Type4 type = *(const Type4 *)esp.data;
- assert(type.uint == rt[TES4]);
+ {
+ Type4 *type = NULL;
+ int err = sb_peek(esp, sizeof(Type4), &type);
+ assert(err == 0);
+ assert(type->uint == rt[TES4]);
+ }
- esp.data = walk_concat(esp, cb, from_parent);
- assert(esp.data == data_start + esp.size);
+ walk_concat(&esp, cb, from_parent);
+ assert(sb_empty(esp));
}
/* Unknown data will be some concatenation of groups and records.
@@ -140,27 +138,22 @@ void espr_walk(
* `walk_concat` will call the appropriate walking function
* for each segment of unknown data in this concatenation.
*/
-char *walk_concat(
- struct sized_buf tree,
- struct walker_callbacks cb,
- void *from_parent
-) {
- const char *end = tree.data + tree.size;
- while (tree.data != end) {
- assert(tree.data < end);
-
- const Type4 *type = (Type4 *)tree.data;
+void walk_concat(SizedBuf *tree, struct walker_callbacks cb, void *from_parent)
+{
+ while (!sb_empty(*tree)) {
+ const Type4 *type = NULL;
+ int err = sb_peek(*tree, sizeof(Type4), &type);
+ assert(err == 0);
// check valid type
assert(rt[rt_hash(type->uint)] == type->uint);
// only need to distinguish between groups and records
if (type->uint == rt[GRUP])
- tree.data = walk_group(tree.data, cb, from_parent);
+ walk_group(tree, cb, from_parent);
else
- tree.data = walk_record(tree.data, cb, from_parent);
+ walk_record(tree, cb, from_parent);
}
- return tree.data;
}
/* Walk a group record. Group records are containers for any other type of
@@ -169,18 +162,25 @@ char *walk_concat(
* This function will also call `cb` with the node constructed from this group
* record.
*/
-char *walk_group(char *data, struct walker_callbacks cb, void *from_parent)
+void walk_group(SizedBuf *tree, struct walker_callbacks cb, void *from_parent)
{
- Group *const header = (Group *const)data;
+ Group *header = NULL;
+ {
+ int err = sb_peek(*tree, sizeof(Group), &header);
+ assert(err == 0);
+ }
- // The size in the group header includes the size of the header
- char *data_start = data + sizeof(Group);
- char *data_end = data + header->size;
- size_t data_size = data_end - data_start;
+ SizedBuf group = { .size = header->size };
+ {
+ int err = sb_recast(tree, group.size, &group.data);
+ assert(err == 0);
+ err = sb_recast(&group, sizeof(Group), &header);
+ assert(err == 0);
+ }
Node n = {
.header.group = header,
- .data = data_start,
+ .data = group.data,
.type = NT_GROUP
};
void *carry = NULL;
@@ -191,27 +191,30 @@ char *walk_group(char *data, struct walker_callbacks cb, void *from_parent)
cb.pre(n, cb.data, &carry, from_parent, &to_children);
// Walk through the concatenation of data inside the group.
- struct sized_buf tree = { data_start, data_size };
- data = walk_concat(tree, cb, to_children);
- assert(data == data_end);
+ walk_concat(&group, cb, to_children);
+ assert(sb_empty(group));
// Post-walk callback
if (cb.post)
cb.post(n, cb.data, carry);
-
- return data;
}
-char *walk_record(char *data, struct walker_callbacks cb, void *from_parent)
+void walk_record(SizedBuf *tree, struct walker_callbacks cb, void *from_parent)
{
- Record *header = (Record *)data;
- assert(header->type.uint != rt[GRUP]);
+ Record *header = NULL;
+ char *data = NULL;
+ {
+ int err = sb_recast(tree, sizeof(Record), &header);
+ assert(err == 0);
+ err = sb_recast(tree, header->size, &data);
+ assert(err == 0);
+ }
- char *data_start = data + sizeof(Record);
+ assert(header->type.uint != rt[GRUP]);
Node n = {
.header.record = header,
- .data = data_start,
+ .data = data,
.type = NT_RECORD
};
void *carry = NULL;
@@ -226,17 +229,12 @@ char *walk_record(char *data, struct walker_callbacks cb, void *from_parent)
if (cb.pre)
cb.pre(n, cb.data, &carry, from_parent, &to_children);
- // Update data ptr based on record size.
- data += sizeof(Record) + header->size;
-
// Post-walk callback
if (cb.post)
cb.post(n, cb.data, carry);
-
- return data;
}
-void espr_print(struct sized_buf esp)
+void espr_print(SizedBuf esp)
{
struct walker_callbacks cb = { .pre = print_cb };
espr_walk(esp, cb, NULL);
@@ -265,9 +263,9 @@ void print_cb(
}
}
-struct esp_stats espr_stats(struct sized_buf esp)
+ESPStats espr_stats(SizedBuf esp)
{
- struct esp_stats stats = { 0 };
+ ESPStats stats = { 0 };
struct walker_callbacks cb = { .pre = stats_cb, .data = &stats };
espr_walk(esp, cb, NULL);
return stats;
@@ -310,7 +308,7 @@ void stats_cb(
}
}
-void espr_decompress(struct sized_buf esp, struct sized_buf decom)
+void espr_decompress(SizedBuf esp, SizedBuf decom)
{
struct walker_callbacks cb = {
.pre = decompress_pre,
@@ -334,7 +332,7 @@ void espr_decompress(struct sized_buf esp, struct sized_buf decom)
*/
void decompress_pre(
Node n,
- void *decom_ptr,
+ void *out_buf,
void **carry_out,
void *from_parent,
void **to_children
@@ -342,28 +340,32 @@ void decompress_pre(
(void)from_parent;
(void)to_children;
- struct sized_buf *d = decom_ptr;
+ SizedBuf *d = out_buf;
switch (n.type) {
case NT_RECORD:
// compressed record
if (n.header.record->flags & COMPRESSED_FLAG) {
- // copy header
- memcpy(d->data, n.header.record, sizeof(Record));
-
- // copied header reference
- Record *header = (Record *)d->data;
-
- // update decom struct
- sized_buf_update(d, sizeof(Record));
+ Record *copied_header = NULL;
+ {
+ // Acces for copied header
+ int err = sb_peek(*d, sizeof(Record), &copied_header);
+ assert(err == 0);
+ // copy header
+ err = sb_copyin(d, (char *)n.header.record, sizeof(Record));
+ assert(err == 0);
+ }
// decompress directly into buffer
// first 4 bytes are the decompressed size
const uint32_t dc_size = *((uint32_t *)n.data);
uint32_t to_copy = dc_size;
- uint32_t cur_size =
- n.header.record->size - sizeof(uint32_t);
+ uint32_t cur_size = n.header.record->size - sizeof(uint32_t);
char *data_start = n.data + sizeof(uint32_t);
+
+ // check that we have enough space in the buffer
+ sb_check(*d, dc_size);
+
int ret = uncompress(
(Bytef *)d->data,
(uLongf *)&to_copy,
@@ -373,32 +375,27 @@ void decompress_pre(
assert(ret == Z_OK);
assert(to_copy == dc_size);
- // update decom struct
- sized_buf_update(d, dc_size);
+ // update the buffer
+ sb_update(d, dc_size);
// update header data size
- header->size = dc_size;
+ copied_header->size = dc_size;
// unset compressed flag
- header->flags &= ~COMPRESSED_FLAG;
+ copied_header->flags &= ~COMPRESSED_FLAG;
} else {
// copy record
- size_t record_size = sizeof(Record) + n.header.record->size;
- memcpy(d->data, n.header.record, record_size);
-
- // update decom
- sized_buf_update(d, record_size);
+ size_t record_size = sizeof(Record)
+ + n.header.record->size;
+ sb_copyin(d, (char *)n.header.record, record_size);
}
break;
case NT_GROUP:
- // copy header, contents will be copied while walking
- memcpy(d->data, n.header.group, sizeof(Group));
-
// save copied header location for post-walk group size recalc
*carry_out = (void *)d->data;
- // update decom
- sized_buf_update(d, sizeof(Group));
+ // copy header, contents will be copied while walking
+ sb_copyin(d, (char *)n.header.group, sizeof(Group));
break;
default:
@@ -412,9 +409,9 @@ void decompress_pre(
* based on the difference between the current destination pointer and the
* group header pointer.
*/
-void decompress_post(Node n, void *decom_ptr, void *carry_in)
+void decompress_post(Node n, void *out, void *carry_in)
{
- struct sized_buf *d = decom_ptr;
+ SizedBuf *d = out;
// only need to handle group resize
if (n.type == NT_GROUP) {
@@ -630,15 +627,16 @@ Timestamp convert_ts(uint16_t ts)
return (Timestamp) { year, month, day };
}
-MetaTree espr_create_tree(struct sized_buf in, struct sized_buf tree)
+MetaTree espr_create_tree(SizedBuf in, SizedBuf tree)
{
// create root node
- MetaNode *root = (MetaNode *)tree.data;
+ MetaNode *root = NULL;
+ {
+ int err = sb_recast(&tree, sizeof(MetaNode), &root);
+ assert(err == 0);
+ }
*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, cb, root);
@@ -656,9 +654,12 @@ void create_tree_cb(
(void)carry_out;
// add new metanode to tree
- struct sized_buf *tree = data;
- MetaNode *m = (MetaNode *)tree->data;
- sized_buf_update(tree, sizeof(MetaNode));
+ SizedBuf *tree = data;
+ MetaNode *m = NULL;
+ {
+ int err = sb_recast(tree, sizeof(MetaNode), &m);
+ assert(err == 0);
+ }
// parent passes their MetaNode to children
MetaNode *p = from_parent;
@@ -692,13 +693,13 @@ void espr_meta_node_walk(MetaNode *m, struct meta_callbacks cb) {
}
}
-void espr_serialize(MetaTree tree, struct sized_buf out) {
+void espr_serialize(MetaTree tree, SizedBuf out) {
struct meta_callbacks cb = { .pre = serialize_cb, .data = &out };
espr_meta_walk(tree, cb);
}
void serialize_cb(MetaNode *m, void *data) {
- struct sized_buf *out = data;
+ SizedBuf *out = data;
// exit on empty node
if (!m->n.data)
@@ -707,19 +708,25 @@ void serialize_cb(MetaNode *m, void *data) {
switch (m->n.type) {
case NT_GROUP:
// only serialize the header of groups
- assert(out->size >= sizeof(Group));
- memcpy(out->data, m->n.header.group, sizeof(Group));
- sized_buf_update(out, sizeof(Group));
- break;
+ {
+ int err = sb_copyin(out, (char *)m->n.header.group, sizeof(Group));
+ assert(err == 0);
+ }
+ break;
case NT_RECORD:
size_t data_size = m->n.header.record->size;
- assert(out->size >= data_size + sizeof(Record));
+ char *header = (char *)m->n.header.record;
// serialize header and data separately as they may be
// discontiguous
- memcpy(out->data, m->n.header.record, sizeof(Record));
- sized_buf_update(out, sizeof(Record));
- memcpy(out->data, m->n.data, data_size);
- sized_buf_update(out, data_size);
+ {
+ int err = sb_copyin(out, header, sizeof(Record));
+ assert(err == 0);
+ err = sb_copyin(out, m->n.data, data_size);
+ assert(err == 0);
+ }
+ break;
+ default:
+ assert(false);
}
}
diff --git a/espReader/espReader.vcxproj b/espReader/espReader.vcxproj
index 4f5460c..ad77202 100644
--- a/espReader/espReader.vcxproj
+++ b/espReader/espReader.vcxproj
@@ -111,7 +111,7 @@
true
stdcpp17
stdc11
- ..\zlib-win-build
+ ..\zlib-win-build;..\SizedBuffer
Disabled
@@ -129,7 +129,7 @@
NDEBUG;_LIB;%(PreprocessorDefinitions)
true
stdc11
- ..\zlib-win-build
+ ..\zlib-win-build;..\SizedBuffer
@@ -148,6 +148,9 @@
+
+ {cb1c8f66-5b90-4de7-890b-f6430daaf25f}
+
{b56d17bc-072b-42f3-844a-870a07afbaaa}