From b9db39926fcfc2474c696688a5dcaec4e4901cff Mon Sep 17 00:00:00 2001 From: decafcode Date: Sun, 19 Nov 2023 22:18:03 -0500 Subject: [PATCH] feat(573file): add support for prop-valued arrays --- 573file/prop-binary-reader.c | 2 +- 573file/prop-type.c | 10 ++++- 573file/prop-type.h | 1 + 573file/prop-xml-writer.c | 78 +++++++++++++++++++++++++++--------- 573file/prop.c | 50 +++++++++++++++++------ 573file/prop.h | 1 + 6 files changed, 109 insertions(+), 33 deletions(-) diff --git a/573file/prop-binary-reader.c b/573file/prop-binary-reader.c index bcfd6be..4d06125 100644 --- a/573file/prop-binary-reader.c +++ b/573file/prop-binary-reader.c @@ -391,7 +391,7 @@ static int prop_binary_slice_value(struct prop_binary_parser *bp, uint8_t type, orig_nbytes = prop_type_to_size(type); - if (orig_nbytes < 0) { + if (orig_nbytes < 0 || prop_type_is_array(type)) { is_variable = true; r = iobuf_read_be32(&bp->body, &nbytes); diff --git a/573file/prop-type.c b/573file/prop-type.c index edc3c98..ff07bdb 100644 --- a/573file/prop-type.c +++ b/573file/prop-type.c @@ -22,7 +22,13 @@ static const int prop_type_sizes[64] = { [PROP_ATTR] = -1, [PROP_BOOL] = 1, }; +bool prop_type_is_array(enum prop_type type) { + return (type & PROP_ARRAY_FLAG) != 0; +} + bool prop_type_is_valid(enum prop_type type) { + type &= ~PROP_ARRAY_FLAG; + if (type < 0 || type >= lengthof(prop_type_names)) { return false; } @@ -33,11 +39,11 @@ bool prop_type_is_valid(enum prop_type type) { const char *prop_type_to_string(enum prop_type type) { assert(prop_type_is_valid(type)); - return prop_type_names[type]; + return prop_type_names[type & ~PROP_ARRAY_FLAG]; } int prop_type_to_size(enum prop_type type) { assert(type == PROP_ATTR /* hack */ || prop_type_is_valid(type)); - return prop_type_sizes[type]; + return prop_type_sizes[type & ~PROP_ARRAY_FLAG]; } diff --git a/573file/prop-type.h b/573file/prop-type.h index 3c7ea9e..d5bac2e 100644 --- a/573file/prop-type.h +++ b/573file/prop-type.h @@ -23,6 +23,7 @@ enum prop_type { PROP_ARRAY_FLAG = 0x40 }; +bool prop_type_is_array(enum prop_type type); bool prop_type_is_valid(enum prop_type type); const char *prop_type_to_string(enum prop_type type); int prop_type_to_size(enum prop_type type); diff --git a/573file/prop-xml-writer.c b/573file/prop-xml-writer.c index 0fcf980..55d96dd 100644 --- a/573file/prop-xml-writer.c +++ b/573file/prop-xml-writer.c @@ -1,5 +1,6 @@ #include +#include "573file/prop-type.h" #include "573file/prop-xml-writer.h" #include "573file/prop.h" @@ -26,6 +27,10 @@ static void prop_xml_write_void(struct strbuf *dest, const struct prop *p, unsigned int indent); static void prop_xml_write_text(struct strbuf *dest, const struct prop *p, enum prop_xml_escape ctx); +static void prop_xml_write_text_element(struct strbuf *dest, + enum prop_type type, + struct const_iobuf *src, + enum prop_xml_escape ctx); static void prop_xml_write_text_s8(struct strbuf *dest, struct const_iobuf *src); static void prop_xml_write_text_s16(struct strbuf *dest, @@ -154,6 +159,10 @@ static void prop_xml_write_nonvoid(struct strbuf *dest, const struct prop *p, prop_xml_write_indent(dest, indent); strbuf_printf(dest, "<%s __type=\"%s\"", name, type_str); + if (prop_type_is_array(type)) { + strbuf_printf(dest, " __count=\"%lu\"", (unsigned long)prop_get_count(p)); + } + first_child = prop_get_first_child_const(p); if (first_child != NULL) { @@ -275,91 +284,124 @@ static void prop_xml_write_indent(struct strbuf *dest, unsigned int indent) { static void prop_xml_write_text(struct strbuf *dest, const struct prop *p, enum prop_xml_escape ctx) { - struct const_iobuf src; + struct const_iobuf value; + struct const_iobuf item; enum prop_type type; + uint32_t count; + uint32_t i; + int item_size; + int r; type = prop_get_type(p); - prop_borrow_value(p, &src); + prop_borrow_value(p, &value); + + if (prop_type_is_array(type)) { + item_size = prop_type_to_size(type); + count = prop_get_count(p); + + assert(item_size > 0); + + for (i = 0; i < count; i++) { + if (i > 0) { + strbuf_putc(dest, ' '); + } + + r = iobuf_slice(&item, &value, item_size); + + assert(r >= 0); + + prop_xml_write_text_element(dest, type, &item, ctx); + } + } else { + prop_xml_write_text_element(dest, type, &value, ctx); + } +} + +static void prop_xml_write_text_element(struct strbuf *dest, + enum prop_type type, + struct const_iobuf *src, + enum prop_xml_escape ctx) { + type &= ~PROP_ARRAY_FLAG; switch (type) { case PROP_S8: - prop_xml_write_text_s8(dest, &src); + prop_xml_write_text_s8(dest, src); break; case PROP_S16: - prop_xml_write_text_s16(dest, &src); + prop_xml_write_text_s16(dest, src); break; case PROP_S32: - prop_xml_write_text_s32(dest, &src); + prop_xml_write_text_s32(dest, src); break; case PROP_S64: - prop_xml_write_text_s64(dest, &src); + prop_xml_write_text_s64(dest, src); break; case PROP_U8: - prop_xml_write_text_u8(dest, &src); + prop_xml_write_text_u8(dest, src); break; case PROP_U16: - prop_xml_write_text_u16(dest, &src); + prop_xml_write_text_u16(dest, src); break; case PROP_U32: - prop_xml_write_text_u32(dest, &src); + prop_xml_write_text_u32(dest, src); break; case PROP_U64: - prop_xml_write_text_u64(dest, &src); + prop_xml_write_text_u64(dest, src); break; case PROP_BIN: - prop_xml_write_text_bin(dest, &src); + prop_xml_write_text_bin(dest, src); break; case PROP_STR: - prop_xml_write_text_str(dest, &src, ctx); + prop_xml_write_text_str(dest, src, ctx); break; case PROP_IP4: - prop_xml_write_text_ip4(dest, &src); + prop_xml_write_text_ip4(dest, src); break; case PROP_TIME: /* Reuse the u32 writer for timestamps */ - prop_xml_write_text_u32(dest, &src); + prop_xml_write_text_u32(dest, src); break; case PROP_2U16: - prop_xml_write_text_u16_tuple(dest, &src, 2); + prop_xml_write_text_u16_tuple(dest, src, 2); break; case PROP_3S32: - prop_xml_write_text_s32_tuple(dest, &src, 3); + prop_xml_write_text_s32_tuple(dest, src, 3); break; case PROP_4U16: - prop_xml_write_text_u16_tuple(dest, &src, 4); + prop_xml_write_text_u16_tuple(dest, src, 4); break; case PROP_BOOL: - prop_xml_write_text_bool(dest, &src); + prop_xml_write_text_bool(dest, src); break; diff --git a/573file/prop.c b/573file/prop.c index f0da770..0339192 100644 --- a/573file/prop.c +++ b/573file/prop.c @@ -37,13 +37,8 @@ static int prop_validate(const char *name, enum prop_type type, static int prop_validate(const char *name, enum prop_type type, const void *bytes, uint32_t nbytes) { const char *chars; - int expected_nbytes; - - if (type & PROP_ARRAY_FLAG) { - log_write("\"%s\": Arrays are not currently supported", name); - - return -ENOTSUP; - } + const char *type_str; + int item_size; if (!prop_type_is_valid(type)) { log_write("\"%s\": Unsupported type code %#x", name, type); @@ -51,13 +46,30 @@ static int prop_validate(const char *name, enum prop_type type, return -ENOTSUP; } - expected_nbytes = prop_type_to_size(type); + item_size = prop_type_to_size(type); + type_str = prop_type_to_string(type); - if (expected_nbytes >= 0 && nbytes != expected_nbytes) { - log_write("\"%s\": Incorrect size %#x for type %s (expected %#x)", name, - nbytes, prop_type_to_string(type), expected_nbytes); + if (prop_type_is_array(type)) { + if (item_size <= 0) { + log_write("\"%s\": Nonsensical array type %#x", name, type); - return -EINVAL; + return -EINVAL; + } + + if (nbytes % item_size != 0) { + log_write( + "\"%s\": %s item size %i does not divide value length %#x evenly", + name, type_str, item_size, nbytes); + + return -EINVAL; + } + } else { + if (item_size >= 0 && nbytes != item_size) { + log_write("\"%s\": Incorrect size %#x for type %s (expected %#x)", name, + nbytes, type_str, item_size); + + return -EINVAL; + } } if (type == PROP_STR) { @@ -194,6 +206,20 @@ const char *prop_get_attr(const struct prop *p, const char *key) { return NULL; } +uint32_t prop_get_count(const struct prop *p) { + int item_size; + + assert(p != NULL); + assert(prop_type_is_array(p->type)); + + item_size = prop_type_to_size(p->type); + + assert(item_size > 0); + assert(p->nbytes % item_size == 0); + + return p->nbytes / item_size; +} + const struct attr *prop_get_first_attr(const struct prop *p) { struct list_node *attr; diff --git a/573file/prop.h b/573file/prop.h index 1fd9d3c..b09eb51 100644 --- a/573file/prop.h +++ b/573file/prop.h @@ -15,6 +15,7 @@ void prop_free(struct prop *p); void prop_append(struct prop *p, struct prop *child); void prop_borrow_value(const struct prop *p, struct const_iobuf *out); const char *prop_get_attr(const struct prop *p, const char *key); +uint32_t prop_get_count(const struct prop *p); const struct attr *prop_get_first_attr(const struct prop *p); struct prop *prop_get_first_child(struct prop *p); const struct prop *prop_get_first_child_const(const struct prop *p);