libhtmlpp 1.0.0
Loading...
Searching...
No Matches
html.cpp
Go to the documentation of this file.
1
9/*******************************************************************************
10 * Copyright (c) 2021, Jan Koester jan.koester@gmx.net
11 * All rights reserved.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions are met:
15 * Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * Neither the name of the <organization> nor the
21 * names of its contributors may be used to endorse or promote products
22 * derived from this software without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27 * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
28 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 *******************************************************************************/
35
36#include <iostream>
37#include <cstdarg>
38#include <compare>
39#include <string_view>
40#include <array>
41#include <algorithm>
42#include <fstream>
43
44#include "utils.h"
45#include "html.h"
46#include "config.h"
47#include "encode.h"
48#include <assert.h>
49
50
51#define HTMLTAG_OPEN '<'
52#define HTMLTAG_TERMINATE '/'
53#define HTMLTAG_CLOSE '>'
54#define HTMLTAG_COMMENT '!'
60namespace libhtmlpp {
61
62 const std::array<std::string_view,100> ContainerTypes{{
63 "a",
64 "abbr",
65 "address",
66 "article",
67 "aside",
68 "audio",
69 "b",
70 "bdi",
71 "bdo",
72 "blockquote",
73 "body",
74 "button",
75 "canvas",
76 "caption",
77 "cite",
78 "code",
79 "colgroup",
80 "data",
81 "datalist",
82 "dd",
83 "del",
84 "details",
85 "dfn",
86 "dialog",
87 "div",
88 "dl",
89 "dt",
90 "em",
91 "fieldset",
92 "figcaption",
93 "figure",
94 "footer",
95 "form",
96 "frame",
97 "frameset",
98 "h1",
99 "h2",
100 "h3",
101 "h4",
102 "h5",
103 "h6",
104 "head",
105 "header",
106 "hgroup",
107 "html",
108 "i",
109 "iframe",
110 "ins",
111 "kbd",
112 "label",
113 "legend",
114 "li",
115 "main",
116 "map",
117 "mark",
118 "menu",
119 "meter",
120 "nav",
121 "noscript",
122 "object",
123 "ol",
124 "optgroup",
125 "option",
126 "output",
127 "p",
128 "picture",
129 "pre",
130 "progress",
131 "q",
132 "rp",
133 "rt",
134 "ruby",
135 "s",
136 "samp",
137 "search",
138 "section",
139 "select",
140 "small",
141 "span",
142 "strong",
143 "style",
144 "sub",
145 "summary",
146 "sup",
147 "svg",
148 "table",
149 "tbody",
150 "td",
151 "template",
152 "textarea",
153 "tfoot",
154 "th",
155 "thead",
156 "time",
157 "title",
158 "tr",
159 "u",
160 "ul",
161 "var",
162 "video"
163 }};
164
166 public:
167 std::unique_ptr<Element> element;
169 std::unique_ptr<DocElements> nextel;
171
173 nextel = nullptr;
174 prevel = nullptr;
175 element = nullptr;
176 terminator = false;
177 }
178
180 auto cur = std::move(nextel);
181 while (cur) {
182 cur = std::move(cur->nextel);
183 }
184 }
185 };
186};
187
189 _Data.push_back(str);
190}
191
193 if(str.empty())
194 return;
195
196 if (!_Data.empty() && _Data.back() == '\0') {
197 _Data.pop_back();
198 }
199
200 for(auto i = str.begin(); i!=str.end(); ++i){
201 if(*i=='\0')
202 break;
203 _Data.push_back(*i);
204 }
205
206 if (_Data.empty() || _Data.back() != '\0') {
207 _Data.push_back('\0');
208 }
209}
210
213
215 std::copy(str._Data.begin(),str._Data.end(),std::insert_iterator<std::vector<char>>(_Data,_Data.begin()));
216}
217
219 if(!src)
220 return;
221
222 if (!_Data.empty() && _Data.back() == '\0') {
223 _Data.pop_back();
224 }
225 _Data.push_back(src);
226
227 _Data.push_back('\0');
228}
229
230void libhtmlpp::HtmlString::append(const std::string& src) {
231 if(src.empty())
232 return;
233
234 if (!_Data.empty() && _Data.back() == '\0') {
235 _Data.pop_back();
236 }
237
238 for(auto i = src.begin(); i!=src.end(); ++i){
239 if(*i=='\0')
240 break;
241 _Data.push_back(*i);
242 }
243
244 if (_Data.empty() || _Data.back() != '\0') {
245 _Data.push_back('\0');
246 }
247}
248
250 std::copy(hstring._Data.begin(),hstring._Data.end(),std::back_inserter(_Data));
251}
252
253void libhtmlpp::HtmlString::insert(size_t pos, char src){
254 _Data.at(pos)=src;
255}
256
258 _rootEl.reset();
259 _Data.clear();
260}
261
263 return _Data.empty();
264}
265
266
268 append(src);
269 return *this;
270}
271
273 append(hstring);
274 return *this;
275}
276
278 clear();
279 append(src);
280 return *this;
281}
282
284 clear();
285 std::copy(src._Data.begin(),src._Data.end(),std::insert_iterator<std::vector<char>>(_Data,_Data.begin()));
286 return *this;
287}
288
290 return _Data.at(pos);
291}
292
294 append(src);
295 return *this;
296}
297
299 append(src);
300 return *this;
301}
302
304 if(src._Data.data())
305 std::copy(src._Data.begin(),src._Data.end(),std::back_inserter(_Data));
306 return *this;
307}
308
310 char buf[255];
311 snprintf(buf, 255, "%d", src);
312 append(buf);
313 return *this;
314}
315
317 char buf[255];
318 snprintf(buf, 255, "%zu", src);
319 append(buf);
320 return *this;
321}
322
324 push_back(src);
325 return *this;
326}
327
329 return _Data.data();
330}
331
333 return _Data.empty() ? 0 : (_Data.size() - 1);
334}
335
337 return _Data.size();
338}
339
340const std::string libhtmlpp::HtmlString::str() const{
341 if(_Data.data())
342 return std::string(_Data.begin(),_Data.end());
343 return "";
344}
345
347 return _Data.data();
348}
349
350const std::vector<char>& libhtmlpp::HtmlString::data() const{
351 return _Data;
352}
353
354
356 HTMLException excp;
357 _buildTree();
358 return *_rootEl;
359}
360
361void libhtmlpp::HtmlString::_buildtreenode(
362 DocElements *firstel,
364 std::unique_ptr<Element> &html)
365{
366 if (!firstel) {
367 HTMLException excp;
368 excp[HTMLException::Error] << "No start Element!";
369 throw excp;
370 }
371
372 struct Frame {
373 DocElements *open; // Opener-DocElement (Start-Tag)
374 DocElements *close; // passender Terminator-DocElement (End-Tag)
375 const DocElements *outer_end; // Grenze der aktuellen Ebene
376 Element *outer_prev_el; // letztes bereits eingebautes Geschwister der äußeren Ebene
377 };
378 std::stack<Frame> stack;
379
380 DocElements *start = firstel;
381 const DocElements *end = lastel; // nullptr bedeutet: bis Ketten-Ende
382
383 Element *prev_el_in_tree = nullptr; // zuletzt in den Baum eingebautes Element
384
385 auto checkContainer = [&](const std::string &tag) {
386 for (size_t i = 0; i < ContainerTypes.size(); ++i) {
387 if (tag == ContainerTypes[i]) return true;
388 }
389 return false;
390 };
391
392 // Leere DocElements überspringen (z. B. Kommentare/Text, die nicht als element abgebildet sind)
393 auto skip_empty = [](DocElements *cur, const DocElements *stop) -> DocElements* {
394 while (cur && cur != stop && (!cur->element)) {
395 cur = cur->nextel.get();
396 }
397 return cur;
398 };
399
400 // Finde zum gegebenen Start-Tag dessen passenden Terminator in [open->nextel, bound).
401 auto find_terminator = [&skip_empty, checkContainer](DocElements *open, const DocElements *bound) -> DocElements* {
402 if (!open || !open->element || open->terminator ||
403 open->element->getType() != HtmlEl) return nullptr;
404
405 const std::string &tag = static_cast<HtmlElement*>(open->element.get())->getTagname();
406 int nest = 0;
407 DocElements *cur = open->nextel.get();
408
409 while (cur && cur != bound) {
410 cur = skip_empty(cur, bound);
411 if (!cur || cur == bound) break;
412
413 if (cur->element && cur->element->getType() == HtmlEl) {
414 const std::string &curtag = static_cast<HtmlElement*>(cur->element.get())->getTagname();
415 if (curtag == tag) {
416 if (cur->terminator) {
417 if (nest == 0) return cur; // passendes End-Tag gefunden
418 --nest;
419 } else {
420 ++nest;
421 }
422 }
423 }
424 cur = cur->nextel.get();
425 }
426
427 // Wenn ein Container nicht geschlossen wurde: Fehler werfen
428 if (checkContainer(tag)) {
429 HTMLException e;
430 e[HTMLException::Error] << tag << " must be terminated ! "
431 << static_cast<HtmlElement*>(open->element.get())->getAtributte("id");
432 throw e;
433 }
434 return nullptr;
435 };
436
437 for (;;) {
438 // bis zum nächsten sinnvollen DocElement laufen
439 start = skip_empty(start, end);
440
441 // Terminator-Knoten als eigenständige Nodes überspringen
442 if (start && start != end && start->terminator) {
443 start = start->nextel.get();
444 continue;
445 }
446
447 // Ende der aktuellen Ebene erreicht?
448 if (!start || start == end) {
449 if (stack.empty()) {
450 // Ganz oben: Root setzen (falls vorhanden)
451 if (firstel->element) {
452 html = std::move(firstel->element);
453 }
454 return;
455 }
456
457 // Frame schließen: Kinderbereich [open->nextel, close) einsammeln
458 Frame fr = stack.top(); stack.pop();
459 HtmlElement *opener_el = static_cast<HtmlElement*>(fr.open->element.get());
460
461 // Alle Kinder zwischen open und close verketten
462 Element* last_child_in_chain = nullptr;
463 {
464 DocElements* cur = fr.open->nextel.get();
465 // bis zum ersten brauchbaren Kind
466 while (cur && cur != fr.close && (!cur->element || cur->terminator)) {
467 cur = cur->nextel.get();
468 }
469
470 // alle nicht-leeren, nicht-Terminierer bis vor close anbinden
471 while (cur && cur != fr.close) {
472 if (cur->element && !cur->terminator) {
473 if (!opener_el->_childElement) {
474 opener_el->_childElement = std::move(cur->element);
475 last_child_in_chain = opener_el->_childElement.get();
476 } else {
477 last_child_in_chain->_nextElement = std::move(cur->element);
478 // _prev (falls genutzt) setzen
479 last_child_in_chain->_nextElement->_prevElement = last_child_in_chain;
480 last_child_in_chain = last_child_in_chain->_nextElement.get();
481 }
482 }
483 cur = cur->nextel.get();
484 // leere/terminator Knoten überspringen
485 while (cur && cur != fr.close && (!cur->element || cur->terminator)) {
486 cur = cur->nextel.get();
487 }
488 }
489 }
490
491 // dieses Container-Element ist nun das "aktuelle" in der äußeren Ebene
492 prev_el_in_tree = opener_el;
493
494 // Wenn es bereits ein vorheriges Geschwister in der äußeren Ebene gibt: verketten
495 if (fr.outer_prev_el) {
496 prev_el_in_tree->_prevElement = fr.outer_prev_el;
497 fr.outer_prev_el->_nextElement = std::move(fr.open->element);
498 prev_el_in_tree = fr.outer_prev_el->_nextElement.get();
499 }
500
501 // für die äußere Ebene fortsetzen
502 prev_el_in_tree = opener_el;
503 start = (fr.close ? fr.close->nextel.get() : nullptr);
504 end = fr.outer_end;
505
506 continue;
507 }
508
509 // Start-Tag eines HTML-Elements: passenden Terminator suchen → in den Stack tauchen
510 if (start->element && !start->terminator && start->element->getType() == HtmlEl) {
511 if (DocElements *close = find_terminator(start, end)) {
512 // neuen Rahmen für diesen Container aufmachen
513 stack.push(Frame{start, close, end, prev_el_in_tree});
514
515 // wir wechseln in die innere Ebene: prev zurücksetzen
516 prev_el_in_tree = nullptr;
517 start = start->nextel.get();
518 end = close;
519 continue;
520 }
521 }
522
523 // "normales" Element (kein Container mit eigenem Terminatorbereich):
524 if (start->element && !start->terminator) {
525 Element *current_el = start->element.get();
526
527 if (prev_el_in_tree) {
528 current_el->_prevElement = prev_el_in_tree;
529 prev_el_in_tree->_nextElement = std::move(start->element);
530 prev_el_in_tree = prev_el_in_tree->_nextElement.get();
531 } else {
532 prev_el_in_tree = current_el;
533 }
534 }
535
536 // weiter zum nächsten DocElement
537 start = start->nextel.get();
538 }
539}
540
546void libhtmlpp::HtmlString::_buildTree() {
547 DocElements* lastEl = nullptr;
548 std::unique_ptr<DocElements> firstEl = nullptr;
549
550 auto is_ws = [](unsigned char ch) -> bool {
551 // space, \t, \n, \r
552 return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r';
553 };
554
555 auto ascii_tolower = [](unsigned char c) -> unsigned char {
556 return (c >= 'A' && c <= 'Z') ? static_cast<unsigned char>(c + 32) : c;
557 };
558
559 auto starts_with_ci = [&](const char* s, const char* e, const char* k) -> bool {
560 const size_t klen = std::char_traits<char>::length(k);
561 if (static_cast<size_t>(e - s) < klen) return false;
562 for (size_t i = 0; i < klen; ++i) {
563 unsigned char a = static_cast<unsigned char>(s[i]);
564 unsigned char b = static_cast<unsigned char>(k[i]);
565 if (ascii_tolower(a) != ascii_tolower(b)) return false;
566 }
567 return true;
568 };
569
570 auto add_element_node = [&](DocElements** last) {
571 if (!firstEl) {
572 firstEl = std::make_unique<DocElements>();
573 *last = firstEl.get();
574 } else {
575 (*last)->nextel = std::make_unique<DocElements>();
576 (*last)->nextel->prevel = (*last);
577 *last = (*last)->nextel.get();
578 }
579 };
580
581 const char* const base = _Data.data();
582 const size_t n = _Data.size();
583 const char* const end = base + n;
584
585 const char* p = base;
586
587 while (p < end) {
588 while (p < end && is_ws(static_cast<unsigned char>(*p))) ++p;
589 if (p >= end) break;
590
591 if (*p == HTMLTAG_OPEN) { // '<'
592 const char* const remain_end = end;
593 const size_t remain = static_cast<size_t>(remain_end - p);
594
595 if (remain >= 2) {
596 const unsigned char c1 = ascii_tolower(static_cast<unsigned char>(p[1]));
597
598 if (p[1] == '!') {
599 // <!-- ... -->
600 if (starts_with_ci(p, end, "<!--")) {
601 add_element_node(&lastEl);
602 size_t i = static_cast<size_t>(p - base);
603 i = CommentElement::parseElement(_Data, lastEl->element, i, lastEl->terminator);
604 p = base + i;
605 continue;
606 }
607 } else if (c1 == 's') {
608 if (starts_with_ci(p, end, "<script")) {
609 add_element_node(&lastEl);
610 size_t i = static_cast<size_t>(p - base);
611 i = ScriptElement::parseElement(_Data, lastEl->element, i, lastEl->terminator);
612 p = base + i;
613 continue;
614 }
615 if (starts_with_ci(p, end, "<svg")) {
616 add_element_node(&lastEl);
617 size_t i = static_cast<size_t>(p - base);
618 i = SvgElement::parseElement(_Data, lastEl->element, i, lastEl->terminator);
619 p = base + i;
620 continue;
621 }
622 } else if (c1 == 't') {
623 if (starts_with_ci(p, end, "<textarea")) {
624 add_element_node(&lastEl);
625 size_t i = static_cast<size_t>(p - base);
626 i = TextArea::parseElement(_Data, lastEl->element, i, lastEl->terminator);
627 p = base + i;
628 continue;
629 }
630 }
631 }
632
633 {
634 add_element_node(&lastEl);
635 size_t i = static_cast<size_t>(p - base);
636 i = HtmlElement::parseElement(_Data, lastEl->element, i, lastEl->terminator);
637 p = base + i;
638 }
639 } else {
640 add_element_node(&lastEl);
641 size_t i = static_cast<size_t>(p - base);
642 i = TextElement::parseElement(_Data, lastEl->element, i, lastEl->terminator);
643 p = base + i;
644 }
645 }
646
647 _buildtreenode(firstEl.get(), nullptr, _rootEl);
648}
649
657std::ostream& operator<<(std::ostream& os, const libhtmlpp::HtmlString& p) {
658 os << p.str();
659 return os;
660}
661
662void libhtmlpp::HtmlEncode(const std::string &input, std::string &output){
663 size_t ilen=input.length();
664 for(size_t i=0; i<ilen; ++i){
665 size_t ii=0;
666 bool changed=false;
667 while(HtmlSigns[ii][0]){
668 if(input[i]==HtmlSigns[ii][0][0]){
669 output+=HtmlSigns[ii][1];
670 changed=true;
671 }
672 ++ii;
673 }
674 if(!changed)
675 output.push_back(input[i]);
676 }
677}
678
679void libhtmlpp::HtmlDecode(const std::string &input,std::string &output){
680 size_t ilen=input.length();
681 for(size_t i=0; i<ilen; ++i){
682 size_t ii=0;
683 bool changed=false;
684 while(HtmlSigns[ii][0]){
685 if(input.compare(i,strlen(HtmlSigns[ii][1]),HtmlSigns[ii][1]) == 0){
686 output += HtmlSigns[ii][0];
687 changed=true;
688 }
689 ++ii;
690 }
691 if(!changed)
692 output += input[i];
693 }
694}
695
696void libhtmlpp::HtmlDecode(const std::string &input,HtmlString &output){
697 std::string tmp;
698 HtmlDecode(input,tmp);
699 output << tmp;
700 output.parse();
701}
702
703libhtmlpp::HtmlElement::HtmlElement(const std::string &tagname) : HtmlElement(){
704 _TagName.clear();
705 std::copy(tagname.begin(),tagname.end(),std::back_inserter(_TagName));
706}
707
709 _childElement=nullptr;
710 _firstAttr=nullptr;
711 _lastAttr=nullptr;
712}
713
717
721
724
726 return -1;
727}
728
729void libhtmlpp::HtmlElement::setTagname(const std::string &name){
730 _TagName.clear();
731 std::copy(name.begin(),name.begin()+name.length(),std::back_inserter(_TagName));
732}
733
734const std::string libhtmlpp::HtmlElement::getTagname() const{
735 if(_TagName.empty())
736 return "";
737 return std::string(_TagName.begin(),_TagName.end());
738}
739
741 if(_childElement){
742 remove(_childElement.get());
743 }
744
745 switch(el->getType()){
746 case HtmlEl:
747 _childElement=std::make_unique<HtmlElement>();
748 break;
749 case TextEl:
750 _childElement=std::make_unique<TextElement>();
751 break;
752 case CommentEl:
753 _childElement=std::make_unique<CommentElement>();
754 break;
755 case ScriptEL:
756 _childElement=std::make_unique<ScriptElement>();
757 break;
758 case SvgEL:
759 _childElement=std::make_unique<SvgElement>();
760 break;
761 default:
762 HTMLException ex;
763 ex[HTMLException::Critical] << "appendChild: Unknown html element found: "<< el->getType() << " !";
764 throw ex;
765 }
766 _copy(_childElement.get(),el);
767}
768
770 insertChild(&el);
771}
772
774 if(!el)
775 return;
776 if(_childElement){
777 Element *prev=nullptr;
778
779 for(Element *curel=_childElement.get(); curel; curel=curel->nextElement()){
780 prev=curel;
781 }
782
783 switch(el->getType()){
784 case HtmlEl:
785 prev->_nextElement=std::make_unique<HtmlElement>();
786 break;
787 case TextEl:
788 prev->_nextElement=std::make_unique<TextElement>();
789 break;
790 case CommentEl:
791 prev->_nextElement=std::make_unique<CommentElement>();
792 break;
793 case ScriptEL:
794 prev->_nextElement=std::make_unique<ScriptElement>();
795 break;
796 case SvgEL:
797 prev->_nextElement=std::make_unique<SvgElement>();
798 break;
799 default:
800 HTMLException ex;
801 ex[HTMLException::Critical] << "appendChild: Unknown html element found: "<< el->getType() << " !";
802 throw ex;
803 }
804
805 _copy(prev->_nextElement.get(),el);
806
807 if(prev->_nextElement){
808 prev->_nextElement->_prevElement=prev;
809 }
810 }else{
811 insertChild(el);
812 }
813}
814
816 appendChild(&el);
817}
818
819
821 if(!hel)
822 return false;
823 if( _TagName.size() != hel->_TagName.size())
824 return false;
825 if(std::equal(_TagName.begin(),_TagName.end(),hel->_TagName.begin()))
826 return true;
827 return false;
828}
829
831 if(_TagName.size() != hel._TagName.size())
832 return false;
833 if(std::equal(_TagName.begin(),_TagName.end(),hel._TagName.begin()))
834 return true;
835 return false;
836}
837
839 _copy(this,&hel);
840 return *this;
841}
842
847
849 Element *cur=this;
850
851 std::stack<Element*> parents;
852
853 DELETEELEMENT:
854 while(cur){
855 if(cur==el){
856 if(cur->_prevElement)
857 cur->_prevElement->_nextElement=std::move(cur->_nextElement);
858 if(cur->_nextElement)
859 cur->_nextElement->_prevElement=cur->_prevElement;
860 cur->_nextElement=nullptr;
861 cur->_prevElement=nullptr;
862 cur=nullptr;
863 }
864
865 if(cur->getType()==HtmlEl){
866 if(((HtmlElement*)cur)->_childElement){
867 parents.push(cur);
868 cur=((HtmlElement*)cur)->_childElement.get();
869 }
870 }
871
872 Element *next=cur->_nextElement.get();
873 cur=next;
874 }
875
876 if(!parents.empty()){
877 cur=parents.top()->nextElement();
878 parents.pop();
879 if(cur!=el)
880 goto DELETEELEMENT;
881 }
882
883
884}
885
893void libhtmlpp::HtmlElement::_serialelize(const std::vector<char>& in) {
894 _TagName.clear();
895
896 auto is_space = [](unsigned char c) -> bool {
897 return c == ' ' || c == '\t' || c == '\n' || c == '\r';
898 };
899 auto tolower_ascii = [](unsigned char c) -> unsigned char {
900 return (c >= 'A' && c <= 'Z') ? static_cast<unsigned char>(c + 32) : c;
901 };
902
903 size_t i = 0, n = in.size();
904
905 if (i < n && in[i] == '<') ++i;
906 while (i < n && is_space(static_cast<unsigned char>(in[i]))) ++i;
907
908 bool end_tag = false;
909 if (i < n && in[i] == '/') {
910 end_tag = true;
911 ++i;
912 while (i < n && is_space(static_cast<unsigned char>(in[i]))) ++i;
913 }
914
915 size_t r = n;
916 while (r > i && is_space(static_cast<unsigned char>(in[r - 1]))) --r;
917 if (r > i && in[r - 1] == '>') --r; // ignore '>' if present
918 while (r > i && is_space(static_cast<unsigned char>(in[r - 1]))) --r;
919
920 if (i >= r) {
921 HTMLException excp;
922 throw excp[HTMLException::Critical] << "no tag in element found!";
923 }
924
925 const size_t name_start = i;
926 while (i < r) {
927 unsigned char c = static_cast<unsigned char>(in[i]);
928 if (is_space(c) || c == '/' || c == '>') break;
929 ++i;
930 }
931 const size_t name_end = i;
932 if (name_start == name_end) {
933 HTMLException excp;
934 throw excp[HTMLException::Critical] << "no tag in element found!";
935 }
936
937 _TagName.assign(in.begin() + name_start, in.begin() + name_end);
938 for (char& ch : _TagName) ch = static_cast<char>(tolower_ascii(static_cast<unsigned char>(ch)));
939
940 if (end_tag) {
941 return;
942 }
943
944 while (i < r) {
945 while (i < r && is_space(static_cast<unsigned char>(in[i]))) ++i;
946 if (i >= r) break;
947
948 if (in[i] == '/') {
949 ++i;
950 while (i < r && is_space(static_cast<unsigned char>(in[i]))) ++i;
951 break;
952 }
953
954 const size_t kstart = i;
955 while (i < r) {
956 unsigned char c = static_cast<unsigned char>(in[i]);
957 if (is_space(c) || c == '=' || c == '/' || c == '>') break;
958 ++i;
959 }
960 const size_t kend = i;
961 if (kstart == kend) {
962 ++i;
963 continue;
964 }
965
966 std::string key(in.begin() + kstart, in.begin() + kend);
967 for (char& ch : key) ch = static_cast<char>(tolower_ascii(static_cast<unsigned char>(ch)));
968
969 while (i < r && is_space(static_cast<unsigned char>(in[i]))) ++i;
970
971 std::string val;
972
973 if (i < r && in[i] == '=') {
974 ++i;
975 while (i < r && is_space(static_cast<unsigned char>(in[i]))) ++i;
976
977 if (i < r && (in[i] == '"' || in[i] == '\'')) {
978 char quote = in[i++];
979 const size_t vstart = i;
980 while (i < r && in[i] != quote) ++i;
981 const size_t vend = i;
982 val.assign(in.begin() + vstart, in.begin() + vend);
983 if (i < r && in[i] == quote) ++i;
984 } else {
985 const size_t vstart = i;
986 while (i < r) {
987 unsigned char c = static_cast<unsigned char>(in[i]);
988 if (is_space(c) || c == '/' || c == '>') break;
989 ++i;
990 }
991 const size_t vend = i;
992 val.assign(in.begin() + vstart, in.begin() + vend);
993 }
994 } else {
995 val.clear();
996 }
997
998 setAttribute(key, val);
999 }
1000}
1001
1002
1004 const std::vector<char>& in,
1005 std::unique_ptr<libhtmlpp::Element>& el,
1006 size_t start,
1007 bool& termination
1008){
1009 el = std::make_unique<HtmlElement>();
1010 termination = false;
1011
1012 size_t i = start;
1013 if (i >= in.size() || in[i] != HTMLTAG_OPEN) return i;
1014
1015 ++i;
1016
1017 while (i < in.size() && std::isspace(static_cast<unsigned char>(in[i]))) ++i;
1018
1019
1020
1021 size_t close = i;
1022 while (close < in.size() && in[close] != HTMLTAG_CLOSE) { // '>'
1023 ++close;
1024 }
1025
1026 size_t k = i;
1027 while (k < close && std::isspace(static_cast<unsigned char>(in[k]))) ++k;
1028
1029 std::vector<char> tel;
1030
1031 if (k < close && in[k] == HTMLTAG_TERMINATE) { // '/'
1032 termination = true;
1033 ++k;
1034 while (k < close && std::isspace(static_cast<unsigned char>(in[k]))) ++k;
1035 }
1036
1037 tel.insert(tel.end(), in.begin() + k, in.begin() + close);
1038
1039 reinterpret_cast<HtmlElement*>(el.get())->_serialelize(tel);
1040
1041 return ++close;
1042}
1043
1044namespace libhtmlpp {
1045
1047 if(!dest || !src)
1048 return;
1049
1050 const libhtmlpp::Element* prev=nullptr;
1051
1052 struct cpyel {
1053 cpyel(){
1054 destin = nullptr;
1055 source = nullptr;
1056 };
1057
1058 cpyel(const cpyel &src){
1059 destin=src.destin;
1060 source=src.source;
1061 };
1062
1063 ~cpyel(){
1064 }
1065
1066 libhtmlpp::Element *destin;
1067 libhtmlpp::Element *source;
1068 };
1069
1070 std::stack<cpyel> cpylist;
1071
1072 NEWEL:
1073
1074 if(src->getType()==HtmlEl && dest->getType()==HtmlEl){
1075 ((libhtmlpp::HtmlElement*)dest)->_TagName=(((libhtmlpp::HtmlElement*)src)->_TagName);
1076 for(libhtmlpp::HtmlElement::Attributes *cattr=((libhtmlpp::HtmlElement*)src)->_firstAttr.get(); cattr; cattr=cattr->_nextAttr.get()){
1077 ((libhtmlpp::HtmlElement*)dest)->setAttribute(
1078 std::string(
1079 cattr->_Key.begin(),
1080 cattr->_Key.end()
1081 ),std::string(
1082 cattr->_Value.begin(),
1083 cattr->_Value.end()
1084 )
1085 );
1086 }
1087
1088 if(((libhtmlpp::HtmlElement*)src)->_childElement){
1089 switch(((libhtmlpp::HtmlElement*)src)->_childElement->getType()){
1090 case HtmlEl:
1091 ((libhtmlpp::HtmlElement*)dest)->_childElement=std::make_unique<HtmlElement>();
1092 break;
1093 case TextEl:
1094 ((libhtmlpp::HtmlElement*)dest)->_childElement =std::make_unique<TextElement>();
1095 break;
1096 case CommentEl:
1097 ((libhtmlpp::HtmlElement*)dest)->_childElement = std::make_unique<CommentElement>();
1098 break;
1099 case ScriptEL:
1100 ((libhtmlpp::HtmlElement*)dest)->_childElement = std::make_unique<ScriptElement>();
1101 break;
1102 case SvgEL:
1103 ((libhtmlpp::HtmlElement*)dest)->_childElement = std::make_unique<SvgElement>();
1104 break;
1105 case TextAreaEL:
1106 ((libhtmlpp::HtmlElement*)dest)->_childElement = std::make_unique<TextArea>();
1107 break;
1108 default:
1109 HTMLException ex;
1110 ex[HTMLException::Critical] << "_copy: Unknown html element found !";
1111 throw ex;
1112 }
1113 cpyel childel;
1114 childel.destin=((libhtmlpp::HtmlElement*)dest)->_childElement.get();
1115 childel.source=((libhtmlpp::HtmlElement*)src)->_childElement.get();
1116 cpylist.push(childel);
1117 }
1118 }else if(src->getType()==libhtmlpp::ScriptEL && dest->getType()== libhtmlpp::ScriptEL){
1119 ((libhtmlpp::ScriptElement*)dest)->_TagName=(((libhtmlpp::ScriptElement*)src)->_TagName);
1120 for(libhtmlpp::ScriptElement::Attributes *cattr=((libhtmlpp::ScriptElement*)src)->_firstAttr.get(); cattr; cattr=cattr->_nextAttr.get()){
1121 if(!cattr->_Value.empty()){
1122 ((libhtmlpp::ScriptElement*)dest)->setAttribute(
1123 std::string(
1124 cattr->_Key.begin(),
1125 cattr->_Key.end()
1126 ),std::string(
1127 cattr->_Value.begin(),
1128 cattr->_Value.end()
1129 )
1130 );
1131 }else{
1132 ((libhtmlpp::ScriptElement*)dest)->setAttribute(std::string(cattr->_Key.begin(),cattr->_Key.end()),"");
1133 }
1134 }
1135 ((ScriptElement*)dest)->_Script=(((ScriptElement*)src)->_Script);
1136 }else if(src->getType()==libhtmlpp::SvgEL && dest->getType()== libhtmlpp::SvgEL){
1137 ((libhtmlpp::SvgElement*)dest)->_TagName=(((libhtmlpp::SvgElement*)src)->_TagName);
1138 for(libhtmlpp::SvgElement::Attributes *cattr=((libhtmlpp::SvgElement*)src)->_firstAttr.get(); cattr; cattr=cattr->_nextAttr.get()){
1139 if(!cattr->_Value.empty()){
1140 ((libhtmlpp::SvgElement*)dest)->setAttribute(
1141 std::string(
1142 cattr->_Key.begin(),
1143 cattr->_Key.end()
1144 ),std::string(
1145 cattr->_Value.begin(),
1146 cattr->_Value.end()
1147 )
1148 );
1149 }else{
1150 ((libhtmlpp::SvgElement*)dest)->setAttribute(std::string(cattr->_Key.begin(),cattr->_Key.end()),"");
1151 }
1152 }
1153 ((SvgElement*)dest)->_Svg=(((SvgElement*)src)->_Svg);
1154 }else if(src->getType()==libhtmlpp::TextAreaEL&& dest->getType()== libhtmlpp::TextAreaEL){
1155 ((libhtmlpp::TextArea*)dest)->_TagName=(((libhtmlpp::TextArea*)src)->_TagName);
1156 for(libhtmlpp::TextArea::Attributes *cattr=((libhtmlpp::TextArea*)src)->_firstAttr.get(); cattr; cattr=cattr->_nextAttr.get()){
1157 if(!cattr->_Value.empty()){
1158 ((libhtmlpp::TextArea*)dest)->setAttribute(
1159 std::string(
1160 cattr->_Key.begin(),
1161 cattr->_Key.end()
1162 ),std::string(
1163 cattr->_Value.begin(),
1164 cattr->_Value.end()
1165 )
1166 );
1167 }else{
1168 ((libhtmlpp::TextArea*)dest)->setAttribute(std::string(cattr->_Key.begin(),cattr->_Key.end()),"");
1169 }
1170 }
1171 ((TextArea*)dest)->_Text=(((TextArea*)src)->_Text);
1172 }else if(src->getType()==libhtmlpp::TextEl && dest->getType()== libhtmlpp::TextEl){
1173 ((TextElement*)dest)->_Text=(((TextElement*)src)->_Text);
1174 }else if(src->getType()==libhtmlpp::CommentEl && dest->getType()== libhtmlpp::CommentEl){
1175 ((CommentElement*)dest)->_Comment=(((CommentElement*)src)->_Comment);
1176 }
1177
1178 if(prev)
1179 dest->_prevElement=(Element*)prev;
1180
1181 Element* next=src->nextElement();
1182
1183 if(next){
1184 switch(next->getType()){
1185 case HtmlEl:
1186 dest->_nextElement= std::make_unique<HtmlElement>();
1187 break;
1188 case TextEl:
1189 dest->_nextElement= std::make_unique<TextElement>();
1190 break;
1191 case CommentEl:
1192 dest->_nextElement= std::make_unique<CommentElement>();
1193 break;
1194 case ScriptEL:
1195 dest->_nextElement= std::make_unique<ScriptElement>();
1196 break;
1197 case SvgEL:
1198 dest->_nextElement= std::make_unique<SvgElement>();
1199 break;
1200 case TextAreaEL:
1201 dest->_nextElement= std::make_unique<TextArea>();
1202 break;
1203 default:
1204 HTMLException ex;
1205 ex[HTMLException::Critical] << "_copy: Unknown next html element found !";
1206 throw ex;
1207 }
1208 prev=dest;
1209 src=next;
1210 dest=dest->_nextElement.get();
1211 goto NEWEL;
1212 }
1213
1214 if(!cpylist.empty()){
1215 cpyel childel(cpylist.top());
1216 prev=nullptr;
1217 dest=childel.destin;
1218 src=childel.source;
1219 cpylist.pop();
1220 goto NEWEL;
1221 }
1222 return;
1223 }
1224};
1225
1227 std::unique_ptr<Element> nel;
1228 switch(el->getType()){
1229 case HtmlEl:
1230 nel->_nextElement= std::make_unique<HtmlElement>();
1231 break;
1232 case TextEl:
1233 nel->_nextElement= std::make_unique<TextElement>();
1234 break;
1235 case CommentEl:
1236 nel->_nextElement= std::make_unique<CommentElement>();
1237 break;
1238 case ScriptEL:
1239 nel->_nextElement= std::make_unique<ScriptElement>();
1240 break;
1241 case SvgEL:
1242 nel->_nextElement= std::make_unique<SvgElement>();
1243 break;
1244 case TextAreaEL:
1245 nel->_nextElement= std::make_unique<TextArea>();
1246 break;
1247 default:
1248 HTMLException ex;
1249 ex[HTMLException::Critical] << "_copy: Unknown next html element found !";
1250 throw ex;
1251 }
1252 _copy(nel.get(),el);
1253 std::unique_ptr<Element> prev=std::move(_prevElement->_nextElement);
1254 _prevElement->_nextElement=std::move(nel);
1255 nel->_nextElement=std::move(prev);
1256}
1257
1259 Element *nexel=nullptr,*prev=nullptr;
1260
1261 switch(el->getType()){
1262 case HtmlEl:
1263 _nextElement= std::make_unique<HtmlElement>();
1264 break;
1265 case TextEl:
1266 _nextElement= std::make_unique<TextElement>();
1267 break;
1268 case CommentEl:
1269 _nextElement= std::make_unique<CommentElement>();
1270 break;
1271 case ScriptEL:
1272 _nextElement= std::make_unique<ScriptElement>();
1273 break;
1274 case SvgEL:
1275 _nextElement= std::make_unique<SvgElement>();
1276 break;
1277 case TextAreaEL:
1278 _nextElement= std::make_unique<TextArea>();
1279 break;
1280 default:
1281 HTMLException ex;
1282 ex[HTMLException::Critical] << "_copy: Unknown next html element found !";
1283 throw ex;
1284 }
1285
1286 _copy(_nextElement.get(),el);
1287
1288 nexel=_nextElement.get();
1289
1290 while(nexel){
1291 prev=nexel;
1292 nexel=nexel->nextElement();
1293 }
1294
1295 nexel=prev;
1296
1297}
1298
1300 _copy(this,&hel);
1301 return *this;
1302}
1303
1305 _copy(this,hel);
1306 return *this;
1307}
1308
1310 return _nextElement.get();
1311}
1312
1314 return _prevElement;
1315}
1316
1318 _prevElement=nullptr;
1319 _nextElement=nullptr;
1320}
1321
1323 _prevElement=nullptr;
1324 _nextElement=nullptr;
1325 _copy(this,&el);
1326}
1327
1329 auto cur = std::move(_nextElement);
1330 while (cur) {
1331 cur = std::move(cur->_nextElement);
1332 }
1333};
1334
1336 Element *curel=this;
1337
1338 while(curel){
1339 Element *next=curel->_nextElement.get();
1340
1341 if(curel==el){
1342 if(curel->_prevElement)
1343 curel->_prevElement->_nextElement=std::move(curel->_nextElement);
1344
1345 if(curel->_nextElement)
1346 curel->_nextElement->_prevElement=curel->_prevElement;
1347 curel->_prevElement=nullptr;
1348 curel->_nextElement=nullptr;
1349 }
1350
1351 curel=next;
1352 }
1353}
1354
1355
1358
1360 setText(txt);
1361}
1362
1364 _copy(this,&texel);
1365}
1366
1369
1370
1372 _copy(this,&hel);
1373 return *this;
1374}
1375
1377 _copy(this,hel);
1378 return *this;
1379}
1380
1381void libhtmlpp::TextElement::setText(const std::string& txt){
1382 std::copy(txt.begin(),txt.end(),std::back_inserter(_Text));
1383}
1384
1386 return std::string(_Text.begin(),_Text.end());
1387}
1388
1392
1394 const std::vector<char>& in,
1395 std::unique_ptr<libhtmlpp::Element>& el,
1396 size_t start,
1397 bool &termination
1398){
1399 termination = false;
1400
1401 std::vector<char> buf;
1402 buf.reserve(64);
1403 bool seen_nonws = false;
1404 bool last_was_space = false;
1405
1406 size_t i = start;
1407 while (i < in.size()) {
1408 char c = in[i];
1409 if (c == HTMLTAG_OPEN) {
1410 break;
1411 }
1412
1413 if (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
1414 if (seen_nonws) {
1415 if (!last_was_space) {
1416 buf.push_back(' ');
1417 last_was_space = true;
1418 }
1419 }
1420 ++i;
1421 continue;
1422 }
1423
1424 buf.push_back(c);
1425 seen_nonws = true;
1426 last_was_space = false;
1427 ++i;
1428 }
1429
1430 if (!buf.empty()) {
1431 auto text = std::make_unique<TextElement>();
1432 (static_cast<TextElement*>(text.get()))->_Text.insert(
1433 (static_cast<TextElement*>(text.get()))->_Text.end(),
1434 buf.begin(), buf.end()
1435 );
1436 el = std::move(text);
1437 }
1438
1439 return i;
1440}
1441
1442
1445
1447 _copy(this,&comel);
1448}
1449
1452
1453
1455 _copy(this,&hel);
1456 return *this;
1457}
1458
1460 _copy(this,hel);
1461 return *this;
1462}
1463
1464void libhtmlpp::CommentElement::setComment(const std::string& txt){
1465 std::copy(txt.begin(),txt.end(),
1466 std::insert_iterator<std::vector<char>>(_Comment,_Comment.begin()));
1467}
1468
1470 return std::string(_Comment.begin(),_Comment.end());
1471}
1472
1476
1478 const std::vector<char>& in,
1479 std::unique_ptr<Element>& el,
1480 size_t start,
1481 bool& termination
1482){
1483 termination = false;
1484
1485 size_t i = start;
1486 if (i + 3 >= in.size()) return i;
1487
1488 if (!(in[i] == '<' && in[i+1] == '!' && in[i+2] == '-' && in[i+3] == '-')) {
1489 return i;
1490 }
1491
1492 el = std::make_unique<CommentElement>();
1493
1494 i += 4;
1495 const size_t content_begin = i;
1496
1497 while (i + 2 < in.size()) {
1498 if (in[i] == '-' && in[i+1] == '-' && in[i+2] == '>') {
1499 break;
1500 }
1501 ++i;
1502 }
1503
1504 auto* self = static_cast<CommentElement*>(el.get());
1505 if (i > content_begin) {
1506 self->_Comment.insert(self->_Comment.end(),
1507 in.begin() + content_begin,
1508 in.begin() + i);
1509 }
1510
1511 if (i + 2 < in.size()) {
1512 i += 3;
1513 } else {
1514 i = in.size();
1515 }
1516 return i;
1517}
1518
1519
1522
1524 _copy(this,&scriptsrc);
1525}
1526
1529
1530
1532 _copy(this,&hel);
1533 return *this;
1534}
1535
1537 _copy(this,hel);
1538 return *this;
1539}
1540
1541void libhtmlpp::ScriptElement::setScript(const std::string& script){
1542 std::copy(script.begin(),script.end(),std::back_inserter(_Script));
1543}
1544
1546 return std::string(_Script.begin(),_Script.end());
1547}
1548
1552
1554 const std::vector<char>& in,
1555 std::unique_ptr<Element>& el,
1556 size_t start,
1557 bool& termination
1558){
1559termination = false;
1560 el = std::make_unique<ScriptElement>();
1561 auto* self = static_cast<ScriptElement*>(el.get());
1562
1563 size_t i = start;
1564 if (i >= in.size() || in[i] != '<') {
1565 // If it doesn't start with '<', we can't parse a tag here.
1566 return start;
1567 }
1568
1569 // Helper to perform case-insensitive comparison
1570 auto iequals = [](char a, char b) {
1571 return std::tolower(static_cast<unsigned char>(a)) ==
1572 std::tolower(static_cast<unsigned char>(b));
1573 };
1574
1575 // Helper to perform case-insensitive match for a keyword starting at 'pos'
1576 auto match_ci = [&](size_t pos, const char* k) -> bool {
1577 for (size_t j = 0; k[j]; ++j) {
1578 if (pos + j >= in.size() || !iequals(in[pos + j], k[j])) {
1579 return false;
1580 }
1581 }
1582 return true;
1583 };
1584
1585 // --- 1. Validate Opening Tag Name (<script) ---
1586 ++i; // Consume '<'
1587
1588 // Skip leading whitespace after '<'
1589 while (i < in.size() && std::isspace(static_cast<unsigned char>(in[i]))) {
1590 ++i;
1591 }
1592
1593 const char* tag_keyword = "script";
1594 size_t keyword_len = std::char_traits<char>::length(tag_keyword);
1595
1596 if (i + keyword_len >= in.size() || !match_ci(i, tag_keyword)) {
1597 // Tag name doesn't match "script"
1598 // Skip till next '>' and return the position after it.
1599 while (i < in.size() && in[i] != '>') {
1600 ++i;
1601 }
1602 if (i < in.size()) {
1603 ++i; // Consume '>'
1604 }
1605 return i;
1606 }
1607 i += keyword_len; // Consume "script"
1608
1609 // --- 2. Extract Opening Tag and Attributes ---
1610 // Find the closing '>' of the opening tag.
1611 size_t tag_end = i;
1612 while (i < in.size() && in[i] != '>') {
1613 ++i;
1614 }
1615
1616 // Capture the raw opening tag data (including '<script' and attributes) for serialization.
1617 if (i > start && in[i] == '>') {
1618 // Copy data from '<' (start) up to and including '>' (i)
1619 std::vector<char> raw_tag_data(in.begin() + start, in.begin() + i + 1);
1620 self->_serialelize(raw_tag_data);
1621 }
1622
1623 if (i >= in.size() || in[i] != '>') {
1624 // The tag was never closed (e.g., '<script src="..." EOF')
1625 return i;
1626 }
1627
1628 ++i; // Consume '>' and move to content start
1629 size_t content_begin = i;
1630
1631 // --- 3. Extract Script Content (CDATA-like section) ---
1632 for (; i < in.size(); ++i) {
1633 // Look for the start of the closing tag sequence: </script
1634 if (in[i] == '<' && match_ci(i, "</script")) {
1635 size_t content_end = i;
1636
1637 // 3a. Extract content preceding the closing tag
1638 if (content_end > content_begin) {
1639 // FIX: Use std::vector::insert instead of non-existent append
1640 self->_Script.insert(self->_Script.end(),
1641 in.begin() + content_begin,
1642 in.begin() + content_end);
1643 }
1644
1645 // 3b. Find the end of the closing tag: </script>
1646 size_t closing_tag_end_pos = i + keyword_len + 2; // +2 for '</'
1647
1648 // Skip any characters/whitespace between </script and the final '>'
1649 while (closing_tag_end_pos < in.size() && in[closing_tag_end_pos] != '>') {
1650 ++closing_tag_end_pos;
1651 }
1652
1653 if (closing_tag_end_pos < in.size() && in[closing_tag_end_pos] == '>') {
1654 i = closing_tag_end_pos + 1; // Position after '>'
1655 return i;
1656 }
1657
1658 // If we found "</script" but not the final ">", return the last processed position.
1659 return closing_tag_end_pos;
1660 }
1661 }
1662
1663 // --- 4. End of Input Reached ---
1664 // If the input ends without a closing </script> tag, capture the remaining content.
1665 if (in.size() > content_begin) {
1666 // FIX: Use std::vector::insert instead of non-existent append
1667 self->_Script.insert(self->_Script.end(),
1668 in.begin() + content_begin,
1669 in.end());
1670 }
1671
1672 return i;
1673}
1674
1675
1676
1679
1681 _copy(this,&svgsrc);
1682}
1683
1686
1687
1689 _copy(this,&hel);
1690 return *this;
1691}
1692
1694 _copy(this,hel);
1695 return *this;
1696}
1697
1698void libhtmlpp::SvgElement::setSvg(const std::string& script){
1699 std::copy(script.begin(),script.end(),
1700 std::insert_iterator<std::vector<char>>(_Svg,_Svg.begin()));
1701}
1702
1703const std::vector<char>libhtmlpp::SvgElement::getSvg(){
1704 return _Svg;
1705}
1706
1710
1711size_t libhtmlpp::SvgElement::parseElement(const std::vector<char>& in,
1712 std::unique_ptr<libhtmlpp::Element>& el,
1713 size_t start,
1714 bool& termination)
1715{
1716 const size_t startel = start;
1717 termination = false;
1718
1719 const auto begin = in.begin();
1720 if (start >= in.size()) {
1721 HTMLException excp;
1722 throw excp[HTMLException::Error] << "Parsing error: start offset beyond buffer.";
1723 }
1724 auto it_close_angle = std::find(begin + start, in.end(), HTMLTAG_CLOSE);
1725 if (it_close_angle == in.end()) {
1726 HTMLException excp;
1727 throw excp[HTMLException::Error] << "Parsing error: Missing '>' for <svg> open tag.";
1728 }
1729
1730 el = std::make_unique<SvgElement>();
1731 auto* svgEl = static_cast<SvgElement*>(el.get());
1732
1733 {
1734 std::vector<char> tel;
1735 tel.assign(begin + startel, it_close_angle);
1736 svgEl->_serialelize(tel);
1737 }
1738
1739 auto it_content_begin = it_close_angle;
1740 if (it_content_begin != in.end()) ++it_content_begin; // safe increment
1741
1742 static constexpr char kEndTag[] = "</svg>";
1743 auto it_end = std::search(it_content_begin, in.end(),
1744 std::begin(kEndTag), std::end(kEndTag) - 1 /* no '\0' */);
1745 if (it_end == in.end()) {
1746 HTMLException excp;
1747 throw excp[HTMLException::Error] << "Parsing error: Missing </svg> closing tag.";
1748 }
1749
1750 svgEl->_Svg.insert(svgEl->_Svg.end(), it_content_begin, it_end);
1751
1752 const size_t consumed = static_cast<size_t>((it_end - begin) + (std::size(kEndTag) - 1));
1753 return consumed;
1754}
1755
1756
1757
1760
1762 _copy(this,&textsrc);
1763}
1764
1767
1768
1770 _copy(this,&hel);
1771 return *this;
1772}
1773
1775 _copy(this,hel);
1776 return *this;
1777}
1778
1779void libhtmlpp::TextArea::setText(const std::string& text){
1780 std::copy(text.begin(),text.end(),
1781 std::insert_iterator<std::vector<char>>(_Text,_Text.begin()));
1782}
1783
1784const std::vector<char>libhtmlpp::TextArea::getText(){
1785 return _Text;
1786}
1787
1791
1792size_t libhtmlpp::TextArea::parseElement(const std::vector<char>& in,
1793 std::unique_ptr<libhtmlpp::Element>& el,
1794 size_t start,
1795 bool& termination)
1796{
1797 termination = false;
1798
1799 const auto begin = in.begin();
1800 const auto end = in.end();
1801
1802 if (start >= in.size()) {
1803 HTMLException excp;
1804 throw excp[HTMLException::Error] << "Parsing error: start offset beyond buffer.";
1805 }
1806
1807 // ---- helpers -----------------------------------------------------------
1808 auto is_ws = [](unsigned char c) {
1809 return c == ' ' || c == '\t' || c == '\n' || c == '\r';
1810 };
1811 auto tolower_ascii = [](unsigned char c) -> unsigned char {
1812 return (c >= 'A' && c <= 'Z') ? static_cast<unsigned char>(c + 32) : c;
1813 };
1814 auto ieq_prefix = [&](std::vector<char>::const_iterator it,
1815 std::vector<char>::const_iterator it_end,
1816 const char* lit) -> bool
1817 {
1818 for (; *lit; ++lit, ++it) {
1819 if (it == it_end) return false;
1820 if (tolower_ascii(static_cast<unsigned char>(*it)) !=
1821 tolower_ascii(static_cast<unsigned char>(*lit))) {
1822 return false;
1823 }
1824 }
1825 return true;
1826 };
1827
1828 auto it_gt = std::find(begin + start, end, HTMLTAG_CLOSE);
1829 if (it_gt == end) {
1830 HTMLException excp;
1831 throw excp[HTMLException::Error] << "Parsing error: Unclosed <textarea> tag.";
1832 }
1833
1834 el = std::make_unique<TextArea>();
1835 auto* ta = static_cast<TextArea*>(el.get());
1836 {
1837 std::vector<char> tel;
1838 tel.assign(begin + start, it_gt); // opening tag without '>'
1839 ta->_serialelize(tel);
1840 }
1841
1842 auto it = it_gt;
1843 if (it != end) ++it;
1844 const auto content_begin = it;
1845
1846 for (;;) {
1847 auto lt = std::find(it, end, '<');
1848 if (lt == end) {
1849 HTMLException excp;
1850 throw excp[HTMLException::Error] << "Parsing error: Missing </textarea> closing tag.";
1851 }
1852
1853 if (ieq_prefix(lt, end, "</textarea")) {
1854 auto after_head = lt + std::strlen("</textarea");
1855 while (after_head != end && is_ws(static_cast<unsigned char>(*after_head))) {
1856 ++after_head;
1857 }
1858 if (after_head == end) {
1859 HTMLException excp;
1860 throw excp[HTMLException::Error] << "Parsing error: Unclosed </textarea> end tag.";
1861 }
1862 if (*after_head == '>') {
1863 ta->_Text.insert(ta->_Text.end(), content_begin, lt);
1864 const size_t consumed = static_cast<size_t>((after_head - begin) + 1);
1865 return consumed;
1866 }
1867
1868 it = lt + 1;
1869 continue;
1870 }
1871
1872 it = lt + 1;
1873 }
1874}
1875
1876
1877
1881
1891void libhtmlpp::HtmlPage::loadFile(libhtmlpp::HtmlElement &html,const std::string& path){
1892 std::string data;
1893 std::ifstream fs(path);
1894
1895 if(!fs.is_open()){
1896 HTMLException excp;
1897 throw excp[HTMLException::Critical] << "Can't open file: " << path;
1898 }
1899
1900 fs.seekg(std::ios::end);
1901
1902 data.reserve(fs.tellg());
1903
1904 fs.seekg(std::ios::beg);
1905
1906 data.assign((std::istreambuf_iterator<char>(fs)), std::istreambuf_iterator<char>());
1907
1908 fs.close();
1909
1910 _CheckHeader(data);
1911 loadString(html,data);
1912}
1921 HtmlString buf=src;
1922 Element &el=buf.parse();
1923 _copy(&html,&el);
1924}
1925
1927 HtmlString buf=node;
1928 Element &el=buf.parse();
1929 _copy(&html,&el);
1930}
1931
1933 if(!node){
1935 throw excp[libhtmlpp::HTMLException::Critical] << "loadstring: node can't be null !";
1936 }
1937 libhtmlpp::HtmlString buf=*node;
1938 html=(libhtmlpp::HtmlElement&)buf.parse();
1939}
1947void libhtmlpp::HtmlPage::saveFile(libhtmlpp::HtmlElement &html,const std::string& path){
1948 HtmlString data;
1949 std::ofstream fs;
1950
1951 print(html,data);
1952
1953 try{
1954 fs.open(path);
1955 }catch(std::exception &e){
1956 HTMLException excp;
1957 throw excp[HTMLException::Critical] << e.what();
1958 }
1959
1960 fs << data.str();
1961
1962 fs.close();
1963
1964}
1965
1967 return _Html5;
1968}
1969
1970
1971void libhtmlpp::HtmlPage::_CheckHeader(const HtmlString &page){
1972 const char type[] = { '!','D','O','C','T','Y','P','E' };
1973
1974 int i = 0;
1975
1976 bool start=false;
1977
1978 do{
1979 ++i;
1980 if(page[i]== '<'){
1981 if(start==true){
1982 HTMLException excp;
1983 excp[HTMLException::Critical] << "Wrong Header arborting";
1984 throw excp;
1985 }
1986 start=true;
1987 }
1988 } while ( page[i]== '<' || page[i]== '!' || page[i] == ' ');
1989
1990 if (page.size() < 8) {
1991 HTMLException excp;
1992 excp[HTMLException::Critical] << "No Doctype found arborting";
1993 throw excp;
1994 }
1995
1996 while (i < 8) {
1997 if (page[i+1] != type[i]) {
1998 HTMLException excp;
1999 excp[HTMLException::Critical] << "No Doctype found arborting";
2000 throw excp;
2001 }
2002 ++i;
2003 }
2004
2005 do{
2006 ++i;
2007 }while (page[i] == ' ');
2008
2009 const char doctype[] = { 'H','T','M','L' };
2010 size_t tpvl = 4;
2011
2012 const char typevalue4[] = {'P','U','B','L','I','C'};
2013 size_t tpvl4 = 6;
2014
2015 if ((i + tpvl) > page.size()) {
2016 HTMLException excp;
2017 excp[HTMLException::Critical] << "Document to short broken !";
2018 throw excp;
2019 }
2020
2021 size_t ii=0;
2022
2023 while ( ii < tpvl) {
2024 if (tolower(page[i++]) != tolower(doctype[ii++])) {
2025 HTMLException excp;
2026 excp[HTMLException::Critical] << "Doctype header broken or wrong type";
2027 throw excp;
2028 }
2029 }
2030
2031 ii=0;
2032
2033 do{
2034 ++i;
2035 } while (page[i] == ' ');
2036
2037 bool html4=true;
2038
2039 if(i +tpvl4 <page.size()){
2040 while(ii < tpvl4){
2041 if (tolower(page[i++]) != tolower(typevalue4[ii++])) {
2042 html4=false;
2043 }
2044 }
2045 }
2046
2047 _Html5=!html4;
2048
2049}
2057void libhtmlpp::print(const Element &element, HtmlString &output,bool formated) {
2058
2059 const Element *el=&element;
2060
2061 auto isContainer = [](const std::string &tagname) {
2062 for(size_t i=0; i<ContainerTypes.size(); ++i){
2063 if(tagname==ContainerTypes[i])
2064 return true;
2065 }
2066 return false;
2067 };
2068
2069 std::stack<const libhtmlpp::Element*> cpylist;
2070
2071 int lvl=0;
2072
2073 bool virgin=true;
2074
2075 PRINTNEXTEL:
2076
2077 if(formated){
2078 for(int i=0; i<lvl; ++i){
2079 output.append(" ");
2080 }
2081 }
2082
2083 switch(el->getType()){
2084 case HtmlEl:{
2085 output.append("<");
2086 output.append(static_cast<const HtmlElement*>(el)->getTagname());
2087 for (HtmlElement::Attributes* curattr = static_cast<const HtmlElement*>(el)->_firstAttr.get(); curattr; curattr = curattr->_nextAttr.get()) {
2088 output.append(" ");
2089 std::copy(
2090 curattr->_Key.begin(),
2091 curattr->_Key.end(),
2092 std::back_inserter(output)
2093 );
2094 if(!curattr->_Value.empty()){
2095 output.append("=\"");
2096 std::copy(
2097 curattr->_Value.begin(),
2098 curattr->_Value.end(),
2099 std::back_inserter(output)
2100 );
2101 output.append("\"");
2102 }
2103 }
2104
2105 output.append(">");
2106
2107 if( !formated && virgin ){
2108 output.append("\r\n ");
2109 virgin=false;
2110 }
2111
2112 if (static_cast<const HtmlElement*>(el)->_childElement) {
2113 if(formated)
2114 output.append("\r\n");
2115 cpylist.push(el);
2116 el=static_cast<const HtmlElement*>(el)->_childElement.get();
2117 ++lvl;
2118 goto PRINTNEXTEL;
2119 }
2120
2121 //Container must be always terminated fuck html5
2122 if(isContainer(static_cast<const HtmlElement*>(el)->getTagname())){
2123 output.append("</");
2124 std::copy(
2125 static_cast<const HtmlElement*>(el)->_TagName.begin(),
2126 static_cast<const HtmlElement*>(el)->_TagName.end(),
2127 std::back_inserter(output)
2128 );
2129 output.append(">");
2130 }
2131
2132 if(formated)
2133 output.append("\r\n");
2134
2135 if (el->_nextElement) {
2136 el=el->_nextElement.get();
2137 goto PRINTNEXTEL;
2138 }
2139 }break;
2140
2141 case TextEl :{
2142 std::copy(
2143 static_cast<const TextElement*>(el)->_Text.begin(),
2144 static_cast<const TextElement*>(el)->_Text.end(),
2145 std::back_inserter(output)
2146 );
2147 if(formated)
2148 output.append("\r\n");
2149
2150 if (el->_nextElement) {
2151 el=el->_nextElement.get();
2152 goto PRINTNEXTEL;
2153 }
2154 }break;
2155 case CommentEl: {
2156 output.append("<!--");
2157 std::copy(
2158 static_cast<const CommentElement*>(el)->_Comment.begin(),
2159 static_cast<const CommentElement*>(el)->_Comment.end(),
2160 std::back_inserter(output)
2161 );
2162 output.append("-->");
2163 if(formated)
2164 output.append("\r\n");
2165
2166 if (el->_nextElement) {
2167 el=el->_nextElement.get();
2168 goto PRINTNEXTEL;
2169 }
2170 }break;
2171 case ScriptEL:{
2172 output.append("<");
2173 output.append(static_cast<const ScriptElement*>(el)->getTagname());
2174 for (ScriptElement::Attributes* curattr = static_cast<const ScriptElement*>(el)->_firstAttr.get(); curattr; curattr = curattr->_nextAttr.get()) {
2175 output.append(" ");
2176 std::copy(
2177 curattr->_Key.begin(),
2178 curattr->_Key.end(),
2179 std::back_inserter(output)
2180 );
2181 if(!curattr->_Value.empty()){
2182 output.append("=\"");
2183 std::copy(
2184 curattr->_Value.begin(),
2185 curattr->_Value.end(),
2186 std::back_inserter(output)
2187 );
2188 output.append("\"");
2189 }
2190 }
2191
2192 output.append(">");
2193 if(formated){
2194 output.append("\r\n");
2195 for(int i=0; i<lvl+1; ++i){
2196 output.append(" ");
2197 }
2198 }
2199 std::copy(
2200 static_cast<const ScriptElement*>(el)->_Script.begin(),
2201 static_cast<const ScriptElement*>(el)->_Script.end(),
2202 std::back_inserter(output)
2203 );
2204 if(formated){
2205 output.append("\r\n");
2206 for(int i=0; i<lvl; ++i){
2207 output.append(" ");
2208 }
2209 }
2210 output.append("</");
2211 output.append(static_cast<const ScriptElement*>(el)->getTagname());
2212 output.append(">");
2213 if(formated)
2214 output.append("\r\n");
2215
2216 if (el->_nextElement) {
2217 el=el->_nextElement.get();
2218 goto PRINTNEXTEL;
2219 }
2220 }break;
2221 case SvgEL:{
2222 output.append("<");
2223 output.append(static_cast<const ScriptElement*>(el)->getTagname());
2224 for (SvgElement::Attributes* curattr = static_cast<const SvgElement*>(el)->_firstAttr.get(); curattr; curattr = curattr->_nextAttr.get()) {
2225 output.append(" ");
2226 std::copy(
2227 curattr->_Key.begin(),
2228 curattr->_Key.end(),
2229 std::back_inserter(output)
2230 );
2231 if(!curattr->_Value.empty()){
2232 output.append("=\"");
2233 std::copy(
2234 curattr->_Value.begin(),
2235 curattr->_Value.end(),
2236 std::back_inserter(output)
2237 );
2238 output.append("\"");
2239 }
2240 }
2241 output.append(">");
2242
2243 if(formated){
2244 output.append("\r\n");
2245 for(int i=0; i<lvl+1; ++i){
2246 output.append(" ");
2247 }
2248 }
2249 std::copy(
2250 static_cast<const SvgElement*>(el)->_Svg.begin(),
2251 static_cast<const SvgElement*>(el)->_Svg.end(),
2252 std::back_inserter(output)
2253 );
2254 if(formated){
2255 output.append("\r\n");
2256 for(int i=0; i<lvl; ++i){
2257 output.append(" ");
2258 }
2259 }
2260 output.append("</");
2261 output.append(static_cast<const SvgElement*>(el)->getTagname());
2262 output.append(">");
2263 if(formated)
2264 output.append("\r\n");
2265
2266 if (el->_nextElement) {
2267 el=el->_nextElement.get();
2268 goto PRINTNEXTEL;
2269 }
2270 }break;
2271 case TextAreaEL:{
2272 output.append("<");
2273 output.append(static_cast<const TextArea*>(el)->getTagname());
2274 for (TextArea::Attributes* curattr = static_cast<const TextArea*>(el)->_firstAttr.get(); curattr; curattr = curattr->_nextAttr.get()) {
2275 output.append(" ");
2276 std::copy(
2277 curattr->_Key.begin(),
2278 curattr->_Key.end(),
2279 std::back_inserter(output)
2280 );
2281 if(!curattr->_Value.empty()){
2282 output.append("=\"");
2283 std::copy(
2284 curattr->_Value.begin(),
2285 curattr->_Value.end(),
2286 std::back_inserter(output)
2287 );
2288 output.append("\"");
2289 }
2290 }
2291 output.append(">");
2292 std::copy(
2293 static_cast<const TextArea*>(el)->_Text.begin(),
2294 static_cast<const TextArea*>(el)->_Text.end(),
2295 std::back_inserter(output)
2296 );
2297 output.append("</");
2298 output.append(static_cast<const TextArea*>(el)->getTagname());
2299 output.append(">");
2300 if(formated)
2301 output.append("\r\n");
2302
2303 if (el->_nextElement) {
2304 el=el->_nextElement.get();
2305 goto PRINTNEXTEL;
2306 }
2307 }break;
2308 default:
2309 HTMLException excp;
2310 excp[HTMLException::Error] << "Unkown Elementtype";
2311 throw excp;
2312 break;
2313 }
2314
2315 while(!cpylist.empty()){
2316 el=cpylist.top();
2317
2318 --lvl;
2319
2320 if(formated){
2321 for(int i=0; i<lvl; ++i){
2322 output.append(" ");
2323 }
2324 }
2325
2326 output.append("</");
2327 std::copy(
2328 static_cast<const HtmlElement*>(el)->_TagName.begin(),
2329 static_cast<const HtmlElement*>(el)->_TagName.end(),
2330 std::back_inserter(output)
2331 );
2332 output.append(">");
2333
2334 if(formated)
2335 output.append("\r\n");
2336
2337 cpylist.pop();
2338 if (el->_nextElement) {
2339 el=el->_nextElement.get();
2340 goto PRINTNEXTEL;
2341 }
2342 }
2343}
2344
2346 std::stack <Element*> childs;
2347 const Element *curel=this;
2348 SEARCHBYID:
2349 if(curel->getType()==HtmlEl || curel->getType()== ScriptEL || curel->getType()==SvgEL){
2350 if(((HtmlElement*)curel)->_childElement){
2351 childs.push(((HtmlElement*)curel)->_childElement.get());
2352 }
2353 std::string idname=((HtmlElement*)curel)->getAtributte("id");
2354 if(idname.length()==id.length() && std::equal(id.begin(),id.end(),idname.begin()) ){
2355 return (HtmlElement*)curel;
2356 }
2357 }
2358
2359 if(curel->nextElement()){
2360 curel=curel->nextElement();
2361 goto SEARCHBYID;
2362 }
2363
2364 if(!childs.empty()){
2365 curel=childs.top();
2366 childs.pop();
2367 goto SEARCHBYID;
2368 }
2369 return nullptr;
2370}
2371
2373 std::stack <Element*> childs;
2374 const Element *curel=this;
2375 SEARCHBYTAG:
2376 if(curel->getType()==HtmlEl || curel->getType()== ScriptEL || curel->getType()==SvgEL){
2377 if(((HtmlElement*)curel)->_childElement){
2378 childs.push(((HtmlElement*)curel)->_childElement.get());
2379 }
2380 const std::string tname=((HtmlElement*)curel)->getTagname();
2381 if(!tname.empty() && std::equal(tag.begin(),tag.end(),tname.begin())){
2382 return (HtmlElement*)curel;
2383 }
2384 }
2385
2386 if(curel->nextElement()){
2387 curel=curel->nextElement();
2388 goto SEARCHBYTAG;
2389 }
2390
2391 if(!childs.empty()){
2392 curel=childs.top();
2393 childs.pop();
2394 goto SEARCHBYTAG;
2395 }
2396 return nullptr;
2397}
2398
2400 return _childElement.get();
2401}
2402
2404 return std::string(_Key.begin(), _Key.end());
2405}
2406
2408 return std::string(_Value.begin(), _Value.end());
2409}
2410
2414
2416 return _firstAttr.get();
2417}
2418
2419void libhtmlpp::HtmlElement::setAttribute(const std::string &name, const std::string &value) {
2420 Attributes* cattr = nullptr;
2421
2422 const char forbidden[] = {'\"'};
2423
2424 auto checkForbidden = [forbidden](const std::string &input){
2425 for(size_t i = 0; i<input.length(); ++i){
2426 for(size_t ii=0; ii<sizeof(forbidden[ii]); ii++){
2427 if(input[i]==forbidden[ii]){
2428 return true;
2429 }
2430 }
2431 }
2432 return false;
2433 };
2434
2435 if(checkForbidden(name) || checkForbidden(value)){
2436 HTMLException e;
2437 e[HTMLException::Error] << "setAttribute " << name.c_str() << "forbidden sign is used !";
2438 throw e;
2439 }
2440
2441 for (cattr= _firstAttr.get(); cattr; cattr=cattr->_nextAttr.get()) {
2442 if(name.size() == cattr->_Key.size() && std::equal(name.begin(),name.end(),cattr->_Key.begin())){
2443 cattr->_Value.clear();
2444 std::copy(value.begin(),value.end(),std::back_inserter(cattr->_Value));
2445 return;
2446 }
2447 }
2448 if (_lastAttr){
2449 _lastAttr->_nextAttr = std::make_unique<Attributes>();
2450 _lastAttr = _lastAttr->_nextAttr.get();
2451 }else {
2452 _firstAttr = std::make_unique<Attributes>();
2453 _lastAttr = _firstAttr.get();
2454 }
2455
2456 cattr = _lastAttr;
2457 std::copy(name.begin(),name.end(),std::back_inserter(cattr->_Key) );
2458 std::copy(value.begin(),value.end(),std::back_inserter(cattr->_Value));
2459}
2460
2461void libhtmlpp::HtmlElement::setIntAttribute(const std::string& name, int value) {
2462 char buf[255];
2463 snprintf(buf,255,"%d",value);
2464 setAttribute(name,buf);
2465}
2466
2467const std::string libhtmlpp::HtmlElement::getAtributte(const std::string& name) const {
2468 for (Attributes* curattr = _firstAttr.get(); curattr; curattr = curattr->_nextAttr.get()) {
2469
2470 if (curattr->_Key.size() != name.length() ) {
2471 continue;
2472 }
2473
2474 if (std::equal(name.begin(), name.end(), curattr->_Key.begin())) {
2475 return std::string(curattr->_Value.begin(), curattr->_Value.end());
2476 }
2477 }
2478 return "";
2479}
2480
2481int libhtmlpp::HtmlElement::getIntAtributte(const std::string& name) const
2482{
2483 return atoi(getAtributte(name).c_str());
2484}
2485
2487 _nextAttr=nullptr;
2488}
2489
2491 auto cur = std::move(_nextAttr);
2492 while (cur) {
2493 cur = std::move(cur->_nextAttr);
2494 }
2495}
2496
2500
2501
2503 _firstRow=nullptr;
2504 _lastRow=nullptr;
2505 _count = 0;
2506}
2507
2510
2512 std::unique_ptr<Row> newRow = std::make_unique<Row>(row);
2513
2514 if (!_firstRow) {
2515 _firstRow = std::move(newRow);
2516 _lastRow = _firstRow.get();
2517 } else {
2518 _lastRow->_nextRow = std::move(newRow);
2519 _lastRow = _lastRow->_nextRow.get();
2520 }
2521
2522 ++_count;
2523 return *_lastRow;
2524}
2525
2527 if(!_firstRow || _count<pos){
2529 exp[HTMLException::Error] << "HtmlTable: Row at this position won't exists !";
2530 throw exp;
2531 }
2532 size_t cpos=0;
2533 Row *curel=nullptr;
2534 for(curel=_firstRow.get(); curel; curel=curel->_nextRow.get()){
2535 if(cpos==pos)
2536 return *curel;
2537 ++cpos;
2538 }
2539 return *curel;
2540}
2541
2543 element->setTagname("table");
2544 for(Row *crow=_firstRow.get(); crow; crow=crow->_nextRow.get()){
2545 HtmlElement hrow("tr");
2546 for(Column *ccol=crow->_firstColumn.get(); ccol; ccol=ccol->_nextColumn.get() ){
2547 HtmlElement hcol("td");
2548 TextElement cellContent(ccol->Data.c_str());
2549 hcol.appendChild(cellContent);
2550 hrow.appendChild(hcol);
2551 }
2552 element->appendChild(&hrow);
2553 }
2554}
2555
2556
2559
2561 va_list args;
2562 va_start(args,count);
2563
2564 for (int i = 0; i < count; ++i) {
2565 _header << va_arg(args, const char*);
2566 }
2567
2568}
2569
2571 if (pos >= _count)
2572 return;
2573 if (pos == 0) {
2574 _firstRow = std::move(_firstRow->_nextRow);
2575 _lastRow = (pos == (_count - 1)) ? nullptr : _firstRow.get();
2576 } else {
2577 Row *prev = &(*this)[pos - 1];
2578 if (prev->_nextRow) {
2579 prev->_nextRow = std::move(prev->_nextRow->_nextRow);
2580
2581 if (prev->_nextRow.get() == nullptr) {
2582 _lastRow = prev;
2583 }
2584 }
2585 }
2586
2587 --_count;
2588 if (_count == 0) {
2589 _firstRow = nullptr;
2590 _lastRow = nullptr;
2591 }
2592}
2593
2595 _nextColumn=nullptr;
2596}
2597
2599 _nextColumn=nullptr;
2600 Data = col.Data;
2601}
2602
2604 _nextColumn=nullptr;
2605 Data=data;
2606}
2607
2609 _nextColumn=nullptr;
2610 Data=data.str();
2611}
2612
2615
2617 _nextColumn = std::move(col._nextColumn);
2618 Data = std::move(col.Data);
2619}
2620
2622 _firstColumn=nullptr;
2623 _lastColumn=nullptr;
2624 _nextRow=nullptr;
2625 _count=0;
2626}
2627
2630
2632 _firstColumn=nullptr;
2633 _lastColumn=nullptr;
2634 _nextRow=nullptr;
2635 _count=0;
2636
2637 for(Column *curel=row._firstColumn.get(); curel; curel=curel->_nextColumn.get()){
2638 *this << HtmlString(curel->Data);
2639 }
2640}
2641
2643 std::unique_ptr<Column> ptr = std::make_unique<Column>(std::move(col));
2644
2645 if(_firstColumn){
2646 _lastColumn->_nextColumn=std::move(ptr);
2647 _lastColumn=_lastColumn->_nextColumn.get();
2648 }else{
2649 _firstColumn= std::move(ptr);
2650 _lastColumn=_firstColumn.get();
2651 }
2652 ++_count;
2653 return *this;
2654}
2655
2657 std::unique_ptr<Column> ptr = std::make_unique<Column>(col);
2658
2659 if(_firstColumn){
2660 _lastColumn->_nextColumn=std::move(ptr);
2661 _lastColumn=_lastColumn->_nextColumn.get();
2662 }else{
2663 _firstColumn= std::move(ptr);
2664 _lastColumn=_firstColumn.get();
2665 }
2666 ++_count;
2667 return *this;
2668}
2669
2671 Column col(value);
2672 *this << col;
2673 return *this;
2674}
2675
2677 Column col(value);
2678 *this << col;
2679 return *this;
2680}
2681
2682
2684 HtmlString buf;
2685 buf << value;
2686 *this << buf;
2687 return *this;
2688}
2689
2691 char buf[255];
2692 snprintf(buf,255,"%d",value);
2693 return *this << buf;
2694}
2695
2697 if(!_firstColumn || _count<pos){
2699 exp[HTMLException::Error] << "HtmlTable: Column at this position won't exists !";
2700 throw exp;
2701 }
2702 size_t cpos=0;
2703 Column *curel=nullptr;
2704 for(curel=_firstColumn.get(); curel; curel=curel->_nextColumn.get()){
2705 if(cpos==pos)
2706 return *curel;
2707 ++cpos;
2708 }
2709 return *curel;
2710}
2711
2713 Column *dcol=&(*this)[pos];
2714 try{
2715 Column *prev=&(*this)[pos-1];
2716 prev->_nextColumn=std::move(dcol->_nextColumn);
2717 }catch(...){}
2718 --_count;
2719}
2720
2722 _firstColumn.reset();
2723 _lastColumn = nullptr;
2724 _count = 0;
2725}
Leaf node representing an HTML comment ().
Definition html.h:216
static size_t parseElement(const std::vector< char > &in, std::unique_ptr< libhtmlpp::Element > &el, size_t start, bool &termination)
Definition html.cpp:1477
CommentElement & operator=(const Element &hel)
Definition html.cpp:1454
std::vector< char > _Comment
Definition html.h:232
friend void _copy(libhtmlpp::Element *dest, const libhtmlpp::Element *src)
Definition html.cpp:1046
void setComment(const std::string &txt)
Definition html.cpp:1464
const std::string getComment()
Definition html.cpp:1469
class DocElements * prevel
Definition html.cpp:170
std::unique_ptr< Element > element
Definition html.cpp:167
std::unique_ptr< DocElements > nextel
Definition html.cpp:169
Abstract base class for all nodes in the HTML tree.
Definition html.h:76
virtual void remove(Element *el)
Definition html.cpp:1335
Element * _prevElement
Definition html.h:99
void insertAfter(Element *el)
Definition html.cpp:1258
virtual ~Element()
Definition html.cpp:1328
void insertBefore(Element *el)
Definition html.cpp:1226
Element & operator=(const Element &hel)
Definition html.cpp:1299
std::unique_ptr< Element > _nextElement
Definition html.h:98
virtual int getType() const =0
Definition html.cpp:725
Element * prevElement() const
Definition html.cpp:1313
Element * nextElement() const
Definition html.cpp:1309
int getType() const
Definition html.cpp:2497
const Attributes * firstAttribute() const
Definition html.cpp:2415
HtmlElement * getElementbyTag(const std::string &tag) const
Definition html.cpp:2372
const std::string getAtributte(const std::string &name) const
Definition html.cpp:2467
void _serialelize(const std::vector< char > &in)
Extracts tag name and attributes from a token vector into an HtmlElement.
Definition html.cpp:893
static size_t parseElement(const std::vector< char > &in, std::unique_ptr< libhtmlpp::Element > &el, size_t start, bool &termination)
Definition html.cpp:1003
void appendChild(const Element *el)
Definition html.cpp:773
int getIntAtributte(const std::string &name) const
Definition html.cpp:2481
void setTagname(const std::string &name)
Definition html.cpp:729
void setAttribute(const std::string &name, const std::string &value)
Definition html.cpp:2419
void remove(Element *el)
Definition html.cpp:848
bool operator==(const HtmlElement *hel)
Definition html.cpp:820
friend void _copy(libhtmlpp::Element *dest, const libhtmlpp::Element *src)
Definition html.cpp:1046
void insertChild(const Element *el)
Definition html.cpp:740
Element * firstChild() const
Definition html.cpp:2399
const std::string getTagname() const
Definition html.cpp:734
HtmlElement * getElementbyID(const std::string &id) const
Definition html.cpp:2345
HtmlElement & operator=(const HtmlElement &hel)
Definition html.cpp:838
std::unique_ptr< Element > _childElement
Definition html.h:169
void setIntAttribute(const std::string &name, int value)
Definition html.cpp:2461
void loadString(libhtmlpp::HtmlElement &html, const std::string &src)
Parses an HTML source string and copies the result into html.
Definition html.cpp:1920
void saveFile(libhtmlpp::HtmlElement &html, const std::string &path)
Serializes an HtmlElement subtree and writes it to a file.
Definition html.cpp:1947
void loadFile(libhtmlpp::HtmlElement &html, const std::string &path)
Loads an HTML file from disk into a given HtmlElement root.
Definition html.cpp:1891
const std::vector< char > & data() const
Definition html.cpp:350
void append(const std::string &src)
Definition html.cpp:230
HtmlString & operator<<(const char *src)
Definition html.cpp:293
HtmlString & operator+=(const std::string &src)
Definition html.cpp:267
size_t size() const
Definition html.cpp:336
char operator[](size_t pos) const
Definition html.cpp:289
void push_back(const char src)
Definition html.cpp:218
void insert(size_t pos, char src)
Definition html.cpp:253
const char * c_str() const
Definition html.cpp:346
size_t length() const
Definition html.cpp:332
libhtmlpp::Element & parse()
Parses the current buffer into a DOM-like tree and returns the root element.
Definition html.cpp:355
const char * operator*()
Definition html.cpp:328
HtmlString & operator=(const std::string &src)
Definition html.cpp:277
const std::string str() const
Definition html.cpp:340
Row & operator<<(Column &&col)
Definition html.cpp:2642
Column & operator[](size_t pos)
Definition html.cpp:2696
void delColumn(size_t pos)
Definition html.cpp:2712
Row & operator[](size_t pos)
Definition html.cpp:2526
Row & operator<<(const Row &row)
Definition html.cpp:2511
void deleteRow(size_t pos)
Definition html.cpp:2570
void parse(HtmlElement *element)
Definition html.cpp:2557
void insert(HtmlElement *element)
Definition html.cpp:2542
void setHeader(int count,...)
Definition html.cpp:2560
Element representing a <script> tag and its text content.
Definition html.h:241
void setScript(const std::string &txt)
Definition html.cpp:1541
static size_t parseElement(const std::vector< char > &in, std::unique_ptr< libhtmlpp::Element > &el, size_t start, bool &termination)
Definition html.cpp:1553
ScriptElement & operator=(const Element &hel)
Definition html.cpp:1531
std::vector< char > _Script
Definition html.h:265
const std::string getScript()
Definition html.cpp:1545
friend void _copy(libhtmlpp::Element *dest, const libhtmlpp::Element *src)
Definition html.cpp:1046
Element representing an embedded <svg> tag and its attributes/content.
Definition html.h:274
int getType() const
Definition html.cpp:1707
SvgElement & operator=(const Element &hel)
Definition html.cpp:1688
static size_t parseElement(const std::vector< char > &in, std::unique_ptr< libhtmlpp::Element > &el, size_t start, bool &termination)
Definition html.cpp:1711
const std::vector< char > getSvg()
Definition html.cpp:1703
friend void _copy(libhtmlpp::Element *dest, const libhtmlpp::Element *src)
Definition html.cpp:1046
std::vector< char > _Svg
Definition html.h:298
void setSvg(const std::string &svg)
Definition html.cpp:1698
Element representing an embedded <textarea> tag and its attributes/content.
Definition html.h:308
std::vector< char > _Text
Definition html.h:332
TextArea & operator=(const Element &hel)
Definition html.cpp:1769
const std::vector< char > getText()
Definition html.cpp:1784
friend void _copy(libhtmlpp::Element *dest, const libhtmlpp::Element *src)
Definition html.cpp:1046
static size_t parseElement(const std::vector< char > &in, std::unique_ptr< libhtmlpp::Element > &el, size_t start, bool &termination)
Definition html.cpp:1792
int getType() const
Definition html.cpp:1788
void setText(const std::string &text)
Definition html.cpp:1779
Leaf node representing plain text content of an HTML document.
Definition html.h:189
TextElement & operator=(const Element &hel)
Definition html.cpp:1371
std::vector< char > _Text
Definition html.h:207
void setText(const std::string &txt)
Definition html.cpp:1381
int getType() const
Definition html.cpp:1389
friend void _copy(libhtmlpp::Element *dest, const libhtmlpp::Element *src)
Definition html.cpp:1046
static size_t parseElement(const std::vector< char > &in, std::unique_ptr< libhtmlpp::Element > &el, size_t start, bool &termination)
Definition html.cpp:1393
const std::string getText()
Definition html.cpp:1385
#define HTMLTAG_TERMINATE
Definition html.cpp:52
#define HTMLTAG_CLOSE
Definition html.cpp:53
#define HTMLTAG_OPEN
Definition html.cpp:51
std::ostream & operator<<(std::ostream &os, const libhtmlpp::HtmlString &p)
Streams an HtmlString to an output stream using its underlying string.
Definition html.cpp:657
void loadString(libhtmlpp::HtmlElement &html, const libhtmlpp::HtmlString *node)
Definition html.cpp:1932
Public declarations for libhtmlpp HTML element types and utilities.
Core namespace for the libhtmlpp HTML parsing and printing library.
Definition css.h:34
@ TextEl
Definition html.h:65
@ ScriptEL
Definition html.h:68
@ HtmlEl
Definition html.h:66
@ TextAreaEL
Definition html.h:70
@ SvgEL
Definition html.h:69
@ CommentEl
Definition html.h:67
void print(const Element &element, HtmlString &output, bool formated=false)
Serializes an element (and its subtree) into an HtmlString.
Definition html.cpp:2057
void HtmlEncode(const std::string &input, std::string &output)
Encodes special HTML characters in a string and writes into std::string.
Definition html.cpp:662
const std::array< std::string_view, 100 > ContainerTypes
Definition html.cpp:62
void _copy(libhtmlpp::Element *dest, const libhtmlpp::Element *src)
Definition html.cpp:1046
const char * HtmlSigns[][2]
Definition encode.h:31
void HtmlDecode(const std::string &input, HtmlString &output)
Decodes special HTML characters in a string and appends to an HtmlString.
Definition html.cpp:696
const std::string getValue() const
Definition html.cpp:2407
Attributes * nextAttribute() const
Definition html.cpp:2411
const std::string getKey() const
Definition html.cpp:2403