Loading src/html.cpp +22 −54 Original line number Diff line number Diff line Loading @@ -238,30 +238,25 @@ void libhtmlpp::HtmlString::_buildtreenode( libhtmlpp::DocElements *lastel, std::unique_ptr<Element> &html) { // FIX 1: Relax initial check. If firstel is non-null, lastel=nullptr is valid (end of list). if (!firstel) { HTMLException excp; excp[HTMLException::Error] << "No start Element!"; throw excp; } // If lastel is nullptr, it represents the end of the entire list. We don't check it here. struct Frame { DocElements *open; // The DocElement node of the opening tag (e.g., <div>) DocElements *close; // The DocElement node of the closing tag (e.g., </div>) const DocElements *outer_end; // The end bound of the parent's span DocElements *open; DocElements *close; const DocElements *outer_end; Element *outer_prev_el; }; std::stack<Frame> stack; DocElements *start = firstel; const DocElements *end = lastel; // end will be nullptr for the root call const DocElements *end = lastel; Element *prev_el_in_tree = nullptr; // parent_el is unused and can be removed, but we'll leave it for now. // HtmlElement *parent_el = nullptr; auto skip_empty = [](DocElements *cur, const DocElements *stop) -> DocElements* { while (cur && cur != stop && (!cur->element)) { cur = cur->nextel.get(); Loading @@ -269,7 +264,6 @@ void libhtmlpp::HtmlString::_buildtreenode( return cur; }; // FIX 2: Cleaned and non-redundant find_terminator logic auto find_terminator = [&skip_empty](DocElements *open, const DocElements *bound) -> DocElements* { if (!open || !open->element || open->terminator || open->element->getType() != HtmlEl) Loading @@ -279,7 +273,6 @@ void libhtmlpp::HtmlString::_buildtreenode( int nest = 0; DocElements *cur = open->nextel.get(); // 1. Search for the terminator up to the boundary while (cur && cur != bound) { cur = skip_empty(cur, bound); Loading @@ -300,8 +293,6 @@ void libhtmlpp::HtmlString::_buildtreenode( cur = cur->nextel.get(); } // 2. Mandatory container check (Only one check here, only runs if search failed) // If the loop finished without finding the terminator, and the tag is mandatory, throw. for (size_t i = 0; ContainerTypes[i]; ++i) { if (tag == ContainerTypes[i]) { HTMLException e; Loading @@ -313,45 +304,26 @@ void libhtmlpp::HtmlString::_buildtreenode( return nullptr; }; // --- Main Iterative Traversal Loop --- for (;;) { start = skip_empty(start, end); // A. END OF CURRENT SCOPE CHECK (Base case/Return from recursion) if (!start || start == end) { // Final return for the root scope if (stack.empty()) { // If the root element (firstel->element) was never moved into a sibling chain // because it was the only element, move it now. // In a well-formed HTML (like <html>...</html>), the <html> opener // is the firstel. Its element is moved here only if it wasn't moved // into a sibling chain previously (which shouldn't happen). // The root element must be the *first* element in the list. // We move it only if its unique_ptr hasn't been moved yet. if (firstel->element) { html = std::move(firstel->element); } return; } // Restore parent scope (pop from stack) Frame fr = stack.top(); stack.pop(); HtmlElement *opener_el = static_cast<HtmlElement*>(fr.open->element.get()); // CRITICAL STEP: Set parent's _childElement // The element at fr.open->nextel must be the first child of the completed child span. if (fr.open->nextel) { // If element is still here, it was the first child and its unique_ptr was not moved in Case C. if (fr.open->nextel->element) { opener_el->_childElement = std::move(fr.open->nextel->element); } // If it's empty, it means the ownership was transferred to a sibling in Case C, // which is correct for multi-child containers. } // RESTORE STATE: The parent container (opener_el) itself is the last element // of its sibling chain so far. And restore the parent's previous sibling. prev_el_in_tree = opener_el; if (fr.outer_prev_el) { Loading Loading @@ -562,10 +534,6 @@ void libhtmlpp::HtmlString::_buildTree() { } _buildtreenode(firstEl.get(),nullptr,_rootEl); HtmlString test; print(*_rootEl,test,true); std::cout << "test" << test.c_str() << "test" << std::endl; } void libhtmlpp::HtmlString::_serialelize(std::vector<char> in, libhtmlpp::HtmlElement *out) { Loading Loading @@ -745,29 +713,27 @@ void libhtmlpp::HtmlElement::insertChild(const Element& el){ void libhtmlpp::HtmlElement::appendChild(const libhtmlpp::Element* el){ if(_childElement){ Element *curel=_childElement.get(),*prev=nullptr; do{ prev=curel; curel=curel->nextElement(); }while(curel); Element *prev=nullptr; std::unique_ptr<Element> addel; for(Element *curel=_childElement.get(); curel; curel=curel->nextElement()){ prev=curel; } switch(el->getType()){ case HtmlEl: addel=std::make_unique<HtmlElement>(); prev->_nextElement=std::make_unique<HtmlElement>(); break; case TextEl: addel=std::make_unique<TextElement>(); prev->_nextElement=std::make_unique<TextElement>(); break; case CommentEl: addel=std::make_unique<CommentElement>(); prev->_nextElement=std::make_unique<CommentElement>(); break; case ScriptEL: addel=std::make_unique<ScriptElement>(); prev->_nextElement=std::make_unique<ScriptElement>(); break; case SvgEL: addel=std::make_unique<SvgElement>(); prev->_nextElement=std::make_unique<SvgElement>(); break; default: HTMLException ex; Loading @@ -775,11 +741,10 @@ void libhtmlpp::HtmlElement::appendChild(const libhtmlpp::Element* el){ throw ex; } _copy(curel,el); _copy(prev->_nextElement.get(),el); if(prev){ prev->_nextElement=std::move(addel); curel->_prevElement=prev; if(prev->_nextElement){ prev->_nextElement->_prevElement=prev; } }else{ insertChild(el); Loading Loading @@ -861,7 +826,8 @@ void libhtmlpp::HtmlElement::remove(libhtmlpp::Element* el){ namespace libhtmlpp { void _copy(libhtmlpp::Element *dest,const libhtmlpp::Element *src){ const libhtmlpp::Element* prev=dest->prevElement(); const libhtmlpp::Element* prev=nullptr; struct cpyel { cpyel(){ Loading @@ -884,6 +850,7 @@ namespace libhtmlpp { std::stack<cpyel> cpylist; NEWEL: if(src->getType()==HtmlEl && dest->getType()==HtmlEl){ ((libhtmlpp::HtmlElement*)dest)->_TagName=(((libhtmlpp::HtmlElement*)src)->_TagName); for(libhtmlpp::HtmlElement::Attributes *cattr=((libhtmlpp::HtmlElement*)src)->_firstAttr.get(); cattr; cattr=cattr->_nextAttr.get()){ Loading Loading @@ -1008,6 +975,7 @@ namespace libhtmlpp { cpylist.pop(); goto NEWEL; } return; } }; Loading Loading
src/html.cpp +22 −54 Original line number Diff line number Diff line Loading @@ -238,30 +238,25 @@ void libhtmlpp::HtmlString::_buildtreenode( libhtmlpp::DocElements *lastel, std::unique_ptr<Element> &html) { // FIX 1: Relax initial check. If firstel is non-null, lastel=nullptr is valid (end of list). if (!firstel) { HTMLException excp; excp[HTMLException::Error] << "No start Element!"; throw excp; } // If lastel is nullptr, it represents the end of the entire list. We don't check it here. struct Frame { DocElements *open; // The DocElement node of the opening tag (e.g., <div>) DocElements *close; // The DocElement node of the closing tag (e.g., </div>) const DocElements *outer_end; // The end bound of the parent's span DocElements *open; DocElements *close; const DocElements *outer_end; Element *outer_prev_el; }; std::stack<Frame> stack; DocElements *start = firstel; const DocElements *end = lastel; // end will be nullptr for the root call const DocElements *end = lastel; Element *prev_el_in_tree = nullptr; // parent_el is unused and can be removed, but we'll leave it for now. // HtmlElement *parent_el = nullptr; auto skip_empty = [](DocElements *cur, const DocElements *stop) -> DocElements* { while (cur && cur != stop && (!cur->element)) { cur = cur->nextel.get(); Loading @@ -269,7 +264,6 @@ void libhtmlpp::HtmlString::_buildtreenode( return cur; }; // FIX 2: Cleaned and non-redundant find_terminator logic auto find_terminator = [&skip_empty](DocElements *open, const DocElements *bound) -> DocElements* { if (!open || !open->element || open->terminator || open->element->getType() != HtmlEl) Loading @@ -279,7 +273,6 @@ void libhtmlpp::HtmlString::_buildtreenode( int nest = 0; DocElements *cur = open->nextel.get(); // 1. Search for the terminator up to the boundary while (cur && cur != bound) { cur = skip_empty(cur, bound); Loading @@ -300,8 +293,6 @@ void libhtmlpp::HtmlString::_buildtreenode( cur = cur->nextel.get(); } // 2. Mandatory container check (Only one check here, only runs if search failed) // If the loop finished without finding the terminator, and the tag is mandatory, throw. for (size_t i = 0; ContainerTypes[i]; ++i) { if (tag == ContainerTypes[i]) { HTMLException e; Loading @@ -313,45 +304,26 @@ void libhtmlpp::HtmlString::_buildtreenode( return nullptr; }; // --- Main Iterative Traversal Loop --- for (;;) { start = skip_empty(start, end); // A. END OF CURRENT SCOPE CHECK (Base case/Return from recursion) if (!start || start == end) { // Final return for the root scope if (stack.empty()) { // If the root element (firstel->element) was never moved into a sibling chain // because it was the only element, move it now. // In a well-formed HTML (like <html>...</html>), the <html> opener // is the firstel. Its element is moved here only if it wasn't moved // into a sibling chain previously (which shouldn't happen). // The root element must be the *first* element in the list. // We move it only if its unique_ptr hasn't been moved yet. if (firstel->element) { html = std::move(firstel->element); } return; } // Restore parent scope (pop from stack) Frame fr = stack.top(); stack.pop(); HtmlElement *opener_el = static_cast<HtmlElement*>(fr.open->element.get()); // CRITICAL STEP: Set parent's _childElement // The element at fr.open->nextel must be the first child of the completed child span. if (fr.open->nextel) { // If element is still here, it was the first child and its unique_ptr was not moved in Case C. if (fr.open->nextel->element) { opener_el->_childElement = std::move(fr.open->nextel->element); } // If it's empty, it means the ownership was transferred to a sibling in Case C, // which is correct for multi-child containers. } // RESTORE STATE: The parent container (opener_el) itself is the last element // of its sibling chain so far. And restore the parent's previous sibling. prev_el_in_tree = opener_el; if (fr.outer_prev_el) { Loading Loading @@ -562,10 +534,6 @@ void libhtmlpp::HtmlString::_buildTree() { } _buildtreenode(firstEl.get(),nullptr,_rootEl); HtmlString test; print(*_rootEl,test,true); std::cout << "test" << test.c_str() << "test" << std::endl; } void libhtmlpp::HtmlString::_serialelize(std::vector<char> in, libhtmlpp::HtmlElement *out) { Loading Loading @@ -745,29 +713,27 @@ void libhtmlpp::HtmlElement::insertChild(const Element& el){ void libhtmlpp::HtmlElement::appendChild(const libhtmlpp::Element* el){ if(_childElement){ Element *curel=_childElement.get(),*prev=nullptr; do{ prev=curel; curel=curel->nextElement(); }while(curel); Element *prev=nullptr; std::unique_ptr<Element> addel; for(Element *curel=_childElement.get(); curel; curel=curel->nextElement()){ prev=curel; } switch(el->getType()){ case HtmlEl: addel=std::make_unique<HtmlElement>(); prev->_nextElement=std::make_unique<HtmlElement>(); break; case TextEl: addel=std::make_unique<TextElement>(); prev->_nextElement=std::make_unique<TextElement>(); break; case CommentEl: addel=std::make_unique<CommentElement>(); prev->_nextElement=std::make_unique<CommentElement>(); break; case ScriptEL: addel=std::make_unique<ScriptElement>(); prev->_nextElement=std::make_unique<ScriptElement>(); break; case SvgEL: addel=std::make_unique<SvgElement>(); prev->_nextElement=std::make_unique<SvgElement>(); break; default: HTMLException ex; Loading @@ -775,11 +741,10 @@ void libhtmlpp::HtmlElement::appendChild(const libhtmlpp::Element* el){ throw ex; } _copy(curel,el); _copy(prev->_nextElement.get(),el); if(prev){ prev->_nextElement=std::move(addel); curel->_prevElement=prev; if(prev->_nextElement){ prev->_nextElement->_prevElement=prev; } }else{ insertChild(el); Loading Loading @@ -861,7 +826,8 @@ void libhtmlpp::HtmlElement::remove(libhtmlpp::Element* el){ namespace libhtmlpp { void _copy(libhtmlpp::Element *dest,const libhtmlpp::Element *src){ const libhtmlpp::Element* prev=dest->prevElement(); const libhtmlpp::Element* prev=nullptr; struct cpyel { cpyel(){ Loading @@ -884,6 +850,7 @@ namespace libhtmlpp { std::stack<cpyel> cpylist; NEWEL: if(src->getType()==HtmlEl && dest->getType()==HtmlEl){ ((libhtmlpp::HtmlElement*)dest)->_TagName=(((libhtmlpp::HtmlElement*)src)->_TagName); for(libhtmlpp::HtmlElement::Attributes *cattr=((libhtmlpp::HtmlElement*)src)->_firstAttr.get(); cattr; cattr=cattr->_nextAttr.get()){ Loading Loading @@ -1008,6 +975,7 @@ namespace libhtmlpp { cpylist.pop(); goto NEWEL; } return; } }; Loading