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)) {
431 <<
static_cast<HtmlElement*
>(open->element.get())->getAtributte(
"id");
439 start = skip_empty(start, end);
442 if (start && start != end && start->terminator) {
443 start = start->nextel.get();
448 if (!start || start == end) {
452 html = std::move(firstel->
element);
458 Frame fr = stack.top(); stack.pop();
459 HtmlElement *opener_el =
static_cast<HtmlElement*
>(fr.open->element.get());
462 Element* last_child_in_chain =
nullptr;
464 DocElements* cur = fr.open->nextel.get();
466 while (cur && cur != fr.close && (!cur->element || cur->terminator)) {
467 cur = cur->nextel.get();
471 while (cur && cur != fr.close) {
472 if (cur->element && !cur->terminator) {
473 if (!opener_el->_childElement) {
474 opener_el->_childElement = std::move(cur->element);
475 last_child_in_chain = opener_el->_childElement.get();
477 last_child_in_chain->_nextElement = std::move(cur->element);
479 last_child_in_chain->_nextElement->_prevElement = last_child_in_chain;
480 last_child_in_chain = last_child_in_chain->_nextElement.get();
483 cur = cur->nextel.get();
485 while (cur && cur != fr.close && (!cur->element || cur->terminator)) {
486 cur = cur->nextel.get();
492 prev_el_in_tree = opener_el;
495 if (fr.outer_prev_el) {
496 prev_el_in_tree->_prevElement = fr.outer_prev_el;
497 fr.outer_prev_el->_nextElement = std::move(fr.open->element);
498 prev_el_in_tree = fr.outer_prev_el->_nextElement.get();
502 prev_el_in_tree = opener_el;
503 start = (fr.close ? fr.close->nextel.get() :
nullptr);
510 if (start->element && !start->terminator && start->element->getType() ==
HtmlEl) {
511 if (DocElements *close = find_terminator(start, end)) {
513 stack.push(Frame{start, close, end, prev_el_in_tree});
516 prev_el_in_tree =
nullptr;
517 start = start->nextel.get();
524 if (start->element && !start->terminator) {
525 Element *current_el = start->element.get();
527 if (prev_el_in_tree) {
528 current_el->_prevElement = prev_el_in_tree;
529 prev_el_in_tree->_nextElement = std::move(start->element);
530 prev_el_in_tree = prev_el_in_tree->_nextElement.get();
532 prev_el_in_tree = current_el;
537 start = start->nextel.get();
546void libhtmlpp::HtmlString::_buildTree() {
547 DocElements* lastEl =
nullptr;
548 std::unique_ptr<DocElements> firstEl =
nullptr;
550 auto is_ws = [](
unsigned char ch) ->
bool {
552 return ch ==
' ' || ch ==
'\t' || ch ==
'\n' || ch ==
'\r';
555 auto ascii_tolower = [](
unsigned char c) ->
unsigned char {
556 return (c >=
'A' && c <=
'Z') ?
static_cast<unsigned char>(c + 32) : c;
559 auto starts_with_ci = [&](
const char* s,
const char* e,
const char* k) ->
bool {
560 const size_t klen = std::char_traits<char>::length(k);
561 if (
static_cast<size_t>(e - s) < klen)
return false;
562 for (
size_t i = 0; i < klen; ++i) {
563 unsigned char a =
static_cast<unsigned char>(s[i]);
564 unsigned char b =
static_cast<unsigned char>(k[i]);
565 if (ascii_tolower(a) != ascii_tolower(b))
return false;
570 auto add_element_node = [&](DocElements** last) {
572 firstEl = std::make_unique<DocElements>();
573 *last = firstEl.get();
575 (*last)->nextel = std::make_unique<DocElements>();
576 (*last)->nextel->prevel = (*last);
577 *last = (*last)->nextel.get();
581 const char*
const base = _Data.data();
582 const size_t n = _Data.size();
583 const char*
const end = base + n;
585 const char* p = base;
588 while (p < end && is_ws(
static_cast<unsigned char>(*p))) ++p;
592 const char*
const remain_end = end;
593 const size_t remain =
static_cast<size_t>(remain_end - p);
596 const unsigned char c1 = ascii_tolower(
static_cast<unsigned char>(p[1]));
600 if (starts_with_ci(p, end,
"<!--")) {
601 add_element_node(&lastEl);
602 size_t i =
static_cast<size_t>(p - base);
607 }
else if (c1 ==
's') {
608 if (starts_with_ci(p, end,
"<script")) {
609 add_element_node(&lastEl);
610 size_t i =
static_cast<size_t>(p - base);
615 if (starts_with_ci(p, end,
"<svg")) {
616 add_element_node(&lastEl);
617 size_t i =
static_cast<size_t>(p - base);
622 }
else if (c1 ==
't') {
623 if (starts_with_ci(p, end,
"<textarea")) {
624 add_element_node(&lastEl);
625 size_t i =
static_cast<size_t>(p - base);
634 add_element_node(&lastEl);
635 size_t i =
static_cast<size_t>(p - base);
640 add_element_node(&lastEl);
641 size_t i =
static_cast<size_t>(p - base);
647 _buildtreenode(firstEl.get(),
nullptr, _rootEl);
663 size_t ilen=input.length();
664 for(
size_t i=0; i<ilen; ++i){
675 output.push_back(input[i]);
680 size_t ilen=input.length();
681 for(
size_t i=0; i<ilen; ++i){
705 std::copy(tagname.begin(),tagname.end(),std::back_inserter(_TagName));
731 std::copy(name.begin(),name.begin()+name.length(),std::back_inserter(_TagName));
737 return std::string(_TagName.begin(),_TagName.end());
742 remove(_childElement.get());
747 _childElement=std::make_unique<HtmlElement>();
750 _childElement=std::make_unique<TextElement>();
753 _childElement=std::make_unique<CommentElement>();
756 _childElement=std::make_unique<ScriptElement>();
759 _childElement=std::make_unique<SvgElement>();
766 _copy(_childElement.get(),el);
779 for(
Element *curel=_childElement.get(); curel; curel=curel->nextElement()){
823 if( _TagName.size() != hel->_TagName.size())
825 if(std::equal(_TagName.begin(),_TagName.end(),hel->_TagName.begin()))
831 if(_TagName.size() != hel._TagName.size())
833 if(std::equal(_TagName.begin(),_TagName.end(),hel._TagName.begin()))
851 std::stack<Element*> parents;
876 if(!parents.empty()){
896 auto is_space = [](
unsigned char c) ->
bool {
897 return c ==
' ' || c ==
'\t' || c ==
'\n' || c ==
'\r';
899 auto tolower_ascii = [](
unsigned char c) ->
unsigned char {
900 return (c >=
'A' && c <=
'Z') ?
static_cast<unsigned char>(c + 32) : c;
903 size_t i = 0, n = in.size();
905 if (i < n && in[i] ==
'<') ++i;
906 while (i < n && is_space(
static_cast<unsigned char>(in[i]))) ++i;
908 bool end_tag =
false;
909 if (i < n && in[i] ==
'/') {
912 while (i < n && is_space(
static_cast<unsigned char>(in[i]))) ++i;
916 while (r > i && is_space(
static_cast<unsigned char>(in[r - 1]))) --r;
917 if (r > i && in[r - 1] ==
'>') --r;
918 while (r > i && is_space(
static_cast<unsigned char>(in[r - 1]))) --r;
925 const size_t name_start = i;
927 unsigned char c =
static_cast<unsigned char>(in[i]);
928 if (is_space(c) || c ==
'/' || c ==
'>')
break;
931 const size_t name_end = i;
932 if (name_start == name_end) {
937 _TagName.assign(in.begin() + name_start, in.begin() + name_end);
938 for (
char& ch : _TagName) ch =
static_cast<char>(tolower_ascii(
static_cast<unsigned char>(ch)));
945 while (i < r && is_space(
static_cast<unsigned char>(in[i]))) ++i;
950 while (i < r && is_space(
static_cast<unsigned char>(in[i]))) ++i;
954 const size_t kstart = i;
956 unsigned char c =
static_cast<unsigned char>(in[i]);
957 if (is_space(c) || c ==
'=' || c ==
'/' || c ==
'>')
break;
960 const size_t kend = i;
961 if (kstart == kend) {
966 std::string key(in.begin() + kstart, in.begin() + kend);
967 for (
char& ch : key) ch =
static_cast<char>(tolower_ascii(
static_cast<unsigned char>(ch)));
969 while (i < r && is_space(
static_cast<unsigned char>(in[i]))) ++i;
973 if (i < r && in[i] ==
'=') {
975 while (i < r && is_space(
static_cast<unsigned char>(in[i]))) ++i;
977 if (i < r && (in[i] ==
'"' || in[i] ==
'\'')) {
978 char quote = in[i++];
979 const size_t vstart = i;
980 while (i < r && in[i] != quote) ++i;
981 const size_t vend = i;
982 val.assign(in.begin() + vstart, in.begin() + vend);
983 if (i < r && in[i] == quote) ++i;
985 const size_t vstart = i;
987 unsigned char c =
static_cast<unsigned char>(in[i]);
988 if (is_space(c) || c ==
'/' || c ==
'>')
break;
991 const size_t vend = i;
992 val.assign(in.begin() + vstart, in.begin() + vend);
998 setAttribute(key, val);
1004 const std::vector<char>& in,
1005 std::unique_ptr<libhtmlpp::Element>& el,
1009 el = std::make_unique<HtmlElement>();
1010 termination =
false;
1017 while (i < in.size() && std::isspace(
static_cast<unsigned char>(in[i]))) ++i;
1027 while (k < close && std::isspace(
static_cast<unsigned char>(in[k]))) ++k;
1029 std::vector<char> tel;
1034 while (k < close && std::isspace(
static_cast<unsigned char>(in[k]))) ++k;
1037 tel.insert(tel.end(), in.begin() + k, in.begin() + close);
1039 reinterpret_cast<HtmlElement*
>(el.get())->_serialelize(tel);
1058 cpyel(
const cpyel &src){
1070 std::stack<cpyel> cpylist;
1079 cattr->_Key.begin(),
1082 cattr->_Value.begin(),
1116 cpylist.push(childel);
1121 if(!cattr->_Value.empty()){
1124 cattr->_Key.begin(),
1127 cattr->_Value.begin(),
1139 if(!cattr->_Value.empty()){
1142 cattr->_Key.begin(),
1145 cattr->_Value.begin(),
1150 ((
libhtmlpp::SvgElement*)dest)->setAttribute(std::string(cattr->_Key.begin(),cattr->_Key.end()),
"");
1157 if(!cattr->_Value.empty()){
1160 cattr->_Key.begin(),
1163 cattr->_Value.begin(),
1168 ((
libhtmlpp::TextArea*)dest)->setAttribute(std::string(cattr->_Key.begin(),cattr->_Key.end()),
"");
1192 dest->
_nextElement= std::make_unique<CommentElement>();
1214 if(!cpylist.empty()){
1215 cpyel childel(cpylist.top());
1217 dest=childel.destin;
1227 std::unique_ptr<Element> nel;
1230 nel->_nextElement= std::make_unique<HtmlElement>();
1233 nel->_nextElement= std::make_unique<TextElement>();
1236 nel->_nextElement= std::make_unique<CommentElement>();
1239 nel->_nextElement= std::make_unique<ScriptElement>();
1242 nel->_nextElement= std::make_unique<SvgElement>();
1245 nel->_nextElement= std::make_unique<TextArea>();
1252 _copy(nel.get(),el);
1253 std::unique_ptr<Element> prev=std::move(_prevElement->_nextElement);
1254 _prevElement->_nextElement=std::move(nel);
1255 nel->_nextElement=std::move(prev);
1259 Element *nexel=
nullptr,*prev=
nullptr;
1263 _nextElement= std::make_unique<HtmlElement>();
1266 _nextElement= std::make_unique<TextElement>();
1269 _nextElement= std::make_unique<CommentElement>();
1272 _nextElement= std::make_unique<ScriptElement>();
1275 _nextElement= std::make_unique<SvgElement>();
1278 _nextElement= std::make_unique<TextArea>();
1286 _copy(_nextElement.get(),el);
1288 nexel=_nextElement.get();
1310 return _nextElement.get();
1314 return _prevElement;
1318 _prevElement=
nullptr;
1319 _nextElement=
nullptr;
1323 _prevElement=
nullptr;
1324 _nextElement=
nullptr;
1329 auto cur = std::move(_nextElement);
1331 cur = std::move(cur->_nextElement);
1382 std::copy(txt.begin(),txt.end(),std::back_inserter(_Text));
1386 return std::string(_Text.begin(),_Text.end());
1394 const std::vector<char>& in,
1395 std::unique_ptr<libhtmlpp::Element>& el,
1399 termination =
false;
1401 std::vector<char> buf;
1403 bool seen_nonws =
false;
1404 bool last_was_space =
false;
1407 while (i < in.size()) {
1413 if (c ==
' ' || c ==
'\t' || c ==
'\r' || c ==
'\n') {
1415 if (!last_was_space) {
1417 last_was_space =
true;
1426 last_was_space =
false;
1431 auto text = std::make_unique<TextElement>();
1432 (
static_cast<TextElement*
>(text.get()))->_Text.insert(
1433 (
static_cast<TextElement*
>(text.get()))->_Text.end(),
1434 buf.begin(), buf.end()
1436 el = std::move(text);
1465 std::copy(txt.begin(),txt.end(),
1466 std::insert_iterator<std::vector<char>>(_Comment,_Comment.begin()));
1470 return std::string(_Comment.begin(),_Comment.end());
1478 const std::vector<char>& in,
1479 std::unique_ptr<Element>& el,
1483 termination =
false;
1486 if (i + 3 >= in.size())
return i;
1488 if (!(in[i] ==
'<' && in[i+1] ==
'!' && in[i+2] ==
'-' && in[i+3] ==
'-')) {
1492 el = std::make_unique<CommentElement>();
1495 const size_t content_begin = i;
1497 while (i + 2 < in.size()) {
1498 if (in[i] ==
'-' && in[i+1] ==
'-' && in[i+2] ==
'>') {
1505 if (i > content_begin) {
1506 self->
_Comment.insert(self->_Comment.end(),
1507 in.begin() + content_begin,
1511 if (i + 2 < in.size()) {
1524 _copy(
this,&scriptsrc);
1542 std::copy(script.begin(),script.end(),std::back_inserter(_Script));
1546 return std::string(_Script.begin(),_Script.end());
1554 const std::vector<char>& in,
1555 std::unique_ptr<Element>& el,
1560 el = std::make_unique<ScriptElement>();
1564 if (i >= in.size() || in[i] !=
'<') {
1570 auto iequals = [](
char a,
char b) {
1571 return std::tolower(
static_cast<unsigned char>(a)) ==
1572 std::tolower(
static_cast<unsigned char>(b));
1576 auto match_ci = [&](
size_t pos,
const char* k) ->
bool {
1577 for (
size_t j = 0; k[j]; ++j) {
1578 if (pos + j >= in.size() || !iequals(in[pos + j], k[j])) {
1589 while (i < in.size() && std::isspace(
static_cast<unsigned char>(in[i]))) {
1593 const char* tag_keyword =
"script";
1594 size_t keyword_len = std::char_traits<char>::length(tag_keyword);
1596 if (i + keyword_len >= in.size() || !match_ci(i, tag_keyword)) {
1599 while (i < in.size() && in[i] !=
'>') {
1602 if (i < in.size()) {
1612 while (i < in.size() && in[i] !=
'>') {
1617 if (i > start && in[i] ==
'>') {
1619 std::vector<char> raw_tag_data(in.begin() + start, in.begin() + i + 1);
1620 self->_serialelize(raw_tag_data);
1623 if (i >= in.size() || in[i] !=
'>') {
1629 size_t content_begin = i;
1632 for (; i < in.size(); ++i) {
1634 if (in[i] ==
'<' && match_ci(i,
"</script")) {
1635 size_t content_end = i;
1638 if (content_end > content_begin) {
1640 self->_Script.insert(self->_Script.end(),
1641 in.begin() + content_begin,
1642 in.begin() + content_end);
1646 size_t closing_tag_end_pos = i + keyword_len + 2;
1649 while (closing_tag_end_pos < in.size() && in[closing_tag_end_pos] !=
'>') {
1650 ++closing_tag_end_pos;
1653 if (closing_tag_end_pos < in.size() && in[closing_tag_end_pos] ==
'>') {
1654 i = closing_tag_end_pos + 1;
1659 return closing_tag_end_pos;
1665 if (in.size() > content_begin) {
1667 self->_Script.insert(self->_Script.end(),
1668 in.begin() + content_begin,
1681 _copy(
this,&svgsrc);
1699 std::copy(script.begin(),script.end(),
1700 std::insert_iterator<std::vector<char>>(_Svg,_Svg.begin()));
1712 std::unique_ptr<libhtmlpp::Element>& el,
1716 const size_t startel = start;
1717 termination =
false;
1719 const auto begin = in.begin();
1720 if (start >= in.size()) {
1724 auto it_close_angle = std::find(begin + start, in.end(),
HTMLTAG_CLOSE);
1725 if (it_close_angle == in.end()) {
1730 el = std::make_unique<SvgElement>();
1731 auto* svgEl =
static_cast<SvgElement*
>(el.get());
1734 std::vector<char> tel;
1735 tel.assign(begin + startel, it_close_angle);
1739 auto it_content_begin = it_close_angle;
1740 if (it_content_begin != in.end()) ++it_content_begin;
1742 static constexpr char kEndTag[] =
"</svg>";
1743 auto it_end = std::search(it_content_begin, in.end(),
1744 std::begin(kEndTag), std::end(kEndTag) - 1 );
1745 if (it_end == in.end()) {
1750 svgEl->_Svg.insert(svgEl->_Svg.end(), it_content_begin, it_end);
1752 const size_t consumed =
static_cast<size_t>((it_end - begin) + (std::size(kEndTag) - 1));
1762 _copy(
this,&textsrc);
1780 std::copy(text.begin(),text.end(),
1781 std::insert_iterator<std::vector<char>>(_Text,_Text.begin()));
1793 std::unique_ptr<libhtmlpp::Element>& el,
1797 termination =
false;
1799 const auto begin = in.begin();
1800 const auto end = in.end();
1802 if (start >= in.size()) {
1808 auto is_ws = [](
unsigned char c) {
1809 return c ==
' ' || c ==
'\t' || c ==
'\n' || c ==
'\r';
1811 auto tolower_ascii = [](
unsigned char c) ->
unsigned char {
1812 return (c >=
'A' && c <=
'Z') ?
static_cast<unsigned char>(c + 32) : c;
1814 auto ieq_prefix = [&](std::vector<char>::const_iterator it,
1815 std::vector<char>::const_iterator it_end,
1816 const char* lit) ->
bool
1818 for (; *lit; ++lit, ++it) {
1819 if (it == it_end)
return false;
1820 if (tolower_ascii(
static_cast<unsigned char>(*it)) !=
1821 tolower_ascii(
static_cast<unsigned char>(*lit))) {
1834 el = std::make_unique<TextArea>();
1835 auto* ta =
static_cast<TextArea*
>(el.get());
1837 std::vector<char> tel;
1838 tel.assign(begin + start, it_gt);
1843 if (it != end) ++it;
1844 const auto content_begin = it;
1847 auto lt = std::find(it, end,
'<');
1853 if (ieq_prefix(lt, end,
"</textarea")) {
1854 auto after_head = lt + std::strlen(
"</textarea");
1855 while (after_head != end && is_ws(
static_cast<unsigned char>(*after_head))) {
1858 if (after_head == end) {
1862 if (*after_head ==
'>') {
1863 ta->_Text.insert(ta->_Text.end(), content_begin, lt);
1864 const size_t consumed =
static_cast<size_t>((after_head - begin) + 1);
1893 std::ifstream fs(path);
1900 fs.seekg(std::ios::end);
1902 data.reserve(fs.tellg());
1904 fs.seekg(std::ios::beg);
1906 data.assign((std::istreambuf_iterator<char>(fs)), std::istreambuf_iterator<char>());
1955 }
catch(std::exception &e){
1971void libhtmlpp::HtmlPage::_CheckHeader(
const HtmlString &page){
1972 const char type[] = {
'!',
'D',
'O',
'C',
'T',
'Y',
'P',
'E' };
1988 }
while ( page[i]==
'<' || page[i]==
'!' || page[i] ==
' ');
1990 if (page.
size() < 8) {
1997 if (page[i+1] != type[i]) {
2007 }
while (page[i] ==
' ');
2009 const char doctype[] = {
'H',
'T',
'M',
'L' };
2012 const char typevalue4[] = {
'P',
'U',
'B',
'L',
'I',
'C'};
2015 if ((i + tpvl) > page.
size()) {
2023 while ( ii < tpvl) {
2024 if (tolower(page[i++]) != tolower(doctype[ii++])) {
2035 }
while (page[i] ==
' ');
2039 if(i +tpvl4 <page.
size()){
2041 if (tolower(page[i++]) != tolower(typevalue4[ii++])) {
2061 auto isContainer = [](
const std::string &tagname) {
2069 std::stack<const libhtmlpp::Element*> cpylist;
2078 for(
int i=0; i<lvl; ++i){
2090 curattr->_Key.begin(),
2091 curattr->_Key.end(),
2092 std::back_inserter(output)
2094 if(!curattr->_Value.empty()){
2097 curattr->_Value.begin(),
2098 curattr->_Value.end(),
2099 std::back_inserter(output)
2107 if( !formated && virgin ){
2112 if (
static_cast<const HtmlElement*
>(el)->_childElement) {
2116 el=
static_cast<const HtmlElement*
>(el)->_childElement.get();
2122 if(isContainer(
static_cast<const HtmlElement*
>(el)->getTagname())){
2125 static_cast<const HtmlElement*
>(el)->_TagName.begin(),
2126 static_cast<const HtmlElement*
>(el)->_TagName.end(),
2127 std::back_inserter(output)
2143 static_cast<const TextElement*
>(el)->_Text.begin(),
2145 std::back_inserter(output)
2160 std::back_inserter(output)
2177 curattr->_Key.begin(),
2178 curattr->_Key.end(),
2179 std::back_inserter(output)
2181 if(!curattr->_Value.empty()){
2184 curattr->_Value.begin(),
2185 curattr->_Value.end(),
2186 std::back_inserter(output)
2195 for(
int i=0; i<lvl+1; ++i){
2202 std::back_inserter(output)
2206 for(
int i=0; i<lvl; ++i){
2227 curattr->_Key.begin(),
2228 curattr->_Key.end(),
2229 std::back_inserter(output)
2231 if(!curattr->_Value.empty()){
2234 curattr->_Value.begin(),
2235 curattr->_Value.end(),
2236 std::back_inserter(output)
2245 for(
int i=0; i<lvl+1; ++i){
2250 static_cast<const SvgElement*
>(el)->_Svg.begin(),
2252 std::back_inserter(output)
2256 for(
int i=0; i<lvl; ++i){
2274 for (
TextArea::Attributes* curattr =
static_cast<const TextArea*
>(el)->_firstAttr.get(); curattr; curattr = curattr->_nextAttr.get()) {
2277 curattr->_Key.begin(),
2278 curattr->_Key.end(),
2279 std::back_inserter(output)
2281 if(!curattr->_Value.empty()){
2284 curattr->_Value.begin(),
2285 curattr->_Value.end(),
2286 std::back_inserter(output)
2293 static_cast<const TextArea*
>(el)->_Text.begin(),
2295 std::back_inserter(output)
2315 while(!cpylist.empty()){
2321 for(
int i=0; i<lvl; ++i){
2328 static_cast<const HtmlElement*
>(el)->_TagName.begin(),
2329 static_cast<const HtmlElement*
>(el)->_TagName.end(),
2330 std::back_inserter(output)
2346 std::stack <Element*> childs;
2351 childs.push(((
HtmlElement*)curel)->_childElement.get());
2353 std::string idname=((
HtmlElement*)curel)->getAtributte(
"id");
2354 if(idname.length()==
id.length() && std::equal(
id.begin(),
id.end(),idname.begin()) ){
2364 if(!childs.empty()){
2373 std::stack <Element*> childs;
2378 childs.push(((
HtmlElement*)curel)->_childElement.get());
2380 const std::string tname=((
HtmlElement*)curel)->getTagname();
2381 if(!tname.empty() && std::equal(tag.begin(),tag.end(),tname.begin())){
2391 if(!childs.empty()){
2400 return _childElement.get();
2404 return std::string(_Key.begin(), _Key.end());
2408 return std::string(_Value.begin(), _Value.end());
2412 return _nextAttr.get();
2416 return _firstAttr.get();
2422 const char forbidden[] = {
'\"'};
2424 auto checkForbidden = [forbidden](
const std::string &input){
2425 for(
size_t i = 0; i<input.length(); ++i){
2426 for(
size_t ii=0; ii<
sizeof(forbidden[ii]); ii++){
2427 if(input[i]==forbidden[ii]){
2435 if(checkForbidden(name) || checkForbidden(value)){
2441 for (cattr= _firstAttr.get(); cattr; cattr=cattr->_nextAttr.get()) {
2442 if(name.size() == cattr->_Key.size() && std::equal(name.begin(),name.end(),cattr->_Key.begin())){
2443 cattr->_Value.clear();
2444 std::copy(value.begin(),value.end(),std::back_inserter(cattr->_Value));
2449 _lastAttr->_nextAttr = std::make_unique<Attributes>();
2450 _lastAttr = _lastAttr->_nextAttr.get();
2452 _firstAttr = std::make_unique<Attributes>();
2453 _lastAttr = _firstAttr.get();
2457 std::copy(name.begin(),name.end(),std::back_inserter(cattr->_Key) );
2458 std::copy(value.begin(),value.end(),std::back_inserter(cattr->_Value));
2463 snprintf(buf,255,
"%d",value);
2464 setAttribute(name,buf);
2468 for (
Attributes* curattr = _firstAttr.get(); curattr; curattr = curattr->_nextAttr.get()) {
2470 if (curattr->_Key.size() != name.length() ) {
2474 if (std::equal(name.begin(), name.end(), curattr->_Key.begin())) {
2475 return std::string(curattr->_Value.begin(), curattr->_Value.end());
2483 return atoi(getAtributte(name).c_str());
2491 auto cur = std::move(_nextAttr);
2493 cur = std::move(cur->_nextAttr);
2512 std::unique_ptr<Row> newRow = std::make_unique<Row>(row);
2515 _firstRow = std::move(newRow);
2516 _lastRow = _firstRow.get();
2518 _lastRow->_nextRow = std::move(newRow);
2519 _lastRow = _lastRow->_nextRow.get();
2527 if(!_firstRow || _count<pos){
2534 for(curel=_firstRow.get(); curel; curel=curel->_nextRow.get()){
2544 for(
Row *crow=_firstRow.get(); crow; crow=crow->_nextRow.get()){
2546 for(
Column *ccol=crow->_firstColumn.get(); ccol; ccol=ccol->_nextColumn.get() ){
2562 va_start(args,count);
2564 for (
int i = 0; i < count; ++i) {
2565 _header << va_arg(args,
const char*);
2574 _firstRow = std::move(_firstRow->_nextRow);
2575 _lastRow = (pos == (_count - 1)) ? nullptr : _firstRow.get();
2577 Row *prev = &(*this)[pos - 1];
2578 if (prev->_nextRow) {
2579 prev->_nextRow = std::move(prev->_nextRow->_nextRow);
2581 if (prev->_nextRow.get() ==
nullptr) {
2589 _firstRow =
nullptr;
2595 _nextColumn=
nullptr;
2599 _nextColumn=
nullptr;
2604 _nextColumn=
nullptr;
2609 _nextColumn=
nullptr;
2617 _nextColumn = std::move(col._nextColumn);
2618 Data = std::move(col.Data);
2622 _firstColumn=
nullptr;
2623 _lastColumn=
nullptr;
2632 _firstColumn=
nullptr;
2633 _lastColumn=
nullptr;
2637 for(
Column *curel=row._firstColumn.get(); curel; curel=curel->_nextColumn.get()){
2643 std::unique_ptr<Column> ptr = std::make_unique<Column>(std::move(col));
2646 _lastColumn->_nextColumn=std::move(ptr);
2647 _lastColumn=_lastColumn->_nextColumn.get();
2649 _firstColumn= std::move(ptr);
2650 _lastColumn=_firstColumn.get();
2657 std::unique_ptr<Column> ptr = std::make_unique<Column>(col);
2660 _lastColumn->_nextColumn=std::move(ptr);
2661 _lastColumn=_lastColumn->_nextColumn.get();
2663 _firstColumn= std::move(ptr);
2664 _lastColumn=_firstColumn.get();
2692 snprintf(buf,255,
"%d",value);
2693 return *
this << buf;
2697 if(!_firstColumn || _count<pos){
2704 for(curel=_firstColumn.get(); curel; curel=curel->_nextColumn.get()){
2713 Column *dcol=&(*this)[pos];
2715 Column *prev=&(*this)[pos-1];
2716 prev->_nextColumn=std::move(dcol->_nextColumn);
2722 _firstColumn.reset();
2723 _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