File Coverage

third_party/modest/source/myhtml/tokenizer.c
Criterion Covered Total %
statement 524 999 52.4
branch 158 472 33.4
condition n/a
subroutine n/a
pod n/a
total 682 1471 46.3


line stmt bran cond sub pod time code
1             /*
2             Copyright (C) 2015-2017 Alexander Borisov
3            
4             This library is free software; you can redistribute it and/or
5             modify it under the terms of the GNU Lesser General Public
6             License as published by the Free Software Foundation; either
7             version 2.1 of the License, or (at your option) any later version.
8            
9             This library is distributed in the hope that it will be useful,
10             but WITHOUT ANY WARRANTY; without even the implied warranty of
11             MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12             Lesser General Public License for more details.
13            
14             You should have received a copy of the GNU Lesser General Public
15             License along with this library; if not, write to the Free Software
16             Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17            
18             Author: lex.borisov@gmail.com (Alexander Borisov)
19             */
20              
21             #include "myhtml/tokenizer.h"
22             #include "mycore/utils/resources.h"
23              
24 145           mystatus_t myhtml_tokenizer_set_first_settings(myhtml_tree_t* tree, const char* html, size_t html_length)
25             {
26 145           tree->current_qnode = mythread_queue_get_current_node(tree->queue);
27 145           mythread_queue_node_clean(tree->current_qnode);
28            
29 145           tree->current_qnode->context = tree;
30 145           tree->current_token_node = myhtml_token_node_create(tree->token, tree->token->mcasync_token_id);
31            
32 145 50         if(tree->current_token_node == NULL)
33 0           return MyHTML_STATUS_ERROR_MEMORY_ALLOCATION;
34            
35 145           tree->incoming_buf_first = tree->incoming_buf;
36            
37 145           return MyHTML_STATUS_OK;
38             }
39              
40 143           mystatus_t myhtml_tokenizer_begin(myhtml_tree_t* tree, const char* html, size_t html_length)
41             {
42 143           return myhtml_tokenizer_chunk(tree, html, html_length);
43             }
44              
45 148           mystatus_t myhtml_tokenizer_chunk_process(myhtml_tree_t* tree, const char* html, size_t html_length)
46             {
47 148           myhtml_t* myhtml = tree->myhtml;
48 148           myhtml_tokenizer_state_f* state_f = myhtml->parse_state_func;
49            
50             // add for a chunk
51 148           tree->incoming_buf = mycore_incoming_buffer_add(tree->incoming_buf, tree->mcobject_incoming_buf, html, html_length);
52            
53             #ifndef MyCORE_BUILD_WITHOUT_THREADS
54            
55 148 100         if(myhtml->opt & MyHTML_OPTIONS_PARSE_MODE_SINGLE)
56 142           tree->flags |= MyHTML_TREE_FLAGS_SINGLE_MODE;
57            
58 148 100         if((tree->flags & MyHTML_TREE_FLAGS_SINGLE_MODE) == 0)
59             {
60 6 50         if(tree->queue_entry == NULL) {
61 6           mystatus_t status = MyHTML_STATUS_OK;
62 12           tree->queue_entry = mythread_queue_list_entry_push(myhtml->thread_list, 2,
63 6           myhtml->thread_stream->context, tree->queue,
64             myhtml->thread_total, &status);
65            
66 6 50         if(status)
67 0           return status;
68             }
69            
70 6           myhtml_tokenizer_post(tree);
71             }
72            
73             #else
74            
75             tree->flags |= MyHTML_TREE_FLAGS_SINGLE_MODE;
76            
77             #endif
78            
79 148 100         if(tree->current_qnode == NULL) {
80 145           mystatus_t status = myhtml_tokenizer_set_first_settings(tree, html, html_length);
81 145 50         if(status)
82 0           return status;
83             }
84            
85 148           size_t offset = 0;
86            
87 4374 100         while (offset < html_length) {
88 4226           offset = state_f[tree->state](tree, tree->current_token_node, html, offset, html_length);
89             }
90            
91 148           tree->global_offset += html_length;
92            
93 148           return MyHTML_STATUS_OK;
94             }
95              
96 148           mystatus_t myhtml_tokenizer_chunk(myhtml_tree_t* tree, const char* html, size_t html_length)
97             {
98 148 100         if(tree->encoding_usereq == MyENCODING_UTF_16LE ||
99 145 50         tree->encoding_usereq == MyENCODING_UTF_16BE)
100             {
101 3           return myhtml_tokenizer_chunk_with_stream_buffer(tree, html, html_length);
102             }
103            
104 145           return myhtml_tokenizer_chunk_process(tree, html, html_length);
105             }
106              
107 3           mystatus_t myhtml_tokenizer_chunk_with_stream_buffer(myhtml_tree_t* tree, const char* html, size_t html_length)
108             {
109 3           unsigned const char* u_html = (unsigned const char*)html;
110 3           const myencoding_custom_f func = myencoding_get_function_by_id(tree->encoding);
111            
112 3 50         if(tree->stream_buffer == NULL) {
113 3           tree->stream_buffer = myhtml_stream_buffer_create();
114            
115 3 50         if(tree->stream_buffer == NULL)
116 0           return MyHTML_STATUS_STREAM_BUFFER_ERROR_CREATE;
117            
118 3           mystatus_t status = myhtml_stream_buffer_init(tree->stream_buffer, 1024);
119            
120 3 50         if(status)
121 0           return status;
122            
123 3 50         if(myhtml_stream_buffer_add_entry(tree->stream_buffer, (4096 * 4)) == NULL)
124 0           return MyHTML_STATUS_STREAM_BUFFER_ERROR_ADD_ENTRY;
125             }
126            
127 3           myhtml_stream_buffer_t *stream_buffer = tree->stream_buffer;
128 3           myhtml_stream_buffer_entry_t *stream_entry = myhtml_stream_buffer_current_entry(stream_buffer);
129            
130 3           size_t temp_curr_pos = stream_entry->length;
131            
132 75 100         for (size_t i = 0; i < html_length; i++)
133             {
134 72 100         if(func(u_html[i], &stream_buffer->res) == MyENCODING_STATUS_OK)
135             {
136 36 50         if((stream_entry->length + 4) >= stream_entry->size)
137             {
138 0           tree->encoding = MyENCODING_UTF_8;
139 0           myhtml_tokenizer_chunk_process(tree, &stream_entry->data[temp_curr_pos], (stream_entry->length - temp_curr_pos));
140            
141 0           stream_entry = myhtml_stream_buffer_add_entry(stream_buffer, (4096 * 4));
142            
143 0 0         if(stream_entry == NULL)
144 0           return MyHTML_STATUS_STREAM_BUFFER_ERROR_ADD_ENTRY;
145            
146 0           temp_curr_pos = stream_entry->length;
147             }
148            
149 36           stream_entry->length += myencoding_codepoint_to_ascii_utf_8(stream_buffer->res.result, &stream_entry->data[ stream_entry->length ]);
150             }
151             }
152            
153 3 50         if((stream_entry->length - temp_curr_pos)) {
154 3           tree->encoding = MyENCODING_UTF_8;
155 3           myhtml_tokenizer_chunk_process(tree, &stream_entry->data[temp_curr_pos], (stream_entry->length - temp_curr_pos));
156             }
157            
158 3           return MyHTML_STATUS_OK;
159             }
160              
161 145           mystatus_t myhtml_tokenizer_end(myhtml_tree_t* tree)
162             {
163 145 50         if(tree->incoming_buf)
164             {
165 145           tree->global_offset -= tree->incoming_buf->size;
166            
167 145           tree->myhtml->parse_state_func[(tree->state + MyHTML_TOKENIZER_STATE_LAST_ENTRY)]
168 145           (tree, tree->current_token_node, tree->incoming_buf->data, tree->incoming_buf->size, tree->incoming_buf->size);
169             }
170            
171 145           tree->current_token_node->tag_id = MyHTML_TAG__END_OF_FILE;
172            
173 145 50         if(myhtml_queue_add(tree, 0, tree->current_token_node) != MyHTML_STATUS_OK) {
174 0           tree->tokenizer_status = MyHTML_STATUS_ERROR_MEMORY_ALLOCATION;
175             }
176            
177 145           mystatus_t status = tree->tokenizer_status;
178            
179             #ifndef MyCORE_BUILD_WITHOUT_THREADS
180            
181 145 100         if((tree->flags & MyHTML_TREE_FLAGS_SINGLE_MODE) == 0)
182             {
183 6           mythread_queue_list_entry_wait_for_done(tree->myhtml->thread_stream, tree->queue_entry);
184            
185 12           tree->queue_entry = mythread_queue_list_entry_delete(tree->myhtml->thread_list, 2,
186 6           tree->myhtml->thread_stream->context,
187             tree->queue_entry, false);
188            
189             /* Further, any work with tree... */
190 6 50         if(mythread_queue_list_get_count(tree->myhtml->thread_stream->context) == 0)
191 6           myhtml_tokenizer_pause(tree);
192            
193 6 50         if(status == MyHTML_STATUS_OK)
194 6           status = mythread_check_status(tree->myhtml->thread_stream);
195             }
196            
197             #endif
198            
199 145           tree->flags |= MyHTML_TREE_FLAGS_PARSE_END;
200            
201 145           return status;
202             }
203              
204 17           myhtml_tree_node_t * myhtml_tokenizer_fragment_init(myhtml_tree_t* tree, myhtml_tag_id_t tag_idx, enum myhtml_namespace ns)
205             {
206             // step 3
207 17           tree->fragment = myhtml_tree_node_create(tree);
208 17           tree->fragment->ns = ns;
209 17           tree->fragment->tag_id = tag_idx;
210            
211             // step 4, is already done
212 17 50         if(ns == MyHTML_NAMESPACE_HTML) {
213 17 50         if(tag_idx == MyHTML_TAG_NOSCRIPT) {
214 0 0         if(tree->flags & MyHTML_TREE_FLAGS_SCRIPT) {
215 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_RAWTEXT;
216             }
217             else {
218 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_DATA;
219             }
220             }
221             else {
222 17           const myhtml_tag_context_t *tag_ctx = myhtml_tag_get_by_id(tree->tags, tag_idx);
223 17           myhtml_tokenizer_state_set(tree) = tag_ctx->data_parser;
224             }
225             }
226            
227 17           tree->fragment->token = myhtml_token_node_create(tree->token, tree->token->mcasync_token_id);
228            
229 17 50         if(tree->fragment->token == NULL)
230 0           return NULL;
231            
232 17           myhtml_token_set_done(tree->fragment->token);
233 17           tree->token_namespace = tree->fragment->token;
234            
235             // step 5-7
236 17           myhtml_tree_node_t* root = myhtml_tree_node_insert_root(tree, NULL, MyHTML_NAMESPACE_HTML);
237            
238 17 50         if(tag_idx == MyHTML_TAG_TEMPLATE)
239 0           myhtml_tree_template_insertion_append(tree, MyHTML_INSERTION_MODE_IN_TEMPLATE);
240            
241 17           myhtml_tree_reset_insertion_mode_appropriately(tree);
242            
243 17           return root;
244             }
245              
246 0           void myhtml_tokenizer_wait(myhtml_tree_t* tree)
247             {
248             #ifndef MyCORE_BUILD_WITHOUT_THREADS
249 0 0         if(tree->myhtml->thread_stream)
250 0           mythread_queue_list_entry_wait_for_done(tree->myhtml->thread_stream, tree->queue_entry);
251             #endif
252 0           }
253              
254 6           void myhtml_tokenizer_post(myhtml_tree_t* tree)
255             {
256             #ifndef MyCORE_BUILD_WITHOUT_THREADS
257 6 50         if(tree->myhtml->thread_stream)
258 6           mythread_resume(tree->myhtml->thread_stream, MyTHREAD_OPT_UNDEF);
259            
260 6 50         if(tree->myhtml->thread_batch)
261 6           mythread_resume(tree->myhtml->thread_batch, MyTHREAD_OPT_UNDEF);
262             #endif
263 6           }
264              
265 6           void myhtml_tokenizer_pause(myhtml_tree_t* tree)
266             {
267             #ifndef MyCORE_BUILD_WITHOUT_THREADS
268 6 50         if(tree->myhtml->thread_stream)
269 6           mythread_stop(tree->myhtml->thread_stream);
270            
271 6 50         if(tree->myhtml->thread_batch)
272 6           mythread_stop(tree->myhtml->thread_batch);
273             #endif
274 6           }
275              
276 1685           void myhtml_tokenizer_calc_current_namespace(myhtml_tree_t* tree, myhtml_token_node_t* token_node)
277             {
278 1685 50         if((tree->parse_flags & MyHTML_TREE_PARSE_FLAGS_WITHOUT_BUILD_TREE) == 0) {
279 1685 100         if(tree->flags & MyHTML_TREE_FLAGS_SINGLE_MODE)
280             {
281 1663           myhtml_tokenizer_state_set(tree) = tree->state_of_builder;
282             }
283             else {
284 22 50         if(token_node->tag_id == MyHTML_TAG_MATH ||
285 22 50         token_node->tag_id == MyHTML_TAG_SVG ||
286 22 50         token_node->tag_id == MyHTML_TAG_FRAMESET)
287             {
288 0           tree->token_namespace = token_node;
289             }
290 22 50         else if(tree->token_namespace && (token_node->type & MyHTML_TOKEN_TYPE_CLOSE) == 0) {
    0          
291 0           const myhtml_tag_context_t *tag_ctx = myhtml_tag_get_by_id(tree->tags, token_node->tag_id);
292            
293 0 0         if(tag_ctx->data_parser != MyHTML_TOKENIZER_STATE_DATA)
294             {
295 0           myhtml_tree_wait_for_last_done_token(tree, token_node);
296 0           myhtml_tokenizer_state_set(tree) = tree->state_of_builder;
297             }
298             }
299             }
300             }
301 1685           }
302              
303 751           void myhtml_check_tag_parser(myhtml_tree_t* tree, myhtml_token_node_t* token_node, const char* html, size_t html_offset)
304             {
305 751           myhtml_tag_t* tags = tree->tags;
306 751           const myhtml_tag_context_t *tag_ctx = NULL;
307            
308 751 100         if(html_offset < token_node->raw_length) {
309 1           const char *tagname = myhtml_tree_incomming_buffer_make_data(tree, token_node->raw_begin, token_node->raw_length);
310 1           tag_ctx = myhtml_tag_get_by_name(tags, tagname, token_node->raw_length);
311             }
312             else {
313 750           tag_ctx = myhtml_tag_get_by_name(tags, &html[ (token_node->raw_begin - tree->global_offset) ], token_node->raw_length);
314             }
315            
316 751 50         if(tag_ctx) {
317 751           token_node->tag_id = tag_ctx->id;
318             }
319             else {
320 0 0         if(html_offset < token_node->raw_length) {
321 0           const char *tagname = myhtml_tree_incomming_buffer_make_data(tree, token_node->raw_begin, token_node->raw_length);
322 0           token_node->tag_id = myhtml_tag_add(tags, tagname, token_node->raw_length, MyHTML_TOKENIZER_STATE_DATA, true);
323             }
324             else {
325 0           token_node->tag_id = myhtml_tag_add(tags, &html[ (token_node->raw_begin - tree->global_offset) ], token_node->raw_length, MyHTML_TOKENIZER_STATE_DATA, true);
326             }
327            
328 0           myhtml_tag_set_category(tags, token_node->tag_id, MyHTML_NAMESPACE_HTML, MyHTML_TAG_CATEGORIES_ORDINARY);
329             }
330 751           }
331              
332             ////
333 994           myhtml_token_node_t * myhtml_tokenizer_queue_create_text_node_if_need(myhtml_tree_t* tree, myhtml_token_node_t* token_node, const char* html, size_t absolute_html_offset, enum myhtml_token_type type)
334             {
335 994 50         if(token_node->tag_id == MyHTML_TAG__UNDEF)
336             {
337 994 100         if(absolute_html_offset > token_node->raw_begin)
338             {
339 692           size_t tmp_begin = token_node->element_begin;
340            
341 692           token_node->type |= type;
342 692           token_node->tag_id = MyHTML_TAG__TEXT;
343 692           token_node->element_begin = token_node->raw_begin;
344 692           token_node->raw_length = token_node->element_length = absolute_html_offset - token_node->raw_begin;
345            
346 692 50         if(myhtml_queue_add(tree, tmp_begin, token_node) != MyHTML_STATUS_OK) {
347 0           return NULL;
348             }
349            
350 692           return tree->current_token_node;
351             }
352             }
353            
354 302           return token_node;
355             }
356              
357 751           void myhtml_tokenizer_set_state(myhtml_tree_t* tree, myhtml_token_node_t* token_node)
358             {
359 751 100         if((token_node->type & MyHTML_TOKEN_TYPE_CLOSE) == 0)
360             {
361 376 50         if(token_node->tag_id == MyHTML_TAG_NOSCRIPT &&
362 0 0         (tree->flags & MyHTML_TREE_FLAGS_SCRIPT) == 0)
363             {
364 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_DATA;
365             }
366             else {
367 376           const myhtml_tag_context_t *tag_ctx = myhtml_tag_get_by_id(tree->tags, token_node->tag_id);
368 376           myhtml_tokenizer_state_set(tree) = tag_ctx->data_parser;
369             }
370             }
371             else {
372 375           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_DATA;
373             }
374 751           }
375              
376             /////////////////////////////////////////////////////////
377             //// RCDATA
378             ////
379             /////////////////////////////////////////////////////////
380 0           size_t myhtml_tokenizer_state_rcdata(myhtml_tree_t* tree, myhtml_token_node_t* token_node, const char* html, size_t html_offset, size_t html_size)
381             {
382 0 0         if(tree->tmp_tag_id == 0) {
383 0           token_node->raw_begin = (html_offset + tree->global_offset);
384            
385 0           mythread_queue_node_t* prev_qnode = mythread_queue_get_prev_node(tree->current_qnode);
386            
387 0 0         if(prev_qnode && prev_qnode->args) {
    0          
388 0           tree->tmp_tag_id = ((myhtml_token_node_t*)(prev_qnode->args))->tag_id;
389             }
390 0 0         else if(tree->fragment) {
391 0           tree->tmp_tag_id = tree->fragment->tag_id;
392             }
393             }
394            
395 0 0         while(html_offset < html_size)
396             {
397 0 0         if(html[html_offset] == '<')
398             {
399 0           token_node->element_begin = (html_offset + tree->global_offset);
400            
401 0           html_offset++;
402 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_RCDATA_LESS_THAN_SIGN;
403            
404 0           break;
405             }
406            
407 0           html_offset++;
408             }
409            
410 0           return html_offset;
411             }
412              
413 0           size_t myhtml_tokenizer_state_rcdata_less_than_sign(myhtml_tree_t* tree, myhtml_token_node_t* token_node, const char* html, size_t html_offset, size_t html_size)
414             {
415 0 0         if(html[html_offset] == '/')
416             {
417 0           html_offset++;
418 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_RCDATA_END_TAG_OPEN;
419             }
420             else {
421 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_RCDATA;
422             }
423            
424 0           return html_offset;
425             }
426              
427 0           size_t myhtml_tokenizer_state_rcdata_end_tag_open(myhtml_tree_t* tree, myhtml_token_node_t* token_node, const char* html, size_t html_offset, size_t html_size)
428             {
429 0 0         if(mycore_tokenizer_chars_map[ (unsigned char)html[html_offset] ] == MyCORE_STRING_MAP_CHAR_A_Z_a_z)
430             {
431 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_RCDATA_END_TAG_NAME;
432             }
433             else {
434 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_RCDATA;
435             }
436            
437 0           return html_offset;
438             }
439              
440 0           bool _myhtml_tokenizer_state_andata_end_tag_name(myhtml_tree_t* tree, myhtml_token_node_t* token_node, const char* html, size_t *html_offset, size_t tmp_begin, enum myhtml_token_type type)
441             {
442 0           token_node->raw_length = (*html_offset + tree->global_offset) - token_node->raw_begin;
443 0           myhtml_check_tag_parser(tree, token_node, html, *html_offset);
444            
445 0 0         if(token_node->tag_id != tree->tmp_tag_id)
446             {
447 0           token_node->raw_begin = tmp_begin;
448 0           token_node->raw_length = 0;
449            
450 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_RCDATA;
451            
452 0           (*html_offset)++;
453 0           return false;
454             }
455            
456 0 0         if((token_node->raw_begin - 2) > tmp_begin)
457             {
458 0           size_t tmp_element_begin = token_node->element_begin;
459 0           size_t tmp_raw_begin = token_node->raw_begin;
460            
461 0           token_node->raw_length = (token_node->raw_begin - 2) - tmp_begin;
462 0           token_node->raw_begin = tmp_begin;
463 0           token_node->element_begin = tmp_begin;
464 0           token_node->element_length = token_node->raw_length;
465 0           token_node->type |= type;
466 0           token_node->type ^= (token_node->type & MyHTML_TOKEN_TYPE_WHITESPACE);
467 0           token_node->tag_id = MyHTML_TAG__TEXT;
468            
469             /* TODO: return error */
470 0           myhtml_queue_add(tree, *html_offset, token_node);
471            
472             /* return true values */
473 0           token_node = tree->current_token_node;
474 0           token_node->element_begin = tmp_element_begin;
475 0           token_node->raw_begin = tmp_raw_begin;
476             }
477            
478 0           token_node->tag_id = tree->tmp_tag_id;
479 0           token_node->type |= MyHTML_TOKEN_TYPE_CLOSE;
480 0           token_node->raw_length = (tree->global_offset + *html_offset) - token_node->raw_begin;
481            
482 0           return true;
483             }
484              
485 0           size_t myhtml_tokenizer_state_rcdata_end_tag_name(myhtml_tree_t* tree, myhtml_token_node_t* token_node, const char* html, size_t html_offset, size_t html_size)
486             {
487 0           size_t tmp_begin = token_node->raw_begin;
488 0           token_node->raw_begin = html_offset + tree->global_offset;
489            
490 0 0         while(html_offset < html_size)
491             {
492 0 0         if(mycore_tokenizer_chars_map[ (unsigned char)html[html_offset] ] == MyCORE_STRING_MAP_CHAR_WHITESPACE)
493             {
494 0 0         if(_myhtml_tokenizer_state_andata_end_tag_name(tree, token_node, html, &html_offset, tmp_begin, MyHTML_TOKEN_TYPE_RCDATA)) {
495 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_BEFORE_ATTRIBUTE_NAME;
496            
497 0           tree->tmp_tag_id = 0;
498 0           html_offset++;
499            
500 0           return html_offset;
501             }
502            
503 0           break;
504             }
505 0 0         else if(html[html_offset] == '>')
506             {
507 0 0         if(_myhtml_tokenizer_state_andata_end_tag_name(tree, token_node, html, &html_offset, tmp_begin, MyHTML_TOKEN_TYPE_RCDATA)) {
508 0           html_offset++;
509            
510 0           token_node = tree->current_token_node;
511 0           token_node->element_length = (tree->global_offset + html_offset) - token_node->element_begin;
512            
513 0 0         if(myhtml_queue_add(tree, html_offset, token_node) != MyHTML_STATUS_OK) {
514 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_PARSE_ERROR_STOP;
515 0           return 0;
516             }
517            
518 0           tree->tmp_tag_id = 0;
519 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_DATA;
520            
521 0           return html_offset;
522             }
523            
524 0           break;
525             }
526             // check end of tag
527 0 0         else if(html[html_offset] == '/')
528             {
529 0 0         if(_myhtml_tokenizer_state_andata_end_tag_name(tree, token_node, html, &html_offset, tmp_begin, MyHTML_TOKEN_TYPE_RCDATA)) {
530 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_BEFORE_ATTRIBUTE_NAME;
531            
532 0           tree->tmp_tag_id = 0;
533 0           html_offset++;
534            
535 0           return html_offset;
536             }
537            
538 0           break;
539             }
540 0 0         else if (mycore_tokenizer_chars_map[ (unsigned char)html[html_offset] ] != MyCORE_STRING_MAP_CHAR_A_Z_a_z) {
541 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_RCDATA;
542 0           break;
543             }
544            
545 0           html_offset++;
546             }
547            
548 0           token_node->raw_begin = tmp_begin;
549 0           return html_offset;
550             }
551              
552             /////////////////////////////////////////////////////////
553             //// RAWTEXT
554             ////
555             /////////////////////////////////////////////////////////
556 0           size_t myhtml_tokenizer_state_rawtext(myhtml_tree_t* tree, myhtml_token_node_t* token_node, const char* html, size_t html_offset, size_t html_size)
557             {
558 0 0         if(tree->tmp_tag_id == 0) {
559 0           token_node->raw_begin = (html_offset + tree->global_offset);
560            
561 0           mythread_queue_node_t* prev_qnode = mythread_queue_get_prev_node(tree->current_qnode);
562            
563 0 0         if(prev_qnode && prev_qnode->args) {
    0          
564 0           tree->tmp_tag_id = ((myhtml_token_node_t*)prev_qnode->args)->tag_id;
565             }
566 0 0         else if(tree->fragment) {
567 0           tree->tmp_tag_id = tree->fragment->tag_id;
568             }
569             }
570              
571            
572 0 0         while(html_offset < html_size)
573             {
574 0 0         if(html[html_offset] == '<')
575             {
576 0           token_node->element_begin = (html_offset + tree->global_offset);
577            
578 0           html_offset++;
579 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_RAWTEXT_LESS_THAN_SIGN;
580            
581 0           break;
582             }
583            
584 0           html_offset++;
585             }
586            
587 0           return html_offset;
588             }
589              
590 0           size_t myhtml_tokenizer_state_rawtext_less_than_sign(myhtml_tree_t* tree, myhtml_token_node_t* token_node, const char* html, size_t html_offset, size_t html_size)
591             {
592 0 0         if(html[html_offset] == '/')
593             {
594 0           html_offset++;
595 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_RAWTEXT_END_TAG_OPEN;
596             }
597             else {
598 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_RAWTEXT;
599             }
600            
601 0           return html_offset;
602             }
603              
604 0           size_t myhtml_tokenizer_state_rawtext_end_tag_open(myhtml_tree_t* tree, myhtml_token_node_t* token_node, const char* html, size_t html_offset, size_t html_size)
605             {
606 0 0         if(mycore_tokenizer_chars_map[ (unsigned char)html[html_offset] ] == MyCORE_STRING_MAP_CHAR_A_Z_a_z)
607             {
608 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_RAWTEXT_END_TAG_NAME;
609             }
610             else {
611 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_RAWTEXT;
612             }
613            
614 0           return html_offset;
615             }
616              
617 0           size_t myhtml_tokenizer_state_rawtext_end_tag_name(myhtml_tree_t* tree, myhtml_token_node_t* token_node, const char* html, size_t html_offset, size_t html_size)
618             {
619 0           size_t tmp_begin = token_node->raw_begin;
620 0           token_node->raw_begin = html_offset + tree->global_offset;
621            
622 0 0         while(html_offset < html_size)
623             {
624 0 0         if(mycore_tokenizer_chars_map[ (unsigned char)html[html_offset] ] == MyCORE_STRING_MAP_CHAR_WHITESPACE)
625             {
626 0 0         if(_myhtml_tokenizer_state_andata_end_tag_name(tree, token_node, html, &html_offset, tmp_begin, MyHTML_TOKEN_TYPE_RAWTEXT)) {
627 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_BEFORE_ATTRIBUTE_NAME;
628            
629 0           tree->tmp_tag_id = 0;
630 0           html_offset++;
631             }
632            
633 0           return html_offset;
634             }
635 0 0         else if(html[html_offset] == '>')
636             {
637 0 0         if(_myhtml_tokenizer_state_andata_end_tag_name(tree, token_node, html, &html_offset, tmp_begin, MyHTML_TOKEN_TYPE_RAWTEXT)) {
638 0           html_offset++;
639            
640 0           token_node = tree->current_token_node;
641 0           token_node->element_length = (tree->global_offset + html_offset) - token_node->element_begin;
642            
643 0 0         if(myhtml_queue_add(tree, html_offset, token_node) != MyHTML_STATUS_OK) {
644 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_PARSE_ERROR_STOP;
645 0           return 0;
646             }
647            
648 0           tree->tmp_tag_id = 0;
649 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_DATA;
650             }
651            
652 0           return html_offset;
653             }
654             // check end of tag
655 0 0         else if(html[html_offset] == '/')
656             {
657 0 0         if(_myhtml_tokenizer_state_andata_end_tag_name(tree, token_node, html, &html_offset, tmp_begin, MyHTML_TOKEN_TYPE_RAWTEXT)) {
658 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_BEFORE_ATTRIBUTE_NAME;
659            
660 0           tree->tmp_tag_id = 0;
661 0           html_offset++;
662             }
663            
664 0           return html_offset;
665             }
666 0 0         else if (mycore_tokenizer_chars_map[ (unsigned char)html[html_offset] ] != MyCORE_STRING_MAP_CHAR_A_Z_a_z) {
667 0           token_node->raw_begin = tmp_begin;
668 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_RAWTEXT;
669            
670 0           return html_offset;
671             }
672            
673 0           html_offset++;
674             }
675            
676 0           token_node->raw_begin = tmp_begin;
677 0           return html_offset;
678             }
679              
680             /////////////////////////////////////////////////////////
681             //// PLAINTEXT
682             ////
683             /////////////////////////////////////////////////////////
684 0           size_t myhtml_tokenizer_state_plaintext(myhtml_tree_t* tree, myhtml_token_node_t* token_node, const char* html, size_t html_offset, size_t html_size)
685             {
686 0 0         if((token_node->type & MyHTML_TOKEN_TYPE_PLAINTEXT) == 0)
687 0           token_node->type |= MyHTML_TOKEN_TYPE_PLAINTEXT;
688            
689 0           token_node->type ^= (token_node->type & MyHTML_TOKEN_TYPE_WHITESPACE);
690 0           token_node->raw_begin = (html_offset + tree->global_offset);
691 0           token_node->raw_length = token_node->element_length = (html_size + tree->global_offset) - token_node->raw_begin;
692 0           token_node->tag_id = MyHTML_TAG__TEXT;
693            
694 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_DATA;
695            
696 0 0         if(myhtml_queue_add(tree, html_size, token_node) != MyHTML_STATUS_OK) {
697 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_PARSE_ERROR_STOP;
698 0           return 0;
699             }
700            
701 0           return html_size;
702             }
703              
704             /////////////////////////////////////////////////////////
705             //// CDATA
706             ////
707             /////////////////////////////////////////////////////////
708 0           size_t myhtml_tokenizer_state_cdata_section(myhtml_tree_t* tree, myhtml_token_node_t* token_node, const char* html, size_t html_offset, size_t html_size)
709             {
710 0 0         if((token_node->type & MyHTML_TOKEN_TYPE_CDATA) == 0)
711 0           token_node->type |= MyHTML_TOKEN_TYPE_CDATA;
712            
713 0 0         while(html_offset < html_size)
714             {
715 0 0         if(html[html_offset] == '>')
716             {
717             const char *tagname;
718 0 0         if(html_offset < 2)
719 0           tagname = myhtml_tree_incomming_buffer_make_data(tree,((html_offset + tree->global_offset) - 2), 2);
720             else
721 0           tagname = &html[html_offset - 2];
722            
723 0 0         if(tagname[0] == ']' && tagname[1] == ']')
    0          
724             {
725 0           token_node->raw_length = (((html_offset + tree->global_offset) - 2) - token_node->raw_begin);
726 0           html_offset++;
727            
728 0 0         if(token_node->raw_length) {
729 0           token_node->element_length = (tree->global_offset + html_offset) - token_node->element_begin;
730            
731 0 0         if(myhtml_queue_add(tree, html_offset, token_node) != MyHTML_STATUS_OK) {
732 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_PARSE_ERROR_STOP;
733 0           return 0;
734             }
735            
736             }
737             else {
738 0           token_node->raw_begin = html_offset + tree->global_offset;
739             }
740            
741 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_DATA;
742 0           break;
743             }
744             }
745            
746 0           html_offset++;
747             }
748            
749 0           return html_offset;
750             }
751              
752             /////////////////////////////////////////////////////////
753             //// outside of tag
754             //// %HERE%
%HERE%
%HERE%
755             /////////////////////////////////////////////////////////
756 921           size_t myhtml_tokenizer_state_data(myhtml_tree_t* tree, myhtml_token_node_t* token_node, const char* html, size_t html_offset, size_t html_size)
757             {
758 5212 100         while(html_offset < html_size)
759             {
760 5140 100         if(html[html_offset] == '<')
761             {
762 849           token_node->element_begin = (tree->global_offset + html_offset);
763            
764 849           html_offset++;
765 849           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_TAG_OPEN;
766            
767 849           break;
768             }
769 4291 50         else if(html[html_offset] == '\0' && (token_node->type & MyHTML_TOKEN_TYPE_NULL) == 0) {
    0          
770             // parse error
771             /* %EXTERNAL% VALIDATOR:TOKENIZER POSITION STATUS:CHAR_NULL LEVEL:ERROR BEGIN:html_offset LENGTH:1 */
772            
773 0           token_node->type |= MyHTML_TOKEN_TYPE_NULL;
774             }
775 4291 100         else if(token_node->type & MyHTML_TOKEN_TYPE_WHITESPACE &&
776 2202 100         mycore_tokenizer_chars_map[ (unsigned char)html[html_offset] ] != MyCORE_STRING_MAP_CHAR_WHITESPACE) {
777 290           token_node->type ^= (token_node->type & MyHTML_TOKEN_TYPE_WHITESPACE);
778 290           token_node->type |= MyHTML_TOKEN_TYPE_DATA;
779             }
780            
781 4291           html_offset++;
782             }
783            
784 921           return html_offset;
785             }
786              
787             /////////////////////////////////////////////////////////
788             //// inside of tag
789             //// <%HERE%div>
790             /////////////////////////////////////////////////////////
791 849           size_t myhtml_tokenizer_state_tag_open(myhtml_tree_t* tree, myhtml_token_node_t* token_node, const char* html, size_t html_offset, size_t html_size)
792             {
793 849 100         if(mycore_tokenizer_chars_map[ (unsigned char)html[html_offset] ] == MyCORE_STRING_MAP_CHAR_A_Z_a_z)
794             {
795 377           token_node = myhtml_tokenizer_queue_create_text_node_if_need(tree, token_node, html, ((tree->global_offset + html_offset) - 1), MyHTML_TOKEN_TYPE_DATA);
796 377 50         if(token_node == NULL) {
797 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_PARSE_ERROR_STOP;
798 0           return 0;
799             }
800            
801 377           token_node->raw_begin = tree->global_offset + html_offset;
802            
803 377           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_TAG_NAME;
804             }
805 472 100         else if(html[html_offset] == '!')
806             {
807 97           token_node = myhtml_tokenizer_queue_create_text_node_if_need(tree, token_node, html, ((tree->global_offset + html_offset) - 1), MyHTML_TOKEN_TYPE_DATA);
808 97 50         if(token_node == NULL) {
809 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_PARSE_ERROR_STOP;
810 0           return 0;
811             }
812            
813 97           html_offset++;
814 97           token_node->raw_begin = tree->global_offset + html_offset;
815            
816 97           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_MARKUP_DECLARATION_OPEN;
817             }
818 375 50         else if(html[html_offset] == '/')
819             {
820 375           html_offset++;
821 375           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_END_TAG_OPEN;
822             }
823 0 0         else if(html[html_offset] == '?')
824             {
825             // parse error
826             /* %EXTERNAL% VALIDATOR:TOKENIZER POSITION STATUS:CHAR_BAD LEVEL:ERROR BEGIN:html_offset LENGTH:1 */
827            
828 0           token_node = myhtml_tokenizer_queue_create_text_node_if_need(tree, token_node, html, ((tree->global_offset + html_offset) - 1), MyHTML_TOKEN_TYPE_DATA);
829 0 0         if(token_node == NULL) {
830 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_PARSE_ERROR_STOP;
831 0           return 0;
832             }
833            
834 0           token_node->raw_begin = tree->global_offset + html_offset;
835            
836 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_BOGUS_COMMENT;
837             }
838             else {
839             // parse error
840             /* %EXTERNAL% VALIDATOR:TOKENIZER POSITION STATUS:NOT_EXPECTED LEVEL:ERROR BEGIN:html_offset LENGTH:1 */
841            
842 0           token_node->type ^= (token_node->type & MyHTML_TOKEN_TYPE_WHITESPACE);
843 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_DATA;
844             }
845            
846 849           return html_offset;
847             }
848              
849             /////////////////////////////////////////////////////////
850             //// inside of tag
851             ////
852             /////////////////////////////////////////////////////////
853 375           size_t myhtml_tokenizer_state_end_tag_open(myhtml_tree_t* tree, myhtml_token_node_t* token_node, const char* html, size_t html_offset, size_t html_size)
854             {
855 375 50         if(mycore_tokenizer_chars_map[ (unsigned char)html[html_offset] ] == MyCORE_STRING_MAP_CHAR_A_Z_a_z)
856             {
857 375           token_node = myhtml_tokenizer_queue_create_text_node_if_need(tree, token_node, html, ((tree->global_offset + html_offset) - 2), MyHTML_TOKEN_TYPE_DATA);
858 375 50         if(token_node == NULL) {
859 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_PARSE_ERROR_STOP;
860 0           return 0;
861             }
862            
863 375           token_node->raw_begin = tree->global_offset + html_offset;
864 375           token_node->type = MyHTML_TOKEN_TYPE_CLOSE;
865            
866 375           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_TAG_NAME;
867             }
868 0 0         else if(html[html_offset] == '>')
869             {
870             // parse error
871             /* %EXTERNAL% VALIDATOR:TOKENIZER POSITION STATUS:CHAR_BAD LEVEL:ERROR BEGIN:html_offset LENGTH:1 */
872            
873 0           html_offset++;
874 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_DATA;
875             }
876             else {
877             // parse error
878             /* %EXTERNAL% VALIDATOR:TOKENIZER POSITION STATUS:CHAR_BAD LEVEL:ERROR BEGIN:html_offset LENGTH:1 */
879            
880 0           token_node = myhtml_tokenizer_queue_create_text_node_if_need(tree, token_node, html, ((tree->global_offset + html_offset) - 2), MyHTML_TOKEN_TYPE_DATA);
881 0 0         if(token_node == NULL) {
882 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_PARSE_ERROR_STOP;
883 0           return 0;
884             }
885            
886 0           token_node->raw_begin = tree->global_offset + html_offset;
887            
888 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_BOGUS_COMMENT;
889             }
890            
891 375           return html_offset;
892             }
893              
894             /////////////////////////////////////////////////////////
895             //// inside of tag
896             ////
897             /////////////////////////////////////////////////////////
898 97           size_t myhtml_tokenizer_state_markup_declaration_open(myhtml_tree_t* tree, myhtml_token_node_t* token_node, const char* html, size_t html_offset, size_t html_size)
899             {
900 97 50         if((token_node->raw_begin + 2) > (html_size + tree->global_offset)) {
901 0           tree->incoming_buf->length = html_offset;
902 0           return html_size;
903             }
904            
905 97           const char *tagname = myhtml_tree_incomming_buffer_make_data(tree, token_node->raw_begin, 2);
906            
907             // for a comment
908 97 100         if(tagname[0] == '-' && tagname[1] == '-')
    50          
909             {
910 61           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_COMMENT_START;
911            
912 61           html_offset += 2;
913            
914 61           token_node->raw_begin = html_offset + tree->global_offset;
915 61           token_node->raw_length = 0;
916            
917 61           return html_offset;
918             }
919            
920 36 50         if((token_node->raw_begin + 7) > (html_size + tree->global_offset)) {
921 0           tree->incoming_buf->length = html_offset;
922 0           return html_size;
923             }
924            
925 36           tagname = myhtml_tree_incomming_buffer_make_data(tree, token_node->raw_begin, 7);
926            
927 36 50         if(mycore_strncasecmp(tagname, "DOCTYPE", 7) == 0)
928             {
929 36           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_DOCTYPE;
930            
931 36           html_offset = (token_node->raw_begin + 7) - tree->incoming_buf->offset;
932            
933 36           token_node->raw_length = 7;
934 36           token_node->tag_id = MyHTML_TAG__DOCTYPE;
935            
936 36           return html_offset;
937             }
938            
939             // CDATA sections can only be used in foreign content (MathML or SVG)
940 0 0         if(strncmp(tagname, "[CDATA[", 7) == 0) {
941 0 0         if(tree->current_qnode->prev && tree->current_qnode->prev->args)
    0          
942             {
943 0           myhtml_tree_wait_for_last_done_token(tree, tree->current_qnode->prev->args);
944 0           myhtml_tree_node_t *adjusted_current_node = myhtml_tree_adjusted_current_node(tree);
945            
946 0 0         if(adjusted_current_node &&
947 0 0         adjusted_current_node->ns != MyHTML_NAMESPACE_HTML)
948             {
949 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_CDATA_SECTION;
950            
951 0           html_offset = (token_node->raw_begin + 7) - tree->incoming_buf->offset;
952            
953 0           token_node->raw_begin += 7;
954 0           token_node->raw_length = 0;
955 0           token_node->tag_id = MyHTML_TAG__TEXT;
956 0           token_node->type ^= (token_node->type & MyHTML_TOKEN_TYPE_WHITESPACE);
957            
958 0           return html_offset;
959             }
960             }
961             }
962            
963 0           token_node->raw_length = 0;
964            
965 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_BOGUS_COMMENT;
966 0           return html_offset;
967             }
968              
969             /////////////////////////////////////////////////////////
970             //// inside of tag
971             //// <%HERE%
972             /////////////////////////////////////////////////////////
973 753           size_t myhtml_tokenizer_state_tag_name(myhtml_tree_t* tree, myhtml_token_node_t* token_node, const char* html, size_t html_offset, size_t html_size)
974             {
975 2450 100         while(html_offset < html_size)
976             {
977 2448 100         if(mycore_tokenizer_chars_map[ (unsigned char)html[html_offset] ] == MyCORE_STRING_MAP_CHAR_WHITESPACE)
978             {
979 118           token_node->raw_length = (tree->global_offset + html_offset) - token_node->raw_begin;
980 118           myhtml_check_tag_parser(tree, token_node, html, html_offset);
981            
982 118           html_offset++;
983 118           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_BEFORE_ATTRIBUTE_NAME;
984            
985 118           break;
986             }
987 2330 50         else if(html[html_offset] == '/')
988             {
989 0           token_node->raw_length = (tree->global_offset + html_offset) - token_node->raw_begin;
990 0           myhtml_check_tag_parser(tree, token_node, html, html_offset);
991            
992 0           html_offset++;
993 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_SELF_CLOSING_START_TAG;
994            
995 0           break;
996             }
997 2330 100         else if(html[html_offset] == '>')
998             {
999 633           token_node->raw_length = (tree->global_offset + html_offset) - token_node->raw_begin;
1000            
1001 633           myhtml_check_tag_parser(tree, token_node, html, html_offset);
1002 633           myhtml_tokenizer_set_state(tree, token_node);
1003            
1004 633           html_offset++;
1005            
1006 633           token_node->element_length = (tree->global_offset + html_offset) - token_node->element_begin;
1007            
1008 633 50         if(myhtml_queue_add(tree, html_offset, token_node) != MyHTML_STATUS_OK) {
1009 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_PARSE_ERROR_STOP;
1010 0           return 0;
1011             }
1012            
1013 633           break;
1014             }
1015            
1016 1697           html_offset++;
1017             }
1018            
1019 753           return html_offset;
1020             }
1021              
1022             /////////////////////////////////////////////////////////
1023             //// inside of tag
1024             //// <%HERE%
1025             /////////////////////////////////////////////////////////
1026 0           size_t myhtml_tokenizer_state_self_closing_start_tag(myhtml_tree_t* tree, myhtml_token_node_t* token_node, const char* html, size_t html_offset, size_t html_size)
1027             {
1028 0 0         if(html[html_offset] == '>') {
1029 0           token_node->type |= MyHTML_TOKEN_TYPE_CLOSE_SELF;
1030 0           myhtml_tokenizer_set_state(tree, token_node);
1031            
1032 0           html_offset++;
1033            
1034             // TODO: ??????
1035 0           token_node->element_length = (tree->global_offset + html_offset) - token_node->element_begin;
1036            
1037 0 0         if(myhtml_queue_add(tree, html_offset, token_node) != MyHTML_STATUS_OK) {
1038 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_PARSE_ERROR_STOP;
1039 0           return 0;
1040             }
1041             }
1042             else {
1043 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_BEFORE_ATTRIBUTE_NAME;
1044             }
1045            
1046 0           return html_offset;
1047             }
1048              
1049             /////////////////////////////////////////////////////////
1050             //// inside of tag, after tag name
1051             ////
1052             /////////////////////////////////////////////////////////
1053 149           size_t myhtml_tokenizer_state_before_attribute_name(myhtml_tree_t* tree, myhtml_token_node_t* token_node, const char* html, size_t html_offset, size_t html_size)
1054             {
1055             // skip WS
1056 149 50         myhtml_parser_skip_whitespace()
    50          
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
1057            
1058 149 50         if(html_offset >= html_size) {
1059 0           return html_offset;
1060             }
1061            
1062 149 100         if(html[html_offset] == '>')
1063             {
1064 1           myhtml_tokenizer_set_state(tree, token_node);
1065            
1066 1           html_offset++;
1067            
1068 1           token_node->element_length = (tree->global_offset + html_offset) - token_node->element_begin;
1069            
1070 1 50         if(myhtml_queue_add(tree, html_offset, token_node) != MyHTML_STATUS_OK) {
1071 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_PARSE_ERROR_STOP;
1072 0           return 0;
1073             }
1074             }
1075 148 100         else if(html[html_offset] == '/') {
1076 1           token_node->type |= MyHTML_TOKEN_TYPE_CLOSE_SELF;
1077            
1078 1           html_offset++;
1079             }
1080             else {
1081 147 100         myhtml_parser_queue_set_attr(tree, token_node)
1082            
1083 147           tree->attr_current->raw_key_begin = html_offset + tree->global_offset;
1084 147           tree->attr_current->raw_key_length = 0;
1085 147           tree->attr_current->raw_value_begin = 0;
1086 147           tree->attr_current->raw_value_length = 0;
1087            
1088 147 50         if(html[html_offset] == '=') {
1089             // parse error
1090             /* %EXTERNAL% VALIDATOR:TOKENIZER POSITION STATUS:NOT_EXPECTED LEVEL:ERROR BEGIN:html_offset LENGTH:1 */
1091            
1092 0           html_offset++;
1093             }
1094            
1095 147           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_ATTRIBUTE_NAME;
1096             }
1097            
1098 149           return html_offset;
1099             }
1100              
1101             /////////////////////////////////////////////////////////
1102             //// inside of tag, inside of attr key
1103             ////
1104             /////////////////////////////////////////////////////////
1105 153           size_t myhtml_tokenizer_state_attribute_name(myhtml_tree_t* tree, myhtml_token_node_t* token_node, const char* html, size_t html_offset, size_t html_size)
1106             {
1107 997 50         while(html_offset < html_size)
1108             {
1109 997 100         if(myhtml_whithspace(html[html_offset], ==, ||))
    50          
    50          
    50          
    50          
1110             {
1111 6           tree->attr_current->raw_key_length = (tree->global_offset + html_offset) - tree->attr_current->raw_key_begin;
1112 6           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_AFTER_ATTRIBUTE_NAME;
1113            
1114 6           html_offset++;
1115 6           break;
1116             }
1117 991 100         else if(html[html_offset] == '=')
1118             {
1119 147           tree->attr_current->raw_key_length = (tree->global_offset + html_offset) - tree->attr_current->raw_key_begin;
1120 147           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_BEFORE_ATTRIBUTE_VALUE;
1121            
1122 147           html_offset++;
1123 147           break;
1124             }
1125 844 50         else if(html[html_offset] == '>')
1126             {
1127 0           tree->attr_current->raw_key_length = (tree->global_offset + html_offset) - tree->attr_current->raw_key_begin;
1128 0           myhtml_tokenizer_set_state(tree, token_node);
1129            
1130 0           html_offset++;
1131            
1132 0           token_node->element_length = (tree->global_offset + html_offset) - token_node->element_begin;
1133            
1134 0 0         if(myhtml_queue_add(tree, html_offset, token_node) != MyHTML_STATUS_OK) {
1135 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_PARSE_ERROR_STOP;
1136 0           return 0;
1137             }
1138            
1139 0           tree->attr_current = myhtml_token_attr_create(tree->token, tree->token->mcasync_attr_id);
1140 0 0         if(tree->attr_current == NULL) {
1141 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_PARSE_ERROR_STOP;
1142 0           return 0;
1143             }
1144            
1145 0           break;
1146             }
1147 844 50         else if(html[html_offset] == '/')
1148             {
1149 0           tree->attr_current->raw_key_length = (tree->global_offset + html_offset) - tree->attr_current->raw_key_begin;
1150            
1151 0           token_node->type |= MyHTML_TOKEN_TYPE_CLOSE_SELF;
1152 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_BEFORE_ATTRIBUTE_NAME;
1153            
1154 0           tree->attr_current = myhtml_token_attr_create(tree->token, tree->token->mcasync_attr_id);
1155 0 0         if(tree->attr_current == NULL) {
1156 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_PARSE_ERROR_STOP;
1157 0           return 0;
1158             }
1159            
1160 0           html_offset++;
1161 0           break;
1162             }
1163            
1164 844           html_offset++;
1165             }
1166            
1167 153           return html_offset;
1168             }
1169              
1170             /////////////////////////////////////////////////////////
1171             //// inside of tag, after attr key
1172             ////
1173             /////////////////////////////////////////////////////////
1174 6           size_t myhtml_tokenizer_state_after_attribute_name(myhtml_tree_t* tree, myhtml_token_node_t* token_node, const char* html, size_t html_offset, size_t html_size)
1175             {
1176 6 50         while(html_offset < html_size)
1177             {
1178 6 50         if(html[html_offset] == '=')
1179             {
1180 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_BEFORE_ATTRIBUTE_VALUE;
1181            
1182 0           html_offset++;
1183 0           break;
1184             }
1185 6 50         else if(html[html_offset] == '>')
1186             {
1187 0           myhtml_tokenizer_set_state(tree, token_node);
1188            
1189 0           html_offset++;
1190            
1191 0           token_node->element_length = (tree->global_offset + html_offset) - token_node->element_begin;
1192            
1193 0 0         if(myhtml_queue_add(tree, html_offset, token_node) != MyHTML_STATUS_OK) {
1194 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_PARSE_ERROR_STOP;
1195 0           return 0;
1196             }
1197            
1198 0           tree->attr_current = myhtml_token_attr_create(tree->token, tree->token->mcasync_attr_id);
1199 0 0         if(tree->attr_current == NULL) {
1200 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_PARSE_ERROR_STOP;
1201 0           return 0;
1202             }
1203            
1204 0           break;
1205             }
1206 6 50         else if(html[html_offset] == '"' || html[html_offset] == '\'' || html[html_offset] == '<')
    50          
    50          
1207             {
1208 0           tree->attr_current = myhtml_token_attr_create(tree->token, tree->token->mcasync_attr_id);
1209 0 0         if(tree->attr_current == NULL) {
1210 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_PARSE_ERROR_STOP;
1211 0           return 0;
1212             }
1213            
1214 0 0         myhtml_parser_queue_set_attr(tree, token_node)
1215            
1216 0           tree->attr_current->raw_key_begin = (tree->global_offset + html_offset);
1217 0           tree->attr_current->raw_key_length = 0;
1218 0           tree->attr_current->raw_value_begin = 0;
1219 0           tree->attr_current->raw_value_length = 0;
1220            
1221 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_ATTRIBUTE_NAME;
1222 0           break;
1223             }
1224 6 50         else if(myhtml_whithspace(html[html_offset], !=, &&))
    50          
    50          
    50          
    50          
1225             {
1226 6           tree->attr_current = myhtml_token_attr_create(tree->token, tree->token->mcasync_attr_id);
1227 6 50         if(tree->attr_current == NULL) {
1228 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_PARSE_ERROR_STOP;
1229 0           return 0;
1230             }
1231            
1232 6 50         myhtml_parser_queue_set_attr(tree, token_node)
1233            
1234 6           tree->attr_current->raw_key_begin = (html_offset + tree->global_offset);
1235 6           tree->attr_current->raw_key_length = 0;
1236 6           tree->attr_current->raw_value_begin = 0;
1237 6           tree->attr_current->raw_value_length = 0;
1238            
1239 6           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_ATTRIBUTE_NAME;
1240 6           break;
1241             }
1242            
1243 0           html_offset++;
1244             }
1245            
1246 6           return html_offset;
1247             }
1248              
1249             /////////////////////////////////////////////////////////
1250             //// inside of tag, after attr key
1251             ////
1252             /////////////////////////////////////////////////////////
1253 147           size_t myhtml_tokenizer_state_before_attribute_value(myhtml_tree_t* tree, myhtml_token_node_t* token_node, const char* html, size_t html_offset, size_t html_size)
1254             {
1255 147 50         while(html_offset < html_size)
1256             {
1257 147 50         if(html[html_offset] == '>') {
1258             // parse error
1259             /* %EXTERNAL% VALIDATOR:TOKENIZER POSITION STATUS:NOT_EXPECTED LEVEL:ERROR BEGIN:html_offset LENGTH:1 */
1260            
1261 0           myhtml_tokenizer_set_state(tree, token_node);
1262            
1263 0           html_offset++;
1264            
1265 0           token_node->element_length = (tree->global_offset + html_offset) - token_node->element_begin;
1266            
1267 0 0         if(myhtml_queue_add(tree, html_offset, token_node) != MyHTML_STATUS_OK) {
1268 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_PARSE_ERROR_STOP;
1269 0           return 0;
1270             }
1271            
1272 0           tree->attr_current = myhtml_token_attr_create(tree->token, tree->token->mcasync_attr_id);
1273 0 0         if(tree->attr_current == NULL) {
1274 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_PARSE_ERROR_STOP;
1275 0           return 0;
1276             }
1277            
1278 0           break;
1279             }
1280 147 50         else if(myhtml_whithspace(html[html_offset], !=, &&))
    50          
    50          
    50          
    50          
1281             {
1282 147 50         if(html[html_offset] == '"') {
1283 147           html_offset++;
1284 147           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_ATTRIBUTE_VALUE_DOUBLE_QUOTED;
1285             }
1286 0 0         else if(html[html_offset] == '\'') {
1287 0           html_offset++;
1288 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_ATTRIBUTE_VALUE_SINGLE_QUOTED;
1289             }
1290             else {
1291 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_ATTRIBUTE_VALUE_UNQUOTED;
1292             }
1293            
1294 147           tree->attr_current->raw_value_begin = (tree->global_offset + html_offset);
1295            
1296 147           break;
1297             }
1298            
1299 0           html_offset++;
1300             }
1301            
1302 147           return html_offset;
1303             }
1304              
1305             /////////////////////////////////////////////////////////
1306             //// inside of tag, inside of attr value
1307             ////
1308             /////////////////////////////////////////////////////////
1309 147           size_t myhtml_tokenizer_state_attribute_value_double_quoted(myhtml_tree_t* tree, myhtml_token_node_t* token_node, const char* html, size_t html_offset, size_t html_size)
1310             {
1311             //myhtml_t* myhtml = tree->myhtml;
1312            
1313 967 50         while(html_offset < html_size)
1314             {
1315 967 100         if(html[html_offset] == '"')
1316             {
1317 147           tree->attr_current->raw_value_length = (tree->global_offset + html_offset) - tree->attr_current->raw_value_begin;
1318            
1319 147           tree->attr_current = myhtml_token_attr_create(tree->token, tree->token->mcasync_attr_id);
1320 147 50         if(tree->attr_current == NULL) {
1321 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_PARSE_ERROR_STOP;
1322 0           return 0;
1323             }
1324            
1325 147           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_AFTER_ATTRIBUTE_VALUE_QUOTED;
1326            
1327 147           html_offset++;
1328 147           break;
1329             }
1330            
1331 820           html_offset++;
1332             }
1333            
1334 147           return html_offset;
1335             }
1336              
1337             /////////////////////////////////////////////////////////
1338             //// inside of tag, inside of attr value
1339             ////
1340             /////////////////////////////////////////////////////////
1341 0           size_t myhtml_tokenizer_state_attribute_value_single_quoted(myhtml_tree_t* tree, myhtml_token_node_t* token_node, const char* html, size_t html_offset, size_t html_size)
1342             {
1343             //myhtml_t* myhtml = tree->myhtml;
1344            
1345 0 0         while(html_offset < html_size)
1346             {
1347 0 0         if(html[html_offset] == '\'')
1348             {
1349 0           tree->attr_current->raw_value_length = (tree->global_offset + html_offset) - tree->attr_current->raw_value_begin;
1350            
1351 0           tree->attr_current = myhtml_token_attr_create(tree->token, tree->token->mcasync_attr_id);
1352 0 0         if(tree->attr_current == NULL) {
1353 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_PARSE_ERROR_STOP;
1354 0           return 0;
1355             }
1356            
1357 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_AFTER_ATTRIBUTE_VALUE_QUOTED;
1358            
1359 0           html_offset++;
1360 0           break;
1361             }
1362            
1363 0           html_offset++;
1364             }
1365            
1366 0           return html_offset;
1367             }
1368              
1369             /////////////////////////////////////////////////////////
1370             //// inside of tag, inside of attr value
1371             ////
1372             /////////////////////////////////////////////////////////
1373 0           size_t myhtml_tokenizer_state_attribute_value_unquoted(myhtml_tree_t* tree, myhtml_token_node_t* token_node, const char* html, size_t html_offset, size_t html_size)
1374             {
1375 0 0         while(html_offset < html_size)
1376             {
1377 0 0         if(myhtml_whithspace(html[html_offset], ==, ||))
    0          
    0          
    0          
    0          
1378             {
1379 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_BEFORE_ATTRIBUTE_NAME;
1380            
1381 0           tree->attr_current->raw_value_length = (tree->global_offset + html_offset) - tree->attr_current->raw_value_begin;
1382            
1383 0           tree->attr_current = myhtml_token_attr_create(tree->token, tree->token->mcasync_attr_id);
1384 0 0         if(tree->attr_current == NULL) {
1385 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_PARSE_ERROR_STOP;
1386 0           return 0;
1387             }
1388            
1389 0           html_offset++;
1390 0           break;
1391             }
1392 0 0         else if(html[html_offset] == '>') {
1393             // parse error
1394             /* %EXTERNAL% VALIDATOR:TOKENIZER POSITION STATUS:UNSAFE_USE LEVEL:INFO BEGIN:html_offset LENGTH:1 */
1395            
1396 0           tree->attr_current->raw_value_length = (tree->global_offset + html_offset) - tree->attr_current->raw_value_begin;
1397            
1398 0           myhtml_tokenizer_set_state(tree, token_node);
1399            
1400 0           html_offset++;
1401            
1402 0           token_node->element_length = (tree->global_offset + html_offset) - token_node->element_begin;
1403            
1404 0 0         if(myhtml_queue_add(tree, html_offset, token_node) != MyHTML_STATUS_OK) {
1405 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_PARSE_ERROR_STOP;
1406 0           return 0;
1407             }
1408            
1409 0           tree->attr_current = myhtml_token_attr_create(tree->token, tree->token->mcasync_attr_id);
1410 0 0         if(tree->attr_current == NULL) {
1411 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_PARSE_ERROR_STOP;
1412 0           return 0;
1413             }
1414            
1415 0           break;
1416             }
1417            
1418 0           html_offset++;
1419             }
1420            
1421 0           return html_offset;
1422             }
1423              
1424 147           size_t myhtml_tokenizer_state_after_attribute_value_quoted(myhtml_tree_t* tree, myhtml_token_node_t* token_node, const char* html, size_t html_offset, size_t html_size)
1425             {
1426 147 100         if(myhtml_whithspace(html[html_offset], ==, ||)) {
    50          
    50          
    50          
    50          
1427 30           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_BEFORE_ATTRIBUTE_NAME;
1428 30           html_offset++;
1429             }
1430 117 50         else if(html[html_offset] == '/') {
1431 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_SELF_CLOSING_START_TAG;
1432 0           html_offset++;
1433             }
1434 117 50         else if(html[html_offset] == '>') {
1435 117           myhtml_tokenizer_set_state(tree, token_node);
1436            
1437 117           html_offset++;
1438            
1439 117           token_node->element_length = (tree->global_offset + html_offset) - token_node->element_begin;
1440            
1441 117 50         if(myhtml_queue_add(tree, html_offset, token_node) != MyHTML_STATUS_OK) {
1442 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_PARSE_ERROR_STOP;
1443 0           return 0;
1444             }
1445             }
1446             else {
1447 0           myhtml_tokenizer_state_set(tree) = MyHTML_TOKENIZER_STATE_BEFORE_ATTRIBUTE_NAME;
1448             }
1449            
1450 147           return html_offset;
1451             }
1452              
1453             /////////////////////////////////////////////////////////
1454             //// COMMENT
1455             ////