From 70f4a422e01910cdb783aac81f13c11223c3acbd Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 22 Dec 2021 03:17:26 +0100 Subject: Add a return value to plist_to_* and plist_from_* functions This way it can be easier determined why an import/export operation failed instead of just having a NULL result. --- include/plist/plist.h | 24 +++++++++++++++----- src/bplist.c | 60 +++++++++++++++++++++++++++++++++++++------------- src/plist.c | 18 +++++++++------ src/xplist.c | 61 +++++++++++++++++++++++++++++++++++++-------------- 4 files changed, 120 insertions(+), 43 deletions(-) diff --git a/include/plist/plist.h b/include/plist/plist.h index 0f69d40..21fd8bd 100644 --- a/include/plist/plist.h +++ b/include/plist/plist.h @@ -117,6 +117,15 @@ extern "C" PLIST_NONE /**< No type */ } plist_type; + typedef enum + { + PLIST_ERR_SUCCESS = 0, /**< operation successful */ + PLIST_ERR_INVALID_ARG = -1, /**< one or more of the parameters are invalid */ + PLIST_ERR_FORMAT = -2, /**< the plist contains nodes not compatible with the output format */ + PLIST_ERR_PARSE = -3, /**< parsing of the input format failed */ + PLIST_ERR_NO_MEM = -4, /**< not enough memory to handle the operation */ + PLIST_ERR_UNKNOWN = -255 /**< an unspecified error occurred */ + } plist_err_t; /******************************************** * * @@ -655,9 +664,10 @@ extern "C" * @param plist_xml a pointer to a C-string. This function allocates the memory, * caller is responsible for freeing it. Data is UTF-8 encoded. * @param length a pointer to an uint32_t variable. Represents the length of the allocated buffer. + * @return PLIST_ERR_SUCCESS on success or a #plist_error on failure * @note Use plist_mem_free() to free the allocated memory. */ - void plist_to_xml(plist_t plist, char **plist_xml, uint32_t * length); + plist_err_t plist_to_xml(plist_t plist, char **plist_xml, uint32_t * length); /** * Export the #plist_t structure to binary format. @@ -666,9 +676,10 @@ extern "C" * @param plist_bin a pointer to a char* buffer. This function allocates the memory, * caller is responsible for freeing it. * @param length a pointer to an uint32_t variable. Represents the length of the allocated buffer. + * @return PLIST_ERR_SUCCESS on success or a #plist_error on failure * @note Use plist_mem_free() to free the allocated memory. */ - void plist_to_bin(plist_t plist, char **plist_bin, uint32_t * length); + plist_err_t plist_to_bin(plist_t plist, char **plist_bin, uint32_t * length); /** * Import the #plist_t structure from XML format. @@ -676,8 +687,9 @@ extern "C" * @param plist_xml a pointer to the xml buffer. * @param length length of the buffer to read. * @param plist a pointer to the imported plist. + * @return PLIST_ERR_SUCCESS on success or a #plist_error on failure */ - void plist_from_xml(const char *plist_xml, uint32_t length, plist_t * plist); + plist_err_t plist_from_xml(const char *plist_xml, uint32_t length, plist_t * plist); /** * Import the #plist_t structure from binary format. @@ -685,8 +697,9 @@ extern "C" * @param plist_bin a pointer to the xml buffer. * @param length length of the buffer to read. * @param plist a pointer to the imported plist. + * @return PLIST_ERR_SUCCESS on success or a #plist_error on failure */ - void plist_from_bin(const char *plist_bin, uint32_t length, plist_t * plist); + plist_err_t plist_from_bin(const char *plist_bin, uint32_t length, plist_t * plist); /** * Import the #plist_t structure from memory data. @@ -696,8 +709,9 @@ extern "C" * @param plist_data a pointer to the memory buffer containing plist data. * @param length length of the buffer to read. * @param plist a pointer to the imported plist. + * @return PLIST_ERR_SUCCESS on success or a #plist_error on failure */ - void plist_from_memory(const char *plist_data, uint32_t length, plist_t * plist); + plist_err_t plist_from_memory(const char *plist_data, uint32_t length, plist_t * plist); /** * Test if in-memory plist data is binary or XML diff --git a/src/bplist.c b/src/bplist.c index a6e6ded..57ec151 100644 --- a/src/bplist.c +++ b/src/bplist.c @@ -774,7 +774,7 @@ static plist_t parse_bin_node_at_index(struct bplist_data *bplist, uint32_t node return plist; } -PLIST_API void plist_from_bin(const char *plist_bin, uint32_t length, plist_t * plist) +PLIST_API plist_err_t plist_from_bin(const char *plist_bin, uint32_t length, plist_t * plist) { bplist_trailer_t *trailer = NULL; uint8_t offset_size = 0; @@ -786,20 +786,28 @@ PLIST_API void plist_from_bin(const char *plist_bin, uint32_t length, plist_t * const char *start_data = NULL; const char *end_data = NULL; + if (!plist) { + return PLIST_ERR_INVALID_ARG; + } + *plist = NULL; + if (!plist_bin || length == 0) { + return PLIST_ERR_INVALID_ARG; + } + //first check we have enough data if (!(length >= BPLIST_MAGIC_SIZE + BPLIST_VERSION_SIZE + sizeof(bplist_trailer_t))) { PLIST_BIN_ERR("plist data is to small to hold a binary plist\n"); - return; + return PLIST_ERR_PARSE; } //check that plist_bin in actually a plist if (memcmp(plist_bin, BPLIST_MAGIC, BPLIST_MAGIC_SIZE) != 0) { PLIST_BIN_ERR("bplist magic mismatch\n"); - return; + return PLIST_ERR_PARSE; } //check for known version if (memcmp(plist_bin + BPLIST_MAGIC_SIZE, BPLIST_VERSION, BPLIST_VERSION_SIZE) != 0) { PLIST_BIN_ERR("unsupported binary plist version '%.2s\n", plist_bin+BPLIST_MAGIC_SIZE); - return; + return PLIST_ERR_PARSE; } start_data = plist_bin + BPLIST_MAGIC_SIZE + BPLIST_VERSION_SIZE; @@ -816,37 +824,37 @@ PLIST_API void plist_from_bin(const char *plist_bin, uint32_t length, plist_t * if (num_objects == 0) { PLIST_BIN_ERR("number of objects must be larger than 0\n"); - return; + return PLIST_ERR_PARSE; } if (offset_size == 0) { PLIST_BIN_ERR("offset size in trailer must be larger than 0\n"); - return; + return PLIST_ERR_PARSE; } if (ref_size == 0) { PLIST_BIN_ERR("object reference size in trailer must be larger than 0\n"); - return; + return PLIST_ERR_PARSE; } if (root_object >= num_objects) { PLIST_BIN_ERR("root object index (%" PRIu64 ") must be smaller than number of objects (%" PRIu64 ")\n", root_object, num_objects); - return; + return PLIST_ERR_PARSE; } if (offset_table < start_data || offset_table >= end_data) { PLIST_BIN_ERR("offset table offset points outside of valid range\n"); - return; + return PLIST_ERR_PARSE; } if (uint64_mul_overflow(num_objects, offset_size, &offset_table_size)) { PLIST_BIN_ERR("integer overflow when calculating offset table size\n"); - return; + return PLIST_ERR_PARSE; } if (offset_table_size > (uint64_t)(end_data - offset_table)) { PLIST_BIN_ERR("offset table points outside of valid range\n"); - return; + return PLIST_ERR_PARSE; } struct bplist_data bplist; @@ -861,12 +869,18 @@ PLIST_API void plist_from_bin(const char *plist_bin, uint32_t length, plist_t * if (!bplist.used_indexes) { PLIST_BIN_ERR("failed to create array to hold used node indexes. Out of memory?\n"); - return; + return PLIST_ERR_NO_MEM; } *plist = parse_bin_node_at_index(&bplist, root_object); ptr_array_free(bplist.used_indexes); + + if (!*plist) { + return PLIST_ERR_PARSE; + } + + return PLIST_ERR_SUCCESS; } static unsigned int plist_data_hash(const void* key) @@ -1163,7 +1177,7 @@ static int is_ascii_string(char* s, int len) return ret; } -PLIST_API void plist_to_bin(plist_t plist, char **plist_bin, uint32_t * length) +PLIST_API plist_err_t plist_to_bin(plist_t plist, char **plist_bin, uint32_t * length) { ptrarray_t* objects = NULL; hashtable_t* ref_table = NULL; @@ -1181,13 +1195,21 @@ PLIST_API void plist_to_bin(plist_t plist, char **plist_bin, uint32_t * length) uint64_t objects_len = 0; //check for valid input - if (!plist || !plist_bin || *plist_bin || !length) - return; + if (!plist || !plist_bin || !length) { + return PLIST_ERR_INVALID_ARG; + } //list of objects objects = ptr_array_new(4096); + if (!objects) { + return PLIST_ERR_NO_MEM; + } //hashtable to write only once same nodes ref_table = hash_table_new(plist_data_hash, plist_data_compare, free); + if (!ref_table) { + ptr_array_free(objects); + return PLIST_ERR_NO_MEM; + } //serialize plist ser_s.objects = objects; @@ -1212,6 +1234,7 @@ PLIST_API void plist_to_bin(plist_t plist, char **plist_bin, uint32_t * length) uint8_t bsize; switch (data->type) { + case PLIST_NULL: case PLIST_BOOLEAN: req += 1; break; @@ -1286,6 +1309,11 @@ PLIST_API void plist_to_bin(plist_t plist, char **plist_bin, uint32_t * length) //setup a dynamic bytes array to store bplist in bplist_buff = byte_array_new(req); + if (!bplist_buff) { + ptr_array_free(objects); + hash_table_destroy(ref_table); + return PLIST_ERR_NO_MEM; + } //set magic number and version byte_array_append(bplist_buff, BPLIST_MAGIC, BPLIST_MAGIC_SIZE); @@ -1385,4 +1413,6 @@ PLIST_API void plist_to_bin(plist_t plist, char **plist_bin, uint32_t * length) bplist_buff->data = NULL; // make sure we don't free the output buffer byte_array_free(bplist_buff); + + return PLIST_ERR_SUCCESS; } diff --git a/src/plist.c b/src/plist.c index 5453176..61b2913 100644 --- a/src/plist.c +++ b/src/plist.c @@ -183,18 +183,22 @@ PLIST_API int plist_is_binary(const char *plist_data, uint32_t length) } -PLIST_API void plist_from_memory(const char *plist_data, uint32_t length, plist_t * plist) +PLIST_API plist_err_t plist_from_memory(const char *plist_data, uint32_t length, plist_t * plist) { - if (length < 8) { - *plist = NULL; - return; + int res = -1; + if (!plist) { + return PLIST_ERR_INVALID_ARG; + } + *plist = NULL; + if (!plist_data || length < 8) { + return PLIST_ERR_INVALID_ARG; } - if (plist_is_binary(plist_data, length)) { - plist_from_bin(plist_data, length, plist); + res = plist_from_bin(plist_data, length, plist); } else { - plist_from_xml(plist_data, length, plist); + res = plist_from_xml(plist_data, length, plist); } + return res; } plist_t plist_new_node(plist_data_t data) diff --git a/src/xplist.c b/src/xplist.c index 94006f1..3971622 100644 --- a/src/xplist.c +++ b/src/xplist.c @@ -143,7 +143,7 @@ static int node_to_xml(node_t* node, bytearray_t **outbuf, uint32_t depth) if (!node) { PLIST_XML_WRITE_ERR("Encountered invalid empty node in property list\n"); - return -1; + return PLIST_ERR_INVALID_ARG; } node_data = plist_get_data(node); @@ -238,9 +238,9 @@ static int node_to_xml(node_t* node, bytearray_t **outbuf, uint32_t depth) break; case PLIST_NULL: PLIST_XML_WRITE_ERR("PLIST_NULL type is not valid for XML format\n"); - return -1; + return PLIST_ERR_FORMAT; default: - break; + return PLIST_ERR_UNKNOWN; } for (i = 0; i < depth; i++) { @@ -377,7 +377,7 @@ static int node_to_xml(node_t* node, bytearray_t **outbuf, uint32_t depth) str_buf_append(*outbuf, ">", 1); } str_buf_append(*outbuf, "\n", 1); - return 0; + return PLIST_ERR_SUCCESS; } static void parse_date(const char *strval, struct TM *btime) @@ -438,11 +438,11 @@ static int num_digits_u(uint64_t i) return n; } -static void node_estimate_size(node_t *node, uint64_t *size, uint32_t depth) +static int node_estimate_size(node_t *node, uint64_t *size, uint32_t depth) { plist_data_t data; if (!node) { - return; + return PLIST_ERR_INVALID_ARG; } data = plist_get_data(node); if (node->children) { @@ -511,28 +511,47 @@ static void node_estimate_size(node_t *node, uint64_t *size, uint32_t depth) *size += 18; /* CF$UID */ *size += (XPLIST_INT_LEN << 1) + 6; break; + case PLIST_NULL: + PLIST_XML_WRITE_ERR("PLIST_NULL type is not valid for XML format\n"); + return PLIST_ERR_FORMAT; default: - break; + PLIST_XML_WRITE_ERR("invalid node type encountered\n"); + return PLIST_ERR_UNKNOWN; } *size += indent; } + return PLIST_ERR_SUCCESS; } -PLIST_API void plist_to_xml(plist_t plist, char **plist_xml, uint32_t * length) +PLIST_API plist_err_t plist_to_xml(plist_t plist, char **plist_xml, uint32_t * length) { uint64_t size = 0; - node_estimate_size(plist, &size, 0); + int res; + + if (!plist || !plist_xml || !length) { + return PLIST_ERR_INVALID_ARG; + } + + res = node_estimate_size(plist, &size, 0); + if (res < 0) { + return res; + } size += sizeof(XML_PLIST_PROLOG) + sizeof(XML_PLIST_EPILOG) - 1; strbuf_t *outbuf = str_buf_new(size); + if (!outbuf) { + PLIST_XML_WRITE_ERR("Could not allocate output buffer"); + return PLIST_ERR_NO_MEM; + } str_buf_append(outbuf, XML_PLIST_PROLOG, sizeof(XML_PLIST_PROLOG)-1); - if (node_to_xml(plist, &outbuf, 0) < 0) { + res = node_to_xml(plist, &outbuf, 0); + if (res < 0) { str_buf_free(outbuf); *plist_xml = NULL; *length = 0; - return; + return res; } str_buf_append(outbuf, XML_PLIST_EPILOG, sizeof(XML_PLIST_EPILOG)); @@ -542,6 +561,8 @@ PLIST_API void plist_to_xml(plist_t plist, char **plist_xml, uint32_t * length) outbuf->data = NULL; str_buf_free(outbuf); + + return PLIST_ERR_SUCCESS; } struct _parse_ctx { @@ -932,8 +953,9 @@ static char* text_parts_get_content(text_part_t *tp, int unesc_entities, size_t return str; } -static void node_from_xml(parse_ctx ctx, plist_t *plist) +static int node_from_xml(parse_ctx ctx, plist_t *plist) { + int res; char *tag = NULL; char *keyname = NULL; plist_t subnode = NULL; @@ -1427,17 +1449,24 @@ err_out: if (ctx->err) { plist_free(*plist); *plist = NULL; + res = PLIST_ERR_PARSE; + } else { + res = PLIST_ERR_SUCCESS; } + return res; } -PLIST_API void plist_from_xml(const char *plist_xml, uint32_t length, plist_t * plist) +PLIST_API plist_err_t plist_from_xml(const char *plist_xml, uint32_t length, plist_t * plist) { + if (!plist) { + return PLIST_ERR_INVALID_ARG; + } + *plist = NULL; if (!plist_xml || (length == 0)) { - *plist = NULL; - return; + return PLIST_ERR_INVALID_ARG; } struct _parse_ctx ctx = { plist_xml, plist_xml + length, 0 }; - node_from_xml(&ctx, plist); + return node_from_xml(&ctx, plist); } -- cgit v1.1-32-gdbae