VirtualBox

Ignore:
Timestamp:
Oct 1, 2013 2:14:13 AM (12 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
89417
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.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • 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.

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