VirtualBox

Changeset 48779 in vbox


Ignore:
Timestamp:
Oct 1, 2013 2:14:13 AM (11 years ago)
Author:
vboxsync
Message:

iprt/xml.h: Replaced std::list<shared_ptr<>> with RTList both to safe a bunch of heap allocations but more importantly to improve enumerability of the XML tree. Added some new methods too, both related to enumeration and to other things. Note: If we can get rid of the shared_ptr stuff with attributes we can jettison the boost dependency we have, AFAICT.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/iprt/cpp/xml.h

    r46169 r48779  
    3131#endif
    3232
     33/*#define USE_STD_LIST_FOR_CHILDREN*/
     34
     35#include <iprt/list.h>
     36#include <iprt/cpp/exception.h>
     37
    3338#include <list>
    3439#include <memory>
    3540
    36 #include <iprt/cpp/exception.h>
    3741
    3842/** @defgroup grp_rt_cpp_xml    C++ XML support
     
    381385
    382386/**
    383  * Node base class. Cannot be used directly, but ElementNode, ContentNode and
    384  * AttributeNode derive from this. This does implement useful public methods though.
     387 * Node base class.
     388 *
     389 * Cannot be used directly, but ElementNode, ContentNode and AttributeNode
     390 * derive from this.  This does implement useful public methods though.
     391 *
     392 *
    385393 */
    386394class RT_DECL_CLASS Node
     
    389397    ~Node();
    390398
    391     const char* getName() const;
    392     const char* getPrefix() const;
    393     const char* getNamespaceURI() const;
     399    const char *getName() const;
     400    const char *getPrefix() const;
     401    const char *getNamespaceURI() const;
    394402    bool nameEquals(const char *pcszNamespace, const char *pcsz) const;
    395403    bool nameEquals(const char *pcsz) const
     
    397405        return nameEquals(NULL, pcsz);
    398406    }
    399 
    400     const char* getValue() const;
     407    bool nameEqualsN(const char *pcszNamespace, const char *pcsz, size_t cchMax) const;
     408
     409    const char *getValue() const;
    401410    bool copyValue(int32_t &i) const;
    402411    bool copyValue(uint32_t &i) const;
     
    404413    bool copyValue(uint64_t &i) const;
    405414
     415    /** @name Introspection.
     416     * @{ */
     417    /** Is this an ElementNode instance.
     418     * @returns true / false  */
     419    bool isElement() const
     420    {
     421        return m_Type == IsElement;
     422    }
     423
     424    /** Is this an ContentNode instance.
     425     * @returns true / false  */
     426    bool isContent() const
     427    {
     428        return m_Type == IsContent;
     429    }
     430
     431    /** Is this an AttributeNode instance.
     432     * @returns true / false  */
     433    bool isAttribute() const
     434    {
     435        return m_Type == IsElement;
     436    }
     437
    406438    int getLineNumber() const;
    407439
    408     int isElement() const
    409     {
    410         return m_Type == IsElement;
    411     }
     440    /** @} */
     441
     442#ifndef USE_STD_LIST_FOR_CHILDREN
     443    /** @name General tree enumeration.
     444     *
     445     * Use the introspection methods isElement() and isContent() before doing static
     446     * casting.  Parents are always or ElementNode type, but siblings and children
     447     * can be of both ContentNode and ElementNode types.
     448     *
     449     * @remarks Careful mixing tree walking with node removal!
     450     * @{
     451     */
     452    /** Get the parent node
     453     * @returns Pointer to the parent node, or NULL if root. */
     454    const Node *getParent() const
     455    {
     456        return m_pParent;
     457    }
     458
     459    /** Get the first child node.
     460     * @returns Pointer to the first child node, NULL if no children. */
     461    const Node *getFirstChild() const
     462    {
     463        return RTListGetFirst(&m_children, const Node, m_childEntry);
     464    }
     465
     466    /** Get the last child node.
     467     * @returns Pointer to the last child node, NULL if no children. */
     468    const Node *getLastChild() const
     469    {
     470        return RTListGetLast(&m_children, const Node, m_childEntry);
     471    }
     472
     473    /** Get the previous sibling.
     474     * @returns Pointer to the previous sibling node, NULL if first child. */
     475    const Node *getPrevSibiling() const
     476    {
     477        if (!m_pParent)
     478            return NULL;
     479        return RTListGetPrev(&m_pParent->m_children, this, const Node, m_childEntry);
     480    }
     481
     482    /** Get the next sibling.
     483     * @returns Pointer to the next sibling node, NULL if last child. */
     484    const Node *getNextSibiling() const
     485    {
     486        if (!m_pParent)
     487            return NULL;
     488        return RTListGetNext(&m_pParent->m_children, this, const Node, m_childEntry);
     489    }
     490    /** @} */
     491#endif
    412492
    413493protected:
    414     typedef enum {IsElement, IsAttribute, IsContent} EnumType;
    415 
    416     EnumType    m_Type;
    417     Node        *m_pParent;
    418     xmlNode     *m_plibNode;            // != NULL if this is an element or content node
    419     xmlAttr     *m_plibAttr;            // != NULL if this is an attribute node
    420     const char  *m_pcszNamespacePrefix; // not always set
    421     const char  *m_pcszNamespaceHref;   // full http:// spec
    422     const char  *m_pcszName;            // element or attribute name, points either into plibNode or plibAttr;
    423                                         // NULL if this is a content node
     494    /** Node types. */
     495    typedef enum { IsElement, IsAttribute, IsContent } EnumType;
     496
     497    EnumType    m_Type;                 /**< The type of node this is an instance of. */
     498    Node       *m_pParent;              /**< The parent node, NULL if root. */
     499    xmlNode    *m_plibNode;            ///< != NULL if this is an element or content node
     500    xmlAttr    *m_plibAttr;            ///< != NULL if this is an attribute node
     501    const char *m_pcszNamespacePrefix; ///< not always set
     502    const char *m_pcszNamespaceHref;   ///< full http:// spec
     503    const char *m_pcszName;            ///< element or attribute name, points either into plibNode or plibAttr;
     504                                       ///< NULL if this is a content node
     505
     506#ifndef USE_STD_LIST_FOR_CHILDREN
     507    /** Child list entry of this node. (List head m_pParent->m_children.) */
     508    RTLISTNODE      m_childEntry;
     509    /** Child elements, if this is an element; can be empty. */
     510    RTLISTANCHOR    m_children;
     511#endif
    424512
    425513    // hide the default constructor so people use only our factory methods
     
    437525
    438526    friend class AttributeNode;
     527    friend class ElementNode; /* C list hack. */
    439528};
    440529
     
    465554    const ElementNode* findChildElementFromId(const char *pcszId) const;
    466555
     556    const ElementNode *findChildElementDeep(const char *pcszNamespace, const char *pcszPath) const;
     557    const ElementNode *findChildElementDeep(const char *pcszPath) const
     558    {
     559        return findChildElementDeep(NULL, pcszPath);
     560    }
     561
    467562    const AttributeNode* findAttribute(const char *pcszMatch) const;
    468     bool getAttributeValue(const char *pcszMatch, const char *&ppcsz) const;
     563    bool getAttributeValue(const char *pcszMatch, const char *&pcsz) const;
    469564    bool getAttributeValue(const char *pcszMatch, RTCString &str) const;
    470565    bool getAttributeValuePath(const char *pcszMatch, RTCString &str) const;
     
    474569    bool getAttributeValue(const char *pcszMatch, uint64_t &i) const;
    475570    bool getAttributeValue(const char *pcszMatch, bool &f) const;
     571
     572    /** @name Variants that for clarity does not use references for output params.
     573     * @{ */
     574    bool getAttributeValue(const char *pcszMatch, const char **ppcsz) const { return getAttributeValue(pcszMatch, *ppcsz); }
     575    bool getAttributeValue(const char *pcszMatch, RTCString *pStr) const    { return getAttributeValue(pcszMatch, *pStr); }
     576    bool getAttributeValuePath(const char *pcszMatch, RTCString *pStr) const { return getAttributeValuePath(pcszMatch, *pStr); }
     577    bool getAttributeValue(const char *pcszMatch, int32_t *pi) const        { return getAttributeValue(pcszMatch, *pi); }
     578    bool getAttributeValue(const char *pcszMatch, uint32_t *pu) const       { return getAttributeValue(pcszMatch, *pu); }
     579    bool getAttributeValue(const char *pcszMatch, int64_t *pi) const        { return getAttributeValue(pcszMatch, *pi); }
     580    bool getAttributeValue(const char *pcszMatch, uint64_t *pu) const       { return getAttributeValue(pcszMatch, *pu); }
     581    bool getAttributeValue(const char *pcszMatch, bool *pf) const           { return getAttributeValue(pcszMatch, *pf); }
     582    /** @} */
     583
    476584
    477585    ElementNode* createChild(const char *pcszElementName);
  • trunk/src/VBox/Runtime/r3/xml.cpp

    r46169 r48779  
    55
    66/*
    7  * Copyright (C) 2007-2012 Oracle Corporation
     7 * Copyright (C) 2007-2013 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    2525 */
    2626
     27
     28/*******************************************************************************
     29*   Header Files                                                               *
     30*******************************************************************************/
    2731#include <iprt/dir.h>
    2832#include <iprt/file.h>
     
    4347
    4448#include <map>
    45 #include <boost/shared_ptr.hpp>
    46 
    47 ////////////////////////////////////////////////////////////////////////////////
    48 //
    49 // globals
    50 //
    51 ////////////////////////////////////////////////////////////////////////////////
    52 
     49#include <boost/shared_ptr.hpp> /* This is the ONLY use of boost. */
     50
     51
     52/*******************************************************************************
     53*   Global Variables                                                           *
     54*******************************************************************************/
    5355/**
    5456 * Global module initialization structure. This is to wrap non-reentrant bits
     
    5961 * this structure.
    6062 */
    61 static
    62 class Global
     63static class Global
    6364{
    6465public:
     
    9495    }
    9596    sxml;  /* XXX naming this xml will break with gcc-3.3 */
    96 }
    97 gGlobal;
     97} gGlobal;
    9898
    9999
     
    132132 * returned string using RTStrFree() when no more necessary.
    133133 */
    134 // static
    135 char *XmlError::Format(xmlErrorPtr aErr)
     134/* static */ char *XmlError::Format(xmlErrorPtr aErr)
    136135{
    137136    const char *msg = aErr->message ? aErr->message : "<none>";
     
    443442    AttributesMap attribs;
    444443
     444#ifdef USE_STD_LIST_FOR_CHILDREN
    445445    // child elements, if this is an element; can be empty
    446446    typedef std::list< boost::shared_ptr<Node> > InternalNodesList;
    447447    InternalNodesList children;
     448#endif
    448449};
    449450
     
    452453           xmlNode *plibNode,
    453454           xmlAttr *plibAttr)
    454     : m_Type(type),
    455       m_pParent(pParent),
    456       m_plibNode(plibNode),
    457       m_plibAttr(plibAttr),
    458       m_pcszNamespacePrefix(NULL),
    459       m_pcszNamespaceHref(NULL),
    460       m_pcszName(NULL),
    461       m(new Data)
    462 {
     455    : m_Type(type)
     456    , m_pParent(pParent)
     457    , m_plibNode(plibNode)
     458    , m_plibAttr(plibAttr)
     459    , m_pcszNamespacePrefix(NULL)
     460    , m_pcszNamespaceHref(NULL)
     461    , m_pcszName(NULL)
     462    , m(new Data)
     463{
     464#ifndef USE_STD_LIST_FOR_CHILDREN
     465    RTListInit(&m_childEntry);
     466    RTListInit(&m_children);
     467#endif
    463468}
    464469
    465470Node::~Node()
    466471{
     472#ifndef USE_STD_LIST_FOR_CHILDREN
     473    Node *pCur, *pNext;
     474    RTListForEachSafe(&m_children, pCur, pNext, Node, m_childEntry)
     475    {
     476        delete pCur;
     477    }
     478    RTListInit(&m_children);
     479#endif
    467480    delete m;
    468481}
     
    487500
    488501    // go thru this element's child elements
    489     xmlNodePtr plibNode = m_plibNode->children;
    490     while (plibNode)
    491     {
     502    for (xmlNodePtr plibNode = m_plibNode->children; plibNode; plibNode = plibNode->next)
     503    {
     504#ifndef USE_STD_LIST_FOR_CHILDREN
     505        Node *pNew;
     506        if (plibNode->type == XML_ELEMENT_NODE)
     507            pNew = new ElementNode(&elmRoot, this, plibNode);
     508        else if (plibNode->type == XML_TEXT_NODE)
     509            pNew = new ContentNode(this, plibNode);
     510        else
     511            continue;
     512        RTListAppend(&m_children, &pNew->m_childEntry);
     513
     514        /* Recurse for this child element to get its own children. */
     515        pNew->buildChildren(elmRoot);
     516#else
    492517        boost::shared_ptr<Node> pNew;
    493518
     
    504529            pNew->buildChildren(elmRoot);
    505530        }
    506 
    507         plibNode = plibNode->next;
     531#endif
    508532    }
    509533}
     
    567591
    568592/**
     593 * Variant of nameEquals that checks the namespace as well.
     594 *
     595 * @return  true if equal, false if not.
     596 * @param   pcszNamespace   The name space prefix or NULL.
     597 * @param   pcsz            The element name.
     598 * @param   cchMax          The maximum number of character from @a pcsz to
     599 *                          match.
     600 */
     601bool Node::nameEqualsN(const char *pcszNamespace, const char *pcsz, size_t cchMax) const
     602{
     603    /* Match the name. */
     604    if (!m_pcszName)
     605        return false;
     606    if (!pcsz || cchMax == 0)
     607        return false;
     608    if (strncmp(m_pcszName, pcsz, cchMax))
     609        return false;
     610    if (strlen(m_pcszName) > cchMax)
     611        return false;
     612
     613    /* Match name space. */
     614    if (!pcszNamespace)
     615        return true;    /* NULL, anything goes. */
     616    if (!m_pcszNamespacePrefix)
     617        return false;   /* Element has no namespace. */
     618    return !strcmp(m_pcszNamespacePrefix, pcszNamespace);
     619}
     620
     621/**
    569622 * Returns the value of a node. If this node is an attribute, returns
    570623 * the attribute value; if this node is an element, then this returns
     
    572625 * @return
    573626 */
    574 const char* Node::getValue() const
    575 {
    576     if (    (m_plibAttr)
    577          && (m_plibAttr->children)
    578        )
     627const char *Node::getValue() const
     628{
     629    if (   m_plibAttr
     630        && m_plibAttr->children
     631        )
    579632        // libxml hides attribute values in another node created as a
    580633        // single child of the attribute node, and it's in the content field
    581         return (const char*)m_plibAttr->children->content;
    582 
    583     if (    (m_plibNode)
    584          && (m_plibNode->children)
    585        )
    586         return (const char*)m_plibNode->children->content;
     634        return (const char *)m_plibAttr->children->content;
     635
     636    if (   m_plibNode
     637        && m_plibNode->children)
     638        return (const char *)m_plibNode->children->content;
    587639
    588640    return NULL;
     
    710762{
    711763    int i = 0;
     764#ifndef USE_STD_LIST_FOR_CHILDREN
     765    Node *p;
     766    RTListForEach(&m_children, p, Node, m_childEntry)
     767#else
    712768    for (Data::InternalNodesList::iterator it = m->children.begin();
    713769         it != m->children.end();
    714770         ++it)
     771#endif
    715772    {
    716773        // export this child node if ...
     774#ifdef USE_STD_LIST_FOR_CHILDREN
    717775        Node *p = it->get();
     776#endif
    718777        if (p->isElement())
    719             if (    (!pcszMatch)    // the caller wants all nodes or
    720                  || (!strcmp(pcszMatch, p->getName())) // the element name matches
     778            if (   !pcszMatch                       // ... the caller wants all nodes or ...
     779                || !strcmp(pcszMatch, p->getName()) // ... the element name matches.
    721780               )
    722781            {
    723                 children.push_back(static_cast<ElementNode*>(p));
     782                children.push_back(static_cast<ElementNode *>(p));
    724783                ++i;
    725784            }
     
    735794 * @return
    736795 */
    737 const ElementNode* ElementNode::findChildElement(const char *pcszNamespace,
    738                                                  const char *pcszMatch)
    739     const
    740 {
     796const ElementNode *ElementNode::findChildElement(const char *pcszNamespace, const char *pcszMatch) const
     797{
     798#ifndef USE_STD_LIST_FOR_CHILDREN
     799    Node *p;
     800    RTListForEach(&m_children, p, Node, m_childEntry)
     801    {
     802        if (p->isElement())
     803        {
     804            ElementNode *pelm = static_cast<ElementNode*>(p);
     805            if (pelm->nameEquals(pcszNamespace, pcszMatch))
     806                return pelm;
     807        }
     808    }
     809#else
    741810    Data::InternalNodesList::const_iterator
    742811        it,
    743812        last = m->children.end();
    744     for (it = m->children.begin();
    745          it != last;
    746          ++it)
    747     {
     813    for (it = m->children.begin(); it != last; ++it)
    748814        if ((**it).isElement())
    749815        {
     
    752818                return pelm;
    753819        }
    754     }
     820#endif
    755821
    756822    return NULL;
     
    762828 * @return child element or NULL if not found.
    763829 */
    764 const ElementNode* ElementNode::findChildElementFromId(const char *pcszId) const
    765 {
     830const ElementNode * ElementNode::findChildElementFromId(const char *pcszId) const
     831{
     832#ifndef USE_STD_LIST_FOR_CHILDREN
     833    Node *p;
     834    RTListForEach(&m_children, p, Node, m_childEntry)
     835    {
     836        if (p->isElement())
     837        {
     838            ElementNode *pelm = static_cast<ElementNode*>(p);
     839            const AttributeNode *pAttr = pelm->findAttribute("id");
     840            if (pAttr && !strcmp(pAttr->getValue(), pcszId))
     841                return pelm;
     842        }
     843    }
     844#else
    766845    Data::InternalNodesList::const_iterator
    767846        it,
     
    781860        }
    782861    }
     862#endif
     863    return NULL;
     864}
     865
     866/**
     867 * Recursively find the first matching child element.
     868 *
     869 * @returns child element or NULL if not found.
     870 * @param   pcszNamespace   The Namespace prefix or NULL.
     871 * @param   pcszPath        Simple element path, with parent and child elements
     872 *                          separated by a forward slash ('/').
     873 */
     874const ElementNode *ElementNode::findChildElementDeep(const char *pcszNamespace, const char *pcszPath) const
     875{
     876    size_t cchThis = strchr(pcszPath, '/') - pcszPath;
     877    if (cchThis == (const char *)0 - pcszPath)
     878        return this->findChildElement(pcszNamespace, pcszPath);
     879
     880#ifndef USE_STD_LIST_FOR_CHILDREN
     881    /** @todo Can be done without recursion as we have both sibling lists and parent
     882     *        pointers in this variant.  */
     883    Node *p;
     884    RTListForEach(&m_children, p, Node, m_childEntry)
     885    {
     886        if (p->isElement())
     887        {
     888            const ElementNode *pElm = static_cast<ElementNode*>(p);
     889            if (pElm->nameEqualsN(pcszNamespace, pcszPath, cchThis))
     890            {
     891                pElm = findChildElementDeep(pcszNamespace, pcszPath + cchThis);
     892                if (pElm)
     893                    return pElm;
     894            }
     895        }
     896    }
     897#else
     898    Data::InternalNodesList::const_iterator  itLast = m->children.end();
     899    for (Data::InternalNodesList::const_iterator it = m->children.begin(); it != itLast; ++it)
     900    {
     901        if ((**it).isElement())
     902        {
     903            const ElementNode *pElm = static_cast<ElementNode*>((*it).get());
     904            if (pElm->nameEqualsN(pcszNamespace, pcszPath, cchThis))
     905            {
     906                pElm = findChildElementDeep(pcszNamespace, pcszPath + cchThis);
     907                if (pElm)
     908                    return pElm;
     909            }
     910        }
     911    }
     912#endif
    783913
    784914    return NULL;
     
    10011131 * @return
    10021132 */
    1003 ElementNode* ElementNode::createChild(const char *pcszElementName)
     1133ElementNode *ElementNode::createChild(const char *pcszElementName)
    10041134{
    10051135    // we must be an element, not an attribute
     
    10161146    // now wrap this in C++
    10171147    ElementNode *p = new ElementNode(m_pelmRoot, this, plibNode);
     1148#ifndef USE_STD_LIST_FOR_CHILDREN
     1149    RTListAppend(&m_children, &p->m_childEntry);
     1150#else
    10181151    boost::shared_ptr<ElementNode> pNew(p);
    10191152    m->children.push_back(pNew);
     1153#endif
    10201154
    10211155    return p;
     
    10301164 * @return
    10311165 */
    1032 ContentNode* ElementNode::addContent(const char *pcszContent)
     1166ContentNode *ElementNode::addContent(const char *pcszContent)
    10331167{
    10341168    // libxml side: create new node
    1035     xmlNode *plibNode;
    1036     if (!(plibNode = xmlNewText((const xmlChar*)pcszContent)))
     1169    xmlNode *plibNode = xmlNewText((const xmlChar*)pcszContent);
     1170    if (!plibNode)
    10371171        throw std::bad_alloc();
    10381172    xmlAddChild(m_plibNode, plibNode);
     
    10401174    // now wrap this in C++
    10411175    ContentNode *p = new ContentNode(this, plibNode);
     1176#ifndef USE_STD_LIST_FOR_CHILDREN
     1177    RTListAppend(&m_children, &p->m_childEntry);
     1178#else
    10421179    boost::shared_ptr<ContentNode> pNew(p);
    10431180    m->children.push_back(pNew);
     1181#endif
    10441182
    10451183    return p;
     
    15011639 * The document that is passed in will be reset before being filled if not empty.
    15021640 *
    1503  * @param pvBuf in: memory buffer to parse.
    1504  * @param cbSize in: size of the memory buffer.
    1505  * @param strFilename in: name fo file to parse.
    1506  * @param doc out: document to be reset and filled with data according to file contents.
    1507  */
    1508 void XmlMemParser::read(const void* pvBuf, size_t cbSize,
     1641 * @param pvBuf         Memory buffer to parse.
     1642 * @param cbSize        Size of the memory buffer.
     1643 * @param strFilename   Refernece to the name of the file we're parsing.
     1644 * @param doc           Reference to the output document.  This will be reset
     1645 *                      and filled with data according to file contents.
     1646 */
     1647void XmlMemParser::read(const void *pvBuf, size_t cbSize,
    15091648                        const RTCString &strFilename,
    15101649                        Document &doc)
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette