UIMarkup.cpp 21 KB

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