diff options
Diffstat (limited to 'src/xplist.c')
-rw-r--r-- | src/xplist.c | 190 |
1 files changed, 120 insertions, 70 deletions
diff --git a/src/xplist.c b/src/xplist.c index a7d52e5..66e1dba 100644 --- a/src/xplist.c +++ b/src/xplist.c @@ -41,7 +41,6 @@ #include <limits.h> #include <node.h> -#include <node_list.h> #include "plist.h" #include "base64.h" @@ -71,7 +70,7 @@ #define MAC_EPOCH 978307200 -#define MAX_DATA_BYTES_PER_LINE(__i) (((76 - (__i << 3)) >> 2) * 3) +#define MAX_DATA_BYTES_PER_LINE(__i) (((76 - ((__i) << 3)) >> 2) * 3) static const char XML_PLIST_PROLOG[] = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\ <!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n\ @@ -81,8 +80,10 @@ static const char XML_PLIST_EPILOG[] = "</plist>\n"; #ifdef DEBUG static int plist_xml_debug = 0; #define PLIST_XML_ERR(...) if (plist_xml_debug) { fprintf(stderr, "libplist[xmlparser] ERROR: " __VA_ARGS__); } +#define PLIST_XML_WRITE_ERR(...) if (plist_xml_debug) { fprintf(stderr, "libplist[xmlwriter] ERROR: " __VA_ARGS__); } #else #define PLIST_XML_ERR(...) +#define PLIST_XML_WRITE_ERR(...) #endif void plist_xml_init(void) @@ -101,6 +102,13 @@ void plist_xml_deinit(void) /* deinit XML stuff */ } +void plist_xml_set_debug(int debug) +{ +#if DEBUG + plist_xml_debug = debug; +#endif +} + static size_t dtostr(char *buf, size_t bufsize, double realval) { size_t len = 0; @@ -113,7 +121,7 @@ static size_t dtostr(char *buf, size_t bufsize, double realval) } else { size_t i = 0; len = snprintf(buf, bufsize, "%.*g", 17, realval); - for (i = 0; i < len; i++) { + for (i = 0; buf && i < len; i++) { if (buf[i] == ',') { buf[i] = '.'; break; @@ -125,7 +133,7 @@ static size_t dtostr(char *buf, size_t bufsize, double realval) return len; } -static void node_to_xml(node_t* node, bytearray_t **outbuf, uint32_t depth) +static plist_err_t node_to_xml(node_t node, bytearray_t **outbuf, uint32_t depth) { plist_data_t node_data = NULL; @@ -139,8 +147,10 @@ static void node_to_xml(node_t* node, bytearray_t **outbuf, uint32_t depth) uint32_t i = 0; - if (!node) - return; + if (!node) { + PLIST_XML_WRITE_ERR("Encountered invalid empty node in property list\n"); + return PLIST_ERR_INVALID_ARG; + } node_data = plist_get_data(node); @@ -158,14 +168,14 @@ static void node_to_xml(node_t* node, bytearray_t **outbuf, uint32_t depth) } break; - case PLIST_UINT: + case PLIST_INT: tag = XPLIST_INT; tag_len = XPLIST_INT_LEN; val = (char*)malloc(64); if (node_data->length == 16) { - val_len = snprintf(val, 64, "%"PRIu64, node_data->intval); + val_len = snprintf(val, 64, "%" PRIu64, node_data->intval); } else { - val_len = snprintf(val, 64, "%"PRIi64, node_data->intval); + val_len = snprintf(val, 64, "%" PRIi64, node_data->intval); } break; @@ -211,8 +221,7 @@ static void node_to_xml(node_t* node, bytearray_t **outbuf, uint32_t depth) struct TM _btime; struct TM *btime = gmtime64_r(&timev, &_btime); if (btime) { - val = (char*)malloc(24); - memset(val, 0, 24); + val = (char*)calloc(1, 24); struct tm _tmcopy; copy_TM64_to_tm(btime, &_tmcopy); val_len = strftime(val, 24, "%Y-%m-%dT%H:%M:%SZ", &_tmcopy); @@ -228,13 +237,16 @@ static void node_to_xml(node_t* node, bytearray_t **outbuf, uint32_t depth) tag_len = XPLIST_DICT_LEN; val = (char*)malloc(64); if (node_data->length == 16) { - val_len = snprintf(val, 64, "%"PRIu64, node_data->intval); + val_len = snprintf(val, 64, "%" PRIu64, node_data->intval); } else { - val_len = snprintf(val, 64, "%"PRIi64, node_data->intval); + val_len = snprintf(val, 64, "%" PRIi64, node_data->intval); } break; + case PLIST_NULL: + PLIST_XML_WRITE_ERR("PLIST_NULL type is not valid for XML format\n"); + return PLIST_ERR_FORMAT; default: - break; + return PLIST_ERR_UNKNOWN; } for (i = 0; i < depth; i++) { @@ -352,9 +364,10 @@ static void node_to_xml(node_t* node, bytearray_t **outbuf, uint32_t depth) if (node_data->type == PLIST_DICT && node->children) { assert((node->children->count % 2) == 0); } - node_t *ch; + node_t ch; for (ch = node_first_child(node); ch; ch = node_next_sibling(ch)) { - node_to_xml(ch, outbuf, depth+1); + plist_err_t res = node_to_xml(ch, outbuf, depth+1); + if (res < 0) return res; } /* fix indent for structured types */ @@ -370,8 +383,7 @@ static void node_to_xml(node_t* node, bytearray_t **outbuf, uint32_t depth) str_buf_append(*outbuf, ">", 1); } str_buf_append(*outbuf, "\n", 1); - - return; + return PLIST_ERR_SUCCESS; } static void parse_date(const char *strval, struct TM *btime) @@ -403,7 +415,7 @@ static int num_digits_i(int64_t i) int64_t po10; n=1; if (i < 0) { - i = -i; + i = (i == INT64_MIN) ? INT64_MAX : -i; n++; } po10=10; @@ -432,15 +444,15 @@ 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 plist_err_t 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) { - node_t *ch; + node_t ch; for (ch = node_first_child(node); ch; ch = node_next_sibling(ch)) { node_estimate_size(ch, size, depth + 1); } @@ -473,7 +485,7 @@ static void node_estimate_size(node_t *node, uint64_t *size, uint32_t depth) *size += data->length; *size += (XPLIST_KEY_LEN << 1) + 6; break; - case PLIST_UINT: + case PLIST_INT: if (data->length == 16) { *size += num_digits_u(data->intval); } else { @@ -482,7 +494,7 @@ static void node_estimate_size(node_t *node, uint64_t *size, uint32_t depth) *size += (XPLIST_INT_LEN << 1) + 6; break; case PLIST_REAL: - *size += num_digits_i((int64_t)data->realval) + 7; + *size += dtostr(NULL, 0, data->realval); *size += (XPLIST_REAL_LEN << 1) + 6; break; case PLIST_DATE: @@ -505,37 +517,58 @@ static void node_estimate_size(node_t *node, uint64_t *size, uint32_t depth) *size += 18; /* <key>CF$UID</key> */ *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_err_t plist_to_xml(plist_t plist, char **plist_xml, uint32_t * length) { uint64_t size = 0; - node_estimate_size(plist, &size, 0); + plist_err_t res; + + if (!plist || !plist_xml || !length) { + return PLIST_ERR_INVALID_ARG; + } + + res = node_estimate_size((node_t)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\n"); + return PLIST_ERR_NO_MEM; + } str_buf_append(outbuf, XML_PLIST_PROLOG, sizeof(XML_PLIST_PROLOG)-1); - node_to_xml(plist, &outbuf, 0); + res = node_to_xml((node_t)plist, &outbuf, 0); + if (res < 0) { + str_buf_free(outbuf); + *plist_xml = NULL; + *length = 0; + return res; + } str_buf_append(outbuf, XML_PLIST_EPILOG, sizeof(XML_PLIST_EPILOG)); - *plist_xml = outbuf->data; + *plist_xml = (char*)outbuf->data; *length = outbuf->len - 1; outbuf->data = NULL; str_buf_free(outbuf); -} -PLIST_API void plist_to_xml_free(char *plist_xml) -{ - free(plist_xml); + return PLIST_ERR_SUCCESS; } struct _parse_ctx { @@ -638,14 +671,14 @@ static void text_parts_free(text_part_t *tp) { while (tp) { text_part_t *tmp = tp; - tp = tp->next; + tp = (text_part_t*)tp->next; free(tmp); } } static text_part_t* text_part_append(text_part_t* parts, const char *begin, size_t length, int is_cdata) { - text_part_t* newpart = malloc(sizeof(text_part_t)); + text_part_t* newpart = (text_part_t*)malloc(sizeof(text_part_t)); assert(newpart); parts->next = text_part_init(newpart, begin, length, is_cdata); return newpart; @@ -751,7 +784,7 @@ static text_part_t* get_text_parts(parse_ctx ctx, const char* tag, size_t tag_le } } while (1); ctx->pos++; - if (ctx->pos >= ctx->end-tag_len || strncmp(ctx->pos, tag, tag_len)) { + if (ctx->pos >= ctx->end-tag_len || strncmp(ctx->pos, tag, tag_len) != 0) { PLIST_XML_ERR("EOF or end tag mismatch\n"); ctx->err++; return NULL; @@ -897,9 +930,9 @@ static char* text_parts_get_content(text_part_t *tp, int unesc_entities, size_t text_part_t *tmp = tp; while (tp && tp->begin) { total_length += tp->length; - tp = tp->next; + tp = (text_part_t*)tp->next; } - str = malloc(total_length + 1); + str = (char*)malloc(total_length + 1); assert(str); p = str; tp = tmp; @@ -914,7 +947,7 @@ static char* text_parts_get_content(text_part_t *tp, int unesc_entities, size_t } } p += len; - tp = tp->next; + tp = (text_part_t*)tp->next; } *p = '\0'; if (length) { @@ -926,7 +959,7 @@ 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 plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist) { char *tag = NULL; char *keyname = NULL; @@ -967,7 +1000,7 @@ static void node_from_xml(parse_ctx ctx, plist_t *plist) ctx->err++; goto err_out; } - if (strncmp(ctx->pos, "?>", 2)) { + if (strncmp(ctx->pos, "?>", 2) != 0) { PLIST_XML_ERR("Couldn't find <? tag closing marker\n"); ctx->err++; goto err_out; @@ -979,7 +1012,7 @@ static void node_from_xml(parse_ctx ctx, plist_t *plist) if (((ctx->end - ctx->pos) > 3) && !strncmp(ctx->pos, "!--", 3)) { ctx->pos += 3; find_str(ctx,"-->", 3, 0); - if (ctx->pos > ctx->end-3 || strncmp(ctx->pos, "-->", 3)) { + if (ctx->pos > ctx->end-3 || strncmp(ctx->pos, "-->", 3) != 0) { PLIST_XML_ERR("Couldn't find end of comment\n"); ctx->err++; goto err_out; @@ -1008,7 +1041,7 @@ static void node_from_xml(parse_ctx ctx, plist_t *plist) } if (embedded_dtd) { find_str(ctx, "]>", 2, 1); - if (ctx->pos > ctx->end-2 || strncmp(ctx->pos, "]>", 2)) { + if (ctx->pos > ctx->end-2 || strncmp(ctx->pos, "]>", 2) != 0) { PLIST_XML_ERR("Couldn't find end of DOCTYPE\n"); ctx->err++; goto err_out; @@ -1034,7 +1067,7 @@ static void node_from_xml(parse_ctx ctx, plist_t *plist) goto err_out; } int taglen = ctx->pos - p; - tag = malloc(taglen + 1); + tag = (char*)malloc(taglen + 1); strncpy(tag, p, taglen); tag[taglen] = '\0'; if (*ctx->pos != '>') { @@ -1072,7 +1105,7 @@ static void node_from_xml(parse_ctx ctx, plist_t *plist) goto err_out; } - struct node_path_item *path_item = malloc(sizeof(struct node_path_item)); + struct node_path_item *path_item = (struct node_path_item*)malloc(sizeof(struct node_path_item)); if (!path_item) { PLIST_XML_ERR("out of memory when allocating node path item\n"); ctx->err++; @@ -1100,7 +1133,7 @@ static void node_from_xml(parse_ctx ctx, plist_t *plist) goto err_out; } struct node_path_item *path_item = node_path; - node_path = node_path->prev; + node_path = (struct node_path_item*)node_path->prev; free(path_item); free(tag); @@ -1123,7 +1156,7 @@ static void node_from_xml(parse_ctx ctx, plist_t *plist) text_part_t *tp = get_text_parts(ctx, tag, taglen, 1, &first_part); if (!tp) { PLIST_XML_ERR("Could not parse text content for '%s' node\n", tag); - text_parts_free(first_part.next); + text_parts_free((text_part_t*)first_part.next); ctx->err++; goto err_out; } @@ -1132,7 +1165,7 @@ static void node_from_xml(parse_ctx ctx, plist_t *plist) char *str_content = text_parts_get_content(tp, 0, NULL, &requires_free); if (!str_content) { PLIST_XML_ERR("Could not get text content for '%s' node\n", tag); - text_parts_free(first_part.next); + text_parts_free((text_part_t*)first_part.next); ctx->err++; goto err_out; } @@ -1144,7 +1177,7 @@ static void node_from_xml(parse_ctx ctx, plist_t *plist) } str++; } - data->intval = strtoull((char*)str, NULL, 0); + data->intval = strtoull(str, NULL, 0); if (is_negative || (data->intval <= INT64_MAX)) { uint64_t v = data->intval; if (is_negative) { @@ -1161,20 +1194,20 @@ static void node_from_xml(parse_ctx ctx, plist_t *plist) } else { is_empty = 1; } - text_parts_free(tp->next); + text_parts_free((text_part_t*)tp->next); } if (is_empty) { data->intval = 0; data->length = 8; } - data->type = PLIST_UINT; + data->type = PLIST_INT; } else if (!strcmp(tag, XPLIST_REAL)) { if (!is_empty) { text_part_t first_part = { NULL, 0, 0, NULL }; text_part_t *tp = get_text_parts(ctx, tag, taglen, 1, &first_part); if (!tp) { PLIST_XML_ERR("Could not parse text content for '%s' node\n", tag); - text_parts_free(first_part.next); + text_parts_free((text_part_t*)first_part.next); ctx->err++; goto err_out; } @@ -1183,7 +1216,7 @@ static void node_from_xml(parse_ctx ctx, plist_t *plist) char *str_content = text_parts_get_content(tp, 0, NULL, &requires_free); if (!str_content) { PLIST_XML_ERR("Could not get text content for '%s' node\n", tag); - text_parts_free(first_part.next); + text_parts_free((text_part_t*)first_part.next); ctx->err++; goto err_out; } @@ -1192,7 +1225,7 @@ static void node_from_xml(parse_ctx ctx, plist_t *plist) free(str_content); } } - text_parts_free(tp->next); + text_parts_free((text_part_t*)tp->next); } data->type = PLIST_REAL; data->length = 8; @@ -1218,12 +1251,12 @@ static void node_from_xml(parse_ctx ctx, plist_t *plist) size_t length = 0; if (!tp) { PLIST_XML_ERR("Could not parse text content for '%s' node\n", tag); - text_parts_free(first_part.next); + text_parts_free((text_part_t*)first_part.next); ctx->err++; goto err_out; } str = text_parts_get_content(tp, 1, &length, NULL); - text_parts_free(first_part.next); + text_parts_free((text_part_t*)first_part.next); if (!str) { PLIST_XML_ERR("Could not get text content for '%s' node\n", tag); ctx->err++; @@ -1251,7 +1284,7 @@ static void node_from_xml(parse_ctx ctx, plist_t *plist) text_part_t *tp = get_text_parts(ctx, tag, taglen, 1, &first_part); if (!tp) { PLIST_XML_ERR("Could not parse text content for '%s' node\n", tag); - text_parts_free(first_part.next); + text_parts_free((text_part_t*)first_part.next); ctx->err++; goto err_out; } @@ -1260,7 +1293,7 @@ static void node_from_xml(parse_ctx ctx, plist_t *plist) char *str_content = text_parts_get_content(tp, 0, NULL, &requires_free); if (!str_content) { PLIST_XML_ERR("Could not get text content for '%s' node\n", tag); - text_parts_free(first_part.next); + text_parts_free((text_part_t*)first_part.next); ctx->err++; goto err_out; } @@ -1274,7 +1307,7 @@ static void node_from_xml(parse_ctx ctx, plist_t *plist) free(str_content); } } - text_parts_free(tp->next); + text_parts_free((text_part_t*)tp->next); } data->type = PLIST_DATA; } else if (!strcmp(tag, XPLIST_DATE)) { @@ -1283,7 +1316,7 @@ static void node_from_xml(parse_ctx ctx, plist_t *plist) text_part_t *tp = get_text_parts(ctx, tag, taglen, 1, &first_part); if (!tp) { PLIST_XML_ERR("Could not parse text content for '%s' node\n", tag); - text_parts_free(first_part.next); + text_parts_free((text_part_t*)first_part.next); ctx->err++; goto err_out; } @@ -1294,7 +1327,7 @@ static void node_from_xml(parse_ctx ctx, plist_t *plist) char *str_content = text_parts_get_content(tp, 0, &length, &requires_free); if (!str_content) { PLIST_XML_ERR("Could not get text content for '%s' node\n", tag); - text_parts_free(first_part.next); + text_parts_free((text_part_t*)first_part.next); ctx->err++; goto err_out; } @@ -1314,7 +1347,7 @@ static void node_from_xml(parse_ctx ctx, plist_t *plist) free(str_content); } } - text_parts_free(tp->next); + text_parts_free((text_part_t*)tp->next); data->realval = (double)(timev - MAC_EPOCH); } data->length = sizeof(double); @@ -1358,7 +1391,7 @@ static void node_from_xml(parse_ctx ctx, plist_t *plist) } } if (!is_empty && (data->type == PLIST_DICT || data->type == PLIST_ARRAY)) { - struct node_path_item *path_item = malloc(sizeof(struct node_path_item)); + struct node_path_item *path_item = (struct node_path_item*)malloc(sizeof(struct node_path_item)); if (!path_item) { PLIST_XML_ERR("out of memory when allocating node path item\n"); ctx->err++; @@ -1383,10 +1416,10 @@ static void node_from_xml(parse_ctx ctx, plist_t *plist) goto err_out; } struct node_path_item *path_item = node_path; - node_path = node_path->prev; + node_path = (struct node_path_item*)node_path->prev; free(path_item); - parent = ((node_t*)parent)->parent; + parent = ((node_t)parent)->parent; if (!parent) { goto err_out; } @@ -1414,24 +1447,41 @@ err_out: /* clean up node_path if required */ while (node_path) { struct node_path_item *path_item = node_path; - node_path = path_item->prev; + node_path = (struct node_path_item*)path_item->prev; free(path_item); } if (ctx->err) { plist_free(*plist); *plist = NULL; + return PLIST_ERR_PARSE; } + + /* check if we have a UID "dict" so we can replace it with a proper UID node */ + if (PLIST_IS_DICT(*plist) && plist_dict_get_size(*plist) == 1) { + plist_t value = plist_dict_get_item(*plist, "CF$UID"); + if (PLIST_IS_UINT(value)) { + uint64_t u64val = 0; + plist_get_uint_val(value, &u64val); + plist_free(*plist); + *plist = plist_new_uid(u64val); + } + } + + return PLIST_ERR_SUCCESS; } -PLIST_API 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) { + 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); } |