LCOV - code coverage report
Current view: top level - ezlibs - ezXml.hpp (source / functions) Coverage Total Hit
Test: Coverage (llvm-cov → lcov → genhtml) Lines: 70.4 % 371 261
Test Date: 2025-09-16 22:55:37 Functions: 68.8 % 48 33
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 85.4 % 96 82

             Branch data     Line data    Source code
       1                 :             : #pragma once
       2                 :             : 
       3                 :             : /*
       4                 :             : MIT License
       5                 :             : 
       6                 :             : Copyright (c) 2014-2024 Stephane Cuillerdier (aka aiekick)
       7                 :             : 
       8                 :             : Permission is hereby granted, free of charge, to any person obtaining a copy
       9                 :             : of this software and associated documentation files (the "Software"), to deal
      10                 :             : in the Software without restriction, including without limitation the rights
      11                 :             : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      12                 :             : copies of the Software, and to permit persons to whom the Software is
      13                 :             : furnished to do so, subject to the following conditions:
      14                 :             : 
      15                 :             : The above copyright notice and this permission notice shall be included in all
      16                 :             : copies or substantial portions of the Software.
      17                 :             : 
      18                 :             : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      19                 :             : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      20                 :             : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      21                 :             : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      22                 :             : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      23                 :             : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
      24                 :             : SOFTWARE.
      25                 :             : */
      26                 :             : 
      27                 :             : // ezXml is part of the ezLibs project : https://github.com/aiekick/ezLibs.git
      28                 :             : // ezXml is part of the ezLibs project : https://github.com/aiekick/ezLibs.git
      29                 :             : 
      30                 :             : #include <map>
      31                 :             : #include <stack>
      32                 :             : #include <string>
      33                 :             : #include <vector>
      34                 :             : #include <cstdint>
      35                 :             : #include <cassert>
      36                 :             : #include <sstream>
      37                 :             : #include <ostream>
      38                 :             : #include <fstream>
      39                 :             : 
      40                 :             : namespace ez {
      41                 :             :     class Xml;
      42                 :             : 
      43                 :             :     namespace xml {
      44                 :             : 
      45                 :             :         class Node;
      46                 :             : 
      47                 :             :         typedef std::vector<Node> Nodes;
      48                 :             : 
      49                 :             :         class Node {
      50                 :             :             friend class ez::Xml;
      51                 :             : 
      52                 :             :         public:
      53                 :             :             enum class Type {
      54                 :             :                 None = 0,
      55                 :             :                 Token,
      56                 :             :                 Comment
      57                 :             :             };
      58                 :             : 
      59                 :             :             class Attribute {
      60                 :             :             private:
      61                 :             :                 std::string m_value;
      62                 :             :             public:
      63                 :          24 :                 Attribute() = default;
      64                 :             : 
      65                 :          24 :                 explicit Attribute(const std::string &vValue) : m_value(vValue) {}
      66                 :             : 
      67                 :             :                 template<typename T>
      68                 :           0 :                 Attribute &operator<<(const T &vValue) {
      69                 :           0 :                     std::ostringstream vOut;
      70                 :           0 :                     vOut << vValue;
      71                 :           0 :                     m_value = vOut.str();
      72                 :           0 :                     return *this;
      73                 :           0 :                 }
      74                 :             : 
      75                 :          24 :                 friend std::ostream& operator<<(std::ostream& os, const Attribute& attr) {
      76                 :          24 :                     os << attr.m_value;
      77                 :          24 :                     return os;
      78                 :          24 :                 }
      79                 :             : 
      80                 :          24 :                 const std::string& getValue() const {
      81                 :          24 :                     return m_value;
      82                 :          24 :                 }
      83                 :             :             };
      84                 :             : 
      85                 :             :         private:
      86                 :             :             std::string m_name;
      87                 :             :             std::map<std::string, Attribute> m_attributes;
      88                 :             :             std::string m_content;
      89                 :             :             std::string m_parentNodeName;
      90                 :             :             Nodes m_children;
      91                 :             :             Type m_type = Type::None;
      92                 :             : 
      93                 :             :         public:
      94                 :          52 :             static std::string escapeXml(const std::string &vDatas) {
      95                 :          52 :                 std::string escaped = vDatas;
      96                 :          52 :                 replaceAll(escaped, "&", "&amp;");
      97                 :          52 :                 replaceAll(escaped, "<", "&lt;");
      98                 :          52 :                 replaceAll(escaped, "\"", "&quot;");
      99                 :          52 :                 replaceAll(escaped, "'", "&apos;");
     100                 :          52 :                 replaceAll(escaped, ">", "&gt;");
     101                 :          52 :                 return escaped;
     102                 :          52 :             }
     103                 :             : 
     104                 :             :             // replace xml excaped pattern by corresponding good pattern
     105                 :          46 :             static std::string unEscapeXml(const std::string &vDatas) {
     106                 :          46 :                 std::string unescaped = vDatas;
     107                 :          46 :                 replaceAll(unescaped, "&lt;", "<");
     108                 :          46 :                 replaceAll(unescaped, "&amp;", "&");
     109                 :          46 :                 replaceAll(unescaped, "&quot;", "\"");
     110                 :          46 :                 replaceAll(unescaped, "&apos;", "'");
     111                 :          46 :                 replaceAll(unescaped, "&gt;", ">");
     112                 :          46 :                 return unescaped;
     113                 :          46 :             }
     114                 :             : 
     115                 :         490 :             static void replaceAll(std::string &vStr, const std::string &vFrom, const std::string &vTo) {
     116         [ -  + ]:         490 :                 if (vFrom.empty()) return;
     117                 :         490 :                 size_t startPos = 0;
     118         [ +  + ]:         522 :                 while ((startPos = vStr.find(vFrom, startPos)) != std::string::npos) {
     119                 :          32 :                     vStr.replace(startPos, vFrom.length(), vTo);
     120                 :          32 :                     startPos += vTo.length();
     121                 :          32 :                 }
     122                 :         490 :             }
     123                 :             : 
     124                 :             :         public:
     125                 :          42 :             Node(const std::string &vName = "") : m_name(vName) {
     126                 :          42 :             }
     127                 :             : 
     128                 :           0 :             Node &setName(const std::string &vName) {
     129                 :           0 :                 m_name = vName;
     130                 :           0 :                 return *this;
     131                 :           0 :             }
     132                 :             : 
     133                 :          34 :             Node &addChild(const Node &vChild) {
     134                 :          34 :                 m_children.push_back(vChild);
     135                 :          34 :                 m_children.back().m_setParentNodeName(getName());
     136                 :          34 :                 return m_children.back();
     137                 :          34 :             }
     138                 :             : 
     139                 :           0 :             Node &addChild(const std::string &vName) {
     140                 :           0 :                 Node node(vName);
     141                 :           0 :                 return addChild(node);
     142                 :           0 :             }
     143                 :             : 
     144                 :           0 :             Node &addComment(const std::string &vComment) {
     145                 :           0 :                 Node node;
     146                 :           0 :                 node.setContent(vComment).m_setType(Type::Comment);
     147                 :           0 :                 return addChild(node);
     148                 :           0 :             }
     149                 :             : 
     150                 :           0 :             Node *getChild(const std::string &vName) {
     151                 :           0 :                 for (auto &child: m_children) {
     152                 :           0 :                     if (child.m_name == vName) {
     153                 :           0 :                         return &child;
     154                 :           0 :                     }
     155                 :           0 :                 }
     156                 :           0 :                 return nullptr;
     157                 :           0 :             }
     158                 :             : 
     159                 :           0 :             Node &getOrAddChild(const std::string &vName) {
     160                 :           0 :                 Node *ret = getChild(vName);
     161                 :           0 :                 if (ret == nullptr) {
     162                 :           0 :                     ret = &addChild(vName);
     163                 :           0 :                 }
     164                 :           0 :                 return *ret;
     165                 :           0 :             }
     166                 :             : 
     167                 :           0 :             Node &addChilds(const Nodes &vChilds) {
     168                 :           0 :                 for (const auto &node: vChilds) {
     169                 :           0 :                     addChild(node);
     170                 :           0 :                 }
     171                 :           0 :                 return *this;
     172                 :           0 :             }
     173                 :             :             template<typename T>
     174                 :           0 :             Node& addAttribute(const std::string& vKey, const T& vValue) {
     175                 :           0 :                 std::stringstream ss;
     176                 :           0 :                 ss << vValue;
     177                 :           0 :                 m_attributes[vKey] = Attribute(ss.str());
     178                 :           0 :                 return *this;
     179                 :           0 :             }
     180                 :             : 
     181                 :           0 :             Attribute& addAttribute(const std::string& vKey) {
     182                 :           0 :                 m_attributes[vKey] = Attribute();
     183                 :           0 :                 return m_attributes[vKey];
     184                 :           0 :             }
     185                 :             : 
     186                 :           1 :             bool isAttributeExist(const std::string &vKey) const {
     187                 :           1 :                 return (m_attributes.find(vKey) != m_attributes.end());
     188                 :           1 :             }
     189                 :             : 
     190                 :             :             template<typename T = std::string>
     191                 :          23 :             T getAttribute(const std::string &vKey) const {
     192                 :          23 :                 T ret;
     193                 :          23 :                 std::stringstream ss;
     194                 :          23 :                 auto it = m_attributes.find(vKey);
     195 [ +  - ][ +  - ]:          23 :                 if (it != m_attributes.end()) {
     196                 :          23 :                     ss << it->second;
     197                 :          23 :                 }
     198                 :          23 :                 ss >> ret;
     199                 :          23 :                 return ret;
     200                 :          23 :             }
     201                 :             : 
     202                 :             :             template<typename T>
     203                 :           0 :             Node &setContent(const T &vContent) {
     204                 :           0 :                 std::stringstream ss;
     205                 :           0 :                 ss << vContent;
     206                 :           0 :                 m_content = ss.str();
     207                 :           0 :                 return *this;
     208                 :           0 :             }
     209                 :             : 
     210                 :          14 :             Node &setContent(const std::string &vContent) {
     211                 :          14 :                 m_content = escapeXml(vContent);
     212                 :          14 :                 return *this;
     213                 :          14 :             }
     214                 :             : 
     215                 :             :             // specific case for std::string
     216                 :             :             template <typename T = std::string>
     217                 :          46 :             typename std::enable_if<std::is_same<T, std::string>::value, T>::type getContent() const {
     218                 :          46 :                 return unEscapeXml(m_content);
     219                 :          46 :             }
     220                 :             : 
     221                 :             :             // specific case for bool
     222                 :             :             template <typename T>
     223                 :           2 :             typename std::enable_if<std::is_same<T, bool>::value, T>::type getContent() const {
     224                 :           2 :                 return (m_content == "true");
     225                 :           2 :             }
     226                 :             : 
     227                 :             :             // general cases (exclude std::string and bool)
     228                 :             :             template <typename T>
     229                 :             :             typename std::enable_if<!std::is_same<T, std::string>::value && !std::is_same<T, bool>::value, T>::type getContent() const {
     230                 :             :                 T ret;
     231                 :             :                 std::stringstream ss;
     232                 :             :                 ss << m_content;
     233                 :             :                 ss >> ret;
     234                 :             :                 return ret;
     235                 :             :             }
     236                 :             : 
     237                 :          22 :             Nodes &getChildren() { return m_children; }
     238                 :             : 
     239                 :          46 :             const Nodes &getChildren() const { return m_children; }
     240                 :             : 
     241                 :           1 :             const std::string &getParentNodeName() const {
     242                 :           1 :                 return m_parentNodeName;
     243                 :           1 :             }
     244                 :             : 
     245                 :         108 :             const std::string &getName() const {
     246                 :         108 :                 return m_name;
     247                 :         108 :             }
     248                 :             : 
     249                 :          40 :             std::string dump(const xml::Node &vNode, const uint32_t vLevel = 0) const {
     250                 :          40 :                 std::string indent(vLevel * 2, ' ');  // Indentation based on the depth level
     251                 :          40 :                 std::ostringstream oss;
     252                 :             : 
     253                 :          40 :                 oss << indent;
     254         [ +  + ]:          40 :                 if (vNode.m_getType() != xml::Node::Type::Comment) {
     255                 :          36 :                     oss << "<" << vNode.getName();
     256         [ +  + ]:          36 :                     for (const auto &attr: vNode.m_attributes) {
     257                 :          24 :                         oss << " " << attr.first << "=\"" << xml::Node::escapeXml(attr.second.getValue()) << "\"";
     258                 :          24 :                     }
     259                 :          36 :                 } else {
     260                 :           4 :                     oss << "<!-- ";
     261                 :           4 :                 }
     262                 :             : 
     263                 :          40 :                 const auto &content = vNode.getContent();
     264                 :          40 :                 const auto &children = vNode.getChildren();
     265                 :             : 
     266 [ +  + ][ +  + ]:          40 :                 if (content.empty() && children.empty()) {
     267                 :          16 :                     oss << "/>" << std::endl;
     268                 :          24 :                 } else {
     269         [ +  + ]:          24 :                     if (vNode.m_getType() != xml::Node::Type::Comment) {
     270                 :          20 :                         oss << ">";
     271                 :          20 :                     }
     272         [ +  + ]:          24 :                     if (!content.empty()) {
     273                 :          14 :                         oss << xml::Node::escapeXml(content);
     274                 :          14 :                     }
     275         [ +  + ]:          24 :                     if (vNode.m_getType() == xml::Node::Type::Comment) {
     276                 :           4 :                         oss << " -->" << std::endl;
     277                 :           4 :                     }
     278         [ +  + ]:          24 :                     if (!children.empty()) {
     279                 :          14 :                         oss << std::endl;
     280         [ +  + ]:          34 :                         for (const auto &child: children) {
     281                 :          34 :                             oss << dump(child, vLevel + 1);
     282                 :          34 :                         }
     283                 :          14 :                         oss << indent;
     284                 :          14 :                     }
     285         [ +  + ]:          24 :                     if (vNode.m_getType() != xml::Node::Type::Comment) {
     286                 :          20 :                         oss << "</" << vNode.getName() << ">" << std::endl;
     287                 :          20 :                     }
     288                 :          24 :                 }
     289                 :             : 
     290                 :          40 :                 return oss.str();
     291                 :          40 :             }
     292                 :             : 
     293                 :           6 :             std::string dump() const {
     294                 :           6 :                 return dump(*this);
     295                 :           6 :             }
     296                 :             : 
     297                 :             :         private:
     298                 :             : 
     299                 :          24 :             void m_setAttribute(const std::string &vKey, const std::string &vValue) {
     300                 :          24 :                 m_attributes[vKey] = Attribute(vValue);
     301                 :          24 :             }
     302                 :             : 
     303                 :          40 :             void m_setType(Type vType) {
     304                 :          40 :                 m_type = vType;
     305                 :          40 :             }
     306                 :             : 
     307                 :         112 :             Type m_getType() const {
     308                 :         112 :                 return m_type;
     309                 :         112 :             }
     310                 :             : 
     311                 :          34 :             void m_setParentNodeName(const std::string &vName) {
     312                 :          34 :                 m_parentNodeName = vName;
     313                 :          34 :             }
     314                 :             :         };
     315                 :             : 
     316                 :             :         template <>
     317                 :           0 :         inline Node &Node::setContent(const bool &vContent) {
     318                 :           0 :             m_content = vContent ? "true" : "false";
     319                 :           0 :             return *this;
     320                 :           0 :         }
     321                 :             : 
     322                 :             : #if __cplusplus >= 201703L  // c++17
     323                 :             :         template <>
     324                 :             :         inline bool Node::getContent<bool>() const {
     325                 :             :             return (m_content == "true");
     326                 :             :         }
     327                 :             : #endif
     328                 :             : 
     329                 :             :     }  // namespace xml
     330                 :             : 
     331                 :             :     class Xml {
     332                 :             :     private:
     333                 :             :         xml::Node m_Root;
     334                 :             :         // just during parsing,
     335                 :             :         // for know what is the current node
     336                 :             :         std::stack<xml::Node *> m_NodeStack;
     337                 :             :         enum class TokenType {  //
     338                 :             :             OPENED = 0,
     339                 :             :             CLOSED,
     340                 :             :             OPENED_CLOSED,
     341                 :             :             COMMENT,
     342                 :             :             CONTENT,
     343                 :             :             Count
     344                 :             :         };
     345                 :             : 
     346                 :             :     public:
     347                 :           6 :         Xml(const std::string &vRootName = "root") : m_Root(vRootName) {
     348                 :           6 :             m_NodeStack.push(&m_Root);
     349                 :           6 :         }
     350                 :             : 
     351                 :           4 :         xml::Node &getRoot() {
     352                 :           4 :             return m_Root;
     353                 :           4 :         }
     354                 :             : 
     355                 :           0 :         bool parseFile(const std::string &vFilePathName) {
     356                 :           0 :             std::ifstream docFile(vFilePathName, std::ios::in);
     357                 :           0 :             if (docFile.is_open()) {
     358                 :           0 :                 std::stringstream strStream;
     359                 :           0 :                 strStream << docFile.rdbuf();  // read the file
     360                 :           0 :                 auto xml_content = strStream.str();
     361                 :           0 :                 m_replaceString(xml_content, "\r\n", "\n");
     362                 :           0 :                 m_replaceString(xml_content, "\r", "\n");
     363                 :           0 :                 docFile.close();
     364                 :           0 :                 return parseString(xml_content);
     365                 :           0 :             }
     366                 :           0 :             return false;
     367                 :           0 :         }
     368                 :             : 
     369                 :           6 :         bool parseString(const std::string &vDoc) {
     370                 :           6 :             auto tokens = m_tokenize(vDoc);
     371         [ -  + ]:           6 :             if (tokens.empty()) {
     372                 :           0 :                 return false;
     373                 :           0 :             }
     374         [ +  + ]:         100 :             for (const auto &token: tokens) {
     375                 :         100 :                 std::string tagName;
     376                 :         100 :                 std::map<std::string, std::string> attributes;
     377         [ -  + ]:         100 :                 if (token.first.empty()) {
     378                 :           0 :                     continue;
     379                 :           0 :                 }
     380         [ +  + ]:         100 :                 if (token.second == TokenType::CLOSED) {
     381                 :          12 :                     m_NodeStack.pop();
     382         [ +  + ]:          88 :                 } else if (token.second == TokenType::OPENED ||         //
     383         [ +  + ]:          88 :                            token.second == TokenType::OPENED_CLOSED ||  //
     384         [ +  + ]:          88 :                            token.second == TokenType::COMMENT) {
     385         [ +  + ]:          36 :                     if (token.second != TokenType::COMMENT) {
     386                 :          32 :                         tagName = m_extractTagName(token.first);
     387                 :          32 :                     }
     388                 :          36 :                     xml::Node newNode(tagName);
     389                 :          36 :                     newNode.m_setType(xml::Node::Type::Token);
     390         [ +  + ]:          36 :                     if (token.second == TokenType::COMMENT) {
     391                 :           4 :                         newNode.m_setType(xml::Node::Type::Comment);
     392                 :           4 :                         newNode.setContent(token.first);
     393                 :          32 :                     } else {
     394         [ +  + ]:          32 :                         if (!m_extractAttributes(tagName, token.first, attributes)) {
     395                 :           2 :                             return false;
     396                 :           2 :                         }
     397         [ +  + ]:          30 :                         for (const auto &kv: attributes) {
     398                 :          24 :                             newNode.m_setAttribute(kv.first, kv.second);
     399                 :          24 :                         }
     400                 :          30 :                     }
     401                 :          34 :                     m_NodeStack.top()->addChild(newNode);
     402         [ +  + ]:          34 :                     if (token.second == TokenType::OPENED) {
     403                 :          18 :                         m_NodeStack.push(const_cast<xml::Node *>(&m_NodeStack.top()->getChildren().back()));
     404                 :          18 :                     }
     405         [ +  - ]:          52 :                 } else if (token.second == TokenType::CONTENT) {
     406         [ +  - ]:          52 :                     if (!m_NodeStack.empty()) {
     407         [ +  + ]:          52 :                         if (token.first[0] != '\n') {
     408                 :          10 :                             m_NodeStack.top()->setContent(token.first);
     409                 :          10 :                         }
     410                 :          52 :                     }
     411                 :          52 :                 }
     412                 :         100 :             }
     413                 :           4 :             return true;
     414                 :           6 :         }
     415                 :             : 
     416                 :           6 :         std::string dump() const {
     417                 :           6 :             return m_Root.dump();
     418                 :           6 :         }
     419                 :             : 
     420                 :             :     private:
     421                 :           0 :         bool m_replaceString(std::string &str, const std::string &oldStr, const std::string &newStr) {
     422                 :           0 :             bool found = false;
     423                 :           0 :             size_t pos = 0;
     424                 :           0 :             while ((pos = str.find(oldStr, pos)) != std::string::npos) {
     425                 :           0 :                 found = true;
     426                 :           0 :                 str.replace(pos, oldStr.length(), newStr);
     427                 :           0 :                 pos += newStr.length();
     428                 :           0 :             }
     429                 :           0 :             return found;
     430                 :           0 :         }
     431                 :             : 
     432                 :           6 :         std::vector<std::pair<std::string, TokenType>> m_tokenize(const std::string &vDoc) {
     433                 :           6 :             std::vector<std::pair<std::string, TokenType>> tokens;
     434                 :           6 :             size_t pos = 0;
     435                 :           6 :             size_t length = vDoc.length();
     436                 :           6 :             TokenType type = TokenType::Count;
     437         [ +  + ]:         112 :             while (pos < length) {
     438         [ +  + ]:         106 :                 if (vDoc[pos] == '<') {
     439                 :          50 :                     type = TokenType::OPENED;
     440         [ +  + ]:          50 :                     if (vDoc[pos + 1] == '/') {
     441                 :          14 :                         type = TokenType::CLOSED;
     442         [ +  + ]:          36 :                     } else if (vDoc[pos + 1] == '!') {
     443                 :           4 :                         type = TokenType::COMMENT;
     444                 :           4 :                     }
     445                 :          50 :                     size_t end = vDoc.find(">", pos);
     446         [ -  + ]:          50 :                     if (end == std::string::npos) {
     447                 :           0 :                         break;
     448                 :           0 :                     }
     449         [ +  + ]:          50 :                     if (vDoc[end - 1] == '/') {
     450                 :          14 :                         type = TokenType::OPENED_CLOSED;
     451                 :          14 :                     }
     452                 :          50 :                     const auto ss = vDoc.substr(pos, end + 1 - pos);
     453                 :          50 :                     tokens.push_back(std::make_pair(ss, type));
     454                 :          50 :                     pos = end + 1;
     455                 :          56 :                 } else {
     456                 :          56 :                     size_t end = vDoc.find('<', pos);
     457                 :          56 :                     const auto ss = vDoc.substr(pos, end - pos);
     458                 :          56 :                     tokens.push_back(std::make_pair(ss, TokenType::CONTENT));
     459                 :          56 :                     pos = end;
     460                 :          56 :                 }
     461                 :         106 :             }
     462                 :           6 :             return tokens;
     463                 :           6 :         }
     464                 :             : 
     465                 :          32 :         std::string m_extractTagName(const std::string &vLine) {
     466                 :          32 :             std::string ret;
     467                 :          32 :             size_t startPos = vLine.find('<') + 1;
     468 [ +  + ][ +  - ]:          34 :             while (vLine.at(startPos) == ' ' && vLine.size() > startPos) {
     469                 :           2 :                 ++startPos;
     470                 :           2 :             }
     471                 :          32 :             size_t endPos = vLine.find_first_of(" \t/>", startPos);
     472                 :          32 :             return vLine.substr(startPos, endPos - startPos);
     473                 :          32 :         }
     474                 :             : 
     475                 :             :         // will remove space outside of <> and ""
     476                 :           0 :         std::string m_trim1(const std::string &vToken) {
     477                 :           0 :             std::string res;
     478                 :           0 :             int32_t scope = 0;
     479                 :           0 :             for (const auto c: vToken) {
     480                 :           0 :                 if (scope == 1) {
     481                 :           0 :                     res += c;
     482                 :           0 :                 } else if (c == '"') {
     483                 :           0 :                     if (scope == 0) {
     484                 :           0 :                         ++scope;
     485                 :           0 :                     } else {
     486                 :           0 :                         --scope;
     487                 :           0 :                     }
     488                 :           0 :                 }
     489                 :           0 :             }
     490                 :           0 :             return res;
     491                 :           0 :         }
     492                 :             : 
     493                 :             :         // will remove spaces from start and from end
     494                 :             :         // if the token is like tk0 tk1 tk2, only tk0 will be returned
     495                 :          28 :         std::string m_trim2(const std::string &vToken) {
     496                 :          28 :             std::string res;
     497         [ +  + ]:         144 :             for (const auto c: vToken) {
     498         [ +  + ]:         144 :                 if (c != ' ') {
     499                 :         140 :                     res += c;
     500         [ +  - ]:         140 :                 } else if (!res.empty()) {
     501                 :           4 :                     break;
     502                 :           4 :                 }
     503                 :         144 :             }
     504                 :          28 :             return res;
     505                 :          28 :         }
     506                 :             : 
     507                 :             :         bool m_extractAttributes(const std::string &vTagName, const std::string &vLine,
     508                 :          32 :                                  std::map<std::string, std::string> &attributes) {
     509                 :          32 :             size_t startPos = vLine.find(vTagName);
     510         [ +  - ]:          32 :             if (startPos != std::string::npos) {
     511                 :          32 :                 startPos += vTagName.size();
     512                 :          32 :                 startPos = vLine.find(' ', startPos);
     513         [ +  + ]:          58 :                 while (startPos != std::string::npos) {
     514                 :          30 :                     startPos = vLine.find_first_not_of(" \t", startPos);
     515         [ +  + ]:          30 :                     if (vLine.at(startPos) == '>') {
     516                 :           2 :                         break;
     517                 :           2 :                     }
     518                 :          28 :                     size_t equalsPos = vLine.find('=', startPos);
     519         [ -  + ]:          28 :                     if (equalsPos == std::string::npos) {
     520                 :           0 :                         return false;
     521                 :           0 :                     }
     522                 :          28 :                     std::string key = m_trim2(vLine.substr(startPos, equalsPos - startPos));
     523                 :          28 :                     startPos = equalsPos + 1;
     524                 :          28 :                     char quoteChar = vLine[startPos];
     525         [ +  + ]:          32 :                     while (quoteChar == ' ') {
     526                 :           4 :                         quoteChar = vLine[++startPos];
     527                 :           4 :                     }
     528 [ +  + ][ -  + ]:          28 :                     if (quoteChar == '"' || quoteChar == '\'') {
     529                 :          26 :                         startPos++;
     530                 :          26 :                         size_t endPos = vLine.find(quoteChar, startPos);
     531         [ +  - ]:          26 :                         if (endPos != std::string::npos) {
     532                 :          26 :                             std::string value = vLine.substr(startPos, endPos - startPos);
     533                 :          26 :                             attributes[key] = value;
     534                 :          26 :                             startPos = vLine.find(' ', endPos);  // Passer ? l'attribut suivant
     535                 :          26 :                         } else {
     536                 :             : #ifdef LogVarError
     537                 :             :                             LogVarError("The attribut '%s' have invalid value", key.c_str());
     538                 :             : #endif
     539                 :           0 :                             return false;  // Erreur : guillemets/apostrophes non ferm?s
     540                 :           0 :                         }
     541                 :          26 :                     } else {
     542                 :             : #ifdef LogVarError
     543                 :             :                         LogVarError("The attribut '%s' have invalid value", key.c_str());
     544                 :             : #endif
     545                 :           2 :                         return false;  // Erreur : attribut sans guillemets ou apostrophes
     546                 :           2 :                     }
     547                 :          28 :                 }
     548                 :          30 :                 return true;
     549                 :          32 :             }
     550                 :           0 :             return false;
     551                 :          32 :         }
     552                 :             :     };
     553                 :             : 
     554                 :             : }  // namespace ez
        

Generated by: LCOV version 2.0-1