1 /*
2  * Copyright (C) 2018-2020 Alexander Borisov
3  *
4  * Author: Alexander Borisov <borisov@lexbor.com>
5  */
6 
7 #include "lexbor/html/tree/insertion_mode.h"
8 #include "lexbor/html/token.h"
9 
10 
11 static void
12 lxb_html_tree_insertion_mode_in_table_text_erase(lxb_html_tree_t *tree);
13 
14 
15 bool
lxb_html_tree_insertion_mode_in_table_text(lxb_html_tree_t * tree,lxb_html_token_t * token)16 lxb_html_tree_insertion_mode_in_table_text(lxb_html_tree_t *tree,
17                                            lxb_html_token_t *token)
18 {
19     lxb_status_t status;
20     lexbor_str_t *text;
21     lexbor_array_obj_t *pt_list = tree->pending_table.text_list;
22 
23     if (token->tag_id == LXB_TAG__TEXT) {
24         if (token->null_count != 0) {
25             lxb_html_tree_parse_error(tree, token,
26                                       LXB_HTML_RULES_ERROR_NUCH);
27         }
28 
29         text = lexbor_array_obj_push(pt_list);
30         if (text == NULL) {
31             tree->status = LXB_STATUS_ERROR_MEMORY_ALLOCATION;
32 
33             lxb_html_tree_insertion_mode_in_table_text_erase(tree);
34 
35             return lxb_html_tree_process_abort(tree);
36         }
37 
38         if (token->null_count != 0) {
39             lxb_html_tree_parse_error(tree, token,
40                                       LXB_HTML_RULES_ERROR_NUCH);
41 
42             tree->status = lxb_html_token_make_text_drop_null(token, text,
43                                                               tree->document->dom_document.text);
44         }
45         else {
46             tree->status = lxb_html_token_make_text(token, text,
47                                                     tree->document->dom_document.text);
48         }
49 
50         if (tree->status != LXB_STATUS_OK) {
51             lxb_html_tree_insertion_mode_in_table_text_erase(tree);
52 
53             return lxb_html_tree_process_abort(tree);
54         }
55 
56         if (text->length == 0) {
57             lexbor_array_obj_pop(pt_list);
58             lexbor_str_destroy(text, tree->document->dom_document.text, false);
59 
60             return true;
61         }
62 
63         /*
64          * The lxb_html_token_data_skip_ws_begin function
65          * can change token->text_start value.
66          */
67         size_t i_pos = lexbor_str_whitespace_from_begin(text);
68 
69         if (i_pos != text->length) {
70             if (!tree->pending_table.have_non_ws) {
71                 tree->pending_table.have_non_ws = true;
72             }
73         }
74 
75         return true;
76     }
77 
78     if (tree->pending_table.have_non_ws) {
79         lxb_html_tree_parse_error(tree, token, LXB_HTML_RULES_ERROR_CHINTATE);
80 
81         tree->foster_parenting = true;
82 
83         for (size_t i = 0; i < lexbor_array_obj_length(pt_list); i++) {
84             text = lexbor_array_obj_get(pt_list, i);
85 
86             status = lxb_html_tree_insertion_mode_in_body_text_append(tree,
87                                                                       text);
88             if (status != LXB_STATUS_OK) {
89                 lxb_html_tree_insertion_mode_in_table_text_erase(tree);
90 
91                 return lxb_html_tree_process_abort(tree);
92             }
93         }
94 
95         tree->foster_parenting = false;
96     }
97     else {
98         for (size_t i = 0; i < lexbor_array_obj_length(pt_list); i++) {
99             text = lexbor_array_obj_get(pt_list, i);
100 
101             tree->status = lxb_html_tree_insert_character_for_data(tree, text,
102                                                                    NULL);
103             if (tree->status != LXB_STATUS_OK) {
104                 lxb_html_tree_insertion_mode_in_table_text_erase(tree);
105 
106                 return lxb_html_tree_process_abort(tree);
107             }
108         }
109     }
110 
111     tree->mode = tree->original_mode;
112 
113     return false;
114 }
115 
116 static void
lxb_html_tree_insertion_mode_in_table_text_erase(lxb_html_tree_t * tree)117 lxb_html_tree_insertion_mode_in_table_text_erase(lxb_html_tree_t *tree)
118 {
119     lexbor_str_t *text;
120     lexbor_array_obj_t *pt_list = tree->pending_table.text_list;
121 
122     for (size_t i = 0; i < lexbor_array_obj_length(pt_list); i++) {
123         text = lexbor_array_obj_get(pt_list, i);
124 
125         lexbor_str_destroy(text, tree->document->dom_document.text, false);
126     }
127 }
128