XmlManager.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604
  1. #include "StdAfx.h"
  2. #include "XmlManager.h"
  3. #ifndef TRACE
  4. #define TRACE
  5. #endif
  6. #pragma warning(disable: 4244)
  7. ///////////////////////////////////////////////////////////////////////////////////////
  8. //
  9. //
  10. //
  11. CXmlNode::CXmlNode() : m_pOwner(NULL)
  12. {
  13. }
  14. CXmlNode::CXmlNode(CXmlManager* pOwner, int iPos) : m_pOwner(pOwner), m_iPos(iPos), m_nAttributes(0)
  15. {
  16. }
  17. CXmlNode CXmlNode::GetSibling()
  18. {
  19. if( m_pOwner == NULL ) return CXmlNode();
  20. ULONG iPos = m_pOwner->m_pElements[m_iPos].iNext;
  21. if( iPos == 0 ) return CXmlNode();
  22. return CXmlNode(m_pOwner, iPos);
  23. }
  24. bool CXmlNode::HasSiblings() const
  25. {
  26. if( m_pOwner == NULL ) return false;
  27. ULONG iPos = m_pOwner->m_pElements[m_iPos].iNext;
  28. return iPos > 0;
  29. }
  30. CXmlNode CXmlNode::GetChild()
  31. {
  32. if( m_pOwner == NULL ) return CXmlNode();
  33. ULONG iPos = m_pOwner->m_pElements[m_iPos].iChild;
  34. if( iPos == 0 ) return CXmlNode();
  35. return CXmlNode(m_pOwner, iPos);
  36. }
  37. CXmlNode CXmlNode::GetChild(LPCTSTR pstrName)
  38. {
  39. if( m_pOwner == NULL ) return CXmlNode();
  40. ULONG iPos = m_pOwner->m_pElements[m_iPos].iChild;
  41. while( iPos != 0 )
  42. {
  43. if( _tcscmp(m_pOwner->m_pstrXML + m_pOwner->m_pElements[iPos].iStart, pstrName) == 0 )
  44. {
  45. return CXmlNode(m_pOwner, iPos);
  46. }
  47. iPos = m_pOwner->m_pElements[iPos].iNext;
  48. }
  49. return CXmlNode();
  50. }
  51. bool CXmlNode::HasChildren() const
  52. {
  53. if( m_pOwner == NULL ) return false;
  54. return m_pOwner->m_pElements[m_iPos].iChild != 0;
  55. }
  56. CXmlNode CXmlNode::GetParent()
  57. {
  58. if( m_pOwner == NULL ) return CXmlNode();
  59. ULONG iPos = m_pOwner->m_pElements[m_iPos].iParent;
  60. if( iPos == 0 ) return CXmlNode();
  61. return CXmlNode(m_pOwner, iPos);
  62. }
  63. bool CXmlNode::IsValid() const
  64. {
  65. return m_pOwner != NULL;
  66. }
  67. LPCTSTR CXmlNode::GetName() const
  68. {
  69. if( m_pOwner == NULL ) return NULL;
  70. return m_pOwner->m_pstrXML + m_pOwner->m_pElements[m_iPos].iStart;
  71. }
  72. LPCTSTR CXmlNode::GetValue() const
  73. {
  74. if( m_pOwner == NULL ) return NULL;
  75. return m_pOwner->m_pstrXML + m_pOwner->m_pElements[m_iPos].iData;
  76. }
  77. LPCTSTR CXmlNode::GetAttributeName(int iIndex)
  78. {
  79. if( m_pOwner == NULL ) return NULL;
  80. if( m_nAttributes == 0 ) _MapAttributes();
  81. if( iIndex < 0 || iIndex >= m_nAttributes ) return _T("");
  82. return m_pOwner->m_pstrXML + m_aAttributes[iIndex].iName;
  83. }
  84. LPCTSTR CXmlNode::GetAttributeValue(int iIndex)
  85. {
  86. if( m_pOwner == NULL ) return NULL;
  87. if( m_nAttributes == 0 ) _MapAttributes();
  88. if( iIndex < 0 || iIndex >= m_nAttributes ) return _T("");
  89. return m_pOwner->m_pstrXML + m_aAttributes[iIndex].iValue;
  90. }
  91. LPCTSTR CXmlNode::GetAttributeValue(LPCTSTR pstrName)
  92. {
  93. if( m_pOwner == NULL ) return NULL;
  94. if( m_nAttributes == 0 ) _MapAttributes();
  95. for( int i = 0; i < m_nAttributes; i++ )
  96. {
  97. if( _tcscmp(m_pOwner->m_pstrXML + m_aAttributes[i].iName, pstrName) == 0 ) return m_pOwner->m_pstrXML + m_aAttributes[i].iValue;
  98. }
  99. return _T("");
  100. }
  101. bool CXmlNode::GetAttributeValue(int iIndex, LPTSTR pstrValue, SIZE_T cchMax)
  102. {
  103. if( m_pOwner == NULL ) return false;
  104. if( m_nAttributes == 0 ) _MapAttributes();
  105. if( iIndex < 0 || iIndex >= m_nAttributes ) return false;
  106. _tcsncpy_s(pstrValue,-1, m_pOwner->m_pstrXML + m_aAttributes[iIndex].iValue, cchMax);
  107. return true;
  108. }
  109. bool CXmlNode::GetAttributeValue(LPCTSTR pstrName, LPTSTR pstrValue, SIZE_T cchMax)
  110. {
  111. if( m_pOwner == NULL ) return false;
  112. if( m_nAttributes == 0 ) _MapAttributes();
  113. for( int i = 0; i < m_nAttributes; i++ )
  114. {
  115. if( _tcscmp(m_pOwner->m_pstrXML + m_aAttributes[i].iName, pstrName) == 0 )
  116. {
  117. _tcsncpy_s(pstrValue,-1, m_pOwner->m_pstrXML + m_aAttributes[i].iValue, cchMax);
  118. return true;
  119. }
  120. }
  121. return false;
  122. }
  123. int CXmlNode::GetAttributeCount()
  124. {
  125. if( m_pOwner == NULL ) return 0;
  126. if( m_nAttributes == 0 ) _MapAttributes();
  127. return m_nAttributes;
  128. }
  129. bool CXmlNode::HasAttributes()
  130. {
  131. if( m_pOwner == NULL ) return false;
  132. if( m_nAttributes == 0 ) _MapAttributes();
  133. return m_nAttributes > 0;
  134. }
  135. bool CXmlNode::HasAttribute(LPCTSTR pstrName)
  136. {
  137. if( m_pOwner == NULL ) return false;
  138. if( m_nAttributes == 0 ) _MapAttributes();
  139. for( int i = 0; i < m_nAttributes; i++ )
  140. {
  141. if( _tcscmp(m_pOwner->m_pstrXML + m_aAttributes[i].iName, pstrName) == 0 ) return true;
  142. }
  143. return false;
  144. }
  145. void CXmlNode::_MapAttributes()
  146. {
  147. m_nAttributes = 0;
  148. LPCTSTR pstr = m_pOwner->m_pstrXML + m_pOwner->m_pElements[m_iPos].iStart;
  149. LPCTSTR pstrEnd = m_pOwner->m_pstrXML + m_pOwner->m_pElements[m_iPos].iData;
  150. pstr += _tcslen(pstr) + 1;
  151. while( pstr < pstrEnd )
  152. {
  153. m_pOwner->_SkipWhitespace(pstr);
  154. m_aAttributes[m_nAttributes].iName = pstr - m_pOwner->m_pstrXML;
  155. pstr += _tcslen(pstr) + 1;
  156. m_pOwner->_SkipWhitespace(pstr);
  157. if( *pstr++ != _T('\"') ) return; // if( *pstr != _T('\"') ) { pstr = ::CharNext(pstr); return; }
  158. m_aAttributes[m_nAttributes++].iValue = pstr - m_pOwner->m_pstrXML;
  159. if( m_nAttributes >= MAX_XML_ATTRIBUTES ) return;
  160. pstr += _tcslen(pstr) + 1;
  161. }
  162. }
  163. ///////////////////////////////////////////////////////////////////////////////////////
  164. //
  165. //
  166. //
  167. CXmlManager::CXmlManager(LPCTSTR pstrXML)
  168. {
  169. m_pstrXML = NULL;
  170. m_pElements = NULL;
  171. m_nElements = 0;
  172. m_bPreserveWhitespace = true;
  173. if( pstrXML != NULL ) Load(pstrXML);
  174. }
  175. CXmlManager::~CXmlManager()
  176. {
  177. Release();
  178. }
  179. bool CXmlManager::IsValid() const
  180. {
  181. return m_pElements != NULL;
  182. }
  183. void CXmlManager::SetPreserveWhitespace(bool bPreserve)
  184. {
  185. m_bPreserveWhitespace = bPreserve;
  186. }
  187. bool CXmlManager::Load(LPCTSTR pstrXML)
  188. {
  189. Release();
  190. SIZE_T cchLen = _tcslen(pstrXML) + 1;
  191. m_pstrXML = static_cast<LPTSTR>(malloc(cchLen * sizeof(TCHAR)));
  192. ::CopyMemory(m_pstrXML, pstrXML, cchLen * sizeof(TCHAR));
  193. bool bRes = _Parse();
  194. if( !bRes ) Release();
  195. return bRes;
  196. }
  197. bool CXmlManager::LoadFromMem(BYTE* pByte, DWORD dwSize, int encoding)
  198. {
  199. #ifdef _UNICODE
  200. if (encoding == XMLFILE_ENCODING_UTF8)
  201. {
  202. DWORD nWide = ::MultiByteToWideChar( CP_UTF8, 0, (LPCSTR)pByte, dwSize, NULL, 0 );
  203. m_pstrXML = static_cast<LPTSTR>(malloc((nWide + 1)*sizeof(TCHAR)));
  204. ::MultiByteToWideChar( CP_UTF8, 0, (LPCSTR)pByte, dwSize, m_pstrXML, nWide );
  205. m_pstrXML[nWide] = _T('\0');
  206. }
  207. else if (encoding == XMLFILE_ENCODING_ASNI)
  208. {
  209. DWORD nWide = ::MultiByteToWideChar( CP_ACP, 0, (LPCSTR)pByte, dwSize, NULL, 0 );
  210. m_pstrXML = static_cast<LPTSTR>(malloc((nWide + 1)*sizeof(TCHAR)));
  211. ::MultiByteToWideChar( CP_ACP, 0, (LPCSTR)pByte, dwSize, m_pstrXML, nWide );
  212. m_pstrXML[nWide] = _T('\0');
  213. }
  214. else
  215. {
  216. if ( dwSize >= 2 && ( ( pByte[0] == 0xFE && pByte[1] == 0xFF ) || ( pByte[0] == 0xFF && pByte[1] == 0xFE ) ) )
  217. {
  218. dwSize = dwSize / 2 - 1;
  219. if ( pByte[0] == 0xFE && pByte[1] == 0xFF )
  220. {
  221. pByte += 2;
  222. for ( DWORD nSwap = 0 ; nSwap < dwSize ; nSwap ++ )
  223. {
  224. register CHAR nTemp = pByte[ ( nSwap << 1 ) + 0 ];
  225. pByte[ ( nSwap << 1 ) + 0 ] = pByte[ ( nSwap << 1 ) + 1 ];
  226. pByte[ ( nSwap << 1 ) + 1 ] = nTemp;
  227. }
  228. }
  229. else
  230. {
  231. pByte += 2;
  232. }
  233. m_pstrXML = static_cast<LPTSTR>(malloc((dwSize + 1)*sizeof(TCHAR)));
  234. ::CopyMemory( m_pstrXML, pByte, dwSize * sizeof(TCHAR) );
  235. m_pstrXML[dwSize] = _T('\0');
  236. pByte -= 2;
  237. }
  238. }
  239. #else // !_UNICODE
  240. if (encoding == XMLFILE_ENCODING_UTF8)
  241. {
  242. DWORD nWide = ::MultiByteToWideChar( CP_UTF8, 0, (LPCSTR)pByte, dwSize, NULL, 0 );
  243. LPWSTR w_str = static_cast<LPWSTR>(malloc((nWide + 1)*sizeof(WCHAR)));
  244. ::MultiByteToWideChar( CP_UTF8, 0, (LPCSTR)pByte, dwSize, w_str, nWide );
  245. w_str[nWide] = L'\0';
  246. DWORD wide = ::WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)w_str, nWide, NULL, 0, NULL, NULL);
  247. m_pstrXML = static_cast<LPTSTR>(malloc((wide + 1)*sizeof(TCHAR)));
  248. ::WideCharToMultiByte( CP_ACP, 0, (LPCWSTR)w_str, nWide, m_pstrXML, wide, NULL, NULL);
  249. m_pstrXML[wide] = _T('\0');
  250. free(w_str);
  251. }
  252. else if (encoding == XMLFILE_ENCODING_UNICODE)
  253. {
  254. if ( dwSize >= 2 && ( ( pByte[0] == 0xFE && pByte[1] == 0xFF ) || ( pByte[0] == 0xFF && pByte[1] == 0xFE ) ) )
  255. {
  256. dwSize = dwSize / 2 - 1;
  257. if ( pByte[0] == 0xFE && pByte[1] == 0xFF )
  258. {
  259. pByte += 2;
  260. for ( DWORD nSwap = 0 ; nSwap < dwSize ; nSwap ++ )
  261. {
  262. register CHAR nTemp = pByte[ ( nSwap << 1 ) + 0 ];
  263. pByte[ ( nSwap << 1 ) + 0 ] = pByte[ ( nSwap << 1 ) + 1 ];
  264. pByte[ ( nSwap << 1 ) + 1 ] = nTemp;
  265. }
  266. }
  267. else
  268. {
  269. pByte += 2;
  270. }
  271. DWORD nWide = ::WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)pByte, dwSize, NULL, 0, NULL, NULL);
  272. m_pstrXML = static_cast<LPTSTR>(malloc((nWide + 1)*sizeof(TCHAR)));
  273. ::WideCharToMultiByte( CP_ACP, 0, (LPCWSTR)pByte, dwSize, m_pstrXML, nWide, NULL, NULL);
  274. m_pstrXML[nWide] = _T('\0');
  275. pByte -= 2;
  276. }
  277. }
  278. else
  279. {
  280. m_pstrXML = static_cast<LPTSTR>(malloc((dwSize + 1)*sizeof(TCHAR)));
  281. ::CopyMemory( m_pstrXML, pByte, dwSize * sizeof(TCHAR) );
  282. m_pstrXML[dwSize] = _T('\0');
  283. }
  284. #endif // _UNICODE
  285. bool bRes = _Parse();
  286. if( !bRes ) Release();
  287. return bRes;
  288. }
  289. bool CXmlManager::LoadFromFile(LPCTSTR pstrFilename, int encoding)
  290. {
  291. ASSERT(pstrFilename);
  292. Release();
  293. HANDLE hFile = ::CreateFile(pstrFilename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  294. if( hFile == INVALID_HANDLE_VALUE ) return _Failed(_T("打开文件失败"));
  295. DWORD dwSize = ::GetFileSize(hFile, NULL);
  296. if( dwSize == 0 ) return _Failed(_T("File is empty"));
  297. if ( dwSize > 4096*1024 ) return _Failed(_T("File too large"));
  298. DWORD dwRead = 0;
  299. BYTE* pByte = new BYTE[ dwSize ];
  300. ::ReadFile( hFile, pByte, dwSize, &dwRead, NULL );
  301. ::CloseHandle( hFile );
  302. if( dwRead != dwSize )
  303. {
  304. delete[] pByte;
  305. Release();
  306. return _Failed(_T("Could not read file"));
  307. }
  308. bool ret = LoadFromMem(pByte, dwSize, encoding);
  309. delete[] pByte;
  310. return ret;
  311. }
  312. void CXmlManager::Release()
  313. {
  314. if( m_pstrXML != NULL ) free(m_pstrXML);
  315. if( m_pElements != NULL ) free(m_pElements);
  316. m_pstrXML = NULL;
  317. m_pElements = NULL;
  318. m_nElements;
  319. }
  320. void CXmlManager::GetLastErrorMessage(LPTSTR pstrMessage, SIZE_T cchMax) const
  321. {
  322. _tcsncpy_s(pstrMessage, -1,m_szErrorMsg, cchMax);
  323. }
  324. void CXmlManager::GetLastErrorLocation(LPTSTR pstrSource, SIZE_T cchMax) const
  325. {
  326. _tcsncpy_s(pstrSource, -1,m_szErrorXML, cchMax);
  327. }
  328. CXmlNode CXmlManager::GetRoot()
  329. {
  330. if( m_nElements == 0 ) return CXmlNode();
  331. return CXmlNode(this, 1);
  332. }
  333. bool CXmlManager::_Parse()
  334. {
  335. _ReserveElement(); // Reserve index 0 for errors
  336. ::ZeroMemory(m_szErrorMsg, sizeof(m_szErrorMsg));
  337. ::ZeroMemory(m_szErrorXML, sizeof(m_szErrorXML));
  338. LPTSTR pstrXML = m_pstrXML;
  339. return _Parse(pstrXML, 0);
  340. }
  341. bool CXmlManager::_Parse(LPTSTR& pstrText, ULONG iParent)
  342. {
  343. _SkipWhitespace(pstrText);
  344. ULONG iPrevious = 0;
  345. for( ; ; )
  346. {
  347. if( *pstrText == _T('\0') && iParent <= 1 ) return true;
  348. _SkipWhitespace(pstrText);
  349. if( *pstrText != _T('<') ) return _Failed(_T("Expected start tag"), pstrText);
  350. if( pstrText[1] == _T('/') ) return true;
  351. *pstrText++ = _T('\0');
  352. _SkipWhitespace(pstrText);
  353. // Skip comment or processing directive
  354. if( *pstrText == _T('!') || *pstrText == _T('?') )
  355. {
  356. TCHAR ch = *pstrText;
  357. if( *pstrText == _T('!') ) ch = _T('-');
  358. while( *pstrText != _T('\0') && !(*pstrText == ch && *(pstrText + 1) == _T('>')) ) pstrText = ::CharNext(pstrText);
  359. if( *pstrText != _T('\0') ) pstrText += 2;
  360. _SkipWhitespace(pstrText);
  361. continue;
  362. }
  363. _SkipWhitespace(pstrText);
  364. // Fill out element structure
  365. XMLELEMENT* pEl = _ReserveElement();
  366. ULONG iPos = pEl - m_pElements;
  367. pEl->iStart = pstrText - m_pstrXML;
  368. pEl->iParent = iParent;
  369. pEl->iNext = pEl->iChild = 0;
  370. if( iPrevious != 0 ) m_pElements[iPrevious].iNext = iPos;
  371. else if( iParent > 0 ) m_pElements[iParent].iChild = iPos;
  372. iPrevious = iPos;
  373. // Parse name
  374. LPCTSTR pstrName = pstrText;
  375. _SkipIdentifier(pstrText);
  376. LPTSTR pstrNameEnd = pstrText;
  377. if( *pstrText == _T('\0') ) return _Failed(_T("Error parsing element name"), pstrText);
  378. // Parse attributes
  379. if( !_ParseAttributes(pstrText) ) return false;
  380. _SkipWhitespace(pstrText);
  381. if( pstrText[0] == _T('/') && pstrText[1] == _T('>') )
  382. {
  383. pEl->iData = pstrText - m_pstrXML;
  384. *pstrText = _T('\0');
  385. pstrText += 2;
  386. }
  387. else
  388. {
  389. if( *pstrText != _T('>') ) return _Failed(_T("Expected start-tag closing"), pstrText);
  390. // Parse node data
  391. pEl->iData = ++pstrText - m_pstrXML;
  392. LPTSTR pstrDest = pstrText;
  393. if( !_ParseData(pstrText, pstrDest, _T('<')) ) return false;
  394. // Determine type of next element
  395. if( *pstrText == _T('\0') && iParent <= 1 ) return true;
  396. if( *pstrText != _T('<') ) return _Failed(_T("Expected end-tag start"), pstrText);
  397. if( pstrText[0] == _T('<') && pstrText[1] != _T('/') )
  398. {
  399. if( !_Parse(pstrText, iPos) ) return false;
  400. }
  401. if( pstrText[0] == _T('<') && pstrText[1] == _T('/') )
  402. {
  403. *pstrDest = _T('\0');
  404. *pstrText = _T('\0');
  405. pstrText += 2;
  406. _SkipWhitespace(pstrText);
  407. SIZE_T cchName = pstrNameEnd - pstrName;
  408. if( _tcsncmp(pstrText, pstrName, cchName) != 0 ) return _Failed(_T("Unmatched closing tag"), pstrText);
  409. pstrText += cchName;
  410. _SkipWhitespace(pstrText);
  411. if( *pstrText++ != _T('>') ) return _Failed(_T("Unmatched closing tag"), pstrText);
  412. }
  413. }
  414. *pstrNameEnd = _T('\0');
  415. _SkipWhitespace(pstrText);
  416. }
  417. }
  418. CXmlManager::XMLELEMENT* CXmlManager::_ReserveElement()
  419. {
  420. if( m_nElements == 0 ) m_nReservedElements = 0;
  421. if( m_nElements >= m_nReservedElements ) {
  422. m_nReservedElements += (m_nReservedElements / 2) + 500;
  423. m_pElements = static_cast<XMLELEMENT*>(realloc(m_pElements, m_nReservedElements * sizeof(XMLELEMENT)));
  424. }
  425. return &m_pElements[m_nElements++];
  426. }
  427. void CXmlManager::_SkipWhitespace(LPCTSTR& pstr) const
  428. {
  429. while( *pstr > _T('\0') && *pstr <= _T(' ') ) pstr = ::CharNext(pstr);
  430. }
  431. void CXmlManager::_SkipWhitespace(LPTSTR& pstr) const
  432. {
  433. while( *pstr > _T('\0') && *pstr <= _T(' ') ) pstr = ::CharNext(pstr);
  434. }
  435. void CXmlManager::_SkipIdentifier(LPCTSTR& pstr) const
  436. {
  437. // 属性只能用英文,所以这样处理没有问题
  438. while( *pstr != _T('\0') && (*pstr == _T('_') || *pstr == _T(':') || _istalnum(*pstr)) ) pstr = ::CharNext(pstr);
  439. }
  440. void CXmlManager::_SkipIdentifier(LPTSTR& pstr) const
  441. {
  442. // 属性只能用英文,所以这样处理没有问题
  443. while( *pstr != _T('\0') && (*pstr == _T('_') || *pstr == _T(':') || _istalnum(*pstr)) ) pstr = ::CharNext(pstr);
  444. }
  445. bool CXmlManager::_ParseAttributes(LPTSTR& pstrText)
  446. {
  447. if( *pstrText == _T('>') ) return true;
  448. *pstrText++ = _T('\0');
  449. _SkipWhitespace(pstrText);
  450. while( *pstrText != _T('\0') && *pstrText != _T('>') && *pstrText != _T('/') )
  451. {
  452. _SkipIdentifier(pstrText);
  453. LPTSTR pstrIdentifierEnd = pstrText;
  454. _SkipWhitespace(pstrText);
  455. if( *pstrText != _T('=') ) return _Failed(_T("Error while parsing attributes"), pstrText);
  456. *pstrText++ = _T(' ');
  457. *pstrIdentifierEnd = _T('\0');
  458. _SkipWhitespace(pstrText);
  459. if( *pstrText++ != _T('\"') ) return _Failed(_T("Expected attribute value"), pstrText);
  460. LPTSTR pstrDest = pstrText;
  461. if( !_ParseData(pstrText, pstrDest, _T('\"')) ) return false;
  462. if( *pstrText == _T('\0') ) return _Failed(_T("Error while parsing attribute string"), pstrText);
  463. *pstrDest = _T('\0');
  464. *pstrText++ = _T('\0');
  465. _SkipWhitespace(pstrText);
  466. }
  467. return true;
  468. }
  469. bool CXmlManager::_ParseData(LPTSTR& pstrText, LPTSTR& pstrDest, char cEnd)
  470. {
  471. while( *pstrText != _T('\0') && *pstrText != cEnd )
  472. {
  473. while (*pstrText == _T('&'))
  474. {
  475. _ParseMetaChar(++pstrText, pstrDest);
  476. }
  477. if( *pstrText == _T(' ') )
  478. {
  479. *pstrDest++ = *pstrText++;
  480. if( !m_bPreserveWhitespace ) _SkipWhitespace(pstrText);
  481. }
  482. else
  483. {
  484. LPTSTR pstrTemp = ::CharNext(pstrText);
  485. while( pstrText < pstrTemp)
  486. {
  487. *pstrDest++ = *pstrText++;
  488. }
  489. }
  490. }
  491. // Make sure that MapAttributes() works correctly when it parses
  492. // over a value that has been transformed.
  493. LPTSTR pstrFill = pstrDest + 1;
  494. while( pstrFill < pstrText ) *pstrFill++ = _T(' ');
  495. return true;
  496. }
  497. void CXmlManager::_ParseMetaChar(LPTSTR& pstrText, LPTSTR& pstrDest)
  498. {
  499. if( pstrText[0] == _T('a') && pstrText[1] == _T('m') && pstrText[2] == _T('p') && pstrText[3] == _T(';') )
  500. {
  501. *pstrDest++ = _T('&');
  502. pstrText += 4;
  503. }
  504. else if( pstrText[0] == _T('l') && pstrText[1] == _T('t') && pstrText[2] == _T(';') )
  505. {
  506. *pstrDest++ = _T('<');
  507. pstrText += 3;
  508. }
  509. else if( pstrText[0] == _T('g') && pstrText[1] == _T('t') && pstrText[2] == _T(';') )
  510. {
  511. *pstrDest++ = _T('>');
  512. pstrText += 3;
  513. }
  514. else if( pstrText[0] == _T('q') && pstrText[1] == _T('u') && pstrText[2] == _T('o') && pstrText[3] == _T('t') && pstrText[4] == _T(';') )
  515. {
  516. *pstrDest++ = _T('\"');
  517. pstrText += 5;
  518. }
  519. else if( pstrText[0] == _T('a') && pstrText[1] == _T('p') && pstrText[2] == _T('o') && pstrText[3] == _T('s') && pstrText[4] == _T(';') )
  520. {
  521. *pstrDest++ = _T('\'');
  522. pstrText += 5;
  523. }
  524. else
  525. {
  526. *pstrDest++ = _T('&');
  527. }
  528. }
  529. bool CXmlManager::_Failed(LPCTSTR pstrError, LPCTSTR pstrLocation)
  530. {
  531. // Register last error
  532. //TRACE(_T("XML Error: %s"), pstrError);
  533. // TRACE(pstrLocation);
  534. _tcsncpy_s(m_szErrorMsg, pstrError, (sizeof(m_szErrorMsg) / sizeof(m_szErrorMsg[0])) - 1);
  535. _tcsncpy_s(m_szErrorXML, pstrLocation != NULL ? pstrLocation : _T(""), _countof(m_szErrorXML) - 1);
  536. return false; // Always return 'false'
  537. }