* This function creates a deep copy of the whole structure. * The new structure is dynamically allocated and needs to be freed. Signed-off-by: Jakub Jelen <jjelen@xxxxxxxxxx> Reviewed-by: Robert Relyea <rrelyea@xxxxxxxxxx> --- src/simpletlv.c | 42 ++++++++++++++++++++++++++++++++++++++++++ src/simpletlv.h | 9 +++++++++ tests/simpletlv.c | 28 ++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+) diff --git a/src/simpletlv.c b/src/simpletlv.c index 5cea04b..2a9a6a7 100644 --- a/src/simpletlv.c +++ b/src/simpletlv.c @@ -278,4 +278,46 @@ simpletlv_free(struct simpletlv_member *tlv, size_t tlvlen) } free(tlv); } + +struct simpletlv_member * +simpletlv_clone(struct simpletlv_member *tlv, size_t tlvlen) +{ + size_t i = 0, j; + struct simpletlv_member *new = NULL; + + new = malloc(sizeof(struct simpletlv_member)*tlvlen); + if (!new) + goto failure; + + for (i = 0; i < tlvlen; i++) { + new[i].type = tlv[i].type; + new[i].tag = tlv[i].tag; + new[i].length = tlv[i].length; + if (tlv[i].type == SIMPLETLV_TYPE_COMPOUND) { + new[i].value.child = simpletlv_clone( + tlv[i].value.child, tlv[i].length); + if (new[i].value.child == NULL) + goto failure; + } else { + new[i].value.value = malloc( + sizeof(unsigned char)*tlv[i].length); + if (new[i].value.value == NULL) + goto failure; + memcpy(new[i].value.value, tlv[i].value.value, + tlv[i].length); + } + } + return new; + +failure: + for (j = 0; j < i; i++) { + if (tlv[i].type == SIMPLETLV_TYPE_COMPOUND) { + simpletlv_free(new[i].value.child, new[i].length); + } else { + free(new[i].value.value); + } + } + free(new); + return NULL; +} /* vim: set ts=4 sw=4 tw=0 noet expandtab: */ diff --git a/src/simpletlv.h b/src/simpletlv.h index dcb795b..e1cb5a2 100644 --- a/src/simpletlv.h +++ b/src/simpletlv.h @@ -115,4 +115,13 @@ int simpletlv_read_tag(unsigned char **buf, size_t buflen, unsigned char *tag_out, size_t *taglen); + +/* create a deep copy of the SimpleTLV structure + * + * The calling function is responsible for freeing the structure and + * all its children by calling simpletlv_free(). + */ +struct simpletlv_member * +simpletlv_clone(struct simpletlv_member *tlv, size_t tlvlen); + #endif diff --git a/tests/simpletlv.c b/tests/simpletlv.c index 3bd22ae..2be78db 100644 --- a/tests/simpletlv.c +++ b/tests/simpletlv.c @@ -220,6 +220,7 @@ static void test_encode_skipped(void) {0x30, 2, {/*.value = simple_value2*/}, SIMPLETLV_TYPE_NONE} }; unsigned char encoded[] = "\x25\x02\x12\x14"; + simple[0].value.value = simple_value; simple[1].value.value = simple_value2; @@ -242,6 +243,32 @@ static void test_encode_skipped(void) g_free(result); } +static void test_clone_simple(void) +{ + unsigned char *result = NULL; + size_t result_len = 0; + unsigned char simple_value[] = "\x14\x18"; + unsigned char simple_value2[] = "\x64\x24\x44"; + static struct simpletlv_member simple[2] = { + {0x13, 2, {/*.value = simple_value*/}, SIMPLETLV_TYPE_LEAF}, + {0xDD, 3, {/*.value = simple_value2*/}, SIMPLETLV_TYPE_LEAF} + }; + unsigned char encoded[] = "\x13\x02\x14\x18\xDD\x03\x64\x24\x44"; + struct simpletlv_member *clone; + + simple[0].value.value = simple_value; + simple[1].value.value = simple_value2; + + clone = simpletlv_clone(simple, 2); + g_assert_nonnull(clone); + + result = NULL; + result_len = simpletlv_encode(clone, 2, &result, 0, NULL); + g_assert_cmpmem(result, result_len, encoded, 9); + g_free(result); + simpletlv_free(clone, 2); +} + int main(int argc, char *argv[]) { int ret; @@ -256,6 +283,7 @@ int main(int argc, char *argv[]) g_test_add_func("/simpletlv/encode/simple", test_encode_simple); g_test_add_func("/simpletlv/encode/nested", test_encode_nested); g_test_add_func("/simpletlv/encode/skipped", test_encode_skipped); + g_test_add_func("/simpletlv/clone/simple", test_clone_simple); ret = g_test_run(); -- 2.17.1 _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/spice-devel