in source/xml_parser.c [278:373]
int aws_xml_node_traverse(
struct aws_xml_parser *parser,
struct aws_xml_node *node,
aws_xml_parser_on_node_encountered_fn *on_node_encountered,
void *user_data) {
AWS_PRECONDITION(parser);
AWS_PRECONDITION(node);
if (on_node_encountered == NULL) {
AWS_LOGF_ERROR(
AWS_LS_COMMON_XML_PARSER, "Callback 'on_node_encountered' for aws_xml_node_traverse is invalid.");
aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
return AWS_OP_ERR;
}
node->processed = true;
struct cb_stack_data stack_data = {
.cb = on_node_encountered,
.user_data = user_data,
};
size_t doc_depth = aws_array_list_length(&parser->callback_stack);
if (doc_depth >= parser->max_depth) {
AWS_LOGF_ERROR(AWS_LS_COMMON_XML_PARSER, "XML document is invalid.");
parser->error = aws_raise_error(AWS_ERROR_MALFORMED_INPUT_STRING);
return AWS_OP_ERR;
}
if (aws_array_list_push_back(&parser->callback_stack, &stack_data)) {
AWS_LOGF_ERROR(AWS_LS_COMMON_XML_PARSER, "XML document is invalid.");
parser->error = aws_raise_error(AWS_ERROR_MALFORMED_INPUT_STRING);
return AWS_OP_ERR;
}
/* look for the next node at the current level. do this until we encounter the parent node's
* closing tag. */
while (!parser->stop_parsing && !parser->error) {
uint8_t *next_location = memchr(parser->doc.ptr, '<', parser->doc.len);
if (!next_location) {
AWS_LOGF_ERROR(AWS_LS_COMMON_XML_PARSER, "XML document is invalid.");
return aws_raise_error(AWS_ERROR_MALFORMED_INPUT_STRING);
}
uint8_t *end_location = memchr(parser->doc.ptr, '>', parser->doc.len);
if (!end_location) {
AWS_LOGF_ERROR(AWS_LS_COMMON_XML_PARSER, "XML document is invalid.");
return aws_raise_error(AWS_ERROR_MALFORMED_INPUT_STRING);
}
bool parent_closed = false;
if (*(next_location + 1) == '/') {
parent_closed = true;
}
size_t node_name_len = end_location - next_location;
aws_byte_cursor_advance(&parser->doc, end_location - parser->doc.ptr + 1);
if (parent_closed) {
break;
}
struct aws_byte_cursor decl_body = aws_byte_cursor_from_array(next_location + 1, node_name_len - 1);
struct aws_xml_node next_node = {
.doc_at_body = parser->doc,
.processed = false,
};
if (s_load_node_decl(parser, &decl_body, &next_node)) {
return AWS_OP_ERR;
}
if (!on_node_encountered(parser, &next_node, user_data)) {
parser->stop_parsing = true;
return parser->error;
}
/* if the user simply returned while skipping the node altogether, go ahead and do the skip over. */
if (!parser->stop_parsing && !next_node.processed) {
if (s_advance_to_closing_tag(parser, &next_node, NULL)) {
return AWS_OP_ERR;
}
}
}
if (parser->stop_parsing) {
return parser->error;
}
aws_array_list_pop_back(&parser->callback_stack);
return parser->error;
}