UIMarkup.cpp 22 KB

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