51#define HTMLTAG_OPEN '<'
52#define HTMLTAG_TERMINATE '/'
53#define HTMLTAG_CLOSE '>'
54#define HTMLTAG_COMMENT '!'
180 auto cur = std::move(
nextel);
182 cur = std::move(cur->nextel);
189 _Data.push_back(
str);
196 if (!_Data.empty() && _Data.back() ==
'\0') {
200 for(
auto i =
str.begin(); i!=
str.end(); ++i){
206 if (_Data.empty() || _Data.back() !=
'\0') {
207 _Data.push_back(
'\0');
215 std::copy(
str._Data.begin(),
str._Data.end(),std::insert_iterator<std::vector<char>>(_Data,_Data.begin()));
222 if (!_Data.empty() && _Data.back() ==
'\0') {
225 _Data.push_back(src);
227 _Data.push_back(
'\0');
234 if (!_Data.empty() && _Data.back() ==
'\0') {
238 for(
auto i = src.begin(); i!=src.end(); ++i){
244 if (_Data.empty() || _Data.back() !=
'\0') {
245 _Data.push_back(
'\0');
250 std::copy(hstring._Data.begin(),hstring._Data.end(),std::back_inserter(_Data));
263 return _Data.empty();
285 std::copy(src._Data.begin(),src._Data.end(),std::insert_iterator<std::vector<char>>(_Data,_Data.begin()));
290 return _Data.at(pos);
305 std::copy(src._Data.begin(),src._Data.end(),std::back_inserter(_Data));
311 snprintf(buf, 255,
"%d", src);
318 snprintf(buf, 255,
"%zu", src);
333 return _Data.empty() ? 0 : (_Data.size() - 1);
342 return std::string(_Data.begin(),_Data.end());
361void libhtmlpp::HtmlString::_buildtreenode(
364 std::unique_ptr<Element> &html)
375 const DocElements *outer_end;
376 Element *outer_prev_el;
378 std::stack<Frame> stack;
380 DocElements *start = firstel;
381 const DocElements *end = lastel;
383 Element *prev_el_in_tree =
nullptr;
385 auto checkContainer = [&](
const std::string &tag) {
393 auto skip_empty = [](DocElements *cur,
const DocElements *stop) -> DocElements* {
394 while (cur && cur != stop && (!cur->element)) {
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;
405 const std::string &tag =
static_cast<HtmlElement*
>(open->element.get())->getTagname();
407 DocElements *cur = open->nextel.get();
409 while (cur && cur != bound) {
410 cur = skip_empty(cur, bound);
411 if (!cur || cur == bound)
break;
413 if (cur->element && cur->element->getType() ==
HtmlEl) {
414 const std::string &curtag =
static_cast<HtmlElement*
>(cur->element.get())->getTagname();
416 if (cur->terminator) {
417 if (nest == 0)
return cur;
424 cur = cur->nextel.get();
428 if (checkContainer(tag)) {
437 start = skip_empty(start, end);
440 if (start && start != end && start->terminator) {
441 start = start->nextel.get();
446 if (!start || start == end) {
450 html = std::move(firstel->
element);
456 Frame fr = stack.top(); stack.pop();
457 HtmlElement *opener_el =
static_cast<HtmlElement*
>(fr.open->element.get());
460 Element* last_child_in_chain =
nullptr;
462 DocElements* cur = fr.open->nextel.get();
464 while (cur && cur != fr.close && (!cur->element || cur->terminator)) {
465 cur = cur->nextel.get();
469 while (cur && cur != fr.close) {
470 if (cur->element && !cur->terminator) {
471 if (!opener_el->_childElement) {
472 opener_el->_childElement = std::move(cur->element);
473 last_child_in_chain = opener_el->_childElement.get();
475 last_child_in_chain->_nextElement = std::move(cur->element);
477 last_child_in_chain->_nextElement->_prevElement = last_child_in_chain;
478 last_child_in_chain = last_child_in_chain->_nextElement.get();
481 cur = cur->nextel.get();
483 while (cur && cur != fr.close && (!cur->element || cur->terminator)) {
484 cur = cur->nextel.get();
490 prev_el_in_tree = opener_el;
493 if (fr.outer_prev_el) {
494 prev_el_in_tree->_prevElement = fr.outer_prev_el;
495 fr.outer_prev_el->_nextElement = std::move(fr.open->element);
496 prev_el_in_tree = fr.outer_prev_el->_nextElement.get();
500 prev_el_in_tree = opener_el;
501 start = (fr.close ? fr.close->nextel.get() :
nullptr);
508 if (start->element && !start->terminator && start->element->getType() ==
HtmlEl) {
509 if (DocElements *close = find_terminator(start, end)) {
511 stack.push(Frame{start, close, end, prev_el_in_tree});
514 prev_el_in_tree =
nullptr;
515 start = start->nextel.get();
522 if (start->element && !start->terminator) {
523 Element *current_el = start->element.get();
525 if (prev_el_in_tree) {
526 current_el->_prevElement = prev_el_in_tree;
527 prev_el_in_tree->_nextElement = std::move(start->element);
528 prev_el_in_tree = prev_el_in_tree->_nextElement.get();
530 prev_el_in_tree = current_el;
535 start = start->nextel.get();
544void libhtmlpp::HtmlString::_buildTree() {
545 DocElements* lastEl =
nullptr;
546 std::unique_ptr<DocElements> firstEl =
nullptr;
548 auto is_ws = [](
unsigned char ch) ->
bool {
550 return ch ==
' ' || ch ==
'\t' || ch ==
'\n' || ch ==
'\r';
553 auto ascii_tolower = [](
unsigned char c) ->
unsigned char {
554 return (c >=
'A' && c <=
'Z') ?
static_cast<unsigned char>(c + 32) : c;
557 auto starts_with_ci = [&](
const char* s,
const char* e,
const char* k) ->
bool {
558 const size_t klen = std::char_traits<char>::length(k);
559 if (
static_cast<size_t>(e - s) < klen)
return false;
560 for (
size_t i = 0; i < klen; ++i) {
561 unsigned char a =
static_cast<unsigned char>(s[i]);
562 unsigned char b =
static_cast<unsigned char>(k[i]);
563 if (ascii_tolower(a) != ascii_tolower(b))
return false;
568 auto add_element_node = [&](DocElements** last) {
570 firstEl = std::make_unique<DocElements>();
571 *last = firstEl.get();
573 (*last)->nextel = std::make_unique<DocElements>();
574 (*last)->nextel->prevel = (*last);
575 *last = (*last)->nextel.get();
579 const char*
const base = _Data.data();
580 const size_t n = _Data.size();
581 const char*
const end = base + n;
583 const char* p = base;
586 while (p < end && is_ws(
static_cast<unsigned char>(*p))) ++p;
590 const char*
const remain_end = end;
591 const size_t remain =
static_cast<size_t>(remain_end - p);
594 const unsigned char c1 = ascii_tolower(
static_cast<unsigned char>(p[1]));
598 if (starts_with_ci(p, end,
"<!--")) {
599 add_element_node(&lastEl);
600 size_t i =
static_cast<size_t>(p - base);
605 if (starts_with_ci(p, end,
"<!doctype")) {
606 const char* close_tag = p;
607 while (close_tag < end && *close_tag !=
'>') {
610 if (close_tag < end) {
617 }
else if (c1 ==
's') {
618 if (starts_with_ci(p, end,
"<script")) {
619 add_element_node(&lastEl);
620 size_t i =
static_cast<size_t>(p - base);
625 if (starts_with_ci(p, end,
"<svg")) {
626 add_element_node(&lastEl);
627 size_t i =
static_cast<size_t>(p - base);
632 }
else if (c1 ==
't') {
633 if (starts_with_ci(p, end,
"<textarea")) {
634 add_element_node(&lastEl);
635 size_t i =
static_cast<size_t>(p - base);
644 add_element_node(&lastEl);
645 size_t i =
static_cast<size_t>(p - base);
650 add_element_node(&lastEl);
651 size_t i =
static_cast<size_t>(p - base);
657 _buildtreenode(firstEl.get(),
nullptr, _rootEl);
673 size_t ilen=input.length();
674 for(
size_t i=0; i<ilen; ++i){
685 output.push_back(input[i]);
690 size_t ilen=input.length();
691 for(
size_t i=0; i<ilen; ++i){
715 std::copy(tagname.begin(),tagname.end(),std::back_inserter(_TagName));
741 std::copy(name.begin(),name.begin()+name.length(),std::back_inserter(_TagName));
747 return std::string(_TagName.begin(),_TagName.end());
752 remove(_childElement.get());
757 _childElement=std::make_unique<HtmlElement>();
760 _childElement=std::make_unique<TextElement>();
763 _childElement=std::make_unique<CommentElement>();
766 _childElement=std::make_unique<ScriptElement>();
769 _childElement=std::make_unique<SvgElement>();
776 _copy(_childElement.get(),el);
789 for(
Element *curel=_childElement.get(); curel; curel=curel->nextElement()){
833 if( _TagName.size() != hel->_TagName.size())
835 if(std::equal(_TagName.begin(),_TagName.end(),hel->_TagName.begin()))
841 if(_TagName.size() != hel._TagName.size())
843 if(std::equal(_TagName.begin(),_TagName.end(),hel._TagName.begin()))
861 std::stack<Element*> parents;
886 if(!parents.empty()){
906 auto is_space = [](
unsigned char c) ->
bool {
907 return c ==
' ' || c ==
'\t' || c ==
'\n' || c ==
'\r';
909 auto tolower_ascii = [](
unsigned char c) ->
unsigned char {
910 return (c >=
'A' && c <=
'Z') ?
static_cast<unsigned char>(c + 32) : c;
913 size_t i = 0, n = in.size();
915 if (i < n && in[i] ==
'<') ++i;
916 while (i < n && is_space(
static_cast<unsigned char>(in[i]))) ++i;
918 bool end_tag =
false;
919 if (i < n && in[i] ==
'/') {
922 while (i < n && is_space(
static_cast<unsigned char>(in[i]))) ++i;
926 while (r > i && is_space(
static_cast<unsigned char>(in[r - 1]))) --r;
927 if (r > i && in[r - 1] ==
'>') --r;
928 while (r > i && is_space(
static_cast<unsigned char>(in[r - 1]))) --r;
935 const size_t name_start = i;
937 unsigned char c =
static_cast<unsigned char>(in[i]);
938 if (is_space(c) || c ==
'/' || c ==
'>')
break;
941 const size_t name_end = i;
942 if (name_start == name_end) {
947 _TagName.assign(in.begin() + name_start, in.begin() + name_end);
948 for (
char& ch : _TagName) ch =
static_cast<char>(tolower_ascii(
static_cast<unsigned char>(ch)));
955 while (i < r && is_space(
static_cast<unsigned char>(in[i]))) ++i;
960 while (i < r && is_space(
static_cast<unsigned char>(in[i]))) ++i;
964 const size_t kstart = i;
966 unsigned char c =
static_cast<unsigned char>(in[i]);
967 if (is_space(c) || c ==
'=' || c ==
'/' || c ==
'>')
break;
970 const size_t kend = i;
971 if (kstart == kend) {
976 std::string key(in.begin() + kstart, in.begin() + kend);
977 for (
char& ch : key) ch =
static_cast<char>(tolower_ascii(
static_cast<unsigned char>(ch)));
979 while (i < r && is_space(
static_cast<unsigned char>(in[i]))) ++i;
983 if (i < r && in[i] ==
'=') {
985 while (i < r && is_space(
static_cast<unsigned char>(in[i]))) ++i;
987 if (i < r && (in[i] ==
'"' || in[i] ==
'\'')) {
988 char quote = in[i++];
989 const size_t vstart = i;
990 while (i < r && in[i] != quote) ++i;
991 const size_t vend = i;
992 val.assign(in.begin() + vstart, in.begin() + vend);
993 if (i < r && in[i] == quote) ++i;
995 const size_t vstart = i;
997 unsigned char c =
static_cast<unsigned char>(in[i]);
998 if (is_space(c) || c ==
'/' || c ==
'>')
break;
1001 const size_t vend = i;
1002 val.assign(in.begin() + vstart, in.begin() + vend);
1008 setAttribute(key, val);
1014 const std::vector<char>& in,
1015 std::unique_ptr<libhtmlpp::Element>& el,
1019 el = std::make_unique<HtmlElement>();
1020 termination =
false;
1027 while (i < in.size() && std::isspace(
static_cast<unsigned char>(in[i]))) ++i;
1037 while (k < close && std::isspace(
static_cast<unsigned char>(in[k]))) ++k;
1039 std::vector<char> tel;
1044 while (k < close && std::isspace(
static_cast<unsigned char>(in[k]))) ++k;
1047 tel.insert(tel.end(), in.begin() + k, in.begin() + close);
1049 reinterpret_cast<HtmlElement*
>(el.get())->_serialelize(tel);
1068 cpyel(
const cpyel &src){
1080 std::stack<cpyel> cpylist;
1089 cattr->_Key.begin(),
1092 cattr->_Value.begin(),
1126 cpylist.push(childel);
1131 if(!cattr->_Value.empty()){
1134 cattr->_Key.begin(),
1137 cattr->_Value.begin(),
1149 if(!cattr->_Value.empty()){
1152 cattr->_Key.begin(),
1155 cattr->_Value.begin(),
1160 ((
libhtmlpp::SvgElement*)dest)->setAttribute(std::string(cattr->_Key.begin(),cattr->_Key.end()),
"");
1167 if(!cattr->_Value.empty()){
1170 cattr->_Key.begin(),
1173 cattr->_Value.begin(),
1178 ((
libhtmlpp::TextArea*)dest)->setAttribute(std::string(cattr->_Key.begin(),cattr->_Key.end()),
"");
1202 dest->
_nextElement= std::make_unique<CommentElement>();
1224 if(!cpylist.empty()){
1225 cpyel childel(cpylist.top());
1227 dest=childel.destin;
1237 std::unique_ptr<Element> nel;
1240 nel->_nextElement= std::make_unique<HtmlElement>();
1243 nel->_nextElement= std::make_unique<TextElement>();
1246 nel->_nextElement= std::make_unique<CommentElement>();
1249 nel->_nextElement= std::make_unique<ScriptElement>();
1252 nel->_nextElement= std::make_unique<SvgElement>();
1255 nel->_nextElement= std::make_unique<TextArea>();
1262 _copy(nel.get(),el);
1263 std::unique_ptr<Element> prev=std::move(_prevElement->_nextElement);
1264 _prevElement->_nextElement=std::move(nel);
1265 nel->_nextElement=std::move(prev);
1269 Element *nexel=
nullptr,*prev=
nullptr;
1273 _nextElement= std::make_unique<HtmlElement>();
1276 _nextElement= std::make_unique<TextElement>();
1279 _nextElement= std::make_unique<CommentElement>();
1282 _nextElement= std::make_unique<ScriptElement>();
1285 _nextElement= std::make_unique<SvgElement>();
1288 _nextElement= std::make_unique<TextArea>();
1296 _copy(_nextElement.get(),el);
1298 nexel=_nextElement.get();
1320 return _nextElement.get();
1324 return _prevElement;
1328 _prevElement=
nullptr;
1329 _nextElement=
nullptr;
1333 _prevElement=
nullptr;
1334 _nextElement=
nullptr;
1339 auto cur = std::move(_nextElement);
1341 cur = std::move(cur->_nextElement);
1392 std::copy(txt.begin(),txt.end(),std::back_inserter(_Text));
1396 return std::string(_Text.begin(),_Text.end());
1404 const std::vector<char>& in,
1405 std::unique_ptr<libhtmlpp::Element>& el,
1409 termination =
false;
1411 std::vector<char> buf;
1413 bool seen_nonws =
false;
1414 bool last_was_space =
false;
1417 while (i < in.size()) {
1423 if (c ==
' ' || c ==
'\t' || c ==
'\r' || c ==
'\n') {
1425 if (!last_was_space) {
1427 last_was_space =
true;
1436 last_was_space =
false;
1441 auto text = std::make_unique<TextElement>();
1442 (
static_cast<TextElement*
>(text.get()))->_Text.insert(
1443 (
static_cast<TextElement*
>(text.get()))->_Text.end(),
1444 buf.begin(), buf.end()
1446 el = std::move(text);
1475 std::copy(txt.begin(),txt.end(),
1476 std::insert_iterator<std::vector<char>>(_Comment,_Comment.begin()));
1480 return std::string(_Comment.begin(),_Comment.end());
1488 const std::vector<char>& in,
1489 std::unique_ptr<Element>& el,
1493 termination =
false;
1496 if (i + 3 >= in.size())
return i;
1498 if (!(in[i] ==
'<' && in[i+1] ==
'!' && in[i+2] ==
'-' && in[i+3] ==
'-')) {
1502 el = std::make_unique<CommentElement>();
1505 const size_t content_begin = i;
1507 while (i + 2 < in.size()) {
1508 if (in[i] ==
'-' && in[i+1] ==
'-' && in[i+2] ==
'>') {
1515 if (i > content_begin) {
1516 self->
_Comment.insert(self->_Comment.end(),
1517 in.begin() + content_begin,
1521 if (i + 2 < in.size()) {
1534 _copy(
this,&scriptsrc);
1552 std::copy(script.begin(),script.end(),std::back_inserter(_Script));
1556 return std::string(_Script.begin(),_Script.end());
1564 const std::vector<char>& in,
1565 std::unique_ptr<Element>& el,
1570 el = std::make_unique<ScriptElement>();
1574 if (i >= in.size() || in[i] !=
'<') {
1580 auto iequals = [](
char a,
char b) {
1581 return std::tolower(
static_cast<unsigned char>(a)) ==
1582 std::tolower(
static_cast<unsigned char>(b));
1586 auto match_ci = [&](
size_t pos,
const char* k) ->
bool {
1587 for (
size_t j = 0; k[j]; ++j) {
1588 if (pos + j >= in.size() || !iequals(in[pos + j], k[j])) {
1599 while (i < in.size() && std::isspace(
static_cast<unsigned char>(in[i]))) {
1603 const char* tag_keyword =
"script";
1604 size_t keyword_len = std::char_traits<char>::length(tag_keyword);
1606 if (i + keyword_len >= in.size() || !match_ci(i, tag_keyword)) {
1609 while (i < in.size() && in[i] !=
'>') {
1612 if (i < in.size()) {
1622 while (i < in.size() && in[i] !=
'>') {
1627 if (i > start && in[i] ==
'>') {
1629 std::vector<char> raw_tag_data(in.begin() + start, in.begin() + i + 1);
1630 self->_serialelize(raw_tag_data);
1633 if (i >= in.size() || in[i] !=
'>') {
1639 size_t content_begin = i;
1642 for (; i < in.size(); ++i) {
1644 if (in[i] ==
'<' && match_ci(i,
"</script")) {
1645 size_t content_end = i;
1648 if (content_end > content_begin) {
1650 self->_Script.insert(self->_Script.end(),
1651 in.begin() + content_begin,
1652 in.begin() + content_end);
1656 size_t closing_tag_end_pos = i + keyword_len + 2;
1659 while (closing_tag_end_pos < in.size() && in[closing_tag_end_pos] !=
'>') {
1660 ++closing_tag_end_pos;
1663 if (closing_tag_end_pos < in.size() && in[closing_tag_end_pos] ==
'>') {
1664 i = closing_tag_end_pos + 1;
1669 return closing_tag_end_pos;
1675 if (in.size() > content_begin) {
1677 self->_Script.insert(self->_Script.end(),
1678 in.begin() + content_begin,
1691 _copy(
this,&svgsrc);
1709 std::copy(script.begin(),script.end(),
1710 std::insert_iterator<std::vector<char>>(_Svg,_Svg.begin()));
1722 std::unique_ptr<libhtmlpp::Element>& el,
1726 const size_t startel = start;
1727 termination =
false;
1729 const auto begin = in.begin();
1730 if (start >= in.size()) {
1734 auto it_close_angle = std::find(begin + start, in.end(),
HTMLTAG_CLOSE);
1735 if (it_close_angle == in.end()) {
1740 el = std::make_unique<SvgElement>();
1741 auto* svgEl =
static_cast<SvgElement*
>(el.get());
1744 std::vector<char> tel;
1745 tel.assign(begin + startel, it_close_angle);
1749 auto it_content_begin = it_close_angle;
1750 if (it_content_begin != in.end()) ++it_content_begin;
1752 static constexpr char kEndTag[] =
"</svg>";
1753 auto it_end = std::search(it_content_begin, in.end(),
1754 std::begin(kEndTag), std::end(kEndTag) - 1 );
1755 if (it_end == in.end()) {
1760 svgEl->_Svg.insert(svgEl->_Svg.end(), it_content_begin, it_end);
1762 const size_t consumed =
static_cast<size_t>((it_end - begin) + (std::size(kEndTag) - 1));
1772 _copy(
this,&textsrc);
1790 std::copy(text.begin(),text.end(),
1791 std::insert_iterator<std::vector<char>>(_Text,_Text.begin()));
1803 std::unique_ptr<libhtmlpp::Element>& el,
1807 termination =
false;
1809 const auto begin = in.begin();
1810 const auto end = in.end();
1812 if (start >= in.size()) {
1818 auto is_ws = [](
unsigned char c) {
1819 return c ==
' ' || c ==
'\t' || c ==
'\n' || c ==
'\r';
1821 auto tolower_ascii = [](
unsigned char c) ->
unsigned char {
1822 return (c >=
'A' && c <=
'Z') ?
static_cast<unsigned char>(c + 32) : c;
1824 auto ieq_prefix = [&](std::vector<char>::const_iterator it,
1825 std::vector<char>::const_iterator it_end,
1826 const char* lit) ->
bool
1828 for (; *lit; ++lit, ++it) {
1829 if (it == it_end)
return false;
1830 if (tolower_ascii(
static_cast<unsigned char>(*it)) !=
1831 tolower_ascii(
static_cast<unsigned char>(*lit))) {
1844 el = std::make_unique<TextArea>();
1845 auto* ta =
static_cast<TextArea*
>(el.get());
1847 std::vector<char> tel;
1848 tel.assign(begin + start, it_gt);
1853 if (it != end) ++it;
1854 const auto content_begin = it;
1857 auto lt = std::find(it, end,
'<');
1863 if (ieq_prefix(lt, end,
"</textarea")) {
1864 auto after_head = lt + std::strlen(
"</textarea");
1865 while (after_head != end && is_ws(
static_cast<unsigned char>(*after_head))) {
1868 if (after_head == end) {
1872 if (*after_head ==
'>') {
1873 ta->_Text.insert(ta->_Text.end(), content_begin, lt);
1874 const size_t consumed =
static_cast<size_t>((after_head - begin) + 1);
1903 std::ifstream fs(path);
1910 fs.seekg(std::ios::end);
1912 data.reserve(fs.tellg());
1914 fs.seekg(std::ios::beg);
1916 data.assign((std::istreambuf_iterator<char>(fs)), std::istreambuf_iterator<char>());
1965 }
catch(std::exception &e){
1981void libhtmlpp::HtmlPage::_CheckHeader(
const HtmlString &page){
1982 const char type[] = {
'!',
'D',
'O',
'C',
'T',
'Y',
'P',
'E' };
1998 }
while ( page[i]==
'<' || page[i]==
'!' || page[i] ==
' ');
2000 if (page.
size() < 8) {
2007 if (page[i+1] != type[i]) {
2017 }
while (page[i] ==
' ');
2019 const char doctype[] = {
'H',
'T',
'M',
'L' };
2022 const char typevalue4[] = {
'P',
'U',
'B',
'L',
'I',
'C'};
2025 if ((i + tpvl) > page.
size()) {
2033 while ( ii < tpvl) {
2034 if (tolower(page[i++]) != tolower(doctype[ii++])) {
2045 }
while (page[i] ==
' ');
2049 if(i +tpvl4 <page.
size()){
2051 if (tolower(page[i++]) != tolower(typevalue4[ii++])) {
2073 const std::string &tag =
static_cast<const HtmlElement*
>(el)->getTagname();
2074 if (tag ==
"html") {
2075 output.
append(
"<!DOCTYPE html>");
2081 auto isContainer = [](
const std::string &tagname) {
2089 std::stack<const libhtmlpp::Element*> cpylist;
2098 for(
int i=0; i<lvl; ++i){
2110 curattr->_Key.begin(),
2111 curattr->_Key.end(),
2112 std::back_inserter(output)
2114 if(!curattr->_Value.empty()){
2117 curattr->_Value.begin(),
2118 curattr->_Value.end(),
2119 std::back_inserter(output)
2127 if( !formated && virgin ){
2132 if (
static_cast<const HtmlElement*
>(el)->_childElement) {
2136 el=
static_cast<const HtmlElement*
>(el)->_childElement.get();
2142 if(isContainer(
static_cast<const HtmlElement*
>(el)->getTagname())){
2145 static_cast<const HtmlElement*
>(el)->_TagName.begin(),
2146 static_cast<const HtmlElement*
>(el)->_TagName.end(),
2147 std::back_inserter(output)
2163 static_cast<const TextElement*
>(el)->_Text.begin(),
2165 std::back_inserter(output)
2180 std::back_inserter(output)
2197 curattr->_Key.begin(),
2198 curattr->_Key.end(),
2199 std::back_inserter(output)
2201 if(!curattr->_Value.empty()){
2204 curattr->_Value.begin(),
2205 curattr->_Value.end(),
2206 std::back_inserter(output)
2215 for(
int i=0; i<lvl+1; ++i){
2222 std::back_inserter(output)
2226 for(
int i=0; i<lvl; ++i){
2247 curattr->_Key.begin(),
2248 curattr->_Key.end(),
2249 std::back_inserter(output)
2251 if(!curattr->_Value.empty()){
2254 curattr->_Value.begin(),
2255 curattr->_Value.end(),
2256 std::back_inserter(output)
2265 for(
int i=0; i<lvl+1; ++i){
2270 static_cast<const SvgElement*
>(el)->_Svg.begin(),
2272 std::back_inserter(output)
2276 for(
int i=0; i<lvl; ++i){
2294 for (
TextArea::Attributes* curattr =
static_cast<const TextArea*
>(el)->_firstAttr.get(); curattr; curattr = curattr->_nextAttr.get()) {
2297 curattr->_Key.begin(),
2298 curattr->_Key.end(),
2299 std::back_inserter(output)
2301 if(!curattr->_Value.empty()){
2304 curattr->_Value.begin(),
2305 curattr->_Value.end(),
2306 std::back_inserter(output)
2313 static_cast<const TextArea*
>(el)->_Text.begin(),
2315 std::back_inserter(output)
2335 while(!cpylist.empty()){
2341 for(
int i=0; i<lvl; ++i){
2348 static_cast<const HtmlElement*
>(el)->_TagName.begin(),
2349 static_cast<const HtmlElement*
>(el)->_TagName.end(),
2350 std::back_inserter(output)
2366 std::stack <Element*> childs;
2371 childs.push(((
HtmlElement*)curel)->_childElement.get());
2373 std::string idname=((
HtmlElement*)curel)->getAtributte(
"id");
2374 if(idname.length()==
id.length() && std::equal(
id.begin(),
id.end(),idname.begin()) ){
2384 if(!childs.empty()){
2393 std::stack <Element*> childs;
2398 childs.push(((
HtmlElement*)curel)->_childElement.get());
2400 const std::string tname=((
HtmlElement*)curel)->getTagname();
2401 if(!tname.empty() && std::equal(tag.begin(),tag.end(),tname.begin())){
2411 if(!childs.empty()){
2420 return _childElement.get();
2424 return std::string(_Key.begin(), _Key.end());
2428 return std::string(_Value.begin(), _Value.end());
2432 return _nextAttr.get();
2436 return _firstAttr.get();
2442 const char forbidden[] = {
'\"'};
2444 auto checkForbidden = [forbidden](
const std::string &input){
2445 for(
size_t i = 0; i<input.length(); ++i){
2446 for(
size_t ii=0; ii<
sizeof(forbidden[ii]); ii++){
2447 if(input[i]==forbidden[ii]){
2455 if(checkForbidden(name) || checkForbidden(value)){
2461 for (cattr= _firstAttr.get(); cattr; cattr=cattr->_nextAttr.get()) {
2462 if(name.size() == cattr->_Key.size() && std::equal(name.begin(),name.end(),cattr->_Key.begin())){
2463 cattr->_Value.clear();
2464 std::copy(value.begin(),value.end(),std::back_inserter(cattr->_Value));
2469 _lastAttr->_nextAttr = std::make_unique<Attributes>();
2470 _lastAttr = _lastAttr->_nextAttr.get();
2472 _firstAttr = std::make_unique<Attributes>();
2473 _lastAttr = _firstAttr.get();
2477 std::copy(name.begin(),name.end(),std::back_inserter(cattr->_Key) );
2478 std::copy(value.begin(),value.end(),std::back_inserter(cattr->_Value));
2483 snprintf(buf,255,
"%d",value);
2484 setAttribute(name,buf);
2488 for (
Attributes* curattr = _firstAttr.get(); curattr; curattr = curattr->_nextAttr.get()) {
2490 if (curattr->_Key.size() != name.length() ) {
2494 if (std::equal(name.begin(), name.end(), curattr->_Key.begin())) {
2495 return std::string(curattr->_Value.begin(), curattr->_Value.end());
2503 return atoi(getAtributte(name).c_str());
2511 auto cur = std::move(_nextAttr);
2513 cur = std::move(cur->_nextAttr);
2532 std::unique_ptr<Row> newRow = std::make_unique<Row>(row);
2535 _firstRow = std::move(newRow);
2536 _lastRow = _firstRow.get();
2538 _lastRow->_nextRow = std::move(newRow);
2539 _lastRow = _lastRow->_nextRow.get();
2547 if(!_firstRow || _count<pos){
2554 for(curel=_firstRow.get(); curel; curel=curel->_nextRow.get()){
2564 for(
Row *crow=_firstRow.get(); crow; crow=crow->_nextRow.get()){
2566 for(
Column *ccol=crow->_firstColumn.get(); ccol; ccol=ccol->_nextColumn.get() ){
2582 va_start(args,count);
2584 for (
int i = 0; i < count; ++i) {
2585 _header << va_arg(args,
const char*);
2594 _firstRow = std::move(_firstRow->_nextRow);
2595 _lastRow = (pos == (_count - 1)) ? nullptr : _firstRow.get();
2597 Row *prev = &(*this)[pos - 1];
2598 if (prev->_nextRow) {
2599 prev->_nextRow = std::move(prev->_nextRow->_nextRow);
2601 if (prev->_nextRow.get() ==
nullptr) {
2609 _firstRow =
nullptr;
2615 _nextColumn=
nullptr;
2619 _nextColumn=
nullptr;
2624 _nextColumn=
nullptr;
2629 _nextColumn=
nullptr;
2637 _nextColumn = std::move(col._nextColumn);
2638 Data = std::move(col.Data);
2642 _firstColumn=
nullptr;
2643 _lastColumn=
nullptr;
2652 _firstColumn=
nullptr;
2653 _lastColumn=
nullptr;
2657 for(
Column *curel=row._firstColumn.get(); curel; curel=curel->_nextColumn.get()){
2663 std::unique_ptr<Column> ptr = std::make_unique<Column>(std::move(col));
2666 _lastColumn->_nextColumn=std::move(ptr);
2667 _lastColumn=_lastColumn->_nextColumn.get();
2669 _firstColumn= std::move(ptr);
2670 _lastColumn=_firstColumn.get();
2677 std::unique_ptr<Column> ptr = std::make_unique<Column>(col);
2680 _lastColumn->_nextColumn=std::move(ptr);
2681 _lastColumn=_lastColumn->_nextColumn.get();
2683 _firstColumn= std::move(ptr);
2684 _lastColumn=_firstColumn.get();
2712 snprintf(buf,255,
"%d",value);
2713 return *
this << buf;
2717 if(!_firstColumn || _count<pos){
2724 for(curel=_firstColumn.get(); curel; curel=curel->_nextColumn.get()){
2733 Column *dcol=&(*this)[pos];
2735 Column *prev=&(*this)[pos-1];
2736 prev->_nextColumn=std::move(dcol->_nextColumn);
2742 _firstColumn.reset();
2743 _lastColumn =
nullptr;
class DocElements * prevel
std::unique_ptr< Element > element
std::unique_ptr< DocElements > nextel
Abstract base class for all nodes in the HTML tree.
virtual void remove(Element *el)
void insertAfter(Element *el)
void insertBefore(Element *el)
Element & operator=(const Element &hel)
std::unique_ptr< Element > _nextElement
virtual int getType() const =0
Element * prevElement() const
Element * nextElement() const
const Attributes * firstAttribute() const
HtmlElement * getElementbyTag(const std::string &tag) const
const std::string getAtributte(const std::string &name) const
void _serialelize(const std::vector< char > &in)
Extracts tag name and attributes from a token vector into an HtmlElement.
static size_t parseElement(const std::vector< char > &in, std::unique_ptr< libhtmlpp::Element > &el, size_t start, bool &termination)
void appendChild(const Element *el)
int getIntAtributte(const std::string &name) const
void setTagname(const std::string &name)
void setAttribute(const std::string &name, const std::string &value)
bool operator==(const HtmlElement *hel)
friend void _copy(libhtmlpp::Element *dest, const libhtmlpp::Element *src)
void insertChild(const Element *el)
Element * firstChild() const
const std::string getTagname() const
HtmlElement * getElementbyID(const std::string &id) const
HtmlElement & operator=(const HtmlElement &hel)
std::unique_ptr< Element > _childElement
void setIntAttribute(const std::string &name, int value)
void loadString(libhtmlpp::HtmlElement &html, const std::string &src)
Parses an HTML source string and copies the result into html.
void saveFile(libhtmlpp::HtmlElement &html, const std::string &path)
Serializes an HtmlElement subtree and writes it to a file.
void loadFile(libhtmlpp::HtmlElement &html, const std::string &path)
Loads an HTML file from disk into a given HtmlElement root.
const std::vector< char > & data() const
void append(const std::string &src)
HtmlString & operator<<(const char *src)
HtmlString & operator+=(const std::string &src)
char operator[](size_t pos) const
void push_back(const char src)
void insert(size_t pos, char src)
const char * c_str() const
libhtmlpp::Element & parse()
Parses the current buffer into a DOM-like tree and returns the root element.
HtmlString & operator=(const std::string &src)
const std::string str() const
Row & operator<<(Column &&col)
Column & operator[](size_t pos)
void delColumn(size_t pos)
Row & operator[](size_t pos)
Row & operator<<(const Row &row)
void deleteRow(size_t pos)
void parse(HtmlElement *element)
void insert(HtmlElement *element)
void setHeader(int count,...)
Element representing a <script> tag and its text content.
void setScript(const std::string &txt)
static size_t parseElement(const std::vector< char > &in, std::unique_ptr< libhtmlpp::Element > &el, size_t start, bool &termination)
ScriptElement & operator=(const Element &hel)
std::vector< char > _Script
const std::string getScript()
friend void _copy(libhtmlpp::Element *dest, const libhtmlpp::Element *src)
Element representing an embedded <svg> tag and its attributes/content.
SvgElement & operator=(const Element &hel)
static size_t parseElement(const std::vector< char > &in, std::unique_ptr< libhtmlpp::Element > &el, size_t start, bool &termination)
const std::vector< char > getSvg()
friend void _copy(libhtmlpp::Element *dest, const libhtmlpp::Element *src)
void setSvg(const std::string &svg)
Element representing an embedded <textarea> tag and its attributes/content.
std::vector< char > _Text
TextArea & operator=(const Element &hel)
const std::vector< char > getText()
friend void _copy(libhtmlpp::Element *dest, const libhtmlpp::Element *src)
static size_t parseElement(const std::vector< char > &in, std::unique_ptr< libhtmlpp::Element > &el, size_t start, bool &termination)
void setText(const std::string &text)
Leaf node representing plain text content of an HTML document.
TextElement & operator=(const Element &hel)
std::vector< char > _Text
void setText(const std::string &txt)
friend void _copy(libhtmlpp::Element *dest, const libhtmlpp::Element *src)
static size_t parseElement(const std::vector< char > &in, std::unique_ptr< libhtmlpp::Element > &el, size_t start, bool &termination)
const std::string getText()
#define HTMLTAG_TERMINATE
std::ostream & operator<<(std::ostream &os, const libhtmlpp::HtmlString &p)
Streams an HtmlString to an output stream using its underlying string.
void loadString(libhtmlpp::HtmlElement &html, const libhtmlpp::HtmlString *node)
Public declarations for libhtmlpp HTML element types and utilities.
Core namespace for the libhtmlpp HTML parsing and printing library.
void print(const Element &element, HtmlString &output, bool formated=false)
Serializes an element (and its subtree) into an HtmlString.
void HtmlEncode(const std::string &input, std::string &output)
Encodes special HTML characters in a string and writes into std::string.
const std::array< std::string_view, 100 > ContainerTypes
void _copy(libhtmlpp::Element *dest, const libhtmlpp::Element *src)
const char * HtmlSigns[][2]
void HtmlDecode(const std::string &input, HtmlString &output)
Decodes special HTML characters in a string and appends to an HtmlString.
const std::string getValue() const
Attributes * nextAttribute() const
const std::string getKey() const