McbXML.c
上传用户:loctitetv
上传日期:2008-08-08
资源大小:42k
文件大小:105k
源码类别:

中间件编程

开发平台:

Visual C++

  1. /**
  2.  ****************************************************************************
  3.  * <P> McbXML.c - implementation file for basic XML parser written in ANSI C 
  4.  * for portability.
  5.  * It works by using recursion and a node tree for breaking down the elements
  6.  * of an XML document.  </P>
  7.  *
  8.  * @version     V1.0
  9.  *
  10.  * @author      Martyn C Brown
  11.  *
  12.  * @changeHistory  
  13.  * 21st August     2001  -  (V1.0) Creation (MCB)
  14.  ****************************************************************************
  15.  */
  16. /*
  17.  ****************************************************************************
  18.  * Include all necessary include files
  19.  ****************************************************************************
  20.  */
  21. #include "McbXML.h"
  22. #include <malloc.h>
  23. #include <memory.h>
  24. #include <assert.h>
  25. /*
  26.  ****************************************************************************
  27.  * Enumeration used to decipher what type a token is
  28.  ****************************************************************************
  29.  */
  30. typedef enum McbTokenType
  31. {
  32. eTokenText = 0,
  33. eTokenQuotedText,
  34. eTokenTagStart, /* "<" */
  35. eTokenTagEnd, /* "</" */
  36. eTokenCloseTag, /* ">" */
  37. eTokenEquals, /* "=" */
  38. eTokenDeclaration, /* "<?" */
  39. eTokenShortHandClose, /* "/>" */
  40. eTokenClear,
  41. eTokenError
  42. } McbTokenType;
  43. /*
  44.  ****************************************************************************
  45.  * Defines to dictate grow by value when adding nodes.
  46.  ****************************************************************************
  47.  */
  48. #define McbGROWBY 5
  49. #define McbINDENTCHAR _T('t')
  50. typedef struct McbClearTag
  51. {
  52. LPTSTR lpszOpen;
  53. LPTSTR lpszClose;
  54. } McbClearTag;
  55. typedef struct McbNextToken
  56. {
  57. McbClearTag *pClr;
  58. LPCTSTR pStr;
  59. } McbNextToken;
  60. /*
  61.  ****************************************************************************
  62.  * Main structure used for parsing XML
  63.  ****************************************************************************
  64.  */
  65. typedef struct McbXML
  66. {
  67. LPCTSTR lpXML;
  68. int nIndex;
  69. enum McbXMLError error;
  70. LPCTSTR lpEndTag;
  71. int cbEndTag;
  72. LPCTSTR lpNewElement;
  73. int cbNewElement;
  74. int nFirst;
  75. McbClearTag *pClrTags;
  76. } McbXML;
  77. /*
  78.  ****************************************************************************
  79.  * Enumeration used when parsing attributes
  80.  ****************************************************************************
  81.  */
  82. typedef enum McbAttrib
  83. {
  84. eAttribName = 0,
  85. eAttribEquals,
  86. eAttribValue
  87. } McbAttrib;
  88. /*
  89.  ****************************************************************************
  90.  * Enumeration used when parsing elements to dictate whether we are currently
  91.  * inside a tag
  92.  ****************************************************************************
  93.  */
  94. typedef enum McbStatus
  95. {
  96. eInsideTag = 0,
  97. eOutsideTag
  98. } McbStatus;
  99. /*
  100.  ****************************************************************************
  101.  * Structure used to obtain List.
  102.  ****************************************************************************
  103.  */
  104. typedef struct List_ST{
  105. struct List_ST *pNext;
  106. struct List_ST *pPrev;
  107. }List_st;
  108. typedef struct{
  109. List_st pList;
  110. int iNum;
  111. }ListHead_st;
  112. /*
  113.  ****************************************************************************
  114.  * Structure used to obtain List Node.
  115.  ****************************************************************************
  116.  */
  117. #ifdef DYNAMIC_MEM
  118. typedef struct{
  119. List_st List;
  120. LPTSTR lpszText;
  121. }NodeText_st;
  122. #else
  123. typedef struct{
  124. List_st List;
  125. char lpszText[256];
  126. }NodeText_st;
  127. #endif
  128. static ListHead_st g_StrList;
  129. void InitList(ListHead_st *pListHead)
  130. {
  131. pListHead->pList.pNext = &(pListHead->pList);
  132. pListHead->pList.pPrev = &(pListHead->pList);
  133. pListHead->iNum = 0;
  134. }/* InitList */
  135. void AddToList(ListHead_st *pListHead,List_st *pListNode)
  136. {
  137. pListNode->pPrev = &(pListHead->pList);
  138. pListNode->pNext = pListHead->pList.pNext;
  139. pListHead->pList.pNext->pPrev = pListNode;
  140. pListHead->pList.pNext = pListNode;
  141. pListHead->iNum++;
  142. }/* AddToList */
  143. List_st *DeleteFromListTial(ListHead_st *pListHead)
  144. {
  145. List_st *pTemp;
  146. //Empty List?
  147. if(pListHead->pList.pPrev == &(pListHead->pList))
  148. return 0;
  149. pTemp = pListHead->pList.pPrev;
  150. pTemp->pPrev->pNext = pTemp->pNext;
  151. pTemp->pNext->pPrev = pTemp->pPrev;
  152. pListHead->iNum--;
  153. return pTemp;
  154. }/* DeleteFromListTial */
  155. void DeleteFromList(List_st *pList)
  156. {
  157. pList->pNext->pPrev = pList->pPrev;
  158. pList->pPrev->pPrev = pList->pNext;
  159. }/*  DeleteFromList */
  160. void FreeList(ListHead_st *pListHead)
  161. {
  162. List_st *pList;
  163. NodeText_st *pNodeText;
  164. //empty List
  165. if(pListHead->pList.pNext == &(pListHead->pList))
  166. return;
  167. while(pListHead->iNum){
  168. pList = DeleteFromListTial(pListHead);
  169. pNodeText = ListEntry(pList,NodeText_st,List);
  170. #ifdef DYNAMIC_MEM
  171. free(pNodeText->lpszText);
  172. #endif
  173. free(pNodeText);
  174. }
  175. }/*FreeList*/
  176. /**
  177.  ****************************************************************************
  178.  * <P> Initialise an element.  </P>
  179.  *
  180.  * @methodName  McbInitElement
  181.  *
  182.  * @param       *pEntry
  183.  * @param       lpszName
  184.  *
  185.  * @return      void
  186.  *
  187.  * @exception   none
  188.  *
  189.  * @author      Martyn C Brown
  190.  *
  191.  * @changeHistory  
  192.  * 14th August     2001  -  (V1.0) Creation (MCB)
  193.  ****************************************************************************
  194.  */
  195. void McbInitElement(McbXMLElement *pEntry, McbXMLElement *pParent, 
  196.    LPTSTR lpszName, int nIsDeclaration)
  197. {
  198. assert(pEntry);
  199. pEntry->nMax = 0;
  200. pEntry->nSize = 0;
  201. pEntry->pEntries = NULL;
  202. pEntry->pParent = pParent;
  203. pEntry->nIsDeclaration = nIsDeclaration;
  204. pEntry->lpszName = lpszName;
  205. }/* McbInitElement */
  206. /**
  207.  ****************************************************************************
  208.  * <P> Create the root element.  </P>
  209.  *
  210.  * @methodName  * McbCreateRoot
  211.  *
  212.  * @param       none
  213.  *
  214.  * @return      McbXMLElement
  215.  *
  216.  * @exception   none
  217.  *
  218.  * @author      Martyn C Brown
  219.  *
  220.  * @changeHistory  
  221.  * 1st February   2002  -  (V1.0) Creation (MCB)
  222.  ****************************************************************************
  223.  */
  224. McbXMLElement * McbCreateRoot()
  225. {
  226. McbXMLElement * pElement;
  227. pElement = (McbXMLElement*)malloc(sizeof(McbXMLElement));
  228. McbInitElement(pElement, NULL, 0, FALSE);
  229. //Init the NodeName LinkList
  230. //Toby add 2006/7/3/9:31
  231. //InitList(&g_StrList);
  232. return pElement;
  233. }/* McbCreateRoot */
  234. /**
  235.  ****************************************************************************
  236.  * <P> Delete the root element and set it to NULL.  </P>
  237.  *
  238.  * @methodName  McbDeleteRoot
  239.  *
  240.  * @param       ** ppElement
  241.  *
  242.  * @return      void
  243.  *
  244.  * @exception   none
  245.  *
  246.  * @author      Martyn C Brown
  247.  *
  248.  * @changeHistory  
  249.  * 1st February   2002  -  (V1.0) Creation (MCB)
  250.  ****************************************************************************
  251.  */
  252. void McbDeleteRoot(McbXMLElement * pElement)
  253. {
  254.     McbDeleteElement(pElement);
  255. free(pElement);
  256. //FreeList(&g_StrList);
  257. }/* McbDeleteRoot */
  258. /**
  259.  ****************************************************************************
  260.  * <P> Delete an attribute.  </P>
  261.  *
  262.  * @methodName  McbDeleteAttribute
  263.  *
  264.  * @param       *pEntry
  265.  *
  266.  * @return      void
  267.  *
  268.  * @exception   none
  269.  *
  270.  * @author      Martyn C Brown
  271.  *
  272.  * @changeHistory  
  273.  * 14th August     2001  -  (V1.0) Creation (MCB)
  274.  ****************************************************************************
  275.  */
  276. void McbDeleteAttribute(McbXMLAttribute *pEntry)
  277. {
  278. assert(pEntry);
  279. if (pEntry->lpszName) 
  280. {
  281. free(pEntry->lpszName);
  282. pEntry->lpszName = NULL;
  283. }
  284. if (pEntry->lpszValue) 
  285. {
  286. free(pEntry->lpszValue);
  287. pEntry->lpszValue=  NULL;
  288. }
  289. }/* McbDeleteAttribute */
  290. /**
  291.  ****************************************************************************
  292.  * <P> Attach attributes from one list to another.  </P>
  293.  *
  294.  * @methodName  McbAttributeAttach
  295.  *
  296.  * @param       *pDst
  297.  * @param       *pSrc
  298.  * @param       nNum
  299.  *
  300.  * @return      void
  301.  *
  302.  * @exception   none
  303.  *
  304.  * @author      Martyn C Brown
  305.  *
  306.  * @changeHistory  
  307.  * 14th August     2001  -  (V1.0) Creation (MCB)
  308.  ****************************************************************************
  309.  */
  310. void McbAttributeAttach(McbXMLAttribute *pDst, McbXMLAttribute *pSrc, int nNum)
  311. {
  312. int n;
  313. for (n=0; n<nNum; n++)
  314. {
  315. pDst[n].lpszName = pSrc[n].lpszName;
  316. pDst[n].lpszValue = pSrc[n].lpszValue;
  317. pSrc[n].lpszName = NULL;
  318. pSrc[n].lpszValue = NULL;
  319. }
  320. }/* McbAttributeAttach */
  321. /**
  322.  ****************************************************************************
  323.  * <P> Obtain the next character from the string.  </P>
  324.  *
  325.  * @methodName  McbGetNextChar
  326.  *
  327.  * @param       *pXML
  328.  *
  329.  * @return      TCHAR
  330.  *
  331.  * @exception   none
  332.  *
  333.  * @author      Martyn C Brown
  334.  *
  335.  * @changeHistory  
  336.  * 17th August     2001  -  (V1.0) Creation (MCB)
  337.  ****************************************************************************
  338.  */
  339. TCHAR McbGetNextChar(McbXML *pXML)
  340. {
  341. TCHAR ch;
  342. ch = pXML->lpXML[pXML->nIndex];
  343. if (ch != 0) pXML->nIndex++;
  344. return ch;
  345. }/* McbGetNextChar */
  346. /**
  347.  ****************************************************************************
  348.  * <P> Find next non-white space character.  </P>
  349.  *
  350.  * @methodName  McbFindNonWhiteSpace
  351.  *
  352.  * @param       *pXML
  353.  *
  354.  * @return      TCHAR
  355.  *
  356.  * @exception   none
  357.  *
  358.  * @author      Martyn C Brown
  359.  *
  360.  * @changeHistory  
  361.  * 18th August     2001  -  (V1.0) Creation (MCB)
  362.  ****************************************************************************
  363.  */
  364. TCHAR McbFindNonWhiteSpace(McbXML *pXML)
  365. {
  366. TCHAR ch;
  367. LPCTSTR lpXML = pXML->lpXML;
  368. int nExit = FALSE;
  369. assert(pXML);
  370.    /*
  371.     *************************************************************************
  372.     * Iterate through characters in the string until we find a NULL or a
  373.     * non-white space character
  374.     *************************************************************************
  375.     */
  376. while((nExit == FALSE) && (ch = McbGetNextChar(pXML)))
  377. {
  378. switch(ch)
  379. {
  380.        /*
  381.         *********************************************************************
  382.         * Ignore white space
  383.         *********************************************************************
  384.         */
  385.         case _T('n'):
  386.         case _T(' '):
  387. case _T('t'):
  388. case _T('r'):
  389. continue;
  390. default:
  391. nExit = TRUE;
  392. }
  393. }
  394. return ch;
  395. }/* McbFindNonWhiteSpace */
  396. /**
  397.  ****************************************************************************
  398.  * <P> Duplicate a given string.  </P>
  399.  *
  400.  * @methodName  McbStrdup
  401.  *
  402.  * @param       lpszData
  403.  * @param       cbData
  404.  *
  405.  * @return      LPTSTR
  406.  *
  407.  * @exception   none
  408.  *
  409.  * @author      Martyn C Brown
  410.  *
  411.  * @changeHistory  
  412.  * 18th August     2001  -  (V1.0) Creation (MCB)
  413.  ****************************************************************************
  414.  */
  415. LPTSTR McbStrdup(LPCTSTR lpszData, int cbData)
  416. {
  417. LPTSTR lpszNew;
  418. assert(lpszData);
  419. if (cbData == 0) cbData = _tcslen(lpszData);
  420. lpszNew = malloc((cbData+1) * sizeof(TCHAR));
  421. if (lpszNew)
  422. {
  423. memcpy(lpszNew, lpszData, (cbData) * sizeof(TCHAR));
  424. lpszNew[cbData] = (TCHAR)NULL;
  425. }
  426. return lpszNew;
  427. }/* McbStrdup */
  428. /**
  429.  ****************************************************************************
  430.  * <P> Find the next token in a string.  </P>
  431.  *
  432.  * @methodName  McbGetNextToken
  433.  *
  434.  * @param       *pXML
  435.  * @param       *pcbToken
  436.  * @param       *pType
  437.  *
  438.  * @return      LPCTSTR
  439.  *
  440.  * @exception   none
  441.  *
  442.  * @author      Martyn C Brown
  443.  *
  444.  * @changeHistory  
  445.  * 17th August     2001  -  (V1.0) Creation (MCB)
  446.  ****************************************************************************
  447.  */
  448. McbNextToken McbGetNextToken(McbXML *pXML, int *pcbToken, McbTokenType *pType)
  449. {
  450. McbNextToken result;
  451. LPCTSTR lpXML;
  452. TCHAR ch;
  453. TCHAR chTemp;
  454. int nSize;
  455. int nFoundMatch;
  456. int nExit;
  457. int n;
  458. LPCTSTR lpszOpen;
  459. int cbOpen;
  460. int nIsText = FALSE;
  461.    /*
  462.     *************************************************************************
  463.     * Find next non-whte space character
  464.     *************************************************************************
  465.     */
  466. ch = McbFindNonWhiteSpace(pXML);
  467. if (ch)
  468. {
  469.        /*
  470.         *********************************************************************
  471.         * Cache the current string pointer
  472.         *********************************************************************
  473.         */
  474. lpXML = pXML->lpXML;
  475. result.pStr = &lpXML[pXML->nIndex-1];
  476.        /*
  477.         *********************************************************************
  478.         * First check whether the token is in the clear tag list (meaning it 
  479. * does not need formatting).
  480.         *********************************************************************
  481.         */
  482. n = 0;
  483. while(TRUE)
  484. {
  485.            /*
  486.             *****************************************************************
  487.             * Obtain the name of the open part of the clear tag
  488.             *****************************************************************
  489.             */
  490. lpszOpen = pXML->pClrTags[n].lpszOpen;
  491. if (lpszOpen)
  492. {
  493.                /*
  494.                 *************************************************************
  495.                 * Compare the open tag with the current token
  496.                 *************************************************************
  497.                 */
  498. cbOpen = _tcslen(lpszOpen);
  499. if (_tcsnicmp(lpszOpen, result.pStr, cbOpen) == 0)
  500. {
  501. result.pClr = &pXML->pClrTags[n];
  502. pXML->nIndex += cbOpen-1;
  503. *pType  = eTokenClear;
  504. return result;
  505. }
  506. n++;
  507. }
  508. else
  509. {
  510. break;
  511. }
  512. }
  513.        /*
  514.         *********************************************************************
  515.         * If we didn't find a clear tag then check for standard tokens
  516.         *********************************************************************
  517.         */
  518. chTemp = 0;
  519. lpXML = pXML->lpXML;
  520. switch(ch)
  521. {
  522.        /*
  523.         *********************************************************************
  524.         * Check for quotes
  525.         *********************************************************************
  526.         */
  527. case _T('''):
  528. case _T('"'):
  529.            /*
  530.             *****************************************************************
  531.             * Type of token
  532.             *****************************************************************
  533.             */
  534. *pType = eTokenQuotedText;
  535. chTemp = ch;
  536.            /*
  537.             *****************************************************************
  538.             * Set the size
  539.             *****************************************************************
  540.             */
  541. nSize = 1;
  542. nFoundMatch = FALSE;
  543.            /*
  544.             *****************************************************************
  545.             * Search through the string to find a matching quote
  546.             *****************************************************************
  547.             */
  548. while(ch = McbGetNextChar(pXML))
  549. {
  550. nSize++;
  551. if (ch == chTemp)
  552. {
  553. nFoundMatch = TRUE;
  554. break;
  555. }
  556. }
  557.            /*
  558.             *****************************************************************
  559.             * If we failed to find a matching quote
  560.             *****************************************************************
  561.             */
  562. if (nFoundMatch == FALSE)
  563. {
  564.                /*
  565.                 *************************************************************
  566.                 * Indicate error
  567.                 *************************************************************
  568.                 */
  569. pXML->error = eXMLErrorNoMatchingQuote;
  570. *pType = eTokenError;
  571. }
  572. /* MCB 4.02.2002 */
  573. if (McbFindNonWhiteSpace(pXML))
  574. {
  575. pXML->nIndex--;
  576. }
  577. break;
  578.        /*
  579.         *********************************************************************
  580.         * Equals (used with attribute values)
  581.         *********************************************************************
  582.         */
  583. case _T('='):
  584. nSize = 1;
  585. *pType = eTokenEquals;
  586. break;
  587.        /*
  588.         *********************************************************************
  589.         * Close tag
  590.         *********************************************************************
  591.         */
  592. case _T('>'):
  593. nSize = 1;
  594. *pType = eTokenCloseTag;
  595. break;
  596.        /*
  597.         *********************************************************************
  598.         * Check for tag start and tag end
  599.         *********************************************************************
  600.         */
  601. case _T('<'):
  602.            /*
  603.             *****************************************************************
  604.             * Peek at the next character to see if we have an end tag '</',
  605. * or an xml declaration '<?'
  606.             *****************************************************************
  607.             */
  608. chTemp = pXML->lpXML[pXML->nIndex];
  609.            /*
  610.             *****************************************************************
  611.             * If we have a tag end...
  612.             *****************************************************************
  613.             */
  614. if (chTemp == _T('/'))
  615. {
  616.                /*
  617.                 *************************************************************
  618.                 * Set the type and ensure we point at the next character 
  619.                 *************************************************************
  620.                 */
  621. McbGetNextChar(pXML);
  622. *pType = eTokenTagEnd;
  623. nSize = 2;
  624. }
  625.            /*
  626.             *****************************************************************
  627.             * If we have an XML declaration tag
  628.             *****************************************************************
  629.             */
  630. else if (chTemp == _T('?'))
  631. {
  632.                /*
  633.                 *************************************************************
  634.                 * Set the type and ensure we point at the next character 
  635.                 *************************************************************
  636.                 */
  637. McbGetNextChar(pXML);
  638. *pType = eTokenDeclaration;
  639. nSize = 2;
  640. }
  641.            /*
  642.             *****************************************************************
  643.             * Otherwise we must have a start tag
  644.             *****************************************************************
  645.             */
  646.             else 
  647. {
  648. *pType = eTokenTagStart;
  649. nSize = 1;
  650. }
  651. break;
  652.        /*
  653.         *********************************************************************
  654.         * Check to see if we have a short hand type end tag ('/>').
  655.         *********************************************************************
  656.         */
  657. case _T('/'):
  658.    /*
  659.             *****************************************************************
  660.             * Peek at the next character to see if we have an end tag '</'
  661. * or an xml declaration '<?'
  662.             *****************************************************************
  663.             */
  664. chTemp = pXML->lpXML[pXML->nIndex];
  665.            /*
  666.             *****************************************************************
  667.             * If we have a short hand end tag...
  668.             *****************************************************************
  669.             */
  670. if (chTemp == _T('>'))
  671. {
  672.                /*
  673.                 *************************************************************
  674.                 * Set the type and ensure we point at the next character 
  675.                 *************************************************************
  676.                 */
  677. McbGetNextChar(pXML);
  678. *pType = eTokenShortHandClose;
  679. nSize = 2;
  680. break;
  681. }
  682.            /*
  683.             *****************************************************************
  684.             * If we haven't found a short hand closing tag then drop into the
  685. * text process
  686.             *****************************************************************
  687.             */
  688.        /*
  689.         *********************************************************************
  690.         * Other characters
  691.         *********************************************************************
  692.         */
  693. default:
  694. nIsText = TRUE;
  695. }
  696.        /*
  697.         *********************************************************************
  698.         * If this is a TEXT node
  699.         *********************************************************************
  700.         */
  701. if (nIsText)
  702. {
  703.            /*
  704.             *****************************************************************
  705.             * Indicate we are dealing with text
  706.             *****************************************************************
  707.             */
  708. *pType = eTokenText;
  709. nSize = 1;
  710. nExit = FALSE;
  711. while((nExit == FALSE) && (ch = McbGetNextChar(pXML)))
  712. {
  713.                 switch(ch)
  714.                 {
  715.                /*
  716.                 *************************************************************
  717.                 * Break when we find white space
  718.                 *************************************************************
  719.                 */
  720.                 case _T('n'):
  721.                 case _T(' '):
  722.                 case _T('t'):
  723.                 case _T('r'):
  724. nExit = TRUE;
  725.                     break;
  726.                /*
  727.                 *************************************************************
  728.                 * If we find a slash then this maybe text or a short hand end
  729. * tag.
  730.                 *************************************************************
  731.                 */
  732. case _T('/'):
  733.                    /*
  734.                     *********************************************************
  735.                     * Peek at the next character to see it we have short hand
  736. * end tag
  737.                     *********************************************************
  738.                     */
  739. chTemp = pXML->lpXML[pXML->nIndex];
  740.                    /*
  741.                     *********************************************************
  742.                     * If we found a short hand end tag then we need to exit 
  743. * the loop
  744.                     *********************************************************
  745.                     */
  746. if (chTemp == _T('>'))
  747. {
  748. pXML->nIndex--; /* MCB 03.02.2002 */
  749. nExit = TRUE;
  750. }
  751. else
  752. {
  753. nSize++;
  754. }
  755. break;
  756.                /*
  757.                 *************************************************************
  758.                 * Break when we find a terminator and decrement the index and
  759. * column count so that we are pointing at the right character
  760. * the next time we are called.
  761.                 *************************************************************
  762.                 */
  763. case _T('<'):
  764. case _T('>'):
  765. case _T('='):
  766. pXML->nIndex--;
  767. nExit = TRUE;
  768. break;
  769. case 0:
  770. nExit = TRUE;
  771. break;
  772. default:
  773. nSize++;
  774.                 }
  775. }
  776. }
  777. *pcbToken = nSize;
  778. }
  779.    /*
  780.     *************************************************************************
  781.     * If we failed to obtain a valid character
  782.     *************************************************************************
  783.     */
  784.     else 
  785.     {
  786.     *pcbToken = 0;
  787. *pType = eTokenError;
  788.     }
  789. return result;
  790. }/* McbGetNextToken */
  791. /**
  792.  ****************************************************************************
  793.  * <P> Parse XML errors into a user friendly string.  </P>
  794.  *
  795.  * @methodName  McbGetError
  796.  *
  797.  * @param       error
  798.  *
  799.  * @return      LPCTSTR
  800.  *
  801.  * @exception   none
  802.  *
  803.  * @author      Martyn C Brown
  804.  *
  805.  * @changeHistory  
  806.  * 19th August     2001  -  (V1.0) Creation (MCB)
  807.  ****************************************************************************
  808.  */
  809. LPCTSTR McbGetError(McbXMLError error)
  810. {
  811. LPCTSTR lpszErr = _T("Unknown");
  812. int n;
  813.    /*
  814.     *************************************************************************
  815.     * Structure for errors array
  816.     *************************************************************************
  817.     */
  818. typedef struct McbErrorList
  819. {
  820. enum McbXMLError err;
  821. LPCTSTR lpszErr;
  822. } McbErrorList;
  823.    /*
  824.     *************************************************************************
  825.     * Static array containing helpful error text.
  826.     *************************************************************************
  827.     */
  828. static struct McbErrorList errs[] = 
  829. {
  830. { eXMLErrorNone, _T("No error") },
  831. { eXMLErrorEmpty, _T("No XML data") },
  832. { eXMLErrorFirstNotStartTag, _T("First token not start tag") },
  833. { eXMLErrorMissingTagName, _T("Missing start tag name") },
  834. { eXMLErrorMissingEndTagName, _T("Missing end tag name") },
  835. { eXMLErrorNoMatchingQuote, _T("Unmatched quote") },
  836. { eXMLErrorUnmatchedEndTag, _T("Unmatched end tag") },
  837. { eXMLErrorUnexpectedToken, _T("Unexpected token found") },
  838. { eXMLErrorInvalidTag, _T("Invalid tag found") },
  839. { eXMLErrorNoElements, _T("No elements found") },
  840. { 0, NULL }
  841. };
  842.    /*
  843.     *************************************************************************
  844.     * Iterate through the list of errors to find a matching error
  845.     *************************************************************************
  846.     */
  847. for(n = 0; errs[n].lpszErr; n++)
  848. {
  849. if (errs[n].err == error)
  850. {
  851. lpszErr = errs[n].lpszErr;
  852. break;
  853. }
  854. }
  855. return lpszErr;
  856. }/* McbGetError */
  857. /**
  858.  ****************************************************************************
  859.  * <P> Delete memory associated with a text node.   </P>
  860.  *
  861.  * @methodName  McbDeleteText
  862.  *
  863.  * @param       *pText
  864.  *
  865.  * @return      void
  866.  *
  867.  * @exception   none
  868.  *
  869.  * @author      Martyn C Brown
  870.  *
  871.  * @changeHistory  
  872.  * 20th August     2001  -  (V1.0) Creation (MCB)
  873.  ****************************************************************************
  874.  */
  875. void McbDeleteText(McbXMLText *pText)
  876. {
  877. assert(pText);
  878. if (pText->lpszValue)
  879. {
  880. free(pText->lpszValue);
  881. pText->lpszValue = NULL;
  882. }
  883. }/* McbDeleteText */
  884. /**
  885.  ****************************************************************************
  886.  * <P> Delete memory associated with a clear (unformatted) node.   </P>
  887.  *
  888.  * @methodName  McbDeleteClear
  889.  *
  890.  * @param       *pClear
  891.  *
  892.  * @return      void
  893.  *
  894.  * @exception   none
  895.  *
  896.  * @author      Martyn C Brown
  897.  *
  898.  * @changeHistory  
  899.  * 20th August     2001  -  (V1.0) Creation (MCB)
  900.  ****************************************************************************
  901.  */
  902. void McbDeleteClear(McbXMLClear *pClear)
  903. {
  904. assert(pClear);
  905. if (pClear->lpszValue)
  906. {
  907. free(pClear->lpszValue);
  908. pClear->lpszValue = NULL;
  909. }
  910. }/* McbDeleteClear */
  911. /**
  912.  ****************************************************************************
  913.  * <P> Delete a given node.  </P>
  914.  *
  915.  * @methodName  McbDeleteNode
  916.  *
  917.  * @param       *pEntry
  918.  *
  919.  * @return      void
  920.  *
  921.  * @exception   none
  922.  *
  923.  * @author      Martyn C Brown
  924.  *
  925.  * @changeHistory  
  926.  * 20th August     2001  -  (V1.0) Creation (MCB)
  927.  ****************************************************************************
  928.  */
  929. void McbDeleteNode(McbXMLNode *pEntry)
  930. {
  931. if (pEntry)
  932. {
  933. if (pEntry->type == eNodeEmpty)
  934. {
  935. return;
  936. }
  937.        /*
  938.         *********************************************************************
  939.         * Delete the appropriate node
  940.         *********************************************************************
  941.         */
  942. switch(pEntry->type)
  943. {
  944. case eNodeAttribute:
  945. McbDeleteAttribute(pEntry->node.pAttrib);
  946. break;
  947. case eNodeElement:
  948. McbDeleteElement(pEntry->node.pElement);
  949. break;
  950. case eNodeText:
  951. McbDeleteText(pEntry->node.pText);
  952. break;
  953. case eNodeClear:
  954. McbDeleteClear(pEntry->node.pClear);
  955. break;
  956. default:
  957. assert(TRUE);
  958. }
  959. free(pEntry->node.pAttrib);
  960. pEntry->type = eNodeEmpty;
  961. }
  962. }/* McbDeleteNode */
  963. /**
  964.  ****************************************************************************
  965.  * <P> Delete an element and all it's contained nodes.  </P>
  966.  *
  967.  * @methodName  McbDeleteElement
  968.  *
  969.  * @param       *pEntry
  970.  *
  971.  * @return      void
  972.  *
  973.  * @exception   none
  974.  *
  975.  * @author      Martyn C Brown
  976.  *
  977.  * @changeHistory  
  978.  * 20th August     2001  -  (V1.0) Creation (MCB)
  979.  ****************************************************************************
  980.  */
  981. void McbDeleteElement(McbXMLElement *pEntry)
  982. {
  983. int n;
  984. assert(pEntry);
  985.    /*
  986.     *************************************************************************
  987.     * Delete each node (this may recurse)
  988.     *************************************************************************
  989.     */
  990. for(n = 0; n<pEntry->nSize; n++)
  991. {
  992. McbDeleteNode(&pEntry->pEntries[n]);
  993. }
  994.    /*
  995.     *************************************************************************
  996.     * Cleanup the list of nodes
  997.     *************************************************************************
  998.     */
  999. pEntry->nMax = 0;
  1000. pEntry->nSize = 0;
  1001. free(pEntry->pEntries);
  1002. pEntry->pEntries = NULL;
  1003.    /*
  1004.     *************************************************************************
  1005.     * Delete the name of the element
  1006.     *************************************************************************
  1007.     */
  1008. if (pEntry->lpszName)
  1009. {
  1010. free(pEntry->lpszName);
  1011. pEntry->lpszName = NULL;
  1012. }
  1013. /* free(pEntry); */
  1014. }/* McbDeleteElement */
  1015. /**
  1016.  ****************************************************************************
  1017.  * <P> Attach nodes from one list to another.  </P>
  1018.  *
  1019.  * @methodName  McbAttachNodes
  1020.  *
  1021.  * @param       *pDst
  1022.  * @param       *pSrc
  1023.  * @param       nNum
  1024.  *
  1025.  * @return      void
  1026.  *
  1027.  * @exception   none
  1028.  *
  1029.  * @author      Martyn C Brown
  1030.  *
  1031.  * @changeHistory  
  1032.  * 14th August     2001  -  (V1.0) Creation (MCB)
  1033.  ****************************************************************************
  1034.  */
  1035. void McbAttachNodes(McbXMLNode *pDst, McbXMLNode *pSrc, int nNum)
  1036. {
  1037. int n;
  1038. for (n=0; n<nNum; n++)
  1039. {
  1040. pDst[n] = pSrc[n];
  1041. pSrc[n].type = eNodeEmpty;
  1042. }
  1043. }/* McbAttachNodes */
  1044. /**
  1045.  ****************************************************************************
  1046.  * <P> Reserve memory for additional nodes.  </P>
  1047.  *
  1048.  * @methodName  McbAllocNodes
  1049.  *
  1050.  * @param       *pEntry
  1051.  * @param       nGrowBy
  1052.  *
  1053.  * @return      void
  1054.  *
  1055.  * @exception   none
  1056.  *
  1057.  * @author      Martyn C Brown
  1058.  *
  1059.  * @changeHistory  
  1060.  * 15th August     2001  -  (V1.0) Creation (MCB)
  1061.  ****************************************************************************
  1062.  */
  1063. void McbAllocNodes(McbXMLElement *pEntry, int nGrowBy)
  1064. {
  1065. int nMax;
  1066. McbXMLNode * pNew;
  1067. assert(pEntry);
  1068. assert(nGrowBy > 0);
  1069.    /*
  1070.     *************************************************************************
  1071.     * Allocate storage for new nodes
  1072.     *************************************************************************
  1073.     */
  1074.     nMax = pEntry->nMax += nGrowBy;
  1075.     pNew = malloc(sizeof(McbXMLNode) * nMax);
  1076.    /*
  1077.     *************************************************************************
  1078.     * Attach old entries to the new storage
  1079.     *************************************************************************
  1080.     */
  1081.     McbAttachNodes(pNew, pEntry->pEntries, pEntry->nSize);
  1082. if (pEntry->pEntries)
  1083. {
  1084. free(pEntry->pEntries);
  1085. }
  1086.     pEntry->pEntries = pNew;
  1087. }/* McbAllocNodes */
  1088. /**
  1089.  ****************************************************************************
  1090.  * <P> Add an element node to the element.  </P>
  1091.  *
  1092.  * @methodName  McbAddElement
  1093.  *
  1094.  * @param       *pEntry
  1095.  * @param       lpszName
  1096.  * @param       nIsDeclaration
  1097.  * @param       nGrowBy
  1098.  *
  1099.  * @return      McbXMLElement *
  1100.  *
  1101.  * @exception   none
  1102.  *
  1103.  * @author      Martyn C Brown
  1104.  *
  1105.  * @changeHistory  
  1106.  * 20th August     2001  -  (V1.0) Creation (MCB)
  1107.  ****************************************************************************
  1108.  */
  1109. McbXMLElement * McbAddElement(McbXMLElement *pEntry, LPTSTR lpszName, 
  1110.  int nIsDeclaration, int nGrowBy)
  1111. {
  1112. McbXMLNode *pNode;
  1113. McbXMLElement * pElement;
  1114. assert(pEntry);
  1115. assert(nGrowBy > 0);
  1116.    /*
  1117.     *************************************************************************
  1118.     * Check we have enough storage
  1119.     *************************************************************************
  1120.     */
  1121. if (pEntry->nSize == pEntry->nMax)
  1122. {
  1123. McbAllocNodes(pEntry, nGrowBy);
  1124. }
  1125.    /*
  1126.     *************************************************************************
  1127.     * Obtain the new node, set the type and initialise it.
  1128.     *************************************************************************
  1129.     */
  1130. pNode = &pEntry->pEntries[pEntry->nSize];
  1131. pNode->type = eNodeElement;
  1132. pElement = malloc(sizeof(McbXMLElement));
  1133. pNode->node.pElement = pElement;
  1134. McbInitElement(pElement, pEntry, lpszName, nIsDeclaration);
  1135.    /*
  1136.     *************************************************************************
  1137.     * Increment the number of contained nodes
  1138.     *************************************************************************
  1139.     */
  1140. pEntry->nSize++;
  1141.    /*
  1142.     *************************************************************************
  1143.     * Return the new element.
  1144.     *************************************************************************
  1145.     */
  1146. return pElement;
  1147. }/* McbAddElement */
  1148. /**
  1149.  ****************************************************************************
  1150.  * <P> Add an attribute to an element.  </P>
  1151.  *
  1152.  * @methodName  McbAddAttribute
  1153.  *
  1154.  * @param       *pEntry
  1155.  * @param       lpszName
  1156.  * @param       lpszValue
  1157.  * @param       nGrowBy
  1158.  *
  1159.  * @return      McbXMLAttribute * 
  1160.  *
  1161.  * @exception   none
  1162.  *
  1163.  * @author      Martyn C Brown
  1164.  *
  1165.  * @changeHistory  
  1166.  * 14th August     2001  -  (V1.0) Creation (MCB)
  1167.  ****************************************************************************
  1168.  */
  1169. McbXMLAttribute * McbAddAttribute(McbXMLElement *pEntry, LPTSTR lpszName, 
  1170. LPTSTR lpszValue, int nGrowBy)
  1171. {
  1172. McbXMLNode *pNode;
  1173. McbXMLAttribute *pAttr;
  1174. assert(pEntry);
  1175. assert(nGrowBy > 0);
  1176.    /*
  1177.     *************************************************************************
  1178.     * Check we have enough storage
  1179.     *************************************************************************
  1180.     */
  1181. if (pEntry->nSize == pEntry->nMax)
  1182. {
  1183. McbAllocNodes(pEntry, nGrowBy);
  1184. }
  1185.    /*
  1186.     *************************************************************************
  1187.     * Obtain the new node, set the type and initialise it.
  1188.     *************************************************************************
  1189.     */
  1190. pNode = &pEntry->pEntries[pEntry->nSize];
  1191. pNode->type = eNodeAttribute;
  1192. pAttr = malloc(sizeof(McbXMLAttribute));
  1193. pNode->node.pAttrib = pAttr;
  1194. //pAttr->lpszName = lpszName;
  1195. //pAttr->lpszValue = lpszValue;
  1196. //toby add 2006/7/4 10:03
  1197. pAttr->lpszName = lpszName;//McbStrdup(lpszName,0);
  1198. pAttr->lpszValue = lpszValue;//McbStrdup(lpszValue,0);
  1199.    /*
  1200.     *************************************************************************
  1201.     * Increment the number of contained nodes
  1202.     *************************************************************************
  1203.     */
  1204. pEntry->nSize++;
  1205.    /*
  1206.     *************************************************************************
  1207.     * Return the new attribute.
  1208.     *************************************************************************
  1209.     */
  1210. return pAttr;
  1211. }/* McbAddAttribute */
  1212. /**
  1213.  ****************************************************************************
  1214.  * <P> Add text to the element.  </P>
  1215.  *
  1216.  * @methodName  * McbAddText
  1217.  *
  1218.  * @param       *pEntry
  1219.  * @param       lpszValue
  1220.  * @param       nGrowBy
  1221.  *
  1222.  * @return      McbXMLText
  1223.  *
  1224.  * @exception   none
  1225.  *
  1226.  * @author      Martyn C Brown
  1227.  *
  1228.  * @changeHistory  
  1229.  * 20th August     2001  -  (V1.0) Creation (MCB)
  1230.  ****************************************************************************
  1231.  */
  1232. McbXMLText * McbAddText(McbXMLElement *pEntry, LPTSTR lpszValue, int nGrowBy)
  1233. {
  1234. McbXMLNode *pNode;
  1235. McbXMLText *pText;
  1236. assert(pEntry);
  1237. assert(nGrowBy > 0);
  1238.    /*
  1239.     *************************************************************************
  1240.     * Check we have enough storage
  1241.     *************************************************************************
  1242.     */
  1243. if (pEntry->nSize == pEntry->nMax)
  1244. {
  1245. McbAllocNodes(pEntry, nGrowBy);
  1246. }
  1247.    /*
  1248.     *************************************************************************
  1249.     * Obtain the new node, set the type and initialise it.
  1250.     *************************************************************************
  1251.     */
  1252. pNode = &pEntry->pEntries[pEntry->nSize];
  1253. pNode->type = eNodeText;
  1254. pText = malloc(sizeof(McbXMLText));
  1255. pNode->node.pText = pText;
  1256. pText->lpszValue = lpszValue;
  1257.    /*
  1258.     *************************************************************************
  1259.     * Increment the number of contained nodes
  1260.     *************************************************************************
  1261.     */
  1262. pEntry->nSize++;
  1263.    /*
  1264.     *************************************************************************
  1265.     * Return the new attribute.
  1266.     *************************************************************************
  1267.     */
  1268. return pText;
  1269. }/* McbAddText */
  1270. /**
  1271.  ****************************************************************************
  1272.  * <P> Add clear (unformatted) to the element.  </P>
  1273.  *
  1274.  * @methodName  * McbAddClear
  1275.  *
  1276.  * @param       *pEntry
  1277.  * @param       lpszValue
  1278.  * @param       nGrowBy
  1279.  *
  1280.  * @return      McbXMLClear
  1281.  *
  1282.  * @exception   none
  1283.  *
  1284.  * @author      Martyn C Brown
  1285.  *
  1286.  * @changeHistory  
  1287.  * 20th August     2001  -  (V1.0) Creation (MCB)
  1288.  ****************************************************************************
  1289.  */
  1290. McbXMLClear * McbAddClear(McbXMLElement *pEntry, LPTSTR lpszValue, 
  1291. McbClearTag *pClear, int nGrowBy)
  1292. {
  1293. McbXMLNode *pNode;
  1294. McbXMLClear *pNewClear;
  1295. assert(pEntry);
  1296. assert(nGrowBy > 0);
  1297.    /*
  1298.     *************************************************************************
  1299.     * Check we have enough storage
  1300.     *************************************************************************
  1301.     */
  1302. if (pEntry->nSize == pEntry->nMax)
  1303. {
  1304. McbAllocNodes(pEntry, nGrowBy);
  1305. }
  1306.    /*
  1307.     *************************************************************************
  1308.     * Obtain the new node, set the type and initialise it.
  1309.     *************************************************************************
  1310.     */
  1311. pNode = &pEntry->pEntries[pEntry->nSize];
  1312. pNode->type = eNodeClear;
  1313. pNewClear = malloc(sizeof(McbXMLClear));
  1314. pNode->node.pClear = pNewClear;
  1315. pNewClear->lpszValue = lpszValue;
  1316. pNewClear->lpszOpenTag = pClear->lpszOpen;
  1317. pNewClear->lpszCloseTag = pClear->lpszClose;
  1318.    /*
  1319.     *************************************************************************
  1320.     * Increment the number of contained nodes
  1321.     *************************************************************************
  1322.     */
  1323. pEntry->nSize++;
  1324.    /*
  1325.     *************************************************************************
  1326.     * Return the new attribute.
  1327.     *************************************************************************
  1328.     */
  1329. return pNewClear;
  1330. }/* McbAddClear */
  1331. /**
  1332.  ****************************************************************************
  1333.  * <P> Enumerate nodes in the list.  </P>
  1334.  *
  1335.  * @methodName  McbEnumNodes
  1336.  *
  1337.  * @param       *pEntry
  1338.  * @param       *pnIndex
  1339.  *
  1340.  * @return      McbXMLNode
  1341.  *
  1342.  * @exception   none
  1343.  *
  1344.  * @author      Martyn C Brown
  1345.  *
  1346.  * @changeHistory  
  1347.  * 20th August     2001  -  (V1.0) Creation (MCB)
  1348.  ****************************************************************************
  1349.  */
  1350. McbXMLNode * McbEnumNodes(McbXMLElement *pEntry, int *pnIndex)
  1351. {
  1352. McbXMLNode * pResult = NULL;
  1353. assert(pnIndex);
  1354. assert(pEntry);
  1355. if (*pnIndex < pEntry->nSize)
  1356. {
  1357. pResult = &pEntry->pEntries[*pnIndex];
  1358. (*pnIndex)++;
  1359. }
  1360. return pResult;
  1361. }/* McbEnumNodes */
  1362. /**
  1363.  ****************************************************************************
  1364.  * <P> Enumerate elements on a base element.  </P>
  1365.  *
  1366.  * @methodName  McbEnumElements
  1367.  *
  1368.  * @param       *pEntry
  1369.  * @param       *pnIndex
  1370.  *
  1371.  * @return      McbXMLNode
  1372.  *
  1373.  * @exception   none
  1374.  *
  1375.  * @author      Martyn C Brown
  1376.  *
  1377.  * @changeHistory  
  1378.  * 20th August     2001  -  (V1.0) Creation (MCB)
  1379.  ****************************************************************************
  1380.  */
  1381. McbXMLElement * McbEnumElements(McbXMLElement *pEntry, int *pnIndex)
  1382. {
  1383. McbXMLElement * pResult = NULL;
  1384. int nIndex;
  1385. assert(pnIndex);
  1386. assert(pEntry);
  1387. nIndex = *pnIndex;
  1388. for (;nIndex < pEntry->nSize && !pResult; nIndex++)
  1389. {
  1390. if (pEntry->pEntries[nIndex].type == eNodeElement)
  1391. {
  1392. pResult = pEntry->pEntries[nIndex].node.pElement;
  1393. }
  1394. }
  1395. *pnIndex = nIndex;
  1396. return pResult;
  1397. }/* McbEnumElements */
  1398. /**
  1399.  ****************************************************************************
  1400.  * <P> Enumerate attributes on a base element.  </P>
  1401.  *
  1402.  * @methodName  McbEnumAttributes
  1403.  *
  1404.  * @param       *pEntry
  1405.  * @param       *pnIndex
  1406.  *
  1407.  * @return      McbXMLNode
  1408.  *
  1409.  * @exception   none
  1410.  *
  1411.  * @author      Martyn C Brown
  1412.  *
  1413.  * @changeHistory  
  1414.  * 20th August     2001  -  (V1.0) Creation (MCB)
  1415.  ****************************************************************************
  1416.  */
  1417. McbXMLAttribute * McbEnumAttributes(McbXMLElement *pEntry, int *pnIndex)
  1418. {
  1419. McbXMLAttribute * pResult = NULL;
  1420. int nIndex;
  1421. assert(pnIndex);
  1422. assert(pEntry);
  1423. nIndex = *pnIndex;
  1424. for (;nIndex < pEntry->nSize && !pResult; nIndex++)
  1425. {
  1426. if (pEntry->pEntries[nIndex].type == eNodeAttribute)
  1427. {
  1428. pResult = pEntry->pEntries[nIndex].node.pAttrib;
  1429. }
  1430. }
  1431. *pnIndex = nIndex;
  1432. return pResult;
  1433. }/* McbEnumAttributes */
  1434. /**
  1435.  ****************************************************************************
  1436.  * <P> Trim the end of the text to remove white space characters.  </P>
  1437.  *
  1438.  * @methodName  McbFindEndOfText
  1439.  *
  1440.  * @param       lpszToken
  1441.  * @param       *pcbText
  1442.  *
  1443.  * @return      void
  1444.  *
  1445.  * @exception   none
  1446.  *
  1447.  * @author      Martyn C Brown
  1448.  *
  1449.  * @changeHistory  
  1450.  * 20th August     2001  -  (V1.0) Creation (MCB)
  1451.  ****************************************************************************
  1452.  */
  1453. void McbFindEndOfText(LPCTSTR lpszToken, int *pcbText)
  1454. {
  1455. TCHAR ch;
  1456. int cbText;
  1457. assert(lpszToken);
  1458. assert(pcbText);
  1459. cbText = (*pcbText)-1;
  1460. while(TRUE)
  1461. {
  1462. assert(cbText >= 0);
  1463. ch = lpszToken[cbText];
  1464. switch(ch)
  1465. {
  1466. case _T('r'):
  1467. case _T('n'):
  1468. case _T('t'):
  1469. case _T(' '):
  1470. cbText--;
  1471. break;
  1472. default:
  1473. *pcbText = cbText+1;
  1474. return;
  1475. }
  1476. }
  1477. }/* McbFindEndOfText */
  1478. /**
  1479.  ****************************************************************************
  1480.  * <P> Parse a clear (unformatted) type node.  </P>
  1481.  *
  1482.  * @methodName  McbParseClearTag
  1483.  *
  1484.  * @param       *pXML
  1485.  * @param       *pElement
  1486.  * @param       lpszClose
  1487.  * @param       lpszToken
  1488.  *
  1489.  * @return      int
  1490.  *
  1491.  * @exception   none
  1492.  *
  1493.  * @author      Martyn C Brown
  1494.  *
  1495.  * @changeHistory  
  1496.  * 26th August     2001  -  (V1.0) Creation (MCB)
  1497.  ****************************************************************************
  1498.  */
  1499. int McbParseClearTag(McbXML *pXML, McbXMLElement *pElement, McbClearTag * pClear)
  1500. {
  1501. int cbTemp = 0;
  1502. LPTSTR lpszTemp;
  1503. LPCTSTR lpszXML = &pXML->lpXML[pXML->nIndex];
  1504.    /*
  1505.     *************************************************************************
  1506.     * Find the closing tag
  1507.     *************************************************************************
  1508.     */
  1509. lpszTemp = _tcsstr(lpszXML, pClear->lpszClose);
  1510.    /*
  1511.     *************************************************************************
  1512.     * Iterate through the tokens until we find the closing tag.
  1513.     *************************************************************************
  1514.     */
  1515.     if (lpszTemp)
  1516.     {
  1517.        /*
  1518.         *********************************************************************
  1519.         * Cache the size and increment the index
  1520.         *********************************************************************
  1521.         */
  1522.         cbTemp = lpszTemp - lpszXML;
  1523. pXML->nIndex += cbTemp;
  1524. pXML->nIndex += _tcslen(pClear->lpszClose);
  1525.         
  1526.        /*
  1527.         *********************************************************************
  1528.         * Add the clear node to the current element
  1529.         *********************************************************************
  1530.         */
  1531.         lpszTemp = McbStrdup(lpszXML, cbTemp);
  1532.         McbAddClear(pElement, lpszTemp, pClear, McbGROWBY);
  1533. #ifdef McbSTOREOFFSETS
  1534. pElement->pEntries[pElement->nSize-1].nStringOffset = (lpszXML -
  1535. _tcslen(pClear->lpszOpen)) - pXML->lpXML;
  1536. #endif /* McbSTOREOFFSETS */
  1537.         return TRUE;
  1538.     }
  1539.    /*
  1540.     *************************************************************************
  1541.     * If we failed to find the end tag
  1542.     *************************************************************************
  1543.     */
  1544.     else
  1545.     {
  1546.         pXML->error = eXMLErrorUnmatchedEndTag;
  1547.         return FALSE;
  1548.     }
  1549. }/* McbParseClearTag */
  1550. /**
  1551.  ****************************************************************************
  1552.  * <P> Recursively parse an XML element.  </P>
  1553.  *
  1554.  * @methodName  McbParseXMLElement
  1555.  *
  1556.  * @param       *pXML
  1557.  * @param       * pElement
  1558.  *
  1559.  * @return      int
  1560.  *
  1561.  * @exception   none
  1562.  *
  1563.  * @author      Martyn C Brown
  1564.  *
  1565.  * @changeHistory  
  1566.  * 19th August     2001  -  (V1.0) Creation (MCB)
  1567.  ****************************************************************************
  1568.  */
  1569. int McbParseXMLElement(McbXML *pXML, McbXMLElement * pElement)
  1570. {
  1571. LPCTSTR lpszToken;
  1572. int cbToken;
  1573. enum McbTokenType type;
  1574. McbNextToken token;
  1575. LPCTSTR lpszTemp;
  1576. int cbTemp;
  1577. int nDeclaration;
  1578. LPCTSTR lpszText = NULL;
  1579. McbXMLElement *pNew;
  1580. enum McbStatus status;
  1581. enum McbAttrib attrib = eAttribName;
  1582. assert(pXML);
  1583. assert(pElement);
  1584.    /*
  1585.     *************************************************************************
  1586.     * If this is the first call to the function
  1587.     *************************************************************************
  1588.     */
  1589. if (pXML->nFirst)
  1590. {
  1591.        /*
  1592.         *********************************************************************
  1593.         * Assume we are outside of a tag definition
  1594.         *********************************************************************
  1595.         */
  1596. pXML->nFirst = FALSE;
  1597. status = eOutsideTag;
  1598. }
  1599.    /*
  1600.     *************************************************************************
  1601.     * If this is not the first call then we should only be called when inside
  1602. * a tag.
  1603.     *************************************************************************
  1604.     */
  1605.     else 
  1606. {
  1607. status = eInsideTag;
  1608. }
  1609.    /*
  1610.     *************************************************************************
  1611.     * Iterate through the tokens in the document
  1612.     *************************************************************************
  1613.     */
  1614. while(TRUE)
  1615. {
  1616.        /*
  1617.         *********************************************************************
  1618.         * Obtain the next token
  1619.         *********************************************************************
  1620.         */
  1621. token = McbGetNextToken(pXML, &cbToken, &type);
  1622.   if (type != eTokenError)
  1623. {
  1624.            /*
  1625.             *****************************************************************
  1626.             * Check the current status
  1627.             *****************************************************************
  1628.             */
  1629. switch(status)
  1630. {
  1631.            /*
  1632.             *****************************************************************
  1633.             * If we outside of a tag definition
  1634.             *****************************************************************
  1635.             */
  1636. case eOutsideTag:
  1637.                /*
  1638.                 *************************************************************
  1639.                 * Check what type of token we obtained
  1640.                 *************************************************************
  1641.                 */
  1642. switch(type)
  1643. {
  1644.                /*
  1645.                 *************************************************************
  1646.                 * If we have found text or quoted text
  1647.                 *************************************************************
  1648.                 */
  1649. case eTokenText:
  1650. case eTokenQuotedText:
  1651. case eTokenEquals:
  1652. if (!lpszText)
  1653. {
  1654. lpszText = token.pStr;
  1655. }
  1656. break;
  1657.                /*
  1658.                 *************************************************************
  1659.                 * If we found a start tag '<' and declarations '<?'
  1660.                 *************************************************************
  1661.                 */
  1662. case eTokenTagStart:
  1663. case eTokenDeclaration:
  1664.                    /*
  1665.                     *********************************************************
  1666.                     * Cache whether this new element is a declaration or not
  1667.                     *********************************************************
  1668.                     */
  1669. nDeclaration = type == eTokenDeclaration;
  1670.                    /*
  1671.                     *********************************************************
  1672.                     * If we have node text then add this to the element
  1673.                     *********************************************************
  1674.                     */
  1675. if (lpszText)
  1676. {
  1677. cbTemp = token.pStr - lpszText;
  1678. McbFindEndOfText(lpszText, &cbTemp);
  1679. McbAddText(pElement, McbStrdup(lpszText, cbTemp), 
  1680. McbGROWBY);
  1681. #ifdef McbSTOREOFFSETS
  1682. pElement->pEntries[pElement->nSize-1].nStringOffset
  1683. = lpszText - pXML->lpXML;
  1684. #endif /* McbSTOREOFFSETS */
  1685. lpszText = NULL;
  1686. }
  1687.                    /*
  1688.                     *********************************************************
  1689.                     * Find the name of the tag
  1690.                     *********************************************************
  1691.                     */
  1692. token = McbGetNextToken(pXML, &cbToken, &type);
  1693.                    /*
  1694.                     *********************************************************
  1695.                     * Return an error if we couldn't obtain the next token or
  1696. * it wasnt text
  1697.                     *********************************************************
  1698.                     */
  1699. if (type != eTokenText)
  1700. {
  1701. pXML->error = eXMLErrorMissingTagName;
  1702. return FALSE;
  1703. }
  1704.                    /*
  1705.                     *********************************************************
  1706.                     * If we found a new element which has the same as this 
  1707. * element then we need to pass this back to the caller..
  1708.                     *********************************************************
  1709.                     */
  1710. if (pElement->lpszName && 
  1711. _tcsnicmp(pElement->lpszName, token.pStr, 
  1712. _tcslen(pElement->lpszName)) == 0)
  1713. {
  1714.                        /*
  1715.                         *****************************************************
  1716.                         * Indicate to the caller that it needs to create a 
  1717. * new element.
  1718.                         *****************************************************
  1719.                         */
  1720.                         pXML->lpNewElement = token.pStr;
  1721.                         pXML->cbNewElement = cbToken;
  1722. return TRUE;
  1723. }
  1724.                    /*
  1725.                     *********************************************************
  1726.                     * If the name of the new element differs from the name of
  1727. * the current element we need to add the new element to 
  1728. * the current one and recurse
  1729.                     *********************************************************
  1730.                     */
  1731. else
  1732. {
  1733.                        /*
  1734.                         *****************************************************
  1735.                         * Now we need to add the new element and recurse
  1736.                         *****************************************************
  1737.                         */
  1738.                         pNew = McbAddElement(pElement, 
  1739.                             McbStrdup(token.pStr, cbToken), nDeclaration, 
  1740. McbGROWBY);
  1741. #ifdef McbSTOREOFFSETS
  1742. pElement->pEntries[pElement->nSize-1].nStringOffset = 
  1743. token.pStr - pXML->lpXML;
  1744. #endif /* McbSTOREOFFSETS */
  1745. while(pNew)
  1746.                         {
  1747.                            /*
  1748.                             *************************************************
  1749.                             * Callself to process the new node.  If we return 
  1750.                             * FALSE this means we dont have any more 
  1751. * processing to do...
  1752.                             *************************************************
  1753.                             */
  1754.                             if (!McbParseXMLElement(pXML, pNew))
  1755.                             {
  1756.                                 return FALSE;
  1757.                             }
  1758.                             else
  1759.                             {
  1760.                                /*
  1761.                                 *********************************************
  1762.                                 * If the call to recurse this function 
  1763. * evented in a end tag specified in XML then 
  1764. * we need to unwind the calls to this 
  1765. * function until we find the appropriate node 
  1766. * (the element name and end tag name must 
  1767. * match)
  1768.                                 *********************************************
  1769.                                 */
  1770.                                 if (pXML->cbEndTag)
  1771.                                 {
  1772.                                    /*
  1773.                                     *****************************************
  1774.                                     * If we are back at the root node then we 
  1775.                                     * have an unmatched end tag
  1776.                                     *****************************************
  1777.                                     */
  1778.                                     if (!pElement->lpszName)
  1779.                                     {
  1780.                                         pXML->error = 
  1781. eXMLErrorUnmatchedEndTag;
  1782.                                         return FALSE;
  1783.                                     }
  1784.                                    /*
  1785.                                     *****************************************
  1786.                                     * If the end tag matches the name of this 
  1787.                                     * element then we only need to unwind 
  1788.                                     * once more...
  1789.                                     *****************************************
  1790.                                     */
  1791.                                     if (_tcsnicmp(pXML->lpEndTag, 
  1792.                                         pElement->lpszName, 
  1793. _tcslen(pElement->lpszName)) == 0)
  1794.                                     {                                    
  1795.                                         pXML->cbEndTag = 0;
  1796.                                     }
  1797.                                     return TRUE;
  1798.                                 }
  1799.                                /*
  1800.                                 *********************************************
  1801.                                 * If the call indicated a new element is to 
  1802.                                 * be created on THIS element.
  1803.                                 *********************************************
  1804.                                 */
  1805.                                 else if (pXML->cbNewElement)
  1806.                                 {
  1807.                                    /*
  1808.                                     *****************************************
  1809.                                     * If the name of this element matches the
  1810. * name of the element we need to create 
  1811. * then we need to return to the caller 
  1812. * and let it process the element.
  1813.                                     *****************************************
  1814.                                     */
  1815. if (_tcsnicmp(pXML->lpNewElement, 
  1816.                                         pElement->lpszName, 
  1817. _tcslen(pElement->lpszName)) == 0)
  1818.                                     {                                    
  1819.                                         return TRUE;
  1820.                                     }
  1821.                                    /*
  1822.                                     *****************************************
  1823.                                     * Add the new element and recurse
  1824.                                     *****************************************
  1825.                                     */
  1826.                                     pNew = McbAddElement(pElement, 
  1827.                                         McbStrdup(pXML->lpNewElement, 
  1828.                                         pXML->cbNewElement), FALSE, 
  1829. McbGROWBY);
  1830. #ifdef McbSTOREOFFSETS
  1831. pElement->pEntries[pElement->nSize-1].
  1832. nStringOffset = 
  1833. pXML->lpNewElement - pXML->lpXML;
  1834. #endif /* McbSTOREOFFSETS */
  1835. pXML->cbNewElement = 0;
  1836. }
  1837.                                /*
  1838.                                 *********************************************
  1839.                                 * If we didn't have a new element to create
  1840.                                 *********************************************
  1841.                                 */
  1842.                                 else 
  1843. {
  1844. pNew = NULL;
  1845. }
  1846. }
  1847. }
  1848. }
  1849. break;
  1850.                /*
  1851.                 *************************************************************
  1852.                 * If we found an end tag
  1853.                 *************************************************************
  1854.                 */
  1855. case eTokenTagEnd:
  1856.                    /*
  1857.                     *********************************************************
  1858.                     * If we have node text then add this to the element
  1859.                     *********************************************************
  1860.                     */
  1861. if (lpszText)
  1862. {
  1863. cbTemp = token.pStr - lpszText;
  1864. McbFindEndOfText(lpszText, &cbTemp);
  1865. McbAddText(pElement, McbStrdup(lpszText, cbTemp), 
  1866. McbGROWBY);
  1867. #ifdef McbSTOREOFFSETS
  1868. pElement->pEntries[pElement->nSize-1].nStringOffset
  1869. = lpszText - pXML->lpXML;
  1870. #endif /* McbSTOREOFFSETS */
  1871. lpszText = NULL;
  1872. }
  1873.                    /*
  1874.                     *********************************************************
  1875.                     * Find the name of the end tag
  1876.                     *********************************************************
  1877.                     */
  1878. token = McbGetNextToken(pXML, &cbTemp, &type);
  1879.                    /*
  1880.                     *********************************************************
  1881.                     * The end tag should be text
  1882.                     *********************************************************
  1883.                     */
  1884. if (type != eTokenText)
  1885. {
  1886. pXML->error = eXMLErrorMissingEndTagName;
  1887. return FALSE;
  1888. }
  1889. lpszTemp = token.pStr;
  1890.                    /*
  1891.                     *********************************************************
  1892.                     * After the end tag we should find a closing tag
  1893.                     *********************************************************
  1894.                     */
  1895. token = McbGetNextToken(pXML, &cbToken, &type);
  1896. if (type != eTokenCloseTag)
  1897. {
  1898. pXML->error = eXMLErrorMissingEndTagName;
  1899. return FALSE;
  1900. }
  1901.                    /*
  1902.                     *********************************************************
  1903. * We need to return to the previous caller.  If the name 
  1904. * of the tag cannot be found we need to keep returning to
  1905. * caller until we find a match
  1906.                     *********************************************************
  1907.                     */
  1908. if (_tcsnicmp(lpszTemp, pElement->lpszName, 
  1909. _tcslen(pElement->lpszName)) != 0)
  1910. {
  1911. pXML->lpEndTag = lpszTemp;
  1912. pXML->cbEndTag = cbTemp;
  1913. }
  1914.                    /*
  1915.                     *********************************************************
  1916.                     * Return to the caller
  1917.                     *********************************************************
  1918.                     */
  1919. return TRUE;
  1920.                /*
  1921.                 *************************************************************
  1922.                 * If we found a clear (unformatted) token
  1923.                 *************************************************************
  1924.                 */
  1925. case eTokenClear:
  1926.                    /*
  1927.                     *********************************************************
  1928.                     * If we have node text then add this to the element
  1929.                     *********************************************************
  1930.                     */
  1931. if (lpszText)
  1932. {
  1933. cbTemp = token.pStr - lpszText;
  1934. McbFindEndOfText(lpszText, &cbTemp);
  1935. McbAddText(pElement, McbStrdup(lpszText, cbTemp), 
  1936. McbGROWBY);
  1937. #ifdef McbSTOREOFFSETS
  1938. pElement->pEntries[pElement->nSize-1].nStringOffset
  1939. = lpszText - pXML->lpXML;
  1940. #endif /* McbSTOREOFFSETS */
  1941. lpszText = NULL;
  1942. }
  1943. if (!McbParseClearTag(pXML, pElement, token.pClr))
  1944. {
  1945. return FALSE;
  1946. }
  1947. break;
  1948.                /*
  1949.                 *************************************************************
  1950.                 * Errors...
  1951.                 *************************************************************
  1952.                 */
  1953. case eTokenCloseTag: /* '>' */
  1954. case eTokenShortHandClose: /* '/>' */
  1955. pXML->error = eXMLErrorUnexpectedToken;
  1956. return FALSE;
  1957. }
  1958. break;
  1959.            /*
  1960.             *****************************************************************
  1961.             * If we are inside a tag definition we need to search for 
  1962. * attributes
  1963.             *****************************************************************
  1964.             */
  1965. case eInsideTag:
  1966.                /*
  1967.                 *************************************************************
  1968.                 * Check what part of the attribute (name, equals, value) we 
  1969. * are looking for.
  1970.                 *************************************************************
  1971.                 */
  1972.                 switch(attrib)
  1973.                 {
  1974.                /*
  1975.                 ************************************************************
  1976.                 * If we are looking for a new attribute
  1977.                 ************************************************************
  1978.                 */
  1979.                 case eAttribName:
  1980.                    /*
  1981.                     *********************************************************
  1982.                     * Check what the current token type is
  1983.                     *********************************************************
  1984.                     */
  1985. switch(type)
  1986. {
  1987.                    /*
  1988.                     *********************************************************
  1989.                     * If the current type is text...
  1990. * Eg.  'attribute'
  1991.                     *********************************************************
  1992.                     */
  1993. case eTokenText:
  1994.                        /*
  1995.                         *****************************************************
  1996.                         * Cache the token then indicate that we are next to 
  1997. * look for the equals
  1998.                         *****************************************************
  1999.                         */
  2000. lpszTemp = token.pStr;
  2001. cbTemp = cbToken;
  2002. attrib = eAttribEquals;
  2003. break;
  2004.                    /*
  2005.                     *********************************************************
  2006.                     * If we found a closing tag...
  2007. * Eg.  '>'
  2008.                     *********************************************************
  2009.                     */
  2010. case eTokenCloseTag:
  2011.                        /*
  2012.                         *****************************************************
  2013.                         * We are now outside the tag
  2014.                         *****************************************************
  2015.                         */
  2016. status = eOutsideTag;
  2017. break;
  2018.                    /*
  2019.                     *********************************************************
  2020.                     * If we found a short hand '/>' closing tag then we can 
  2021. * return to the caller
  2022.                     *********************************************************
  2023.                     */
  2024. case eTokenShortHandClose:
  2025. return TRUE;
  2026.                    /*
  2027.                     *********************************************************
  2028.                     * Errors...
  2029.                     *********************************************************
  2030.                     */
  2031. case eTokenQuotedText: /* '"SomeText"' */
  2032. case eTokenTagStart: /* '<' */
  2033. case eTokenTagEnd: /* '</' */
  2034. case eTokenEquals: /* '=' */
  2035. case eTokenDeclaration: /* '<?' */
  2036. case eTokenClear:
  2037. pXML->error = eXMLErrorUnexpectedToken;
  2038. return FALSE;
  2039. }
  2040. break;
  2041.                /*
  2042.                 ************************************************************
  2043.                 * If we are looking for an equals
  2044.                 ************************************************************
  2045.                 */
  2046.                 case eAttribEquals:
  2047.                    /*
  2048.                     *********************************************************
  2049.                     * Check what the current token type is
  2050.                     *********************************************************
  2051.                     */
  2052. switch(type)
  2053. {
  2054.                    /*
  2055.                     *********************************************************
  2056.                     * If the current type is text...
  2057. * Eg.  'Attribute AnotherAttribute'
  2058.                     *********************************************************
  2059.                     */
  2060. case eTokenText:
  2061.                        /*
  2062.                         *****************************************************
  2063.                         * Add the unvalued attribute to the list
  2064.                         *****************************************************
  2065.                         */
  2066. McbAddAttribute(pElement, McbStrdup(lpszTemp, 
  2067. cbTemp), NULL, McbGROWBY);
  2068. #ifdef McbSTOREOFFSETS
  2069. pElement->pEntries[pElement->nSize-1].nStringOffset =
  2070. lpszTemp - pXML->lpXML;
  2071. #endif /* McbSTOREOFFSETS */
  2072.                        /*
  2073.                         *****************************************************
  2074.                         * Cache the token then indicate.  We are next to 
  2075. * look for the equals attribute
  2076.                         *****************************************************
  2077.                         */
  2078. lpszTemp = token.pStr;
  2079. cbTemp = cbToken;
  2080. break;
  2081.                    /*
  2082.                     *********************************************************
  2083.                     * If we found a closing tag 'Attribute >' or a short hand 
  2084. * closing tag 'Attribute />'
  2085.                     *********************************************************
  2086.                     */
  2087. case eTokenShortHandClose:
  2088. case eTokenCloseTag:
  2089.                        /*
  2090.                         *****************************************************
  2091.                         * If we are a declaration element '<?' then we need
  2092. * to remove extra closing '?' if it exists
  2093.                         *****************************************************
  2094.                         */
  2095. if (pElement->nIsDeclaration && 
  2096. (lpszTemp[cbTemp-1]) == _T('?'))
  2097. {
  2098. cbTemp--;
  2099. }
  2100. if (cbTemp)
  2101. {
  2102.                            /*
  2103.                             *************************************************
  2104.                             * Add the unvalued attribute to the list
  2105.                             *************************************************
  2106.                             */
  2107.                             McbAddAttribute(pElement, McbStrdup(lpszTemp, 
  2108.                                 cbTemp), NULL, McbGROWBY);
  2109. #ifdef McbSTOREOFFSETS
  2110. pElement->pEntries[pElement->nSize-1].
  2111. nStringOffset = lpszTemp - pXML->lpXML;
  2112. #endif /* McbSTOREOFFSETS */
  2113. }
  2114.                        /*
  2115.                         *****************************************************
  2116.                         * If this is the end of the tag then return to the 
  2117. * caller
  2118.                         *****************************************************
  2119.                         */
  2120. if (type == eTokenShortHandClose)
  2121. {
  2122. return TRUE;
  2123. }
  2124.                        /*
  2125.                         *****************************************************
  2126.                         * We are now outside the tag
  2127.                         *****************************************************
  2128.                         */
  2129. status = eOutsideTag;
  2130. break;
  2131.                    /*
  2132.                     *********************************************************
  2133.                     * If we found the equals token...
  2134. * Eg.  'Attribute ='
  2135.                     *********************************************************
  2136.                     */
  2137. case eTokenEquals:
  2138.                        /*
  2139.                         *****************************************************
  2140.                         * Indicate that we next need to search for the value
  2141. * for the attribute
  2142.                         *****************************************************
  2143.                         */
  2144. attrib = eAttribValue;
  2145. break;
  2146.                    /*
  2147.                     *********************************************************
  2148.                     * Errors...
  2149.                     *********************************************************
  2150.                     */
  2151. case eTokenQuotedText: /* 'Attribute "InvalidAttr"'*/
  2152. case eTokenTagStart: /* 'Attribute <' */
  2153. case eTokenTagEnd: /* 'Attribute </' */
  2154. case eTokenDeclaration: /* 'Attribute <?' */
  2155. case eTokenClear:
  2156. pXML->error = eXMLErrorUnexpectedToken;
  2157. return FALSE;
  2158. }
  2159. break;
  2160.                /*
  2161.                 ************************************************************
  2162.                 * If we are looking for an attribute value
  2163.                 ************************************************************
  2164.                 */
  2165.                 case eAttribValue:
  2166.                    /*
  2167.                     *********************************************************
  2168.                     * Check what the current token type is
  2169.                     *********************************************************
  2170.                     */
  2171. switch(type)
  2172. {
  2173.                    /*
  2174.                     *********************************************************
  2175.                     * If the current type is text or quoted text...
  2176. * Eg.  'Attribute = "Value"' or 'Attribute = Value' or
  2177. * 'Attribute = 'Value''.
  2178.                     *********************************************************
  2179.                     */
  2180. case eTokenText:
  2181. case eTokenQuotedText:
  2182.                        /*
  2183.                         *****************************************************
  2184.                         * If we are a declaration element '<?' then we need
  2185. * to remove extra closing '?' if it exists
  2186.                         *****************************************************
  2187.                         */
  2188. if (pElement->nIsDeclaration && 
  2189. (token.pStr[cbToken-1]) == _T('?'))
  2190. {
  2191. cbToken--;
  2192. }
  2193. if (cbTemp)
  2194. {
  2195. lpszToken = McbStrdup(token.pStr, cbToken);
  2196. }
  2197. else
  2198. {
  2199. lpszToken = NULL;
  2200. }
  2201.                        /*
  2202.                         *****************************************************
  2203.                         * Add the valued attribute to the list
  2204.                         *****************************************************
  2205.                         */
  2206.                         McbAddAttribute(pElement, McbStrdup(lpszTemp, 
  2207.                             cbTemp), (LPTSTR)lpszToken, McbGROWBY);
  2208. #ifdef McbSTOREOFFSETS
  2209. pElement->pEntries[pElement->nSize-1].nStringOffset
  2210. = lpszTemp - pXML->lpXML;
  2211. #endif /* McbSTOREOFFSETS */
  2212.                        /*
  2213.                         *****************************************************
  2214.                         * Indicate we are searching for a new attribute
  2215.                         *****************************************************
  2216.                         */
  2217. attrib = eAttribName;
  2218. break;
  2219.                    /*
  2220.                     *********************************************************
  2221.                     * Errors...
  2222.                     *********************************************************
  2223.                     */
  2224. case eTokenTagStart: /* 'Attr = <' */
  2225. case eTokenTagEnd: /* 'Attr = </' */
  2226. case eTokenCloseTag: /* 'Attr = >' */
  2227. case eTokenShortHandClose: /* "Attr = />" */
  2228. case eTokenEquals: /* 'Attr = =' */
  2229. case eTokenDeclaration: /* 'Attr = <?' */
  2230. case eTokenClear:
  2231. pXML->error = eXMLErrorUnexpectedToken;
  2232. return FALSE;
  2233. break;
  2234. }
  2235. }
  2236. }
  2237. }
  2238.        /*
  2239.         *********************************************************************
  2240.         * If we failed to obtain the next token
  2241.         *********************************************************************
  2242.         */
  2243.         else 
  2244.         {
  2245.         return FALSE;
  2246.         }
  2247. }
  2248. }/* McbParseXMLElement */
  2249. /**
  2250.  ****************************************************************************
  2251.  * <P> Count the number of lines and columns in an XML string.  </P>
  2252.  *
  2253.  * @methodName  McbCountLinesAndColumns
  2254.  *
  2255.  * @param       lpXML
  2256.  * @param       nUpto
  2257.  * @param       *pResults
  2258.  *
  2259.  * @return      void
  2260.  *
  2261.  * @exception   none
  2262.  *
  2263.  * @author      Martyn C Brown
  2264.  *
  2265.  * @changeHistory  
  2266.  * 21st August     2001  -  (V1.0) Creation (MCB)
  2267.  ****************************************************************************
  2268.  */
  2269. void McbCountLinesAndColumns(LPCTSTR lpXML, int nUpto, McbXMLResults *pResults)
  2270. {
  2271. TCHAR ch;
  2272. int n;
  2273. assert(lpXML);
  2274. assert(pResults);
  2275. pResults->nLine = 1;
  2276. pResults->nColumn = 1;
  2277. for(n=0; n<nUpto; n++)
  2278. {
  2279. ch = lpXML[n];
  2280. assert(ch);
  2281. if (ch == _T('n'))
  2282. {
  2283. pResults->nLine++;
  2284. pResults->nColumn = 1;
  2285. }
  2286. else
  2287. {
  2288. pResults->nColumn++;
  2289. }
  2290. }
  2291. }/* McbCountLinesAndColumns */
  2292. /**
  2293.  ****************************************************************************
  2294.  * <P> Obtain tags used for unformatted text within elements.  </P>
  2295.  *
  2296.  * @methodName  * McbGetClearTags
  2297.  *
  2298.  * @param       none
  2299.  *
  2300.  * @return      McbClearTag
  2301.  *
  2302.  * @exception   none
  2303.  *
  2304.  * @author      Martyn C Brown
  2305.  *
  2306.  * @changeHistory  
  2307.  * 3rd February   2002  -  (V1.0) Creation (MCB)
  2308.  ****************************************************************************
  2309.  */
  2310. McbClearTag * McbGetClearTags()
  2311. {
  2312. static struct McbClearTag tags[] =
  2313. {
  2314. { _T("<![CDATA["), _T("]]>") },
  2315. { _T("<PRE>"), _T("</PRE>") },
  2316. { _T("<Script>"), _T("</Script>") },
  2317. { _T("<!--"), _T("-->") },
  2318. { _T("<!DOCTYPE"), _T(">") },
  2319. { NULL, NULL }
  2320. };
  2321. return tags;
  2322. }/* McbGetClearTags */
  2323. #define McbGETCDATA() &McbGetClearTags()[0]
  2324. /**
  2325.  ****************************************************************************
  2326.  * <P> Parse XML and return the root element.  </P>
  2327.  *
  2328.  * @methodName  * McbParseXML
  2329.  *
  2330.  * @param       lpszXML
  2331.  * @param       *pResults
  2332.  *
  2333.  * @return      McbXMLElement
  2334.  *
  2335.  * @exception   none
  2336.  *
  2337.  * @author      Martyn C Brown
  2338.  *
  2339.  * @changeHistory  
  2340.  * 20th August     2001  -  (V1.0) Creation (MCB)
  2341.  ****************************************************************************
  2342.  */
  2343. McbXMLElement * McbParseXML(LPCTSTR lpszXML, McbXMLResults *pResults)
  2344. {
  2345. enum McbXMLError error;
  2346. struct McbXMLElement * pElement = NULL;
  2347. struct McbXML xml = 
  2348. { NULL, 0, 0, NULL, 0, NULL, 0, TRUE };
  2349. xml.lpXML = lpszXML;
  2350. xml.pClrTags = McbGetClearTags();
  2351.    /*
  2352.     *************************************************************************
  2353.     * Create header element
  2354.     *************************************************************************
  2355.     */
  2356. pElement = McbCreateRoot();
  2357. McbParseXMLElement(&xml, pElement);
  2358. error = xml.error;
  2359.    /*
  2360.     *************************************************************************
  2361.     * If an error occurred
  2362.     *************************************************************************
  2363.     */
  2364. if (error != eXMLErrorNone)
  2365. {
  2366.        /*
  2367.         *********************************************************************
  2368.         * Cleanup
  2369.         *********************************************************************
  2370.         */
  2371. McbDeleteRoot(pElement);
  2372. pElement = NULL;
  2373. }
  2374.    /*
  2375.     *************************************************************************
  2376.     * If we hae been given somewhere to place results
  2377.     *************************************************************************
  2378.     */
  2379. if (pResults)
  2380. {
  2381. pResults->error = error;
  2382.        /*
  2383.         *********************************************************************
  2384.         * If we have an error
  2385.         *********************************************************************
  2386.         */
  2387. if (error != eXMLErrorNone)
  2388. {
  2389.            /*
  2390.             *****************************************************************
  2391.             * Find which line and column it starts on.
  2392.             *****************************************************************
  2393.             */
  2394. McbCountLinesAndColumns(xml.lpXML, xml.nIndex, pResults);
  2395. }
  2396. }
  2397. free(lpszXML);
  2398. lpszXML = NULL;
  2399. xml.lpXML = NULL;
  2400. return pElement;
  2401. }/* McbParseXML */
  2402. /**
  2403.  ****************************************************************************
  2404.  * <P> Search for an element in the list.  </P>
  2405.  *
  2406.  * @methodName  * McbFindElement
  2407.  *
  2408.  * @param       lpszName
  2409.  *
  2410.  * @return      McbXMLElement
  2411.  *
  2412.  * @exception   none
  2413.  *
  2414.  * @author      Martyn C Brown
  2415.  *
  2416.  * @changeHistory  
  2417.  * 25th August     2001  -  (V1.0) Creation (MCB)
  2418.  ****************************************************************************
  2419.  */
  2420. McbXMLElement * McbFindElement(McbXMLElement *pEntry, LPCTSTR lpszPath)
  2421. {
  2422. McbXMLElement * pChild;
  2423. LPCTSTR lpszName;
  2424. LPCTSTR lpszNext;
  2425. int cbName;
  2426. int nIndex;
  2427. assert(lpszPath);
  2428. assert(pEntry);
  2429.    /*
  2430.     *************************************************************************
  2431.     * Find the next name in the path in case we need to recurse
  2432.     *************************************************************************
  2433.     */
  2434. lpszNext = _tcschr(lpszPath, _T('/'));
  2435.    /*
  2436.     *************************************************************************
  2437.     * Calculate the length of the current name we are searching for
  2438.     *************************************************************************
  2439.     */
  2440. if (!lpszNext)
  2441. {
  2442. cbName = _tcslen(lpszPath);
  2443. }
  2444. else
  2445. {
  2446. cbName = lpszNext - lpszPath;
  2447. if (lpszNext[1])
  2448. {
  2449. lpszNext++;
  2450. }
  2451. else
  2452. {
  2453. lpszNext = NULL;
  2454. }
  2455. }
  2456. if (cbName)
  2457. {
  2458.        /*
  2459.         *********************************************************************
  2460.         * Enumerate child elements
  2461.         *********************************************************************
  2462.         */
  2463.         nIndex = 0;
  2464.         while(pChild = McbEnumElements(pEntry, &nIndex))
  2465.         {
  2466.            /*
  2467.             *****************************************************************
  2468.             * Obtain the name of the child element
  2469.             *****************************************************************
  2470.             */
  2471.             lpszName = pChild->lpszName;
  2472.             if (lpszName)
  2473.             {
  2474.                /*
  2475.                 *************************************************************
  2476.                 * If the name of the element is what we are looking for
  2477.                 *************************************************************
  2478.                 */
  2479.                 if (_tcsnicmp(lpszPath, lpszName, cbName) == 0)
  2480.                 {
  2481.                    /*
  2482.                     *********************************************************
  2483.                     * Check if this is the last element to search for
  2484.                     *********************************************************
  2485.                     */
  2486.                     if (!lpszNext)
  2487.                     {
  2488.                         return pChild;
  2489.                     }
  2490.                    /*
  2491.                     *********************************************************
  2492.                     * If we have further nodes to find then recurse.
  2493.                     *********************************************************
  2494.                     */
  2495.                     else 
  2496.                     {
  2497.                         return McbFindElement(pChild, lpszNext);
  2498.                     }
  2499.                 }
  2500.             }
  2501.         }
  2502. }
  2503. return NULL;
  2504. }/* McbFindElement */
  2505. /**
  2506.  ****************************************************************************
  2507.  * <P> Find an attribute on an element.  </P>
  2508.  *
  2509.  * @methodName  * McbFindAttribute
  2510.  *
  2511.  * @param       *pEntry
  2512.  * @param       lpszAttrib
  2513.  *
  2514.  * @return      McbXMLAttribute
  2515.  *
  2516.  * @exception   none
  2517.  *
  2518.  * @author      Martyn C Brown
  2519.  *
  2520.  * @changeHistory  
  2521.  * 25th August     2001  -  (V1.0) Creation (MCB)
  2522.  ****************************************************************************
  2523.  */
  2524. McbXMLAttribute * McbFindAttribute(McbXMLElement *pEntry, LPCTSTR lpszAttrib)
  2525. {
  2526. McbXMLAttribute * pAttr;
  2527. int cbAttrib;
  2528. int nIndex;
  2529. assert(pEntry);
  2530. assert(lpszAttrib);
  2531. cbAttrib = _tcslen(lpszAttrib);
  2532. nIndex = 0;
  2533. while(pAttr = McbEnumAttributes(pEntry, &nIndex))
  2534. {
  2535. if (_tcsnicmp(pAttr->lpszName, lpszAttrib, cbAttrib) == 0)
  2536. {
  2537. return pAttr;
  2538. }
  2539. }
  2540. return NULL;
  2541. }/* McbFindAttribute */
  2542. /**
  2543.  ****************************************************************************
  2544.  * <P> Add CData to the element.  </P>
  2545.  *
  2546.  * @methodName  * McbAddCData
  2547.  *
  2548.  * @param       *pEntry
  2549.  * @param       lpszValue
  2550.  * @param       nGrowBy
  2551.  *
  2552.  * @return      McbXMLClear
  2553.  *
  2554.  * @exception   none
  2555.  *
  2556.  * @author      Martyn C Brown
  2557.  *
  2558.  * @changeHistory  
  2559.  * 3rd February   2002  -  (V1.0) Creation (MCB)
  2560.  ****************************************************************************
  2561.  */
  2562. McbXMLClear * McbAddCData(McbXMLElement *pEntry, LPTSTR lpszValue, int nGrowBy)
  2563. {
  2564. return McbAddClear(pEntry, lpszValue, McbGETCDATA(), nGrowBy);
  2565. }/* McbAddCData */
  2566. /**
  2567.  ****************************************************************************
  2568.  * <P> Add elements to the list if they do not exist, return the final node.
  2569.  * </P>
  2570.  *
  2571.  * @methodName  * McbCreateElements
  2572.  *
  2573.  * @param       *pEntry
  2574.  * @param       lpszPath
  2575.  *
  2576.  * @return      McbXMLElement
  2577.  *
  2578.  * @exception   none
  2579.  *
  2580.  * @author      Martyn C Brown
  2581.  *
  2582.  * @changeHistory  
  2583.  * 29th January    2002  -  (V1.0) Creation (MCB)
  2584.  ****************************************************************************
  2585.  */
  2586. McbXMLElement * McbCreateElements(McbXMLElement *pEntry, LPCTSTR lpszPath)
  2587. {
  2588. McbXMLElement * pChild;
  2589. McbXMLElement * pNew;
  2590. LPCTSTR lpszName;
  2591. LPCTSTR lpszNext;
  2592. int cbName;
  2593. int nIndex;
  2594. assert(lpszPath);
  2595. assert(pEntry);
  2596.    /*
  2597.     *************************************************************************
  2598.     * Find the next name in the path in case we need to recurse
  2599.     *************************************************************************
  2600.     */
  2601. lpszNext = _tcschr(lpszPath, _T('/'));
  2602.    /*
  2603.     *************************************************************************
  2604.     * Calculate the length of the current name we are searching for
  2605.     *************************************************************************
  2606.     */
  2607. if (!lpszNext)
  2608. {
  2609. cbName = _tcslen(lpszPath);
  2610. }
  2611. else
  2612. {
  2613. cbName = lpszNext - lpszPath;
  2614. if (lpszNext[1])
  2615. {
  2616. lpszNext++;
  2617. }
  2618. else
  2619. {
  2620. lpszNext = NULL;
  2621. }
  2622. }
  2623. if (cbName)
  2624. {
  2625.        /*
  2626.         *********************************************************************
  2627.         * Enumerate child elements
  2628.         *********************************************************************
  2629.         */
  2630.         nIndex = 0;
  2631.         while(pChild = McbEnumElements(pEntry, &nIndex))
  2632.         {
  2633.            /*
  2634.             *****************************************************************
  2635.             * Obtain the name of the child element
  2636.             *****************************************************************
  2637.             */
  2638.             lpszName = pChild->lpszName;
  2639.             if (lpszName)
  2640.             {
  2641.                /*
  2642.                 *************************************************************
  2643.                 * If the name of the element is what we are looking for
  2644.                 *************************************************************
  2645.                 */
  2646.                 if (_tcsnicmp(lpszPath, lpszName, cbName) == 0)
  2647.                 {
  2648.                    /*
  2649.                     *********************************************************
  2650.                     * Check if this is the last element to search for
  2651.                     *********************************************************
  2652.                     */
  2653.                     if (!lpszNext)
  2654.                     {
  2655.                         return pChild;
  2656.                     }
  2657.                    /*
  2658.                     *********************************************************
  2659.                     * If we have further nodes to find then recurse.
  2660.                     *********************************************************
  2661.                     */
  2662.                     else 
  2663.                     {
  2664.                         return McbCreateElements(pChild, lpszNext);
  2665.                     }
  2666.                 }
  2667.             }
  2668.         }
  2669.        /*
  2670.         *********************************************************************
  2671.         * If we got this far then we couldn't find the required element so we
  2672. * need to add a new element to the current element
  2673.         *********************************************************************
  2674.         */
  2675. pNew = McbAddElement(pEntry, McbStrdup(lpszPath, cbName), FALSE, 
  2676. McbGROWBY);
  2677.        /*
  2678.         *********************************************************************
  2679.         * If there are no more entries then return the node we just created.
  2680.         *********************************************************************
  2681.         */
  2682. if (!lpszNext)
  2683. {
  2684. return pNew;
  2685. }
  2686.        /*
  2687.         *********************************************************************
  2688.         * If there are more elements to search
  2689.         *********************************************************************
  2690.         */
  2691.         else 
  2692. {
  2693.            /*
  2694.             *****************************************************************
  2695.             * Recurse to add the remaining nodes
  2696.             *****************************************************************
  2697.             */
  2698. return McbCreateElements(pNew, lpszNext);
  2699. }
  2700. }
  2701. return NULL;
  2702. }/* McbCreateElements */
  2703. /**
  2704.  ****************************************************************************
  2705.  * <P> Creates an user friendly XML string from a given element with 
  2706.  * appropriate white space and carriage returns.
  2707.  *
  2708.  * This recurses through all subnodes then adds contents of the nodes to the
  2709.  * string.
  2710.  * </P>
  2711.  *
  2712.  * @methodName  McbCreateXMLStringR
  2713.  *
  2714.  * @param       McbXMLElement * pEntry - XML Element
  2715.  * @param       LPTSTR lpszMarker   - String to create results into, this 
  2716.  * can be zero if you want to calculate
  2717.  * the size of the returned string.
  2718.  * @param       int nFormat   - Specify -1 for no formatting or the
  2719.  * indent level (0 initially).
  2720.  * @return      int   - Size of the returned string, not 
  2721.  * including the NULL terminator.
  2722.  *
  2723.  * @exception   none
  2724.  *
  2725.  * @author      Martyn C Brown
  2726.  *
  2727.  * @changeHistory  
  2728.  * 31st January    2002  -  (V1.0) Creation (MCB)
  2729.  ****************************************************************************
  2730.  */
  2731. int McbCreateXMLStringR(McbXMLElement * pEntry, LPTSTR lpszMarker, int nFormat)
  2732. {
  2733. int nResult = 0;
  2734. int cb;
  2735. int cbElement;
  2736. int nIndex;
  2737. int nChildFormat;
  2738. int bHasChildren = FALSE;
  2739. McbXMLNode * pChild;
  2740. McbXMLAttribute * pAttr;
  2741. assert(pEntry);
  2742. #define McbLENSTR(lpsz) (lpsz ? _tcslen(lpsz) : 0)
  2743.    /*
  2744.     *************************************************************************
  2745.     * If the element has no name then assume this is the head node.
  2746.     *************************************************************************
  2747.     */
  2748. cbElement = McbLENSTR(pEntry->lpszName);
  2749. if (cbElement)
  2750. {
  2751.        /*
  2752.         *********************************************************************
  2753.         * "<elementname "
  2754.         *********************************************************************
  2755.         */
  2756. cb = nFormat == -1 ? 0 : nFormat;
  2757.         if (lpszMarker)
  2758.         {
  2759.             if (cb)
  2760.             {
  2761.                 memset(lpszMarker, McbINDENTCHAR, sizeof(TCHAR)*cb);
  2762.             }
  2763.             nResult = cb;
  2764.             lpszMarker[nResult++] = _T('<');        
  2765.             _tcscpy(&lpszMarker[nResult], pEntry->lpszName);
  2766.             nResult += cbElement;
  2767.             lpszMarker[nResult++] = _T(' ');        
  2768.         }                
  2769.         else
  2770.         {
  2771.             nResult += cbElement + 2 + cb;
  2772.         }
  2773.         
  2774.        /*
  2775.         *********************************************************************
  2776.         * Enumerate attributes and add them to the string
  2777.         *********************************************************************
  2778.         */
  2779.         nIndex = 0;
  2780.         while (pChild = McbEnumNodes(pEntry, &nIndex))
  2781.         {
  2782.             switch(pChild->type)
  2783.             {
  2784.            /*
  2785.             *****************************************************************
  2786.             * Add attributes
  2787.             *****************************************************************
  2788.             */
  2789.             case eNodeAttribute:
  2790.                 {
  2791.                     pAttr = pChild->node.pAttrib;
  2792.                    /*
  2793.                     *********************************************************
  2794.                     * "Attrib
  2795.                     *********************************************************
  2796.                     */
  2797.                     cb = McbLENSTR(pAttr->lpszName);
  2798.                     if (cb)
  2799.                     {
  2800.                         if (lpszMarker)
  2801.                         {
  2802.                             _tcscpy(&lpszMarker[nResult], pAttr->lpszName);             
  2803.                         }
  2804.                         nResult += cb;
  2805.                        /*
  2806.                         *****************************************************
  2807.                         * "Attrib=Value "
  2808.                         *****************************************************
  2809.                         */
  2810.                         cb = McbLENSTR(pAttr->lpszValue);
  2811.                         if (cb)
  2812.                         {
  2813.                             if (lpszMarker)
  2814.                             {
  2815.                                 lpszMarker[nResult] = _T('=');
  2816.                                 _tcscpy(&lpszMarker[nResult+1], 
  2817.                                     pAttr->lpszValue);                  
  2818.                             }
  2819.                             nResult += cb + 1;
  2820.                         }
  2821.                         if (lpszMarker)
  2822.                         {
  2823.                             lpszMarker[nResult] = _T(' ');                              
  2824.                         }
  2825.                         nResult++;              
  2826.                     }
  2827.                 }
  2828.                 break;
  2829.             case eNodeEmpty:
  2830.                 continue;
  2831.             default:
  2832.                /*
  2833.                 *************************************************************
  2834.                 * If this node isn't an attribute then flag that this element 
  2835. * has children.
  2836.                 *************************************************************
  2837.                 */
  2838.                 bHasChildren = TRUE;
  2839.             }
  2840.         }
  2841.         
  2842.        /*
  2843.         *********************************************************************
  2844.         * If there are child nodes we need to terminate the start tag
  2845.         *********************************************************************
  2846.         */
  2847.         if (bHasChildren)
  2848.         {   
  2849.             if (lpszMarker)
  2850.             {
  2851.                 lpszMarker[nResult-1] = _T('>');
  2852.             }
  2853.             if (nFormat != -1)
  2854.             {
  2855.                 if (lpszMarker)
  2856.                 {
  2857.                     lpszMarker[nResult] = _T('n');
  2858.                 }
  2859.                 nResult++;
  2860.             }
  2861.         }
  2862.         else
  2863.         {
  2864.             nResult--;
  2865.         }
  2866. }
  2867.    /*
  2868.     *************************************************************************
  2869.     * Calculate the child format for when we recurse.  This is used to 
  2870. * determine the number of spaces used for prefixes.
  2871.     *************************************************************************
  2872.     */
  2873. if (nFormat == -1)
  2874. {
  2875. nChildFormat = -1;
  2876. }
  2877. else
  2878. {
  2879. if (cbElement) 
  2880. {
  2881. nChildFormat = nFormat + 1;
  2882. }
  2883. else
  2884. {
  2885. nChildFormat = nFormat;
  2886. }
  2887. }
  2888.    /*
  2889.     *************************************************************************
  2890.     * Enumerate through remaining children
  2891.     *************************************************************************
  2892.     */
  2893. nIndex = 0;
  2894. while (pChild = McbEnumNodes(pEntry, &nIndex))
  2895. {
  2896. switch(pChild->type)
  2897. {
  2898.        /*
  2899.         *********************************************************************
  2900.         * Text nodes
  2901.         *********************************************************************
  2902.         */
  2903. case eNodeText:
  2904. {
  2905.                /*
  2906.                 *************************************************************
  2907.                 * "Text"
  2908.                 *************************************************************
  2909.                 */
  2910.                 cb = McbLENSTR(pChild->node.pText->lpszValue);
  2911.                 if (cb)
  2912.                 {
  2913. if (nFormat != -1)
  2914. {
  2915.                         if (lpszMarker)
  2916.                         {
  2917.                             memset(&lpszMarker[nResult], McbINDENTCHAR, 
  2918.                                     sizeof(TCHAR)*(nFormat + 1));                       
  2919.                             _tcscpy(&lpszMarker[nResult + nFormat + 1], 
  2920.                                 pChild->node.pText->lpszValue);
  2921. lpszMarker[nResult + nFormat + 1 + cb] = 
  2922. _T('n');
  2923.                         }
  2924.                         nResult += cb + nFormat + 2;
  2925. }
  2926. else
  2927. {
  2928. if (lpszMarker)
  2929.                         {
  2930. _tcscpy(&lpszMarker[nResult], 
  2931. pChild->node.pText->lpszValue);
  2932. }
  2933. nResult += cb;
  2934. }               
  2935.                 }
  2936. }
  2937. break;
  2938.        /*
  2939.         *********************************************************************
  2940.         * Clear type nodes
  2941.         *********************************************************************
  2942.         */
  2943. case eNodeClear:
  2944. {
  2945.                /*
  2946.                 *************************************************************
  2947.                 * "OpenTag"
  2948.                 *************************************************************
  2949.                 */
  2950.                 cb = McbLENSTR(pChild->node.pClear->lpszOpenTag);
  2951.                 if (cb)
  2952.                 {
  2953. if (nFormat != -1)
  2954. {
  2955.                         if (lpszMarker)
  2956.                         {
  2957.                             memset(&lpszMarker[nResult], McbINDENTCHAR, 
  2958.                                     sizeof(TCHAR)*(nFormat + 1));                       
  2959.                             _tcscpy(&lpszMarker[nResult + nFormat + 1], 
  2960.                                 pChild->node.pClear->lpszOpenTag);
  2961. /* lpszMarker[nResult + nFormat + 1 + cb] = 
  2962. _T('n'); */
  2963.                         }
  2964.                         /* nResult += cb + nFormat + 2; */
  2965. nResult += cb + nFormat + 1;
  2966. }
  2967. else
  2968. {
  2969. if (lpszMarker)
  2970.                         {
  2971. _tcscpy(&lpszMarker[nResult], 
  2972. pChild->node.pClear->lpszOpenTag);
  2973. }
  2974. nResult += cb;
  2975. }               
  2976.                 }
  2977.                /*
  2978.                 *************************************************************
  2979.                 * "OpenTag Value"
  2980.                 *************************************************************
  2981.                 */
  2982. cb = McbLENSTR(pChild->node.pClear->lpszValue);
  2983.                 if (cb)
  2984.                 {
  2985. if (lpszMarker)
  2986.                     {
  2987. _tcscpy(&lpszMarker[nResult], 
  2988. pChild->node.pClear->lpszValue);
  2989. }
  2990. nResult += cb;
  2991. }
  2992.                /*
  2993.                 *************************************************************
  2994.                 * "OpenTag Value CloseTag"
  2995.                 *************************************************************
  2996.                 */
  2997. cb = McbLENSTR(pChild->node.pClear->lpszCloseTag);
  2998.                 if (cb)
  2999.                 {
  3000. if (lpszMarker)
  3001.                     {
  3002. _tcscpy(&lpszMarker[nResult], 
  3003. pChild->node.pClear->lpszCloseTag);
  3004. }
  3005. nResult += cb;
  3006. }
  3007. if (nFormat != -1)
  3008. {
  3009. if (lpszMarker)
  3010. {
  3011. lpszMarker[nResult] = _T('n');
  3012. }
  3013. nResult++;
  3014. }
  3015. }
  3016. break;
  3017.        /*
  3018.         *********************************************************************
  3019.         * Element nodes
  3020.         *********************************************************************
  3021.         */
  3022. case eNodeElement:
  3023. {
  3024.                /*
  3025.                 *************************************************************
  3026.                 * Recursively add child nodes
  3027.                 *************************************************************
  3028.                 */
  3029. nResult += McbCreateXMLStringR(pChild->node.pElement, 
  3030. lpszMarker ? lpszMarker + nResult : 0, nChildFormat);
  3031. }
  3032. }
  3033. }
  3034. if (cbElement)
  3035. {
  3036.        /*
  3037.         *********************************************************************
  3038.         * If we have child entries we need to use long XML notation for 
  3039. * closing the element - "<elementname>blah blah blah</elementname>"
  3040.         *********************************************************************
  3041.         */
  3042.         if (bHasChildren)
  3043.         {
  3044.            /*
  3045.             *****************************************************************
  3046.             * "</elementname>"
  3047.             *****************************************************************
  3048.             */
  3049.             if (lpszMarker)
  3050.             {
  3051.                 if (nFormat != -1)
  3052.                 {
  3053.                     if (nFormat)
  3054.                     {
  3055.                         memset(&lpszMarker[nResult], McbINDENTCHAR, 
  3056.                             sizeof(TCHAR)*nFormat);
  3057.                         nResult+=nFormat;
  3058.                     }
  3059.                 }       
  3060.                 _tcscpy(&lpszMarker[nResult], _T("</"));        
  3061.                 nResult += 2;
  3062.                 _tcscpy(&lpszMarker[nResult], pEntry->lpszName);
  3063.                 nResult += cbElement;
  3064.                 
  3065.                 if (nFormat == -1)
  3066.                 {
  3067.                     _tcscpy(&lpszMarker[nResult], _T(">"));
  3068.                     nResult++;
  3069.                 }
  3070.                 else
  3071.                 {
  3072.                     _tcscpy(&lpszMarker[nResult], _T(">n"));
  3073.                     nResult += 2;
  3074.                 }
  3075.             }
  3076.             else
  3077.             {
  3078.                 if (nFormat != -1)
  3079.                 {
  3080.                     nResult += cbElement + 4 + nFormat;
  3081.                 }
  3082.                 else
  3083.                 {
  3084.                     nResult += cbElement + 3;
  3085.                 }
  3086.             }       
  3087.         }
  3088.        /*
  3089.         *********************************************************************
  3090.         * If there are no children we can use shorthand XML notation - 
  3091.         * "<elementname/>"
  3092.         *********************************************************************
  3093.         */
  3094.         else 
  3095.         {
  3096.            /*
  3097.             *****************************************************************
  3098.             * "/>"
  3099.             *****************************************************************
  3100.             */
  3101.             if (lpszMarker)
  3102.             {
  3103.                 if (nFormat == -1)
  3104.                 {
  3105.                     _tcscpy(&lpszMarker[nResult], _T("/>")); 
  3106.                     nResult += 2;
  3107.                 }
  3108.                 else
  3109.                 {
  3110.                     _tcscpy(&lpszMarker[nResult], _T("/>n")); 
  3111.                     nResult += 3;
  3112.                 }
  3113.             }
  3114.             else
  3115.             {
  3116.                 nResult += nFormat == -1 ? 2 : 3;
  3117.             }
  3118.         }
  3119. }
  3120. return nResult;
  3121. }/* McbCreateXMLStringR */
  3122. /**
  3123.  ****************************************************************************
  3124.  * <P> Create an XML string from the head element.  </P>
  3125.  *
  3126.  * @methodName  McbCreateXMLString
  3127.  *
  3128.  * @param       McbXMLElement * pHead - head element
  3129.  * @param       int nFormat  -  0 if no formatting is required 
  3130.  * otherwise nonzero for formatted text
  3131.  * with carriage returns and indentation.
  3132.  * @param       int *pnSize  - [out] pointer to the size of the 
  3133.  * returned string not including the 
  3134.  * NULL terminator.
  3135.  *
  3136.  * @return      LPTSTR  - Allocated XML string, you must free
  3137.  * this with free().
  3138.  *
  3139.  * @exception   none
  3140.  *
  3141.  * @author      Martyn C Brown
  3142.  *
  3143.  * @changeHistory  
  3144.  * 31st January    2002  -  (V1.0) Creation (MCB)
  3145.  ****************************************************************************
  3146.  */
  3147. LPTSTR McbCreateXMLString(McbXMLElement * pHead, int nFormat, int *pnSize)
  3148. {
  3149. LPTSTR lpszResult = NULL;
  3150. int cbStr;
  3151. if (pHead)
  3152. {
  3153.        /*
  3154.         *********************************************************************
  3155.         * Recursively Calculate the size of the XML string
  3156.         *********************************************************************
  3157.         */
  3158. nFormat = nFormat ? 0 : -1;
  3159. cbStr = McbCreateXMLStringR(pHead, 0, nFormat);
  3160. assert(cbStr);
  3161.        /*
  3162.         *********************************************************************
  3163.         * Alllocate memory for the XML string + the NULL terminator and
  3164. * create the recursively XML string.
  3165.         *********************************************************************
  3166.         */
  3167. lpszResult = (LPTSTR)malloc(cbStr+1);
  3168. if (lpszResult)
  3169. {
  3170. McbCreateXMLStringR(pHead, lpszResult, nFormat);
  3171. if (pnSize) *pnSize = cbStr;
  3172. }
  3173. }
  3174. return lpszResult;
  3175. }/* McbCreateXMLString */
  3176. /*
  3177.  *********************************************************************
  3178.  * Add New Node To the List;
  3179.  * Toby add 2006/7/3/9:40
  3180.  *********************************************************************
  3181. */
  3182. McbXMLElement* AddElementToXML(McbXMLElement *pParent,LPTSTR lpszText)
  3183. {
  3184. NodeText_st *pTemp = NULL;
  3185. McbXMLElement *pElement;
  3186. //pTemp = (NodeText_st *)malloc(sizeof(NodeText_st));
  3187. //got the mem?
  3188. //if(!pTemp)
  3189. // return NULL;
  3190. #ifdef DYNAMIC_MEM
  3191. // pTemp->lpszText = (LPTSTR)malloc((char)*strlen(lpszText));
  3192. #endif
  3193. //strcpy(pTemp->lpszText,lpszText);
  3194. //AddToList(&g_StrList,&(pTemp->List));
  3195. //pElement = McbCreateElements(pParent,pTemp->lpszText);
  3196. pElement = McbCreateElements(pParent,lpszText);
  3197. return pElement;
  3198. }
  3199. /*
  3200.  *********************************************************************
  3201.  * Add New Attr Node To the List;
  3202.  * Toby add 2006/7/3/9:40
  3203.  *********************************************************************
  3204. */
  3205. McbXMLAttribute* AddAttrToXML(McbXMLElement *pEntry,LPTSTR lpszName,LPTSTR lpszValue)
  3206. {
  3207. McbXMLAttribute *pAttr = NULL;
  3208. if(!pEntry)
  3209. return NULL;
  3210. pAttr = McbAddAttribute(pEntry,
  3211. McbStrdup(lpszName,0),
  3212. McbStrdup(lpszValue,0),
  3213. 1);
  3214. return pAttr;
  3215. }
  3216. /*
  3217.  *********************************************************************
  3218.  * Delete Node From the List;
  3219.  * Toby add 2006/7/3/9:53
  3220.  *********************************************************************
  3221. */
  3222. void DeleteElementFromXML(McbXMLElement *pEntry)
  3223. {
  3224. NodeText_st *pTemp = NULL;
  3225. if(!pEntry)
  3226. return;
  3227. pTemp = ListEntry(pEntry->lpszName,NodeText_st,lpszText);
  3228. DeleteFromList(&(pTemp->List));
  3229. free(pTemp->lpszText);
  3230. free(pTemp);
  3231. //delete from the list...add Later
  3232. McbDeleteElement(pEntry);
  3233. }
  3234. /*
  3235.  *********************************************************************
  3236.  * Delete Node From the List;
  3237.  * Toby add 2006/7/3/10:01
  3238.  *********************************************************************
  3239. */
  3240. void DeleteAttrFromXML(McbXMLAttribute *pEntry)
  3241. {
  3242. NodeText_st *pTemp = NULL;
  3243. pTemp = ListEntry(pEntry->lpszName,NodeText_st,lpszText);
  3244. DeleteFromList(&(pTemp->List));
  3245. free(pTemp->lpszText);
  3246. free(pTemp);
  3247. pTemp = ListEntry(pEntry->lpszValue,NodeText_st,lpszText);
  3248. DeleteFromList(&(pTemp->List));
  3249. free(pTemp->lpszText);
  3250. free(pTemp);
  3251. if(!pEntry)
  3252. return;
  3253. //delete from the list... add later
  3254. McbDeleteAttribute(pEntry);
  3255. }