blob: c0873ee2fdab9d2333347eaaad068e16fee97284 [file] [log] [blame]
/*******************************************************************************
* Copyright 2009, Marvell Technology Group Ltd.
*
* THIS CODE CONTAINS CONFIDENTIAL INFORMATION OF MARVELL. NO RIGHTS ARE GRANTED
* HEREIN UNDER ANY PATENT, MASK WORK RIGHT OR COPYRIGHT OF MARVELL OR ANY THIRD
* PARTY. MARVELL RESERVES THE RIGHT AT ITS SOLE DISCRETION TO REQUEST THAT THIS
* CODE BE IMMEDIATELY RETURNED TO MARVELL. THIS CODE IS PROVIDED "AS IS".
* MARVELL MAKES NO WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS
* ACCURACY, COMPLETENESS OR PERFORMANCE. MARVELL COMPRISES MARVELL TECHNOLOGY
* GROUP LTD. (MTGL) AND ITS SUBSIDIARIES, MARVELL INTERNATIONAL LTD. (MIL),
* MARVELL TECHNOLOGY, INC. (MTI), MARVELL SEMICONDUCTOR, INC. (MSI), MARVELL
* ASIA PTE LTD. (MAPL), MARVELL JAPAN K.K. (MJKK), GALILEO TECHNOLOGY LTD. (GTL)
* GALILEO TECHNOLOGY, INC. (GTI) AND RADLAN Computer Communications, LTD.
********************************************************************************
*/
/*
****************************************************************************
* Include all necessary include files
****************************************************************************
*/
#include "mrvxml.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <httpclient_sys.h>
#define duster_malloc malloc
#define duster_free free
#define ASSERT assert
#define TRUE 1
#define FALSE 0
#ifndef XML_FILE_SIZE
#define XML_FILE_SIZE 5120
#endif
//#define mrvxml_log(fmt,args...) RDPRINTF(format, ##args);
//#define mrvxml_log PRINTINFO
#define mrvxml_log(fmt,args...)
/*
****************************************************************************
* Enumeration used to decipher what type a token is
****************************************************************************
*/
typedef enum MrvTokenType
{
eTokenText = 0,
eTokenQuotedText,
eTokenTagStart, /* "<" */
eTokenTagEnd, /* "</" */
eTokenCloseTag, /* ">" */
eTokenEquals, /* "=" */
eTokenDeclaration, /* "<?" */
eTokenShortHandClose, /* "/>" */
eTokenClear,
eTokenError
} MrvTokenType;
/*
****************************************************************************
* Defines to dictate grow by value when adding nodes.
****************************************************************************
*/
#define MrvGROWBY 5
//#define MrvINDENTCHAR _T('\t')
#define MrvINDENTCHAR '\t'
typedef struct MrvClearTag
{
MRV_LPTSTR lpszOpen;
MRV_LPTSTR lpszClose;
} MrvClearTag;
typedef struct MrvNextToken
{
MrvClearTag *pClr;
MRV_LPCTSTR pStr;
} MrvNextToken;
/*
****************************************************************************
* Main structure used for parsing XML
****************************************************************************
*/
typedef struct MrvXML
{
MRV_LPCTSTR lpXML;
int nIndex;
enum MrvXMLError error;
MRV_LPCTSTR lpEndTag;
int cbEndTag;
MRV_LPCTSTR lpNewElement;
int cbNewElement;
int nFirst;
MrvClearTag *pClrTags;
} MrvXML;
/*
****************************************************************************
* Enumeration used when parsing attributes
****************************************************************************
*/
typedef enum MrvAttrib
{
eAttribName = 0,
eAttribEquals,
eAttribValue
} MrvAttrib;
/*
****************************************************************************
* Enumeration used when parsing elements to dictate whether we are currently
* inside a tag
****************************************************************************
*/
typedef enum MrvStatus
{
eInsideTag = 0,
eOutsideTag
} MrvStatus;
/*
****************************************************************************
* Structure used to obtain List.
****************************************************************************
*/
typedef struct List_ST{
struct List_ST *pNext;
struct List_ST *pPrev;
}List_st;
typedef struct{
List_st pList;
int iNum;
}ListHead_st;
/*
****************************************************************************
* Structure used to obtain List Node.
****************************************************************************
*/
#ifndef DYNAMIC_MEM
#define DYNAMIC_MEM
#endif
#ifdef DYNAMIC_MEM
typedef struct{
List_st List;
MRV_LPTSTR lpszText;
}NodeText_st;
#else
typedef struct{
List_st List;
char lpszText[256];
}NodeText_st;
#endif
#if 0
static ListHead_st g_StrList;
static void InitList(ListHead_st *pListHead)
{
pListHead->pList.pNext = &(pListHead->pList);
pListHead->pList.pPrev = &(pListHead->pList);
pListHead->iNum = 0;
}/* InitList */
static void AddToList(ListHead_st *pListHead,List_st *pListNode)
{
pListNode->pPrev = &(pListHead->pList);
pListNode->pNext = pListHead->pList.pNext;
pListHead->pList.pNext->pPrev = pListNode;
pListHead->pList.pNext = pListNode;
pListHead->iNum++;
}/* AddToList */
static List_st *DeleteFromListTial(ListHead_st *pListHead)
{
List_st *pTemp;
//Empty List?
if(pListHead->pList.pPrev == &(pListHead->pList))
return 0;
pTemp = pListHead->pList.pPrev;
pTemp->pPrev->pNext = pTemp->pNext;
pTemp->pNext->pPrev = pTemp->pPrev;
pListHead->iNum--;
return pTemp;
}/* DeleteFromListTial */
#endif
static void DeleteFromList(List_st *pList)
{
pList->pNext->pPrev = pList->pPrev;
pList->pPrev->pPrev = pList->pNext;
}/* DeleteFromList */
#if 0
static void FreeList(ListHead_st *pListHead)
{
List_st *pList;
NodeText_st *pNodeText;
//empty List
if(pListHead->pList.pNext == &(pListHead->pList))
return;
while(pListHead->iNum){
pList = DeleteFromListTial(pListHead);
pNodeText = ListEntry(pList,NodeText_st,List);
#ifdef DYNAMIC_MEM
duster_free(pNodeText->lpszText);
#endif
duster_free(pNodeText);
}
}/*FreeList*/
#endif
/**
****************************************************************************
* <P> Initialise an element. </P>
*
* @methodName MrvInitElement
*
* @param *pEntry
* @param lpszName
*
* @return void
*
* @exception none
*
****************************************************************************
*/
static void MrvInitElement(MrvXMLElement *pEntry, MrvXMLElement *pParent,
MRV_LPTSTR lpszName, int nIsDeclaration)
{
ASSERT(pEntry);
pEntry->nMax = 0;
pEntry->nSize = 0;
pEntry->pEntries = NULL;
pEntry->pParent = pParent;
pEntry->nIsDeclaration = nIsDeclaration;
pEntry->lpszName = lpszName;
}/* MrvInitElement */
/**
****************************************************************************
* <P> Create the root element. </P>
*
* @methodName * MrvCreateRoot
*
* @param none
*
* @return MrvXMLElement
*
* @exception none
*
****************************************************************************
*/
MrvXMLElement * MrvCreateRoot()
{
MrvXMLElement * pElement;
pElement = (MrvXMLElement*)duster_malloc(sizeof(MrvXMLElement));
/*modified by shoujunl*/
MrvInitElement(pElement, NULL, NULL, 0);
//Init the NodeName LinkList
//Toby add 2006/7/3/9:31
//InitList(&g_StrList);
return pElement;
}/* MrvCreateRoot */
/**
****************************************************************************
* <P> Delete the root element and set it to NULL. </P>
*
* @methodName MrvDeleteRoot
*
* @param ** ppElement
*
* @return void
*
* @exception none
*
****************************************************************************
*/
void MrvDeleteRoot(MrvXMLElement * pElement)
{
mrvxml_log("enter %s",__FUNCTION__);
MrvDeleteElement(pElement);
mrvxml_log("%s middle",__FUNCTION__);
if(pElement)
duster_free(pElement);
//FreeList(&g_StrList);
mrvxml_log("leave %s",__FUNCTION__);
}/* MrvDeleteRoot */
/**
****************************************************************************
* <P> Delete an attribute. </P>
*
* @methodName MrvDeleteAttribute
*
* @param *pEntry
*
* @return void
*
* @exception none
*
****************************************************************************
*/
static void MrvDeleteAttribute(MrvXMLAttribute *pEntry)
{
ASSERT(pEntry);
if (pEntry->lpszName)
{
duster_free(pEntry->lpszName);
pEntry->lpszName = NULL;
}
if (pEntry->lpszValue)
{
duster_free(pEntry->lpszValue);
pEntry->lpszValue= NULL;
}
}/* MrvDeleteAttribute */
/**
****************************************************************************
* <P> Attach attributes from one list to another. </P>
*
* @methodName MrvAttributeAttach
*
* @param *pDst
* @param *pSrc
* @param nNum
*
* @return void
*
* @exception none
*
****************************************************************************
*/
#if 0
static void MrvAttributeAttach(MrvXMLAttribute *pDst, MrvXMLAttribute *pSrc, int nNum)
{
int n;
for (n=0; n<nNum; n++)
{
pDst[n].lpszName = pSrc[n].lpszName;
pDst[n].lpszValue = pSrc[n].lpszValue;
pSrc[n].lpszName = NULL;
pSrc[n].lpszValue = NULL;
}
}/* MrvAttributeAttach */
#endif
/**
****************************************************************************
* <P> Obtain the next character from the string. </P>
*
* @methodName MrvGetNextChar
*
* @param *pXML
*
* @return MRV_TCHAR
*
* @exception none
*
****************************************************************************
*/
static MRV_TCHAR MrvGetNextChar(MrvXML *pXML)
{
MRV_TCHAR ch;
ch = pXML->lpXML[pXML->nIndex];
if (ch != 0) pXML->nIndex++;
return ch;
}/* MrvGetNextChar */
/**
****************************************************************************
* <P> Find next non-white space character. </P>
*
* @methodName MrvFindNonWhiteSpace
*
* @param *pXML
*
* @return MRV_TCHAR
*
* @exception none
*
****************************************************************************
*/
static MRV_TCHAR MrvFindNonWhiteSpace(MrvXML *pXML)
{
MRV_TCHAR ch;
//MRV_LPCTSTR lpXML = pXML->lpXML;
int nExit = FALSE;
ASSERT(pXML);
/*
*************************************************************************
* Iterate through characters in the string until we find a NULL or a
* non-white space character
*************************************************************************
*/
while((nExit == FALSE) && (ch = MrvGetNextChar(pXML)))
{
switch(ch)
{
/*
*********************************************************************
* Ignore white space
*********************************************************************
*/
case '\n':
case ' ':
case '\t':
case '\r':
continue;
default:
nExit = TRUE;
}
}
return ch;
}/* MrvFindNonWhiteSpace */
/**
****************************************************************************
* <P> Duplicate a given string. </P>
*
* @methodName MrvStrdup
*
* @param lpszData
* @param cbData
*
* @return MRV_LPTSTR
*
* @exception none
*
****************************************************************************
*/
MRV_LPTSTR MrvStrdup(MRV_LPCTSTR lpszData, int cbData)
{
MRV_LPTSTR lpszNew;
ASSERT(lpszData);
if (cbData == 0) cbData = strlen(lpszData);
lpszNew = duster_malloc((cbData+1) * sizeof(MRV_TCHAR));
if (lpszNew)
{
memcpy(lpszNew, lpszData, (cbData) * sizeof(MRV_TCHAR));
//lpszNew[cbData] = (MRV_TCHAR)NULL;
lpszNew[cbData] = '\0';
}
return lpszNew;
}/* MrvStrdup */
/**
****************************************************************************
* <P> Find the next token in a string. </P>
*
* @methodName MrvGetNextToken
*
* @param *pXML
* @param *pcbToken
* @param *pType
*
* @return MRV_LPCTSTR
*
* @exception none
*
****************************************************************************
*/
static int MrvGetNextToken(MrvXML *pXML, int *pcbToken, MrvTokenType *pType , MrvNextToken *result)
{
//MrvNextToken result;
MRV_LPCTSTR lpXML;
MRV_TCHAR ch;
MRV_TCHAR chTemp = 0;
int nSize;
int nFoundMatch;
int nExit;
int n;
MRV_LPCTSTR lpszOpen;
int cbOpen;
int nIsText = FALSE;
/*
*************************************************************************
* Find next non-whte space character
*************************************************************************
*/
ch = MrvFindNonWhiteSpace(pXML);
if (ch)
{
/*
*********************************************************************
* Cache the current string pointer
*********************************************************************
*/
lpXML = pXML->lpXML;
result->pStr = &lpXML[pXML->nIndex-1];
/*
*********************************************************************
* First check whether the token is in the clear tag list (meaning it
* does not need formatting).
*********************************************************************
*/
n = 0;
while(TRUE)
{
/*
*****************************************************************
* Obtain the name of the open part of the clear tag
*****************************************************************
*/
lpszOpen = pXML->pClrTags[n].lpszOpen;
if (lpszOpen)
{
/*
*************************************************************
* Compare the open tag with the current token
*************************************************************
*/
cbOpen = strlen(lpszOpen);
if (strncmp(lpszOpen, result->pStr, cbOpen) == 0)
{
result->pClr = &pXML->pClrTags[n];
pXML->nIndex += cbOpen-1;
*pType = eTokenClear;
//return result;
return 0;
}
n++;
}
else
{
break;
}
}
/*
*********************************************************************
* If we didn't find a clear tag then check for standard tokens
*********************************************************************
*/
chTemp = 0;
lpXML = pXML->lpXML;
switch(ch)
{
/*
*********************************************************************
* Check for quotes
*********************************************************************
*/
case '\'':
case '\"':
/*
*****************************************************************
* Type of token
*****************************************************************
*/
*pType = eTokenQuotedText;
chTemp = ch;
/*
*****************************************************************
* Set the size
*****************************************************************
*/
nSize = 1;
nFoundMatch = FALSE;
/*
*****************************************************************
* Search through the string to find a matching quote
*****************************************************************
*/
while((ch = MrvGetNextChar(pXML)))
{
nSize++;
if (ch == chTemp)
{
nFoundMatch = TRUE;
break;
}
}
/*
*****************************************************************
* If we failed to find a matching quote
*****************************************************************
*/
if (nFoundMatch == FALSE)
{
/*
*************************************************************
* Indicate error
*************************************************************
*/
pXML->error = eXMLErrorNoMatchingQuote;
*pType = eTokenError;
}
/* MCB 4.02.2002 */
if (MrvFindNonWhiteSpace(pXML))
{
pXML->nIndex--;
}
break;
/*
*********************************************************************
* Equals (used with attribute values)
*********************************************************************
*/
case '=':
nSize = 1;
*pType = eTokenEquals;
break;
/*
*********************************************************************
* Close tag
*********************************************************************
*/
case '>':
nSize = 1;
*pType = eTokenCloseTag;
break;
/*
*********************************************************************
* Check for tag start and tag end
*********************************************************************
*/
case '<':
/*
*****************************************************************
* Peek at the next character to see if we have an end tag '</',
* or an xml declaration '<?'
*****************************************************************
*/
chTemp = pXML->lpXML[pXML->nIndex];
/*
*****************************************************************
* If we have a tag end...
*****************************************************************
*/
if (chTemp == '/')
{
/*
*************************************************************
* Set the type and ensure we point at the next character
*************************************************************
*/
MrvGetNextChar(pXML);
*pType = eTokenTagEnd;
nSize = 2;
}
/*
*****************************************************************
* If we have an XML declaration tag
*****************************************************************
*/
else if (chTemp == '?')
{
/*
*************************************************************
* Set the type and ensure we point at the next character
*************************************************************
*/
MrvGetNextChar(pXML);
*pType = eTokenDeclaration;
nSize = 2;
}
/*
*****************************************************************
* Otherwise we must have a start tag
*****************************************************************
*/
else
{
*pType = eTokenTagStart;
nSize = 1;
}
break;
/*
*********************************************************************
* Check to see if we have a short hand type end tag ('/>').
*********************************************************************
*/
case '/':
/*
*****************************************************************
* Peek at the next character to see if we have an end tag '</'
* or an xml declaration '<?'
*****************************************************************
*/
chTemp = pXML->lpXML[pXML->nIndex];
/*
*****************************************************************
* If we have a short hand end tag...
*****************************************************************
*/
if (chTemp == '>')
{
/*
*************************************************************
* Set the type and ensure we point at the next character
*************************************************************
*/
MrvGetNextChar(pXML);
*pType = eTokenShortHandClose;
nSize = 2;
break;
}
/*
*****************************************************************
* If we haven't found a short hand closing tag then drop into the
* text process
*****************************************************************
*/
/*
*********************************************************************
* Other characters
*********************************************************************
*/
default:
nIsText = TRUE;
}
/*
*********************************************************************
* If this is a TEXT node
*********************************************************************
*/
if (nIsText)
{
/*
*****************************************************************
* Indicate we are dealing with text
*****************************************************************
*/
*pType = eTokenText;
nSize = 1;
nExit = FALSE;
while((nExit == FALSE) && (ch = MrvGetNextChar(pXML)))
{
switch(ch)
{
/*
*************************************************************
* Break when we find white space
*************************************************************
*/
case '\n':
case ' ':
case '\t':
case '\r':
nExit = TRUE;
break;
/*
*************************************************************
* If we find a slash then this maybe text or a short hand end
* tag.
*************************************************************
*/
case '/':
/*
*********************************************************
* Peek at the next character to see it we have short hand
* end tag
*********************************************************
*/
chTemp = pXML->lpXML[pXML->nIndex];
/*
*********************************************************
* If we found a short hand end tag then we need to exit
* the loop
*********************************************************
*/
if (chTemp == '>')
{
pXML->nIndex--; /* MCB 03.02.2002 */
nExit = TRUE;
}
else
{
nSize++;
}
break;
/*
*************************************************************
* Break when we find a terminator and decrement the index and
* column count so that we are pointing at the right character
* the next time we are called.
*************************************************************
*/
case '<':
case '>':
case '=':
pXML->nIndex--;
nExit = TRUE;
break;
case 0:
nExit = TRUE;
break;
default:
nSize++;
}
}
}
*pcbToken = nSize;
}
/*
*************************************************************************
* If we failed to obtain a valid character
*************************************************************************
*/
else
{
*pcbToken = 0;
*pType = eTokenError;
}
mrvxml_log("%s chTemp =0x%x *pType = %d",__FUNCTION__,chTemp,*pType);
return 0;
}/* MrvGetNextToken */
/**
****************************************************************************
* <P> Parse XML errors into a user friendly string. </P>
*
* @methodName MrvGetError
*
* @param error
*
* @return MRV_LPCTSTR
*
* @exception none
*
****************************************************************************
*/
MRV_LPCTSTR MrvGetError(MrvXMLError error)
{
MRV_LPCTSTR lpszErr = "Unknown";
int n;
/*
*************************************************************************
* Structure for errors array
*************************************************************************
*/
typedef struct McbErrorList
{
enum MrvXMLError err;
MRV_LPCTSTR lpszErr;
} McbErrorList;
/*
*************************************************************************
* Static array containing helpful error text.
*************************************************************************
*/
static struct McbErrorList errs[] =
{
{ eXMLErrorNone, "No error" },
{ eXMLErrorEmpty, "No XML data" },
{ eXMLErrorFirstNotStartTag, "First token not start tag" },
{ eXMLErrorMissingTagName, "Missing start tag name" },
{ eXMLErrorMissingEndTagName, "Missing end tag name" },
{ eXMLErrorNoMatchingQuote, "Unmatched quote" },
{ eXMLErrorUnmatchedEndTag, "Unmatched end tag" },
{ eXMLErrorUnexpectedToken, "Unexpected token found" },
{ eXMLErrorInvalidTag, "Invalid tag found" },
{ eXMLErrorNoElements, "No elements found" },
{ 0, NULL }
};
/*
*************************************************************************
* Iterate through the list of errors to find a matching error
*************************************************************************
*/
for(n = 0; errs[n].lpszErr; n++)
{
if (errs[n].err == error)
{
lpszErr = errs[n].lpszErr;
break;
}
}
return lpszErr;
}/* MrvGetError */
/**
****************************************************************************
* <P> Delete memory associated with a text node. </P>
*
* @methodName MrvDeleteText
*
* @param *pText
*
* @return void
*
* @exception none
*
****************************************************************************
*/
static void MrvDeleteText(MrvXMLText *pText)
{
ASSERT(pText);
if (pText->lpszValue)
{
duster_free(pText->lpszValue);
pText->lpszValue = NULL;
}
}/* MrvDeleteText */
/**
****************************************************************************
* <P> Delete memory associated with a clear (unformatted) node. </P>
*
* @methodName MrvDeleteClear
*
* @param *pClear
*
* @return void
*
* @exception none
*
****************************************************************************
*/
static void MrvDeleteClear(MrvXMLClear *pClear)
{
ASSERT(pClear);
if (pClear->lpszValue)
{
duster_free(pClear->lpszValue);
pClear->lpszValue = NULL;
}
}/* MrvDeleteClear */
/**
****************************************************************************
* <P> Delete a given node. </P>
*
* @methodName MrvDeleteNode
*
* @param *pEntry
*
* @return void
*
* @exception none
*
****************************************************************************
*/
void MrvDeleteNode(MrvXMLNode *pEntry)
{
mrvxml_log("enter %s",__FUNCTION__);
if (pEntry)
{
if (pEntry->type == eNodeEmpty)
{
return;
}
/*
*********************************************************************
* Delete the appropriate node
*********************************************************************
*/
mrvxml_log("%s ,pEntry->type is %d",__FUNCTION__,pEntry->type);
switch(pEntry->type)
{
case eNodeAttribute:
MrvDeleteAttribute(pEntry->node.pAttrib);
/*modified by shoujunl*/
duster_free(pEntry->node.pAttrib);
pEntry->node.pAttrib = NULL;
break;
case eNodeElement:
MrvDeleteElement(pEntry->node.pElement);
duster_free(pEntry->node.pElement);
pEntry->node.pElement = NULL;
break;
case eNodeText:
MrvDeleteText(pEntry->node.pText);
/*modified by shoujunl*/
duster_free(pEntry->node.pText);
pEntry->node.pText = NULL;
break;
case eNodeClear:
MrvDeleteClear(pEntry->node.pClear);
/*modified by shoujunl*/
duster_free(pEntry->node.pClear);
pEntry->node.pClear = NULL;
break;
default:
ASSERT(TRUE);
}
/*modified by shoujunl*/
// duster_free(pEntry->node.pAttrib);
pEntry->type = eNodeEmpty;
}
mrvxml_log("leave %s",__FUNCTION__);
}/* MrvDeleteNode */
/**
****************************************************************************
* <P> Delete an element and all it's contained nodes. </P>
*
* @methodName MrvDeleteElement
*
* @param *pEntry
*
* @return void
*
* @exception none
*
****************************************************************************
*/
void MrvDeleteElement(MrvXMLElement *pEntry)
{
mrvxml_log("enter %s,pEntry->lpszName is %s",__FUNCTION__,pEntry->lpszName);
int n;
ASSERT(pEntry);
/*
*************************************************************************
* Delete each node (this may recurse)
*************************************************************************
*/
for(n = 0; n<pEntry->nSize; n++)
{
MrvDeleteNode(&pEntry->pEntries[n]);
}
/*
*************************************************************************
* Cleanup the list of nodes
*************************************************************************
*/
pEntry->nMax = 0;
pEntry->nSize = 0;
/*modified by shoujunl*/
if(pEntry->pEntries)
duster_free(pEntry->pEntries);
pEntry->pEntries = NULL;
/*
*************************************************************************
* Delete the name of the element
*************************************************************************
*/
if (pEntry->lpszName)
{
duster_free(pEntry->lpszName);
pEntry->lpszName = NULL;
}
/* duster_free(pEntry); */
mrvxml_log("leave %s",__FUNCTION__);
}/* MrvDeleteElement */
/**
****************************************************************************
* <P> Attach nodes from one list to another. </P>
*
* @methodName MrvAttachNodes
*
* @param *pDst
* @param *pSrc
* @param nNum
*
* @return void
*
* @exception none
*
****************************************************************************
*/
static void MrvAttachNodes(MrvXMLNode *pDst, MrvXMLNode *pSrc, int nNum)
{
int n;
for (n=0; n<nNum; n++)
{
pDst[n] = pSrc[n];
pSrc[n].type = eNodeEmpty;
}
}/* MrvAttachNodes */
/**
****************************************************************************
* <P> Reserve memory for additional nodes. </P>
*
* @methodName MrvAllocNodes
*
* @param *pEntry
* @param nGrowBy
*
* @return void
*
* @exception none
*
****************************************************************************
*/
static void MrvAllocNodes(MrvXMLElement *pEntry, int nGrowBy)
{
int nMax, nIndex = 0;
MrvXMLNode * pNew;
ASSERT(pEntry);
ASSERT(nGrowBy > 0);
/*
*************************************************************************
* Allocate storage for new nodes
*************************************************************************
*/
nMax = pEntry->nMax += nGrowBy;
pNew = duster_malloc(sizeof(MrvXMLNode) * nMax);
/*
*************************************************************************
* Attach old entries to the new storage
*************************************************************************
*/
MrvAttachNodes(pNew, pEntry->pEntries, pEntry->nSize);
/*modified by shoujunl*/
for(nIndex = 0;nIndex < pEntry->nSize;nIndex++)
{
MrvDeleteNode(&pEntry->pEntries[nIndex]);
}
if (pEntry->pEntries)
{
duster_free(pEntry->pEntries);
}
pEntry->pEntries = pNew;
}/* MrvAllocNodes */
/**
****************************************************************************
* <P> Add an element node to the element. </P>
*
* @methodName MrvAddElement
*
* @param *pEntry
* @param lpszName
* @param nIsDeclaration
* @param nGrowBy
*
* @return MrvXMLElement *
*
* @exception none
*
****************************************************************************
*/
MrvXMLElement * MrvAddElement(MrvXMLElement *pEntry, MRV_LPTSTR lpszName,
int nIsDeclaration, int nGrowBy)
{
//mrvxml_log("enter %s",__FUNCTION__);
MrvXMLNode *pNode;
MrvXMLElement * pElement;
ASSERT(pEntry);
ASSERT(nGrowBy > 0);
/*
*************************************************************************
* Check we have enough storage
*************************************************************************
*/
if (pEntry->nSize == pEntry->nMax)
{
MrvAllocNodes(pEntry, nGrowBy);
}
/*
*************************************************************************
* Obtain the new node, set the type and initialise it.
*************************************************************************
*/
pNode = &pEntry->pEntries[pEntry->nSize];
pNode->type = eNodeElement;
pElement = duster_malloc(sizeof(MrvXMLElement));
pNode->node.pElement = pElement;
MrvInitElement(pElement, pEntry, lpszName, nIsDeclaration);
/*
*************************************************************************
* Increment the number of contained nodes
*************************************************************************
*/
pEntry->nSize++;
/*
*************************************************************************
* Return the new element.
*************************************************************************
*/
// mrvxml_log("leave %s",__FUNCTION__);
return pElement;
}/* MrvAddElement */
/**
****************************************************************************
* <P> Add an attribute to an element. </P>
*
* @methodName MrvAddAttribute
*
* @param *pEntry
* @param lpszName
* @param lpszValue
* @param nGrowBy
*
* @return MrvXMLAttribute *
*
* @exception none
*
****************************************************************************
*/
MrvXMLAttribute * MrvAddAttribute(MrvXMLElement *pEntry, MRV_LPTSTR lpszName,
MRV_LPTSTR lpszValue, int nGrowBy)
{
MrvXMLNode *pNode;
MrvXMLAttribute *pAttr;
ASSERT(pEntry);
ASSERT(nGrowBy > 0);
/*
*************************************************************************
* Check we have enough storage
*************************************************************************
*/
if (pEntry->nSize == pEntry->nMax)
{
MrvAllocNodes(pEntry, nGrowBy);
}
/*
*************************************************************************
* Obtain the new node, set the type and initialise it.
*************************************************************************
*/
pNode = &pEntry->pEntries[pEntry->nSize];
pNode->type = eNodeAttribute;
pAttr = duster_malloc(sizeof(MrvXMLAttribute));
pNode->node.pAttrib = pAttr;
//pAttr->lpszName = lpszName;
//pAttr->lpszValue = lpszValue;
//toby add 2006/7/4 10:03
pAttr->lpszName = lpszName;//MrvStrdup(lpszName,0);
pAttr->lpszValue = lpszValue;//MrvStrdup(lpszValue,0);
/*
*************************************************************************
* Increment the number of contained nodes
*************************************************************************
*/
pEntry->nSize++;
/*
*************************************************************************
* Return the new attribute.
*************************************************************************
*/
return pAttr;
}/* MrvAddAttribute */
/**
****************************************************************************
* <P> Add text to the element. </P>
*
* @methodName * MrvAddText
*
* @param *pEntry
* @param lpszValue
* @param nGrowBy
*
* @return MrvAddText
*
* @exception none
*
****************************************************************************
*/
MrvXMLText * MrvAddText(MrvXMLElement *pEntry, MRV_LPTSTR lpszValue, int nGrowBy)
{
MrvXMLNode *pNode;
MrvXMLText *pText;
ASSERT(pEntry);
ASSERT(nGrowBy > 0);
/*
*************************************************************************
* Check we have enough storage
*************************************************************************
*/
if (pEntry->nSize == pEntry->nMax)
{
MrvAllocNodes(pEntry, nGrowBy);
}
/*
*************************************************************************
* Obtain the new node, set the type and initialise it.
*************************************************************************
*/
pNode = &pEntry->pEntries[pEntry->nSize];
pNode->type = eNodeText;
pText = duster_malloc(sizeof(MrvXMLText));
pNode->node.pText = pText;
pText->lpszValue = lpszValue;
/*
*************************************************************************
* Increment the number of contained nodes
*************************************************************************
*/
pEntry->nSize++;
/*
*************************************************************************
* Return the new attribute.
*************************************************************************
*/
return pText;
}/* MrvAddText */
/**
****************************************************************************
* <P> Add clear (unformatted) to the element. </P>
*
* @methodName * MrvAddClear
*
* @param *pEntry
* @param lpszValue
* @param nGrowBy
*
* @return MrvXMLClear
*
* @exception none
*
****************************************************************************
*/
static MrvXMLClear * MrvAddClear(MrvXMLElement *pEntry, MRV_LPTSTR lpszValue,
MrvClearTag *pClear, int nGrowBy)
{
MrvXMLNode *pNode;
MrvXMLClear *pNewClear;
ASSERT(pEntry);
ASSERT(nGrowBy > 0);
/*
*************************************************************************
* Check we have enough storage
*************************************************************************
*/
if (pEntry->nSize == pEntry->nMax)
{
MrvAllocNodes(pEntry, nGrowBy);
}
/*
*************************************************************************
* Obtain the new node, set the type and initialise it.
*************************************************************************
*/
pNode = &pEntry->pEntries[pEntry->nSize];
pNode->type = eNodeClear;
pNewClear = duster_malloc(sizeof(MrvXMLClear));
pNode->node.pClear = pNewClear;
pNewClear->lpszValue = lpszValue;
pNewClear->lpszOpenTag = pClear->lpszOpen;
pNewClear->lpszCloseTag = pClear->lpszClose;
/*
*************************************************************************
* Increment the number of contained nodes
*************************************************************************
*/
pEntry->nSize++;
/*
*************************************************************************
* Return the new attribute.
*************************************************************************
*/
return pNewClear;
}/* MrvAddClear */
/**
****************************************************************************
* <P> Enumerate nodes in the list. </P>
*
* @methodName MrvEnumNodes
*
* @param *pEntry
* @param *pnIndex
*
* @return MrvEnumNodes
*
* @exception none
*
****************************************************************************
*/
MrvXMLNode * MrvEnumNodes(MrvXMLElement *pEntry, int *pnIndex)
{
MrvXMLNode * pResult = NULL;
ASSERT(pnIndex);
ASSERT(pEntry);
if (*pnIndex < pEntry->nSize)
{
pResult = &pEntry->pEntries[*pnIndex];
(*pnIndex)++;
}
return pResult;
}/* MrvXMLNode */
/**
****************************************************************************
* <P> Enumerate elements on a base element. </P>
*
* @methodName MrvEnumElements
*
* @param *pEntry
* @param *pnIndex
*
* @return MrvXMLNode
*
* @exception none
*
* @author Martyn C Brown
*
* @changeHistory
* 20th August 2001 - (V1.0) Creation (MCB)
****************************************************************************
*/
MrvXMLElement * MrvEnumElements(MrvXMLElement *pEntry, int *pnIndex)
{
MrvXMLElement * pResult = NULL;
int nIndex;
ASSERT(pnIndex);
ASSERT(pEntry);
nIndex = *pnIndex;
for (;nIndex < pEntry->nSize && !pResult; nIndex++)
{
if (pEntry->pEntries[nIndex].type == eNodeElement)
{
pResult = pEntry->pEntries[nIndex].node.pElement;
//mrvxml_log("%s Element type pResult.lpszName is %s,nsize is %d",__FUNCTION__,pResult->lpszName,pResult->nSize);
}
}
*pnIndex = nIndex;
return pResult;
}/* MrvEnumElements */
/**
****************************************************************************
* <P> Enumerate attributes on a base element. </P>
*
* @methodName MrvEnumAttributes
*
* @param *pEntry
* @param *pnIndex
*
* @return MrvXMLNode
*
* @exception none
*
****************************************************************************
*/
MrvXMLAttribute * MrvEnumAttributes(MrvXMLElement *pEntry, int *pnIndex)
{
MrvXMLAttribute * pResult = NULL;
int nIndex;
ASSERT(pnIndex);
ASSERT(pEntry);
nIndex = *pnIndex;
for (;nIndex < pEntry->nSize && !pResult; nIndex++)
{
if (pEntry->pEntries[nIndex].type == eNodeAttribute)
{
pResult = pEntry->pEntries[nIndex].node.pAttrib;
}
}
*pnIndex = nIndex;
return pResult;
}/* MrvEnumAttributes */
/**
****************************************************************************
* <P> Trim the end of the text to remove white space characters. </P>
*
* @methodName MrvFindEndOfText
*
* @param lpszToken
* @param *pcbText
*
* @return void
*
* @exception none
*
****************************************************************************
*/
static void MrvFindEndOfText(MRV_LPCTSTR lpszToken, int *pcbText)
{
MRV_TCHAR ch;
int cbText;
ASSERT(lpszToken);
ASSERT(pcbText);
cbText = (*pcbText)-1;
while(TRUE)
{
ASSERT(cbText >= 0);
ch = lpszToken[cbText];
switch(ch)
{
case '\r':
case '\n':
case '\t':
case ' ':
cbText--;
break;
default:
*pcbText = cbText+1;
return;
}
}
}/* MrvFindEndOfText */
/**
****************************************************************************
* <P> Parse a clear (unformatted) type node. </P>
*
* @methodName MrvParseClearTag
*
* @param *pXML
* @param *pElement
* @param lpszClose
* @param lpszToken
*
* @return int
*
* @exception none
****************************************************************************
*/
static int MrvParseClearTag(MrvXML *pXML, MrvXMLElement *pElement, MrvClearTag * pClear)
{
int cbTemp = 0;
MRV_LPTSTR lpszTemp;
MRV_LPCTSTR lpszXML = &pXML->lpXML[pXML->nIndex];
/*
*************************************************************************
* Find the closing tag
*************************************************************************
*/
//lpszTemp = _tcsstr(lpszXML, pClear->lpszClose);
lpszTemp = strstr(lpszXML, pClear->lpszClose);
/*
*************************************************************************
* Iterate through the tokens until we find the closing tag.
*************************************************************************
*/
if (lpszTemp)
{
/*
*********************************************************************
* Cache the size and increment the index
*********************************************************************
*/
cbTemp = lpszTemp - lpszXML;
pXML->nIndex += cbTemp;
pXML->nIndex += strlen(pClear->lpszClose);
/*
*********************************************************************
* Add the clear node to the current element
*********************************************************************
*/
lpszTemp = MrvStrdup(lpszXML, cbTemp);
MrvAddClear(pElement, lpszTemp, pClear, MrvGROWBY);
#ifdef MrvSTOREOFFSETS
pElement->pEntries[pElement->nSize-1].nStringOffset = (lpszXML -
strlen(pClear->lpszOpen)) - pXML->lpXML;
#endif /* MrvSTOREOFFSETS */
return TRUE;
}
/*
*************************************************************************
* If we failed to find the end tag
*************************************************************************
*/
else
{
mrvxml_log("%s pClear is 0x%x,%c",__FUNCTION__,pClear,pClear);
pXML->error = eXMLErrorUnmatchedEndTag;
return FALSE;
}
}/* MrvParseClearTag */
/**
****************************************************************************
* <P> Recursively parse an XML element. </P>
*
* @methodName MrvParseXMLElement
*
* @param *pXML
* @param * pElement
*
* @return int
*
* @exception none
*
****************************************************************************
*/
static int MrvParseXMLElement(MrvXML *pXML, MrvXMLElement * pElement)
{
//mrvxml_log("enter %s");
MRV_LPCTSTR lpszToken;
int cbToken;
enum MrvTokenType type;
MrvNextToken token;
MRV_LPCTSTR lpszTemp = NULL;
int cbTemp;
int nDeclaration;
MRV_LPCTSTR lpszText = NULL;
MrvXMLElement *pNew;
enum MrvStatus status;
enum MrvAttrib attrib = eAttribName;
ASSERT(pXML);
ASSERT(pElement);
if(pElement->lpszName){
mrvxml_log("%s,pElement->lpszname is %s",__FUNCTION__,pElement->lpszName);
}
/*
*************************************************************************
* If this is the first call to the function
*************************************************************************
*/
if (pXML->nFirst)
{
/*
*********************************************************************
* Assume we are outside of a tag definition
*********************************************************************
*/
pXML->nFirst = FALSE;
status = eOutsideTag;
}
/*
*************************************************************************
* If this is not the first call then we should only be called when inside
* a tag.
*************************************************************************
*/
else
{
status = eInsideTag;
}
/*
*************************************************************************
* Iterate through the tokens in the document
*************************************************************************
*/
while(TRUE)
{
/*
*********************************************************************
* Obtain the next token
*********************************************************************
*/
MrvGetNextToken(pXML, &cbToken, &type , &token);
mrvxml_log("%s,type = %d,status = %d",__FUNCTION__,type,status);
if (type != eTokenError)
{
/*
*****************************************************************
* Check the current status
*****************************************************************
*/
switch(status)
{
/*
*****************************************************************
* If we outside of a tag definition
*****************************************************************
*/
case eOutsideTag:
/*
*************************************************************
* Check what type of token we obtained
*************************************************************
*/
switch(type)
{
/*
*************************************************************
* If we have found text or quoted text
*************************************************************
*/
case eTokenText:
case eTokenQuotedText:
case eTokenEquals:
if (!lpszText)
{
lpszText = token.pStr;
}
break;
/*
*************************************************************
* If we found a start tag '<' and declarations '<?'
*************************************************************
*/
case eTokenTagStart:
case eTokenDeclaration:
/*
*********************************************************
* Cache whether this new element is a declaration or not
*********************************************************
*/
nDeclaration = type == eTokenDeclaration;
/*
*********************************************************
* If we have node text then add this to the element
*********************************************************
*/
if (lpszText)
{
cbTemp = token.pStr - lpszText;
MrvFindEndOfText(lpszText, &cbTemp);
MrvAddText(pElement, MrvStrdup(lpszText, cbTemp),
MrvGROWBY);
#ifdef MrvSTOREOFFSETS
pElement->pEntries[pElement->nSize-1].nStringOffset
= lpszText - pXML->lpXML;
#endif /* MrvSTOREOFFSETS */
lpszText = NULL;
}
/*
*********************************************************
* Find the name of the tag
*********************************************************
*/
//token = MrvGetNextToken(pXML, &cbToken, &type);
MrvGetNextToken(pXML, &cbToken, &type , &token);
mrvxml_log("%s, find name of tag type = %d,status = %d",__FUNCTION__,type,status);
/*
*********************************************************
* Return an error if we couldn't obtain the next token or
* it wasnt text
*********************************************************
*/
if (type != eTokenText)
{
pXML->error = eXMLErrorMissingTagName;
return FALSE;
}
/*
*********************************************************
* If we found a new element which has the same as this
* element then we need to pass this back to the caller..
*********************************************************
*/
/*modified by shoujunl*/
/*
if (pElement->lpszName &&
strncmp(pElement->lpszName, token.pStr,
strlen(pElement->lpszName)) == 0)*/
mrvxml_log("%s,strlen(pElement->lpszName) is %d,cbToken =%d",__FUNCTION__,pElement->lpszName,cbToken);
mrvxml_log("%s,pElement->lpszName is %s",__FUNCTION__,pElement->lpszName);
if (pElement->lpszName && (strlen(pElement->lpszName) == (unsigned int)cbToken)&&
strncmp(pElement->lpszName, token.pStr,
strlen(pElement->lpszName)) == 0)
{
/*
*****************************************************
* Indicate to the caller that it needs to create a
* new element.
*****************************************************
*/
mrvxml_log("%s need to add a new element,pElement->lpszName is %s",__FUNCTION__,pElement->lpszName);
pXML->lpNewElement = token.pStr;
pXML->cbNewElement = cbToken;
return TRUE;
}
/*
*********************************************************
* If the name of the new element differs from the name of
* the current element we need to add the new element to
* the current one and recurse
*********************************************************
*/
else
{
/*
*****************************************************
* Now we need to add the new element and recurse
*****************************************************
*/
pNew = MrvAddElement(pElement,
MrvStrdup(token.pStr, cbToken), nDeclaration,
MrvGROWBY);
mrvxml_log("%s add a new element pElement->lpszName is %s",__FUNCTION__,pElement->lpszName);
#ifdef MrvSTOREOFFSETS
pElement->pEntries[pElement->nSize-1].nStringOffset =
token.pStr - pXML->lpXML;
#endif /* MrvSTOREOFFSETS */
while(pNew)
{
/*
*************************************************
* Callself to process the new node. If we return
* FALSE this means we dont have any more
* processing to do...
*************************************************
*/
if (!MrvParseXMLElement(pXML, pNew))
{
return FALSE;
}
else
{
mrvxml_log("%s recurse back,OK,pElement->lpszname is %s,pElement->nSize is %d",__FUNCTION__,pElement->lpszName,pElement->nSize);
/*
*********************************************
* If the call to recurse this function
* evented in a end tag specified in XML then
* we need to unwind the calls to this
* function until we find the appropriate node
* (the element name and end tag name must
* match)
*********************************************
*/
if (pXML->cbEndTag)
{
/*
*****************************************
* If we are back at the root node then we
* have an unmatched end tag
*****************************************
*/
if (!pElement->lpszName)
{
pXML->error = eXMLErrorUnmatchedEndTag;
mrvxml_log("%s ,back at the root node",__FUNCTION__);
if(pElement->pParent){
mrvxml_log("%s pParent->lpszName is %s",__FUNCTION__,pElement->pParent->lpszName);
}
return FALSE;
}
/*
*****************************************
* If the end tag matches the name of this
* element then we only need to unwind
* once more...
*****************************************
*/
/*modified by shoujunl*/
/*
if (strncmp(pXML->lpEndTag,
pElement->lpszName,
strlen(pElement->lpszName)) == 0)
*/
mrvxml_log("%s ,pXML->cbEndTag = %d,strlen(pElement->lpszName) = %d",__FUNCTION__,pXML->cbEndTag,strlen(pElement->lpszName));
mrvxml_log("%s,pElement->lpszName is %s",__FUNCTION__,pElement->lpszName);
if (((unsigned int)pXML->cbEndTag == strlen(pElement->lpszName))&&
strncmp(pXML->lpEndTag, pElement->lpszName, strlen(pElement->lpszName)) == 0)
{
pXML->cbEndTag = 0;
}
return TRUE;
}
/*
*********************************************
* If the call indicated a new element is to
* be created on THIS element.
*********************************************
*/
else if (pXML->cbNewElement)
{
/*
*****************************************
* If the name of this element matches the
* name of the element we need to create
* then we need to return to the caller
* and let it process the element.
*****************************************
*/
/*modified by shoujunl*/
/*
if (strncmp(pXML->lpNewElement,
pElement->lpszName,
strlen(pElement->lpszName)) == 0)
*/
mrvxml_log("%s,strlen(pElement->lpszName) = %d,pXML->cbNewElement =%d",__FUNCTION__,strlen(pElement->lpszName),pXML->cbNewElement);
mrvxml_log("%s,pElement->lpszName is %s",__FUNCTION__,pElement->lpszName);
if ((strlen(pElement->lpszName) == (unsigned int)pXML->cbNewElement)&&
(strncmp(pXML->lpNewElement, pElement->lpszName, strlen(pElement->lpszName)) == 0))
{
return TRUE;
}
/*
*****************************************
* Add the new element and recurse
*****************************************
*/
pNew = MrvAddElement(pElement,
MrvStrdup(pXML->lpNewElement,
pXML->cbNewElement), FALSE,
MrvGROWBY);
#ifdef MrvSTOREOFFSETS
pElement->pEntries[pElement->nSize-1].
nStringOffset =
pXML->lpNewElement - pXML->lpXML;
#endif /* MrvSTOREOFFSETS */
pXML->cbNewElement = 0;
}
/*
*********************************************
* If we didn't have a new element to create
*********************************************
*/
else
{
pNew = NULL;
}
}
}
}
break;
/*
*************************************************************
* If we found an end tag
*************************************************************
*/
case eTokenTagEnd:
/*
*********************************************************
* If we have node text then add this to the element
*********************************************************
*/
if (lpszText)
{
cbTemp = token.pStr - lpszText;
MrvFindEndOfText(lpszText, &cbTemp);
MrvAddText(pElement, MrvStrdup(lpszText, cbTemp),
MrvGROWBY);
#ifdef MrvSTOREOFFSETS
pElement->pEntries[pElement->nSize-1].nStringOffset
= lpszText - pXML->lpXML;
#endif /* MrvSTOREOFFSETS */
lpszText = NULL;
}
/*
*********************************************************
* Find the name of the end tag
*********************************************************
*/
//token = MrvGetNextToken(pXML, &cbTemp, &type);
MrvGetNextToken(pXML, &cbTemp, &type , &token);
/*
*********************************************************
* The end tag should be text
*********************************************************
*/
if (type != eTokenText)
{
pXML->error = eXMLErrorMissingEndTagName;
return FALSE;
}
lpszTemp = token.pStr;
/*
*********************************************************
* After the end tag we should find a closing tag
*********************************************************
*/
//token = MrvGetNextToken(pXML, &cbToken, &type);
MrvGetNextToken(pXML, &cbToken, &type , &token);
if (type != eTokenCloseTag)
{
pXML->error = eXMLErrorMissingEndTagName;
return FALSE;
}
/*
*********************************************************
* We need to return to the previous caller. If the name
* of the tag cannot be found we need to keep returning to
* caller until we find a match
*********************************************************
*/
/*modified by shoujunl*/
/*
if (strncmp(lpszTemp, pElement->lpszName,
strlen(pElement->lpszName)) != 0)
*/
mrvxml_log("%s,pElement->lpszName is %s",__FUNCTION__,pElement->lpszName);
mrvxml_log("%s,cbTemp = %d,strlen(pElement->lpszName) is %d",__FUNCTION__,cbTemp,strlen(pElement->lpszName));
if (((unsigned int)cbTemp != strlen(pElement->lpszName))||
strncmp(lpszTemp, pElement->lpszName,
strlen(pElement->lpszName)) != 0)
{
pXML->lpEndTag = lpszTemp;
pXML->cbEndTag = cbTemp;
}
/*
*********************************************************
* Return to the caller
*********************************************************
*/
return TRUE;
/*
*************************************************************
* If we found a clear (unformatted) token
*************************************************************
*/
case eTokenClear:
/*
*********************************************************
* If we have node text then add this to the element
*********************************************************
*/
if (lpszText)
{
cbTemp = token.pStr - lpszText;
MrvFindEndOfText(lpszText, &cbTemp);
MrvAddText(pElement, MrvStrdup(lpszText, cbTemp),
MrvGROWBY);
#ifdef MrvSTOREOFFSETS
pElement->pEntries[pElement->nSize-1].nStringOffset
= lpszText - pXML->lpXML;
#endif /* MrvSTOREOFFSETS */
lpszText = NULL;
}
if (!MrvParseClearTag(pXML, pElement, token.pClr))
{
return FALSE;
}
break;
/*
*************************************************************
* Errors...
*************************************************************
*/
case eTokenCloseTag: /* '>' */
case eTokenShortHandClose: /* '/>' */
pXML->error = eXMLErrorUnexpectedToken;
return FALSE;
break;
default:
break;
}
break;
/*
*****************************************************************
* If we are inside a tag definition we need to search for
* attributes
*****************************************************************
*/
case eInsideTag:
/*
*************************************************************
* Check what part of the attribute (name, equals, value) we
* are looking for.
*************************************************************
*/
switch(attrib)
{
/*
************************************************************
* If we are looking for a new attribute
************************************************************
*/
case eAttribName:
/*
*********************************************************
* Check what the current token type is
*********************************************************
*/
switch(type)
{
/*
*********************************************************
* If the current type is text...
* Eg. 'attribute'
*********************************************************
*/
case eTokenText:
/*
*****************************************************
* Cache the token then indicate that we are next to
* look for the equals
*****************************************************
*/
lpszTemp = token.pStr;
cbTemp = cbToken;
attrib = eAttribEquals;
break;
/*
*********************************************************
* If we found a closing tag...
* Eg. '>'
*********************************************************
*/
case eTokenCloseTag:
/*
*****************************************************
* We are now outside the tag
*****************************************************
*/
status = eOutsideTag;
break;
/*
*********************************************************
* If we found a short hand '/>' closing tag then we can
* return to the caller
*********************************************************
*/
case eTokenShortHandClose:
return TRUE;
/*
*********************************************************
* Errors...
*********************************************************
*/
case eTokenQuotedText: /* '"SomeText"' */
case eTokenTagStart: /* '<' */
case eTokenTagEnd: /* '</' */
case eTokenEquals: /* '=' */
case eTokenDeclaration: /* '<?' */
case eTokenClear:
pXML->error = eXMLErrorUnexpectedToken;
return FALSE;
default:
break;
}
break;
/*
************************************************************
* If we are looking for an equals
************************************************************
*/
case eAttribEquals:
/*
*********************************************************
* Check what the current token type is
*********************************************************
*/
switch(type)
{
/*
*********************************************************
* If the current type is text...
* Eg. 'Attribute AnotherAttribute'
*********************************************************
*/
case eTokenText:
/*
*****************************************************
* Add the unvalued attribute to the list
*****************************************************
*/
MrvAddAttribute(pElement, MrvStrdup(lpszTemp,
cbTemp), NULL, MrvGROWBY);
#ifdef MrvSTOREOFFSETS
pElement->pEntries[pElement->nSize-1].nStringOffset =
lpszTemp - pXML->lpXML;
#endif /* MrvSTOREOFFSETS */
/*
*****************************************************
* Cache the token then indicate. We are next to
* look for the equals attribute
*****************************************************
*/
lpszTemp = token.pStr;
cbTemp = cbToken;
break;
/*
*********************************************************
* If we found a closing tag 'Attribute >' or a short hand
* closing tag 'Attribute />'
*********************************************************
*/
case eTokenShortHandClose:
case eTokenCloseTag:
/*
*****************************************************
* If we are a declaration element '<?' then we need
* to remove extra closing '?' if it exists
*****************************************************
*/
if (pElement->nIsDeclaration &&
(lpszTemp[cbTemp-1]) == '?')
{
cbTemp--;
}
if (cbTemp)
{
/*
*************************************************
* Add the unvalued attribute to the list
*************************************************
*/
MrvAddAttribute(pElement, MrvStrdup(lpszTemp,
cbTemp), NULL, MrvGROWBY);
#ifdef MrvSTOREOFFSETS
pElement->pEntries[pElement->nSize-1].
nStringOffset = lpszTemp - pXML->lpXML;
#endif /* MrvSTOREOFFSETS */
}
/*
*****************************************************
* If this is the end of the tag then return to the
* caller
*****************************************************
*/
if (type == eTokenShortHandClose)
{
return TRUE;
}
/*
*****************************************************
* We are now outside the tag
*****************************************************
*/
status = eOutsideTag;
break;
/*
*********************************************************
* If we found the equals token...
* Eg. 'Attribute ='
*********************************************************
*/
case eTokenEquals:
/*
*****************************************************
* Indicate that we next need to search for the value
* for the attribute
*****************************************************
*/
attrib = eAttribValue;
break;
/*
*********************************************************
* Errors...
*********************************************************
*/
case eTokenQuotedText: /* 'Attribute "InvalidAttr"'*/
case eTokenTagStart: /* 'Attribute <' */
case eTokenTagEnd: /* 'Attribute </' */
case eTokenDeclaration: /* 'Attribute <?' */
case eTokenClear:
pXML->error = eXMLErrorUnexpectedToken;
return FALSE;
default:
break;
}
break;
/*
************************************************************
* If we are looking for an attribute value
************************************************************
*/
case eAttribValue:
/*
*********************************************************
* Check what the current token type is
*********************************************************
*/
switch(type)
{
/*
*********************************************************
* If the current type is text or quoted text...
* Eg. 'Attribute = "Value"' or 'Attribute = Value' or
* 'Attribute = 'Value''.
*********************************************************
*/
case eTokenText:
case eTokenQuotedText:
/*
*****************************************************
* If we are a declaration element '<?' then we need
* to remove extra closing '?' if it exists
*****************************************************
*/
if (pElement->nIsDeclaration &&
(token.pStr[cbToken-1]) == '?')
{
cbToken--;
}
if (cbTemp)
{
lpszToken = MrvStrdup(token.pStr, cbToken);
}
else
{
lpszToken = NULL;
}
/*
*****************************************************
* Add the valued attribute to the list
*****************************************************
*/
MrvAddAttribute(pElement, MrvStrdup(lpszTemp,
cbTemp), (MRV_LPTSTR)lpszToken, MrvGROWBY);
#ifdef MrvSTOREOFFSETS
pElement->pEntries[pElement->nSize-1].nStringOffset
= lpszTemp - pXML->lpXML;
#endif /* MrvSTOREOFFSETS */
/*
*****************************************************
* Indicate we are searching for a new attribute
*****************************************************
*/
attrib = eAttribName;
break;
/*
*********************************************************
* Errors...
*********************************************************
*/
case eTokenTagStart: /* 'Attr = <' */
case eTokenTagEnd: /* 'Attr = </' */
case eTokenCloseTag: /* 'Attr = >' */
case eTokenShortHandClose: /* "Attr = />" */
case eTokenEquals: /* 'Attr = =' */
case eTokenDeclaration: /* 'Attr = <?' */
case eTokenClear:
pXML->error = eXMLErrorUnexpectedToken;
return FALSE;
break;
default:
break;
}
}
}
}
/*
*********************************************************************
* If we failed to obtain the next token
*********************************************************************
*/
else
{
return FALSE;
}
}
//mrvxml_log("leave %s");
}/* MrvParseXMLElement */
/**
****************************************************************************
* <P> Count the number of lines and columns in an XML string. </P>
*
* @methodName MrvCountLinesAndColumns
*
* @param lpXML
* @param nUpto
* @param *pResults
*
* @return void
*
* @exception none
*
****************************************************************************
*/
static void MrvCountLinesAndColumns(MRV_LPCTSTR lpXML, int nUpto, MrvXMLResults *pResults)
{
MRV_TCHAR ch;
int n;
ASSERT(lpXML);
ASSERT(pResults);
pResults->nLine = 1;
pResults->nColumn = 1;
for(n=0; n<nUpto; n++)
{
ch = lpXML[n];
ASSERT(ch);
if (ch == '\n')
{
pResults->nLine++;
pResults->nColumn = 1;
}
else
{
pResults->nColumn++;
}
}
}/* MrvCountLinesAndColumns */
/**
****************************************************************************
* <P> Obtain tags used for unformatted text within elements. </P>
*
* @methodName * MrvGetClearTags
*
* @param none
*
* @return MrvClearTag
*
* @exception none
*
****************************************************************************
*/
static MrvClearTag * MrvGetClearTags()
{
static struct MrvClearTag tags[] =
{
{ "<![CDATA[", "]]>" },
{ "<PRE>", "</PRE>" },
{ "<Script>", "</Script>" },
{ "<!--", "-->" },
{ "<!DOCTYPE", ">" },
{ NULL, NULL }
};
return tags;
}/* MrvGetClearTags */
#define MrvGETCDATA() &MrvGetClearTags()[0]
/**
****************************************************************************
* <P> Parse XML and return the root element. </P>
*
* @methodName * MrvParseXML
*
* @param lpszXML
* @param *pResults
*
* @return MrvXMLElement
*
* @exception none
*
****************************************************************************
*/
MrvXMLElement * MrvParseXML(MRV_LPCTSTR lpszXML, MrvXMLResults *pResults)
{
//mrvxml_log("enter %s",__FUNCTION__);
enum MrvXMLError error;
struct MrvXMLElement * pElement = NULL;
struct MrvXML xml =
{ NULL, 0, 0, NULL, 0, NULL, 0, TRUE , NULL };
xml.lpXML = lpszXML;
xml.pClrTags = MrvGetClearTags();
/*
*************************************************************************
* Create header element
*************************************************************************
*/
pElement = MrvCreateRoot();
MrvParseXMLElement(&xml, pElement);
error = xml.error;
mrvxml_log("%s, error is %d",__FUNCTION__,error);
/*
*************************************************************************
* If an error occurred
*************************************************************************
*/
if (error != eXMLErrorNone)
{
/*
*********************************************************************
* Cleanup
*********************************************************************
*/
MrvDeleteRoot(pElement);
pElement = NULL;
}
/*
*************************************************************************
* If we hae been given somewhere to place results
*************************************************************************
*/
if (pResults)
{
pResults->error = error;
/*
*********************************************************************
* If we have an error
*********************************************************************
*/
if (error != eXMLErrorNone)
{
/*
*****************************************************************
* Find which line and column it starts on.
*****************************************************************
*/
MrvCountLinesAndColumns(xml.lpXML, xml.nIndex, pResults);
mrvxml_log("%s error starts on Line %d, column %d", __FUNCTION__, pResults->nLine, pResults->nColumn);
}
}
//duster_free(lpszXML);
//lpszXML = NULL;
xml.lpXML = NULL;
//mrvxml_log("leave %s",__FUNCTION__);
return pElement;
}/* MrvParseXML */
/**
****************************************************************************
* <P> Search for an element in the list. </P>
*
* @methodName * MrvFindElement
*
* @param lpszName
*
* @return MrvXMLElement
*
* @exception none
*
****************************************************************************
*/
MrvXMLElement * MrvFindElement(MrvXMLElement *pEntry, MRV_LPCTSTR lpszPath)
{
MrvXMLElement * pChild;
MRV_LPCTSTR lpszName;
MRV_LPCTSTR lpszNext;
int cbName, nlpszNameLen = 0;
int nIndex;
ASSERT(lpszPath);
ASSERT(pEntry);
/*
*************************************************************************
* Find the next name in the path in case we need to recurse
*************************************************************************
*/
lpszNext = strchr(lpszPath, '/');
/*
*************************************************************************
* Calculate the length of the current name we are searching for
*************************************************************************
*/
if (!lpszNext)
{
cbName = strlen(lpszPath);
}
else
{
cbName = lpszNext - lpszPath;
if (lpszNext[1])
{
lpszNext++;
}
else
{
lpszNext = NULL;
}
}
if (cbName)
{
/*
*********************************************************************
* Enumerate child elements
*********************************************************************
*/
nIndex = 0;
while((pChild = MrvEnumElements(pEntry, &nIndex)))
{
/*
*****************************************************************
* Obtain the name of the child element
*****************************************************************
*/
lpszName = pChild->lpszName;
if (lpszName)
{
/*
*************************************************************
* If the name of the element is what we are looking for
*************************************************************
*/
/*modified by shoujunl*/
nlpszNameLen = strlen(lpszName);
if ((nlpszNameLen == cbName)&& strncmp(lpszPath, lpszName, cbName) == 0)
{
/*
*********************************************************
* Check if this is the last element to search for
*********************************************************
*/
if (!lpszNext)
{
return pChild;
}
/*
*********************************************************
* If we have further nodes to find then recurse.
*********************************************************
*/
else
{
return MrvFindElement(pChild, lpszNext);
}
}
}
}
}
return NULL;
}/* MrvFindElement */
/**
****************************************************************************
* <P> Find an attribute on an element. </P>
*
* @methodName * MrvFindAttribute
*
* @param *pEntry
* @param lpszAttrib
*
* @return MrvXMLAttribute
*
* @exception none
*
****************************************************************************
*/
MrvXMLAttribute * MrvFindAttribute(MrvXMLElement *pEntry, MRV_LPCTSTR lpszAttrib)
{
MrvXMLAttribute * pAttr;
int cbAttrib;
int nIndex;
ASSERT(pEntry);
ASSERT(lpszAttrib);
cbAttrib = strlen(lpszAttrib);
nIndex = 0;
while((pAttr = MrvEnumAttributes(pEntry, &nIndex)))
{
if (strncmp(pAttr->lpszName, lpszAttrib, cbAttrib) == 0)
{
return pAttr;
}
}
return NULL;
}/* MrvFindAttribute */
/**
****************************************************************************
* <P> Add CData to the element. </P>
*
* @methodName * MrvAddCData
*
* @param *pEntry
* @param lpszValue
* @param nGrowBy
*
* @return MrvXMLClear
*
* @exception none
* ****************************************************************************
*/
MrvXMLClear * MrvAddCData(MrvXMLElement *pEntry, MRV_LPTSTR lpszValue, int nGrowBy)
{
return MrvAddClear(pEntry, lpszValue, MrvGETCDATA(), nGrowBy);
}/* MrvAddCData */
/**
****************************************************************************
* <P> Add elements to the list if they do not exist, return the final node.
* </P>
*
* @methodName * MrvCreateElements
*
* @param *pEntry
* @param lpszPath
*
* @return MrvXMLElement
*
* @exception none
*
****************************************************************************
*/
MrvXMLElement * MrvCreateElements(MrvXMLElement *pEntry, MRV_LPCTSTR lpszPath)
{
MrvXMLElement * pChild;
MrvXMLElement * pNew;
MRV_LPCTSTR lpszName;
MRV_LPCTSTR lpszNext;
int cbName;
int nIndex;
ASSERT(lpszPath);
ASSERT(pEntry);
/*
*************************************************************************
* Find the next name in the path in case we need to recurse
*************************************************************************
*/
lpszNext = strchr(lpszPath, '/');
/*
*************************************************************************
* Calculate the length of the current name we are searching for
*************************************************************************
*/
if (!lpszNext)
{
cbName = strlen(lpszPath);
}
else
{
cbName = lpszNext - lpszPath;
if (lpszNext[1])
{
lpszNext++;
}
else
{
lpszNext = NULL;
}
}
if (cbName)
{
/*
*********************************************************************
* Enumerate child elements
*********************************************************************
*/
nIndex = 0;
while((pChild = MrvEnumElements(pEntry, &nIndex)))
{
/*
*****************************************************************
* Obtain the name of the child element
*****************************************************************
*/
lpszName = pChild->lpszName;
if (lpszName)
{
/*
*************************************************************
* If the name of the element is what we are looking for
*************************************************************
*/
if (strncmp(lpszPath, lpszName, cbName) == 0)
{
/*
*********************************************************
* Check if this is the last element to search for
*********************************************************
*/
if (!lpszNext)
{
return pChild;
}
/*
*********************************************************
* If we have further nodes to find then recurse.
*********************************************************
*/
else
{
return MrvCreateElements(pChild, lpszNext);
}
}
}
}
/*
*********************************************************************
* If we got this far then we couldn't find the required element so we
* need to add a new element to the current element
*********************************************************************
*/
pNew = MrvAddElement(pEntry, MrvStrdup(lpszPath, cbName), FALSE,
MrvGROWBY);
/*
*********************************************************************
* If there are no more entries then return the node we just created.
*********************************************************************
*/
if (!lpszNext)
{
return pNew;
}
/*
*********************************************************************
* If there are more elements to search
*********************************************************************
*/
else
{
/*
*****************************************************************
* Recurse to add the remaining nodes
*****************************************************************
*/
return MrvCreateElements(pNew, lpszNext);
}
}
return NULL;
}/* MrvCreateElements */
/**
****************************************************************************
* <P> Creates an user friendly XML string from a given element with
* appropriate white space and carriage returns.
*
* This recurses through all subnodes then adds contents of the nodes to the
* string.
* </P>
*
* @methodName MrvCreateXMLStringR
*
* @param MrvXMLElement * pEntry - XML Element
* @param MRV_LPTSTR lpszMarker - String to create results into, this
* can be zero if you want to calculate
* the size of the returned string.
* @param int nFormat - Specify -1 for no formatting or the
* indent level (0 initially).
* @return int - Size of the returned string, not
* including the NULL terminator.
*
* @exception none
*
****************************************************************************
*/
int MrvCreateXMLStringR(MrvXMLElement * pEntry, MRV_LPTSTR lpszMarker, int nFormat)
{
int nResult = 0;
int cb;
int cbElement;
int nIndex;
int nChildFormat;
int bHasChildren = FALSE;
MrvXMLNode * pChild;
MrvXMLAttribute * pAttr;
ASSERT(pEntry);
#define McbLENSTR(lpsz) (lpsz ? strlen(lpsz) : 0)
/*
*************************************************************************
* If the element has no name then assume this is the head node.
*************************************************************************
*/
cbElement = McbLENSTR(pEntry->lpszName);
if (cbElement)
{
/*
*********************************************************************
* "<elementname "
*********************************************************************
*/
cb = nFormat == -1 ? 0 : nFormat;
if (lpszMarker)
{
if (cb)
{
memset(lpszMarker, MrvINDENTCHAR, sizeof(MRV_TCHAR)*cb);
}
nResult = cb;
lpszMarker[nResult++] = '<';
strcpy(&lpszMarker[nResult], pEntry->lpszName);
nResult += cbElement;
lpszMarker[nResult++] = ' ';
}
else
{
nResult += cbElement + 2 + cb;
}
/*
*********************************************************************
* Enumerate attributes and add them to the string
*********************************************************************
*/
nIndex = 0;
while ((pChild = MrvEnumNodes(pEntry, &nIndex)))
{
switch(pChild->type)
{
/*
*****************************************************************
* Add attributes
*****************************************************************
*/
case eNodeAttribute:
{
pAttr = pChild->node.pAttrib;
/*
*********************************************************
* "Attrib
*********************************************************
*/
cb = McbLENSTR(pAttr->lpszName);
if (cb)
{
if (lpszMarker)
{
strcpy(&lpszMarker[nResult], pAttr->lpszName);
}
nResult += cb;
/*
*****************************************************
* "Attrib=Value "
*****************************************************
*/
/*modified bu shoujun */
cb = McbLENSTR(pAttr->lpszValue);
if (cb)
{
if (lpszMarker)
{
lpszMarker[nResult] = '=';
lpszMarker[++nResult] = '"'; //added by shoujun
strcpy(&lpszMarker[nResult+1],
pAttr->lpszValue);
nResult += cb + 1;
lpszMarker[nResult++] = '"';
}
else if(!lpszMarker)
nResult += cb + 3;
// nResult += cb + 1;
}
if (lpszMarker)
{
lpszMarker[nResult] = ' ';
}
nResult++;
}
}
break;
case eNodeEmpty:
continue;
default:
/*
*************************************************************
* If this node isn't an attribute then flag that this element
* has children.
*************************************************************
*/
bHasChildren = TRUE;
}
}
/*
*********************************************************************
* If there are child nodes we need to terminate the start tag
*********************************************************************
*/
if (bHasChildren)
{
if (lpszMarker)
{
lpszMarker[nResult-1] = '>';
}
if (nFormat != -1)
{
if (lpszMarker)
{
lpszMarker[nResult] = '\n';
}
nResult++;
}
}
else
{
nResult--;
}
}
/*
*************************************************************************
* Calculate the child format for when we recurse. This is used to
* determine the number of spaces used for prefixes.
*************************************************************************
*/
if (nFormat == -1)
{
nChildFormat = -1;
}
else
{
if (cbElement)
{
nChildFormat = nFormat + 1;
}
else
{
nChildFormat = nFormat;
}
}
/*
*************************************************************************
* Enumerate through remaining children
*************************************************************************
*/
nIndex = 0;
while ((pChild = MrvEnumNodes(pEntry, &nIndex)))
{
switch(pChild->type)
{
/*
*********************************************************************
* Text nodes
*********************************************************************
*/
case eNodeText:
{
/*
*************************************************************
* "Text"
*************************************************************
*/
cb = McbLENSTR(pChild->node.pText->lpszValue);
if (cb)
{
if (nFormat != -1)
{
if (lpszMarker)
{
memset(&lpszMarker[nResult], MrvINDENTCHAR,
sizeof(MRV_TCHAR)*(nFormat + 1));
strcpy(&lpszMarker[nResult + nFormat + 1],
pChild->node.pText->lpszValue);
lpszMarker[nResult + nFormat + 1 + cb] =
'\n';
}
nResult += cb + nFormat + 2;
}
else
{
if (lpszMarker)
{
strcpy(&lpszMarker[nResult],
pChild->node.pText->lpszValue);
}
nResult += cb;
}
}
}
break;
/*
*********************************************************************
* Clear type nodes
*********************************************************************
*/
case eNodeClear:
{
/*
*************************************************************
* "OpenTag"
*************************************************************
*/
cb = McbLENSTR(pChild->node.pClear->lpszOpenTag);
if (cb)
{
if (nFormat != -1)
{
if (lpszMarker)
{
memset(&lpszMarker[nResult], MrvINDENTCHAR,
sizeof(MRV_TCHAR)*(nFormat + 1));
strcpy(&lpszMarker[nResult + nFormat + 1],
pChild->node.pClear->lpszOpenTag);
/* lpszMarker[nResult + nFormat + 1 + cb] =
_T('\n'); */
}
/* nResult += cb + nFormat + 2; */
nResult += cb + nFormat + 1;
}
else
{
if (lpszMarker)
{
strcpy(&lpszMarker[nResult],
pChild->node.pClear->lpszOpenTag);
}
nResult += cb;
}
}
/*
*************************************************************
* "OpenTag Value"
*************************************************************
*/
cb = McbLENSTR(pChild->node.pClear->lpszValue);
if (cb)
{
if (lpszMarker)
{
strcpy(&lpszMarker[nResult],
pChild->node.pClear->lpszValue);
}
nResult += cb;
}
/*
*************************************************************
* "OpenTag Value CloseTag"
*************************************************************
*/
cb = McbLENSTR(pChild->node.pClear->lpszCloseTag);
if (cb)
{
if (lpszMarker)
{
strcpy(&lpszMarker[nResult],
pChild->node.pClear->lpszCloseTag);
}
nResult += cb;
}
if (nFormat != -1)
{
if (lpszMarker)
{
lpszMarker[nResult] = '\n';
}
nResult++;
}
}
break;
/*
*********************************************************************
* Element nodes
*********************************************************************
*/
case eNodeElement:
{
/*
*************************************************************
* Recursively add child nodes
*************************************************************
*/
nResult += MrvCreateXMLStringR(pChild->node.pElement,
lpszMarker ? lpszMarker + nResult : 0, nChildFormat);
}
default:
break;
}
}
if (cbElement)
{
/*
*********************************************************************
* If we have child entries we need to use long XML notation for
* closing the element - "<elementname>blah blah blah</elementname>"
*********************************************************************
*/
if (bHasChildren)
{
/*
*****************************************************************
* "</elementname>\0"
*****************************************************************
*/
if (lpszMarker)
{
if (nFormat != -1)
{
if (nFormat)
{
memset(&lpszMarker[nResult], MrvINDENTCHAR,
sizeof(MRV_TCHAR)*nFormat);
nResult+=nFormat;
}
}
strcpy(&lpszMarker[nResult], "</");
nResult += 2;
strcpy(&lpszMarker[nResult], pEntry->lpszName);
nResult += cbElement;
if (nFormat == -1)
{
strcpy(&lpszMarker[nResult], ">");
nResult++;
}
else
{
strcpy(&lpszMarker[nResult], ">\n");
nResult += 2;
}
}
else
{
if (nFormat != -1)
{
nResult += cbElement + 4 + nFormat;
}
else
{
nResult += cbElement + 3;
}
}
}
/*
*********************************************************************
* If there are no children we can use shorthand XML notation -
* "<elementname/>"
*********************************************************************
*/
else
{
/*
*****************************************************************
* "/>\0"
*****************************************************************
*/
if (lpszMarker)
{
if (nFormat == -1)
{
strcpy(&lpszMarker[nResult], "/>");
nResult += 2;
}
else
{
strcpy(&lpszMarker[nResult], "/>\n");
nResult += 3;
}
}
else
{
nResult += nFormat == -1 ? 2 : 3;
}
}
}
return nResult;
}/* MrvCreateXMLStringR */
/**
****************************************************************************
* <P> Create an XML string from the head element. </P>
*
* @methodName MrvCreateXMLString
*
* @param MrvXMLElement * pHead - head element
* @param int nFormat - 0 if no formatting is required
* otherwise nonzero for formatted text
* with carriage returns and indentation.
* @param int *pnSize - [out] pointer to the size of the
* returned string not including the
* NULL terminator.
*
* @return MRV_LPTSTR - Allocated XML string, you must duster_free
* this with duster_free().
*
* @exception none
*
****************************************************************************
*/
MRV_LPTSTR MrvCreateXMLString(MrvXMLElement * pHead, int nFormat, int *pnSize)
{
MRV_LPTSTR lpszResult = NULL;
int cbStr;
if (pHead)
{
/*
*********************************************************************
* Recursively Calculate the size of the XML string
*********************************************************************
*/
nFormat = nFormat ? 0 : -1;
cbStr = MrvCreateXMLStringR(pHead, 0, nFormat);
ASSERT(cbStr);
/*
*********************************************************************
* Alllocate memory for the XML string + the NULL terminator and
* create the recursively XML string.
*********************************************************************
*/
lpszResult = (MRV_LPTSTR)duster_malloc(cbStr+1);
if (lpszResult)
{
MrvCreateXMLStringR(pHead, lpszResult, nFormat);
if (pnSize) *pnSize = cbStr;
}
}
return lpszResult;
}/* MrvCreateXMLString */
/*
*********************************************************************
* Add New Node To the List;
* Toby add 2006/7/3/9:40
*********************************************************************
*/
MrvXMLElement* AddElementToXML(MrvXMLElement *pParent,MRV_LPTSTR lpszText)
{
//NodeText_st *pTemp = NULL;
MrvXMLElement *pElement;
//pTemp = (NodeText_st *)duster_malloc(sizeof(NodeText_st));
//got the mem?
//if(!pTemp)
// return NULL;
#ifdef DYNAMIC_MEM
// pTemp->lpszText = (MRV_LPTSTR)duster_malloc((char)*strlen(lpszText));
#endif
//strcpy(pTemp->lpszText,lpszText);
//AddToList(&g_StrList,&(pTemp->List));
//pElement = MrvCreateElements(pParent,pTemp->lpszText);
pElement = MrvCreateElements(pParent,lpszText);
return pElement;
}
/*
*********************************************************************
* Add New Attr Node To the List;
* Toby add 2006/7/3/9:40
*********************************************************************
*/
MrvXMLAttribute* AddAttrToXML(MrvXMLElement *pEntry,MRV_LPTSTR lpszName,MRV_LPTSTR lpszValue)
{
MrvXMLAttribute *pAttr = NULL;
if(!pEntry)
return NULL;
pAttr = MrvAddAttribute(pEntry,
MrvStrdup(lpszName,0),
MrvStrdup(lpszValue,0),
1);
return pAttr;
}
/*
*********************************************************************
* Delete Node From the List;
* Toby add 2006/7/3/9:53
*********************************************************************
*/
void DeleteElementFromXML(MrvXMLElement *pEntry)
{
NodeText_st *pTemp = NULL;
if(!pEntry)
return;
pTemp = ListEntry(pEntry->lpszName,NodeText_st,lpszText);
DeleteFromList(&(pTemp->List));
duster_free(pTemp->lpszText);
duster_free(pTemp);
//delete from the list...add Later
//coverity[double_free:SUPPRESS]
MrvDeleteElement(pEntry);
}
/*
*********************************************************************
* Delete Node From the List;
* Toby add 2006/7/3/10:01
*********************************************************************
*/
void DeleteAttrFromXML(MrvXMLAttribute *pEntry)
{
NodeText_st *pTemp = NULL;
pTemp = ListEntry(pEntry->lpszName,NodeText_st,lpszText);
DeleteFromList(&(pTemp->List));
duster_free(pTemp->lpszText);
duster_free(pTemp);
pTemp = ListEntry(pEntry->lpszValue,NodeText_st,lpszText);
DeleteFromList(&(pTemp->List));
duster_free(pTemp->lpszText);
duster_free(pTemp);
//coverity[check_after_deref:SUPPRESS]
if(!pEntry)
return;
//delete from the list... add later
//coverity[double_free:SUPPRESS]
MrvDeleteAttribute(pEntry);
}
MrvXMLNode * MrvEnumPrintf(MrvXMLElement *pEntry,int *nrow)
{
int nIndex = 0,prenRow;
MrvXMLElement * pResult = NULL;
//MrvXMLElement * pParent = NULL;
//char *ver = NULL;
mrvxml_log("enter %s,pEntry->nSize is %d,pEntry->nIsDeclaration is %d,pEntry->lpszName is %s",__FUNCTION__,pEntry->nSize,pEntry->nIsDeclaration,pEntry->lpszName);
if(pEntry->pParent)
{
mrvxml_log("%s,this element has parents",__FUNCTION__);
//pParent = pEntry->pParent;
mrvxml_log("%s,pParent->nSize is %d,pParent->nIsDeclaration is %d,pParent->lpszName is %s",
__FUNCTION__,pParent->nSize,pParent->nIsDeclaration,pParent->lpszName);
}
else
{
mrvxml_log("%s,this element has no parents",__FUNCTION__);
}
(*nrow)++;
prenRow = *nrow;
for (;nIndex < pEntry->nSize ; nIndex++)
{
mrvxml_log("%s root->pEntries[%d].type is %d,nrow is %d", __FUNCTION__,nIndex,pEntry->pEntries[nIndex].type,*nrow);
switch(pEntry->pEntries[nIndex].type)
{
case eNodeElement:
pResult = pEntry->pEntries[nIndex].node.pElement;
mrvxml_log("%s Element type root->pEntries[%d].lpszName is %s,pResult->nSize is %d",__FUNCTION__,nIndex,pResult->lpszName,pResult->nSize);
/*if(strcmp(pResult->lpszName,"version_num") == 0)
{
mrvxml_log("%s,meet version_num,pResult->nSize is %d",__FUNCTION__,pResult->nSize);
ver = duster_malloc(10);
memset(ver, 0, 10);
memcpy(ver, "nezha", 5);
MrvAddText(pResult, ver, 1);
}
*/
MrvEnumPrintf(pResult,nrow);
break;
case eNodeAttribute:
mrvxml_log("%s eNodeAttribute name is %s,value is %s",__FUNCTION__,(pEntry->pEntries[nIndex].node.pAttrib)->lpszName,(pEntry->pEntries[nIndex].node.pAttrib)->lpszValue);
break;
case eNodeText:
mrvxml_log("%s eNodeText,value is %s",__FUNCTION__,(pEntry->pEntries[nIndex].node.pText)->lpszValue);
break;
case eNodeClear:
mrvxml_log("%s eNodeClear,",__FUNCTION__,(pEntry->pEntries[nIndex].node.pClear)->lpszOpenTag,(pEntry->pEntries[nIndex].node.pClear)->lpszValue,(pEntry->pEntries[nIndex].node.pClear)->lpszCloseTag);
break;
case eNodeEmpty:
mrvxml_log("%s eNodeEmpty",__FUNCTION__);
}
*nrow = prenRow;
}
return NULL;
}
/*
*********************************************************************
*McbCountElementl
*2013-05-31 --added by shoujunl
*********************************************************************
*/
int MrvCountElement(MrvXMLElement *pEntry)
{
int num = 0, nIndex = 0;
for(;nIndex < pEntry->nSize;nIndex++)
{
if(pEntry->pEntries[nIndex].type == eNodeElement)
num++;
}
return num;
}
/*
*********************************************************************
*McbCountElementl
*2013-05-31 --added by shoujunl
*********************************************************************
*/
MrvXMLText *MrvFindOnlyText(MrvXMLElement * pEntry)
{
int textNodeNum = 0,nIndex = 0;
MrvXMLText *pText = NULL;
for(;nIndex < pEntry->nSize;nIndex++)
{
if(pEntry->pEntries[nIndex].type == eNodeText)
{
pText = pEntry->pEntries[nIndex].node.pText;
textNodeNum++;
if(textNodeNum>1)
return NULL;
}
}
return pText;
}