diff options
| author | 2026-01-17 15:18:06 +0100 | |
|---|---|---|
| committer | 2026-01-17 16:04:00 +0100 | |
| commit | e45099fb21b679aa0cdb0db394587bb5ba675b0c (patch) | |
| tree | b1a2c1dd34877d83a04d6d6fab804fb2e5a65f2d /src/xplist.c | |
| parent | 26dd27c435a0d110c924e1fef34ad0f6ae60e251 (diff) | |
| download | libplist-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.
Diffstat (limited to 'src/xplist.c')
| -rw-r--r-- | src/xplist.c | 111 |
1 files changed, 62 insertions, 49 deletions
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) | |||
| 596 | struct _parse_ctx { | 601 | struct _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 | }; |
| 601 | typedef struct _parse_ctx* parse_ctx; | 606 | typedef 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 | ||
| 1472 | err_out: | 1485 | err_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 | } |
