| 2892 | } |
| 2893 | |
| 2894 | static xml_parse_result parse(char_t* buffer, size_t length, xml_document_struct* xmldoc, xml_node_struct* root, unsigned int optmsk) |
| 2895 | { |
| 2896 | // allocator object is a part of document object |
| 2897 | xml_allocator& alloc_ = *static_cast<xml_allocator*>(xmldoc); |
| 2898 | |
| 2899 | // early-out for empty documents |
| 2900 | if (length == 0) |
| 2901 | return make_parse_result(PUGI__OPTSET(parse_fragment) ? status_ok : status_no_document_element); |
| 2902 | |
| 2903 | // get last child of the root before parsing |
| 2904 | xml_node_struct* last_root_child = root->first_child ? root->first_child->prev_sibling_c : 0; |
| 2905 | |
| 2906 | // create parser on stack |
| 2907 | xml_parser parser(alloc_); |
| 2908 | |
| 2909 | // save last character and make buffer zero-terminated (speeds up parsing) |
| 2910 | char_t endch = buffer[length - 1]; |
| 2911 | buffer[length - 1] = 0; |
| 2912 | |
| 2913 | // skip BOM to make sure it does not end up as part of parse output |
| 2914 | char_t* buffer_data = parse_skip_bom(buffer); |
| 2915 | |
| 2916 | // perform actual parsing |
| 2917 | parser.parse_tree(buffer_data, root, optmsk, endch); |
| 2918 | |
| 2919 | // update allocator state |
| 2920 | alloc_ = parser.alloc; |
| 2921 | |
| 2922 | xml_parse_result result = make_parse_result(parser.error_status, parser.error_offset ? parser.error_offset - buffer : 0); |
| 2923 | assert(result.offset >= 0 && static_cast<size_t>(result.offset) <= length); |
| 2924 | |
| 2925 | if (result) |
| 2926 | { |
| 2927 | // since we removed last character, we have to handle the only possible false positive (stray <) |
| 2928 | if (endch == '<') |
| 2929 | return make_parse_result(status_unrecognized_tag, length - 1); |
| 2930 | |
| 2931 | // check if there are any element nodes parsed |
| 2932 | xml_node_struct* first_root_child_parsed = last_root_child ? last_root_child->next_sibling : root->first_child; |
| 2933 | |
| 2934 | if (!PUGI__OPTSET(parse_fragment) && !has_element_node_siblings(first_root_child_parsed)) |
| 2935 | return make_parse_result(status_no_document_element, length - 1); |
| 2936 | } |
| 2937 | else |
| 2938 | { |
| 2939 | // roll back offset if it occurs on a null terminator in the source buffer |
| 2940 | if (result.offset > 0 && static_cast<size_t>(result.offset) == length - 1 && endch == 0) |
| 2941 | result.offset--; |
| 2942 | } |
| 2943 | |
| 2944 | return result; |
| 2945 | } |
| 2946 | }; |
| 2947 | |
| 2948 | // Output facilities |
no test coverage detected