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);
345 if (!_Data.empty() && _Data.back() ==
'\0')
346 return _Data.size() - 1;
352 return std::string(_Data.begin(), _Data.begin() +
static_cast<long>(size()));
371void libhtmlpp::HtmlString::_buildtreenode(
374 std::unique_ptr<Element> &html)
385 const DocElements *outer_end;
386 Element *outer_prev_el;
388 std::stack<Frame> stack;
390 DocElements *start = firstel;
391 const DocElements *end = lastel;
393 Element *prev_el_in_tree =
nullptr;
395 auto checkContainer = [&](
const std::string &tag) {
403 auto skip_empty = [](DocElements *cur,
const DocElements *stop) -> DocElements* {
404 while (cur && cur != stop && (!cur->element)) {
411 auto find_terminator = [&skip_empty, checkContainer](DocElements *open,
const DocElements *bound) -> DocElements* {
412 if (!open || !open->element || open->terminator ||
413 open->element->getType() !=
HtmlEl)
return nullptr;
415 const std::string &tag =
static_cast<HtmlElement*
>(open->element.get())->getTagname();
417 DocElements *cur = open->nextel.get();
419 while (cur && cur != bound) {
420 cur = skip_empty(cur, bound);
421 if (!cur || cur == bound)
break;
423 if (cur->element && cur->element->getType() ==
HtmlEl) {
424 const std::string &curtag =
static_cast<HtmlElement*
>(cur->element.get())->getTagname();
426 if (cur->terminator) {
427 if (nest == 0)
return cur;
434 cur = cur->nextel.get();
438 if (checkContainer(tag)) {
447 start = skip_empty(start, end);
450 if (start && start != end && start->terminator) {
451 start = start->nextel.get();
456 if (!start || start == end) {
460 html = std::move(firstel->
element);
466 Frame fr = stack.top(); stack.pop();
467 HtmlElement *opener_el =
static_cast<HtmlElement*
>(fr.open->element.get());
470 Element* last_child_in_chain =
nullptr;
472 DocElements* cur = fr.open->nextel.get();
474 while (cur && cur != fr.close && (!cur->element || cur->terminator)) {
475 cur = cur->nextel.get();
479 while (cur && cur != fr.close) {
480 if (cur->element && !cur->terminator) {
481 if (!opener_el->_childElement) {
482 opener_el->_childElement = std::move(cur->element);
483 last_child_in_chain = opener_el->_childElement.get();
485 last_child_in_chain->_nextElement = std::move(cur->element);
487 last_child_in_chain->_nextElement->_prevElement = last_child_in_chain;
488 last_child_in_chain = last_child_in_chain->_nextElement.get();
491 cur = cur->nextel.get();
493 while (cur && cur != fr.close && (!cur->element || cur->terminator)) {
494 cur = cur->nextel.get();
500 prev_el_in_tree = opener_el;
503 if (fr.outer_prev_el) {
504 prev_el_in_tree->_prevElement = fr.outer_prev_el;
505 fr.outer_prev_el->_nextElement = std::move(fr.open->element);
506 prev_el_in_tree = fr.outer_prev_el->_nextElement.get();
510 prev_el_in_tree = opener_el;
511 start = (fr.close ? fr.close->nextel.get() :
nullptr);
518 if (start->element && !start->terminator && start->element->getType() ==
HtmlEl) {
519 if (DocElements *close = find_terminator(start, end)) {
521 stack.push(Frame{start, close, end, prev_el_in_tree});
524 prev_el_in_tree =
nullptr;
525 start = start->nextel.get();
532 if (start->element && !start->terminator) {
533 Element *current_el = start->element.get();
535 if (prev_el_in_tree) {
536 current_el->_prevElement = prev_el_in_tree;
537 prev_el_in_tree->_nextElement = std::move(start->element);
538 prev_el_in_tree = prev_el_in_tree->_nextElement.get();
540 prev_el_in_tree = current_el;
545 start = start->nextel.get();
554void libhtmlpp::HtmlString::_buildTree() {
555 DocElements* lastEl =
nullptr;
556 std::unique_ptr<DocElements> firstEl =
nullptr;
558 auto is_ws = [](
unsigned char ch) ->
bool {
560 return ch ==
' ' || ch ==
'\t' || ch ==
'\n' || ch ==
'\r';
563 auto ascii_tolower = [](
unsigned char c) ->
unsigned char {
564 return (c >=
'A' && c <=
'Z') ?
static_cast<unsigned char>(c + 32) : c;
567 auto starts_with_ci = [&](
const char* s,
const char* e,
const char* k) ->
bool {
568 const size_t klen = std::char_traits<char>::length(k);
569 if (
static_cast<size_t>(e - s) < klen)
return false;
570 for (
size_t i = 0; i < klen; ++i) {
571 unsigned char a =
static_cast<unsigned char>(s[i]);
572 unsigned char b =
static_cast<unsigned char>(k[i]);
573 if (ascii_tolower(a) != ascii_tolower(b))
return false;
578 auto add_element_node = [&](DocElements** last) {
580 firstEl = std::make_unique<DocElements>();
581 *last = firstEl.get();
583 (*last)->nextel = std::make_unique<DocElements>();
584 (*last)->nextel->prevel = (*last);
585 *last = (*last)->nextel.get();
589 const char*
const base = _Data.data();
590 const size_t n = _Data.size();
591 const char*
const end = base + n;
593 const char* p = base;
596 while (p < end && is_ws(
static_cast<unsigned char>(*p))) ++p;
600 const char*
const remain_end = end;
601 const size_t remain =
static_cast<size_t>(remain_end - p);
604 const unsigned char c1 = ascii_tolower(
static_cast<unsigned char>(p[1]));
608 if (starts_with_ci(p, end,
"<!--")) {
609 add_element_node(&lastEl);
610 size_t i =
static_cast<size_t>(p - base);
615 if (starts_with_ci(p, end,
"<!doctype")) {
616 const char* close_tag = p;
617 while (close_tag < end && *close_tag !=
'>') {
620 if (close_tag < end) {
627 }
else if (c1 ==
's') {
628 if (starts_with_ci(p, end,
"<script")) {
629 add_element_node(&lastEl);
630 size_t i =
static_cast<size_t>(p - base);
635 if (starts_with_ci(p, end,
"<svg")) {
636 add_element_node(&lastEl);
637 size_t i =
static_cast<size_t>(p - base);
642 }
else if (c1 ==
't') {
643 if (starts_with_ci(p, end,
"<textarea")) {
644 add_element_node(&lastEl);
645 size_t i =
static_cast<size_t>(p - base);
654 add_element_node(&lastEl);
655 size_t i =
static_cast<size_t>(p - base);
660 add_element_node(&lastEl);
661 size_t i =
static_cast<size_t>(p - base);
667 _buildtreenode(firstEl.get(),
nullptr, _rootEl);
673 if(_rootEl) HtmlElement::_assignParentPointers(_rootEl.get(),
nullptr);
689 size_t ilen=input.length();
690 for(
size_t i=0; i<ilen; ++i){
701 output.push_back(input[i]);
706 size_t ilen=input.length();
707 for(
size_t i=0; i<ilen; ++i){
731 std::copy(tagname.begin(),tagname.end(),std::back_inserter(_TagName));
757 std::copy(name.begin(),name.begin()+name.length(),std::back_inserter(_TagName));
763 return std::string(_TagName.begin(),_TagName.end());
766void libhtmlpp::HtmlElement::_assignParentPointers(
Element* node,
Element* parent){
786 remove(_childElement.get());
791 _childElement=std::make_unique<HtmlElement>();
794 _childElement=std::make_unique<TextElement>();
797 _childElement=std::make_unique<CommentElement>();
800 _childElement=std::make_unique<ScriptElement>();
803 _childElement=std::make_unique<SvgElement>();
810 _copy(_childElement.get(),el);
814 _childElement->_parentElement =
this;
827 for(
Element *curel=_childElement.get(); curel; curel=curel->nextElement()){
873 if( _TagName.size() != hel->_TagName.size())
875 if(std::equal(_TagName.begin(),_TagName.end(),hel->_TagName.begin()))
881 if(_TagName.size() != hel._TagName.size())
883 if(std::equal(_TagName.begin(),_TagName.end(),hel._TagName.begin()))
922 std::unique_ptr<Element> elsNext(el->
_nextElement.release());
926 if(elsNext) elsNext->_prevElement =
nullptr;
927 static_cast<HtmlElement*
>(parent)->_childElement = std::move(elsNext);
928 }
else if(prevSibling){
950 auto is_space = [](
unsigned char c) ->
bool {
951 return c ==
' ' || c ==
'\t' || c ==
'\n' || c ==
'\r';
953 auto tolower_ascii = [](
unsigned char c) ->
unsigned char {
954 return (c >=
'A' && c <=
'Z') ?
static_cast<unsigned char>(c + 32) : c;
957 size_t i = 0, n = in.size();
959 if (i < n && in[i] ==
'<') ++i;
960 while (i < n && is_space(
static_cast<unsigned char>(in[i]))) ++i;
962 bool end_tag =
false;
963 if (i < n && in[i] ==
'/') {
966 while (i < n && is_space(
static_cast<unsigned char>(in[i]))) ++i;
970 while (r > i && is_space(
static_cast<unsigned char>(in[r - 1]))) --r;
971 if (r > i && in[r - 1] ==
'>') --r;
972 while (r > i && is_space(
static_cast<unsigned char>(in[r - 1]))) --r;
979 const size_t name_start = i;
981 unsigned char c =
static_cast<unsigned char>(in[i]);
982 if (is_space(c) || c ==
'/' || c ==
'>')
break;
985 const size_t name_end = i;
986 if (name_start == name_end) {
991 _TagName.assign(in.begin() + name_start, in.begin() + name_end);
992 for (
char& ch : _TagName) ch =
static_cast<char>(tolower_ascii(
static_cast<unsigned char>(ch)));
999 while (i < r && is_space(
static_cast<unsigned char>(in[i]))) ++i;
1004 while (i < r && is_space(
static_cast<unsigned char>(in[i]))) ++i;
1008 const size_t kstart = i;
1010 unsigned char c =
static_cast<unsigned char>(in[i]);
1011 if (is_space(c) || c ==
'=' || c ==
'/' || c ==
'>')
break;
1014 const size_t kend = i;
1015 if (kstart == kend) {
1020 std::string key(in.begin() + kstart, in.begin() + kend);
1021 if (!preserveAttrCase) {
1022 for (
char& ch : key) ch =
static_cast<char>(tolower_ascii(
static_cast<unsigned char>(ch)));
1025 while (i < r && is_space(
static_cast<unsigned char>(in[i]))) ++i;
1029 if (i < r && in[i] ==
'=') {
1031 while (i < r && is_space(
static_cast<unsigned char>(in[i]))) ++i;
1033 if (i < r && (in[i] ==
'"' || in[i] ==
'\'')) {
1034 char quote = in[i++];
1035 const size_t vstart = i;
1036 while (i < r && in[i] != quote) ++i;
1037 const size_t vend = i;
1038 val.assign(in.begin() + vstart, in.begin() + vend);
1039 if (i < r && in[i] == quote) ++i;
1041 const size_t vstart = i;
1043 unsigned char c =
static_cast<unsigned char>(in[i]);
1044 if (is_space(c) || c ==
'/' || c ==
'>')
break;
1047 const size_t vend = i;
1048 val.assign(in.begin() + vstart, in.begin() + vend);
1054 setAttribute(key, val);
1060 const std::vector<char>& in,
1061 std::unique_ptr<libhtmlpp::Element>& el,
1065 el = std::make_unique<HtmlElement>();
1066 termination =
false;
1073 while (i < in.size() && std::isspace(
static_cast<unsigned char>(in[i]))) ++i;
1083 while (k < close && std::isspace(
static_cast<unsigned char>(in[k]))) ++k;
1085 std::vector<char> tel;
1090 while (k < close && std::isspace(
static_cast<unsigned char>(in[k]))) ++k;
1093 tel.insert(tel.end(), in.begin() + k, in.begin() + close);
1095 reinterpret_cast<HtmlElement*
>(el.get())->_serialelize(tel);
1119 cpyel(
const cpyel &src){
1131 std::stack<cpyel> cpylist;
1140 cattr->_Key.begin(),
1143 cattr->_Value.begin(),
1177 cpylist.push(childel);
1182 if(!cattr->_Value.empty()){
1185 cattr->_Key.begin(),
1188 cattr->_Value.begin(),
1200 if(!cattr->_Value.empty()){
1203 cattr->_Key.begin(),
1206 cattr->_Value.begin(),
1211 ((
libhtmlpp::SvgElement*)dest)->setAttribute(std::string(cattr->_Key.begin(),cattr->_Key.end()),
"");
1218 if(!cattr->_Value.empty()){
1221 cattr->_Key.begin(),
1224 cattr->_Value.begin(),
1229 ((
libhtmlpp::TextArea*)dest)->setAttribute(std::string(cattr->_Key.begin(),cattr->_Key.end()),
"");
1253 dest->
_nextElement= std::make_unique<CommentElement>();
1275 if(!cpylist.empty()){
1276 cpyel childel(cpylist.top());
1278 dest=childel.destin;
1296 libhtmlpp::HtmlElement::_assignParentPointers(destHel->
_childElement.get(), originalDest);
1303 std::unique_ptr<Element> nel;
1306 nel->_nextElement= std::make_unique<HtmlElement>();
1309 nel->_nextElement= std::make_unique<TextElement>();
1312 nel->_nextElement= std::make_unique<CommentElement>();
1315 nel->_nextElement= std::make_unique<ScriptElement>();
1318 nel->_nextElement= std::make_unique<SvgElement>();
1321 nel->_nextElement= std::make_unique<TextArea>();
1328 _copy(nel.get(),el);
1329 std::unique_ptr<Element> prev=std::move(_prevElement->_nextElement);
1330 _prevElement->_nextElement=std::move(nel);
1331 nel->_nextElement=std::move(prev);
1335 Element *nexel=
nullptr,*prev=
nullptr;
1339 _nextElement= std::make_unique<HtmlElement>();
1342 _nextElement= std::make_unique<TextElement>();
1345 _nextElement= std::make_unique<CommentElement>();
1348 _nextElement= std::make_unique<ScriptElement>();
1351 _nextElement= std::make_unique<SvgElement>();
1354 _nextElement= std::make_unique<TextArea>();
1362 _copy(_nextElement.get(),el);
1364 nexel=_nextElement.get();
1386 return _nextElement.get();
1390 return _prevElement;
1394 return _parentElement;
1398 _prevElement=
nullptr;
1399 _nextElement=
nullptr;
1403 _prevElement=
nullptr;
1404 _nextElement=
nullptr;
1409 auto cur = std::move(_nextElement);
1411 cur = std::move(cur->_nextElement);
1431 std::unique_ptr<Element> curelsNext(curel->
_nextElement.release());
1473 std::copy(txt.begin(),txt.end(),std::back_inserter(_Text));
1477 return std::string(_Text.begin(),_Text.end());
1485 const std::vector<char>& in,
1486 std::unique_ptr<libhtmlpp::Element>& el,
1490 termination =
false;
1492 std::vector<char> buf;
1494 bool seen_nonws =
false;
1495 bool last_was_space =
false;
1498 while (i < in.size()) {
1504 if (c ==
' ' || c ==
'\t' || c ==
'\r' || c ==
'\n') {
1506 if (!last_was_space) {
1508 last_was_space =
true;
1517 last_was_space =
false;
1522 auto text = std::make_unique<TextElement>();
1523 (
static_cast<TextElement*
>(text.get()))->_Text.insert(
1524 (
static_cast<TextElement*
>(text.get()))->_Text.end(),
1525 buf.begin(), buf.end()
1527 el = std::move(text);
1556 std::copy(txt.begin(),txt.end(),
1557 std::insert_iterator<std::vector<char>>(_Comment,_Comment.begin()));
1561 return std::string(_Comment.begin(),_Comment.end());
1569 const std::vector<char>& in,
1570 std::unique_ptr<Element>& el,
1574 termination =
false;
1577 if (i + 3 >= in.size())
return i;
1579 if (!(in[i] ==
'<' && in[i+1] ==
'!' && in[i+2] ==
'-' && in[i+3] ==
'-')) {
1583 el = std::make_unique<CommentElement>();
1586 const size_t content_begin = i;
1588 while (i + 2 < in.size()) {
1589 if (in[i] ==
'-' && in[i+1] ==
'-' && in[i+2] ==
'>') {
1596 if (i > content_begin) {
1597 self->
_Comment.insert(self->_Comment.end(),
1598 in.begin() + content_begin,
1602 if (i + 2 < in.size()) {
1615 _copy(
this,&scriptsrc);
1633 _Script.assign(script.begin(),script.end());
1637 return std::string(_Script.begin(),_Script.end());
1645 const std::vector<char>& in,
1646 std::unique_ptr<Element>& el,
1651 el = std::make_unique<ScriptElement>();
1655 if (i >= in.size() || in[i] !=
'<') {
1661 auto iequals = [](
char a,
char b) {
1662 return std::tolower(
static_cast<unsigned char>(a)) ==
1663 std::tolower(
static_cast<unsigned char>(b));
1667 auto match_ci = [&](
size_t pos,
const char* k) ->
bool {
1668 for (
size_t j = 0; k[j]; ++j) {
1669 if (pos + j >= in.size() || !iequals(in[pos + j], k[j])) {
1680 while (i < in.size() && std::isspace(
static_cast<unsigned char>(in[i]))) {
1684 const char* tag_keyword =
"script";
1685 size_t keyword_len = std::char_traits<char>::length(tag_keyword);
1687 if (i + keyword_len >= in.size() || !match_ci(i, tag_keyword)) {
1690 while (i < in.size() && in[i] !=
'>') {
1693 if (i < in.size()) {
1703 while (i < in.size() && in[i] !=
'>') {
1708 if (i > start && in[i] ==
'>') {
1710 std::vector<char> raw_tag_data(in.begin() + start, in.begin() + i + 1);
1711 self->_serialelize(raw_tag_data);
1714 if (i >= in.size() || in[i] !=
'>') {
1720 size_t content_begin = i;
1723 for (; i < in.size(); ++i) {
1725 if (in[i] ==
'<' && match_ci(i,
"</script")) {
1726 size_t content_end = i;
1729 if (content_end > content_begin) {
1731 self->_Script.insert(self->_Script.end(),
1732 in.begin() + content_begin,
1733 in.begin() + content_end);
1737 size_t closing_tag_end_pos = i + keyword_len + 2;
1740 while (closing_tag_end_pos < in.size() && in[closing_tag_end_pos] !=
'>') {
1741 ++closing_tag_end_pos;
1744 if (closing_tag_end_pos < in.size() && in[closing_tag_end_pos] ==
'>') {
1745 i = closing_tag_end_pos + 1;
1750 return closing_tag_end_pos;
1756 if (in.size() > content_begin) {
1758 self->_Script.insert(self->_Script.end(),
1759 in.begin() + content_begin,
1772 _copy(
this,&svgsrc);
1790 std::copy(script.begin(),script.end(),
1791 std::insert_iterator<std::vector<char>>(_Svg,_Svg.begin()));
1803 std::unique_ptr<libhtmlpp::Element>& el,
1807 const size_t startel = start;
1808 termination =
false;
1810 const auto begin = in.begin();
1811 if (start >= in.size()) {
1815 auto it_close_angle = std::find(begin + start, in.end(),
HTMLTAG_CLOSE);
1816 if (it_close_angle == in.end()) {
1821 el = std::make_unique<SvgElement>();
1822 auto* svgEl =
static_cast<SvgElement*
>(el.get());
1825 std::vector<char> tel;
1826 tel.assign(begin + startel, it_close_angle);
1830 auto it_content_begin = it_close_angle;
1831 if (it_content_begin != in.end()) ++it_content_begin;
1833 static constexpr char kEndTag[] =
"</svg>";
1834 auto ci_eq = [](
char a,
char b) {
1835 auto lower = [](
unsigned char c) ->
unsigned char {
1836 return (c >=
'A' && c <=
'Z') ?
static_cast<unsigned char>(c + 32) : c;
1838 return lower(
static_cast<unsigned char>(a)) == lower(
static_cast<unsigned char>(b));
1840 auto it_end = std::search(it_content_begin, in.end(),
1841 std::begin(kEndTag), std::end(kEndTag) - 1 , ci_eq);
1842 if (it_end == in.end()) {
1847 svgEl->_Svg.insert(svgEl->_Svg.end(), it_content_begin, it_end);
1849 const size_t consumed =
static_cast<size_t>((it_end - begin) + (std::size(kEndTag) - 1));
1859 _copy(
this,&textsrc);
1877 std::copy(text.begin(),text.end(),
1878 std::insert_iterator<std::vector<char>>(_Text,_Text.begin()));
1890 std::unique_ptr<libhtmlpp::Element>& el,
1894 termination =
false;
1896 const auto begin = in.begin();
1897 const auto end = in.end();
1899 if (start >= in.size()) {
1905 auto is_ws = [](
unsigned char c) {
1906 return c ==
' ' || c ==
'\t' || c ==
'\n' || c ==
'\r';
1908 auto tolower_ascii = [](
unsigned char c) ->
unsigned char {
1909 return (c >=
'A' && c <=
'Z') ?
static_cast<unsigned char>(c + 32) : c;
1911 auto ieq_prefix = [&](std::vector<char>::const_iterator it,
1912 std::vector<char>::const_iterator it_end,
1913 const char* lit) ->
bool
1915 for (; *lit; ++lit, ++it) {
1916 if (it == it_end)
return false;
1917 if (tolower_ascii(
static_cast<unsigned char>(*it)) !=
1918 tolower_ascii(
static_cast<unsigned char>(*lit))) {
1931 el = std::make_unique<TextArea>();
1932 auto* ta =
static_cast<TextArea*
>(el.get());
1934 std::vector<char> tel;
1935 tel.assign(begin + start, it_gt);
1940 if (it != end) ++it;
1941 const auto content_begin = it;
1944 auto lt = std::find(it, end,
'<');
1950 if (ieq_prefix(lt, end,
"</textarea")) {
1951 auto after_head = lt + std::strlen(
"</textarea");
1952 while (after_head != end && is_ws(
static_cast<unsigned char>(*after_head))) {
1955 if (after_head == end) {
1959 if (*after_head ==
'>') {
1960 ta->_Text.insert(ta->_Text.end(), content_begin, lt);
1961 const size_t consumed =
static_cast<size_t>((after_head - begin) + 1);
1990 std::ifstream fs(path);
1997 fs.seekg(std::ios::end);
1999 data.reserve(fs.tellg());
2001 fs.seekg(std::ios::beg);
2003 data.assign((std::istreambuf_iterator<char>(fs)), std::istreambuf_iterator<char>());
2052 }
catch(std::exception &e){
2068void libhtmlpp::HtmlPage::_CheckHeader(
const HtmlString &page){
2069 const char type[] = {
'!',
'D',
'O',
'C',
'T',
'Y',
'P',
'E' };
2085 }
while ( page[i]==
'<' || page[i]==
'!' || page[i] ==
' ');
2087 if (page.
size() < 8) {
2094 if (page[i+1] != type[i]) {
2104 }
while (page[i] ==
' ');
2106 const char doctype[] = {
'H',
'T',
'M',
'L' };
2109 const char typevalue4[] = {
'P',
'U',
'B',
'L',
'I',
'C'};
2112 if ((i + tpvl) > page.
size()) {
2120 while ( ii < tpvl) {
2121 if (tolower(page[i++]) != tolower(doctype[ii++])) {
2132 }
while (page[i] ==
' ');
2136 if(i +tpvl4 <page.
size()){
2138 if (tolower(page[i++]) != tolower(typevalue4[ii++])) {
2160 const std::string &tag =
static_cast<const HtmlElement*
>(el)->getTagname();
2161 if (tag ==
"html") {
2162 output.
append(
"<!DOCTYPE html>");
2168 auto isContainer = [](
const std::string &tagname) {
2176 std::stack<const libhtmlpp::Element*> cpylist;
2185 for(
int i=0; i<lvl; ++i){
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)
2214 if( !formated && virgin ){
2219 if (
static_cast<const HtmlElement*
>(el)->_childElement) {
2223 el=
static_cast<const HtmlElement*
>(el)->_childElement.get();
2229 if(isContainer(
static_cast<const HtmlElement*
>(el)->getTagname())){
2232 static_cast<const HtmlElement*
>(el)->_TagName.begin(),
2233 static_cast<const HtmlElement*
>(el)->_TagName.end(),
2234 std::back_inserter(output)
2250 static_cast<const TextElement*
>(el)->_Text.begin(),
2252 std::back_inserter(output)
2267 std::back_inserter(output)
2284 curattr->_Key.begin(),
2285 curattr->_Key.end(),
2286 std::back_inserter(output)
2288 if(!curattr->_Value.empty()){
2291 curattr->_Value.begin(),
2292 curattr->_Value.end(),
2293 std::back_inserter(output)
2302 for(
int i=0; i<lvl+1; ++i){
2309 std::back_inserter(output)
2313 for(
int i=0; i<lvl; ++i){
2334 curattr->_Key.begin(),
2335 curattr->_Key.end(),
2336 std::back_inserter(output)
2338 if(!curattr->_Value.empty()){
2341 curattr->_Value.begin(),
2342 curattr->_Value.end(),
2343 std::back_inserter(output)
2352 for(
int i=0; i<lvl+1; ++i){
2357 static_cast<const SvgElement*
>(el)->_Svg.begin(),
2359 std::back_inserter(output)
2363 for(
int i=0; i<lvl; ++i){
2381 for (
TextArea::Attributes* curattr =
static_cast<const TextArea*
>(el)->_firstAttr.get(); curattr; curattr = curattr->_nextAttr.get()) {
2384 curattr->_Key.begin(),
2385 curattr->_Key.end(),
2386 std::back_inserter(output)
2388 if(!curattr->_Value.empty()){
2391 curattr->_Value.begin(),
2392 curattr->_Value.end(),
2393 std::back_inserter(output)
2400 static_cast<const TextArea*
>(el)->_Text.begin(),
2402 std::back_inserter(output)
2422 while(!cpylist.empty()){
2428 for(
int i=0; i<lvl; ++i){
2435 static_cast<const HtmlElement*
>(el)->_TagName.begin(),
2436 static_cast<const HtmlElement*
>(el)->_TagName.end(),
2437 std::back_inserter(output)
2453 std::stack <Element*> childs;
2458 childs.push(((
HtmlElement*)curel)->_childElement.get());
2460 std::string idname=((
HtmlElement*)curel)->getAtributte(
"id");
2461 if(idname.length()==
id.length() && std::equal(
id.begin(),
id.end(),idname.begin()) ){
2471 if(!childs.empty()){
2480 std::stack <Element*> childs;
2485 childs.push(((
HtmlElement*)curel)->_childElement.get());
2487 const std::string tname=((
HtmlElement*)curel)->getTagname();
2488 if(!tname.empty() && std::equal(tag.begin(),tag.end(),tname.begin())){
2498 if(!childs.empty()){
2507 return _childElement.get();
2511 return std::string(_Key.begin(), _Key.end());
2515 return std::string(_Value.begin(), _Value.end());
2519 return _nextAttr.get();
2523 return _firstAttr.get();
2529 const char forbidden[] = {
'\"'};
2531 auto checkForbidden = [forbidden](
const std::string &input){
2532 for(
size_t i = 0; i<input.length(); ++i){
2533 for(
size_t ii=0; ii<
sizeof(forbidden[ii]); ii++){
2534 if(input[i]==forbidden[ii]){
2542 if(checkForbidden(name) || checkForbidden(value)){
2548 for (cattr= _firstAttr.get(); cattr; cattr=cattr->_nextAttr.get()) {
2549 if(name.size() == cattr->_Key.size() && std::equal(name.begin(),name.end(),cattr->_Key.begin())){
2550 cattr->_Value.clear();
2551 std::copy(value.begin(),value.end(),std::back_inserter(cattr->_Value));
2556 _lastAttr->_nextAttr = std::make_unique<Attributes>();
2557 _lastAttr = _lastAttr->_nextAttr.get();
2559 _firstAttr = std::make_unique<Attributes>();
2560 _lastAttr = _firstAttr.get();
2564 std::copy(name.begin(),name.end(),std::back_inserter(cattr->_Key) );
2565 std::copy(value.begin(),value.end(),std::back_inserter(cattr->_Value));
2570 snprintf(buf,255,
"%d",value);
2571 setAttribute(name,buf);
2575 for (
Attributes* curattr = _firstAttr.get(); curattr; curattr = curattr->_nextAttr.get()) {
2577 if (curattr->_Key.size() != name.length() ) {
2581 if (std::equal(name.begin(), name.end(), curattr->_Key.begin())) {
2582 return std::string(curattr->_Value.begin(), curattr->_Value.end());
2590 return atoi(getAtributte(name).c_str());
2598 auto cur = std::move(_nextAttr);
2600 cur = std::move(cur->_nextAttr);
2619 std::unique_ptr<Row> newRow = std::make_unique<Row>(row);
2622 _firstRow = std::move(newRow);
2623 _lastRow = _firstRow.get();
2625 _lastRow->_nextRow = std::move(newRow);
2626 _lastRow = _lastRow->_nextRow.get();
2634 if(!_firstRow || _count<pos){
2641 for(curel=_firstRow.get(); curel; curel=curel->_nextRow.get()){
2651 for(
Row *crow=_firstRow.get(); crow; crow=crow->_nextRow.get()){
2653 for(
Column *ccol=crow->_firstColumn.get(); ccol; ccol=ccol->_nextColumn.get() ){
2669 va_start(args,count);
2671 for (
int i = 0; i < count; ++i) {
2672 _header << va_arg(args,
const char*);
2681 _firstRow = std::move(_firstRow->_nextRow);
2682 _lastRow = (pos == (_count - 1)) ? nullptr : _firstRow.get();
2684 Row *prev = &(*this)[pos - 1];
2685 if (prev->_nextRow) {
2686 prev->_nextRow = std::move(prev->_nextRow->_nextRow);
2688 if (prev->_nextRow.get() ==
nullptr) {
2696 _firstRow =
nullptr;
2702 _nextColumn=
nullptr;
2706 _nextColumn=
nullptr;
2711 _nextColumn=
nullptr;
2716 _nextColumn=
nullptr;
2724 _nextColumn = std::move(col._nextColumn);
2725 Data = std::move(col.Data);
2729 _firstColumn=
nullptr;
2730 _lastColumn=
nullptr;
2739 _firstColumn=
nullptr;
2740 _lastColumn=
nullptr;
2744 for(
Column *curel=row._firstColumn.get(); curel; curel=curel->_nextColumn.get()){
2750 std::unique_ptr<Column> ptr = std::make_unique<Column>(std::move(col));
2753 _lastColumn->_nextColumn=std::move(ptr);
2754 _lastColumn=_lastColumn->_nextColumn.get();
2756 _firstColumn= std::move(ptr);
2757 _lastColumn=_firstColumn.get();
2764 std::unique_ptr<Column> ptr = std::make_unique<Column>(col);
2767 _lastColumn->_nextColumn=std::move(ptr);
2768 _lastColumn=_lastColumn->_nextColumn.get();
2770 _firstColumn= std::move(ptr);
2771 _lastColumn=_firstColumn.get();
2799 snprintf(buf,255,
"%d",value);
2800 return *
this << buf;
2804 if(!_firstColumn || _count<pos){
2811 for(curel=_firstColumn.get(); curel; curel=curel->_nextColumn.get()){
2820 Column *dcol=&(*this)[pos];
2822 Column *prev=&(*this)[pos-1];
2823 prev->_nextColumn=std::move(dcol->_nextColumn);
2829 _firstColumn.reset();
2830 _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 * parentElement() const
Element * nextElement() const
const char * what() const noexcept override
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, bool preserveAttrCase=false)
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