| 259 | } |
| 260 | |
| 261 | bool |
| 262 | EsiParser::_parse(const string &data, int &parse_start_pos, DocNodeList &node_list, bool last_chunk /* = false */) const |
| 263 | { |
| 264 | size_t orig_list_size = node_list.size(); |
| 265 | size_t curr_pos, end_pos; |
| 266 | const char *const data_start_ptr = data.data(); |
| 267 | size_t data_size = data.size(); |
| 268 | const EsiNodeInfo *node_info; |
| 269 | MATCH_TYPE search_result; |
| 270 | bool is_html_comment_node; |
| 271 | bool parse_result; |
| 272 | |
| 273 | while (parse_start_pos < static_cast<int>(data_size)) { |
| 274 | search_result = _findOpeningTag(data, static_cast<int>(parse_start_pos), curr_pos, is_html_comment_node); |
| 275 | if (search_result == NO_MATCH) { |
| 276 | // we could add this chunk as a PRE node, but it might be |
| 277 | // possible that the next chunk is also a PRE node, in which |
| 278 | // case it is more correct to create one PRE node than two PRE |
| 279 | // nodes even though processing would result in the same final |
| 280 | // output in either case. we are sacrificing a little |
| 281 | // performance (we'll have to parse this chunk again next time) |
| 282 | // for correctness |
| 283 | break; |
| 284 | } |
| 285 | if (search_result == PARTIAL_MATCH) { |
| 286 | goto lPartialMatch; |
| 287 | } |
| 288 | |
| 289 | // we have a complete match of the opening tag |
| 290 | if ((curr_pos - parse_start_pos) > 0) { |
| 291 | // add text till here as a PRE node |
| 292 | Dbg(dbg_ctl, "[%s], Adding data of size %d before (newly found) ESI tag as PRE node", __FUNCTION__, |
| 293 | int(curr_pos - parse_start_pos)); |
| 294 | node_list.push_back(DocNode(DocNode::TYPE_PRE, data_start_ptr + parse_start_pos, curr_pos - parse_start_pos)); |
| 295 | parse_start_pos = curr_pos; |
| 296 | } |
| 297 | |
| 298 | if (is_html_comment_node) { |
| 299 | Dbg(dbg_ctl, "[%s] Found html comment tag at position %d", __FUNCTION__, int(curr_pos)); |
| 300 | node_info = &HTML_COMMENT_NODE_INFO; |
| 301 | ++curr_pos; |
| 302 | } else { |
| 303 | curr_pos += ESI_TAG_PREFIX_LEN; |
| 304 | |
| 305 | for (node_info = ESI_NODES; node_info->type != DocNode::TYPE_UNKNOWN; ++node_info) { |
| 306 | search_result = _compareData(data, curr_pos, node_info->tag_suffix, node_info->tag_suffix_len); |
| 307 | if (search_result == COMPLETE_MATCH) { |
| 308 | if (node_info->tag_suffix[node_info->tag_suffix_len - 1] == '>') { |
| 309 | Dbg(dbg_ctl, "[%s] Found [%s] tag at position %d", __FUNCTION__, DocNode::type_names_[node_info->type], |
| 310 | int(curr_pos - ESI_TAG_PREFIX_LEN)); |
| 311 | break; |
| 312 | } else { |
| 313 | if (curr_pos + node_info->tag_suffix_len < data_size) { |
| 314 | char ch = data_start_ptr[curr_pos + node_info->tag_suffix_len]; |
| 315 | if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n') { |
| 316 | Dbg(dbg_ctl, "[%s] Found [%s] tag at position %d", __FUNCTION__, DocNode::type_names_[node_info->type], |
| 317 | int(curr_pos - ESI_TAG_PREFIX_LEN)); |
| 318 | ++curr_pos; // skip the space char |