summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Nikias Bassen2026-01-17 15:18:06 +0100
committerGravatar Nikias Bassen2026-01-17 16:04:00 +0100
commite45099fb21b679aa0cdb0db394587bb5ba675b0c (patch)
treeb1a2c1dd34877d83a04d6d6fab804fb2e5a65f2d
parent26dd27c435a0d110c924e1fef34ad0f6ae60e251 (diff)
downloadlibplist-e45099fb21b679aa0cdb0db394587bb5ba675b0c.tar.gz
libplist-e45099fb21b679aa0cdb0db394587bb5ba675b0c.tar.bz2
Prevent deep nesting of plist structures in all input/output formats
Thanks to @unbengable12 for reporting. Addresses #288, #289, #290, #291, and #292.
-rw-r--r--include/plist/plist.h1
-rw-r--r--src/bplist.c26
-rw-r--r--src/jplist.c48
-rw-r--r--src/oplist.c69
-rw-r--r--src/out-default.c7
-rw-r--r--src/out-limd.c7
-rw-r--r--src/out-plutil.c7
-rw-r--r--src/plist.h4
-rw-r--r--src/xplist.c111
9 files changed, 185 insertions, 95 deletions
diff --git a/include/plist/plist.h b/include/plist/plist.h
index 5ea30b8..8ed9063 100644
--- a/include/plist/plist.h
+++ b/include/plist/plist.h
@@ -145,6 +145,7 @@ extern "C"
145 PLIST_ERR_NO_MEM = -4, /**< not enough memory to handle the operation */ 145 PLIST_ERR_NO_MEM = -4, /**< not enough memory to handle the operation */
146 PLIST_ERR_IO = -5, /**< I/O error */ 146 PLIST_ERR_IO = -5, /**< I/O error */
147 PLIST_ERR_CIRCULAR_REF = -6, /**< circular reference detected */ 147 PLIST_ERR_CIRCULAR_REF = -6, /**< circular reference detected */
148 PLIST_ERR_MAX_NESTING = -7, /**< maximum nesting depth exceeded */
148 PLIST_ERR_UNKNOWN = -255 /**< an unspecified error occurred */ 149 PLIST_ERR_UNKNOWN = -255 /**< an unspecified error occurred */
149 } plist_err_t; 150 } plist_err_t;
150 151
diff --git a/src/bplist.c b/src/bplist.c
index a2dc957..254c0ff 100644
--- a/src/bplist.c
+++ b/src/bplist.c
@@ -239,6 +239,7 @@ struct bplist_data {
239 const char* offset_table; 239 const char* offset_table;
240 uint32_t level; 240 uint32_t level;
241 ptrarray_t* used_indexes; 241 ptrarray_t* used_indexes;
242 plist_err_t err;
242}; 243};
243 244
244#ifdef DEBUG 245#ifdef DEBUG
@@ -787,6 +788,7 @@ static plist_t parse_bin_node_at_index(struct bplist_data *bplist, uint32_t node
787 788
788 if (node_index >= bplist->num_objects) { 789 if (node_index >= bplist->num_objects) {
789 PLIST_BIN_ERR("node index (%u) must be smaller than the number of objects (%" PRIu64 ")\n", node_index, bplist->num_objects); 790 PLIST_BIN_ERR("node index (%u) must be smaller than the number of objects (%" PRIu64 ")\n", node_index, bplist->num_objects);
791 bplist->err = PLIST_ERR_PARSE;
790 return NULL; 792 return NULL;
791 } 793 }
792 794
@@ -794,6 +796,7 @@ static plist_t parse_bin_node_at_index(struct bplist_data *bplist, uint32_t node
794 if (idx_ptr < bplist->offset_table || 796 if (idx_ptr < bplist->offset_table ||
795 idx_ptr >= bplist->offset_table + bplist->num_objects * bplist->offset_size) { 797 idx_ptr >= bplist->offset_table + bplist->num_objects * bplist->offset_size) {
796 PLIST_BIN_ERR("node index %u points outside of valid range\n", node_index); 798 PLIST_BIN_ERR("node index %u points outside of valid range\n", node_index);
799 bplist->err = PLIST_ERR_PARSE;
797 return NULL; 800 return NULL;
798 } 801 }
799 802
@@ -801,6 +804,14 @@ static plist_t parse_bin_node_at_index(struct bplist_data *bplist, uint32_t node
801 /* make sure the node offset is in a sane range */ 804 /* make sure the node offset is in a sane range */
802 if ((ptr < bplist->data+BPLIST_MAGIC_SIZE+BPLIST_VERSION_SIZE) || (ptr >= bplist->offset_table)) { 805 if ((ptr < bplist->data+BPLIST_MAGIC_SIZE+BPLIST_VERSION_SIZE) || (ptr >= bplist->offset_table)) {
803 PLIST_BIN_ERR("offset for node index %u points outside of valid range\n", node_index); 806 PLIST_BIN_ERR("offset for node index %u points outside of valid range\n", node_index);
807 bplist->err = PLIST_ERR_PARSE;
808 return NULL;
809 }
810
811 /* check nesting depth */
812 if (bplist->level > PLIST_MAX_NESTING_DEPTH) {
813 PLIST_BIN_ERR("maximum nesting depth (%u) exceeded\n",(unsigned)PLIST_MAX_NESTING_DEPTH);
814 bplist->err = PLIST_ERR_MAX_NESTING;
804 return NULL; 815 return NULL;
805 } 816 }
806 817
@@ -820,6 +831,7 @@ static plist_t parse_bin_node_at_index(struct bplist_data *bplist, uint32_t node
820 void *node_level = ptr_array_index(bplist->used_indexes, bplist->level); 831 void *node_level = ptr_array_index(bplist->used_indexes, bplist->level);
821 if (node_i == node_level) { 832 if (node_i == node_level) {
822 PLIST_BIN_ERR("recursion detected in binary plist\n"); 833 PLIST_BIN_ERR("recursion detected in binary plist\n");
834 bplist->err = PLIST_ERR_PARSE;
823 return NULL; 835 return NULL;
824 } 836 }
825 } 837 }
@@ -931,6 +943,7 @@ plist_err_t plist_from_bin(const char *plist_bin, uint32_t length, plist_t * pli
931 bplist.offset_table = offset_table; 943 bplist.offset_table = offset_table;
932 bplist.level = 0; 944 bplist.level = 0;
933 bplist.used_indexes = ptr_array_new(16); 945 bplist.used_indexes = ptr_array_new(16);
946 bplist.err = PLIST_ERR_SUCCESS;
934 947
935 if (!bplist.used_indexes) { 948 if (!bplist.used_indexes) {
936 PLIST_BIN_ERR("failed to create array to hold used node indexes. Out of memory?\n"); 949 PLIST_BIN_ERR("failed to create array to hold used node indexes. Out of memory?\n");
@@ -942,7 +955,7 @@ plist_err_t plist_from_bin(const char *plist_bin, uint32_t length, plist_t * pli
942 ptr_array_free(bplist.used_indexes); 955 ptr_array_free(bplist.used_indexes);
943 956
944 if (!*plist) { 957 if (!*plist) {
945 return PLIST_ERR_PARSE; 958 return (bplist.err != PLIST_ERR_SUCCESS) ? bplist.err : PLIST_ERR_PARSE;
946 } 959 }
947 960
948 return PLIST_ERR_SUCCESS; 961 return PLIST_ERR_SUCCESS;
@@ -1002,11 +1015,16 @@ struct serialize_s
1002 hashtable_t* in_stack; 1015 hashtable_t* in_stack;
1003}; 1016};
1004 1017
1005static plist_err_t serialize_plist(node_t node, void* data) 1018static plist_err_t serialize_plist(node_t node, void* data, uint32_t depth)
1006{ 1019{
1007 uint64_t *index_val = NULL; 1020 uint64_t *index_val = NULL;
1008 struct serialize_s *ser = (struct serialize_s *) data; 1021 struct serialize_s *ser = (struct serialize_s *) data;
1009 1022
1023 if (depth > PLIST_MAX_NESTING_DEPTH) {
1024 PLIST_BIN_WRITE_ERR("maximum nesting depth (%u) exceeded\n", (unsigned)PLIST_MAX_NESTING_DEPTH);
1025 return PLIST_ERR_MAX_NESTING;
1026 }
1027
1010 // circular reference check: is node on current recursion stack? 1028 // circular reference check: is node on current recursion stack?
1011 if (hash_table_lookup(ser->in_stack, node)) { 1029 if (hash_table_lookup(ser->in_stack, node)) {
1012 PLIST_BIN_WRITE_ERR("circular reference detected\n"); 1030 PLIST_BIN_WRITE_ERR("circular reference detected\n");
@@ -1036,7 +1054,7 @@ static plist_err_t serialize_plist(node_t node, void* data)
1036 node_t ch; 1054 node_t ch;
1037 plist_err_t err = PLIST_ERR_SUCCESS; 1055 plist_err_t err = PLIST_ERR_SUCCESS;
1038 for (ch = node_first_child(node); ch; ch = node_next_sibling(ch)) { 1056 for (ch = node_first_child(node); ch; ch = node_next_sibling(ch)) {
1039 err = serialize_plist(ch, data); 1057 err = serialize_plist(ch, data, depth+1);
1040 if (err != PLIST_ERR_SUCCESS) { 1058 if (err != PLIST_ERR_SUCCESS) {
1041 break; 1059 break;
1042 } 1060 }
@@ -1313,7 +1331,7 @@ plist_err_t plist_to_bin(plist_t plist, char **plist_bin, uint32_t * length)
1313 ser_s.objects = objects; 1331 ser_s.objects = objects;
1314 ser_s.ref_table = ref_table; 1332 ser_s.ref_table = ref_table;
1315 ser_s.in_stack = in_stack; 1333 ser_s.in_stack = in_stack;
1316 plist_err_t err = serialize_plist((node_t)plist, &ser_s); 1334 plist_err_t err = serialize_plist((node_t)plist, &ser_s, 0);
1317 if (err != PLIST_ERR_SUCCESS) { 1335 if (err != PLIST_ERR_SUCCESS) {
1318 ptr_array_free(objects); 1336 ptr_array_free(objects);
1319 hash_table_destroy(ref_table); 1337 hash_table_destroy(ref_table);
diff --git a/src/jplist.c b/src/jplist.c
index 2e53400..9a40844 100644
--- a/src/jplist.c
+++ b/src/jplist.c
@@ -323,6 +323,11 @@ static plist_err_t _node_estimate_size(node_t node, uint64_t *size, uint32_t dep
323 return PLIST_ERR_INVALID_ARG; 323 return PLIST_ERR_INVALID_ARG;
324 } 324 }
325 325
326 if (depth > PLIST_MAX_NESTING_DEPTH) {
327 PLIST_JSON_WRITE_ERR("maximum nesting depth (%u) exceeded\n", (unsigned)PLIST_MAX_NESTING_DEPTH);
328 return PLIST_ERR_MAX_NESTING;
329 }
330
326 if (hash_table_lookup(visited, node)) { 331 if (hash_table_lookup(visited, node)) {
327 PLIST_JSON_WRITE_ERR("circular reference detected\n"); 332 PLIST_JSON_WRITE_ERR("circular reference detected\n");
328 return PLIST_ERR_CIRCULAR_REF; 333 return PLIST_ERR_CIRCULAR_REF;
@@ -471,6 +476,7 @@ plist_err_t plist_to_json(plist_t plist, char **plist_json, uint32_t* length, in
471typedef struct { 476typedef struct {
472 jsmntok_t* tokens; 477 jsmntok_t* tokens;
473 int count; 478 int count;
479 plist_err_t err;
474} jsmntok_info_t; 480} jsmntok_info_t;
475 481
476static int64_t parse_decimal(const char* str, const char* str_end, char** endp) 482static int64_t parse_decimal(const char* str, const char* str_end, char** endp)
@@ -698,12 +704,18 @@ static plist_t parse_string(const char* js, jsmntok_info_t* ti, int* index)
698 return node; 704 return node;
699} 705}
700 706
701static plist_t parse_object(const char* js, jsmntok_info_t* ti, int* index); 707static plist_t parse_object(const char* js, jsmntok_info_t* ti, int* index, uint32_t depth);
702 708
703static plist_t parse_array(const char* js, jsmntok_info_t* ti, int* index) 709static plist_t parse_array(const char* js, jsmntok_info_t* ti, int* index, uint32_t depth)
704{ 710{
705 if (ti->tokens[*index].type != JSMN_ARRAY) { 711 if (ti->tokens[*index].type != JSMN_ARRAY) {
706 PLIST_JSON_ERR("%s: token type != JSMN_ARRAY\n", __func__); 712 PLIST_JSON_ERR("%s: token type != JSMN_ARRAY\n", __func__);
713 ti->err = PLIST_ERR_PARSE;
714 return NULL;
715 }
716 if (depth > PLIST_MAX_NESTING_DEPTH) {
717 PLIST_JSON_ERR("%s: maximum nesting depth (%u) exceeded\n", __func__, (unsigned)PLIST_MAX_NESTING_DEPTH);
718 ti->err = PLIST_ERR_MAX_NESTING;
707 return NULL; 719 return NULL;
708 } 720 }
709 plist_t arr = plist_new_array(); 721 plist_t arr = plist_new_array();
@@ -714,15 +726,16 @@ static plist_t parse_array(const char* js, jsmntok_info_t* ti, int* index)
714 if (j >= ti->count) { 726 if (j >= ti->count) {
715 PLIST_JSON_ERR("%s: token index out of valid range\n", __func__); 727 PLIST_JSON_ERR("%s: token index out of valid range\n", __func__);
716 plist_free(arr); 728 plist_free(arr);
729 ti->err = PLIST_ERR_PARSE;
717 return NULL; 730 return NULL;
718 } 731 }
719 plist_t val = NULL; 732 plist_t val = NULL;
720 switch (ti->tokens[j].type) { 733 switch (ti->tokens[j].type) {
721 case JSMN_OBJECT: 734 case JSMN_OBJECT:
722 val = parse_object(js, ti, &j); 735 val = parse_object(js, ti, &j, depth+1);
723 break; 736 break;
724 case JSMN_ARRAY: 737 case JSMN_ARRAY:
725 val = parse_array(js, ti, &j); 738 val = parse_array(js, ti, &j, depth+1);
726 break; 739 break;
727 case JSMN_STRING: 740 case JSMN_STRING:
728 val = parse_string(js, ti, &j); 741 val = parse_string(js, ti, &j);
@@ -737,6 +750,7 @@ static plist_t parse_array(const char* js, jsmntok_info_t* ti, int* index)
737 plist_array_append_item(arr, val); 750 plist_array_append_item(arr, val);
738 } else { 751 } else {
739 plist_free(arr); 752 plist_free(arr);
753 ti->err = PLIST_ERR_PARSE;
740 return NULL; 754 return NULL;
741 } 755 }
742 } 756 }
@@ -744,10 +758,16 @@ static plist_t parse_array(const char* js, jsmntok_info_t* ti, int* index)
744 return arr; 758 return arr;
745} 759}
746 760
747static plist_t parse_object(const char* js, jsmntok_info_t* ti, int* index) 761static plist_t parse_object(const char* js, jsmntok_info_t* ti, int* index, uint32_t depth)
748{ 762{
749 if (ti->tokens[*index].type != JSMN_OBJECT) { 763 if (ti->tokens[*index].type != JSMN_OBJECT) {
750 PLIST_JSON_ERR("%s: token type != JSMN_OBJECT\n", __func__); 764 PLIST_JSON_ERR("%s: token type != JSMN_OBJECT\n", __func__);
765 ti->err = PLIST_ERR_PARSE;
766 return NULL;
767 }
768 if (depth > PLIST_MAX_NESTING_DEPTH) {
769 PLIST_JSON_ERR("%s: maximum nesting depth (%u) exceeded\n", __func__, (unsigned)PLIST_MAX_NESTING_DEPTH);
770 ti->err = PLIST_ERR_MAX_NESTING;
751 return NULL; 771 return NULL;
752 } 772 }
753 int num_tokens = ti->tokens[*index].size; 773 int num_tokens = ti->tokens[*index].size;
@@ -755,6 +775,7 @@ static plist_t parse_object(const char* js, jsmntok_info_t* ti, int* index)
755 int j = (*index)+1; 775 int j = (*index)+1;
756 if (num_tokens % 2 != 0) { 776 if (num_tokens % 2 != 0) {
757 PLIST_JSON_ERR("%s: number of children must be even\n", __func__); 777 PLIST_JSON_ERR("%s: number of children must be even\n", __func__);
778 ti->err = PLIST_ERR_PARSE;
758 return NULL; 779 return NULL;
759 } 780 }
760 plist_t obj = plist_new_dict(); 781 plist_t obj = plist_new_dict();
@@ -762,12 +783,14 @@ static plist_t parse_object(const char* js, jsmntok_info_t* ti, int* index)
762 if (j+1 >= ti->count) { 783 if (j+1 >= ti->count) {
763 PLIST_JSON_ERR("%s: token index out of valid range\n", __func__); 784 PLIST_JSON_ERR("%s: token index out of valid range\n", __func__);
764 plist_free(obj); 785 plist_free(obj);
786 ti->err = PLIST_ERR_PARSE;
765 return NULL; 787 return NULL;
766 } 788 }
767 if (ti->tokens[j].type == JSMN_STRING) { 789 if (ti->tokens[j].type == JSMN_STRING) {
768 char* key = unescape_string(js + ti->tokens[j].start, ti->tokens[j].end - ti->tokens[j].start, NULL); 790 char* key = unescape_string(js + ti->tokens[j].start, ti->tokens[j].end - ti->tokens[j].start, NULL);
769 if (!key) { 791 if (!key) {
770 plist_free(obj); 792 plist_free(obj);
793 ti->err = PLIST_ERR_PARSE;
771 return NULL; 794 return NULL;
772 } 795 }
773 plist_t val = NULL; 796 plist_t val = NULL;
@@ -775,10 +798,10 @@ static plist_t parse_object(const char* js, jsmntok_info_t* ti, int* index)
775 num++; 798 num++;
776 switch (ti->tokens[j].type) { 799 switch (ti->tokens[j].type) {
777 case JSMN_OBJECT: 800 case JSMN_OBJECT:
778 val = parse_object(js, ti, &j); 801 val = parse_object(js, ti, &j, depth+1);
779 break; 802 break;
780 case JSMN_ARRAY: 803 case JSMN_ARRAY:
781 val = parse_array(js, ti, &j); 804 val = parse_array(js, ti, &j, depth+1);
782 break; 805 break;
783 case JSMN_STRING: 806 case JSMN_STRING:
784 val = parse_string(js, ti, &j); 807 val = parse_string(js, ti, &j);
@@ -794,12 +817,14 @@ static plist_t parse_object(const char* js, jsmntok_info_t* ti, int* index)
794 } else { 817 } else {
795 free(key); 818 free(key);
796 plist_free(obj); 819 plist_free(obj);
820 ti->err = PLIST_ERR_PARSE;
797 return NULL; 821 return NULL;
798 } 822 }
799 free(key); 823 free(key);
800 } else { 824 } else {
801 PLIST_JSON_ERR("%s: keys must be of type STRING\n", __func__); 825 PLIST_JSON_ERR("%s: keys must be of type STRING\n", __func__);
802 plist_free(obj); 826 plist_free(obj);
827 ti->err = PLIST_ERR_PARSE;
803 return NULL; 828 return NULL;
804 } 829 }
805 } 830 }
@@ -859,7 +884,7 @@ plist_err_t plist_from_json(const char *json, uint32_t length, plist_t * plist)
859 } 884 }
860 885
861 int startindex = 0; 886 int startindex = 0;
862 jsmntok_info_t ti = { tokens, parser.toknext }; 887 jsmntok_info_t ti = { tokens, parser.toknext, PLIST_ERR_SUCCESS };
863 switch (tokens[startindex].type) { 888 switch (tokens[startindex].type) {
864 case JSMN_PRIMITIVE: 889 case JSMN_PRIMITIVE:
865 *plist = parse_primitive(json, &ti, &startindex); 890 *plist = parse_primitive(json, &ti, &startindex);
@@ -868,14 +893,17 @@ plist_err_t plist_from_json(const char *json, uint32_t length, plist_t * plist)
868 *plist = parse_string(json, &ti, &startindex); 893 *plist = parse_string(json, &ti, &startindex);
869 break; 894 break;
870 case JSMN_ARRAY: 895 case JSMN_ARRAY:
871 *plist = parse_array(json, &ti, &startindex); 896 *plist = parse_array(json, &ti, &startindex, 0);
872 break; 897 break;
873 case JSMN_OBJECT: 898 case JSMN_OBJECT:
874 *plist = parse_object(json, &ti, &startindex); 899 *plist = parse_object(json, &ti, &startindex, 0);
875 break; 900 break;
876 default: 901 default:
877 break; 902 break;
878 } 903 }
879 free(tokens); 904 free(tokens);
905 if (!*plist) {
906 return (ti.err != PLIST_ERR_SUCCESS) ? ti.err : PLIST_ERR_PARSE;
907 }
880 return PLIST_ERR_SUCCESS; 908 return PLIST_ERR_SUCCESS;
881} 909}
diff --git a/src/oplist.c b/src/oplist.c
index 680873c..0eea27a 100644
--- a/src/oplist.c
+++ b/src/oplist.c
@@ -367,6 +367,11 @@ static plist_err_t _node_estimate_size(node_t node, uint64_t *size, uint32_t dep
367 return PLIST_ERR_INVALID_ARG; 367 return PLIST_ERR_INVALID_ARG;
368 } 368 }
369 369
370 if (depth > PLIST_MAX_NESTING_DEPTH) {
371 PLIST_OSTEP_WRITE_ERR("node tree is nested too deeply\n");
372 return PLIST_ERR_MAX_NESTING;
373 }
374
370 if (hash_table_lookup(visited, node)) { 375 if (hash_table_lookup(visited, node)) {
371 PLIST_OSTEP_WRITE_ERR("circular reference detected\n"); 376 PLIST_OSTEP_WRITE_ERR("circular reference detected\n");
372 return PLIST_ERR_CIRCULAR_REF; 377 return PLIST_ERR_CIRCULAR_REF;
@@ -511,7 +516,7 @@ struct _parse_ctx {
511 const char *start; 516 const char *start;
512 const char *pos; 517 const char *pos;
513 const char *end; 518 const char *end;
514 int err; 519 plist_err_t err;
515 uint32_t depth; 520 uint32_t depth;
516}; 521};
517typedef struct _parse_ctx* parse_ctx; 522typedef struct _parse_ctx* parse_ctx;
@@ -568,50 +573,50 @@ static void parse_dict_data(parse_ctx ctx, plist_t dict)
568 } 573 }
569 key = NULL; 574 key = NULL;
570 ctx->err = node_from_openstep(ctx, &key); 575 ctx->err = node_from_openstep(ctx, &key);
571 if (ctx->err != 0) { 576 if (ctx->err != PLIST_ERR_SUCCESS) {
572 break; 577 break;
573 } 578 }
574 if (!PLIST_IS_STRING(key)) { 579 if (!PLIST_IS_STRING(key)) {
575 PLIST_OSTEP_ERR("Invalid type for dictionary key at offset %ld\n", (long int)(ctx->pos - ctx->start)); 580 PLIST_OSTEP_ERR("Invalid type for dictionary key at offset %ld\n", (long int)(ctx->pos - ctx->start));
576 ctx->err++; 581 ctx->err = PLIST_ERR_PARSE;
577 break; 582 break;
578 } 583 }
579 parse_skip_ws(ctx); 584 parse_skip_ws(ctx);
580 if (ctx->pos >= ctx->end) { 585 if (ctx->pos >= ctx->end) {
581 PLIST_OSTEP_ERR("EOF while parsing dictionary '=' delimiter at offset %ld\n", (long int)(ctx->pos - ctx->start)); 586 PLIST_OSTEP_ERR("EOF while parsing dictionary '=' delimiter at offset %ld\n", (long int)(ctx->pos - ctx->start));
582 ctx->err++; 587 ctx->err = PLIST_ERR_PARSE;
583 break; 588 break;
584 } 589 }
585 if (*ctx->pos != '=') { 590 if (*ctx->pos != '=') {
586 PLIST_OSTEP_ERR("Missing '=' while parsing dictionary item at offset %ld\n", (long int)(ctx->pos - ctx->start)); 591 PLIST_OSTEP_ERR("Missing '=' while parsing dictionary item at offset %ld\n", (long int)(ctx->pos - ctx->start));
587 ctx->err++; 592 ctx->err = PLIST_ERR_PARSE;
588 break; 593 break;
589 } 594 }
590 ctx->pos++; 595 ctx->pos++;
591 if (ctx->pos >= ctx->end) { 596 if (ctx->pos >= ctx->end) {
592 PLIST_OSTEP_ERR("EOF while parsing dictionary item at offset %ld\n", (long int)(ctx->pos - ctx->start)); 597 PLIST_OSTEP_ERR("EOF while parsing dictionary item at offset %ld\n", (long int)(ctx->pos - ctx->start));
593 ctx->err++; 598 ctx->err = PLIST_ERR_PARSE;
594 break; 599 break;
595 } 600 }
596 val = NULL; 601 val = NULL;
597 ctx->err = node_from_openstep(ctx, &val); 602 ctx->err = node_from_openstep(ctx, &val);
598 if (ctx->err != 0) { 603 if (ctx->err != PLIST_ERR_SUCCESS) {
599 break; 604 break;
600 } 605 }
601 if (!val) { 606 if (!val) {
602 PLIST_OSTEP_ERR("Missing value for dictionary item at offset %ld\n", (long int)(ctx->pos - ctx->start)); 607 PLIST_OSTEP_ERR("Missing value for dictionary item at offset %ld\n", (long int)(ctx->pos - ctx->start));
603 ctx->err++; 608 ctx->err = PLIST_ERR_PARSE;
604 break; 609 break;
605 } 610 }
606 parse_skip_ws(ctx); 611 parse_skip_ws(ctx);
607 if (ctx->pos >= ctx->end) { 612 if (ctx->pos >= ctx->end) {
608 PLIST_OSTEP_ERR("EOF while parsing dictionary item terminator ';' at offset %ld\n", (long int)(ctx->pos - ctx->start)); 613 PLIST_OSTEP_ERR("EOF while parsing dictionary item terminator ';' at offset %ld\n", (long int)(ctx->pos - ctx->start));
609 ctx->err++; 614 ctx->err = PLIST_ERR_PARSE;
610 break; 615 break;
611 } 616 }
612 if (*ctx->pos != ';') { 617 if (*ctx->pos != ';') {
613 PLIST_OSTEP_ERR("Missing terminating ';' while parsing dictionary item at offset %ld\n", (long int)(ctx->pos - ctx->start)); 618 PLIST_OSTEP_ERR("Missing terminating ';' while parsing dictionary item at offset %ld\n", (long int)(ctx->pos - ctx->start));
614 ctx->err++; 619 ctx->err = PLIST_ERR_PARSE;
615 break; 620 break;
616 } 621 }
617 622
@@ -631,10 +636,10 @@ static plist_err_t node_from_openstep(parse_ctx ctx, plist_t *plist)
631 plist_t subnode = NULL; 636 plist_t subnode = NULL;
632 const char *p = NULL; 637 const char *p = NULL;
633 ctx->depth++; 638 ctx->depth++;
634 if (ctx->depth > 1000) { 639 if (ctx->depth > PLIST_MAX_NESTING_DEPTH) {
635 PLIST_OSTEP_ERR("Too many levels of recursion (%u) at offset %ld\n", ctx->depth, (long int)(ctx->pos - ctx->start)); 640 PLIST_OSTEP_ERR("Too many levels of recursion (%u) at offset %ld\n", ctx->depth, (long int)(ctx->pos - ctx->start));
636 ctx->err++; 641 ctx->err = PLIST_ERR_MAX_NESTING;
637 return PLIST_ERR_PARSE; 642 return ctx->err;
638 } 643 }
639 while (ctx->pos < ctx->end && !ctx->err) { 644 while (ctx->pos < ctx->end && !ctx->err) {
640 parse_skip_ws(ctx); 645 parse_skip_ws(ctx);
@@ -652,12 +657,12 @@ static plist_err_t node_from_openstep(parse_ctx ctx, plist_t *plist)
652 } 657 }
653 if (ctx->pos >= ctx->end) { 658 if (ctx->pos >= ctx->end) {
654 PLIST_OSTEP_ERR("EOF while parsing dictionary terminator '}' at offset %ld\n", (long int)(ctx->pos - ctx->start)); 659 PLIST_OSTEP_ERR("EOF while parsing dictionary terminator '}' at offset %ld\n", (long int)(ctx->pos - ctx->start));
655 ctx->err++; 660 ctx->err = PLIST_ERR_PARSE;
656 break; 661 break;
657 } 662 }
658 if (*ctx->pos != '}') { 663 if (*ctx->pos != '}') {
659 PLIST_OSTEP_ERR("Missing terminating '}' at offset %ld\n", (long int)(ctx->pos - ctx->start)); 664 PLIST_OSTEP_ERR("Missing terminating '}' at offset %ld\n", (long int)(ctx->pos - ctx->start));
660 ctx->err++; 665 ctx->err = PLIST_ERR_PARSE;
661 goto err_out; 666 goto err_out;
662 } 667 }
663 ctx->pos++; 668 ctx->pos++;
@@ -675,11 +680,11 @@ static plist_err_t node_from_openstep(parse_ctx ctx, plist_t *plist)
675 break; 680 break;
676 } 681 }
677 ctx->err = node_from_openstep(ctx, &tmp); 682 ctx->err = node_from_openstep(ctx, &tmp);
678 if (ctx->err != 0) { 683 if (ctx->err != PLIST_ERR_SUCCESS) {
679 break; 684 break;
680 } 685 }
681 if (!tmp) { 686 if (!tmp) {
682 ctx->err++; 687 ctx->err = PLIST_ERR_PARSE;
683 break; 688 break;
684 } 689 }
685 plist_array_append_item(subnode, tmp); 690 plist_array_append_item(subnode, tmp);
@@ -687,7 +692,7 @@ static plist_err_t node_from_openstep(parse_ctx ctx, plist_t *plist)
687 parse_skip_ws(ctx); 692 parse_skip_ws(ctx);
688 if (ctx->pos >= ctx->end) { 693 if (ctx->pos >= ctx->end) {
689 PLIST_OSTEP_ERR("EOF while parsing array item delimiter ',' at offset %ld\n", (long int)(ctx->pos - ctx->start)); 694 PLIST_OSTEP_ERR("EOF while parsing array item delimiter ',' at offset %ld\n", (long int)(ctx->pos - ctx->start));
690 ctx->err++; 695 ctx->err = PLIST_ERR_PARSE;
691 break; 696 break;
692 } 697 }
693 if (*ctx->pos != ',') { 698 if (*ctx->pos != ',') {
@@ -697,17 +702,17 @@ static plist_err_t node_from_openstep(parse_ctx ctx, plist_t *plist)
697 } 702 }
698 plist_free(tmp); 703 plist_free(tmp);
699 tmp = NULL; 704 tmp = NULL;
700 if (ctx->err) { 705 if (ctx->err != PLIST_ERR_SUCCESS) {
701 goto err_out; 706 goto err_out;
702 } 707 }
703 if (ctx->pos >= ctx->end) { 708 if (ctx->pos >= ctx->end) {
704 PLIST_OSTEP_ERR("EOF while parsing array terminator ')' at offset %ld\n", (long int)(ctx->pos - ctx->start)); 709 PLIST_OSTEP_ERR("EOF while parsing array terminator ')' at offset %ld\n", (long int)(ctx->pos - ctx->start));
705 ctx->err++; 710 ctx->err = PLIST_ERR_PARSE;
706 break; 711 break;
707 } 712 }
708 if (*ctx->pos != ')') { 713 if (*ctx->pos != ')') {
709 PLIST_OSTEP_ERR("Missing terminating ')' at offset %ld\n", (long int)(ctx->pos - ctx->start)); 714 PLIST_OSTEP_ERR("Missing terminating ')' at offset %ld\n", (long int)(ctx->pos - ctx->start));
710 ctx->err++; 715 ctx->err = PLIST_ERR_PARSE;
711 goto err_out; 716 goto err_out;
712 } 717 }
713 ctx->pos++; 718 ctx->pos++;
@@ -722,7 +727,7 @@ static plist_err_t node_from_openstep(parse_ctx ctx, plist_t *plist)
722 parse_skip_ws(ctx); 727 parse_skip_ws(ctx);
723 if (ctx->pos >= ctx->end) { 728 if (ctx->pos >= ctx->end) {
724 PLIST_OSTEP_ERR("EOF while parsing data terminator '>' at offset %ld\n", (long int)(ctx->pos - ctx->start)); 729 PLIST_OSTEP_ERR("EOF while parsing data terminator '>' at offset %ld\n", (long int)(ctx->pos - ctx->start));
725 ctx->err++; 730 ctx->err = PLIST_ERR_PARSE;
726 break; 731 break;
727 } 732 }
728 if (*ctx->pos == '>') { 733 if (*ctx->pos == '>') {
@@ -730,19 +735,19 @@ static plist_err_t node_from_openstep(parse_ctx ctx, plist_t *plist)
730 } 735 }
731 if (!isxdigit(*ctx->pos)) { 736 if (!isxdigit(*ctx->pos)) {
732 PLIST_OSTEP_ERR("Invalid byte group in data at offset %ld\n", (long int)(ctx->pos - ctx->start)); 737 PLIST_OSTEP_ERR("Invalid byte group in data at offset %ld\n", (long int)(ctx->pos - ctx->start));
733 ctx->err++; 738 ctx->err = PLIST_ERR_PARSE;
734 break; 739 break;
735 } 740 }
736 uint8_t b = HEX_DIGIT(*ctx->pos); 741 uint8_t b = HEX_DIGIT(*ctx->pos);
737 ctx->pos++; 742 ctx->pos++;
738 if (ctx->pos >= ctx->end) { 743 if (ctx->pos >= ctx->end) {
739 PLIST_OSTEP_ERR("Unexpected end of data at offset %ld\n", (long int)(ctx->pos - ctx->start)); 744 PLIST_OSTEP_ERR("Unexpected end of data at offset %ld\n", (long int)(ctx->pos - ctx->start));
740 ctx->err++; 745 ctx->err = PLIST_ERR_PARSE;
741 break; 746 break;
742 } 747 }
743 if (!isxdigit(*ctx->pos)) { 748 if (!isxdigit(*ctx->pos)) {
744 PLIST_OSTEP_ERR("Invalid byte group in data at offset %ld\n", (long int)(ctx->pos - ctx->start)); 749 PLIST_OSTEP_ERR("Invalid byte group in data at offset %ld\n", (long int)(ctx->pos - ctx->start));
745 ctx->err++; 750 ctx->err = PLIST_ERR_PARSE;
746 break; 751 break;
747 } 752 }
748 b = (b << 4) + HEX_DIGIT(*ctx->pos); 753 b = (b << 4) + HEX_DIGIT(*ctx->pos);
@@ -758,14 +763,14 @@ static plist_err_t node_from_openstep(parse_ctx ctx, plist_t *plist)
758 byte_array_free(bytes); 763 byte_array_free(bytes);
759 plist_free_data(data); 764 plist_free_data(data);
760 PLIST_OSTEP_ERR("EOF while parsing data terminator '>' at offset %ld\n", (long int)(ctx->pos - ctx->start)); 765 PLIST_OSTEP_ERR("EOF while parsing data terminator '>' at offset %ld\n", (long int)(ctx->pos - ctx->start));
761 ctx->err++; 766 ctx->err = PLIST_ERR_PARSE;
762 goto err_out; 767 goto err_out;
763 } 768 }
764 if (*ctx->pos != '>') { 769 if (*ctx->pos != '>') {
765 byte_array_free(bytes); 770 byte_array_free(bytes);
766 plist_free_data(data); 771 plist_free_data(data);
767 PLIST_OSTEP_ERR("Missing terminating '>' at offset %ld\n", (long int)(ctx->pos - ctx->start)); 772 PLIST_OSTEP_ERR("Missing terminating '>' at offset %ld\n", (long int)(ctx->pos - ctx->start));
768 ctx->err++; 773 ctx->err = PLIST_ERR_PARSE;
769 goto err_out; 774 goto err_out;
770 } 775 }
771 ctx->pos++; 776 ctx->pos++;
@@ -793,13 +798,13 @@ static plist_err_t node_from_openstep(parse_ctx ctx, plist_t *plist)
793 if (ctx->pos >= ctx->end) { 798 if (ctx->pos >= ctx->end) {
794 plist_free_data(data); 799 plist_free_data(data);
795 PLIST_OSTEP_ERR("EOF while parsing quoted string at offset %ld\n", (long int)(ctx->pos - ctx->start)); 800 PLIST_OSTEP_ERR("EOF while parsing quoted string at offset %ld\n", (long int)(ctx->pos - ctx->start));
796 ctx->err++; 801 ctx->err = PLIST_ERR_PARSE;
797 goto err_out; 802 goto err_out;
798 } 803 }
799 if (*ctx->pos != c) { 804 if (*ctx->pos != c) {
800 plist_free_data(data); 805 plist_free_data(data);
801 PLIST_OSTEP_ERR("Missing closing quote (%c) at offset %ld\n", c, (long int)(ctx->pos - ctx->start)); 806 PLIST_OSTEP_ERR("Missing closing quote (%c) at offset %ld\n", c, (long int)(ctx->pos - ctx->start));
802 ctx->err++; 807 ctx->err = PLIST_ERR_PARSE;
803 goto err_out; 808 goto err_out;
804 } 809 }
805 size_t slen = ctx->pos - p; 810 size_t slen = ctx->pos - p;
@@ -900,7 +905,7 @@ static plist_err_t node_from_openstep(parse_ctx ctx, plist_t *plist)
900 } else { 905 } else {
901 plist_free_data(data); 906 plist_free_data(data);
902 PLIST_OSTEP_ERR("Unexpected character when parsing unquoted string at offset %ld\n", (long int)(ctx->pos - ctx->start)); 907 PLIST_OSTEP_ERR("Unexpected character when parsing unquoted string at offset %ld\n", (long int)(ctx->pos - ctx->start));
903 ctx->err++; 908 ctx->err = PLIST_ERR_PARSE;
904 break; 909 break;
905 } 910 }
906 } 911 }
@@ -909,11 +914,11 @@ static plist_err_t node_from_openstep(parse_ctx ctx, plist_t *plist)
909 ctx->depth--; 914 ctx->depth--;
910 915
911err_out: 916err_out:
912 if (ctx->err) { 917 if (ctx->err != PLIST_ERR_SUCCESS) {
913 plist_free(subnode); 918 plist_free(subnode);
914 plist_free(*plist); 919 plist_free(*plist);
915 *plist = NULL; 920 *plist = NULL;
916 return PLIST_ERR_PARSE; 921 return ctx->err;
917 } 922 }
918 return PLIST_ERR_SUCCESS; 923 return PLIST_ERR_SUCCESS;
919} 924}
diff --git a/src/out-default.c b/src/out-default.c
index 09e64c3..fb57bcf 100644
--- a/src/out-default.c
+++ b/src/out-default.c
@@ -318,6 +318,13 @@ static plist_err_t _node_estimate_size(node_t node, uint64_t *size, uint32_t dep
318 return PLIST_ERR_INVALID_ARG; 318 return PLIST_ERR_INVALID_ARG;
319 } 319 }
320 320
321 if (depth > PLIST_MAX_NESTING_DEPTH) {
322#if DEBUG
323 fprintf(stderr, "libplist: ERROR: maximum nesting depth (%u) exceeded\n", (unsigned)PLIST_MAX_NESTING_DEPTH);
324#endif
325 return PLIST_ERR_MAX_NESTING;
326 }
327
321 if (hash_table_lookup(visited, node)) { 328 if (hash_table_lookup(visited, node)) {
322#if DEBUG 329#if DEBUG
323 fprintf(stderr, "libplist: ERROR: circular reference detected\n"); 330 fprintf(stderr, "libplist: ERROR: circular reference detected\n");
diff --git a/src/out-limd.c b/src/out-limd.c
index e281644..35247fb 100644
--- a/src/out-limd.c
+++ b/src/out-limd.c
@@ -286,6 +286,13 @@ static plist_err_t _node_estimate_size(node_t node, uint64_t *size, uint32_t dep
286 return PLIST_ERR_INVALID_ARG; 286 return PLIST_ERR_INVALID_ARG;
287 } 287 }
288 288
289 if (depth > PLIST_MAX_NESTING_DEPTH) {
290#if DEBUG
291 fprintf(stderr, "libplist: ERROR: maximum nesting depth (%u) exceeded\n", (unsigned)PLIST_MAX_NESTING_DEPTH);
292#endif
293 return PLIST_ERR_MAX_NESTING;
294 }
295
289 if (hash_table_lookup(visited, node)) { 296 if (hash_table_lookup(visited, node)) {
290#if DEBUG 297#if DEBUG
291 fprintf(stderr, "libplist: ERROR: circular reference detected\n"); 298 fprintf(stderr, "libplist: ERROR: circular reference detected\n");
diff --git a/src/out-plutil.c b/src/out-plutil.c
index 5354aa3..bf9e72e 100644
--- a/src/out-plutil.c
+++ b/src/out-plutil.c
@@ -312,6 +312,13 @@ static plist_err_t _node_estimate_size(node_t node, uint64_t *size, uint32_t dep
312 return PLIST_ERR_INVALID_ARG; 312 return PLIST_ERR_INVALID_ARG;
313 } 313 }
314 314
315 if (depth > PLIST_MAX_NESTING_DEPTH) {
316#if DEBUG
317 fprintf(stderr, "libplist: ERROR: maximum nesting depth (%u) exceeded\n", (unsigned)PLIST_MAX_NESTING_DEPTH);
318#endif
319 return PLIST_ERR_MAX_NESTING;
320 }
321
315 if (hash_table_lookup(visited, node)) { 322 if (hash_table_lookup(visited, node)) {
316#if DEBUG 323#if DEBUG
317 fprintf(stderr, "libplist: ERROR: circular reference detected\n"); 324 fprintf(stderr, "libplist: ERROR: circular reference detected\n");
diff --git a/src/plist.h b/src/plist.h
index 3043fb7..e310bcc 100644
--- a/src/plist.h
+++ b/src/plist.h
@@ -49,6 +49,10 @@
49 #endif 49 #endif
50#endif 50#endif
51 51
52#ifndef PLIST_MAX_NESTING_DEPTH
53#define PLIST_MAX_NESTING_DEPTH 512
54#endif
55
52#include "plist/plist.h" 56#include "plist/plist.h"
53 57
54struct plist_data_s 58struct plist_data_s
diff --git a/src/xplist.c b/src/xplist.c
index c25c6b9..9870104 100644
--- a/src/xplist.c
+++ b/src/xplist.c
@@ -452,6 +452,11 @@ static plist_err_t _node_estimate_size(node_t node, uint64_t *size, uint32_t dep
452 return PLIST_ERR_INVALID_ARG; 452 return PLIST_ERR_INVALID_ARG;
453 } 453 }
454 454
455 if (depth > PLIST_MAX_NESTING_DEPTH) {
456 PLIST_XML_WRITE_ERR("maximum nesting depth (%u) exceeded\n", (unsigned)PLIST_MAX_NESTING_DEPTH);
457 return PLIST_ERR_MAX_NESTING;
458 }
459
455 if (hash_table_lookup(visited, node)) { 460 if (hash_table_lookup(visited, node)) {
456 PLIST_XML_WRITE_ERR("circular reference detected\n"); 461 PLIST_XML_WRITE_ERR("circular reference detected\n");
457 return PLIST_ERR_CIRCULAR_REF; 462 return PLIST_ERR_CIRCULAR_REF;
@@ -596,7 +601,7 @@ plist_err_t plist_to_xml(plist_t plist, char **plist_xml, uint32_t * length)
596struct _parse_ctx { 601struct _parse_ctx {
597 const char *pos; 602 const char *pos;
598 const char *end; 603 const char *end;
599 int err; 604 plist_err_t err;
600}; 605};
601typedef struct _parse_ctx* parse_ctx; 606typedef struct _parse_ctx* parse_ctx;
602 607
@@ -720,21 +725,21 @@ static text_part_t* get_text_parts(parse_ctx ctx, const char* tag, size_t tag_le
720 find_char(ctx, '<', 0); 725 find_char(ctx, '<', 0);
721 if (ctx->pos >= ctx->end || *ctx->pos != '<') { 726 if (ctx->pos >= ctx->end || *ctx->pos != '<') {
722 PLIST_XML_ERR("EOF while looking for closing tag\n"); 727 PLIST_XML_ERR("EOF while looking for closing tag\n");
723 ctx->err++; 728 ctx->err = PLIST_ERR_PARSE;
724 return NULL; 729 return NULL;
725 } 730 }
726 q = ctx->pos; 731 q = ctx->pos;
727 ctx->pos++; 732 ctx->pos++;
728 if (ctx->pos >= ctx->end) { 733 if (ctx->pos >= ctx->end) {
729 PLIST_XML_ERR("EOF while parsing '%s'\n", p); 734 PLIST_XML_ERR("EOF while parsing '%s'\n", p);
730 ctx->err++; 735 ctx->err = PLIST_ERR_PARSE;
731 return NULL; 736 return NULL;
732 } 737 }
733 if (*ctx->pos == '!') { 738 if (*ctx->pos == '!') {
734 ctx->pos++; 739 ctx->pos++;
735 if (ctx->pos >= ctx->end-1) { 740 if (ctx->pos >= ctx->end-1) {
736 PLIST_XML_ERR("EOF while parsing <! special tag\n"); 741 PLIST_XML_ERR("EOF while parsing <! special tag\n");
737 ctx->err++; 742 ctx->err = PLIST_ERR_PARSE;
738 return NULL; 743 return NULL;
739 } 744 }
740 if (*ctx->pos == '-' && *(ctx->pos+1) == '-') { 745 if (*ctx->pos == '-' && *(ctx->pos+1) == '-') {
@@ -747,7 +752,7 @@ static text_part_t* get_text_parts(parse_ctx ctx, const char* tag, size_t tag_le
747 find_str(ctx, "-->", 3, 0); 752 find_str(ctx, "-->", 3, 0);
748 if (ctx->pos > ctx->end-3 || strncmp(ctx->pos, "-->", 3) != 0) { 753 if (ctx->pos > ctx->end-3 || strncmp(ctx->pos, "-->", 3) != 0) {
749 PLIST_XML_ERR("EOF while looking for end of comment\n"); 754 PLIST_XML_ERR("EOF while looking for end of comment\n");
750 ctx->err++; 755 ctx->err = PLIST_ERR_PARSE;
751 return NULL; 756 return NULL;
752 } 757 }
753 ctx->pos += 3; 758 ctx->pos += 3;
@@ -755,7 +760,7 @@ static text_part_t* get_text_parts(parse_ctx ctx, const char* tag, size_t tag_le
755 ctx->pos++; 760 ctx->pos++;
756 if (ctx->pos >= ctx->end - 8) { 761 if (ctx->pos >= ctx->end - 8) {
757 PLIST_XML_ERR("EOF while parsing <[ tag\n"); 762 PLIST_XML_ERR("EOF while parsing <[ tag\n");
758 ctx->err++; 763 ctx->err = PLIST_ERR_PARSE;
759 return NULL; 764 return NULL;
760 } 765 }
761 if (strncmp(ctx->pos, "CDATA[", 6) == 0) { 766 if (strncmp(ctx->pos, "CDATA[", 6) == 0) {
@@ -771,7 +776,7 @@ static text_part_t* get_text_parts(parse_ctx ctx, const char* tag, size_t tag_le
771 find_str(ctx, "]]>", 3, 0); 776 find_str(ctx, "]]>", 3, 0);
772 if (ctx->pos > ctx->end-3 || strncmp(ctx->pos, "]]>", 3) != 0) { 777 if (ctx->pos > ctx->end-3 || strncmp(ctx->pos, "]]>", 3) != 0) {
773 PLIST_XML_ERR("EOF while looking for end of CDATA block\n"); 778 PLIST_XML_ERR("EOF while looking for end of CDATA block\n");
774 ctx->err++; 779 ctx->err = PLIST_ERR_PARSE;
775 return NULL; 780 return NULL;
776 } 781 }
777 q = ctx->pos; 782 q = ctx->pos;
@@ -785,14 +790,14 @@ static text_part_t* get_text_parts(parse_ctx ctx, const char* tag, size_t tag_le
785 p = ctx->pos; 790 p = ctx->pos;
786 find_next(ctx, " \r\n\t>", 5, 1); 791 find_next(ctx, " \r\n\t>", 5, 1);
787 PLIST_XML_ERR("Invalid special tag <[%.*s> encountered inside <%s> tag\n", (int)(ctx->pos - p), p, tag); 792 PLIST_XML_ERR("Invalid special tag <[%.*s> encountered inside <%s> tag\n", (int)(ctx->pos - p), p, tag);
788 ctx->err++; 793 ctx->err = PLIST_ERR_PARSE;
789 return NULL; 794 return NULL;
790 } 795 }
791 } else { 796 } else {
792 p = ctx->pos; 797 p = ctx->pos;
793 find_next(ctx, " \r\n\t>", 5, 1); 798 find_next(ctx, " \r\n\t>", 5, 1);
794 PLIST_XML_ERR("Invalid special tag <!%.*s> encountered inside <%s> tag\n", (int)(ctx->pos - p), p, tag); 799 PLIST_XML_ERR("Invalid special tag <!%.*s> encountered inside <%s> tag\n", (int)(ctx->pos - p), p, tag);
795 ctx->err++; 800 ctx->err = PLIST_ERR_PARSE;
796 return NULL; 801 return NULL;
797 } 802 }
798 } else if (*ctx->pos == '/') { 803 } else if (*ctx->pos == '/') {
@@ -801,25 +806,25 @@ static text_part_t* get_text_parts(parse_ctx ctx, const char* tag, size_t tag_le
801 p = ctx->pos; 806 p = ctx->pos;
802 find_next(ctx, " \r\n\t>", 5, 1); 807 find_next(ctx, " \r\n\t>", 5, 1);
803 PLIST_XML_ERR("Invalid tag <%.*s> encountered inside <%s> tag\n", (int)(ctx->pos - p), p, tag); 808 PLIST_XML_ERR("Invalid tag <%.*s> encountered inside <%s> tag\n", (int)(ctx->pos - p), p, tag);
804 ctx->err++; 809 ctx->err = PLIST_ERR_PARSE;
805 return NULL; 810 return NULL;
806 } 811 }
807 } while (1); 812 } while (1);
808 ctx->pos++; 813 ctx->pos++;
809 if (ctx->pos >= ctx->end-tag_len || strncmp(ctx->pos, tag, tag_len) != 0) { 814 if (ctx->pos >= ctx->end-tag_len || strncmp(ctx->pos, tag, tag_len) != 0) {
810 PLIST_XML_ERR("EOF or end tag mismatch\n"); 815 PLIST_XML_ERR("EOF or end tag mismatch\n");
811 ctx->err++; 816 ctx->err = PLIST_ERR_PARSE;
812 return NULL; 817 return NULL;
813 } 818 }
814 ctx->pos+=tag_len; 819 ctx->pos+=tag_len;
815 parse_skip_ws(ctx); 820 parse_skip_ws(ctx);
816 if (ctx->pos >= ctx->end) { 821 if (ctx->pos >= ctx->end) {
817 PLIST_XML_ERR("EOF while parsing closing tag\n"); 822 PLIST_XML_ERR("EOF while parsing closing tag\n");
818 ctx->err++; 823 ctx->err = PLIST_ERR_PARSE;
819 return NULL; 824 return NULL;
820 } else if (*ctx->pos != '>') { 825 } else if (*ctx->pos != '>') {
821 PLIST_XML_ERR("Invalid closing tag; expected '>', found '%c'\n", *ctx->pos); 826 PLIST_XML_ERR("Invalid closing tag; expected '>', found '%c'\n", *ctx->pos);
822 ctx->err++; 827 ctx->err = PLIST_ERR_PARSE;
823 return NULL; 828 return NULL;
824 } 829 }
825 ctx->pos++; 830 ctx->pos++;
@@ -995,6 +1000,7 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
995 void *prev; 1000 void *prev;
996 }; 1001 };
997 struct node_path_item* node_path = NULL; 1002 struct node_path_item* node_path = NULL;
1003 int depth = 0;
998 1004
999 while (ctx->pos < ctx->end && !ctx->err) { 1005 while (ctx->pos < ctx->end && !ctx->err) {
1000 parse_skip_ws(ctx); 1006 parse_skip_ws(ctx);
@@ -1005,13 +1011,13 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
1005 p = ctx->pos; 1011 p = ctx->pos;
1006 find_next(ctx, " \t\r\n", 4, 0); 1012 find_next(ctx, " \t\r\n", 4, 0);
1007 PLIST_XML_ERR("Expected: opening tag, found: %.*s\n", (int)(ctx->pos - p), p); 1013 PLIST_XML_ERR("Expected: opening tag, found: %.*s\n", (int)(ctx->pos - p), p);
1008 ctx->err++; 1014 ctx->err = PLIST_ERR_PARSE;
1009 goto err_out; 1015 goto err_out;
1010 } 1016 }
1011 ctx->pos++; 1017 ctx->pos++;
1012 if (ctx->pos >= ctx->end) { 1018 if (ctx->pos >= ctx->end) {
1013 PLIST_XML_ERR("EOF while parsing tag\n"); 1019 PLIST_XML_ERR("EOF while parsing tag\n");
1014 ctx->err++; 1020 ctx->err = PLIST_ERR_PARSE;
1015 goto err_out; 1021 goto err_out;
1016 } 1022 }
1017 1023
@@ -1019,12 +1025,12 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
1019 find_str(ctx, "?>", 2, 1); 1025 find_str(ctx, "?>", 2, 1);
1020 if (ctx->pos > ctx->end-2) { 1026 if (ctx->pos > ctx->end-2) {
1021 PLIST_XML_ERR("EOF while looking for <? tag closing marker\n"); 1027 PLIST_XML_ERR("EOF while looking for <? tag closing marker\n");
1022 ctx->err++; 1028 ctx->err = PLIST_ERR_PARSE;
1023 goto err_out; 1029 goto err_out;
1024 } 1030 }
1025 if (strncmp(ctx->pos, "?>", 2) != 0) { 1031 if (strncmp(ctx->pos, "?>", 2) != 0) {
1026 PLIST_XML_ERR("Couldn't find <? tag closing marker\n"); 1032 PLIST_XML_ERR("Couldn't find <? tag closing marker\n");
1027 ctx->err++; 1033 ctx->err = PLIST_ERR_PARSE;
1028 goto err_out; 1034 goto err_out;
1029 } 1035 }
1030 ctx->pos += 2; 1036 ctx->pos += 2;
@@ -1036,7 +1042,7 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
1036 find_str(ctx,"-->", 3, 0); 1042 find_str(ctx,"-->", 3, 0);
1037 if (ctx->pos > ctx->end-3 || strncmp(ctx->pos, "-->", 3) != 0) { 1043 if (ctx->pos > ctx->end-3 || strncmp(ctx->pos, "-->", 3) != 0) {
1038 PLIST_XML_ERR("Couldn't find end of comment\n"); 1044 PLIST_XML_ERR("Couldn't find end of comment\n");
1039 ctx->err++; 1045 ctx->err = PLIST_ERR_PARSE;
1040 goto err_out; 1046 goto err_out;
1041 } 1047 }
1042 ctx->pos+=3; 1048 ctx->pos+=3;
@@ -1047,7 +1053,7 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
1047 find_next(ctx, " \t\r\n[>", 6, 1); 1053 find_next(ctx, " \t\r\n[>", 6, 1);
1048 if (ctx->pos >= ctx->end) { 1054 if (ctx->pos >= ctx->end) {
1049 PLIST_XML_ERR("EOF while parsing !DOCTYPE\n"); 1055 PLIST_XML_ERR("EOF while parsing !DOCTYPE\n");
1050 ctx->err++; 1056 ctx->err = PLIST_ERR_PARSE;
1051 goto err_out; 1057 goto err_out;
1052 } 1058 }
1053 if (*ctx->pos == '[') { 1059 if (*ctx->pos == '[') {
@@ -1065,7 +1071,7 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
1065 find_str(ctx, "]>", 2, 1); 1071 find_str(ctx, "]>", 2, 1);
1066 if (ctx->pos > ctx->end-2 || strncmp(ctx->pos, "]>", 2) != 0) { 1072 if (ctx->pos > ctx->end-2 || strncmp(ctx->pos, "]>", 2) != 0) {
1067 PLIST_XML_ERR("Couldn't find end of DOCTYPE\n"); 1073 PLIST_XML_ERR("Couldn't find end of DOCTYPE\n");
1068 ctx->err++; 1074 ctx->err = PLIST_ERR_PARSE;
1069 goto err_out; 1075 goto err_out;
1070 } 1076 }
1071 ctx->pos += 2; 1077 ctx->pos += 2;
@@ -1074,7 +1080,7 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
1074 p = ctx->pos; 1080 p = ctx->pos;
1075 find_next(ctx, " \r\n\t>", 5, 1); 1081 find_next(ctx, " \r\n\t>", 5, 1);
1076 PLIST_XML_ERR("Invalid or incomplete special tag <%.*s> encountered\n", (int)(ctx->pos - p), p); 1082 PLIST_XML_ERR("Invalid or incomplete special tag <%.*s> encountered\n", (int)(ctx->pos - p), p);
1077 ctx->err++; 1083 ctx->err = PLIST_ERR_PARSE;
1078 goto err_out; 1084 goto err_out;
1079 } 1085 }
1080 continue; 1086 continue;
@@ -1085,7 +1091,7 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
1085 find_next(ctx," \r\n\t<>", 6, 0); 1091 find_next(ctx," \r\n\t<>", 6, 0);
1086 if (ctx->pos >= ctx->end) { 1092 if (ctx->pos >= ctx->end) {
1087 PLIST_XML_ERR("Unexpected EOF while parsing XML\n"); 1093 PLIST_XML_ERR("Unexpected EOF while parsing XML\n");
1088 ctx->err++; 1094 ctx->err = PLIST_ERR_PARSE;
1089 goto err_out; 1095 goto err_out;
1090 } 1096 }
1091 size_t taglen = ctx->pos - p; 1097 size_t taglen = ctx->pos - p;
@@ -1097,12 +1103,12 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
1097 } 1103 }
1098 if (ctx->pos >= ctx->end) { 1104 if (ctx->pos >= ctx->end) {
1099 PLIST_XML_ERR("Unexpected EOF while parsing XML\n"); 1105 PLIST_XML_ERR("Unexpected EOF while parsing XML\n");
1100 ctx->err++; 1106 ctx->err = PLIST_ERR_PARSE;
1101 goto err_out; 1107 goto err_out;
1102 } 1108 }
1103 if (*ctx->pos != '>') { 1109 if (*ctx->pos != '>') {
1104 PLIST_XML_ERR("Missing '>' for tag <%s\n", tag); 1110 PLIST_XML_ERR("Missing '>' for tag <%s\n", tag);
1105 ctx->err++; 1111 ctx->err = PLIST_ERR_PARSE;
1106 goto err_out; 1112 goto err_out;
1107 } 1113 }
1108 if (*(ctx->pos-1) == '/') { 1114 if (*(ctx->pos-1) == '/') {
@@ -1123,14 +1129,14 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
1123 } 1129 }
1124 if (is_empty) { 1130 if (is_empty) {
1125 PLIST_XML_ERR("Empty plist tag\n"); 1131 PLIST_XML_ERR("Empty plist tag\n");
1126 ctx->err++; 1132 ctx->err = PLIST_ERR_PARSE;
1127 goto err_out; 1133 goto err_out;
1128 } 1134 }
1129 1135
1130 struct node_path_item *path_item = (struct node_path_item*)malloc(sizeof(struct node_path_item)); 1136 struct node_path_item *path_item = (struct node_path_item*)malloc(sizeof(struct node_path_item));
1131 if (!path_item) { 1137 if (!path_item) {
1132 PLIST_XML_ERR("out of memory when allocating node path item\n"); 1138 PLIST_XML_ERR("out of memory when allocating node path item\n");
1133 ctx->err++; 1139 ctx->err = PLIST_ERR_PARSE;
1134 goto err_out; 1140 goto err_out;
1135 } 1141 }
1136 path_item->type = "plist"; 1142 path_item->type = "plist";
@@ -1141,17 +1147,17 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
1141 } else if (!strcmp(tag, "/plist")) { 1147 } else if (!strcmp(tag, "/plist")) {
1142 if (!has_content) { 1148 if (!has_content) {
1143 PLIST_XML_ERR("encountered empty plist tag\n"); 1149 PLIST_XML_ERR("encountered empty plist tag\n");
1144 ctx->err++; 1150 ctx->err = PLIST_ERR_PARSE;
1145 goto err_out; 1151 goto err_out;
1146 } 1152 }
1147 if (!node_path) { 1153 if (!node_path) {
1148 PLIST_XML_ERR("node path is empty while trying to match closing tag with opening tag\n"); 1154 PLIST_XML_ERR("node path is empty while trying to match closing tag with opening tag\n");
1149 ctx->err++; 1155 ctx->err = PLIST_ERR_PARSE;
1150 goto err_out; 1156 goto err_out;
1151 } 1157 }
1152 if (strcmp(node_path->type, tag+1) != 0) { 1158 if (strcmp(node_path->type, tag+1) != 0) {
1153 PLIST_XML_ERR("mismatching closing tag <%s> found for opening tag <%s>\n", tag, node_path->type); 1159 PLIST_XML_ERR("mismatching closing tag <%s> found for opening tag <%s>\n", tag, node_path->type);
1154 ctx->err++; 1160 ctx->err = PLIST_ERR_PARSE;
1155 goto err_out; 1161 goto err_out;
1156 } 1162 }
1157 struct node_path_item *path_item = node_path; 1163 struct node_path_item *path_item = node_path;
@@ -1179,7 +1185,7 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
1179 if (!tp) { 1185 if (!tp) {
1180 PLIST_XML_ERR("Could not parse text content for '%s' node\n", tag); 1186 PLIST_XML_ERR("Could not parse text content for '%s' node\n", tag);
1181 text_parts_free((text_part_t*)first_part.next); 1187 text_parts_free((text_part_t*)first_part.next);
1182 ctx->err++; 1188 ctx->err = PLIST_ERR_PARSE;
1183 goto err_out; 1189 goto err_out;
1184 } 1190 }
1185 if (tp->begin) { 1191 if (tp->begin) {
@@ -1188,7 +1194,7 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
1188 if (!str_content) { 1194 if (!str_content) {
1189 PLIST_XML_ERR("Could not get text content for '%s' node\n", tag); 1195 PLIST_XML_ERR("Could not get text content for '%s' node\n", tag);
1190 text_parts_free((text_part_t*)first_part.next); 1196 text_parts_free((text_part_t*)first_part.next);
1191 ctx->err++; 1197 ctx->err = PLIST_ERR_PARSE;
1192 goto err_out; 1198 goto err_out;
1193 } 1199 }
1194 char *str = str_content; 1200 char *str = str_content;
@@ -1230,7 +1236,7 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
1230 if (!tp) { 1236 if (!tp) {
1231 PLIST_XML_ERR("Could not parse text content for '%s' node\n", tag); 1237 PLIST_XML_ERR("Could not parse text content for '%s' node\n", tag);
1232 text_parts_free((text_part_t*)first_part.next); 1238 text_parts_free((text_part_t*)first_part.next);
1233 ctx->err++; 1239 ctx->err = PLIST_ERR_PARSE;
1234 goto err_out; 1240 goto err_out;
1235 } 1241 }
1236 if (tp->begin) { 1242 if (tp->begin) {
@@ -1239,7 +1245,7 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
1239 if (!str_content) { 1245 if (!str_content) {
1240 PLIST_XML_ERR("Could not get text content for '%s' node\n", tag); 1246 PLIST_XML_ERR("Could not get text content for '%s' node\n", tag);
1241 text_parts_free((text_part_t*)first_part.next); 1247 text_parts_free((text_part_t*)first_part.next);
1242 ctx->err++; 1248 ctx->err = PLIST_ERR_PARSE;
1243 goto err_out; 1249 goto err_out;
1244 } 1250 }
1245 data->realval = atof(str_content); 1251 data->realval = atof(str_content);
@@ -1274,14 +1280,14 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
1274 if (!tp) { 1280 if (!tp) {
1275 PLIST_XML_ERR("Could not parse text content for '%s' node\n", tag); 1281 PLIST_XML_ERR("Could not parse text content for '%s' node\n", tag);
1276 text_parts_free((text_part_t*)first_part.next); 1282 text_parts_free((text_part_t*)first_part.next);
1277 ctx->err++; 1283 ctx->err = PLIST_ERR_PARSE;
1278 goto err_out; 1284 goto err_out;
1279 } 1285 }
1280 str = text_parts_get_content(tp, 1, &length, NULL); 1286 str = text_parts_get_content(tp, 1, &length, NULL);
1281 text_parts_free((text_part_t*)first_part.next); 1287 text_parts_free((text_part_t*)first_part.next);
1282 if (!str) { 1288 if (!str) {
1283 PLIST_XML_ERR("Could not get text content for '%s' node\n", tag); 1289 PLIST_XML_ERR("Could not get text content for '%s' node\n", tag);
1284 ctx->err++; 1290 ctx->err = PLIST_ERR_PARSE;
1285 goto err_out; 1291 goto err_out;
1286 } 1292 }
1287 if (!strcmp(tag, "key") && !keyname && parent && (plist_get_node_type(parent) == PLIST_DICT)) { 1293 if (!strcmp(tag, "key") && !keyname && parent && (plist_get_node_type(parent) == PLIST_DICT)) {
@@ -1315,7 +1321,7 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
1315 if (!tp) { 1321 if (!tp) {
1316 PLIST_XML_ERR("Could not parse text content for '%s' node\n", tag); 1322 PLIST_XML_ERR("Could not parse text content for '%s' node\n", tag);
1317 text_parts_free((text_part_t*)first_part.next); 1323 text_parts_free((text_part_t*)first_part.next);
1318 ctx->err++; 1324 ctx->err = PLIST_ERR_PARSE;
1319 goto err_out; 1325 goto err_out;
1320 } 1326 }
1321 if (tp->begin) { 1327 if (tp->begin) {
@@ -1324,7 +1330,7 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
1324 if (!str_content) { 1330 if (!str_content) {
1325 PLIST_XML_ERR("Could not get text content for '%s' node\n", tag); 1331 PLIST_XML_ERR("Could not get text content for '%s' node\n", tag);
1326 text_parts_free((text_part_t*)first_part.next); 1332 text_parts_free((text_part_t*)first_part.next);
1327 ctx->err++; 1333 ctx->err = PLIST_ERR_PARSE;
1328 goto err_out; 1334 goto err_out;
1329 } 1335 }
1330 size_t size = tp->length; 1336 size_t size = tp->length;
@@ -1347,7 +1353,7 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
1347 if (!tp) { 1353 if (!tp) {
1348 PLIST_XML_ERR("Could not parse text content for '%s' node\n", tag); 1354 PLIST_XML_ERR("Could not parse text content for '%s' node\n", tag);
1349 text_parts_free((text_part_t*)first_part.next); 1355 text_parts_free((text_part_t*)first_part.next);
1350 ctx->err++; 1356 ctx->err = PLIST_ERR_PARSE;
1351 goto err_out; 1357 goto err_out;
1352 } 1358 }
1353 Time64_T timev = 0; 1359 Time64_T timev = 0;
@@ -1358,7 +1364,7 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
1358 if (!str_content) { 1364 if (!str_content) {
1359 PLIST_XML_ERR("Could not get text content for '%s' node\n", tag); 1365 PLIST_XML_ERR("Could not get text content for '%s' node\n", tag);
1360 text_parts_free((text_part_t*)first_part.next); 1366 text_parts_free((text_part_t*)first_part.next);
1361 ctx->err++; 1367 ctx->err = PLIST_ERR_PARSE;
1362 goto err_out; 1368 goto err_out;
1363 } 1369 }
1364 1370
@@ -1387,7 +1393,7 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
1387 } else { 1393 } else {
1388 PLIST_XML_ERR("Unexpected tag <%s%s> encountered\n", tag, (is_empty) ? "/" : ""); 1394 PLIST_XML_ERR("Unexpected tag <%s%s> encountered\n", tag, (is_empty) ? "/" : "");
1389 ctx->pos = ctx->end; 1395 ctx->pos = ctx->end;
1390 ctx->err++; 1396 ctx->err = PLIST_ERR_PARSE;
1391 goto err_out; 1397 goto err_out;
1392 } 1398 }
1393 if (subnode && !closing_tag) { 1399 if (subnode && !closing_tag) {
@@ -1405,7 +1411,7 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
1405 case PLIST_DICT: 1411 case PLIST_DICT:
1406 if (!keyname) { 1412 if (!keyname) {
1407 PLIST_XML_ERR("missing key name while adding dict item\n"); 1413 PLIST_XML_ERR("missing key name while adding dict item\n");
1408 ctx->err++; 1414 ctx->err = PLIST_ERR_PARSE;
1409 goto err_out; 1415 goto err_out;
1410 } 1416 }
1411 plist_dict_set_item(parent, keyname, subnode); 1417 plist_dict_set_item(parent, keyname, subnode);
@@ -1416,35 +1422,42 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
1416 default: 1422 default:
1417 /* should not happen */ 1423 /* should not happen */
1418 PLIST_XML_ERR("parent is not a structured node\n"); 1424 PLIST_XML_ERR("parent is not a structured node\n");
1419 ctx->err++; 1425 ctx->err = PLIST_ERR_PARSE;
1420 goto err_out; 1426 goto err_out;
1421 } 1427 }
1422 } 1428 }
1423 if (!is_empty && (data->type == PLIST_DICT || data->type == PLIST_ARRAY)) { 1429 if (!is_empty && (data->type == PLIST_DICT || data->type == PLIST_ARRAY)) {
1430 if (depth >= PLIST_MAX_NESTING_DEPTH) {
1431 PLIST_XML_ERR("maximum nesting depth (%u) exceeded\n", (unsigned)PLIST_MAX_NESTING_DEPTH);
1432 ctx->err = PLIST_ERR_MAX_NESTING;
1433 goto err_out;
1434 }
1424 struct node_path_item *path_item = (struct node_path_item*)malloc(sizeof(struct node_path_item)); 1435 struct node_path_item *path_item = (struct node_path_item*)malloc(sizeof(struct node_path_item));
1425 if (!path_item) { 1436 if (!path_item) {
1426 PLIST_XML_ERR("out of memory when allocating node path item\n"); 1437 PLIST_XML_ERR("out of memory when allocating node path item\n");
1427 ctx->err++; 1438 ctx->err = PLIST_ERR_PARSE;
1428 goto err_out; 1439 goto err_out;
1429 } 1440 }
1430 path_item->type = (data->type == PLIST_DICT) ? XPLIST_DICT : XPLIST_ARRAY; 1441 path_item->type = (data->type == PLIST_DICT) ? XPLIST_DICT : XPLIST_ARRAY;
1431 path_item->prev = node_path; 1442 path_item->prev = node_path;
1432 node_path = path_item; 1443 node_path = path_item;
1433 1444
1445 depth++;
1434 parent = subnode; 1446 parent = subnode;
1435 } 1447 }
1436 subnode = NULL; 1448 subnode = NULL;
1437 } else if (closing_tag) { 1449 } else if (closing_tag) {
1438 if (!node_path) { 1450 if (!node_path) {
1439 PLIST_XML_ERR("node path is empty while trying to match closing tag with opening tag\n"); 1451 PLIST_XML_ERR("node path is empty while trying to match closing tag with opening tag\n");
1440 ctx->err++; 1452 ctx->err = PLIST_ERR_PARSE;
1441 goto err_out; 1453 goto err_out;
1442 } 1454 }
1443 if (strcmp(node_path->type, tag+1) != 0) { 1455 if (strcmp(node_path->type, tag+1) != 0) {
1444 PLIST_XML_ERR("unexpected %s found (for opening %s)\n", tag, node_path->type); 1456 PLIST_XML_ERR("unexpected %s found (for opening %s)\n", tag, node_path->type);
1445 ctx->err++; 1457 ctx->err = PLIST_ERR_PARSE;
1446 goto err_out; 1458 goto err_out;
1447 } 1459 }
1460 if (depth > 0) depth--;
1448 struct node_path_item *path_item = node_path; 1461 struct node_path_item *path_item = node_path;
1449 node_path = (struct node_path_item*)node_path->prev; 1462 node_path = (struct node_path_item*)node_path->prev;
1450 free(path_item); 1463 free(path_item);
@@ -1466,7 +1479,7 @@ static plist_err_t node_from_xml(parse_ctx ctx, plist_t *plist)
1466 1479
1467 if (node_path) { 1480 if (node_path) {
1468 PLIST_XML_ERR("EOF encountered while </%s> was expected\n", node_path->type); 1481 PLIST_XML_ERR("EOF encountered while </%s> was expected\n", node_path->type);
1469 ctx->err++; 1482 ctx->err = PLIST_ERR_PARSE;
1470 } 1483 }
1471 1484
1472err_out: 1485err_out:
@@ -1481,10 +1494,10 @@ err_out:
1481 free(path_item); 1494 free(path_item);
1482 } 1495 }
1483 1496
1484 if (ctx->err) { 1497 if (ctx->err != PLIST_ERR_SUCCESS) {
1485 plist_free(*plist); 1498 plist_free(*plist);
1486 *plist = NULL; 1499 *plist = NULL;
1487 return PLIST_ERR_PARSE; 1500 return ctx->err;
1488 } 1501 }
1489 1502
1490 /* check if we have a UID "dict" so we can replace it with a proper UID node */ 1503 /* check if we have a UID "dict" so we can replace it with a proper UID node */
@@ -1511,7 +1524,7 @@ plist_err_t plist_from_xml(const char *plist_xml, uint32_t length, plist_t * pli
1511 return PLIST_ERR_INVALID_ARG; 1524 return PLIST_ERR_INVALID_ARG;
1512 } 1525 }
1513 1526
1514 struct _parse_ctx ctx = { plist_xml, plist_xml + length, 0 }; 1527 struct _parse_ctx ctx = { plist_xml, plist_xml + length, PLIST_ERR_SUCCESS };
1515 1528
1516 return node_from_xml(&ctx, plist); 1529 return node_from_xml(&ctx, plist);
1517} 1530}