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);
683 size_t ilen=input.length();
684 for(
size_t i=0; i<ilen; ++i){
695 output.push_back(input[i]);
700 size_t ilen=input.length();
701 for(
size_t i=0; i<ilen; ++i){
725 std::copy(tagname.begin(),tagname.end(),std::back_inserter(_TagName));
751 std::copy(name.begin(),name.begin()+name.length(),std::back_inserter(_TagName));
757 return std::string(_TagName.begin(),_TagName.end());
762 remove(_childElement.get());
767 _childElement=std::make_unique<HtmlElement>();
770 _childElement=std::make_unique<TextElement>();
773 _childElement=std::make_unique<CommentElement>();
776 _childElement=std::make_unique<ScriptElement>();
779 _childElement=std::make_unique<SvgElement>();
786 _copy(_childElement.get(),el);
799 for(
Element *curel=_childElement.get(); curel; curel=curel->nextElement()){
843 if( _TagName.size() != hel->_TagName.size())
845 if(std::equal(_TagName.begin(),_TagName.end(),hel->_TagName.begin()))
851 if(_TagName.size() != hel._TagName.size())
853 if(std::equal(_TagName.begin(),_TagName.end(),hel._TagName.begin()))
871 std::stack<Element*> parents;
896 if(!parents.empty()){
916 auto is_space = [](
unsigned char c) ->
bool {
917 return c ==
' ' || c ==
'\t' || c ==
'\n' || c ==
'\r';
919 auto tolower_ascii = [](
unsigned char c) ->
unsigned char {
920 return (c >=
'A' && c <=
'Z') ?
static_cast<unsigned char>(c + 32) : c;
923 size_t i = 0, n = in.size();
925 if (i < n && in[i] ==
'<') ++i;
926 while (i < n && is_space(
static_cast<unsigned char>(in[i]))) ++i;
928 bool end_tag =
false;
929 if (i < n && in[i] ==
'/') {
932 while (i < n && is_space(
static_cast<unsigned char>(in[i]))) ++i;
936 while (r > i && is_space(
static_cast<unsigned char>(in[r - 1]))) --r;
937 if (r > i && in[r - 1] ==
'>') --r;
938 while (r > i && is_space(
static_cast<unsigned char>(in[r - 1]))) --r;
945 const size_t name_start = i;
947 unsigned char c =
static_cast<unsigned char>(in[i]);
948 if (is_space(c) || c ==
'/' || c ==
'>')
break;
951 const size_t name_end = i;
952 if (name_start == name_end) {
957 _TagName.assign(in.begin() + name_start, in.begin() + name_end);
958 for (
char& ch : _TagName) ch =
static_cast<char>(tolower_ascii(
static_cast<unsigned char>(ch)));
965 while (i < r && is_space(
static_cast<unsigned char>(in[i]))) ++i;
970 while (i < r && is_space(
static_cast<unsigned char>(in[i]))) ++i;
974 const size_t kstart = i;
976 unsigned char c =
static_cast<unsigned char>(in[i]);
977 if (is_space(c) || c ==
'=' || c ==
'/' || c ==
'>')
break;
980 const size_t kend = i;
981 if (kstart == kend) {
986 std::string key(in.begin() + kstart, in.begin() + kend);
987 if (!preserveAttrCase) {
988 for (
char& ch : key) ch =
static_cast<char>(tolower_ascii(
static_cast<unsigned char>(ch)));
991 while (i < r && is_space(
static_cast<unsigned char>(in[i]))) ++i;
995 if (i < r && in[i] ==
'=') {
997 while (i < r && is_space(
static_cast<unsigned char>(in[i]))) ++i;
999 if (i < r && (in[i] ==
'"' || in[i] ==
'\'')) {
1000 char quote = in[i++];
1001 const size_t vstart = i;
1002 while (i < r && in[i] != quote) ++i;
1003 const size_t vend = i;
1004 val.assign(in.begin() + vstart, in.begin() + vend);
1005 if (i < r && in[i] == quote) ++i;
1007 const size_t vstart = i;
1009 unsigned char c =
static_cast<unsigned char>(in[i]);
1010 if (is_space(c) || c ==
'/' || c ==
'>')
break;
1013 const size_t vend = i;
1014 val.assign(in.begin() + vstart, in.begin() + vend);
1020 setAttribute(key, val);
1026 const std::vector<char>& in,
1027 std::unique_ptr<libhtmlpp::Element>& el,
1031 el = std::make_unique<HtmlElement>();
1032 termination =
false;
1039 while (i < in.size() && std::isspace(
static_cast<unsigned char>(in[i]))) ++i;
1049 while (k < close && std::isspace(
static_cast<unsigned char>(in[k]))) ++k;
1051 std::vector<char> tel;
1056 while (k < close && std::isspace(
static_cast<unsigned char>(in[k]))) ++k;
1059 tel.insert(tel.end(), in.begin() + k, in.begin() + close);
1061 reinterpret_cast<HtmlElement*
>(el.get())->_serialelize(tel);
1080 cpyel(
const cpyel &src){
1092 std::stack<cpyel> cpylist;
1101 cattr->_Key.begin(),
1104 cattr->_Value.begin(),
1138 cpylist.push(childel);
1143 if(!cattr->_Value.empty()){
1146 cattr->_Key.begin(),
1149 cattr->_Value.begin(),
1161 if(!cattr->_Value.empty()){
1164 cattr->_Key.begin(),
1167 cattr->_Value.begin(),
1172 ((
libhtmlpp::SvgElement*)dest)->setAttribute(std::string(cattr->_Key.begin(),cattr->_Key.end()),
"");
1179 if(!cattr->_Value.empty()){
1182 cattr->_Key.begin(),
1185 cattr->_Value.begin(),
1190 ((
libhtmlpp::TextArea*)dest)->setAttribute(std::string(cattr->_Key.begin(),cattr->_Key.end()),
"");
1214 dest->
_nextElement= std::make_unique<CommentElement>();
1236 if(!cpylist.empty()){
1237 cpyel childel(cpylist.top());
1239 dest=childel.destin;
1249 std::unique_ptr<Element> nel;
1252 nel->_nextElement= std::make_unique<HtmlElement>();
1255 nel->_nextElement= std::make_unique<TextElement>();
1258 nel->_nextElement= std::make_unique<CommentElement>();
1261 nel->_nextElement= std::make_unique<ScriptElement>();
1264 nel->_nextElement= std::make_unique<SvgElement>();
1267 nel->_nextElement= std::make_unique<TextArea>();
1274 _copy(nel.get(),el);
1275 std::unique_ptr<Element> prev=std::move(_prevElement->_nextElement);
1276 _prevElement->_nextElement=std::move(nel);
1277 nel->_nextElement=std::move(prev);
1281 Element *nexel=
nullptr,*prev=
nullptr;
1285 _nextElement= std::make_unique<HtmlElement>();
1288 _nextElement= std::make_unique<TextElement>();
1291 _nextElement= std::make_unique<CommentElement>();
1294 _nextElement= std::make_unique<ScriptElement>();
1297 _nextElement= std::make_unique<SvgElement>();
1300 _nextElement= std::make_unique<TextArea>();
1308 _copy(_nextElement.get(),el);
1310 nexel=_nextElement.get();
1332 return _nextElement.get();
1336 return _prevElement;
1340 _prevElement=
nullptr;
1341 _nextElement=
nullptr;
1345 _prevElement=
nullptr;
1346 _nextElement=
nullptr;
1351 auto cur = std::move(_nextElement);
1353 cur = std::move(cur->_nextElement);
1404 std::copy(txt.begin(),txt.end(),std::back_inserter(_Text));
1408 return std::string(_Text.begin(),_Text.end());
1416 const std::vector<char>& in,
1417 std::unique_ptr<libhtmlpp::Element>& el,
1421 termination =
false;
1423 std::vector<char> buf;
1425 bool seen_nonws =
false;
1426 bool last_was_space =
false;
1429 while (i < in.size()) {
1435 if (c ==
' ' || c ==
'\t' || c ==
'\r' || c ==
'\n') {
1437 if (!last_was_space) {
1439 last_was_space =
true;
1448 last_was_space =
false;
1453 auto text = std::make_unique<TextElement>();
1454 (
static_cast<TextElement*
>(text.get()))->_Text.insert(
1455 (
static_cast<TextElement*
>(text.get()))->_Text.end(),
1456 buf.begin(), buf.end()
1458 el = std::move(text);
1487 std::copy(txt.begin(),txt.end(),
1488 std::insert_iterator<std::vector<char>>(_Comment,_Comment.begin()));
1492 return std::string(_Comment.begin(),_Comment.end());
1500 const std::vector<char>& in,
1501 std::unique_ptr<Element>& el,
1505 termination =
false;
1508 if (i + 3 >= in.size())
return i;
1510 if (!(in[i] ==
'<' && in[i+1] ==
'!' && in[i+2] ==
'-' && in[i+3] ==
'-')) {
1514 el = std::make_unique<CommentElement>();
1517 const size_t content_begin = i;
1519 while (i + 2 < in.size()) {
1520 if (in[i] ==
'-' && in[i+1] ==
'-' && in[i+2] ==
'>') {
1527 if (i > content_begin) {
1528 self->
_Comment.insert(self->_Comment.end(),
1529 in.begin() + content_begin,
1533 if (i + 2 < in.size()) {
1546 _copy(
this,&scriptsrc);
1564 _Script.assign(script.begin(),script.end());
1568 return std::string(_Script.begin(),_Script.end());
1576 const std::vector<char>& in,
1577 std::unique_ptr<Element>& el,
1582 el = std::make_unique<ScriptElement>();
1586 if (i >= in.size() || in[i] !=
'<') {
1592 auto iequals = [](
char a,
char b) {
1593 return std::tolower(
static_cast<unsigned char>(a)) ==
1594 std::tolower(
static_cast<unsigned char>(b));
1598 auto match_ci = [&](
size_t pos,
const char* k) ->
bool {
1599 for (
size_t j = 0; k[j]; ++j) {
1600 if (pos + j >= in.size() || !iequals(in[pos + j], k[j])) {
1611 while (i < in.size() && std::isspace(
static_cast<unsigned char>(in[i]))) {
1615 const char* tag_keyword =
"script";
1616 size_t keyword_len = std::char_traits<char>::length(tag_keyword);
1618 if (i + keyword_len >= in.size() || !match_ci(i, tag_keyword)) {
1621 while (i < in.size() && in[i] !=
'>') {
1624 if (i < in.size()) {
1634 while (i < in.size() && in[i] !=
'>') {
1639 if (i > start && in[i] ==
'>') {
1641 std::vector<char> raw_tag_data(in.begin() + start, in.begin() + i + 1);
1642 self->_serialelize(raw_tag_data);
1645 if (i >= in.size() || in[i] !=
'>') {
1651 size_t content_begin = i;
1654 for (; i < in.size(); ++i) {
1656 if (in[i] ==
'<' && match_ci(i,
"</script")) {
1657 size_t content_end = i;
1660 if (content_end > content_begin) {
1662 self->_Script.insert(self->_Script.end(),
1663 in.begin() + content_begin,
1664 in.begin() + content_end);
1668 size_t closing_tag_end_pos = i + keyword_len + 2;
1671 while (closing_tag_end_pos < in.size() && in[closing_tag_end_pos] !=
'>') {
1672 ++closing_tag_end_pos;
1675 if (closing_tag_end_pos < in.size() && in[closing_tag_end_pos] ==
'>') {
1676 i = closing_tag_end_pos + 1;
1681 return closing_tag_end_pos;
1687 if (in.size() > content_begin) {
1689 self->_Script.insert(self->_Script.end(),
1690 in.begin() + content_begin,
1703 _copy(
this,&svgsrc);
1721 std::copy(script.begin(),script.end(),
1722 std::insert_iterator<std::vector<char>>(_Svg,_Svg.begin()));
1734 std::unique_ptr<libhtmlpp::Element>& el,
1738 const size_t startel = start;
1739 termination =
false;
1741 const auto begin = in.begin();
1742 if (start >= in.size()) {
1746 auto it_close_angle = std::find(begin + start, in.end(),
HTMLTAG_CLOSE);
1747 if (it_close_angle == in.end()) {
1752 el = std::make_unique<SvgElement>();
1753 auto* svgEl =
static_cast<SvgElement*
>(el.get());
1756 std::vector<char> tel;
1757 tel.assign(begin + startel, it_close_angle);
1761 auto it_content_begin = it_close_angle;
1762 if (it_content_begin != in.end()) ++it_content_begin;
1764 static constexpr char kEndTag[] =
"</svg>";
1765 auto ci_eq = [](
char a,
char b) {
1766 auto lower = [](
unsigned char c) ->
unsigned char {
1767 return (c >=
'A' && c <=
'Z') ?
static_cast<unsigned char>(c + 32) : c;
1769 return lower(
static_cast<unsigned char>(a)) == lower(
static_cast<unsigned char>(b));
1771 auto it_end = std::search(it_content_begin, in.end(),
1772 std::begin(kEndTag), std::end(kEndTag) - 1 , ci_eq);
1773 if (it_end == in.end()) {
1778 svgEl->_Svg.insert(svgEl->_Svg.end(), it_content_begin, it_end);
1780 const size_t consumed =
static_cast<size_t>((it_end - begin) + (std::size(kEndTag) - 1));
1790 _copy(
this,&textsrc);
1808 std::copy(text.begin(),text.end(),
1809 std::insert_iterator<std::vector<char>>(_Text,_Text.begin()));
1821 std::unique_ptr<libhtmlpp::Element>& el,
1825 termination =
false;
1827 const auto begin = in.begin();
1828 const auto end = in.end();
1830 if (start >= in.size()) {
1836 auto is_ws = [](
unsigned char c) {
1837 return c ==
' ' || c ==
'\t' || c ==
'\n' || c ==
'\r';
1839 auto tolower_ascii = [](
unsigned char c) ->
unsigned char {
1840 return (c >=
'A' && c <=
'Z') ?
static_cast<unsigned char>(c + 32) : c;
1842 auto ieq_prefix = [&](std::vector<char>::const_iterator it,
1843 std::vector<char>::const_iterator it_end,
1844 const char* lit) ->
bool
1846 for (; *lit; ++lit, ++it) {
1847 if (it == it_end)
return false;
1848 if (tolower_ascii(
static_cast<unsigned char>(*it)) !=
1849 tolower_ascii(
static_cast<unsigned char>(*lit))) {
1862 el = std::make_unique<TextArea>();
1863 auto* ta =
static_cast<TextArea*
>(el.get());
1865 std::vector<char> tel;
1866 tel.assign(begin + start, it_gt);
1871 if (it != end) ++it;
1872 const auto content_begin = it;
1875 auto lt = std::find(it, end,
'<');
1881 if (ieq_prefix(lt, end,
"</textarea")) {
1882 auto after_head = lt + std::strlen(
"</textarea");
1883 while (after_head != end && is_ws(
static_cast<unsigned char>(*after_head))) {
1886 if (after_head == end) {
1890 if (*after_head ==
'>') {
1891 ta->_Text.insert(ta->_Text.end(), content_begin, lt);
1892 const size_t consumed =
static_cast<size_t>((after_head - begin) + 1);
1921 std::ifstream fs(path);
1928 fs.seekg(std::ios::end);
1930 data.reserve(fs.tellg());
1932 fs.seekg(std::ios::beg);
1934 data.assign((std::istreambuf_iterator<char>(fs)), std::istreambuf_iterator<char>());
1983 }
catch(std::exception &e){
1999void libhtmlpp::HtmlPage::_CheckHeader(
const HtmlString &page){
2000 const char type[] = {
'!',
'D',
'O',
'C',
'T',
'Y',
'P',
'E' };
2016 }
while ( page[i]==
'<' || page[i]==
'!' || page[i] ==
' ');
2018 if (page.
size() < 8) {
2025 if (page[i+1] != type[i]) {
2035 }
while (page[i] ==
' ');
2037 const char doctype[] = {
'H',
'T',
'M',
'L' };
2040 const char typevalue4[] = {
'P',
'U',
'B',
'L',
'I',
'C'};
2043 if ((i + tpvl) > page.
size()) {
2051 while ( ii < tpvl) {
2052 if (tolower(page[i++]) != tolower(doctype[ii++])) {
2063 }
while (page[i] ==
' ');
2067 if(i +tpvl4 <page.
size()){
2069 if (tolower(page[i++]) != tolower(typevalue4[ii++])) {
2091 const std::string &tag =
static_cast<const HtmlElement*
>(el)->getTagname();
2092 if (tag ==
"html") {
2093 output.
append(
"<!DOCTYPE html>");
2099 auto isContainer = [](
const std::string &tagname) {
2107 std::stack<const libhtmlpp::Element*> cpylist;
2116 for(
int i=0; i<lvl; ++i){
2128 curattr->_Key.begin(),
2129 curattr->_Key.end(),
2130 std::back_inserter(output)
2132 if(!curattr->_Value.empty()){
2135 curattr->_Value.begin(),
2136 curattr->_Value.end(),
2137 std::back_inserter(output)
2145 if( !formated && virgin ){
2150 if (
static_cast<const HtmlElement*
>(el)->_childElement) {
2154 el=
static_cast<const HtmlElement*
>(el)->_childElement.get();
2160 if(isContainer(
static_cast<const HtmlElement*
>(el)->getTagname())){
2163 static_cast<const HtmlElement*
>(el)->_TagName.begin(),
2164 static_cast<const HtmlElement*
>(el)->_TagName.end(),
2165 std::back_inserter(output)
2181 static_cast<const TextElement*
>(el)->_Text.begin(),
2183 std::back_inserter(output)
2198 std::back_inserter(output)
2215 curattr->_Key.begin(),
2216 curattr->_Key.end(),
2217 std::back_inserter(output)
2219 if(!curattr->_Value.empty()){
2222 curattr->_Value.begin(),
2223 curattr->_Value.end(),
2224 std::back_inserter(output)
2233 for(
int i=0; i<lvl+1; ++i){
2240 std::back_inserter(output)
2244 for(
int i=0; i<lvl; ++i){
2265 curattr->_Key.begin(),
2266 curattr->_Key.end(),
2267 std::back_inserter(output)
2269 if(!curattr->_Value.empty()){
2272 curattr->_Value.begin(),
2273 curattr->_Value.end(),
2274 std::back_inserter(output)
2283 for(
int i=0; i<lvl+1; ++i){
2288 static_cast<const SvgElement*
>(el)->_Svg.begin(),
2290 std::back_inserter(output)
2294 for(
int i=0; i<lvl; ++i){
2312 for (
TextArea::Attributes* curattr =
static_cast<const TextArea*
>(el)->_firstAttr.get(); curattr; curattr = curattr->_nextAttr.get()) {
2315 curattr->_Key.begin(),
2316 curattr->_Key.end(),
2317 std::back_inserter(output)
2319 if(!curattr->_Value.empty()){
2322 curattr->_Value.begin(),
2323 curattr->_Value.end(),
2324 std::back_inserter(output)
2331 static_cast<const TextArea*
>(el)->_Text.begin(),
2333 std::back_inserter(output)
2353 while(!cpylist.empty()){
2359 for(
int i=0; i<lvl; ++i){
2366 static_cast<const HtmlElement*
>(el)->_TagName.begin(),
2367 static_cast<const HtmlElement*
>(el)->_TagName.end(),
2368 std::back_inserter(output)
2384 std::stack <Element*> childs;
2389 childs.push(((
HtmlElement*)curel)->_childElement.get());
2391 std::string idname=((
HtmlElement*)curel)->getAtributte(
"id");
2392 if(idname.length()==
id.length() && std::equal(
id.begin(),
id.end(),idname.begin()) ){
2402 if(!childs.empty()){
2411 std::stack <Element*> childs;
2416 childs.push(((
HtmlElement*)curel)->_childElement.get());
2418 const std::string tname=((
HtmlElement*)curel)->getTagname();
2419 if(!tname.empty() && std::equal(tag.begin(),tag.end(),tname.begin())){
2429 if(!childs.empty()){
2438 return _childElement.get();
2442 return std::string(_Key.begin(), _Key.end());
2446 return std::string(_Value.begin(), _Value.end());
2450 return _nextAttr.get();
2454 return _firstAttr.get();
2460 const char forbidden[] = {
'\"'};
2462 auto checkForbidden = [forbidden](
const std::string &input){
2463 for(
size_t i = 0; i<input.length(); ++i){
2464 for(
size_t ii=0; ii<
sizeof(forbidden[ii]); ii++){
2465 if(input[i]==forbidden[ii]){
2473 if(checkForbidden(name) || checkForbidden(value)){
2479 for (cattr= _firstAttr.get(); cattr; cattr=cattr->_nextAttr.get()) {
2480 if(name.size() == cattr->_Key.size() && std::equal(name.begin(),name.end(),cattr->_Key.begin())){
2481 cattr->_Value.clear();
2482 std::copy(value.begin(),value.end(),std::back_inserter(cattr->_Value));
2487 _lastAttr->_nextAttr = std::make_unique<Attributes>();
2488 _lastAttr = _lastAttr->_nextAttr.get();
2490 _firstAttr = std::make_unique<Attributes>();
2491 _lastAttr = _firstAttr.get();
2495 std::copy(name.begin(),name.end(),std::back_inserter(cattr->_Key) );
2496 std::copy(value.begin(),value.end(),std::back_inserter(cattr->_Value));
2501 snprintf(buf,255,
"%d",value);
2502 setAttribute(name,buf);
2506 for (
Attributes* curattr = _firstAttr.get(); curattr; curattr = curattr->_nextAttr.get()) {
2508 if (curattr->_Key.size() != name.length() ) {
2512 if (std::equal(name.begin(), name.end(), curattr->_Key.begin())) {
2513 return std::string(curattr->_Value.begin(), curattr->_Value.end());
2521 return atoi(getAtributte(name).c_str());
2529 auto cur = std::move(_nextAttr);
2531 cur = std::move(cur->_nextAttr);
2550 std::unique_ptr<Row> newRow = std::make_unique<Row>(row);
2553 _firstRow = std::move(newRow);
2554 _lastRow = _firstRow.get();
2556 _lastRow->_nextRow = std::move(newRow);
2557 _lastRow = _lastRow->_nextRow.get();
2565 if(!_firstRow || _count<pos){
2572 for(curel=_firstRow.get(); curel; curel=curel->_nextRow.get()){
2582 for(
Row *crow=_firstRow.get(); crow; crow=crow->_nextRow.get()){
2584 for(
Column *ccol=crow->_firstColumn.get(); ccol; ccol=ccol->_nextColumn.get() ){
2600 va_start(args,count);
2602 for (
int i = 0; i < count; ++i) {
2603 _header << va_arg(args,
const char*);
2612 _firstRow = std::move(_firstRow->_nextRow);
2613 _lastRow = (pos == (_count - 1)) ? nullptr : _firstRow.get();
2615 Row *prev = &(*this)[pos - 1];
2616 if (prev->_nextRow) {
2617 prev->_nextRow = std::move(prev->_nextRow->_nextRow);
2619 if (prev->_nextRow.get() ==
nullptr) {
2627 _firstRow =
nullptr;
2633 _nextColumn=
nullptr;
2637 _nextColumn=
nullptr;
2642 _nextColumn=
nullptr;
2647 _nextColumn=
nullptr;
2655 _nextColumn = std::move(col._nextColumn);
2656 Data = std::move(col.Data);
2660 _firstColumn=
nullptr;
2661 _lastColumn=
nullptr;
2670 _firstColumn=
nullptr;
2671 _lastColumn=
nullptr;
2675 for(
Column *curel=row._firstColumn.get(); curel; curel=curel->_nextColumn.get()){
2681 std::unique_ptr<Column> ptr = std::make_unique<Column>(std::move(col));
2684 _lastColumn->_nextColumn=std::move(ptr);
2685 _lastColumn=_lastColumn->_nextColumn.get();
2687 _firstColumn= std::move(ptr);
2688 _lastColumn=_firstColumn.get();
2695 std::unique_ptr<Column> ptr = std::make_unique<Column>(col);
2698 _lastColumn->_nextColumn=std::move(ptr);
2699 _lastColumn=_lastColumn->_nextColumn.get();
2701 _firstColumn= std::move(ptr);
2702 _lastColumn=_firstColumn.get();
2730 snprintf(buf,255,
"%d",value);
2731 return *
this << buf;
2735 if(!_firstColumn || _count<pos){
2742 for(curel=_firstColumn.get(); curel; curel=curel->_nextColumn.get()){
2751 Column *dcol=&(*this)[pos];
2753 Column *prev=&(*this)[pos-1];
2754 prev->_nextColumn=std::move(dcol->_nextColumn);
2760 _firstColumn.reset();
2761 _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 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