Commit c9a99b74 authored by jan.koester's avatar jan.koester
Browse files

split buildtree

parent 6145aaf9
Loading
Loading
Loading
Loading
+310 −272
Original line number Diff line number Diff line
@@ -342,9 +342,10 @@ void libhtmlpp::HtmlString::_buildtreenode(
            Frame fr = stack.top(); stack.pop();
            HtmlElement *opener_el = static_cast<HtmlElement*>(fr.open->element.get());

            if (fr.open->nextel) {
                if (fr.open->nextel->element) {
            for (DocElements *cnex=fr.open->nextel.get(); cnex; cnex=cnex->nextel.get()) {
                if (fr.open->nextel->element && !fr.open->nextel->terminator) {
                    opener_el->_childElement = std::move(fr.open->nextel->element);
                    break;
                }
            }

@@ -414,194 +415,28 @@ void libhtmlpp::HtmlString::_buildTree() {
    HTMLException excp;

    for(size_t ii=0; ii<_Data.size(); ++ii){
        BUILDTREE_STARTLOOP:
        if(_Data[ii]==HTMLTAG_OPEN){
            if( (ii + 3) < _Data.size() && std::equal(_Data.begin()+ii,_Data.begin()+(ii+3), "<!--")){
                size_t start=ii+3;
                while(ii<_Data.size()){
                    if(std::equal(_Data.begin()+ii,_Data.begin()+(ii+3),"-->")) {
                addelement(&lastEl);

                        lastEl->element=std::make_unique<CommentElement>();
                        std::copy(_Data.begin()+start,_Data.begin()+ii,
                                  std::back_inserter(static_cast<CommentElement*>(lastEl->element.get())->_Comment));

                        ii+=2;

                        break;
                    }
                    ++ii;
                }
                ii+=CommentElement::parseElement(_Data,lastEl->element,ii,lastEl->terminator);
            }else if((ii+6) < _Data.size() && std::equal(_Data.begin()+ii,_Data.begin()+(ii+6),"<script")){
                size_t start=ii;

                while(ii<_Data.size()){
                    if(_Data[ii]==HTMLTAG_CLOSE) {
                addelement(&lastEl);
                        lastEl->element=std::make_unique<ScriptElement>();
                        std::vector<char> tel;

                        std::copy(_Data.begin()+start,_Data.begin()+ii,std::back_inserter(tel));

                        _serialelize(tel,static_cast<ScriptElement*>(lastEl->element.get()));

                        break;
                    }
                    ++ii;
                }

                size_t close=++ii;

                while(ii<_Data.size()){
                    if( std::equal(_Data.begin()+ii,_Data.begin()+(ii+7),"</script")) {

                        std::copy(_Data.begin()+close,_Data.begin()+ii,
                                  std::back_inserter(static_cast<ScriptElement*>(lastEl->element.get())->_Script));
                        ii+=8;
                        break;
                    }
                    ++ii;
                }

                if (ii == _Data.size()) {
                    throw excp[HTMLException::Error] << "Parsing error: Missing </script closing tag.";
                }

                ii+=ScriptElement::parseElement(_Data,lastEl->element,ii,lastEl->terminator);
            }else if( (ii+3) < _Data.size() && std::equal(_Data.begin()+ii,_Data.begin()+(ii+3),"<svg")){
                size_t start=ii;

                while(ii<_Data.size()){
                    if(_Data[ii]==HTMLTAG_CLOSE) {
                addelement(&lastEl);
                        lastEl->element=std::make_unique<SvgElement>();
                        std::vector<char> tel;

                        std::copy(_Data.begin()+start,_Data.begin()+ii,std::back_inserter(tel));

                        _serialelize(tel,(SvgElement*)lastEl->element.get());

                        break;
                    }
                    ++ii;
                }

                size_t close=++ii;

                while(ii<_Data.size()){
                    if( std::equal(_Data.begin()+ii,_Data.begin()+(ii+4),"</svg")) {

                        std::copy(_Data.begin()+close,_Data.begin()+ii,
                                  std::back_inserter(static_cast<SvgElement*>(lastEl->element.get())->_Svg));
                        ii+=5;
                        break;
                    }
                    ++ii;
                }

                if (ii == _Data.size()) {
                    throw excp[HTMLException::Error] << "Parsing error: Missing </textarea closing tag.";
                }

                ii+=SvgElement::parseElement(_Data,lastEl->element,ii,lastEl->terminator);
            }else if( (ii + 9) <= _Data.size() && std::equal(_Data.begin()+ii,_Data.begin()+(ii+9),"<textarea")){
                size_t start = ii;
                while(ii < _Data.size()){
                    if(_Data[ii] == HTMLTAG_CLOSE) {
                addelement(&lastEl);
                        lastEl->element = std::make_unique<TextArea>();
                        std::vector<char> tel;

                        std::copy(_Data.begin() + start, _Data.begin() + ii, std::back_inserter(tel));

                        _serialelize(tel, (TextArea*)lastEl->element.get());

                        break;
                    }
                    ++ii;
                }

                if (ii == _Data.size()) {
                    throw excp[HTMLException::Error] << "Parsing error: Unclosed <svg tag.";
                }

                size_t close = ++ii;
                size_t lvl = 0;

                while(ii < _Data.size()){
                    if( (ii + 9) <= _Data.size() && std::equal(_Data.begin()+ii,_Data.begin()+(ii+9),"<textarea")){
                        ++lvl;
                    }

                    if( (ii + 10) <= _Data.size() && std::equal(_Data.begin()+ii,_Data.begin()+(ii+10),"</textarea")) {
                        if(lvl == 0){
                            std::copy(_Data.begin() + close, _Data.begin() + ii,
                                      std::back_inserter(static_cast<TextArea*>(lastEl->element.get())->_Text));

                            ii += 10;
                            break;
                ii+=TextArea::parseElement(_Data,lastEl->element,ii,lastEl->terminator);
            }else {
                            --lvl;
                        }
                    }
                    ++ii;
                }

                if (ii == _Data.size()) {
                    throw excp[HTMLException::Error] << "Parsing error: Missing </textarea closing tag.";
                }
            }else {
                size_t start=ii;
                    addelement(&lastEl);
                lastEl->element=std::make_unique<HtmlElement>();
                bool term=false;
                while(ii<_Data.size()){
                    if(!term && _Data[ii]==HTMLTAG_TERMINATE){
                        lastEl->terminator=true;
                    }else if(_Data[ii]==HTMLTAG_CLOSE) {
                        std::vector<char> tel;
                        std::copy(_Data.begin()+start,_Data.begin()+ii,std::back_inserter(tel));
                        _serialelize(tel,static_cast<HtmlElement*>(lastEl->element.get()));
                        break;
                    }
                    if(_Data[ii]!=' ' && _Data[ii]!=HTMLTAG_OPEN){
                        term=true;
                    }
                    ++ii;
                }
                    ii+=HtmlElement::parseElement(_Data,lastEl->element,ii,lastEl->terminator);
            }
        }else if(_Data[ii]!=' '){
            std::vector<char> buf;
            bool empty=true;
            while(ii<_Data.size()){
                switch(_Data[ii]){
                    case HTMLTAG_OPEN: {
                        if(!buf.empty()){
            addelement(&lastEl);
                            lastEl->element=std::make_unique<TextElement>();
                            std::copy(buf.begin(),buf.end(),std::back_inserter((static_cast<TextElement*>(lastEl->element.get()))->_Text));
                        }
                        goto BUILDTREE_STARTLOOP;
                    };
                    case '\r':{
                        ++ii;
                    }break;
                    case '\n':{
                        ++ii;
                    }break;
                    case ' ':{
                        if(!empty)
                            buf.push_back(_Data[ii++]);
                        else
                            ++ii;
                    }break;
                    default:{
                        buf.push_back(_Data[ii++]);
                        empty=false;
                    }break;
                }
            ii+=TextElement::parseElement(_Data,lastEl->element,ii,lastEl->terminator);
        }
    }
    }

    _buildtreenode(firstEl.get(),nullptr,_rootEl);
}
/**
@@ -615,95 +450,6 @@ std::ostream& operator<<(std::ostream& os, const libhtmlpp::HtmlString& p) {
    os << p.str();
    return os;
}
/**
 * @brief Extracts tag name and attributes from a token vector into an HtmlElement.
 * @param in Token buffer containing a single open tag.
 * @param out Destination HtmlElement to populate.
 * @throws HTMLException if no tag could be determined.
 */

void libhtmlpp::HtmlString::_serialelize(std::vector<char> in, libhtmlpp::HtmlElement *out) {
    size_t st=0,et=0;

    for (size_t i = 0; i < in.size(); ++i) {
        switch (in[i]) {
            case '<':
                continue;
            case '/':
                continue;
            case ' ':
                continue;
            default:
                st=i;
                goto GETTAGEND;
        }
    }

    GETTAGEND:
    for(et=st; et<in.size(); et++){
        if(in[et]==' ' || in[et]=='/' || in[et]=='>' || in[et]=='\r' || in[et]=='\n'){
            break;
        }
    }

    std::string tag;

    std::copy(in.begin()+st,in.begin()+et,std::back_inserter(tag));

    out->setTagname(tag);

    if (!out) {
        HTMLException excp;
        throw excp[HTMLException::Critical] << "no tag in element found!";
    }

    for(size_t i=et; i<in.size(); i++){
        if(in[i]=='>')
            return;
        size_t kstart=std::string::npos,kend=std::string::npos;
        if(in[i]!=' ' && in[i]!='\r' && in[i]!='\n'){
            kstart=i;
            kend=in.size();
            bool value=false;
            size_t vstart=std::string::npos,vend=std::string::npos;
            while(i<in.size()){
                if (in[i]=='='){
                    value=true;
                    kend=i++;
                    break;
                }
                ++i;
            }
            if(value){
                while(i<in.size()){
                    if(in[i]=='\"'){
                        if (vstart==std::string::npos){
                            vstart=++i;
                            continue;
                        }else{
                            vend=i;
                            break;
                        }
                    }
                    ++i;
                }
            }

            if(kstart !=std::string::npos){

                std::string key,val;

                std::copy(in.begin()+kstart,in.begin()+kend,std::back_inserter(key));

                if(vend!=std::string::npos && vstart!=std::string::npos){
                    std::copy(in.begin()+vstart,in.begin()+vend,std::back_inserter(val));
                }

                out->setAttribute(key,val);
            }
        }
    }
}

void libhtmlpp::HtmlEncode(const std::string &input, std::string &output){
    size_t ilen=input.length();
@@ -929,6 +675,116 @@ void libhtmlpp::HtmlElement::remove(libhtmlpp::Element* el){

}

/**
 * @brief Extracts tag name and attributes from a token vector into an HtmlElement.
 * @param in Token buffer containing a single open tag.
 * @param out Destination HtmlElement to populate.
 * @throws HTMLException if no tag could be determined.
 */

void libhtmlpp::HtmlElement::_serialelize(std::vector<char> in) {
    size_t st=0,et=0;

    for (size_t i = 0; i < in.size(); ++i) {
        switch (in[i]) {
            case '<':
                continue;
            case '/':
                continue;
            case ' ':
                continue;
            default:
                st=i;
                goto GETTAGEND;
        }
    }

    GETTAGEND:
    for(et=st; et<in.size(); et++){
        if(in[et]==' ' || in[et]=='/' || in[et]=='>' || in[et]=='\r' || in[et]=='\n'){
            break;
        }
    }

    std::string tag;

    std::copy(in.begin()+st,in.begin()+et,std::back_inserter(tag));

    setTagname(tag);

    if (_TagName.empty()) {
        HTMLException excp;
        throw excp[HTMLException::Critical] << "no tag in element found!";
    }

    for(size_t i=et; i<in.size(); i++){
        if(in[i]=='>')
            return;
        size_t kstart=std::string::npos,kend=std::string::npos;
        if(in[i]!=' ' && in[i]!='\r' && in[i]!='\n'){
            kstart=i;
            kend=in.size();
            bool value=false;
            size_t vstart=std::string::npos,vend=std::string::npos;
            while(i<in.size()){
                if (in[i]=='='){
                    value=true;
                    kend=i++;
                    break;
                }
                ++i;
            }
            if(value){
                while(i<in.size()){
                    if(in[i]=='\"'){
                        if (vstart==std::string::npos){
                            vstart=++i;
                            continue;
                        }else{
                            vend=i;
                            break;
                        }
                    }
                    ++i;
                }
            }

            if(kstart !=std::string::npos){

                std::string key,val;

                std::copy(in.begin()+kstart,in.begin()+kend,std::back_inserter(key));

                if(vend!=std::string::npos && vstart!=std::string::npos){
                    std::copy(in.begin()+vstart,in.begin()+vend,std::back_inserter(val));
                }

                setAttribute(key,val);
            }
        }
    }
}

size_t libhtmlpp::HtmlElement::parseElement(const std::vector<char> in, std::unique_ptr<libhtmlpp::Element>& el, size_t start,bool &termination){
    size_t startel=start;
    el=std::make_unique<HtmlElement>();
    bool term=false;
    while(start<in.size()){
        if(!term &&  in[start]==HTMLTAG_TERMINATE){
            termination=true;
        }else if(in[start]==HTMLTAG_CLOSE) {
            std::vector<char> tel;
            std::copy(in.begin()+startel,in.begin()+start,std::back_inserter(tel));
            reinterpret_cast<HtmlElement*>(el.get())->_serialelize(tel);
            return start;
        }
        if(in[start]!=' '){
            term=true;
        }
        ++start;
    }
    return start;
}

namespace libhtmlpp {

@@ -1275,6 +1131,39 @@ int libhtmlpp::TextElement::getType() const{
    return ElementType::TextEl;
}

size_t libhtmlpp::TextElement::parseElement(const std::vector<char> in, std::unique_ptr<libhtmlpp::Element>& el, size_t start,bool &termination){
    std::vector<char> buf;
    bool empty=true,end=false;
    while(start<in.size() && !end){
        switch(in[start]){
            case HTMLTAG_OPEN: {
                if(!buf.empty()){
                    el=std::make_unique<TextElement>();
                    std::copy(buf.begin(),buf.end(),std::back_inserter((static_cast<TextElement*>(el.get()))->_Text));
                }
                end=true;
                break;
            };
            case '\r':{
                ++start;
            }break;
            case '\n':{
                ++start;
            }break;
            case ' ':{
                if(!empty)
                    buf.push_back(in[start++]);
                else
                    ++start;
            }break;
            default:{
                buf.push_back(in[start++]);
                empty=false;
            }break;
        }
    }
    return start;
}

libhtmlpp::CommentElement::CommentElement() : Element(){
}
@@ -1310,6 +1199,29 @@ int libhtmlpp::CommentElement::getType() const{
    return ElementType::CommentEl;
}

size_t libhtmlpp::CommentElement::parseElement(const std::vector<char> in, std::unique_ptr<libhtmlpp::Element>& el, size_t start, bool& termination){
    size_t startel=start+3;
    while(start<in.size()){
        if(std::equal(in.begin()+start,in.begin()+(start+3),"-->")) {
            el=std::make_unique<CommentElement>();
            std::copy(in.begin()+startel,in.begin()+start,
                      std::back_inserter(static_cast<CommentElement*>(el.get())->_Comment));

            start+=2;

            break;
        }
        ++start;
    }

    if (start == in.size()) {
        HTMLException excp;
        throw excp[HTMLException::Error] << "Parsing error: Missing --> closing tag.";
    }

    return start;
}

libhtmlpp::ScriptElement::ScriptElement() : HtmlElement("script"){
}

@@ -1343,6 +1255,45 @@ int libhtmlpp::ScriptElement::getType() const{
    return ElementType::ScriptEL;
}

size_t libhtmlpp::ScriptElement::parseElement(const std::vector<char> in, std::unique_ptr<libhtmlpp::Element>& el, size_t start, bool& termination){
    size_t startel=start;

    while(start<in.size()){
        if(in[start]==HTMLTAG_CLOSE) {
            el=std::make_unique<ScriptElement>();
            std::vector<char> tel;

            std::copy(in.begin()+startel,in.begin()+start,std::back_inserter(tel));

            static_cast<ScriptElement*>(el.get())->_serialelize(tel);

            break;
        }
        ++start;
    }

    size_t close=++start;

    while(start<in.size()){
        if( std::equal(in.begin()+start,in.begin()+(start+7),"</script")) {

            std::copy(in.begin()+close,in.begin()+start,
                      std::back_inserter(static_cast<ScriptElement*>(el.get())->_Script));
            start+=8;
            break;
        }
        ++start;
    }

    if (start == in.size()) {
        HTMLException excp;
        throw excp[HTMLException::Error] << "Parsing error: Missing </script closing tag.";
    }

    return start;
}


libhtmlpp::SvgElement::SvgElement() : HtmlElement("svg"){
}

@@ -1377,6 +1328,44 @@ int libhtmlpp::SvgElement::getType() const{
    return ElementType::SvgEL;
}

size_t libhtmlpp::SvgElement::parseElement(const std::vector<char> in, std::unique_ptr<libhtmlpp::Element>& el, size_t start, bool& termination){
    size_t startel=start;

    while(start<in.size()){
        if(in[start]==HTMLTAG_CLOSE) {
            el=std::make_unique<SvgElement>();
            std::vector<char> tel;

            std::copy(in.begin()+startel,in.begin()+start,std::back_inserter(tel));

            static_cast<SvgElement*>(el.get())->_serialelize(tel);

            break;
        }
        ++start;
    }

    size_t close=++start;

    while(start<in.size()){
        if( std::equal(in.begin()+start,in.begin()+(start+4),"</svg")) {
            std::copy(in.begin()+close,in.begin()+start,
                      std::back_inserter(static_cast<SvgElement*>(el.get())->_Svg));
            start+=5;
            break;
        }
        ++start;
    }

    if (start == in.size()) {
        HTMLException excp;
        throw excp[HTMLException::Error] << "Parsing error: Missing </svg closing tag.";
    }

    return start;
}


libhtmlpp::TextArea::TextArea() : HtmlElement("svg"){
}

@@ -1411,6 +1400,57 @@ int libhtmlpp::TextArea::getType() const{
    return ElementType::TextAreaEL;
}

size_t libhtmlpp::TextArea::parseElement(const std::vector<char> in, std::unique_ptr<libhtmlpp::Element>& el,size_t start, bool& termination){
    size_t startel = start;
    while(start < in.size()){
        if(in[start] == HTMLTAG_CLOSE) {
            el = std::make_unique<TextArea>();
            std::vector<char> tel;

            std::copy(in.begin() + startel, in.begin() + start, std::back_inserter(tel));

            static_cast<TextArea*>(el.get())->_serialelize(tel);

            break;
        }
        ++start;
    }

    if (start == in.size()) {
        HTMLException excp;
        throw excp[HTMLException::Error] << "Parsing error: Unclosed <svg tag.";
    }

    size_t close = ++start;
    size_t lvl = 0;

    while(start < in.size()){
        if( (start + 9) <= in.size() && std::equal(in.begin()+start,in.begin()+(start+9),"<textarea")){
            ++lvl;
        }

        if( (start + 10) <= in.size() && std::equal(in.begin()+start,in.begin()+(start+10),"</textarea")) {
            if(lvl == 0){
                std::copy(in.begin() + close, in.begin() + start,
                          std::back_inserter(static_cast<TextArea*>(el.get())->_Text));

                start += 10;
                break;
            }else{
                --lvl;
            }
        }
        ++start;
    }

    if (start == in.size()) {
        HTMLException excp;
        throw excp[HTMLException::Error] << "Parsing error: Missing </textarea closing tag.";
    }

    return start;
}

libhtmlpp::HtmlPage::HtmlPage(){

}
@@ -1655,9 +1695,7 @@ void libhtmlpp::print(const Element &element, HtmlString &output,bool formated)
            }

            //Container must be always terminated fuck html5
            if(isContainer(static_cast<const HtmlElement*>(el)->getTagname()) &&
                !static_cast<const HtmlElement*>(el)->_childElement){

            if(isContainer(static_cast<const HtmlElement*>(el)->getTagname())){
                output.append("</");
                std::copy(
                    static_cast<const HtmlElement*>(el)->_TagName.begin(),
+11 −1
Original line number Diff line number Diff line
@@ -140,6 +140,8 @@ namespace libhtmlpp {

        int    getType() const;
        void   remove(Element* el);

        static size_t parseElement(const std::vector<char> in,std::unique_ptr<libhtmlpp::Element> &el,size_t start,bool &termination);
    protected:

        std::unique_ptr<Element>  _childElement=nullptr;
@@ -152,6 +154,7 @@ namespace libhtmlpp {
            std::unique_ptr<Attributes> _nextAttr;
        };

        void _serialelize(std::vector<char> in);
    private:
        //if text tagname must be zero
        std::vector<char> _TagName;
@@ -183,6 +186,9 @@ namespace libhtmlpp {
        void                       setText(const std::string &txt);

        int         getType() const;

        static size_t parseElement(const std::vector<char> in,std::unique_ptr<libhtmlpp::Element> &el,size_t start,bool &termination);

    protected:
        std::vector<char> _Text;
        friend class HtmlString;
@@ -206,6 +212,8 @@ namespace libhtmlpp {
        void        setComment(const std::string &txt);

        int         getType() const;

        static size_t parseElement(const std::vector<char> in,std::unique_ptr<libhtmlpp::Element> &el,size_t start,bool &termination);
    protected:
        std::vector<char> _Comment;
        friend class HtmlString;
@@ -235,6 +243,7 @@ namespace libhtmlpp {
        void         appendChild(const Element* el)=delete;
        void         appendChild(const Element& el)=delete;

        static size_t parseElement(const std::vector<char> in,std::unique_ptr<libhtmlpp::Element> &el,size_t start,bool &termination);
    protected:

        std::unique_ptr<Element> _childElement=nullptr;
@@ -267,6 +276,7 @@ namespace libhtmlpp {
        void         appendChild(const Element* el)=delete;
        void         appendChild(const Element& el)=delete;

        static size_t parseElement(const std::vector<char> in,std::unique_ptr<libhtmlpp::Element> &el,size_t start,bool &termination);
    protected:

        std::unique_ptr<Element> _childElement=nullptr;
@@ -300,6 +310,7 @@ namespace libhtmlpp {
        void         appendChild(const Element* el)=delete;
        void         appendChild(const Element& el)=delete;

        static size_t parseElement(const std::vector<char> in,std::unique_ptr<libhtmlpp::Element> &el,size_t start,bool &termination);
    protected:

        std::unique_ptr<Element> _childElement=nullptr;
@@ -372,7 +383,6 @@ namespace libhtmlpp {

    private:
        std::unique_ptr<Element> _rootEl;
        void                 _serialelize(std::vector<char> in, HtmlElement* out);
        void                 _buildTree();
        void _buildtreenode(DocElements *firstel,DocElements *lastel,std::unique_ptr<Element>&html);
        std::vector<char>    _Data;