Changeset 63 for trunk/src/helpers/xml.c


Ignore:
Timestamp:
Apr 25, 2001, 8:55:35 PM (24 years ago)
Author:
umoeller
Message:

Misc. fixes.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/helpers/xml.c

    r54 r63  
    142142/* ******************************************************************
    143143 *
    144  *   Generic methods
     144 *   Error handling
    145145 *
    146146 ********************************************************************/
    147 
    148 /*
    149  *@@ CompareNodeBaseNodes:
    150  *      tree comparison func for NodeBases.
    151  *      This works for all trees which contain structures
    152  *      whose first item is a _NODEBASE because NODEBASE's first
    153  *      member is a TREE.
    154  *
    155  *      Used in two places:
    156  *
    157  *      --  to insert _CMELEMENTDECLNODE nodes into
    158  *          _DOMDOCTYPENODE.ElementDeclsTree;
    159  *
    160  *      --  to insert _CMELEMENTPARTICLE nodes into
    161  *          _CMELEMENTDECLNODE.ElementNamesTree.
    162  *
    163  *@@added V0.9.9 (2001-02-16) [umoeller]
    164  */
    165 
    166 int TREEENTRY CompareNodeBaseNodes(TREE *t1,
    167                                   TREE *t2)
    168 {
    169     PNODEBASE   p1 = (PNODEBASE)t1,
    170                 p2 = (PNODEBASE)t2;
    171     return (strhcmp(p1->strNodeName.psz, p2->strNodeName.psz));
    172 }
    173 
    174 /*
    175  *@@ CompareNodeBaseNodes:
    176  *      tree comparison func for element declarations.
    177  *      Used to find nodes in _DOMDOCTYPENODE.ElementDeclsTree.
    178  *
    179  *@@added V0.9.9 (2001-02-16) [umoeller]
    180  */
    181 
    182 int TREEENTRY CompareNodeBaseData(TREE *t1,
    183                                  void *pData)
    184 {
    185     PNODEBASE     p1 = (PNODEBASE)t1;
    186     return (strhcmp(p1->strNodeName.psz, (const char*)pData));
    187 }
    188 
    189 /*
    190  *@@ xmlCreateNodeBase:
    191  *      creates a new NODEBASE node.
    192  *
    193  *      Gets called from xmlCreateDomNode also to create
    194  *      a DOMNODE, since that in turn has a NODEBASE.
    195  *
    196  *@@added V0.9.9 (2001-02-16) [umoeller]
    197  */
    198 
    199 APIRET xmlCreateNodeBase(NODEBASETYPE ulNodeType,     // in: node type
    200                          ULONG cb,                    // in: size of struct
    201                          const char *pcszNodeName,    // in: node name or NULL
    202                          ULONG ulNodeNameLength,      // in: node name length
    203                                                       // or 0 to run strlen(pcszNodeName)
    204                          PNODEBASE *ppNew)            // out: new node
    205 {
    206     APIRET      arc = NO_ERROR;
    207     PNODEBASE   pNewNode = (PNODEBASE)malloc(cb);
    208 
    209     if (!pNewNode)
    210         arc = ERROR_NOT_ENOUGH_MEMORY;
    211     else
    212     {
    213         memset(pNewNode, 0, cb);
    214         pNewNode->ulNodeType = ulNodeType;
    215 
    216         xstrInit(&pNewNode->strNodeName, 0);
    217         if (pcszNodeName)
    218             xstrcpy(&pNewNode->strNodeName,
    219                     pcszNodeName,
    220                     ulNodeNameLength);  // if 0, xstrcpy will do strlen()
    221 
    222 
    223         *ppNew = pNewNode;
    224     }
    225 
    226     return (arc);
    227 }
    228 
    229 /*
    230  *@@ xmlDeleteNode:
    231  *      deletes a NODEBASE and frees memory that was
    232  *      associated with its members.
    233  *
    234  *      NOTE: If you call this for derived types, call
    235  *      this LAST, after you have cleared additional
    236  *      members. After calling this, pNode is no longer
    237  *      valid.
    238  *
    239  *@@added V0.9.9 (2001-02-16) [umoeller]
    240  */
    241 
    242 VOID xmlDeleteNode(PNODEBASE pNode)
    243 {
    244     if (pNode)
    245     {
    246         PLISTNODE   pNodeThis;
    247         PDOMNODE    pDomNode = NULL;
    248 
    249         LINKLIST    llDeleteNodes;          // list that nodes to be deleted
    250                                             // can be appended to
    251         PLISTNODE   pDelNode;
    252         lstInit(&llDeleteNodes, FALSE);
    253 
    254         // now handle special types and their allocations
    255         switch (pNode->ulNodeType)
    256         {
    257             case DOMNODE_ELEMENT:
    258             {
    259                 PDOMNODE pAttrib;
    260 
    261                 pDomNode = (PDOMNODE)pNode;
    262 
    263                 // delete all attribute nodes
    264                 pAttrib = (PDOMNODE)treeFirst(pDomNode->AttributesMap);
    265                 while (pAttrib)
    266                 {
    267                     // call delete recursively
    268                     xmlDeleteNode((PNODEBASE)pAttrib);
    269                             // this will remove pAttrib from pNode's attrib
    270                             // tree and rebalance the tree; treeNext will
    271                             // still work #### noooooo
    272                     pAttrib = (PDOMNODE)treeNext((TREE*)pAttrib);
    273                 }
    274             break; }
    275 
    276             case DOMNODE_ATTRIBUTE:
    277             case DOMNODE_TEXT:
    278             case DOMNODE_PROCESSING_INSTRUCTION:
    279             case DOMNODE_COMMENT:
    280             case DOMNODE_DOCUMENT:
    281                 pDomNode = (PDOMNODE)pNode;
    282             break;
    283 
    284             case DOMNODE_DOCUMENT_TYPE:
    285             {
    286                 PDOMDOCTYPENODE pDocType = (PDOMDOCTYPENODE)pNode;
    287                 PCMELEMENTDECLNODE pElDecl;
    288                 PCMATTRIBUTEDECLBASE pAttrDeclBase;
    289 
    290                 pDomNode = (PDOMNODE)pNode;
    291 
    292                 pElDecl = (PCMELEMENTDECLNODE)treeFirst(pDocType->ElementDeclsTree);
    293                 while (pElDecl)
    294                 {
    295                     lstAppendItem(&llDeleteNodes, pElDecl);
    296                     pElDecl = (PCMELEMENTDECLNODE)treeNext((TREE*)pElDecl);
    297                 }
    298 
    299                 pAttrDeclBase = (PCMATTRIBUTEDECLBASE)treeFirst(pDocType->AttribDeclBasesTree);
    300                 while (pAttrDeclBase)
    301                 {
    302                     lstAppendItem(&llDeleteNodes, pAttrDeclBase);
    303                     pAttrDeclBase = (PCMATTRIBUTEDECLBASE)treeNext((TREE*)pAttrDeclBase);
    304                 }
    305 
    306                 xstrClear(&pDocType->strPublicID);
    307                 xstrClear(&pDocType->strSystemID);
    308             break; }
    309 
    310             case ELEMENTPARTICLE_EMPTY:
    311             case ELEMENTPARTICLE_ANY:
    312             case ELEMENTPARTICLE_MIXED:
    313             case ELEMENTPARTICLE_CHOICE:
    314             case ELEMENTPARTICLE_SEQ:
    315             case ELEMENTPARTICLE_NAME:
    316             {
    317                 PCMELEMENTPARTICLE pp = (PCMELEMENTPARTICLE)pNode;
    318                 if (pp->pllSubNodes)
    319                 {
    320                     pDelNode = lstQueryFirstNode(pp->pllSubNodes);
    321                     while (pDelNode)
    322                     {
    323                         PCMELEMENTPARTICLE
    324                                 pParticle = (PCMELEMENTPARTICLE)pDelNode->pItemData;
    325                         xmlDeleteNode((PNODEBASE)pParticle);
    326                         //  treeDelete(pp->         ###
    327                         pDelNode = pDelNode->pNext;
    328                     }
    329                 }
    330             break; }
    331 
    332             // case ATTRIBUTE_DECLARATION_ENUM:     // this is a plain NODEBASE
    333 
    334             case ATTRIBUTE_DECLARATION:
    335             {
    336                 PCMATTRIBUTEDECL pDecl = (PCMATTRIBUTEDECL)pNode;
    337             break; }
    338 
    339             case ATTRIBUTE_DECLARATION_BASE:
    340             break;
    341         }
    342 
    343         if (pDomNode)
    344         {
    345             // recurse into child nodes
    346             while (pNodeThis = lstQueryFirstNode(&pDomNode->llChildren))
    347                 // recurse!!
    348                 xmlDeleteNode((PNODEBASE)(pNodeThis->pItemData));
    349                             // this updates llChildren
    350 
    351             if (pDomNode->pParentNode)
    352             {
    353                 // node has a parent:
    354                 if (pNode->ulNodeType == DOMNODE_ATTRIBUTE)
    355                     // this is an attribute:
    356                     // remove from parent's attributes map
    357                     treeDelete(&pDomNode->pParentNode->AttributesMap,
    358                                (TREE*)pNode);
    359                 else
    360                     // remove this node from the parent's list
    361                     // of child nodes before deleting this node
    362                     lstRemoveItem(&pDomNode->pParentNode->llChildren,
    363                                   pNode);
    364 
    365                 pDomNode->pParentNode = NULL;
    366             }
    367 
    368             xstrFree(pDomNode->pstrNodeValue);
    369             lstClear(&pDomNode->llChildren);
    370         }
    371 
    372         pDelNode = lstQueryFirstNode(&llDeleteNodes);
    373         while (pDelNode)
    374         {
    375             PNODEBASE pNodeBase = (PNODEBASE)pDelNode->pItemData;
    376             xmlDeleteNode(pNodeBase);
    377             pDelNode = pDelNode->pNext;
    378         }
    379 
    380         lstClear(&llDeleteNodes);
    381 
    382         xstrClear(&pNode->strNodeName);
    383         free(pNode);
    384     }
    385 }
    386 
    387 /*
    388  *@@ xmlCreateDomNode:
    389  *      creates a new DOMNODE with the specified
    390  *      type and parent. Other than that, the
    391  *      node fields are zeroed.
    392  *
    393  *      If pParentNode is specified (which is required,
    394  *      unless you are creating a document node),
    395  *      its children list is automatically updated
    396  *      (unless this is an attribute node, which updates
    397  *      the attributes map).
    398  *
    399  *      This returns the following errors:
    400  *
    401  *      --  ERROR_NOT_ENOUGH_MEMORY
    402  *
    403  *      --  ERROR_DOM_NOT_SUPPORTED: invalid ulNodeType
    404  *          specified.
    405  *
    406  *      --  ERROR_DOM_WRONG_DOCUMENT: cannot find the
    407  *          document for this node. This happens if you do
    408  *          not have a document node at the root of your tree.
    409  */
    410 
    411 APIRET xmlCreateDomNode(PDOMNODE pParentNode,        // in: parent node or NULL if root
    412                         NODEBASETYPE ulNodeType,     // in: DOMNODE_* type
    413                         const char *pcszNodeName,    // in: node name or NULL
    414                         ULONG ulNodeNameLength,      // in: node name length
    415                                                      // or 0 to run strlen(pcszNodeName)
    416                         PDOMNODE *ppNew)             // out: new node
    417 {
    418     PDOMNODE pNewNode = NULL;
    419     APIRET  arc = NO_ERROR;
    420 
    421     ULONG   cb = 0;
    422 
    423     switch (ulNodeType)
    424     {
    425         case DOMNODE_DOCUMENT:
    426             cb = sizeof(DOMDOCUMENTNODE);
    427         break;
    428 
    429         case DOMNODE_DOCUMENT_TYPE:
    430             cb = sizeof(DOMDOCTYPENODE);
    431         break;
    432 
    433         default:
    434             cb = sizeof(DOMNODE);
    435         break;
    436     }
    437 
    438     arc = xmlCreateNodeBase(ulNodeType,
    439                             cb,
    440                             pcszNodeName,
    441                             ulNodeNameLength,
    442                             (PNODEBASE*)&pNewNode);
    443     if (arc == NO_ERROR)
    444     {
    445         pNewNode->pParentNode = pParentNode;
    446 
    447         if (pParentNode)
    448         {
    449             // parent specified:
    450             // check if this is an attribute
    451             if (ulNodeType == DOMNODE_ATTRIBUTE)
    452             {
    453                 // attribute:
    454                 // add to parent's attributes list
    455                 if (treeInsertNode(&pParentNode->AttributesMap,
    456                                    &pNewNode->NodeBase.Tree,
    457                                    CompareNodeBaseNodes,
    458                                    FALSE)      // no duplicates
    459                         == TREE_DUPLICATE)
    460                     arc = ERROR_DOM_DUPLICATE_ATTRIBUTE;
    461                                 // shouldn't happen, because expat takes care of this
    462             }
    463             else
    464                 // append this new node to the parent's
    465                 // list of child nodes
    466                 lstAppendItem(&pParentNode->llChildren,
    467                               pNewNode);
    468 
    469             if (!arc)
    470             {
    471                 // set document pointer...
    472                 // if the parent node has a document pointer,
    473                 // we can copy that
    474                 if (pParentNode->pDocumentNode)
    475                     pNewNode->pDocumentNode = pParentNode->pDocumentNode;
    476                 else
    477                     // parent has no document pointer: then it is probably
    478                     // the document itself... check
    479                     if (pParentNode->NodeBase.ulNodeType == DOMNODE_DOCUMENT)
    480                         pNewNode->pDocumentNode = pParentNode;
    481                     else
    482                         arc = ERROR_DOM_NO_DOCUMENT;
    483             }
    484         }
    485 
    486         lstInit(&pNewNode->llChildren, FALSE);
    487         treeInit(&pNewNode->AttributesMap);
    488     }
    489 
    490     if (!arc)
    491         *ppNew = pNewNode;
    492     else
    493         if (pNewNode)
    494             free(pNewNode);
    495 
    496     return (arc);
    497 }
    498 
    499 /*
    500  *@@ xmlGetFirstChild:
    501  *      returns the first child node of pDomNode.
    502  *      See _DOMNODE for what a "child" can be for the
    503  *      various node types.
    504  *
    505  *@@added V0.9.9 (2001-02-14) [umoeller]
    506  */
    507 
    508 PDOMNODE xmlGetFirstChild(PDOMNODE pDomNode)
    509 {
    510     PLISTNODE pListNode = lstQueryFirstNode(&pDomNode->llChildren);
    511     if (pListNode)
    512         return ((PDOMNODE)pListNode->pItemData);
    513 
    514     return (0);
    515 }
    516 
    517 /*
    518  *@@ xmlGetLastChild:
    519  *      returns the last child node of pDomNode.
    520  *      See _DOMNODE for what a "child" can be for the
    521  *      various node types.
    522  *
    523  *@@added V0.9.9 (2001-02-14) [umoeller]
    524  */
    525 
    526 PDOMNODE xmlGetLastChild(PDOMNODE pDomNode)
    527 {
    528     PLISTNODE pListNode = lstQueryLastNode(&pDomNode->llChildren);
    529     if (pListNode)
    530         return ((PDOMNODE)pListNode->pItemData);
    531 
    532     return (0);
    533 }
    534147
    535148/*
     
    584197        "Invalid attribute value",
    585198        "Required attribute is missing",
    586         "Subelement in empty element"
     199        "Subelement in empty element",
     200
     201        "Parsing error",
     202        "Validity error",
     203
     204        "DOM node type not supported",
     205        "No DOM document",
     206        "No DOM element",
     207        "Duplicate doctype",
     208        "Root element doesn't match doctype name",
     209        "DOM integrity error",
     210        "Duplicate attribute",
     211
     212        "Validation error: Undeclared element name",
     213        "Element declaration outside doctype",
     214        "Attlist declaration outside doctype"
    587215    };
    588216
     
    630258/* ******************************************************************
    631259 *
    632  *   Specific DOM node methods
     260 *   Most basic node management
     261 *
     262 ********************************************************************/
     263
     264/*
     265 *@@ CompareNodeBaseNodes:
     266 *      tree comparison func for NodeBases.
     267 *      This works for all trees which contain structures
     268 *      whose first item is a _NODEBASE because NODEBASE's first
     269 *      member is a TREE.
     270 *
     271 *      Used in two places:
     272 *
     273 *      --  to insert _CMELEMENTDECLNODE nodes into
     274 *          _DOMDOCTYPENODE.ElementDeclsTree;
     275 *
     276 *      --  to insert _CMELEMENTPARTICLE nodes into
     277 *          _CMELEMENTDECLNODE.ElementNamesTree.
     278 *
     279 *@@added V0.9.9 (2001-02-16) [umoeller]
     280 */
     281
     282int TREEENTRY CompareNodeBaseNodes(TREE *t1,
     283                                  TREE *t2)
     284{
     285    PNODEBASE   p1 = (PNODEBASE)t1,
     286                p2 = (PNODEBASE)t2;
     287    return (strhcmp(p1->strNodeName.psz, p2->strNodeName.psz));
     288}
     289
     290/*
     291 *@@ CompareNodeBaseNodes:
     292 *      tree comparison func for element declarations.
     293 *      Used to find nodes in _DOMDOCTYPENODE.ElementDeclsTree.
     294 *
     295 *@@added V0.9.9 (2001-02-16) [umoeller]
     296 */
     297
     298int TREEENTRY CompareNodeBaseData(TREE *t1,
     299                                 void *pData)
     300{
     301    PNODEBASE     p1 = (PNODEBASE)t1;
     302    return (strhcmp(p1->strNodeName.psz, (const char*)pData));
     303}
     304
     305/*
     306 *@@ xmlCreateNodeBase:
     307 *      creates a new NODEBASE node.
     308 *
     309 *      Gets called from xmlCreateDomNode also to create
     310 *      a DOMNODE, since that in turn has a NODEBASE.
     311 *
     312 *@@added V0.9.9 (2001-02-16) [umoeller]
     313 */
     314
     315APIRET xmlCreateNodeBase(NODEBASETYPE ulNodeType,     // in: node type
     316                         ULONG cb,                    // in: size of struct
     317                         const char *pcszNodeName,    // in: node name or NULL
     318                         ULONG ulNodeNameLength,      // in: node name length
     319                                                      // or 0 to run strlen(pcszNodeName)
     320                         PNODEBASE *ppNew)            // out: new node
     321{
     322    APIRET      arc = NO_ERROR;
     323    PNODEBASE   pNewNode = (PNODEBASE)malloc(cb);
     324
     325    if (!pNewNode)
     326        arc = ERROR_NOT_ENOUGH_MEMORY;
     327    else
     328    {
     329        memset(pNewNode, 0, cb);
     330        pNewNode->ulNodeType = ulNodeType;
     331
     332        xstrInit(&pNewNode->strNodeName, 0);
     333        if (pcszNodeName)
     334            xstrcpy(&pNewNode->strNodeName,
     335                    pcszNodeName,
     336                    ulNodeNameLength);  // if 0, xstrcpy will do strlen()
     337
     338
     339        *ppNew = pNewNode;
     340    }
     341
     342    return (arc);
     343}
     344
     345/*
     346 *@@ xmlDeleteNode:
     347 *      deletes a NODEBASE and frees memory that was
     348 *      associated with its members.
     349 *
     350 *      NOTE: If you call this for derived types, call
     351 *      this LAST, after you have cleared additional
     352 *      members. After calling this, pNode is no longer
     353 *      valid.
     354 *
     355 *@@added V0.9.9 (2001-02-16) [umoeller]
     356 */
     357
     358VOID xmlDeleteNode(PNODEBASE pNode)
     359{
     360    if (pNode)
     361    {
     362        PLISTNODE   pNodeThis;
     363        PDOMNODE    pDomNode = NULL;
     364
     365        LINKLIST    llDeleteNodes;          // list that nodes to be deleted
     366                                            // can be appended to
     367        PLISTNODE   pDelNode;
     368        lstInit(&llDeleteNodes, FALSE);
     369
     370        // now handle special types and their allocations
     371        switch (pNode->ulNodeType)
     372        {
     373            case DOMNODE_ELEMENT:
     374            {
     375                PDOMNODE pAttrib;
     376
     377                pDomNode = (PDOMNODE)pNode;
     378
     379                // delete all attribute nodes
     380                pAttrib = (PDOMNODE)treeFirst(pDomNode->AttributesMap);
     381                while (pAttrib)
     382                {
     383                    // call delete recursively
     384                    xmlDeleteNode((PNODEBASE)pAttrib);
     385                            // this will remove pAttrib from pNode's attrib
     386                            // tree and rebalance the tree; treeNext will
     387                            // still work #### noooooo
     388                    pAttrib = (PDOMNODE)treeNext((TREE*)pAttrib);
     389                }
     390            break; }
     391
     392            case DOMNODE_ATTRIBUTE:
     393            case DOMNODE_TEXT:
     394            case DOMNODE_PROCESSING_INSTRUCTION:
     395            case DOMNODE_COMMENT:
     396            case DOMNODE_DOCUMENT:
     397                pDomNode = (PDOMNODE)pNode;
     398            break;
     399
     400            case DOMNODE_DOCUMENT_TYPE:
     401            {
     402                PDOMDOCTYPENODE pDocType = (PDOMDOCTYPENODE)pNode;
     403                PCMELEMENTDECLNODE pElDecl;
     404                PCMATTRIBUTEDECLBASE pAttrDeclBase;
     405
     406                pDomNode = (PDOMNODE)pNode;
     407
     408                pElDecl = (PCMELEMENTDECLNODE)treeFirst(pDocType->ElementDeclsTree);
     409                while (pElDecl)
     410                {
     411                    lstAppendItem(&llDeleteNodes, pElDecl);
     412                    pElDecl = (PCMELEMENTDECLNODE)treeNext((TREE*)pElDecl);
     413                }
     414
     415                pAttrDeclBase = (PCMATTRIBUTEDECLBASE)treeFirst(pDocType->AttribDeclBasesTree);
     416                while (pAttrDeclBase)
     417                {
     418                    lstAppendItem(&llDeleteNodes, pAttrDeclBase);
     419                    pAttrDeclBase = (PCMATTRIBUTEDECLBASE)treeNext((TREE*)pAttrDeclBase);
     420                }
     421
     422                xstrClear(&pDocType->strPublicID);
     423                xstrClear(&pDocType->strSystemID);
     424            break; }
     425
     426            case ELEMENTPARTICLE_EMPTY:
     427            case ELEMENTPARTICLE_ANY:
     428            case ELEMENTPARTICLE_MIXED:
     429            case ELEMENTPARTICLE_CHOICE:
     430            case ELEMENTPARTICLE_SEQ:
     431            case ELEMENTPARTICLE_NAME:
     432            {
     433                PCMELEMENTPARTICLE pp = (PCMELEMENTPARTICLE)pNode;
     434                if (pp->pllSubNodes)
     435                {
     436                    pDelNode = lstQueryFirstNode(pp->pllSubNodes);
     437                    while (pDelNode)
     438                    {
     439                        PCMELEMENTPARTICLE
     440                                pParticle = (PCMELEMENTPARTICLE)pDelNode->pItemData;
     441                        xmlDeleteNode((PNODEBASE)pParticle);
     442                        //  treeDelete(pp->         ###
     443                        pDelNode = pDelNode->pNext;
     444                    }
     445                }
     446            break; }
     447
     448            // case ATTRIBUTE_DECLARATION_ENUM:     // this is a plain NODEBASE
     449
     450            case ATTRIBUTE_DECLARATION:
     451            {
     452                PCMATTRIBUTEDECL pDecl = (PCMATTRIBUTEDECL)pNode;
     453            break; }
     454
     455            case ATTRIBUTE_DECLARATION_BASE:
     456            break;
     457        }
     458
     459        if (pDomNode)
     460        {
     461            // recurse into child nodes
     462            while (pNodeThis = lstQueryFirstNode(&pDomNode->llChildren))
     463                // recurse!!
     464                xmlDeleteNode((PNODEBASE)(pNodeThis->pItemData));
     465                            // this updates llChildren
     466
     467            if (pDomNode->pParentNode)
     468            {
     469                // node has a parent:
     470                if (pNode->ulNodeType == DOMNODE_ATTRIBUTE)
     471                    // this is an attribute:
     472                    // remove from parent's attributes map
     473                    treeDelete(&pDomNode->pParentNode->AttributesMap,
     474                               (TREE*)pNode);
     475                else
     476                    // remove this node from the parent's list
     477                    // of child nodes before deleting this node
     478                    lstRemoveItem(&pDomNode->pParentNode->llChildren,
     479                                  pNode);
     480
     481                pDomNode->pParentNode = NULL;
     482            }
     483
     484            xstrFree(pDomNode->pstrNodeValue);
     485            lstClear(&pDomNode->llChildren);
     486        }
     487
     488        pDelNode = lstQueryFirstNode(&llDeleteNodes);
     489        while (pDelNode)
     490        {
     491            PNODEBASE pNodeBase = (PNODEBASE)pDelNode->pItemData;
     492            xmlDeleteNode(pNodeBase);
     493            pDelNode = pDelNode->pNext;
     494        }
     495
     496        lstClear(&llDeleteNodes);
     497
     498        xstrClear(&pNode->strNodeName);
     499        free(pNode);
     500    }
     501}
     502
     503/*
     504 *@@ xmlCreateDomNode:
     505 *      creates a new DOMNODE with the specified
     506 *      type and parent. Other than that, the
     507 *      node fields are zeroed.
     508 *
     509 *      If pParentNode is specified (which is required,
     510 *      unless you are creating a document node),
     511 *      its children list is automatically updated
     512 *      (unless this is an attribute node, which updates
     513 *      the attributes map).
     514 *
     515 *      This returns the following errors:
     516 *
     517 *      --  ERROR_NOT_ENOUGH_MEMORY
     518 *
     519 *      --  ERROR_DOM_NOT_SUPPORTED: invalid ulNodeType
     520 *          specified.
     521 *
     522 *      --  ERROR_DOM_WRONG_DOCUMENT: cannot find the
     523 *          document for this node. This happens if you do
     524 *          not have a document node at the root of your tree.
     525 */
     526
     527APIRET xmlCreateDomNode(PDOMNODE pParentNode,        // in: parent node or NULL if root
     528                        NODEBASETYPE ulNodeType,     // in: DOMNODE_* type
     529                        const char *pcszNodeName,    // in: node name or NULL
     530                        ULONG ulNodeNameLength,      // in: node name length
     531                                                     // or 0 to run strlen(pcszNodeName)
     532                        PDOMNODE *ppNew)             // out: new node
     533{
     534    PDOMNODE pNewNode = NULL;
     535    APIRET  arc = NO_ERROR;
     536
     537    ULONG   cb = 0;
     538
     539    switch (ulNodeType)
     540    {
     541        case DOMNODE_DOCUMENT:
     542            cb = sizeof(DOMDOCUMENTNODE);
     543        break;
     544
     545        case DOMNODE_DOCUMENT_TYPE:
     546            cb = sizeof(DOMDOCTYPENODE);
     547        break;
     548
     549        default:
     550            cb = sizeof(DOMNODE);
     551        break;
     552    }
     553
     554    arc = xmlCreateNodeBase(ulNodeType,
     555                            cb,
     556                            pcszNodeName,
     557                            ulNodeNameLength,
     558                            (PNODEBASE*)&pNewNode);
     559    if (arc == NO_ERROR)
     560    {
     561        pNewNode->pParentNode = pParentNode;
     562
     563        if (pParentNode)
     564        {
     565            // parent specified:
     566            // check if this is an attribute
     567            if (ulNodeType == DOMNODE_ATTRIBUTE)
     568            {
     569                // attribute:
     570                // add to parent's attributes list
     571                if (treeInsertNode(&pParentNode->AttributesMap,
     572                                   &pNewNode->NodeBase.Tree,
     573                                   CompareNodeBaseNodes,
     574                                   FALSE)      // no duplicates
     575                        == TREE_DUPLICATE)
     576                    arc = ERROR_DOM_DUPLICATE_ATTRIBUTE;
     577                                // shouldn't happen, because expat takes care of this
     578            }
     579            else
     580                // append this new node to the parent's
     581                // list of child nodes
     582                lstAppendItem(&pParentNode->llChildren,
     583                              pNewNode);
     584
     585            if (!arc)
     586            {
     587                // set document pointer...
     588                // if the parent node has a document pointer,
     589                // we can copy that
     590                if (pParentNode->pDocumentNode)
     591                    pNewNode->pDocumentNode = pParentNode->pDocumentNode;
     592                else
     593                    // parent has no document pointer: then it is probably
     594                    // the document itself... check
     595                    if (pParentNode->NodeBase.ulNodeType == DOMNODE_DOCUMENT)
     596                        pNewNode->pDocumentNode = pParentNode;
     597                    else
     598                        arc = ERROR_DOM_NO_DOCUMENT;
     599            }
     600        }
     601
     602        lstInit(&pNewNode->llChildren, FALSE);
     603        treeInit(&pNewNode->AttributesMap);
     604    }
     605
     606    if (!arc)
     607        *ppNew = pNewNode;
     608    else
     609        if (pNewNode)
     610            free(pNewNode);
     611
     612    return (arc);
     613}
     614
     615/* ******************************************************************
     616 *
     617 *   Specific DOM node constructors
    633618 *
    634619 ********************************************************************/
     
    871856}
    872857
    873 /*
    874  *@@ xmlGetElementsByTagName:
    875  *      returns a linked list of @DOM_ELEMENT nodes which
    876  *      match the specified element name. The special name
    877  *      "*" matches all elements.
    878  *
    879  *      The caller must free the list by calling lstFree.
    880  *      Returns NULL if no such elements could be found.
    881  *
    882  *@@added V0.9.9 (2001-02-14) [umoeller]
    883  */
    884 
    885 PLINKLIST xmlGetElementsByTagName(const char *pcszName)
    886 {
    887     APIRET arc = NO_ERROR;
    888 
    889     return (0);
    890 }
    891 
    892858/* ******************************************************************
    893859 *
    894  *   Content model methods
     860 *   DOM level 3 content models
    895861 *
    896862 ********************************************************************/
     
    1031997
    1032998/*
    1033  *@@ xmlFindElementDecl:
    1034  *      returns the _CMELEMENTDECLNODE for the element
    1035  *      with the specified name or NULL if there's none.
    1036  *
    1037  *@@added V0.9.9 (2001-02-16) [umoeller]
    1038  */
    1039 
    1040 PCMELEMENTDECLNODE xmlFindElementDecl(PXMLDOM pDom,
    1041                                       const XSTRING *pstrElementName)
    1042 {
    1043     PCMELEMENTDECLNODE pElementDecl = NULL;
    1044 
    1045     PDOMDOCTYPENODE pDocTypeNode = pDom->pDocTypeNode;
    1046     if (    (pDocTypeNode)
    1047          && (pstrElementName)
    1048          && (pstrElementName->ulLength)
    1049        )
    1050     {
    1051         pElementDecl = (PCMELEMENTDECLNODE)treeFindEQData(
    1052                                       &pDocTypeNode->ElementDeclsTree,
    1053                                       (void*)pstrElementName->psz,
    1054                                       CompareNodeBaseData);
    1055     }
    1056 
    1057     return (pElementDecl);
    1058 }
    1059 
    1060 /*
    1061  *@@ xmlFindAttribDeclBase:
    1062  *      returns the _CMATTRIBUTEDECLBASE for the specified
    1063  *      element name, or NULL if none exists.
    1064  *
    1065  *      To find a specific attribute declaration from both
    1066  *      an element and an attribute name, use xmlFindAttribDecl
    1067  *      instead.
    1068  *
    1069  *@@added V0.9.9 (2001-02-16) [umoeller]
    1070  */
    1071 
    1072 PCMATTRIBUTEDECLBASE xmlFindAttribDeclBase(PXMLDOM pDom,
    1073                                              const XSTRING *pstrElementName)
    1074 {
    1075     PCMATTRIBUTEDECLBASE pAttribDeclBase = NULL;
    1076 
    1077     PDOMDOCTYPENODE pDocTypeNode = pDom->pDocTypeNode;
    1078     if (    (pDocTypeNode)
    1079          && (pstrElementName)
    1080          && (pstrElementName->ulLength)
    1081        )
    1082     {
    1083         pAttribDeclBase = (PCMATTRIBUTEDECLBASE)treeFindEQData(
    1084                                         &pDocTypeNode->AttribDeclBasesTree,
    1085                                         (void*)pstrElementName->psz,
    1086                                         CompareNodeBaseData);
    1087     }
    1088 
    1089     return (pAttribDeclBase);
    1090 }
    1091 
    1092 /*
    1093  *@@ xmlFindAttribDecl:
    1094  *      returns the _CMATTRIBUTEDEDECL for the specified
    1095  *      element and attribute name, or NULL if none exists.
    1096  *
    1097  *@@added V0.9.9 (2001-02-16) [umoeller]
    1098  */
    1099 
    1100 PCMATTRIBUTEDECL xmlFindAttribDecl(PXMLDOM pDom,
    1101                                    const XSTRING *pstrElementName,
    1102                                    const XSTRING *pstrAttribName,
    1103                                    PCMATTRIBUTEDECLBASE *ppAttribDeclBase)
    1104                                             // in/out: attr decl base cache;
    1105                                             // the pointer pointed to by this
    1106                                             // must be NULL on the first call
    1107 {
    1108     PCMATTRIBUTEDECL pAttribDecl = NULL;
    1109     if (pstrElementName && pstrAttribName)
    1110     {
    1111         if (!*ppAttribDeclBase)
    1112             // first call for this:
    1113             *ppAttribDeclBase = xmlFindAttribDeclBase(pDom,
    1114                                                       pstrElementName);
    1115         if (*ppAttribDeclBase)
    1116         {
    1117             pAttribDecl = (PCMATTRIBUTEDECL)treeFindEQData(
    1118                                          &((**ppAttribDeclBase).AttribDeclsTree),
    1119                                          (void*)pstrAttribName->psz,
    1120                                          CompareNodeBaseData);
    1121         }
    1122     }
    1123 
    1124     return (pAttribDecl);
    1125 }
    1126 
    1127 /*
    1128999 *@@ ValidateElementChildren
    11291000 *      validates the specified element against the document's @DTD,
     
    11761047                return;     // that's OK
    11771048            else
    1178                 pDom->arcDOM = ERROR_DOM_DOCTYPE_STRUCTURE;
     1049                xmlSetError(pDom,
     1050                            ERROR_DOM_VALIDATE_INVALID_ELEMENT,
     1051                            pNewElement->NodeBase.strNodeName.psz,
     1052                            TRUE);
    11791053        }
    11801054        else
     
    18261700
    18271701    // continue parsing only if we had no errors so far
    1828     /* if (!pDom->arcDOM)
    1829     {
    1830         PLISTNODE pStackLN = NULL;
    1831         PDOMSTACKITEM pSI = PopElementStack(pDom,
    1832                                             &pStackLN);
    1833 
    1834         if (pDom->arcDOM)
    1835             pDom->arcDOM = ERROR_DOM_DOCTYPE_STRUCTURE;
    1836         else
    1837         {
    1838             if (pSI->pDomNode->NodeBase.ulNodeType != DOMNODE_DOCUMENT_TYPE)
    1839                 pDom->arcDOM = ERROR_DOM_DOCTYPE_STRUCTURE;
    1840 
    1841             lstRemoveNode(&pDom->llElementStack, pStackLN); // auto-free
    1842         }
    1843     } */
     1702    if (!pDom->arcDOM)
     1703    {
     1704    }
    18441705}
    18451706
     
    18851746 *
    18861747 *      The pcszPublicId parameter is the public id given in the entity
    1887  *      declaration and may be null.
     1748 *      declaration and may be null (since XML doesn't require public
     1749 *      identifiers).
    18881750 *
    18891751 *      The pcszSystemId is the system identifier specified in the
     
    19261788                                        const XML_Char *pcszPublicId)
    19271789{
    1928     int i = 0;
    1929 
    1930     FILE *f = fopen("log", "w");
    1931     fprintf(f, "sysid: %s\n", pcszSystemId);
    1932     fclose(f);
     1790    int i = 1;
     1791
     1792    // @@todo: allow caller to load external references some way
    19331793
    19341794    /* PXMLDOM     pDom = (PXMLDOM)pUserData;
     
    19701830        PDOMDOCTYPENODE pDocType = pDom->pDocTypeNode;
    19711831        if (!pDocType)
    1972             pDom->arcDOM = ERROR_DOM_DOCTYPE_STRUCTURE;
     1832            xmlSetError(pDom,
     1833                        ERROR_DOM_ELEMENT_DECL_OUTSIDE_DOCTYPE,
     1834                        pcszName,
     1835                        TRUE);
    19731836        else
    19741837        {
     
    20711934        PDOMDOCTYPENODE pDocType = pDom->pDocTypeNode;
    20721935        if (!pDocType)
    2073             pDom->arcDOM = ERROR_DOM_DOCTYPE_STRUCTURE;
     1936            xmlSetError(pDom,
     1937                        ERROR_DOM_ATTLIST_DECL_OUTSIDE_DOCTYPE,
     1938                        pcszElementName,
     1939                        TRUE);
    20741940        else
    20751941        {
     
    22532119/* ******************************************************************
    22542120 *
    2255  *   DOM APIs
     2121 *   DOM root APIs
    22562122 *
    22572123 ********************************************************************/
     
    22712137 *
    22722138 *      --  DF_PARSEDTD: add the @DTD of the document into the DOM tree
    2273  *          as well and validate the document.
     2139 *          as well and validate the document, if a DTD was found.
     2140 *          Otherwise just parse and do not validate.
     2141 *
     2142 *      --  DF_FAIL_IF_NO_DTD: fail if no @DTD was found. Useful
     2143 *          if you want to enforce validation. @@todo
    22742144 *
    22752145 *      Usage:
     
    22782148 *
    22792149 +          PXMLDOM pDom = NULL;
    2280  +          APIRET arc = xmlCreateDom(flags, &pDom);
     2150 +          APIRET arc = xmlCreateDOM(flags, &pDom);
    22812151 +
    22822152 *      2) Give chunks of data (or an entire buffer)
     
    24122282 *         error information in the XMLDOM fields.
    24132283 *
    2414  *      -- ERROR_DOM_PARSING: the document is not @valid.
     2284 *      -- ERROR_DOM_VALIDITY: the document is not @valid.
    24152285 *         This can only happen if @DTD parsing was enabled
    24162286 *         with xmlCreateDOM.
     
    25102380    return (arc);
    25112381}
     2382
     2383/* ******************************************************************
     2384 *
     2385 *   DOM lookup
     2386 *
     2387 ********************************************************************/
     2388
     2389/*
     2390 *@@ xmlFindElementDecl:
     2391 *      returns the _CMELEMENTDECLNODE for the element
     2392 *      with the specified name or NULL if there's none.
     2393 *
     2394 *@@added V0.9.9 (2001-02-16) [umoeller]
     2395 */
     2396
     2397PCMELEMENTDECLNODE xmlFindElementDecl(PXMLDOM pDom,
     2398                                      const XSTRING *pstrElementName)
     2399{
     2400    PCMELEMENTDECLNODE pElementDecl = NULL;
     2401
     2402    PDOMDOCTYPENODE pDocTypeNode = pDom->pDocTypeNode;
     2403    if (    (pDocTypeNode)
     2404         && (pstrElementName)
     2405         && (pstrElementName->ulLength)
     2406       )
     2407    {
     2408        pElementDecl = (PCMELEMENTDECLNODE)treeFindEQData(
     2409                                      &pDocTypeNode->ElementDeclsTree,
     2410                                      (void*)pstrElementName->psz,
     2411                                      CompareNodeBaseData);
     2412    }
     2413
     2414    return (pElementDecl);
     2415}
     2416
     2417/*
     2418 *@@ xmlFindAttribDeclBase:
     2419 *      returns the _CMATTRIBUTEDECLBASE for the specified
     2420 *      element name, or NULL if none exists.
     2421 *
     2422 *      To find a specific attribute declaration from both
     2423 *      an element and an attribute name, use xmlFindAttribDecl
     2424 *      instead.
     2425 *
     2426 *@@added V0.9.9 (2001-02-16) [umoeller]
     2427 */
     2428
     2429PCMATTRIBUTEDECLBASE xmlFindAttribDeclBase(PXMLDOM pDom,
     2430                                           const XSTRING *pstrElementName)
     2431{
     2432    PCMATTRIBUTEDECLBASE pAttribDeclBase = NULL;
     2433
     2434    PDOMDOCTYPENODE pDocTypeNode = pDom->pDocTypeNode;
     2435    if (    (pDocTypeNode)
     2436         && (pstrElementName)
     2437         && (pstrElementName->ulLength)
     2438       )
     2439    {
     2440        pAttribDeclBase = (PCMATTRIBUTEDECLBASE)treeFindEQData(
     2441                                        &pDocTypeNode->AttribDeclBasesTree,
     2442                                        (void*)pstrElementName->psz,
     2443                                        CompareNodeBaseData);
     2444    }
     2445
     2446    return (pAttribDeclBase);
     2447}
     2448
     2449/*
     2450 *@@ xmlFindAttribDecl:
     2451 *      returns the _CMATTRIBUTEDEDECL for the specified
     2452 *      element and attribute name, or NULL if none exists.
     2453 *
     2454 *@@added V0.9.9 (2001-02-16) [umoeller]
     2455 */
     2456
     2457PCMATTRIBUTEDECL xmlFindAttribDecl(PXMLDOM pDom,
     2458                                   const XSTRING *pstrElementName,
     2459                                   const XSTRING *pstrAttribName,
     2460                                   PCMATTRIBUTEDECLBASE *ppAttribDeclBase)
     2461                                            // in/out: attr decl base cache;
     2462                                            // the pointer pointed to by this
     2463                                            // must be NULL on the first call
     2464{
     2465    PCMATTRIBUTEDECL pAttribDecl = NULL;
     2466    if (pstrElementName && pstrAttribName)
     2467    {
     2468        if (!*ppAttribDeclBase)
     2469            // first call for this:
     2470            *ppAttribDeclBase = xmlFindAttribDeclBase(pDom,
     2471                                                      pstrElementName);
     2472        if (*ppAttribDeclBase)
     2473        {
     2474            pAttribDecl = (PCMATTRIBUTEDECL)treeFindEQData(
     2475                                         &((**ppAttribDeclBase).AttribDeclsTree),
     2476                                         (void*)pstrAttribName->psz,
     2477                                         CompareNodeBaseData);
     2478        }
     2479    }
     2480
     2481    return (pAttribDecl);
     2482}
     2483
     2484/*
     2485 *@@ xmlGetRootElement:
     2486 *      returns the root element node from the specified
     2487 *      DOM. Useful helper to start enumerating elements.
     2488 *
     2489 *@@added V0.9.11 (2001-04-22) [umoeller]
     2490 */
     2491
     2492PDOMNODE xmlGetRootElement(PXMLDOM pDom)
     2493{
     2494    PDOMDOCUMENTNODE    pDocumentNode;
     2495    PLISTNODE           pListNode;
     2496    if (    (pDom)
     2497         && (pDocumentNode = pDom->pDocumentNode)
     2498         && (pListNode = lstQueryFirstNode(&pDocumentNode->DomNode.llChildren))
     2499       )
     2500    {
     2501        return ((PDOMNODE)pListNode->pItemData);
     2502    }
     2503
     2504    return (NULL);
     2505}
     2506
     2507/*
     2508 *@@ xmlGetFirstChild:
     2509 *      returns the first child node of pDomNode.
     2510 *      See _DOMNODE for what a "child" can be for the
     2511 *      various node types.
     2512 *
     2513 *@@added V0.9.9 (2001-02-14) [umoeller]
     2514 */
     2515
     2516PDOMNODE xmlGetFirstChild(PDOMNODE pDomNode)
     2517{
     2518    PLISTNODE pListNode = lstQueryFirstNode(&pDomNode->llChildren);
     2519    if (pListNode)
     2520        return ((PDOMNODE)pListNode->pItemData);
     2521
     2522    return (0);
     2523}
     2524
     2525/*
     2526 *@@ xmlGetLastChild:
     2527 *      returns the last child node of pDomNode.
     2528 *      See _DOMNODE for what a "child" can be for the
     2529 *      various node types.
     2530 *
     2531 *@@added V0.9.9 (2001-02-14) [umoeller]
     2532 */
     2533
     2534PDOMNODE xmlGetLastChild(PDOMNODE pDomNode)
     2535{
     2536    PLISTNODE pListNode = lstQueryLastNode(&pDomNode->llChildren);
     2537    if (pListNode)
     2538        return ((PDOMNODE)pListNode->pItemData);
     2539
     2540    return (0);
     2541}
     2542
     2543/*
     2544 *@@ xmlGetFirstText:
     2545 *      returns the first text (character data) node
     2546 *      of pElement or NULL if there's none.
     2547 *
     2548 *@@added V0.9.11 (2001-04-22) [umoeller]
     2549 */
     2550
     2551PDOMNODE xmlGetFirstText(PDOMNODE pElement)
     2552{
     2553    PLISTNODE   pNode;
     2554    PDOMNODE    pDomNodeThis;
     2555
     2556    for (pNode = lstQueryFirstNode(&pElement->llChildren);
     2557         pNode;
     2558         pNode = pNode->pNext)
     2559    {
     2560        if (    (pDomNodeThis = (PDOMNODE)pNode->pItemData)
     2561             && (pDomNodeThis->NodeBase.ulNodeType == DOMNODE_TEXT)
     2562           )
     2563            return (pDomNodeThis);
     2564    }
     2565
     2566    return (NULL);
     2567}
     2568
     2569/*
     2570 *@@ xmlGetElementsByTagName:
     2571 *      returns a linked list of _DOMNODE nodes which
     2572 *      match the specified element name. The special name
     2573 *      "*" matches all elements.
     2574 *
     2575 *      pParent must be the parent element DOMNODE...
     2576 *      the only allowed exception is
     2577 *
     2578 *      The caller must free the list by calling lstFree.
     2579 *      Returns NULL if no such elements could be found.
     2580 *
     2581 *@@added V0.9.9 (2001-02-14) [umoeller]
     2582 */
     2583
     2584PLINKLIST xmlGetElementsByTagName(PDOMNODE pParent,
     2585                                  const char *pcszName)
     2586{
     2587    APIRET arc = NO_ERROR;
     2588
     2589    PLINKLIST pll = lstCreate(FALSE);       // no free
     2590    if (pll)
     2591    {
     2592        ULONG   cItems = 0;
     2593        BOOL    fFindAll = !strcmp(pcszName, "*");
     2594
     2595        PLISTNODE   pNode;
     2596        PDOMNODE    pDomNodeThis;
     2597
     2598        for (pNode = lstQueryFirstNode(&pParent->llChildren);
     2599             pNode;
     2600             pNode = pNode->pNext)
     2601        {
     2602            if (    (pDomNodeThis = (PDOMNODE)pNode->pItemData)
     2603                 && (pDomNodeThis->NodeBase.ulNodeType == DOMNODE_ELEMENT)
     2604                 && (   fFindAll
     2605                     || (!strcmp(pcszName, pDomNodeThis->NodeBase.strNodeName.psz))
     2606                   )
     2607               )
     2608            {
     2609                // element matches:
     2610                lstAppendItem(pll, pDomNodeThis);
     2611                cItems++;
     2612            }
     2613        }
     2614
     2615        if (cItems)
     2616            return (pll);
     2617        else
     2618            lstFree(pll);
     2619    }
     2620
     2621    return (0);
     2622}
     2623
     2624/*
     2625 *@@ xmlGetAttribute:
     2626 *      returns the value of pElement's attribute
     2627 *      with the given name or NULL.
     2628 *
     2629 *      This is a const pointer into the element's
     2630 *      attribute list.
     2631 *
     2632 *@@added V0.9.11 (2001-04-22) [umoeller]
     2633 */
     2634
     2635const XSTRING* xmlGetAttribute(PDOMNODE pElement,
     2636                               const char *pcszAttribName)
     2637{
     2638    PDOMNODE pAttrNode = (PDOMNODE)treeFindEQData(&pElement->AttributesMap,
     2639                                                  (void*)pcszAttribName,
     2640                                                  CompareNodeBaseData);
     2641    if (pAttrNode)
     2642        return (pAttrNode->pstrNodeValue);
     2643
     2644    return (NULL);
     2645}
Note: See TracChangeset for help on using the changeset viewer.