summaryrefslogtreecommitdiffstats
path: root/src/xplist.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/xplist.c')
-rw-r--r--src/xplist.c221
1 files changed, 152 insertions, 69 deletions
diff --git a/src/xplist.c b/src/xplist.c
index 2c21272..6100afc 100644
--- a/src/xplist.c
+++ b/src/xplist.c
@@ -39,6 +39,7 @@
39#include <float.h> 39#include <float.h>
40#include <math.h> 40#include <math.h>
41#include <limits.h> 41#include <limits.h>
42#include <errno.h>
42 43
43#include <node.h> 44#include <node.h>
44 45
@@ -381,24 +382,44 @@ static plist_err_t node_to_xml(node_t node, bytearray_t **outbuf, uint32_t depth
381 return PLIST_ERR_SUCCESS; 382 return PLIST_ERR_SUCCESS;
382} 383}
383 384
384static void parse_date(const char *strval, struct TM *btime) 385static int parse_date(const char *strval, struct TM *btime)
385{ 386{
386 if (!btime) return; 387 if (!btime) return -1;
387 memset(btime, 0, sizeof(struct tm)); 388 memset(btime, 0, sizeof(*btime));
388 if (!strval) return; 389 if (!strval) return -1;
389#ifdef HAVE_STRPTIME 390#ifdef HAVE_STRPTIME
390 strptime((char*)strval, "%Y-%m-%dT%H:%M:%SZ", btime); 391#ifdef USE_TM64
392 struct tm t = { 0 };
393 char* r = strptime((char*)strval, "%Y-%m-%dT%H:%M:%SZ", &t);
394 if (!r || *r != '\0') {
395 return -1;
396 }
397 copy_tm_to_TM64(&t, btime);
398#else
399 char* r = strptime((char*)strval, "%Y-%m-%dT%H:%M:%SZ", btime);
400 if (!r || *r != '\0') {
401 return -1;
402 }
403#endif
391#else 404#else
392#ifdef USE_TM64 405#ifdef USE_TM64
393 #define PLIST_SSCANF_FORMAT "%lld-%d-%dT%d:%d:%dZ" 406 #define PLIST_SSCANF_FORMAT "%lld-%d-%dT%d:%d:%dZ"
394#else 407#else
395 #define PLIST_SSCANF_FORMAT "%d-%d-%dT%d:%d:%dZ" 408 #define PLIST_SSCANF_FORMAT "%d-%d-%dT%d:%d:%dZ"
396#endif 409#endif
397 sscanf(strval, PLIST_SSCANF_FORMAT, &btime->tm_year, &btime->tm_mon, &btime->tm_mday, &btime->tm_hour, &btime->tm_min, &btime->tm_sec); 410 int n = 0;
411 if (sscanf(strval, PLIST_SSCANF_FORMAT "%n", &btime->tm_year, &btime->tm_mon, &btime->tm_mday, &btime->tm_hour, &btime->tm_min, &btime->tm_sec, &n) != 6) return -1;
412 if (strval[n] != '\0') return -1;
413 if (btime->tm_mon < 1 || btime->tm_mon > 12) return -1;
414 if (btime->tm_mday < 1 || btime->tm_mday > 31) return -1;
415 if (btime->tm_hour < 0 || btime->tm_hour > 23) return -1;
416 if (btime->tm_min < 0 || btime->tm_min > 59) return -1;
417 if (btime->tm_sec < 0 || btime->tm_sec > 59) return -1;
398 btime->tm_year-=1900; 418 btime->tm_year-=1900;
399 btime->tm_mon--; 419 btime->tm_mon--;
400#endif 420#endif
401 btime->tm_isdst=0; 421 btime->tm_isdst=0;
422 return 0;
402} 423}
403 424
404#define PO10i_LIMIT (INT64_MAX/10) 425#define PO10i_LIMIT (INT64_MAX/10)
@@ -599,9 +620,14 @@ struct _parse_ctx {
599}; 620};
600typedef struct _parse_ctx* parse_ctx; 621typedef struct _parse_ctx* parse_ctx;
601 622
623static inline int is_xml_ws(unsigned char c)
624{
625 return (c == ' ' || c == '\t' || c == '\r' || c == '\n');
626}
627
602static void parse_skip_ws(parse_ctx ctx) 628static void parse_skip_ws(parse_ctx ctx)
603{ 629{
604 while (ctx->pos < ctx->end && ((*(ctx->pos) == ' ') || (*(ctx->pos) == '\t') || (*(ctx->pos) == '\r') || (*(ctx->pos) == '\n'))) { 630 while (ctx->pos < ctx->end && is_xml_ws(*(ctx->pos))) {
605 ctx->pos++; 631 ctx->pos++;
606 } 632 }
607} 633}
@@ -822,8 +848,7 @@ static text_part_t* get_text_parts(parse_ctx ctx, const char* tag, size_t tag_le
822 return NULL; 848 return NULL;
823 } 849 }
824 ctx->pos++; 850 ctx->pos++;
825 851 if (q > p) {
826 if (q-p > 0) {
827 if (last) { 852 if (last) {
828 last = text_part_append(last, p, q-p, 0); 853 last = text_part_append(last, p, q-p, 0);
829 } else if (parts) { 854 } else if (parts) {
@@ -944,7 +969,7 @@ static int unescape_entities(char *str, size_t *length)
944 return 0; 969 return 0;
945} 970}
946 971
947static char* text_parts_get_content(text_part_t *tp, int unesc_entities, size_t *length, int *requires_free) 972static char* text_parts_get_content(text_part_t *tp, int unesc_entities, int trim_ws, size_t *length, int *requires_free)
948{ 973{
949 char *str = NULL; 974 char *str = NULL;
950 size_t total_length = 0; 975 size_t total_length = 0;
@@ -953,14 +978,12 @@ static char* text_parts_get_content(text_part_t *tp, int unesc_entities, size_t
953 return NULL; 978 return NULL;
954 } 979 }
955 char *p; 980 char *p;
956 if (requires_free && !tp->next) { 981 if (requires_free && !tp->next && !unesc_entities && !trim_ws) {
957 if (tp->is_cdata || !unesc_entities) { 982 *requires_free = 0;
958 *requires_free = 0; 983 if (length) {
959 if (length) { 984 *length = tp->length;
960 *length = tp->length;
961 }
962 return (char*)tp->begin;
963 } 985 }
986 return (char*)tp->begin;
964 } 987 }
965 text_part_t *tmp = tp; 988 text_part_t *tmp = tp;
966 while (tp && tp->begin) { 989 while (tp && tp->begin) {
@@ -985,6 +1008,21 @@ static char* text_parts_get_content(text_part_t *tp, int unesc_entities, size_t
985 tp = (text_part_t*)tp->next; 1008 tp = (text_part_t*)tp->next;
986 } 1009 }
987 *p = '\0'; 1010 *p = '\0';
1011 if (trim_ws) {
1012 char* start = str;
1013 char* end = p;
1014 while (start < end && is_xml_ws((unsigned char)start[0])) start++;
1015 while (end > start && is_xml_ws((unsigned char)end[-1])) end--;
1016 if (start != str) {
1017 size_t newlen = (size_t)(end - start);
1018 memmove(str, start, newlen);
1019 str[newlen] = '\0';
1020 p = str + newlen;
1021 } else {
1022 *end = '\0';
1023 p = end;
1024 }
1025 }
988 if (length) { 1026 if (length) {
989 *length = p - str; 1027 *length = p - str;
990 } 1028 }
@@ -1001,11 +1039,10 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
1001 plist_t subnode = NULL; 1039 plist_t subnode = NULL;
1002 const char *p = NULL; 1040 const char *p = NULL;
1003 plist_t parent = NULL; 1041 plist_t parent = NULL;
1004 int has_content = 0;
1005 1042
1006 struct node_path_item { 1043 struct node_path_item {
1007 const char *type; 1044 const char *type;
1008 void *prev; 1045 struct node_path_item *prev;
1009 }; 1046 };
1010 struct node_path_item* node_path = NULL; 1047 struct node_path_item* node_path = NULL;
1011 int depth = 0; 1048 int depth = 0;
@@ -1047,7 +1084,7 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
1047 /* comment or DTD */ 1084 /* comment or DTD */
1048 if (((ctx->end - ctx->pos) > 3) && !strncmp(ctx->pos, "!--", 3)) { 1085 if (((ctx->end - ctx->pos) > 3) && !strncmp(ctx->pos, "!--", 3)) {
1049 ctx->pos += 3; 1086 ctx->pos += 3;
1050 find_str(ctx,"-->", 3, 0); 1087 find_str(ctx, "-->", 3, 0);
1051 if (ctx->pos > ctx->end-3 || strncmp(ctx->pos, "-->", 3) != 0) { 1088 if (ctx->pos > ctx->end-3 || strncmp(ctx->pos, "-->", 3) != 0) {
1052 PLIST_XML_ERR("Couldn't find end of comment\n"); 1089 PLIST_XML_ERR("Couldn't find end of comment\n");
1053 ctx->err = PLIST_ERR_PARSE; 1090 ctx->err = PLIST_ERR_PARSE;
@@ -1096,7 +1133,7 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
1096 int is_empty = 0; 1133 int is_empty = 0;
1097 int closing_tag = 0; 1134 int closing_tag = 0;
1098 p = ctx->pos; 1135 p = ctx->pos;
1099 find_next(ctx," \r\n\t<>", 6, 0); 1136 find_next(ctx, " \r\n\t<>", 6, 0);
1100 if (ctx->pos >= ctx->end) { 1137 if (ctx->pos >= ctx->end) {
1101 PLIST_XML_ERR("Unexpected EOF while parsing XML\n"); 1138 PLIST_XML_ERR("Unexpected EOF while parsing XML\n");
1102 ctx->err = PLIST_ERR_PARSE; 1139 ctx->err = PLIST_ERR_PARSE;
@@ -1132,8 +1169,6 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
1132 } 1169 }
1133 ctx->pos++; 1170 ctx->pos++;
1134 if (!strcmp(tag, "plist")) { 1171 if (!strcmp(tag, "plist")) {
1135 has_content = 0;
1136
1137 if (!node_path && *plist) { 1172 if (!node_path && *plist) {
1138 /* we don't allow another top-level <plist> */ 1173 /* we don't allow another top-level <plist> */
1139 break; 1174 break;
@@ -1156,7 +1191,7 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
1156 1191
1157 continue; 1192 continue;
1158 } else if (!strcmp(tag, "/plist")) { 1193 } else if (!strcmp(tag, "/plist")) {
1159 if (!has_content) { 1194 if (!*plist) {
1160 PLIST_XML_ERR("encountered empty plist tag\n"); 1195 PLIST_XML_ERR("encountered empty plist tag\n");
1161 ctx->err = PLIST_ERR_PARSE; 1196 ctx->err = PLIST_ERR_PARSE;
1162 goto err_out; 1197 goto err_out;
@@ -1176,10 +1211,12 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
1176 free(path_item); 1211 free(path_item);
1177 continue; 1212 continue;
1178 } 1213 }
1179 1214 if (tag[0] == '/') {
1215 closing_tag = 1;
1216 goto handle_closing;
1217 }
1180 plist_data_t data = plist_new_plist_data(); 1218 plist_data_t data = plist_new_plist_data();
1181 subnode = plist_new_node(data); 1219 subnode = plist_new_node(data);
1182 has_content = 1;
1183 1220
1184 if (!strcmp(tag, XPLIST_DICT)) { 1221 if (!strcmp(tag, XPLIST_DICT)) {
1185 data->type = PLIST_DICT; 1222 data->type = PLIST_DICT;
@@ -1196,8 +1233,7 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
1196 goto err_out; 1233 goto err_out;
1197 } 1234 }
1198 if (tp->begin) { 1235 if (tp->begin) {
1199 int requires_free = 0; 1236 char *str_content = text_parts_get_content(tp, 0, 1, NULL, NULL);
1200 char *str_content = text_parts_get_content(tp, 0, NULL, &requires_free);
1201 if (!str_content) { 1237 if (!str_content) {
1202 PLIST_XML_ERR("Could not get text content for '%s' node\n", tag); 1238 PLIST_XML_ERR("Could not get text content for '%s' node\n", tag);
1203 text_parts_free((text_part_t*)first_part.next); 1239 text_parts_free((text_part_t*)first_part.next);
@@ -1212,7 +1248,30 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
1212 } 1248 }
1213 str++; 1249 str++;
1214 } 1250 }
1215 data->intval = strtoull(str, NULL, 0); 1251 errno = 0;
1252 char* endp = NULL;
1253 data->intval = strtoull(str, &endp, 0);
1254 if (errno == ERANGE) {
1255 PLIST_XML_ERR("Integer overflow detected while parsing '%.20s'\n", str_content);
1256 text_parts_free((text_part_t*)first_part.next);
1257 ctx->err = PLIST_ERR_PARSE;
1258 free(str_content);
1259 goto err_out;
1260 }
1261 if (endp == str || *endp != '\0') {
1262 PLIST_XML_ERR("Invalid characters while parsing integer value '%.20s'\n", str_content);
1263 text_parts_free((text_part_t*)first_part.next);
1264 ctx->err = PLIST_ERR_PARSE;
1265 free(str_content);
1266 goto err_out;
1267 }
1268 if (is_negative && data->intval > ((uint64_t)INT64_MAX + 1)) {
1269 PLIST_XML_ERR("Signed integer value out of range while parsing '%.20s'\n", str_content);
1270 text_parts_free((text_part_t*)first_part.next);
1271 ctx->err = PLIST_ERR_PARSE;
1272 free(str_content);
1273 goto err_out;
1274 }
1216 if (is_negative || (data->intval <= INT64_MAX)) { 1275 if (is_negative || (data->intval <= INT64_MAX)) {
1217 uint64_t v = data->intval; 1276 uint64_t v = data->intval;
1218 if (is_negative) { 1277 if (is_negative) {
@@ -1223,17 +1282,16 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
1223 } else { 1282 } else {
1224 data->length = 16; 1283 data->length = 16;
1225 } 1284 }
1226 if (requires_free) { 1285 free(str_content);
1227 free(str_content);
1228 }
1229 } else { 1286 } else {
1230 is_empty = 1; 1287 is_empty = 1;
1231 } 1288 }
1232 text_parts_free((text_part_t*)tp->next); 1289 text_parts_free((text_part_t*)first_part.next);
1233 } 1290 }
1234 if (is_empty) { 1291 if (is_empty) {
1235 data->intval = 0; 1292 PLIST_XML_ERR("Encountered empty " XPLIST_INT " tag\n");
1236 data->length = 8; 1293 ctx->err = PLIST_ERR_PARSE;
1294 goto err_out;
1237 } 1295 }
1238 data->type = PLIST_INT; 1296 data->type = PLIST_INT;
1239 } else if (!strcmp(tag, XPLIST_REAL)) { 1297 } else if (!strcmp(tag, XPLIST_REAL)) {
@@ -1247,20 +1305,48 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
1247 goto err_out; 1305 goto err_out;
1248 } 1306 }
1249 if (tp->begin) { 1307 if (tp->begin) {
1250 int requires_free = 0; 1308 char *str_content = text_parts_get_content(tp, 0, 1, NULL, NULL);
1251 char *str_content = text_parts_get_content(tp, 0, NULL, &requires_free);
1252 if (!str_content) { 1309 if (!str_content) {
1253 PLIST_XML_ERR("Could not get text content for '%s' node\n", tag); 1310 PLIST_XML_ERR("Could not get text content for '%s' node\n", tag);
1254 text_parts_free((text_part_t*)first_part.next); 1311 text_parts_free((text_part_t*)first_part.next);
1255 ctx->err = PLIST_ERR_PARSE; 1312 ctx->err = PLIST_ERR_PARSE;
1256 goto err_out; 1313 goto err_out;
1257 } 1314 }
1258 data->realval = atof(str_content); 1315 errno = 0;
1259 if (requires_free) { 1316 char *endp = NULL;
1317 data->realval = strtod(str_content, &endp);
1318 if (errno == ERANGE) {
1319 PLIST_XML_ERR("Invalid range while parsing value for '%s' node\n", tag);
1320 text_parts_free((text_part_t*)first_part.next);
1321 ctx->err = PLIST_ERR_PARSE;
1260 free(str_content); 1322 free(str_content);
1323 goto err_out;
1261 } 1324 }
1325 if (endp == str_content || *endp != '\0') {
1326 PLIST_XML_ERR("Could not parse value for '%s' node\n", tag);
1327 text_parts_free((text_part_t*)first_part.next);
1328 ctx->err = PLIST_ERR_PARSE;
1329 free(str_content);
1330 goto err_out;
1331
1332 }
1333 if (!isfinite(data->realval)) {
1334 PLIST_XML_ERR("Invalid real value while parsing '%.20s'\n", str_content);
1335 text_parts_free((text_part_t*)first_part.next);
1336 ctx->err = PLIST_ERR_PARSE;
1337 free(str_content);
1338 goto err_out;
1339 }
1340 free(str_content);
1341 } else {
1342 is_empty = 1;
1262 } 1343 }
1263 text_parts_free((text_part_t*)tp->next); 1344 text_parts_free((text_part_t*)first_part.next);
1345 }
1346 if (is_empty) {
1347 PLIST_XML_ERR("Encountered empty " XPLIST_REAL " tag\n");
1348 ctx->err = PLIST_ERR_PARSE;
1349 goto err_out;
1264 } 1350 }
1265 data->type = PLIST_REAL; 1351 data->type = PLIST_REAL;
1266 data->length = 8; 1352 data->length = 8;
@@ -1290,7 +1376,7 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
1290 ctx->err = PLIST_ERR_PARSE; 1376 ctx->err = PLIST_ERR_PARSE;
1291 goto err_out; 1377 goto err_out;
1292 } 1378 }
1293 str = text_parts_get_content(tp, 1, &length, NULL); 1379 str = text_parts_get_content(tp, 1, 0, &length, NULL);
1294 text_parts_free((text_part_t*)first_part.next); 1380 text_parts_free((text_part_t*)first_part.next);
1295 if (!str) { 1381 if (!str) {
1296 PLIST_XML_ERR("Could not get text content for '%s' node\n", tag); 1382 PLIST_XML_ERR("Could not get text content for '%s' node\n", tag);
@@ -1329,7 +1415,7 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
1329 } 1415 }
1330 if (tp->begin) { 1416 if (tp->begin) {
1331 int requires_free = 0; 1417 int requires_free = 0;
1332 char *str_content = text_parts_get_content(tp, 0, NULL, &requires_free); 1418 char *str_content = text_parts_get_content(tp, 0, 0, NULL, &requires_free);
1333 if (!str_content) { 1419 if (!str_content) {
1334 PLIST_XML_ERR("Could not get text content for '%s' node\n", tag); 1420 PLIST_XML_ERR("Could not get text content for '%s' node\n", tag);
1335 text_parts_free((text_part_t*)first_part.next); 1421 text_parts_free((text_part_t*)first_part.next);
@@ -1346,7 +1432,7 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
1346 free(str_content); 1432 free(str_content);
1347 } 1433 }
1348 } 1434 }
1349 text_parts_free((text_part_t*)tp->next); 1435 text_parts_free((text_part_t*)first_part.next);
1350 } 1436 }
1351 data->type = PLIST_DATA; 1437 data->type = PLIST_DATA;
1352 } else if (!strcmp(tag, XPLIST_DATE)) { 1438 } else if (!strcmp(tag, XPLIST_DATE)) {
@@ -1361,38 +1447,36 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
1361 } 1447 }
1362 Time64_T timev = 0; 1448 Time64_T timev = 0;
1363 if (tp->begin) { 1449 if (tp->begin) {
1364 int requires_free = 0; 1450 char *str_content = text_parts_get_content(tp, 0, 1, NULL, NULL);
1365 size_t length = 0;
1366 char *str_content = text_parts_get_content(tp, 0, &length, &requires_free);
1367 if (!str_content) { 1451 if (!str_content) {
1368 PLIST_XML_ERR("Could not get text content for '%s' node\n", tag); 1452 PLIST_XML_ERR("Could not get text content for '%s' node\n", tag);
1369 text_parts_free((text_part_t*)first_part.next); 1453 text_parts_free((text_part_t*)first_part.next);
1370 ctx->err = PLIST_ERR_PARSE; 1454 ctx->err = PLIST_ERR_PARSE;
1371 goto err_out; 1455 goto err_out;
1372 } 1456 }
1373 1457 struct TM btime;
1374 if ((length >= 11) && (length < 32)) { 1458 if (parse_date(str_content, &btime) < 0) {
1375 /* we need to copy here and 0-terminate because sscanf will read the entire string (whole rest of XML data) which can be huge */ 1459 PLIST_XML_ERR("Failed to parse date node\n");
1376 char strval[32]; 1460 text_parts_free((text_part_t*)first_part.next);
1377 struct TM btime; 1461 ctx->err = PLIST_ERR_PARSE;
1378 memcpy(strval, str_content, length);
1379 strval[tp->length] = '\0';
1380 parse_date(strval, &btime);
1381 timev = timegm64(&btime);
1382 } else {
1383 PLIST_XML_ERR("Invalid text content in date node\n");
1384 }
1385 if (requires_free) {
1386 free(str_content); 1462 free(str_content);
1463 goto err_out;
1387 } 1464 }
1465 timev = timegm64(&btime);
1466 free(str_content);
1467 } else {
1468 is_empty = 1;
1388 } 1469 }
1389 text_parts_free((text_part_t*)tp->next); 1470 text_parts_free((text_part_t*)first_part.next);
1390 data->realval = (double)(timev - MAC_EPOCH); 1471 data->realval = (double)(timev - MAC_EPOCH);
1391 } 1472 }
1473 if (is_empty) {
1474 PLIST_XML_ERR("Encountered empty " XPLIST_DATE " tag\n");
1475 ctx->err = PLIST_ERR_PARSE;
1476 goto err_out;
1477 }
1392 data->length = sizeof(double); 1478 data->length = sizeof(double);
1393 data->type = PLIST_DATE; 1479 data->type = PLIST_DATE;
1394 } else if (tag[0] == '/') {
1395 closing_tag = 1;
1396 } else { 1480 } else {
1397 PLIST_XML_ERR("Unexpected tag <%s%s> encountered\n", tag, (is_empty) ? "/" : ""); 1481 PLIST_XML_ERR("Unexpected tag <%s%s> encountered\n", tag, (is_empty) ? "/" : "");
1398 ctx->pos = ctx->end; 1482 ctx->pos = ctx->end;
@@ -1449,7 +1533,9 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
1449 parent = subnode; 1533 parent = subnode;
1450 } 1534 }
1451 subnode = NULL; 1535 subnode = NULL;
1452 } else if (closing_tag) { 1536 }
1537handle_closing:
1538 if (closing_tag) {
1453 if (!node_path) { 1539 if (!node_path) {
1454 PLIST_XML_ERR("node path is empty while trying to match closing tag with opening tag\n"); 1540 PLIST_XML_ERR("node path is empty while trying to match closing tag with opening tag\n");
1455 ctx->err = PLIST_ERR_PARSE; 1541 ctx->err = PLIST_ERR_PARSE;
@@ -1464,11 +1550,8 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
1464 struct node_path_item *path_item = node_path; 1550 struct node_path_item *path_item = node_path;
1465 node_path = (struct node_path_item*)node_path->prev; 1551 node_path = (struct node_path_item*)node_path->prev;
1466 free(path_item); 1552 free(path_item);
1467 1553 parent = (parent) ? ((node_t)parent)->parent : NULL;
1468 parent = ((node_t)parent)->parent; 1554 /* parent can be NULL when we just closed the root node; keep parsing */
1469 if (!parent) {
1470 goto err_out;
1471 }
1472 } 1555 }
1473 free(keyname); 1556 free(keyname);
1474 keyname = NULL; 1557 keyname = NULL;
@@ -1502,7 +1585,7 @@ err_out:
1502 /* check if we have a UID "dict" so we can replace it with a proper UID node */ 1585 /* check if we have a UID "dict" so we can replace it with a proper UID node */
1503 if (PLIST_IS_DICT(*plist) && plist_dict_get_size(*plist) == 1) { 1586 if (PLIST_IS_DICT(*plist) && plist_dict_get_size(*plist) == 1) {
1504 plist_t value = plist_dict_get_item(*plist, "CF$UID"); 1587 plist_t value = plist_dict_get_item(*plist, "CF$UID");
1505 if (PLIST_IS_UINT(value)) { 1588 if (PLIST_IS_INT(value)) {
1506 uint64_t u64val = 0; 1589 uint64_t u64val = 0;
1507 plist_get_uint_val(value, &u64val); 1590 plist_get_uint_val(value, &u64val);
1508 plist_free(*plist); 1591 plist_free(*plist);