File Coverage

third_party/modest/source/myhtml/myhtml.c
Criterion Covered Total %
statement 403 808 49.8
branch 238 628 37.9
condition n/a
subroutine n/a
pod n/a
total 641 1436 44.6


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/myhtml.h"
22              
23 115           void myhtml_init_marker(myhtml_t* myhtml)
24             {
25 115           myhtml->marker = (myhtml_tree_node_t*)mycore_malloc(sizeof(myhtml_tree_node_t));
26            
27 115 50         if(myhtml->marker)
28 115           myhtml_tree_node_clean(myhtml->marker);
29 115           }
30              
31 115           void myhtml_destroy_marker(myhtml_t* myhtml)
32             {
33 115 50         if(myhtml->marker)
34 115           mycore_free(myhtml->marker);
35 115           }
36              
37             #ifndef MyCORE_BUILD_WITHOUT_THREADS
38 115           mystatus_t myhtml_stream_create(myhtml_t* myhtml, mystatus_t* status, size_t count, size_t id_increase)
39             {
40 115 100         if(count == 0) {
41 108           myhtml->thread_stream = NULL;
42            
43 108           *status = MyHTML_STATUS_OK;
44 108           return *status;
45             }
46            
47 7           myhtml->thread_stream = mythread_create();
48 7 50         if(myhtml->thread_stream == NULL)
49 0           *status = MyCORE_STATUS_THREAD_ERROR_MEMORY_ALLOCATION;
50            
51 7           *status = mythread_init(myhtml->thread_stream, MyTHREAD_TYPE_STREAM, count, id_increase);
52            
53 7 50         if(*status)
54 0           myhtml->thread_stream = mythread_destroy(myhtml->thread_stream, NULL, NULL, true);
55            
56 7           return *status;
57             }
58              
59 115           mystatus_t myhtml_batch_create(myhtml_t* myhtml, mystatus_t* status, size_t count, size_t id_increase)
60             {
61 115 100         if(count == 0) {
62 108           myhtml->thread_batch = NULL;
63            
64 108           *status = MyHTML_STATUS_OK;
65 108           return *status;
66             }
67            
68 7           myhtml->thread_batch = mythread_create();
69 7 50         if(myhtml->thread_stream == NULL) {
70 0           myhtml->thread_stream = mythread_destroy(myhtml->thread_stream, NULL, NULL, true);
71 0           *status = MyCORE_STATUS_THREAD_ERROR_MEMORY_ALLOCATION;
72             }
73            
74 7           *status = mythread_init(myhtml->thread_batch, MyTHREAD_TYPE_BATCH, count, id_increase);
75            
76 7 50         if(*status)
77 0           myhtml->thread_batch = mythread_destroy(myhtml->thread_batch , NULL, NULL, true);
78            
79 7           return *status;
80             }
81              
82 115           mystatus_t myhtml_create_stream_and_batch(myhtml_t* myhtml, size_t stream_count, size_t batch_count)
83             {
84             mystatus_t status;
85            
86             /* stream */
87 115 50         if(myhtml_stream_create(myhtml, &status, stream_count, 0)) {
88 0           return status;
89             }
90            
91             /* batch */
92 115 50         if(myhtml_batch_create(myhtml, &status, batch_count, stream_count)) {
93 0           myhtml->thread_stream = mythread_destroy(myhtml->thread_stream, NULL, NULL, true);
94 0           return status;
95             }
96            
97 115           return status;
98             }
99             #endif /* if undef MyCORE_BUILD_WITHOUT_THREADS */
100              
101 115           myhtml_t * myhtml_create(void)
102             {
103 115           return (myhtml_t*)mycore_calloc(1, sizeof(myhtml_t));
104             }
105              
106 115           mystatus_t myhtml_init(myhtml_t* myhtml, enum myhtml_options opt, size_t thread_count, size_t queue_size)
107             {
108             mystatus_t status;
109            
110 115           myhtml->opt = opt;
111 115           myhtml_init_marker(myhtml);
112            
113 115           status = myhtml_tokenizer_state_init(myhtml);
114 115 50         if(status)
115 0           return status;
116            
117 115           status = myhtml_rules_init(myhtml);
118              
119             #ifdef MyCORE_BUILD_WITHOUT_THREADS
120            
121             myhtml->thread_stream = NULL;
122             myhtml->thread_batch = NULL;
123             myhtml->thread_total = 0;
124            
125             #else /* if undef MyCORE_BUILD_WITHOUT_THREADS */
126 115 50         if(status)
127 0           return status;
128              
129 115 50         if(thread_count == 0) {
130 0           thread_count = 1;
131             }
132              
133 115           switch (opt) {
134             case MyHTML_OPTIONS_PARSE_MODE_SINGLE:
135 108 50         if((status = myhtml_create_stream_and_batch(myhtml, 0, 0)))
136 0           return status;
137            
138 108           break;
139            
140             case MyHTML_OPTIONS_PARSE_MODE_ALL_IN_ONE:
141 0 0         if((status = myhtml_create_stream_and_batch(myhtml, 1, 0)))
142 0           return status;
143            
144 0           myhtml->thread_stream->context = mythread_queue_list_create(&status);
145 0           status = myhread_entry_create(myhtml->thread_stream, mythread_function_queue_stream, myhtml_parser_worker_stream, MyTHREAD_OPT_STOP);
146            
147 0           break;
148            
149             default:
150             // default MyHTML_OPTIONS_PARSE_MODE_SEPARATELY
151 7 50         if(thread_count < 2)
152 0           thread_count = 2;
153            
154 7 50         if((status = myhtml_create_stream_and_batch(myhtml, 1, (thread_count - 1))))
155 0           return status;
156            
157 7           myhtml->thread_stream->context = mythread_queue_list_create(&status);
158 7           myhtml->thread_batch->context = myhtml->thread_stream->context;
159            
160 7           status = myhread_entry_create(myhtml->thread_stream, mythread_function_queue_stream, myhtml_parser_stream, MyTHREAD_OPT_STOP);
161 7 50         if(status)
162 0           return status;
163            
164 14 100         for(size_t i = 0; i < myhtml->thread_batch->entries_size; i++) {
165 7           status = myhread_entry_create(myhtml->thread_batch, mythread_function_queue_batch, myhtml_parser_worker, MyTHREAD_OPT_STOP);
166            
167 7 50         if(status)
168 0           return status;
169             }
170            
171 7           break;
172             }
173            
174 115           myhtml->thread_total = thread_count;
175            
176 115           myhtml->thread_list[0] = myhtml->thread_stream;
177 115           myhtml->thread_list[1] = myhtml->thread_batch;
178 115           myhtml->thread_list[2] = NULL;
179            
180             #endif /* if undef MyCORE_BUILD_WITHOUT_THREADS */
181            
182 115 50         if(status)
183 0           return status;
184            
185 115           myhtml_clean(myhtml);
186            
187 115           return status;
188             }
189              
190 115           void myhtml_clean(myhtml_t* myhtml)
191             {
192             /* some code */
193 115           }
194              
195 115           myhtml_t* myhtml_destroy(myhtml_t* myhtml)
196             {
197 115 50         if(myhtml == NULL)
198 0           return NULL;
199            
200 115           myhtml_destroy_marker(myhtml);
201            
202             #ifndef MyCORE_BUILD_WITHOUT_THREADS
203 115 100         if(myhtml->thread_stream) {
204 7           mythread_queue_list_t* queue_list = myhtml->thread_stream->context;
205              
206 7 50         if(queue_list)
207 7           mythread_queue_list_wait_for_done(myhtml->thread_stream, queue_list);
208            
209 7           myhtml->thread_stream = mythread_destroy(myhtml->thread_stream, mythread_callback_quit, NULL, true);
210            
211 7 50         if(myhtml->thread_batch)
212 7           myhtml->thread_batch = mythread_destroy(myhtml->thread_batch, mythread_callback_quit, NULL, true);
213            
214 7 50         if(queue_list)
215 7           mythread_queue_list_destroy(queue_list);
216             }
217             #endif /* if undef MyCORE_BUILD_WITHOUT_THREADS */
218            
219 115           myhtml_tokenizer_state_destroy(myhtml);
220            
221 115 50         if(myhtml->insertion_func)
222 115           mycore_free(myhtml->insertion_func);
223            
224 115           mycore_free(myhtml);
225            
226 115           return NULL;
227             }
228              
229 126           mystatus_t myhtml_parse(myhtml_tree_t* tree, myencoding_t encoding, const char* html, size_t html_size)
230             {
231 126 50         if(tree->flags & MyHTML_TREE_FLAGS_PARSE_END) {
232 0           myhtml_tree_clean(tree);
233             }
234            
235 126           myhtml_encoding_set(tree, encoding);
236 126           mystatus_t status = myhtml_tokenizer_begin(tree, html, html_size);
237            
238 126 50         if(status)
239 0           return status;
240            
241 126           return myhtml_tokenizer_end(tree);
242             }
243              
244 17           mystatus_t myhtml_parse_fragment(myhtml_tree_t* tree, myencoding_t encoding, const char* html, size_t html_size, myhtml_tag_id_t tag_id, enum myhtml_namespace ns)
245             {
246 17 50         if(tree->flags & MyHTML_TREE_FLAGS_PARSE_END) {
247 0           myhtml_tree_clean(tree);
248             }
249            
250 17 50         if(tag_id == 0)
251 0           tag_id = MyHTML_TAG_DIV;
252            
253 17 50         if(ns == 0)
254 0           ns = MyHTML_NAMESPACE_HTML;
255            
256 17 50         if(myhtml_tokenizer_fragment_init(tree, tag_id, ns) == NULL)
257 0           return MyHTML_STATUS_TOKENIZER_ERROR_FRAGMENT_INIT;
258            
259 17           myhtml_encoding_set(tree, encoding);
260 17           mystatus_t status = myhtml_tokenizer_begin(tree, html, html_size);
261            
262 17 50         if(status)
263 0           return status;
264            
265 17           return myhtml_tokenizer_end(tree);
266             }
267              
268 0           mystatus_t myhtml_parse_single(myhtml_tree_t* tree, myencoding_t encoding, const char* html, size_t html_size)
269             {
270 0 0         if(tree->flags & MyHTML_TREE_FLAGS_PARSE_END) {
271 0           myhtml_tree_clean(tree);
272             }
273            
274 0           tree->flags |= MyHTML_TREE_FLAGS_SINGLE_MODE;
275            
276 0           myhtml_encoding_set(tree, encoding);
277            
278 0           mystatus_t status = myhtml_tokenizer_begin(tree, html, html_size);
279            
280 0 0         if(status)
281 0           return status;
282            
283 0           return myhtml_tokenizer_end(tree);
284             }
285              
286 0           mystatus_t myhtml_parse_fragment_single(myhtml_tree_t* tree, myencoding_t encoding, const char* html, size_t html_size, myhtml_tag_id_t tag_id, enum myhtml_namespace ns)
287             {
288 0 0         if(tree->flags & MyHTML_TREE_FLAGS_PARSE_END) {
289 0           myhtml_tree_clean(tree);
290             }
291            
292 0 0         if(tag_id == 0)
293 0           tag_id = MyHTML_TAG_DIV;
294            
295 0 0         if(ns == 0)
296 0           ns = MyHTML_NAMESPACE_HTML;
297            
298 0           tree->flags |= MyHTML_TREE_FLAGS_SINGLE_MODE;
299            
300 0 0         if(myhtml_tokenizer_fragment_init(tree, tag_id, ns) == NULL)
301 0           return MyHTML_STATUS_TOKENIZER_ERROR_FRAGMENT_INIT;
302            
303 0           myhtml_encoding_set(tree, encoding);
304            
305 0           mystatus_t status = myhtml_tokenizer_begin(tree, html, html_size);
306            
307 0 0         if(status)
308 0           return status;
309            
310 0           return myhtml_tokenizer_end(tree);
311             }
312              
313 5           mystatus_t myhtml_parse_chunk(myhtml_tree_t* tree, const char* html, size_t html_size)
314             {
315 5 50         if(tree->flags & MyHTML_TREE_FLAGS_PARSE_END) {
316 0           myhtml_tree_clean(tree);
317             }
318            
319 5           return myhtml_tokenizer_chunk(tree, html, html_size);
320             }
321              
322 0           mystatus_t myhtml_parse_chunk_fragment(myhtml_tree_t* tree, const char* html, size_t html_size, myhtml_tag_id_t tag_id, enum myhtml_namespace ns)
323             {
324 0 0         if(tree->flags & MyHTML_TREE_FLAGS_PARSE_END) {
325 0           myhtml_tree_clean(tree);
326             }
327            
328 0 0         if(tag_id == 0)
329 0           tag_id = MyHTML_TAG_DIV;
330            
331 0 0         if(ns == 0)
332 0           ns = MyHTML_NAMESPACE_HTML;
333            
334 0 0         if(myhtml_tokenizer_fragment_init(tree, tag_id, ns) == NULL)
335 0           return MyHTML_STATUS_TOKENIZER_ERROR_FRAGMENT_INIT;
336            
337 0           return myhtml_tokenizer_chunk(tree, html, html_size);
338             }
339              
340 0           mystatus_t myhtml_parse_chunk_single(myhtml_tree_t* tree, const char* html, size_t html_size)
341             {
342 0 0         if((tree->flags & MyHTML_TREE_FLAGS_SINGLE_MODE) == 0)
343 0           tree->flags |= MyHTML_TREE_FLAGS_SINGLE_MODE;
344            
345 0           return myhtml_parse_chunk(tree, html, html_size);
346             }
347              
348 0           mystatus_t myhtml_parse_chunk_fragment_single(myhtml_tree_t* tree, const char* html, size_t html_size, myhtml_tag_id_t tag_id, enum myhtml_namespace ns)
349             {
350 0 0         if((tree->flags & MyHTML_TREE_FLAGS_SINGLE_MODE) == 0)
351 0           tree->flags |= MyHTML_TREE_FLAGS_SINGLE_MODE;
352            
353 0           return myhtml_parse_chunk_fragment(tree, html, html_size, tag_id, ns);
354             }
355              
356 2           mystatus_t myhtml_parse_chunk_end(myhtml_tree_t* tree)
357             {
358 2           return myhtml_tokenizer_end(tree);
359             }
360              
361 147           void myhtml_encoding_set(myhtml_tree_t* tree, myencoding_t encoding)
362             {
363 147 50         if(encoding >= MyENCODING_LAST_ENTRY)
364 0           return;
365            
366 147           tree->encoding_usereq = encoding;
367 147           tree->encoding = encoding;
368             }
369              
370 0           myencoding_t myhtml_encoding_get(myhtml_tree_t* tree)
371             {
372 0           return tree->encoding;
373             }
374              
375             /*
376             * Nodes
377             */
378              
379 64           mystatus_t myhtml_get_nodes_by_tag_id_in_scope_find_recursion(myhtml_tree_node_t *node, myhtml_collection_t *collection, myhtml_tag_id_t tag_id)
380             {
381 544 100         while(node) {
382 480 100         if(node->tag_id == tag_id) {
383 64           collection->list[ collection->length ] = node;
384 64           collection->length++;
385            
386 64 50         if(collection->length >= collection->size)
387             {
388 0           mystatus_t mystatus = myhtml_collection_check_size(collection, 1024, 0);
389            
390 0 0         if(mystatus != MyHTML_STATUS_OK)
391 0           return mystatus;
392             }
393             }
394            
395 480 100         if(node->child)
396 48           myhtml_get_nodes_by_tag_id_in_scope_find_recursion(node->child, collection, tag_id);
397            
398 480           node = node->next;
399             }
400            
401 64           return MyHTML_STATUS_OK;
402             }
403              
404 16           myhtml_collection_t * myhtml_get_nodes_by_tag_id_in_scope(myhtml_tree_t* tree, myhtml_collection_t *collection, myhtml_tree_node_t *node, myhtml_tag_id_t tag_id, mystatus_t *status)
405             {
406 16 50         if(node == NULL)
407 0           return NULL;
408            
409 16           mystatus_t mystatus = MyHTML_STATUS_OK;
410            
411 16 50         if(collection == NULL) {
412 16           collection = myhtml_collection_create(1024, &mystatus);
413             }
414            
415 16 50         if(mystatus) {
416 0 0         if(status)
417 0           *status = mystatus;
418            
419 0           return collection;
420             }
421            
422 16 50         if(node->child)
423 16           mystatus = myhtml_get_nodes_by_tag_id_in_scope_find_recursion(node->child, collection, tag_id);
424            
425 16           collection->list[collection->length] = NULL;
426            
427 16 50         if(status)
428 0           *status = mystatus;
429            
430 16           return collection;
431             }
432              
433 24           myhtml_collection_t * myhtml_get_nodes_by_name_in_scope(myhtml_tree_t* tree, myhtml_collection_t *collection, myhtml_tree_node_t *node, const char* html, size_t length, mystatus_t *status)
434             {
435 24           const myhtml_tag_context_t *tag_ctx = myhtml_tag_get_by_name(tree->tags, html, length);
436 24 100         if(tag_ctx == NULL) {
437 8           return NULL;
438             }
439 16           return myhtml_get_nodes_by_tag_id_in_scope(tree, collection, node, tag_ctx->id, status);
440             }
441              
442 0           myhtml_collection_t * myhtml_get_nodes_by_tag_id(myhtml_tree_t* tree, myhtml_collection_t *collection, myhtml_tag_id_t tag_id, mystatus_t *status)
443             {
444 0 0         if(collection == NULL) {
445 0           collection = myhtml_collection_create(1024, NULL);
446            
447 0 0         if(collection == NULL)
448 0           return NULL;
449             }
450            
451 0           myhtml_tree_node_t *node = tree->node_html;
452            
453 0 0         while(node)
454             {
455 0 0         if(node->tag_id == tag_id)
456             {
457 0 0         if(myhtml_collection_check_size(collection, 1, 1024) == MyHTML_STATUS_OK) {
458 0           collection->list[ collection->length ] = node;
459 0           collection->length++;
460             }
461             else {
462 0 0         if(status)
463 0           *status = MyHTML_STATUS_ERROR_MEMORY_ALLOCATION;
464            
465 0           return collection;
466             }
467             }
468            
469 0 0         if(node->child)
470 0           node = node->child;
471             else {
472 0 0         while(node != tree->node_html && node->next == NULL)
    0          
473 0           node = node->parent;
474            
475 0 0         if(node == tree->node_html)
476 0           break;
477            
478 0           node = node->next;
479             }
480             }
481            
482 0 0         if(myhtml_collection_check_size(collection, 1, 1024) == MyHTML_STATUS_OK) {
483 0           collection->list[ collection->length ] = NULL;
484             }
485 0 0         else if(status) {
486 0           *status = MyHTML_STATUS_ERROR_MEMORY_ALLOCATION;
487             }
488            
489 0           return collection;
490             }
491              
492 0           myhtml_collection_t * myhtml_get_nodes_by_name(myhtml_tree_t* tree, myhtml_collection_t *collection, const char* html, size_t length, mystatus_t *status)
493             {
494 0           const myhtml_tag_context_t *tag_ctx = myhtml_tag_get_by_name(tree->tags, html, length);
495            
496 0 0         if(tag_ctx == NULL)
497 0           return NULL;
498            
499 0           return myhtml_get_nodes_by_tag_id(tree, collection, tag_ctx->id, status);
500             }
501              
502             /*
503             * Manipulate Nodes
504             */
505 0           myhtml_tree_node_t * myhtml_node_first(myhtml_tree_t* tree)
506             {
507 0 0         if(tree->fragment) {
508             // document -> html -> need element
509 0 0         if(tree->document && tree->document->child)
    0          
510 0           return tree->document->child->child;
511             }
512 0 0         else if(tree->document) {
513             // document -> html
514 0           return tree->document->child;
515             }
516            
517 0           return NULL;
518             }
519              
520 1117           myhtml_tree_node_t * myhtml_node_next(myhtml_tree_node_t *node)
521             {
522 1117           return node->next;
523             }
524              
525 60           myhtml_tree_node_t * myhtml_node_prev(myhtml_tree_node_t *node)
526             {
527 60           return node->prev;
528             }
529              
530 1336           myhtml_tree_node_t * myhtml_node_parent(myhtml_tree_node_t *node)
531             {
532 1336           return node->parent;
533             }
534              
535 772           myhtml_tree_node_t * myhtml_node_child(myhtml_tree_node_t *node)
536             {
537 772           return node->child;
538             }
539              
540 20           myhtml_tree_node_t * myhtml_node_last_child(myhtml_tree_node_t *node)
541             {
542 20           return node->last_child;
543             }
544              
545 61           myhtml_tree_node_t * myhtml_node_create(myhtml_tree_t* tree, myhtml_tag_id_t tag_id, enum myhtml_namespace ns)
546             {
547 61           myhtml_tree_node_t *node = myhtml_tree_node_create(tree);
548            
549 61           node->tag_id = tag_id;
550 61           node->ns = ns;
551            
552 61           return node;
553             }
554              
555 0           myhtml_tree_node_t * myhtml_node_remove(myhtml_tree_node_t *node)
556             {
557 0           return myhtml_tree_node_remove(node);
558             }
559              
560 0           void myhtml_node_delete(myhtml_tree_node_t *node)
561             {
562 0           myhtml_tree_node_delete(node);
563 0           }
564              
565 0           void myhtml_node_delete_recursive(myhtml_tree_node_t *node)
566             {
567 0           myhtml_tree_node_delete_recursive(node);
568 0           }
569              
570 0           void myhtml_node_free(myhtml_tree_node_t *node)
571             {
572 0           myhtml_tree_node_free(node);
573 0           }
574              
575 0           myhtml_tree_node_t * myhtml_node_insert_before(myhtml_tree_node_t *target, myhtml_tree_node_t *node)
576             {
577 0 0         if(target == NULL || node == NULL)
    0          
578 0           return NULL;
579            
580 0           myhtml_tree_node_insert_before(target, node);
581            
582 0           return node;
583             }
584              
585 0           myhtml_tree_node_t * myhtml_node_insert_after(myhtml_tree_node_t *target, myhtml_tree_node_t *node)
586             {
587 0 0         if(target == NULL || node == NULL)
    0          
588 0           return NULL;
589            
590 0           myhtml_tree_node_insert_after(target, node);
591            
592 0           return node;
593             }
594              
595 0           myhtml_tree_node_t * myhtml_node_append_child(myhtml_tree_node_t *target, myhtml_tree_node_t *node)
596             {
597 0 0         if(target == NULL || node == NULL)
    0          
598 0           return NULL;
599            
600 0           myhtml_tree_node_add_child(target, node);
601            
602 0           return node;
603             }
604              
605 0           myhtml_tree_node_t * myhtml_node_insert_to_appropriate_place(myhtml_tree_node_t *target, myhtml_tree_node_t *node)
606             {
607 0 0         if(target == NULL || node == NULL)
    0          
608 0           return NULL;
609            
610             enum myhtml_tree_insertion_mode mode;
611            
612 0           target->tree->foster_parenting = true;
613 0           target = myhtml_tree_appropriate_place_inserting_in_tree(target, &mode);
614 0           target->tree->foster_parenting = false;
615            
616 0           myhtml_tree_node_insert_by_mode(target, node, mode);
617            
618 0           return node;
619             }
620              
621 21           mycore_string_t * myhtml_node_text_set(myhtml_tree_node_t *node, const char* text, size_t length, myencoding_t encoding)
622             {
623 21 50         if(node == NULL)
624 0           return NULL;
625            
626 21 50         if(encoding >= MyENCODING_LAST_ENTRY)
627 0           return NULL;
628            
629 21           myhtml_tree_t* tree = node->tree;
630            
631 21 50         if(node->token == NULL) {
632 21           node->token = myhtml_token_node_create(tree->token, tree->mcasync_rules_token_id);
633            
634 21 50         if(node->token == NULL)
635 0           return NULL;
636            
637 21           node->token->type |= MyHTML_TOKEN_TYPE_DONE;
638             }
639            
640 21 50         if(node->token->str.data == NULL) {
641 21           mycore_string_init(tree->mchar, tree->mchar_node_id, &node->token->str, (length + 2));
642             }
643             else {
644 0 0         if(node->token->str.size < length) {
645 0           mchar_async_free(tree->mchar, node->token->str.node_idx, node->token->str.data);
646 0           mycore_string_init(tree->mchar, tree->mchar_node_id, &node->token->str, length);
647             }
648             else
649 0           node->token->str.length = 0;
650             }
651            
652 21 50         if(encoding != MyENCODING_UTF_8) {
653 0           myencoding_string_append(&node->token->str, text, length, encoding);
654             }
655             else {
656 21           mycore_string_append(&node->token->str, text, length);
657             }
658            
659 21           node->token->raw_begin = 0;
660 21           node->token->raw_length = 0;
661            
662 21           return &node->token->str;
663             }
664              
665 0           mycore_string_t * myhtml_node_text_set_with_charef(myhtml_tree_node_t *node, const char* text, size_t length, myencoding_t encoding)
666             {
667 0 0         if(node == NULL)
668 0           return NULL;
669            
670 0 0         if(encoding >= MyENCODING_LAST_ENTRY)
671 0           return NULL;
672            
673 0           myhtml_tree_t* tree = node->tree;
674            
675 0 0         if(node->token == NULL) {
676 0           node->token = myhtml_token_node_create(tree->token, tree->mcasync_rules_token_id);
677            
678 0 0         if(node->token == NULL)
679 0           return NULL;
680            
681 0           node->token->type |= MyHTML_TOKEN_TYPE_DONE;
682             }
683            
684 0 0         if(node->token->str.data == NULL) {
685 0           mycore_string_init(tree->mchar, tree->mchar_node_id, &node->token->str, (length + 2));
686             }
687             else {
688 0 0         if(node->token->str.size < length) {
689 0           mchar_async_free(tree->mchar, node->token->str.node_idx, node->token->str.data);
690 0           mycore_string_init(tree->mchar, tree->mchar_node_id, &node->token->str, length);
691             }
692             else
693 0           node->token->str.length = 0;
694             }
695            
696             myhtml_data_process_entry_t proc_entry;
697 0           myhtml_data_process_entry_clean(&proc_entry);
698            
699 0           proc_entry.encoding = encoding;
700 0           myencoding_result_clean(&proc_entry.res);
701            
702 0           myhtml_data_process(&proc_entry, &node->token->str, text, length);
703 0           myhtml_data_process_end(&proc_entry, &node->token->str);
704            
705 0           node->token->raw_begin = 0;
706 0           node->token->raw_length = 0;
707            
708 0           return &node->token->str;
709             }
710              
711 0           myhtml_token_node_t* myhtml_node_token(myhtml_tree_node_t *node)
712             {
713 0           return node->token;
714             }
715              
716 24           myhtml_namespace_t myhtml_node_namespace(myhtml_tree_node_t *node)
717             {
718 24           return node->ns;
719             }
720              
721 2           void myhtml_node_namespace_set(myhtml_tree_node_t *node, myhtml_namespace_t ns)
722             {
723 2           node->ns = ns;
724 2           }
725              
726 0           myhtml_tag_id_t myhtml_node_tag_id(myhtml_tree_node_t *node)
727             {
728 0           return node->tag_id;
729             }
730              
731 167           const char * myhtml_tag_name_by_id(myhtml_tree_t* tree, myhtml_tag_id_t tag_id, size_t *length)
732             {
733 167 50         if(length)
734 167           *length = 0;
735            
736 167 50         if(tree == NULL || tree->tags == NULL)
    50          
737 0           return NULL;
738            
739 167           const myhtml_tag_context_t *tag_ctx = myhtml_tag_get_by_id(tree->tags, tag_id);
740            
741 167 50         if(tag_ctx == NULL)
742 0           return NULL;
743            
744 167 50         if(length)
745 167           *length = tag_ctx->name_length;
746            
747 167           return tag_ctx->name;
748             }
749              
750 452           myhtml_tag_id_t myhtml_tag_id_by_name(myhtml_tree_t* tree, const char *tag_name, size_t length)
751             {
752 452 50         if(tree == NULL || tree->tags == NULL)
    50          
753 0           return MyHTML_TAG__UNDEF;
754            
755 452           const myhtml_tag_context_t *ctx = myhtml_tag_get_by_name(tree->tags, tag_name, length);
756            
757 452 100         if(ctx == NULL)
758 60           return MyHTML_TAG__UNDEF;
759            
760 392           return ctx->id;
761             }
762              
763 2           bool myhtml_node_is_close_self(myhtml_tree_node_t *node)
764             {
765 2 50         if(node->token)
766 2           return (node->token->type & MyHTML_TOKEN_TYPE_CLOSE_SELF);
767            
768 0           return false;
769             }
770              
771 38           bool myhtml_node_is_void_element(myhtml_tree_node_t *node)
772             {
773             // http://w3c.github.io/html-reference/syntax.html#void-elements
774 38 100         switch (node->tag_id)
775             {
776             case MyHTML_TAG_AREA:
777             case MyHTML_TAG_BASE:
778             case MyHTML_TAG_BR:
779             case MyHTML_TAG_COL:
780             case MyHTML_TAG_COMMAND:
781             case MyHTML_TAG_EMBED:
782             case MyHTML_TAG_HR:
783             case MyHTML_TAG_IMG:
784             case MyHTML_TAG_INPUT:
785             case MyHTML_TAG_KEYGEN:
786             case MyHTML_TAG_LINK:
787             case MyHTML_TAG_META:
788             case MyHTML_TAG_PARAM:
789             case MyHTML_TAG_SOURCE:
790             case MyHTML_TAG_TRACK:
791             case MyHTML_TAG_WBR:
792             {
793 2           return true;
794             }
795             default:
796             {
797 36           return false;
798             }
799             }
800             }
801              
802 2           myhtml_tree_attr_t * myhtml_node_attribute_first(myhtml_tree_node_t *node)
803             {
804 2 50         if(node->token)
805 2           return node->token->attr_first;
806            
807 0           return NULL;
808             }
809              
810 0           myhtml_tree_attr_t * myhtml_node_attribute_last(myhtml_tree_node_t *node)
811             {
812 0 0         if(node->token)
813 0           return node->token->attr_last;
814            
815 0           return NULL;
816             }
817              
818 214           const char * myhtml_node_text(myhtml_tree_node_t *node, size_t *length)
819             {
820 214 50         if(node->token && node->token->str.length && node->token->str.data)
    50          
    50          
821             {
822 214 50         if(length)
823 214           *length = node->token->str.length;
824            
825 214           return node->token->str.data;
826             }
827            
828 0 0         if(length)
829 0           *length = 0;
830            
831 0           return NULL;
832             }
833              
834 0           mycore_string_t * myhtml_node_string(myhtml_tree_node_t *node)
835             {
836 0 0         if(node && node->token)
    0          
837 0           return &node->token->str;
838            
839 0           return NULL;
840             }
841              
842 0           myhtml_position_t myhtml_node_raw_position(myhtml_tree_node_t *node)
843             {
844 0 0         if(node && node->token)
    0          
845 0           return (myhtml_position_t){node->token->raw_begin, node->token->raw_length};
846            
847 0           return (myhtml_position_t){0, 0};
848             }
849              
850 0           myhtml_position_t myhtml_node_element_position(myhtml_tree_node_t *node)
851             {
852 0 0         if(node && node->token)
    0          
853 0           return (myhtml_position_t){node->token->element_begin, node->token->element_length};
854            
855 0           return (myhtml_position_t){0, 0};
856             }
857              
858 2492           void myhtml_node_set_data(myhtml_tree_node_t *node, void* data)
859             {
860 2492           node->data = data;
861 2492           }
862              
863 2794           void * myhtml_node_get_data(myhtml_tree_node_t *node)
864             {
865 2794           return node->data;
866             }
867              
868 0           myhtml_tree_t * myhtml_node_tree(myhtml_tree_node_t *node)
869             {
870 0           return node->tree;
871             }
872              
873 0           mystatus_t myhtml_get_nodes_by_attribute_key_recursion(myhtml_tree_node_t* node, myhtml_collection_t* collection, const char* key, size_t key_len)
874             {
875 0 0         while(node)
876             {
877 0 0         if(node->token && node->token->attr_first) {
    0          
878 0           myhtml_tree_attr_t* attr = node->token->attr_first;
879            
880 0 0         while(attr) {
881 0           mycore_string_t* str_key = &attr->key;
882            
883 0 0         if(str_key->length == key_len && mycore_strncasecmp(str_key->data, key, key_len) == 0) {
    0          
884 0           collection->list[ collection->length ] = node;
885            
886 0           collection->length++;
887 0 0         if(collection->length >= collection->size) {
888 0           mystatus_t status = myhtml_collection_check_size(collection, 1024, 0);
889            
890 0 0         if(status)
891 0           return status;
892             }
893             }
894            
895 0           attr = attr->next;
896             }
897             }
898            
899 0 0         if(node->child) {
900 0           mystatus_t status = myhtml_get_nodes_by_attribute_key_recursion(node->child, collection, key, key_len);
901            
902 0 0         if(status)
903 0           return status;
904             }
905            
906 0           node = node->next;
907             }
908            
909 0           return MyHTML_STATUS_OK;
910             }
911              
912 0           myhtml_collection_t * myhtml_get_nodes_by_attribute_key(myhtml_tree_t *tree, myhtml_collection_t* collection, myhtml_tree_node_t* scope_node, const char* key, size_t key_len, mystatus_t* status)
913             {
914 0 0         if(collection == NULL) {
915 0           collection = myhtml_collection_create(1024, status);
916            
917 0 0         if((status && *status) || collection == NULL)
    0          
    0          
918 0           return NULL;
919             }
920            
921 0 0         if(scope_node == NULL)
922 0           scope_node = tree->node_html;
923            
924 0           mystatus_t rec_status = myhtml_get_nodes_by_attribute_key_recursion(scope_node, collection, key, key_len);
925            
926 0 0         if(rec_status && status)
    0          
927 0           *status = rec_status;
928            
929 0           return collection;
930             }
931              
932             /* find by attribute value; case-sensitivity */
933 64           bool myhtml_get_nodes_by_attribute_value_recursion_eq(mycore_string_t* str, const char* value, size_t value_len)
934             {
935 64 100         return str->length == value_len && mycore_strncmp(str->data, value, value_len) == 0;
    100          
936             }
937              
938 128           bool myhtml_get_nodes_by_attribute_value_recursion_whitespace_separated(mycore_string_t* str, const char* value, size_t value_len)
939             {
940 128 100         if(str->length < value_len)
941 36           return false;
942            
943 92           const char *data = str->data;
944            
945 92 100         if(mycore_strncmp(data, value, value_len) == 0) {
946 20 100         if((str->length > value_len && mycore_utils_whithspace(data[value_len], ==, ||)) || str->length == value_len)
    50          
    0          
    0          
    0          
    0          
    50          
947 20           return true;
948             }
949            
950 428 100         for(size_t i = 1; (str->length - i) >= value_len; i++)
951             {
952 368 100         if(mycore_utils_whithspace(data[(i - 1)], ==, ||)) {
    50          
    50          
    50          
    50          
953 64 100         if(mycore_strncmp(&data[i], value, value_len) == 0) {
954 16 100         if((i > value_len && mycore_utils_whithspace(data[(i + value_len)], ==, ||)) || (str->length - i) == value_len)
    100          
    50          
    50          
    50          
    50          
    100          
955 12           return true;
956             }
957             }
958             }
959            
960 60           return false;
961             }
962              
963 8           bool myhtml_get_nodes_by_attribute_value_recursion_begin(mycore_string_t* str, const char* value, size_t value_len)
964             {
965 8 50         if(str->length < value_len)
966 0           return false;
967            
968 8           return mycore_strncmp(str->data, value, value_len) == 0;
969             }
970              
971 8           bool myhtml_get_nodes_by_attribute_value_recursion_end(mycore_string_t* str, const char* value, size_t value_len)
972             {
973 8 50         if(str->length < value_len)
974 0           return false;
975            
976 8           return mycore_strncmp(&str->data[ (str->length - value_len) ], value, value_len) == 0;
977             }
978              
979 8           bool myhtml_get_nodes_by_attribute_value_recursion_contain(mycore_string_t* str, const char* value, size_t value_len)
980             {
981 8 50         if(str->length < value_len)
982 0           return false;
983            
984 8           const char *data = str->data;
985            
986 116 100         for(size_t i = 0; (str->length - i) >= value_len; i++)
987             {
988 112 100         if(mycore_strncmp(&data[i], value, value_len) == 0) {
989 4           return true;
990             }
991             }
992            
993 4           return false;
994             }
995              
996 16           bool myhtml_get_nodes_by_attribute_value_recursion_hyphen_separated(mycore_string_t* str, const char* value, size_t value_len)
997             {
998 16           const char *data = str->data;
999            
1000 16 50         if(str->length < value_len)
1001 0           return false;
1002 16 50         else if(str->length == value_len && mycore_strncmp(data, value, value_len) == 0) {
    0          
1003 0           return true;
1004             }
1005 16 100         else if(mycore_strncmp(data, value, value_len) == 0 && data[value_len] == '-') {
    100          
1006 4           return true;
1007             }
1008            
1009 12           return false;
1010             }
1011              
1012             /* find by attribute value; case-insensitive */
1013 16           bool myhtml_get_nodes_by_attribute_value_recursion_eq_i(mycore_string_t* str, const char* value, size_t value_len)
1014             {
1015 16 100         return str->length == value_len && mycore_strncasecmp(str->data, value, value_len) == 0;
    100          
1016             }
1017              
1018 16           bool myhtml_get_nodes_by_attribute_value_recursion_whitespace_separated_i(mycore_string_t* str, const char* value, size_t value_len)
1019             {
1020 16 50         if(str->length < value_len)
1021 0           return false;
1022            
1023 16           const char *data = str->data;
1024            
1025 16 50         if(mycore_strncasecmp(data, value, value_len) == 0) {
1026 0 0         if((str->length > value_len && mycore_utils_whithspace(data[value_len], ==, ||)) || str->length == value_len)
    0          
    0          
    0          
    0          
    0          
    0          
1027 0           return true;
1028             }
1029            
1030 240 100         for(size_t i = 1; (str->length - i) >= value_len; i++)
1031             {
1032 228 100         if(mycore_utils_whithspace(data[(i - 1)], ==, ||)) {
    50          
    50          
    50          
    50          
1033 48 100         if(mycore_strncasecmp(&data[i], value, value_len) == 0) {
1034 8 50         if((i > value_len && mycore_utils_whithspace(data[(i + value_len)], ==, ||)) || (str->length - i) == value_len)
    100          
    50          
    50          
    50          
    50          
    50          
1035 4           return true;
1036             }
1037             }
1038             }
1039            
1040 12           return false;
1041             }
1042              
1043 8           bool myhtml_get_nodes_by_attribute_value_recursion_begin_i(mycore_string_t* str, const char* value, size_t value_len)
1044             {
1045 8 50         if(str->length < value_len)
1046 0           return false;
1047            
1048 8           return mycore_strncasecmp(str->data, value, value_len) == 0;
1049             }
1050              
1051 8           bool myhtml_get_nodes_by_attribute_value_recursion_end_i(mycore_string_t* str, const char* value, size_t value_len)
1052             {
1053 8 50         if(str->length < value_len)
1054 0           return false;
1055            
1056 8           return mycore_strncasecmp(&str->data[ (str->length - value_len) ], value, value_len) == 0;
1057             }
1058              
1059 8           bool myhtml_get_nodes_by_attribute_value_recursion_contain_i(mycore_string_t* str, const char* value, size_t value_len)
1060             {
1061 8 50         if(str->length < value_len)
1062 0           return false;
1063            
1064 8           const char *data = str->data;
1065            
1066 112 100         for(size_t i = 0; (str->length - i) >= value_len; i++)
1067             {
1068 108 100         if(mycore_strncasecmp(&data[i], value, value_len) == 0) {
1069 4           return true;
1070             }
1071             }
1072            
1073 4           return false;
1074             }
1075              
1076 16           bool myhtml_get_nodes_by_attribute_value_recursion_hyphen_separated_i(mycore_string_t* str, const char* value, size_t value_len)
1077             {
1078 16           const char *data = str->data;
1079            
1080 16 50         if(str->length < value_len)
1081 0           return false;
1082 16 50         else if(str->length == value_len && mycore_strncasecmp(data, value, value_len) == 0) {
    0          
1083 0           return true;
1084             }
1085 16 100         else if(mycore_strncasecmp(data, value, value_len) == 0 && data[value_len] == '-') {
    100          
1086 4           return true;
1087             }
1088            
1089 12           return false;
1090             }
1091              
1092             /* find by attribute value; basic functions */
1093 0           mystatus_t myhtml_get_nodes_by_attribute_value_recursion(myhtml_tree_node_t* node, myhtml_collection_t* collection,
1094             myhtml_attribute_value_find_f func_eq,
1095             const char* value, size_t value_len)
1096             {
1097 0 0         while(node)
1098             {
1099 0 0         if(node->token && node->token->attr_first) {
    0          
1100 0           myhtml_tree_attr_t* attr = node->token->attr_first;
1101            
1102 0 0         while(attr) {
1103 0           mycore_string_t* str = &attr->value;
1104            
1105 0 0         if(func_eq(str, value, value_len)) {
1106 0           collection->list[ collection->length ] = node;
1107            
1108 0           collection->length++;
1109 0 0         if(collection->length >= collection->size) {
1110 0           mystatus_t status = myhtml_collection_check_size(collection, 1024, 0);
1111            
1112 0 0         if(status)
1113 0           return status;
1114             }
1115             }
1116            
1117 0           attr = attr->next;
1118             }
1119             }
1120            
1121 0 0         if(node->child) {
1122 0           mystatus_t status = myhtml_get_nodes_by_attribute_value_recursion(node->child, collection, func_eq, value, value_len);
1123            
1124 0 0         if(status)
1125 0           return status;
1126             }
1127            
1128 0           node = node->next;
1129             }
1130            
1131 0           return MyHTML_STATUS_OK;
1132             }
1133              
1134 680           mystatus_t myhtml_get_nodes_by_attribute_value_recursion_by_key(myhtml_tree_node_t* node, myhtml_collection_t* collection,
1135             myhtml_attribute_value_find_f func_eq,
1136             const char* key, size_t key_len,
1137             const char* value, size_t value_len)
1138             {
1139 4896 100         while(node)
1140             {
1141 4216 100         if(node->token && node->token->attr_first) {
    100          
1142 1836           myhtml_tree_attr_t* attr = node->token->attr_first;
1143            
1144 4488 100         while(attr) {
1145 2652           mycore_string_t* str_key = &attr->key;
1146 2652           mycore_string_t* str = &attr->value;
1147            
1148 2652 100         if(str_key->length == key_len && mycore_strncasecmp(str_key->data, key, key_len) == 0)
    100          
1149             {
1150 304 100         if(func_eq(str, value, value_len)) {
1151 84           collection->list[ collection->length ] = node;
1152            
1153 84           collection->length++;
1154 84 50         if(collection->length >= collection->size) {
1155 0           mystatus_t status = myhtml_collection_check_size(collection, 1024, 0);
1156            
1157 0 0         if(status)
1158 0           return status;
1159             }
1160             }
1161             }
1162            
1163 2652           attr = attr->next;
1164             }
1165             }
1166            
1167 4216 100         if(node->child) {
1168 544           mystatus_t status = myhtml_get_nodes_by_attribute_value_recursion_by_key(node->child, collection, func_eq,
1169             key, key_len, value, value_len);
1170            
1171 544 50         if(status)
1172 0           return status;
1173             }
1174            
1175 4216           node = node->next;
1176             }
1177            
1178 680           return MyHTML_STATUS_OK;
1179             }
1180              
1181 136           myhtml_collection_t * _myhtml_get_nodes_by_attribute_value(myhtml_tree_t *tree, myhtml_collection_t* collection, myhtml_tree_node_t* node,
1182             myhtml_attribute_value_find_f func_eq,
1183             const char* key, size_t key_len,
1184             const char* value, size_t value_len,
1185             mystatus_t* status)
1186             {
1187 136 50         if(collection == NULL) {
1188 136           collection = myhtml_collection_create(1024, status);
1189            
1190 136 50         if((status && *status) || collection == NULL)
    0          
    50          
1191 0           return NULL;
1192             }
1193            
1194 136 50         if(node == NULL)
1195 0           node = tree->node_html;
1196            
1197             mystatus_t rec_status;
1198            
1199 136 50         if(key && key_len)
    50          
1200 136           rec_status = myhtml_get_nodes_by_attribute_value_recursion_by_key(node, collection, func_eq, key, key_len, value, value_len);
1201             else
1202 0           rec_status = myhtml_get_nodes_by_attribute_value_recursion(node, collection, func_eq, value, value_len);
1203            
1204 136 50         if(rec_status && status)
    0          
1205 0           *status = rec_status;
1206            
1207 136           return collection;
1208             }
1209              
1210 28           myhtml_collection_t * myhtml_get_nodes_by_attribute_value(myhtml_tree_t *tree, myhtml_collection_t* collection, myhtml_tree_node_t* node,
1211             bool case_insensitive,
1212             const char* key, size_t key_len,
1213             const char* value, size_t value_len,
1214             mystatus_t* status)
1215             {
1216 28 100         if(case_insensitive) {
1217 8           return _myhtml_get_nodes_by_attribute_value(tree, collection, node,
1218             myhtml_get_nodes_by_attribute_value_recursion_eq_i,
1219             key, key_len, value, value_len, status);
1220             }
1221            
1222 20           return _myhtml_get_nodes_by_attribute_value(tree, collection, node,
1223             myhtml_get_nodes_by_attribute_value_recursion_eq,
1224             key, key_len, value, value_len, status);
1225             }
1226              
1227 44           myhtml_collection_t * myhtml_get_nodes_by_attribute_value_whitespace_separated(myhtml_tree_t *tree, myhtml_collection_t* collection, myhtml_tree_node_t* node,
1228             bool case_insensitive,
1229             const char* key, size_t key_len,
1230             const char* value, size_t value_len,
1231             mystatus_t* status)
1232             {
1233 44 100         if(case_insensitive) {
1234 8           return _myhtml_get_nodes_by_attribute_value(tree, collection, node,
1235             myhtml_get_nodes_by_attribute_value_recursion_whitespace_separated_i,
1236             key, key_len, value, value_len, status);
1237             }
1238            
1239 36           return _myhtml_get_nodes_by_attribute_value(tree, collection, node,
1240             myhtml_get_nodes_by_attribute_value_recursion_whitespace_separated,
1241             key, key_len, value, value_len, status);
1242             }
1243              
1244 16           myhtml_collection_t * myhtml_get_nodes_by_attribute_value_begin(myhtml_tree_t *tree, myhtml_collection_t* collection, myhtml_tree_node_t* node,
1245             bool case_insensitive,
1246             const char* key, size_t key_len,
1247             const char* value, size_t value_len,
1248             mystatus_t* status)
1249             {
1250 16 100         if(case_insensitive) {
1251 8           return _myhtml_get_nodes_by_attribute_value(tree, collection, node,
1252             myhtml_get_nodes_by_attribute_value_recursion_begin_i,
1253             key, key_len, value, value_len, status);
1254             }
1255            
1256 8           return _myhtml_get_nodes_by_attribute_value(tree, collection, node,
1257             myhtml_get_nodes_by_attribute_value_recursion_begin,
1258             key, key_len, value, value_len, status);
1259             }
1260              
1261 16           myhtml_collection_t * myhtml_get_nodes_by_attribute_value_end(myhtml_tree_t *tree, myhtml_collection_t* collection, myhtml_tree_node_t* node,
1262             bool case_insensitive,
1263             const char* key, size_t key_len,
1264             const char* value, size_t value_len,
1265             mystatus_t* status)
1266             {
1267 16 100         if(case_insensitive) {
1268 8           return _myhtml_get_nodes_by_attribute_value(tree, collection, node,
1269             myhtml_get_nodes_by_attribute_value_recursion_end_i,
1270             key, key_len, value, value_len, status);
1271             }
1272            
1273 8           return _myhtml_get_nodes_by_attribute_value(tree, collection, node,
1274             myhtml_get_nodes_by_attribute_value_recursion_end,
1275             key, key_len, value, value_len, status);
1276             }
1277              
1278 16           myhtml_collection_t * myhtml_get_nodes_by_attribute_value_contain(myhtml_tree_t *tree, myhtml_collection_t* collection, myhtml_tree_node_t* node,
1279             bool case_insensitive,
1280             const char* key, size_t key_len,
1281             const char* value, size_t value_len,
1282             mystatus_t* status)
1283             {
1284 16 100         if(case_insensitive) {
1285 8           return _myhtml_get_nodes_by_attribute_value(tree, collection, node,
1286             myhtml_get_nodes_by_attribute_value_recursion_contain_i,
1287             key, key_len, value, value_len, status);
1288             }
1289            
1290 8           return _myhtml_get_nodes_by_attribute_value(tree, collection, node,
1291             myhtml_get_nodes_by_attribute_value_recursion_contain,
1292             key, key_len, value, value_len, status);
1293             }
1294              
1295 16           myhtml_collection_t * myhtml_get_nodes_by_attribute_value_hyphen_separated(myhtml_tree_t *tree, myhtml_collection_t* collection, myhtml_tree_node_t* node,
1296             bool case_insensitive,
1297             const char* key, size_t key_len,
1298             const char* value, size_t value_len,
1299             mystatus_t* status)
1300             {
1301 16 100         if(case_insensitive) {
1302 8           return _myhtml_get_nodes_by_attribute_value(tree, collection, node,
1303             myhtml_get_nodes_by_attribute_value_recursion_hyphen_separated_i,
1304             key, key_len, value, value_len, status);
1305             }
1306            
1307 8           return _myhtml_get_nodes_by_attribute_value(tree, collection, node,
1308             myhtml_get_nodes_by_attribute_value_recursion_hyphen_separated,
1309             key, key_len, value, value_len, status);
1310             }
1311              
1312             /*
1313             * Attributes
1314             */
1315 10           myhtml_tree_attr_t * myhtml_attribute_next(myhtml_tree_attr_t *attr)
1316             {
1317 10           return attr->next;
1318             }
1319              
1320 0           myhtml_tree_attr_t * myhtml_attribute_prev(myhtml_tree_attr_t *attr)
1321             {
1322 0           return attr->prev;
1323             }
1324              
1325 5           enum myhtml_namespace myhtml_attribute_namespace(myhtml_tree_attr_t *attr)
1326             {
1327 5           return attr->ns;
1328             }
1329              
1330 0           void myhtml_attribute_namespace_set(myhtml_tree_attr_t *attr, myhtml_namespace_t ns)
1331             {
1332 0           attr->ns = ns;
1333 0           }
1334              
1335 46           const char * myhtml_attribute_key(myhtml_tree_attr_t *attr, size_t *length)
1336             {
1337 46 50         if(attr->key.data && attr->key.length)
    50          
1338             {
1339 46 50         if(length)
1340 46           *length = attr->key.length;
1341            
1342 46           return attr->key.data;
1343             }
1344            
1345 0 0         if(length)
1346 0           *length = 0;
1347            
1348 0           return NULL;
1349             }
1350              
1351 123           const char * myhtml_attribute_value(myhtml_tree_attr_t *attr, size_t *length)
1352             {
1353 123 100         if(attr->value.data && attr->value.length)
    100          
1354             {
1355 106 50         if(length)
1356 106           *length = attr->value.length;
1357            
1358 106           return attr->value.data;
1359             }
1360            
1361 17 50         if(length)
1362 17           *length = 0;
1363            
1364 17           return NULL;
1365             }
1366              
1367 0           mycore_string_t * myhtml_attribute_key_string(myhtml_tree_attr_t* attr)
1368             {
1369 0 0         if(attr)
1370 0           return &attr->key;
1371            
1372 0           return NULL;
1373             }
1374              
1375 0           mycore_string_t * myhtml_attribute_value_string(myhtml_tree_attr_t* attr)
1376             {
1377 0 0         if(attr)
1378 0           return &attr->value;
1379            
1380 0           return NULL;
1381             }
1382              
1383 120           myhtml_tree_attr_t * myhtml_attribute_by_key(myhtml_tree_node_t *node, const char *key, size_t key_len)
1384             {
1385 120 50         if(node == NULL || node->token == NULL)
    50          
1386 0           return NULL;
1387            
1388 120           return myhtml_token_attr_by_name(node->token, key, key_len);
1389             }
1390              
1391 63           myhtml_tree_attr_t * myhtml_attribute_add(myhtml_tree_node_t *node, const char *key, size_t key_len, const char *value, size_t value_len, myencoding_t encoding)
1392             {
1393 63 50         if(node == NULL)
1394 0           return NULL;
1395            
1396 63           myhtml_tree_t *tree = node->tree;
1397            
1398 63 50         if(node->token == NULL) {
1399 0           node->token = myhtml_token_node_create(tree->token, tree->mcasync_rules_token_id);
1400            
1401 0 0         if(node->token == NULL)
1402 0           return NULL;
1403            
1404 0           node->token->type |= MyHTML_TOKEN_TYPE_DONE;
1405             }
1406            
1407 63           return myhtml_token_node_attr_append_with_convert_encoding(tree->token, node->token, key, key_len,
1408             value, value_len, tree->mcasync_rules_token_id, encoding);
1409             }
1410              
1411 0           myhtml_tree_attr_t * myhtml_attribute_remove(myhtml_tree_node_t *node, myhtml_tree_attr_t *attr)
1412             {
1413 0 0         if(node == NULL || node->token == NULL)
    0          
1414 0           return NULL;
1415            
1416 0           return myhtml_token_attr_remove(node->token, attr);
1417             }
1418              
1419 20           myhtml_tree_attr_t * myhtml_attribute_remove_by_key(myhtml_tree_node_t *node, const char *key, size_t key_len)
1420             {
1421 20 50         if(node == NULL || node->token == NULL)
    50          
1422 0           return NULL;
1423            
1424 20           return myhtml_token_attr_remove_by_name(node->token, key, key_len);
1425             }
1426              
1427 33           void myhtml_attribute_delete(myhtml_tree_t *tree, myhtml_tree_node_t *node, myhtml_tree_attr_t *attr)
1428             {
1429 33 50         if(node == NULL || node->token == NULL)
    50          
1430 0           return;
1431            
1432 33           myhtml_token_attr_remove(node->token, attr);
1433 33           myhtml_attribute_free(tree, attr);
1434             }
1435              
1436 33           void myhtml_attribute_free(myhtml_tree_t *tree, myhtml_tree_attr_t *attr)
1437             {
1438 33 100         if(attr->key.data)
1439 12           mchar_async_free(attr->key.mchar, attr->key.node_idx, attr->key.data);
1440 33 100         if(attr->value.data)
1441 21           mchar_async_free(attr->value.mchar, attr->value.node_idx, attr->value.data);
1442            
1443 33           mcobject_async_free(tree->token->attr_obj, attr);
1444 33           }
1445              
1446 0           myhtml_position_t myhtml_attribute_key_raw_position(myhtml_tree_attr_t *attr)
1447             {
1448 0 0         if(attr)
1449 0           return (myhtml_position_t){attr->raw_key_begin, attr->raw_key_length};
1450            
1451 0           return (myhtml_position_t){0, 0};
1452             }
1453              
1454 0           myhtml_position_t myhtml_attribute_value_raw_position(myhtml_tree_attr_t *attr)
1455             {
1456 0 0         if(attr)
1457 0           return (myhtml_position_t){attr->raw_value_begin, attr->raw_value_length};
1458            
1459 0           return (myhtml_position_t){0, 0};
1460             }
1461              
1462             /*
1463             * Collections
1464             */
1465 189           myhtml_collection_t * myhtml_collection_create(size_t size, mystatus_t *status)
1466             {
1467 189           myhtml_collection_t *collection = (myhtml_collection_t*)mycore_malloc(sizeof(myhtml_collection_t));
1468            
1469 189 50         if(collection == NULL) {
1470 0 0         if(status)
1471 0           *status = MyHTML_STATUS_ERROR_MEMORY_ALLOCATION;
1472            
1473 0           return NULL;
1474             }
1475            
1476 189           collection->size = size;
1477 189           collection->length = 0;
1478 189           collection->list = (myhtml_tree_node_t **)mycore_malloc(sizeof(myhtml_tree_node_t*) * size);
1479            
1480 189 50         if(collection->list == NULL) {
1481 0           mycore_free(collection);
1482            
1483 0 0         if(status)
1484 0           *status = MyHTML_STATUS_ERROR_MEMORY_ALLOCATION;
1485            
1486 0           return NULL;
1487             }
1488            
1489 189 100         if(status)
1490 53           *status = MyHTML_STATUS_OK;
1491            
1492 189           return collection;
1493             }
1494              
1495 89           mystatus_t myhtml_collection_check_size(myhtml_collection_t *collection, size_t need, size_t upto_length)
1496             {
1497 89 50         if((collection->length + need) >= collection->size)
1498             {
1499 0           size_t tmp_size = collection->length + need + upto_length + 1;
1500 0           myhtml_tree_node_t **tmp = (myhtml_tree_node_t **)mycore_realloc(collection->list, sizeof(myhtml_tree_node_t*) * tmp_size);
1501            
1502 0 0         if(tmp) {
1503 0           collection->size = tmp_size;
1504 0           collection->list = tmp;
1505             }
1506             else
1507 0           return MyHTML_STATUS_ERROR_MEMORY_ALLOCATION;
1508             }
1509            
1510 89           return MyHTML_STATUS_OK;
1511             }
1512              
1513 0           void myhtml_collection_clean(myhtml_collection_t *collection)
1514             {
1515 0 0         if(collection)
1516 0           collection->length = 0;
1517 0           }
1518              
1519 189           myhtml_collection_t * myhtml_collection_destroy(myhtml_collection_t *collection)
1520             {
1521 189 50         if(collection == NULL)
1522 0           return NULL;
1523            
1524 189 50         if(collection->list)
1525 189           mycore_free(collection->list);
1526            
1527 189           mycore_free(collection);
1528            
1529 189           return NULL;
1530             }
1531              
1532             /* queue */
1533 1685           mystatus_t myhtml_queue_add(myhtml_tree_t *tree, size_t begin, myhtml_token_node_t* token)
1534             {
1535             // TODO: need refactoring this code
1536             // too many conditions
1537 1685           mythread_queue_node_t *qnode = tree->current_qnode;
1538            
1539 1685 50         if(tree->parse_flags & MyHTML_TREE_PARSE_FLAGS_SKIP_WHITESPACE_TOKEN) {
1540 0 0         if(token && token->tag_id == MyHTML_TAG__TEXT && token->type & MyHTML_TOKEN_TYPE_WHITESPACE)
    0          
    0          
1541             {
1542 0           myhtml_token_node_clean(token);
1543 0           token->raw_begin = token->element_begin = (tree->global_offset + begin);
1544            
1545 0           return MyHTML_STATUS_OK;
1546             }
1547             }
1548            
1549             #ifndef MyCORE_BUILD_WITHOUT_THREADS
1550            
1551 1685 100         if(tree->flags & MyHTML_TREE_FLAGS_SINGLE_MODE) {
1552 1663 50         if(qnode && token) {
    50          
1553 1663           qnode->args = token;
1554            
1555 1663           myhtml_parser_worker(0, qnode);
1556 1663           myhtml_parser_stream(0, qnode);
1557             }
1558            
1559 1663           tree->current_qnode = mythread_queue_node_malloc_limit(tree->myhtml->thread_stream, tree->queue, 4, NULL);
1560             }
1561             else {
1562 22 50         if(qnode)
1563 22           qnode->args = token;
1564            
1565 22           tree->current_qnode = mythread_queue_node_malloc_round(tree->myhtml->thread_stream, tree->queue_entry);
1566            
1567             /* we have a clean queue list */
1568 22 50         if(tree->queue_entry->queue->nodes_length == 0) {
1569 0           mythread_queue_list_entry_make_batch(tree->myhtml->thread_batch, tree->queue_entry);
1570 0           mythread_queue_list_entry_make_stream(tree->myhtml->thread_stream, tree->queue_entry);
1571             }
1572             }
1573            
1574             #else
1575            
1576             if(qnode && token) {
1577             qnode->args = token;
1578            
1579             myhtml_parser_worker(0, qnode);
1580             myhtml_parser_stream(0, qnode);
1581             }
1582            
1583             tree->current_qnode = mythread_queue_node_malloc_limit(tree->myhtml->thread_stream, tree->queue, 4, NULL);
1584            
1585             #endif /* MyCORE_BUILD_WITHOUT_THREADS */
1586            
1587 1685 50         if(tree->current_qnode == NULL)
1588 0           return MyHTML_STATUS_ERROR_MEMORY_ALLOCATION;
1589            
1590 1685           tree->current_qnode->context = tree;
1591 1685           tree->current_qnode->prev = qnode;
1592            
1593 1685 50         if(qnode && token)
    50          
1594 1685           myhtml_tokenizer_calc_current_namespace(tree, token);
1595            
1596 1685           tree->current_token_node = myhtml_token_node_create(tree->token, tree->token->mcasync_token_id);
1597 1685 50         if(tree->current_token_node == NULL)
1598 0           return MyHTML_STATUS_ERROR_MEMORY_ALLOCATION;
1599            
1600 1685           tree->current_token_node->raw_begin = tree->current_token_node->element_begin = (tree->global_offset + begin);
1601            
1602 1685           return MyHTML_STATUS_OK;
1603             }
1604              
1605 0           bool myhtml_utils_strcmp(const char* ab, const char* to_lowercase, size_t size)
1606             {
1607 0           size_t i = 0;
1608            
1609             for(;;) {
1610 0 0         if(i == size)
1611 0           return true;
1612            
1613 0 0         if((const unsigned char)(to_lowercase[i] > 0x40 && to_lowercase[i] < 0x5b ?
    0          
1614 0 0         (to_lowercase[i]|0x60) : to_lowercase[i]) != (const unsigned char)ab[i])
1615             {
1616 0           return false;
1617             }
1618            
1619 0           i++;
1620 0           }
1621            
1622             return false;
1623             }
1624              
1625 501           bool myhtml_is_html_node(myhtml_tree_node_t *node, myhtml_tag_id_t tag_id)
1626             {
1627 501 50         if(node == NULL)
1628 0           return false;
1629            
1630 501 100         return node->tag_id == tag_id && node->ns == MyHTML_NAMESPACE_HTML;
    50          
1631             }
1632              
1633             /* version */
1634 0           myhtml_version_t myhtml_version(void)
1635             {
1636 0           return (myhtml_version_t){MyHTML_VERSION_MAJOR, MyHTML_VERSION_MINOR, MyHTML_VERSION_PATCH};
1637             }
1638              
1639 0           myhtml_tree_node_t * myhtml_node_clone(myhtml_tree_t* dest_tree, myhtml_tree_node_t* src)
1640             {
1641             myhtml_tag_id_t tag_id;
1642             const myhtml_tag_context_t* tag_to, * tag_from;
1643 0           myhtml_tree_node_t* new_node = myhtml_tree_node_create(dest_tree);
1644              
1645 0           tag_id = src->tag_id;
1646              
1647 0 0         if (tag_id >= MyHTML_TAG_LAST_ENTRY) {
1648 0           tag_to = myhtml_tag_get_by_id(dest_tree->tags, src->tag_id);
1649 0           tag_from = myhtml_tag_get_by_id(src->tree->tags, src->tag_id);
1650              
1651 0 0         if (tag_to == NULL
1652 0 0         || tag_to->name_length != tag_from->name_length
1653 0 0         || mycore_strncmp(tag_to->name, tag_from->name, tag_from->name_length) != 0)
1654             {
1655 0           tag_id = myhtml_tag_add(dest_tree->tags, tag_from->name, tag_from->name_length,
1656             MyHTML_TOKENIZER_STATE_DATA, true);
1657             }
1658             }
1659              
1660 0           new_node->token = myhtml_token_node_clone(dest_tree->token, src->token,
1661             dest_tree->mcasync_rules_token_id,
1662             dest_tree->mcasync_rules_attr_id);
1663 0           new_node->tag_id = tag_id;
1664 0           new_node->ns = src->ns;
1665              
1666 0 0         if(new_node->token) {
1667 0           new_node->token->tag_id = tag_id;
1668 0           new_node->token->type |= MyHTML_TOKEN_TYPE_DONE;
1669             }
1670              
1671 0           return new_node;
1672             }
1673              
1674 0           myhtml_tree_node_t * myhtml_node_clone_deep(myhtml_tree_t* dest_tree, myhtml_tree_node_t* src)
1675             {
1676             myhtml_tree_node_t* cloned, *root, *node;
1677 0           myhtml_tree_node_t* scope_node = src;
1678              
1679 0 0         if(scope_node && scope_node->tree && scope_node->tree->document == scope_node) {
    0          
    0          
1680 0           src = scope_node->child;
1681             }
1682              
1683 0           root = node = myhtml_node_clone(dest_tree, src);
1684 0 0         if (root == NULL) {
1685 0           return NULL;
1686             }
1687              
1688 0           src = src->child;
1689              
1690 0 0         while(src != NULL) {
1691 0           cloned = myhtml_node_clone(dest_tree, src);
1692 0 0         if (cloned == NULL) {
1693 0           return NULL;
1694             }
1695              
1696 0           myhtml_tree_node_add_child(node, cloned);
1697              
1698 0 0         if(src->child) {
1699 0           src = src->child;
1700 0           node = cloned;
1701             }
1702             else {
1703 0 0         while(src != scope_node && src->next == NULL) {
    0          
1704 0           node = node->parent;
1705 0           src = src->parent;
1706             }
1707              
1708 0 0         if(src == scope_node) {
1709 0           break;
1710             }
1711              
1712 0           src = src->next;
1713             }
1714             }
1715              
1716 0           return root;
1717             }