summaryrefslogtreecommitdiffstats
path: root/src/xplist.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/xplist.c')
-rw-r--r--src/xplist.c190
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);
}