Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2314 lines
56 KiB

  1. /*++
  2. Copyright (c) 2001 Microsoft Corporation
  3. Module Name :
  4. xmlupgrade.cxx
  5. Abstract:
  6. Classes that are used to upgrade the xml metabase and mbschema from
  7. one version to another
  8. Author:
  9. Christopher Achille (cachille)
  10. Project:
  11. Internet Services Setup
  12. Revision History:
  13. September 2001: Created
  14. --*/
  15. #include "stdafx.h"
  16. #include "buffer.hxx"
  17. #include "xmlupgrade.hxx"
  18. #include "acl.hxx"
  19. // Constructor, initialize all the variables
  20. //
  21. CFileModify::CFileModify()
  22. {
  23. m_hReadFile = INVALID_HANDLE_VALUE;
  24. m_hWriteFile = INVALID_HANDLE_VALUE;
  25. m_buffData.Resize(CFILEMODIFY_BLOCKSIZE + 2);
  26. m_szCurrentData = (LPBYTE) m_buffData.QueryPtr();
  27. m_dwSizeofData = 0;
  28. m_bUnicode = FALSE;
  29. *m_szReadFileName = '\0';
  30. *m_szWriteFileName = '\0';
  31. SetValue(m_szCurrentData, '\0');
  32. }
  33. // Destructor, close the file
  34. //
  35. CFileModify::~CFileModify()
  36. {
  37. // Just incase it has not been closed yet, close it
  38. CloseFile();
  39. }
  40. // function: MoveXChars
  41. //
  42. // Move the pointer the number of characters specified
  43. //
  44. // Parameters:
  45. // szCurrent - Pointer to a unicode or ansi string
  46. // (type is determined by m_m_bUnicode)
  47. //
  48. // Return:
  49. // Pointer to szCurrent + dwChars
  50. //
  51. LPBYTE
  52. CFileModify::MoveXChars(LPBYTE szCurrent, DWORD dwChars)
  53. {
  54. if ( m_bUnicode )
  55. {
  56. return (LPBYTE) ( ( ( LPWSTR ) szCurrent ) + dwChars );
  57. }
  58. else
  59. {
  60. return (LPBYTE) ( ( ( LPSTR ) szCurrent ) + dwChars );
  61. }
  62. }
  63. LPBYTE
  64. CFileModify::MoveXChars(LPVOID szCurrent, DWORD dwChars)
  65. {
  66. return MoveXChars( (LPBYTE) szCurrent, dwChars );
  67. }
  68. // function: SetValue
  69. //
  70. // Set the value at the location specified
  71. //
  72. // Parameters:
  73. // szCurrent - Pointer to a unicode or ansi string
  74. // (type is determined by m_m_bUnicode)
  75. // dwValue - The value to put in the string
  76. // dwOffset - Offset to add to szCurrent (in chars) (default of 0)
  77. //
  78. void
  79. CFileModify::SetValue(LPBYTE szCurrent, DWORD dwValue, DWORD dwOffset )
  80. {
  81. LPBYTE szNewLocation = szCurrent;
  82. if ( dwOffset )
  83. {
  84. szNewLocation = MoveXChars(szCurrent,dwOffset);
  85. }
  86. if ( m_bUnicode )
  87. {
  88. * ( ( LPWSTR ) szNewLocation ) = (WCHAR) dwValue;
  89. }
  90. else
  91. {
  92. * ( ( LPSTR ) szNewLocation ) = (CHAR) dwValue;
  93. }
  94. }
  95. void
  96. CFileModify::SetValue(PVOID szCurrent, DWORD dwValue, DWORD dwOffset )
  97. {
  98. SetValue( (LPBYTE) szCurrent,dwValue,dwOffset);
  99. }
  100. // function: CopyString
  101. //
  102. // Copy a string into the buffer
  103. void
  104. CFileModify::CopyString(LPBYTE szCurrent, LPTSTR szInsertString)
  105. {
  106. while ( *szInsertString )
  107. {
  108. SetValue(szCurrent,*szInsertString);
  109. GetNextChar(szCurrent);
  110. szInsertString++;
  111. }
  112. }
  113. // function: AbortFile
  114. //
  115. // Abort the current file modification. So, we close the file handles, and delete the
  116. // file that we wrote to
  117. //
  118. BOOL
  119. CFileModify::AbortFile()
  120. {
  121. BOOL bRet = TRUE;
  122. if (m_hReadFile != INVALID_HANDLE_VALUE)
  123. {
  124. CloseHandle(m_hReadFile);
  125. m_hReadFile = INVALID_HANDLE_VALUE;
  126. }
  127. if (m_hWriteFile != INVALID_HANDLE_VALUE)
  128. {
  129. CloseHandle(m_hWriteFile);
  130. m_hWriteFile = INVALID_HANDLE_VALUE;
  131. bRet = DeleteFile( m_szWriteFileName );
  132. }
  133. return bRet;
  134. }
  135. // function: CloseFile
  136. //
  137. // Close all of the files, and write all the data to disk
  138. //
  139. BOOL
  140. CFileModify::CloseFile()
  141. {
  142. BOOL bWrite = m_hWriteFile != INVALID_HANDLE_VALUE;
  143. BOOL bRet = TRUE;
  144. if ( bWrite )
  145. {
  146. // Dump the rest of the input file to the output one.
  147. while ( ReadNextChunk() )
  148. {
  149. // Move to the end of the block, so it will all be written
  150. m_szCurrentData = MoveXChars( m_buffData.QueryPtr(), m_dwSizeofData );
  151. }
  152. if ( m_dwSizeofData )
  153. {
  154. // The last ReadNextChunk failed because we could not read anymore,
  155. // lets call it one more time to flush the rest of the data in the buffer
  156. m_szCurrentData = MoveXChars( m_buffData.QueryPtr(), m_dwSizeofData );
  157. ReadNextChunk();
  158. }
  159. }
  160. if (m_hReadFile != INVALID_HANDLE_VALUE)
  161. {
  162. CloseHandle(m_hReadFile);
  163. m_hReadFile = INVALID_HANDLE_VALUE;
  164. }
  165. if (m_hWriteFile != INVALID_HANDLE_VALUE)
  166. {
  167. CloseHandle(m_hWriteFile);
  168. m_hWriteFile = INVALID_HANDLE_VALUE;
  169. }
  170. if ( bWrite )
  171. {
  172. bRet = FALSE;
  173. if ( DeleteFile( m_szReadFileName ) )
  174. {
  175. MoveFile( m_szWriteFileName, m_szReadFileName );
  176. bRet = TRUE;
  177. }
  178. }
  179. return bRet;
  180. }
  181. // function: OpenFile
  182. //
  183. // This function opens a readonly handle to the file specified in szFileName,
  184. // also a second File handle will be opened with write only access under the
  185. // name szFileName+".tmp". This is for temporary storage for the new file
  186. //
  187. // Parameters:
  188. // szFileName - The filename of the file to read
  189. // bModify - Are we going to be modifing this file or not?
  190. //
  191. // Return
  192. // TRUE - Read and Write files we successfully opened
  193. // FALSE - Failure to open one of the files
  194. //
  195. BOOL
  196. CFileModify::OpenFile(LPTSTR szFileName, BOOL bModify)
  197. {
  198. CSecurityDescriptor AdminAcl;
  199. if ( ( _tcslen(szFileName) - _tcslen(_T(".tmp")) ) >= _MAX_PATH )
  200. {
  201. return FALSE;
  202. }
  203. if ( !AdminAcl.CreateAdminDAcl() )
  204. {
  205. // We could not create an admin acl, so lets exit
  206. return FALSE;
  207. }
  208. // First abort the last file, if one was opened
  209. AbortFile();
  210. _tcscpy(m_szReadFileName,szFileName);
  211. _tcscpy(m_szWriteFileName,szFileName);
  212. _tcscat(m_szWriteFileName,_T(".tmp"));
  213. m_hReadFile = CreateFile( m_szReadFileName,
  214. GENERIC_READ,
  215. FILE_SHARE_READ,
  216. NULL,
  217. OPEN_EXISTING,
  218. FILE_ATTRIBUTE_NORMAL,
  219. NULL );
  220. if ( m_hReadFile == INVALID_HANDLE_VALUE )
  221. {
  222. return FALSE;
  223. }
  224. if ( bModify )
  225. {
  226. m_hWriteFile = CreateFile( m_szWriteFileName,
  227. GENERIC_WRITE,
  228. 0,
  229. AdminAcl.QuerySA(),
  230. CREATE_ALWAYS,
  231. FILE_ATTRIBUTE_TEMPORARY,
  232. NULL );
  233. if ( m_hWriteFile == INVALID_HANDLE_VALUE )
  234. {
  235. // Close Read File and return
  236. AbortFile();
  237. return FALSE;
  238. }
  239. }
  240. m_szCurrentData = (LPBYTE) m_buffData.QueryPtr();
  241. m_dwSizeofData = 0;
  242. m_bUnicode = FALSE;
  243. if ( ReadNextChunk() )
  244. {
  245. if ( ( m_dwSizeofData > 3 ) &&
  246. ( *( ( LPBYTE ) m_buffData.QueryPtr() ) == 0xEF ) &&
  247. ( *( ( LPBYTE ) m_buffData.QueryPtr() + 1 ) == 0xBB ) &&
  248. ( *( ( LPBYTE ) m_buffData.QueryPtr() + 2 ) == 0xBF )
  249. )
  250. {
  251. // It is UTF8 Encoded
  252. m_bUnicode = FALSE;
  253. m_szCurrentData = (LPBYTE) m_buffData.QueryPtr() + 3;
  254. }
  255. else if ( ( m_dwSizeofData >= 2 ) &&
  256. ( *( ( LPBYTE ) m_buffData.QueryPtr() ) == 0xFF ) &&
  257. ( *( ( LPBYTE ) m_buffData.QueryPtr() + 1 ) == 0xFE)
  258. )
  259. {
  260. // It is Unicode
  261. m_bUnicode = TRUE;
  262. m_szCurrentData = (LPBYTE) m_buffData.QueryPtr() + 2;
  263. }
  264. }
  265. return TRUE;
  266. }
  267. // function: ResizeData
  268. //
  269. // Resize the data buffer to the size specified
  270. // never shrink the buffer itself, just exand it
  271. //
  272. // Parameters:
  273. // dwNewSize - The new size needed
  274. BOOL
  275. CFileModify::ResizeData(DWORD dwNewSize)
  276. {
  277. BOOL bRet = TRUE;
  278. if (m_buffData.QuerySize() < (dwNewSize + 2) )
  279. {
  280. DWORD dwCurrentOffset = (DWORD) (DWORD_PTR) (m_szCurrentData - (LPBYTE) m_buffData.QueryPtr());
  281. if ( !m_buffData.Resize(dwNewSize + 2) )
  282. {
  283. // We failed to allocate the memory necessary
  284. bRet = FALSE;
  285. }
  286. if (dwCurrentOffset <= dwNewSize)
  287. {
  288. m_szCurrentData = (LPBYTE) m_buffData.QueryPtr() + dwCurrentOffset;
  289. }
  290. else
  291. {
  292. ASSERT(FALSE);
  293. m_szCurrentData = (LPBYTE) m_buffData.QueryPtr();
  294. }
  295. }
  296. return bRet;
  297. }
  298. // function: ResizeData
  299. //
  300. // Resize Data, and move the pointer accourdingly
  301. //
  302. BOOL
  303. CFileModify::ResizeData(DWORD dwNewSize, LPBYTE *szString)
  304. {
  305. DWORD dwOffset = (DWORD) (DWORD_PTR) ( *szString - GetCurrentLocation() );
  306. BOOL bRet;
  307. bRet = ResizeData(dwNewSize);
  308. // Move current pointer to account for possible resizing of buffer
  309. *szString = GetCurrentLocation() + dwOffset;
  310. return bRet;
  311. }
  312. // function: ReadNextChunk
  313. //
  314. // Read in the next Chunk of Data, in order to do this, take the part of
  315. // the chunck that has already been processed, and write it to the output
  316. // file. Then move the rest of the chunck over, so that you can read some
  317. // more data in. The divider between processed, and unprocessed is determined
  318. // by the location of m_szCurrentData
  319. //
  320. // Data before:
  321. // |-------------------------------------------------------------|
  322. // | Used Data | Currently using Data | Extra Space |
  323. // |-------------------------------------------------------------|
  324. //
  325. // Data after:
  326. // |-------------------------------------------------------------|
  327. // | Currently using Data | New Data |
  328. // |-------------------------------------------------------------|
  329. //
  330. // Return:
  331. // TRUE - The next piece of data was correctly read in
  332. // FASLE - Their was an error, either reading from the file, or writing the
  333. // data that we currently have to the output file.
  334. BOOL
  335. CFileModify::ReadNextChunk()
  336. {
  337. DWORD dwUsedSize; // Size of Block used and done with (in bytes)
  338. DWORD dwCurrentlyUsingSize; // Size of Data to keep
  339. DWORD dwExtraSpaceSize; // Size of Free Space
  340. DWORD dwTotalChunkSize;
  341. DWORD dwSizeofCurrentChunk;
  342. if ( m_dwSizeofData != 0 )
  343. {
  344. dwUsedSize = (DWORD) ( ( (BYTE*) m_szCurrentData ) - ( (BYTE*) m_buffData.QueryPtr() ) );
  345. dwCurrentlyUsingSize = m_dwSizeofData - dwUsedSize;
  346. dwExtraSpaceSize = m_buffData.QuerySize() - dwCurrentlyUsingSize - 2; // 2 for possible LPWSTR '\0'
  347. ASSERT( dwUsedSize <= m_dwSizeofData ); // Assert that the UsedSection is smaller that our overall section size
  348. }
  349. else
  350. {
  351. // We have not read anything in before, so initialize stuff
  352. dwUsedSize = 0;
  353. dwCurrentlyUsingSize = 0;
  354. dwExtraSpaceSize = m_buffData.QuerySize() - dwCurrentlyUsingSize - 2;
  355. }
  356. if ( dwUsedSize )
  357. {
  358. // Part of this block is done with, so lets write it to disk
  359. dwTotalChunkSize = dwUsedSize;
  360. dwSizeofCurrentChunk = 0;
  361. if ( m_hWriteFile != INVALID_HANDLE_VALUE )
  362. {
  363. LPBYTE pData = (LPBYTE) m_buffData.QueryPtr();
  364. // If we have a file open, then lets write to it, if not then we are read only
  365. while ( dwTotalChunkSize > 0 )
  366. {
  367. if ( ( !WriteFile(m_hWriteFile, // Handle to write file
  368. pData, // Data to send
  369. dwTotalChunkSize, // # of Bytes to write
  370. &dwSizeofCurrentChunk, // Bytes Written
  371. NULL ) ) ||
  372. ( dwSizeofCurrentChunk == 0 )
  373. )
  374. {
  375. // We had problems writing to disk, FAIL
  376. return FALSE;
  377. }
  378. pData += dwSizeofCurrentChunk;
  379. dwTotalChunkSize -= dwSizeofCurrentChunk;
  380. }
  381. }
  382. // Move Current Block
  383. memmove( m_buffData.QueryPtr(), m_szCurrentData, dwCurrentlyUsingSize + 2 );
  384. m_szCurrentData = ( (BYTE *) m_buffData.QueryPtr() );
  385. m_dwSizeofData -= dwUsedSize;
  386. }
  387. else if (dwCurrentlyUsingSize)
  388. {
  389. // If there is not data to take out of the buffer, and we have data in the buffer
  390. // Double the size of the buffer
  391. ResizeData( m_buffData.QuerySize() * 2 );
  392. dwExtraSpaceSize = m_buffData.QuerySize() - dwCurrentlyUsingSize - 2; // 2 for possible LPWSTR '\0'
  393. }
  394. if ( dwExtraSpaceSize != 0 )
  395. {
  396. // There is space remaining in the block, so lets read the data in
  397. dwTotalChunkSize = dwExtraSpaceSize;
  398. dwSizeofCurrentChunk = 0;
  399. while ( dwTotalChunkSize > 0 )
  400. {
  401. if ( !ReadFile( m_hReadFile,
  402. ( (BYTE *) m_buffData.QueryPtr() ) + dwCurrentlyUsingSize,
  403. dwTotalChunkSize,
  404. &dwSizeofCurrentChunk,
  405. NULL ) )
  406. {
  407. // We could not read the chunk, so fail
  408. return FALSE;
  409. }
  410. if ( dwSizeofCurrentChunk == 0 )
  411. {
  412. if ( dwExtraSpaceSize == dwTotalChunkSize )
  413. {
  414. // If the extra space is the same as the totalchunksize, then we
  415. // haven't read anything yet, so return FALSE signifying that we
  416. // did not read anything from the file
  417. return FALSE;
  418. }
  419. // We are at the end of file, so break out.
  420. break;
  421. }
  422. dwTotalChunkSize -= dwSizeofCurrentChunk;
  423. dwCurrentlyUsingSize += dwSizeofCurrentChunk;
  424. }
  425. // Terminate Block
  426. m_dwSizeofData = dwCurrentlyUsingSize;
  427. SetValue(m_buffData.QueryPtr(),'\0',dwCurrentlyUsingSize / (m_bUnicode?2:1) );
  428. }
  429. return TRUE;
  430. }
  431. // function: MoveCurrentPtr
  432. //
  433. // Move the pointer in the array
  434. //
  435. // Parameters
  436. // szCurrent - New Location
  437. //
  438. BOOL
  439. CFileModify::MoveCurrentPtr(LPBYTE szCurrent)
  440. {
  441. if ( (szCurrent < m_buffData.QueryPtr()) || (szCurrent > ( (LPBYTE) m_buffData.QueryPtr() + m_buffData.QuerySize() ) ) )
  442. {
  443. // This is out of range, reject position
  444. ASSERT(FALSE);
  445. return FALSE;
  446. }
  447. m_szCurrentData = szCurrent;
  448. return TRUE;
  449. }
  450. // function: GetCurrentLocation
  451. //
  452. // return a pointer to the current location of the pointer
  453. LPBYTE
  454. CFileModify::GetCurrentLocation()
  455. {
  456. return m_szCurrentData;
  457. }
  458. // function: GetBaseLocation
  459. //
  460. // return a pointer to the begining of the block
  461. LPBYTE
  462. CFileModify::GetBaseLocation()
  463. {
  464. return (LPBYTE) m_buffData.QueryPtr();
  465. }
  466. // function: GetNextChar
  467. // return the value of the next character
  468. //
  469. // Parameters:
  470. // szCurrent - Pointer to part of our m_buffData Block
  471. //
  472. // Return Value:
  473. // The unicode of ansi value for the next character
  474. //
  475. DWORD
  476. CFileModify::GetNextChar(LPBYTE &szCurrent)
  477. {
  478. DWORD dwValue;
  479. if ( m_bUnicode )
  480. {
  481. szCurrent = (LPBYTE) ( ( LPWSTR ) szCurrent) + 1;
  482. dwValue = *( ( LPWSTR ) szCurrent);
  483. }
  484. else
  485. {
  486. szCurrent = (LPBYTE) ( ( LPSTR ) szCurrent) + 1;
  487. dwValue = *( ( LPSTR ) szCurrent);
  488. }
  489. return dwValue;
  490. }
  491. // function: GetNextWideChar
  492. //
  493. // Return the value of the next wide character
  494. //
  495. // Return Value:
  496. // The unicode equivalent of the next character
  497. //
  498. DWORD
  499. CFileModify::GetNextWideChar(LPBYTE &szCurrent)
  500. {
  501. if ( m_bUnicode )
  502. {
  503. szCurrent = (LPBYTE) ( ( LPWSTR ) szCurrent) + 1;
  504. }
  505. else
  506. {
  507. szCurrent = (LPBYTE) CharNextA( (LPSTR) szCurrent );
  508. }
  509. return GetWideChar( szCurrent );
  510. }
  511. // function: GetPrevChar
  512. // return the value of pointer decremeted and dereferenced
  513. //
  514. // Parameters:
  515. // szCurrent - Pointer to part of our m_buffData Block
  516. //
  517. // Return Value:
  518. // The unicode of ansi value for the next character that is pointer at
  519. //
  520. DWORD
  521. CFileModify::GetPrevChar(LPBYTE &szCurrent)
  522. {
  523. DWORD dwValue;
  524. if ( m_bUnicode )
  525. {
  526. szCurrent = (LPBYTE) ( ( LPWSTR ) szCurrent) - 1;
  527. dwValue = *( ( LPWSTR ) szCurrent);
  528. }
  529. else
  530. {
  531. szCurrent = (LPBYTE) ( ( LPSTR ) szCurrent) - 1;
  532. dwValue = *( ( LPSTR ) szCurrent);
  533. }
  534. return dwValue;
  535. }
  536. // function: GetChar
  537. // return the value of the current character
  538. //
  539. // Parameters:
  540. // szCurrent - Pointer to part of our m_buffData Block
  541. //
  542. // Return Value:
  543. // The unicode of ansi value for the character that is pointer at
  544. //
  545. DWORD
  546. CFileModify::GetChar(LPBYTE szCurrent)
  547. {
  548. if ( m_bUnicode )
  549. {
  550. return *( ( LPWSTR ) szCurrent );
  551. }
  552. else
  553. {
  554. return *( ( LPSTR ) szCurrent );
  555. }
  556. }
  557. // function: GetWideChar
  558. //
  559. // Get the Wide Char equivalent of the current character
  560. //
  561. WCHAR
  562. CFileModify::GetWideChar(LPBYTE szCurrent)
  563. {
  564. if ( m_bUnicode )
  565. {
  566. return (WCHAR) *( ( LPWSTR ) szCurrent );
  567. }
  568. else
  569. {
  570. DWORD dwMBCSLen = (DWORD) ( ( (LPBYTE) CharNextA( (LPSTR) szCurrent ) ) - szCurrent );
  571. WCHAR wChar;
  572. if ( MultiByteToWideChar( CP_ACP,
  573. MB_PRECOMPOSED,
  574. (LPSTR) szCurrent,
  575. dwMBCSLen,
  576. &wChar,
  577. sizeof(wChar)/sizeof(WCHAR) ) == 0 )
  578. {
  579. return 0;
  580. }
  581. return wChar;
  582. }
  583. }
  584. // function: MoveData
  585. //
  586. // Expand or contract data in order to add a value or remove one
  587. //
  588. // Parameters:
  589. // szCurrent - A pointer to where the data will be removed/added
  590. // iBytes - The amount of data to remove or add
  591. //
  592. BOOL
  593. CFileModify::MoveData(LPBYTE szCurrent, INT iBytes)
  594. {
  595. DWORD dwNewSize = ( (INT) m_dwSizeofData ) + iBytes;
  596. if ( !ResizeData(dwNewSize, &szCurrent) )
  597. {
  598. return FALSE;
  599. }
  600. if ( iBytes > 0 )
  601. {
  602. // Move bytes forward
  603. memmove( szCurrent + iBytes, szCurrent, m_dwSizeofData - ( szCurrent - (LPBYTE) m_buffData.QueryPtr() ) + 2 );
  604. }
  605. else
  606. if ( iBytes < 0 )
  607. {
  608. // Move bytes back
  609. memmove( szCurrent, szCurrent - iBytes, m_dwSizeofData - ( szCurrent - iBytes - (LPBYTE) m_buffData.QueryPtr() ) + 2 );
  610. }
  611. m_dwSizeofData = dwNewSize;
  612. return TRUE;
  613. }
  614. BOOL
  615. CFileModify::IsUnicode()
  616. {
  617. return m_bUnicode;
  618. }
  619. // function: GetBufferSize
  620. //
  621. // return the size of the buffer used in this class
  622. DWORD
  623. CFileModify::GetBufferSize()
  624. {
  625. return (m_dwSizeofData);
  626. }
  627. // function: CXMLEdit
  628. //
  629. // Constructor for XMLEditor
  630. //
  631. CXMLEdit::CXMLEdit():
  632. m_dwItemOffset(0),
  633. m_dwPropertyOffset(0),
  634. m_dwValueOffset(0)
  635. {
  636. }
  637. // function: ~CXMLEdit
  638. //
  639. // Destructor for XMLEditor
  640. //
  641. // Close Everything open
  642. //
  643. CXMLEdit::~CXMLEdit()
  644. {
  645. XMLFile.CloseFile();
  646. }
  647. // function: Open
  648. //
  649. // Open the file to edit
  650. //
  651. BOOL
  652. CXMLEdit::Open(LPTSTR szName, BOOL bModify )
  653. {
  654. BOOL bRet;
  655. bRet = XMLFile.OpenFile(szName,bModify);
  656. if ( bRet )
  657. {
  658. SetCurrentItem(XMLFile.GetCurrentLocation());
  659. }
  660. return bRet;
  661. }
  662. // function: Close
  663. //
  664. // Close the xml file
  665. //
  666. BOOL
  667. CXMLEdit::Close()
  668. {
  669. return XMLFile.CloseFile();
  670. }
  671. // function: MoveData
  672. //
  673. // Move the data in the CFileModify. This also means that we need to move our
  674. // pointers into it.
  675. //
  676. // Parameters:
  677. // szCurrent - A pointer to where the data will be removed/added
  678. // iBytes - The amount of data to remove or add
  679. //
  680. BOOL
  681. CXMLEdit::MoveData(LPBYTE szCurrent, INT iBytes)
  682. {
  683. return XMLFile.MoveData(szCurrent,iBytes);
  684. }
  685. // function: ReadNextChunk();
  686. //
  687. // ReadNextChunk of Data
  688. //
  689. BOOL
  690. CXMLEdit::ReadNextChunk()
  691. {
  692. BOOL bRet;
  693. DWORD dwItemOffset = (DWORD) (DWORD_PTR) (GetCurrentItem() - XMLFile.GetCurrentLocation());
  694. DWORD dwPropertyOffset = (DWORD) (DWORD_PTR) (GetCurrentProperty() - XMLFile.GetCurrentLocation());
  695. DWORD dwValueOffset = (DWORD) (DWORD_PTR) (GetCurrentValue() - XMLFile.GetCurrentLocation());
  696. bRet = XMLFile.ReadNextChunk();
  697. // Since the CurrentLocation Pointer might have moved, move
  698. // our pointers as well!
  699. SetCurrentItem( ((LPBYTE) XMLFile.GetCurrentLocation()) + dwItemOffset );
  700. SetCurrentProperty( ((LPBYTE) XMLFile.GetCurrentLocation()) + dwPropertyOffset );
  701. SetCurrentValue( ((LPBYTE) XMLFile.GetCurrentLocation()) + dwValueOffset );
  702. return bRet;
  703. }
  704. // function: LoadFullItem
  705. //
  706. // Load the full item into memory, will all of it's properties before continuing
  707. // The purpose of this is to make it much easier for other functions to scan
  708. // through the buffer. It is a lot simplier, it they can assume all the information
  709. // they need is loaded.
  710. //
  711. // Parameters:
  712. // szPointerInsideBuffer [in/out] - This is a pointer to a something side of our
  713. // file buffer. The purpose of this, is so that we can move this pointer
  714. // so that it points to the same data before we moved the buffer
  715. void
  716. CXMLEdit::LoadFullItem()
  717. {
  718. LPBYTE szCurrent = GetCurrentItem();
  719. LPBYTE szCurrentTemp;
  720. DWORD cCurrent;
  721. BOOL bContinue = TRUE;
  722. do {
  723. cCurrent = XMLFile.GetChar( szCurrent );
  724. szCurrentTemp = szCurrent;
  725. if ( (cCurrent == '<') ||
  726. (cCurrent == '>') ||
  727. ( (cCurrent == '/') && ( XMLFile.GetNextChar(szCurrentTemp) == '>' ) )
  728. )
  729. {
  730. // We have found the end
  731. return;
  732. }
  733. if ( cCurrent == '\0' )
  734. {
  735. // We have found the end of the string, try to get the next chunk
  736. if (!ReadNextChunk())
  737. {
  738. return;
  739. }
  740. // Start again at begining
  741. szCurrent = GetCurrentItem();
  742. }
  743. else
  744. {
  745. szCurrentTemp = szCurrent;
  746. szCurrent = SkipString(szCurrent);
  747. if (szCurrent == szCurrentTemp)
  748. {
  749. XMLFile.GetNextChar( szCurrent );
  750. }
  751. }
  752. } while (bContinue);
  753. }
  754. // function: FindNextItem
  755. //
  756. // Find the next item after the pointer that we are sent
  757. //
  758. // Parameters:
  759. // szStartLocation - A pointer to the current item
  760. // bReturnName - Return a pointer to the begining of the name
  761. //
  762. LPBYTE
  763. CXMLEdit::FindNextItem(LPBYTE szStartLocation, BOOL bReturnName)
  764. {
  765. BOOL bQuotes;
  766. LPBYTE szCurrent;
  767. DWORD dwItemOffset;
  768. if (!szStartLocation)
  769. {
  770. // We have no item to start at
  771. return NULL;
  772. }
  773. // Calculate offset for Start (incase pointer moves)
  774. dwItemOffset = (DWORD) (DWORD_PTR) (szStartLocation - XMLFile.GetCurrentLocation());
  775. do
  776. {
  777. // Reset szCurrent to begining of current item
  778. szCurrent = XMLFile.GetCurrentLocation() + dwItemOffset;
  779. bQuotes = FALSE;
  780. while ( XMLFile.GetChar( szCurrent ) != '\0')
  781. {
  782. switch ( XMLFile.GetChar( szCurrent ) )
  783. {
  784. case '"':
  785. bQuotes = !bQuotes;
  786. break;
  787. case '<':
  788. if (!bQuotes)
  789. {
  790. LPBYTE szTempCurrent = szCurrent;
  791. // Move past '<'
  792. XMLFile.GetNextChar(szCurrent);
  793. while ( IsWhiteSpace( XMLFile.GetChar( szCurrent ) ) )
  794. {
  795. XMLFile.GetNextChar(szCurrent);
  796. }
  797. if (bReturnName)
  798. {
  799. szTempCurrent = szCurrent;
  800. }
  801. while ( ( XMLFile.GetChar( szCurrent ) != ' ') && ( XMLFile.GetChar( szCurrent ) != '\t') && ( XMLFile.GetChar( szCurrent ) != '\0') )
  802. {
  803. XMLFile.GetNextChar(szCurrent);
  804. }
  805. if ( XMLFile.GetChar( szCurrent ) != '\0')
  806. {
  807. // We could not read the whole name, because we are the end of what we
  808. // read in, so lets try this whole thing again
  809. return ( szTempCurrent );
  810. }
  811. }
  812. else
  813. {
  814. // Remove
  815. //ASSERT(FALSE);
  816. }
  817. break;
  818. default:
  819. break;
  820. }
  821. if ( XMLFile.GetChar( szCurrent ) != '\0' )
  822. {
  823. XMLFile.GetNextChar(szCurrent);
  824. }
  825. }
  826. } while ( ReadNextChunk() );
  827. return NULL;
  828. }
  829. // function: FindNextItem()
  830. //
  831. // find the next item. This means to start at the item we are in, and get to the
  832. // next one
  833. //
  834. // Parameters:
  835. // bReturnName - Skip the '<' at the beinging of the item, and return a pointer to the
  836. // begining of the name
  837. LPBYTE
  838. CXMLEdit::FindNextItem(BOOL bReturnName)
  839. {
  840. return FindNextItem(GetCurrentItem(),bReturnName);
  841. }
  842. // function: SkipString
  843. //
  844. // Skip over a string value, and the spaces trailing it
  845. //
  846. LPBYTE
  847. CXMLEdit::SkipString(LPBYTE szString, BOOL bSkipTrailingWhiteSpaces)
  848. {
  849. BOOL bQuotes = FALSE;
  850. while ( XMLFile.GetChar( szString ) )
  851. {
  852. switch ( XMLFile.GetChar( szString ) )
  853. {
  854. case '"':
  855. bQuotes = !bQuotes;
  856. break;
  857. case '<':
  858. case '>':
  859. case '=':
  860. if ( !bQuotes )
  861. {
  862. return szString;
  863. }
  864. break;
  865. default:
  866. if ( !bQuotes )
  867. {
  868. if ( IsWhiteSpace( XMLFile.GetChar( szString ) ) )
  869. {
  870. if (bSkipTrailingWhiteSpaces)
  871. {
  872. while ( IsWhiteSpace( XMLFile.GetChar( szString ) ) )
  873. {
  874. XMLFile.GetNextChar(szString);
  875. }
  876. }
  877. return szString;
  878. }
  879. }
  880. break;
  881. }
  882. XMLFile.GetNextChar(szString);
  883. }
  884. if (bSkipTrailingWhiteSpaces)
  885. {
  886. while ( IsWhiteSpace( XMLFile.GetChar( szString ) ) )
  887. {
  888. XMLFile.GetNextChar(szString);
  889. }
  890. }
  891. return szString;
  892. }
  893. // function: FindNextProperty
  894. //
  895. // Find the next property in the current item
  896. //
  897. // Parameters:
  898. // szCurrentValue - Pointer to Value
  899. //
  900. // Return Values
  901. // NULL - Another Property was not found
  902. // not NULL - The pointer to the next property
  903. LPBYTE
  904. CXMLEdit::FindNextProperty(LPBYTE &szValue)
  905. {
  906. BOOL bQuotes;
  907. LPBYTE szCurrent;
  908. LPBYTE szCurrentProp;
  909. LPBYTE szCurrentValue;
  910. if (!GetCurrentProperty())
  911. {
  912. // We do not have a current property
  913. return NULL;
  914. }
  915. do
  916. {
  917. // Reset szCurrent to begining of current property
  918. bQuotes = FALSE;
  919. szCurrent = SkipString(GetCurrentProperty());
  920. if ( XMLFile.GetChar(szCurrent) == '=' )
  921. {
  922. // We have found a value for our old property
  923. XMLFile.GetNextChar(szCurrent);
  924. szCurrent = SkipString(szCurrent);
  925. }
  926. // Set the current property
  927. szCurrentProp = szCurrent;
  928. // Try to find a value for this property
  929. szCurrent = SkipString(szCurrent);
  930. if ( XMLFile.GetChar(szCurrent) == '=' )
  931. {
  932. // We have found a value for our new property
  933. XMLFile.GetNextChar(szCurrent);
  934. szCurrentValue = szCurrent;
  935. }
  936. else
  937. {
  938. szCurrentValue = NULL;
  939. }
  940. if ( ( XMLFile.GetChar(szCurrent) == '<' ) || ( XMLFile.GetChar(szCurrent) == '>' ) )
  941. {
  942. // We have left the current item, so return NULL
  943. return NULL;
  944. }
  945. if ( XMLFile.GetChar(szCurrent) != '\0' )
  946. {
  947. // We have found the next item, lets return it
  948. szValue = szCurrentValue;
  949. return szCurrentProp;
  950. }
  951. } while ( ReadNextChunk() );
  952. // End of File, no more values are present.
  953. return NULL;
  954. }
  955. // function: MoveToNextItem
  956. //
  957. // Move to the Next Item
  958. //
  959. BOOL
  960. CXMLEdit::MovetoNextItem()
  961. {
  962. LPBYTE szTemp;
  963. LPBYTE szLastItem;
  964. szTemp = FindNextItem();
  965. szLastItem = GetCurrentItem(); // Do this afterwards, just incase we moved the buffer
  966. if (szTemp == NULL)
  967. {
  968. return FALSE;
  969. }
  970. SetCurrentItem(szTemp);
  971. SetCurrentProperty(szTemp);
  972. SetCurrentValue(szTemp);
  973. // Always keep the last item in the buffer
  974. // The reason for this, is because on delete we want to be able
  975. // to back up to the '<' of the current item
  976. XMLFile.MoveCurrentPtr(szLastItem);
  977. return TRUE;
  978. }
  979. // function: MoveToNextProperty
  980. //
  981. // Move to the Next Property
  982. //
  983. BOOL
  984. CXMLEdit::MovetoNextProperty()
  985. {
  986. LPBYTE szTemp;
  987. LPBYTE szTempValue = NULL;
  988. szTemp = FindNextProperty(szTempValue);
  989. if (szTemp == NULL)
  990. {
  991. return FALSE;
  992. }
  993. SetCurrentProperty(szTemp);
  994. if (szTempValue)
  995. {
  996. SetCurrentValue(szTempValue);
  997. }
  998. else
  999. {
  1000. SetCurrentValue(szTemp);
  1001. }
  1002. return TRUE;
  1003. }
  1004. // function: MoveToFirstProperty
  1005. //
  1006. // Move to the First Property
  1007. //
  1008. BOOL
  1009. CXMLEdit::MovetoFirstProperty()
  1010. {
  1011. SetCurrentProperty(GetCurrentItem());
  1012. SetCurrentValue(GetCurrentProperty());
  1013. return MovetoNextProperty();
  1014. }
  1015. // RetrieveCurrentValue
  1016. //
  1017. // Retrieve the current Value, and put it in pstrValue
  1018. //
  1019. BOOL
  1020. CXMLEdit::RetrieveCurrentValue( TSTR *pstrValue )
  1021. {
  1022. LPBYTE szBeginingofValue;
  1023. LPBYTE szCurrentLocation;
  1024. BOOL bInsideQuotes = FALSE;
  1025. DWORD dwCurrentLen = 0;
  1026. DWORD i;
  1027. LoadFullItem();
  1028. szBeginingofValue = GetCurrentValue();
  1029. if ( *szBeginingofValue == '"' )
  1030. {
  1031. bInsideQuotes = TRUE;
  1032. XMLFile.GetNextChar(szBeginingofValue);
  1033. }
  1034. szCurrentLocation = szBeginingofValue;
  1035. while ( TRUE )
  1036. {
  1037. if ( bInsideQuotes && ( XMLFile.GetWideChar(szCurrentLocation) == '"' ) )
  1038. {
  1039. // Hit end
  1040. break;
  1041. }
  1042. if ( ( !bInsideQuotes && IsTerminator( XMLFile.GetWideChar(szCurrentLocation) ) ) ||
  1043. ( XMLFile.GetWideChar(szCurrentLocation) == '\0' ) )
  1044. {
  1045. // We hit the end again
  1046. break;
  1047. }
  1048. XMLFile.GetNextWideChar(szCurrentLocation);
  1049. dwCurrentLen++;
  1050. }
  1051. if ( !pstrValue->Resize( dwCurrentLen + 1 ) )
  1052. {
  1053. return FALSE;
  1054. }
  1055. szCurrentLocation = szBeginingofValue;
  1056. for ( i = 0;
  1057. i < dwCurrentLen;
  1058. i++ )
  1059. {
  1060. *(pstrValue->QueryStr() + i ) = ( WCHAR ) XMLFile.GetWideChar( szCurrentLocation );
  1061. XMLFile.GetNextWideChar( szCurrentLocation );
  1062. }
  1063. *(pstrValue->QueryStr() + i ) = '\0';
  1064. return TRUE;
  1065. }
  1066. // function:IsWhiteSpace
  1067. //
  1068. // returns if the character is a space
  1069. //
  1070. BOOL
  1071. CXMLEdit::IsWhiteSpace(DWORD ch)
  1072. {
  1073. return ( ( ch == ' ' ) ||
  1074. ( ch == '\t' ) ||
  1075. ( ch == '\r' ) ||
  1076. ( ch == '\n' )
  1077. );
  1078. }
  1079. // function:IsWhiteSpace
  1080. //
  1081. // returns if the character is a xml string terminator
  1082. //
  1083. BOOL
  1084. CXMLEdit::IsTerminator(DWORD ch)
  1085. {
  1086. return ( ( ch == '\0' ) ||
  1087. ( ch == '=' ) ||
  1088. IsWhiteSpace(ch)
  1089. );
  1090. }
  1091. // function: GetCurrentItem
  1092. //
  1093. // Return a pointer to the Current Item
  1094. LPBYTE
  1095. CXMLEdit::GetCurrentItem()
  1096. {
  1097. return XMLFile.GetBaseLocation() + m_dwItemOffset;
  1098. }
  1099. // function: GetCurrentProperty
  1100. //
  1101. // Return a pointer to the Current Property
  1102. LPBYTE
  1103. CXMLEdit::GetCurrentProperty()
  1104. {
  1105. return XMLFile.GetBaseLocation() + m_dwPropertyOffset;
  1106. }
  1107. // function: GetCurrentValue
  1108. //
  1109. // Return a pointer to the value for the current property
  1110. LPBYTE
  1111. CXMLEdit::GetCurrentValue()
  1112. {
  1113. return XMLFile.GetBaseLocation() + m_dwValueOffset;
  1114. }
  1115. // function: SetCurrentItem
  1116. //
  1117. // Set the location for the current item
  1118. void
  1119. CXMLEdit::SetCurrentItem(LPBYTE szInput)
  1120. {
  1121. ASSERT( ((DWORD) ( szInput - XMLFile.GetBaseLocation() ) ) < XMLFile.GetBufferSize() );
  1122. m_dwItemOffset = (DWORD) (DWORD_PTR) (szInput - XMLFile.GetBaseLocation());
  1123. }
  1124. // function: SetCurrentProperty
  1125. //
  1126. // Set the location for the current property
  1127. void
  1128. CXMLEdit::SetCurrentProperty(LPBYTE szInput)
  1129. {
  1130. ASSERT( ((DWORD) ( szInput - XMLFile.GetBaseLocation() ) ) < XMLFile.GetBufferSize() );
  1131. m_dwPropertyOffset = (DWORD) (DWORD_PTR) (szInput - XMLFile.GetBaseLocation());
  1132. }
  1133. // function: SetCurrentValue
  1134. //
  1135. // Set the location for the current value
  1136. void
  1137. CXMLEdit::SetCurrentValue(LPBYTE szInput)
  1138. {
  1139. ASSERT( ((DWORD) ( szInput - XMLFile.GetBaseLocation() ) ) < XMLFile.GetBufferSize() );
  1140. m_dwValueOffset = (DWORD) (DWORD_PTR) (szInput - XMLFile.GetBaseLocation());
  1141. }
  1142. // function: FindBeginingofItem
  1143. //
  1144. // Find the begining of the current item
  1145. //
  1146. // Parameters:
  1147. // szInput - The Location to start at
  1148. //
  1149. // Return:
  1150. // NULL - Could not find the begining
  1151. // Pointer - The begining, starting with the '<'
  1152. LPBYTE
  1153. CXMLEdit::FindBeginingofItem(LPBYTE szInput)
  1154. {
  1155. while ( ( szInput >= XMLFile.GetBaseLocation() ) &&
  1156. ( XMLFile.GetChar(szInput) != '\0' )
  1157. )
  1158. {
  1159. if ( XMLFile.GetChar(szInput) == '<' )
  1160. {
  1161. return szInput;
  1162. }
  1163. XMLFile.GetPrevChar(szInput);
  1164. }
  1165. return NULL;
  1166. }
  1167. // function: DeleteItem()
  1168. //
  1169. // Delete an item
  1170. //
  1171. // Note: This will not only delete the current item, but it will delete any items that
  1172. // are nested inside of it.
  1173. //
  1174. // Return:
  1175. // TRUE - Deleted successfully
  1176. // FALSE - Failed to delete it
  1177. BOOL
  1178. CXMLEdit::DeleteItem()
  1179. {
  1180. LPBYTE szBegin;
  1181. LPBYTE szEnd;
  1182. LPBYTE szCurrentItem;
  1183. DWORD dwNestedItems = 0;
  1184. do {
  1185. // Load the whole item
  1186. LoadFullItem();
  1187. // Increment this because we are inside an item
  1188. dwNestedItems++;
  1189. // Initialize to the current Item
  1190. szCurrentItem = GetCurrentItem();
  1191. // Scan for terminator
  1192. // See if this is the end of an item
  1193. if ( XMLFile.GetChar(szCurrentItem) == '/' )
  1194. {
  1195. // This item is in the form </foo>, so it is the end of an item that
  1196. // was opened earlier, we have to subtract 2, one for the current item
  1197. // and one that was for the start of this one
  1198. ASSERT(dwNestedItems >= 2);
  1199. dwNestedItems -= 2;
  1200. }
  1201. // Move to next item
  1202. szEnd = FindNextItem(szCurrentItem,TRUE);
  1203. if (!szEnd)
  1204. {
  1205. // We could not find the end, so we couldn't delete it
  1206. return FALSE;
  1207. }
  1208. // See if this item self terminate (ie. <FOO bar="test"/>)
  1209. while ( ( szEnd != GetCurrentItem() ) &&
  1210. ( XMLFile.GetPrevChar(szEnd) != '>' )
  1211. )
  1212. {
  1213. // continue on
  1214. }
  1215. if ( ( XMLFile.GetChar(szEnd) == '>' ) &&
  1216. ( szEnd != GetCurrentItem() ) &&
  1217. ( XMLFile.GetPrevChar(szEnd) == '/' )
  1218. )
  1219. {
  1220. // We have found an item that self terminates, so we can
  1221. // decrement the counter (ie. <foo bar="TRUE" />
  1222. ASSERT(dwNestedItems>0);
  1223. dwNestedItems--;
  1224. }
  1225. // Delete current item
  1226. szEnd = FindNextItem(GetCurrentItem(),FALSE);
  1227. if (!szEnd)
  1228. {
  1229. return FALSE;
  1230. }
  1231. szBegin = FindBeginingofItem( GetCurrentItem() );
  1232. MoveData(szBegin, (DWORD) (DWORD_PTR) (szBegin - szEnd) );
  1233. szBegin = FindNextItem(szBegin,TRUE);
  1234. if (!szBegin)
  1235. {
  1236. return FALSE;
  1237. }
  1238. SetCurrentItem(szBegin);
  1239. } while ( dwNestedItems > 0 );
  1240. return TRUE;
  1241. }
  1242. BOOL
  1243. CXMLEdit::DeleteValue()
  1244. {
  1245. // Not yet implemented
  1246. ASSERT(FALSE);
  1247. return FALSE;
  1248. }
  1249. BOOL
  1250. CXMLEdit::DeleteProperty()
  1251. {
  1252. LPBYTE szTemp;
  1253. LoadFullItem();
  1254. szTemp = SkipString( GetCurrentProperty() );
  1255. if ( XMLFile.GetChar(szTemp) == '=' )
  1256. {
  1257. // Skip the Value for this also
  1258. XMLFile.GetNextChar(szTemp);
  1259. szTemp = SkipString(szTemp);
  1260. }
  1261. if ( XMLFile.GetChar(szTemp) != '\0' )
  1262. {
  1263. XMLFile.MoveData( GetCurrentProperty(), (INT) ( GetCurrentProperty() - szTemp ) );
  1264. return TRUE;
  1265. }
  1266. return FALSE;
  1267. }
  1268. // function: ReplaceString
  1269. //
  1270. // Replace a string at a given location, with another string
  1271. // that is passed in.
  1272. //
  1273. // Parameters:
  1274. // szLocation - The location of the variable to change
  1275. // szNewValue - The new string to replace it with
  1276. //
  1277. // Return
  1278. // TRUE - It succeeded
  1279. // FLASE - It failed
  1280. BOOL
  1281. CXMLEdit::ReplaceString(LPBYTE szLocation, LPTSTR szNewValue)
  1282. {
  1283. LPBYTE szTemp;
  1284. LPBYTE szOldCurrentItem = GetCurrentItem();
  1285. LoadFullItem();
  1286. if ( szOldCurrentItem != GetCurrentItem() )
  1287. {
  1288. // Current Item has moved, so we must update the szLocation Pointer
  1289. szLocation = szLocation - (szOldCurrentItem - GetCurrentItem());
  1290. }
  1291. // Skip to the begining of the next string
  1292. szTemp = SkipString( szLocation, FALSE );
  1293. if ( XMLFile.GetChar(szTemp) != '\0' )
  1294. {
  1295. MoveData( szLocation, (INT) ( _tcslen(szNewValue) - ( szTemp - szLocation ) ) );
  1296. XMLFile.CopyString( szLocation, szNewValue);
  1297. return TRUE;
  1298. }
  1299. return FALSE;
  1300. }
  1301. // function: ReplaceItem
  1302. //
  1303. // Replace a item name at the CurrentItem()
  1304. //
  1305. // Parameters
  1306. // szNewItem - The new name item to add
  1307. //
  1308. BOOL
  1309. CXMLEdit::ReplaceItem(LPTSTR szNewItem)
  1310. {
  1311. return ReplaceString(GetCurrentItem(),szNewItem);
  1312. }
  1313. // function: ReplaceProperty
  1314. //
  1315. // Replace a property name at the property CurrentProperty()
  1316. //
  1317. // Parameters
  1318. // szProp - The new name for the property
  1319. //
  1320. BOOL
  1321. CXMLEdit::ReplaceProperty(LPTSTR szNewProp)
  1322. {
  1323. return ReplaceString(GetCurrentProperty(),szNewProp);
  1324. }
  1325. // function: ReplaceValue
  1326. //
  1327. // Replace a property name at the property CurrentProperty()
  1328. //
  1329. // Parameters
  1330. // szNewValueProp - The new name for the property
  1331. //
  1332. BOOL
  1333. CXMLEdit::ReplaceValue(LPTSTR szNewValue)
  1334. {
  1335. if (GetCurrentProperty() == GetCurrentValue())
  1336. {
  1337. // There is no value, so we will not replace the property
  1338. // by mistkae
  1339. return FALSE;
  1340. }
  1341. if (*szNewValue != '"')
  1342. {
  1343. BUFFER buffValue;
  1344. if (buffValue.Resize((_tcslen(szNewValue) + 3) * sizeof(TCHAR))) // 3 chars = '"' + '"' + '\0'
  1345. {
  1346. // Copy the string with quotes around it.
  1347. _tcscpy((LPTSTR) buffValue.QueryPtr(), _T("\""));
  1348. _tcscat((LPTSTR) buffValue.QueryPtr(), szNewValue);
  1349. _tcscat((LPTSTR) buffValue.QueryPtr(), _T("\""));
  1350. return ReplaceString(GetCurrentValue(),(LPTSTR) buffValue.QueryPtr());
  1351. }
  1352. return FALSE;
  1353. }
  1354. else
  1355. {
  1356. return ReplaceString(GetCurrentValue(),szNewValue);
  1357. }
  1358. }
  1359. // function: IsEqual
  1360. //
  1361. // Compares a Unicode and ANSI String to see if they are equal
  1362. //
  1363. // Note: This works on ANSI Strings, but will not work on DBCS
  1364. // Strings!
  1365. // Note: Termination character for this function is either a
  1366. // '\0', ' ', or '\t'
  1367. //
  1368. // Parameters:
  1369. // szWideString - Wide Char String
  1370. // szAnsiString - An Ansi String
  1371. //
  1372. // Return:
  1373. // TRUE - They are equal
  1374. // FALSE - They are not equal
  1375. BOOL
  1376. CXMLEdit::IsEqual(LPCWSTR szWideString, LPCSTR szAnsiString)
  1377. {
  1378. if (*szWideString == '"')
  1379. {
  1380. // If the string is inside quotes, do not use that in the comparison
  1381. szWideString++;
  1382. }
  1383. if (*szAnsiString == '"')
  1384. {
  1385. // If the string is inside quotes, do not use that in the comparison
  1386. szAnsiString++;
  1387. }
  1388. while ( *szWideString &&
  1389. *szAnsiString &&
  1390. (*szWideString == *szAnsiString)
  1391. )
  1392. {
  1393. szWideString++; // Increment 1 character (2 bytes)
  1394. szAnsiString++; // Increment 1 character (1 byte )
  1395. }
  1396. if ( ( IsTerminator ( *szWideString ) || ( *szWideString == '"' ) ) &&
  1397. ( IsTerminator ( *szAnsiString ) || ( *szAnsiString == '"' ) )
  1398. )
  1399. {
  1400. // We have made it throught the string, and all the
  1401. // chars were equal
  1402. return TRUE;
  1403. }
  1404. return FALSE;
  1405. }
  1406. // function: IsEqual
  1407. //
  1408. // Compares two unicode strings, or two ansi strings
  1409. //
  1410. // Note: This works on ANSI Strings, but will not work on DBCS
  1411. // Strings!
  1412. // Note: Termination character for this function is either a
  1413. // '\0', ' ', or '\t'
  1414. //
  1415. // Parameters:
  1416. // szString1 - String to Compare
  1417. // szString2 - String to Compare
  1418. //
  1419. // Return:
  1420. // TRUE - They are equal
  1421. // FALSE - They are not equal
  1422. BOOL
  1423. CXMLEdit::IsEqual(LPCTSTR szString1, LPCTSTR szString2)
  1424. {
  1425. if (*szString1 == '"')
  1426. {
  1427. // If the string is inside quotes, do not use that in the comparison
  1428. szString1++;
  1429. }
  1430. if (*szString2 == '"')
  1431. {
  1432. // If the string is inside quotes, do not use that in the comparison
  1433. szString2++;
  1434. }
  1435. while ( *szString1 &&
  1436. *szString2 &&
  1437. (*szString1 == *szString2)
  1438. )
  1439. {
  1440. szString1++; // Increment 1 character (2 bytes)
  1441. szString2++; // Increment 1 character (1 byte )
  1442. }
  1443. if ( ( IsTerminator ( *szString1 ) || ( *szString1 == '"' ) ) &&
  1444. ( IsTerminator ( *szString2 ) || ( *szString2 == '"' ) )
  1445. )
  1446. {
  1447. // We have made it throught the string, and all the
  1448. // chars were equal
  1449. return TRUE;
  1450. }
  1451. return FALSE;
  1452. }
  1453. // function: IsEqual
  1454. //
  1455. // Compare a LPBYTE string of type XMLFile.IsUnicode() with
  1456. // a LPTSTR
  1457. //
  1458. // Parameters:
  1459. // szGenericString - The string from our internal buffer
  1460. // szTCHARString - The string to compare with from the user
  1461. //
  1462. // Return:
  1463. // TRUE - They are the same
  1464. // FALSE - They are different
  1465. //
  1466. BOOL
  1467. CXMLEdit::IsEqual(LPBYTE szGenericString, LPCTSTR szTCHARString)
  1468. {
  1469. if ( (!szGenericString) || (!szTCHARString) )
  1470. {
  1471. // No item to compare it with
  1472. return FALSE;
  1473. }
  1474. #if defined(UNICODE) || defined(_UNICODE)
  1475. // For UNICODE, szItemName is Unicode
  1476. if ( XMLFile.IsUnicode() )
  1477. {
  1478. // Both are Unicode
  1479. return ( IsEqual( szTCHARString, (LPWSTR) szGenericString ) == 0 );
  1480. }
  1481. else
  1482. {
  1483. // szGenericString is Unicode, szCurrentItem is ANSI
  1484. return ( IsEqual( szTCHARString , (LPSTR) szGenericString ) );
  1485. }
  1486. #else
  1487. // For !UNICODE, szItemName is ANSI
  1488. if ( XMLFile.IsUnicode() )
  1489. {
  1490. // szGenericString is ANSI, szCurrentItem is Unicode
  1491. return ( IsEqual( (LPWSTR) szGenericString, szTCHARString ) );
  1492. }
  1493. else
  1494. {
  1495. // Both are ANSI
  1496. return ( IsEqual( (LPSTR) szGenericString, szTCHARString ) == 0 );
  1497. }
  1498. #endif
  1499. }
  1500. // function: IsEqualItem
  1501. //
  1502. // Compares the CurrentItem Name to the one passed in
  1503. //
  1504. // Paramters:
  1505. // szItemName - The ItemName to compare with
  1506. //
  1507. BOOL
  1508. CXMLEdit::IsEqualItem(LPCTSTR szItemName)
  1509. {
  1510. return IsEqual( GetCurrentItem(), szItemName );
  1511. }
  1512. // function: IsPropertyItem
  1513. //
  1514. // Compares the CurrentProperty Name to the one passed in
  1515. //
  1516. // Paramters:
  1517. // szItemName - The ItemName to compare with
  1518. //
  1519. BOOL
  1520. CXMLEdit::IsEqualProperty(LPCTSTR szPropertyName)
  1521. {
  1522. return IsEqual( GetCurrentProperty(), szPropertyName );
  1523. }
  1524. // function: IsEqualValue
  1525. //
  1526. // Compares the CurrentValue to the one passed in
  1527. //
  1528. // Paramters:
  1529. // szValue - The value to coompare with
  1530. //
  1531. BOOL
  1532. CXMLEdit::IsEqualValue(LPCTSTR szValue)
  1533. {
  1534. return IsEqual( GetCurrentValue(), szValue );
  1535. }
  1536. // function: CXML_Metabase_Upgrade::MethodName
  1537. //
  1538. LPTSTR
  1539. CXML_Metabase_Upgrade::GetMethodName()
  1540. {
  1541. return _T("XML_Metabase_Upgrade");
  1542. }
  1543. // function: CXML_Base::ParseFile
  1544. //
  1545. // Upgrade the XML Metabase/Schema to a format that the new
  1546. // Configuration store will be happy with, and not report
  1547. // any errors to the pesky Event Log
  1548. //
  1549. // Parameters
  1550. // szFile - The file to parse
  1551. // ciList - The parameters to use, they consist of:
  1552. // 0 - The name of the Item
  1553. // 1 - Items==2 -> New name of item | Items > 2 -> Name of Property
  1554. // 2 - Items==3 -> New name of property | Items > 3 -> Value to look for
  1555. // 3 - Items==4 -> New Value | Items > 4 -> Name of Next Property to Check
  1556. // 4 - Items==5 -> New Value for last prop | Items > 5 -> Name of the Next Value to look for
  1557. // etc.
  1558. //
  1559. // Note:
  1560. // 1) A '*' as an item name, property name, or value means to replace no matter
  1561. // what it is
  1562. // 2) A '*' for a replacement character means to remove that item/property/value
  1563. // 3) A '**' for a replacement character means to remove the whole item
  1564. //
  1565. // Return Value:
  1566. // TRUE - It worked correctly
  1567. // FALSE - It failed
  1568. BOOL
  1569. CXML_Base::ParseFile(LPTSTR szFile, CItemList &ciList)
  1570. {
  1571. CXMLEdit XMLFile;
  1572. CItemList *pList;
  1573. DWORD i;
  1574. // Create array of ItemLists
  1575. pList = new (CItemList[ciList.GetNumberOfItems()]);
  1576. if ( pList == NULL )
  1577. {
  1578. // Could not allocation memory needed for ItemList
  1579. return FALSE;
  1580. }
  1581. for (i = 0; i < ciList.GetNumberOfItems(); i++)
  1582. {
  1583. if ( ( !pList[i].LoadSubList( ciList.GetItem(i) ) ) ||
  1584. ( pList[i].GetNumberOfItems() < 2 )
  1585. )
  1586. {
  1587. // Could not load one of the items
  1588. delete [] pList;
  1589. return FALSE;
  1590. }
  1591. }
  1592. // Open the metabase, to modify it
  1593. if (!XMLFile.Open(szFile,TRUE))
  1594. {
  1595. delete [] pList;
  1596. return FALSE;
  1597. }
  1598. while (XMLFile.MovetoNextItem())
  1599. {
  1600. // Look for Item in replace list
  1601. for (i = 0; i < ciList.GetNumberOfItems(); i++)
  1602. {
  1603. // Is the item equal to this
  1604. if ( XMLFile.IsEqualItem( pList[i].GetItem(0) ) ||
  1605. ( ( *pList[i].GetItem(0) == '*' ) && ( *(pList[i].GetItem(0)+1) == '\0' ) )
  1606. )
  1607. {
  1608. if ( pList[i].GetNumberOfItems() == 2 )
  1609. {
  1610. // There is only 2 items, so the second item is the new name for the item, so replace/delete it
  1611. if ( ( *pList[i].GetItem(1) == '*' ) && ( *(pList[i].GetItem(1)+1) == '\0' ) )
  1612. {
  1613. XMLFile.DeleteItem();
  1614. }
  1615. else
  1616. {
  1617. XMLFile.ReplaceItem( pList[i].GetItem(1) );
  1618. }
  1619. }
  1620. else
  1621. {
  1622. // The item is found, check the properties...
  1623. XMLFile.MovetoFirstProperty();
  1624. do {
  1625. if ( XMLFile.IsEqualProperty( pList[i].GetItem(1) ) ||
  1626. ( ( *pList[i].GetItem(1) == '*' ) && ( *(pList[i].GetItem(1)+1) == '\0' ) )
  1627. )
  1628. {
  1629. // We have found a match of the property also
  1630. if ( pList[i].GetNumberOfItems() == 3 )
  1631. {
  1632. // There are 3 items, so replace/delete the property name with this
  1633. if ( ( *pList[i].GetItem(2) == '*' ) && ( *(pList[i].GetItem(2)+1) == '\0' ) )
  1634. {
  1635. XMLFile.DeleteProperty();
  1636. }
  1637. else if ( ( *pList[i].GetItem(2) == '*' ) && ( *(pList[i].GetItem(2)+1) == '*' ) && ( *(pList[i].GetItem(2)+2) == '\0' ) )
  1638. {
  1639. XMLFile.DeleteItem();
  1640. // Since we removed the item, we must jump out of the property checking
  1641. break;
  1642. }
  1643. else
  1644. {
  1645. XMLFile.ReplaceProperty( pList[i].GetItem(2) );
  1646. }
  1647. }
  1648. else
  1649. {
  1650. // Check value to make sure it is the same
  1651. if ( XMLFile.IsEqualValue( pList[i].GetItem(2) ) ||
  1652. ( ( *pList[i].GetItem(2) == '*' ) && ( *(pList[i].GetItem(2)+1) == '\0' ) )
  1653. )
  1654. {
  1655. DWORD dwCurrentProp = 3;
  1656. BOOL bContinue = TRUE;
  1657. while ( (pList[i].GetNumberOfItems() > (dwCurrentProp + 1) ) && ( bContinue ) )
  1658. {
  1659. XMLFile.MovetoFirstProperty();
  1660. bContinue = FALSE;
  1661. do {
  1662. // compare the current property and value
  1663. if ( ( ( ( *pList[i].GetItem(dwCurrentProp) == '*' ) && ( *(pList[i].GetItem(dwCurrentProp)+1) == '\0' ) ) || // Compare Property
  1664. XMLFile.IsEqualProperty( pList[i].GetItem(dwCurrentProp) )
  1665. ) &&
  1666. ( ( ( *pList[i].GetItem(dwCurrentProp+1) == '*' ) && ( *(pList[i].GetItem(dwCurrentProp+1)+1) == '\0' ) ) || // Compare Value
  1667. XMLFile.IsEqualValue( pList[i].GetItem(dwCurrentProp+1) )
  1668. )
  1669. )
  1670. {
  1671. // If we have found a match for both property and value, then lets continue
  1672. bContinue = TRUE;
  1673. break;
  1674. }
  1675. } while (XMLFile.MovetoNextProperty());
  1676. dwCurrentProp += 2;
  1677. }
  1678. if (bContinue)
  1679. {
  1680. // The item, property, and value are correct, so replace/delete it
  1681. if ( ( *pList[i].GetItem(dwCurrentProp) == '*' ) && ( *(pList[i].GetItem(dwCurrentProp)+1) == '\0' ) )
  1682. {
  1683. XMLFile.DeleteValue();
  1684. }
  1685. else if ( ( *pList[i].GetItem(dwCurrentProp) == '*' ) &&
  1686. ( *(pList[i].GetItem(dwCurrentProp)+1) == '*' ) &&
  1687. ( *(pList[i].GetItem(dwCurrentProp)+2) == '\0' )
  1688. )
  1689. {
  1690. XMLFile.DeleteItem();
  1691. // Since we removed the item, we must jump out of the property checking
  1692. break;
  1693. }
  1694. else
  1695. {
  1696. XMLFile.ReplaceValue( pList[i].GetItem(dwCurrentProp) );
  1697. }
  1698. }
  1699. break;
  1700. }
  1701. } // if ( pList[i]->GetNumberofItems() == 3 )
  1702. } // if ( XMLFile.IsEqualProperty( pList[i]->GetItem(1) ) ||
  1703. } while (XMLFile.MovetoNextProperty());
  1704. } // if ( pList[i]->GetNumberofItems() == 2 )
  1705. } // if ( XMLFile.IsEqualItem( pList[i]->GetItem(0) ) ||
  1706. } // for (i = 0; i < ciList.GetNumberOfItems(); i++)
  1707. } // while (XMLFile.MovetoNextItem())
  1708. XMLFile.Close();
  1709. delete [] pList;
  1710. return TRUE;
  1711. }
  1712. // function: CXML_Metabase_Upgrade::DoInternalWork
  1713. //
  1714. // Upgrade the XML Metabase to a format that the new
  1715. // Configuration store will be happy with, and not report
  1716. // any errors to the pesky Event Log
  1717. //
  1718. // Return Value:
  1719. // TRUE - It worked correctly
  1720. // FALSE - It failed
  1721. //
  1722. BOOL
  1723. CXML_Metabase_Upgrade::DoInternalWork(CItemList &ciList)
  1724. {
  1725. TSTR strMetabasePath;
  1726. if ( !GetMetabasePath( &strMetabasePath ) )
  1727. {
  1728. return FALSE;
  1729. }
  1730. return ParseFile( strMetabasePath.QueryStr() , ciList);
  1731. }
  1732. // function: CXML_MBSchema_Upgrade::DoInternalWork
  1733. //
  1734. // Upgrade the XML MBSchema to a format that the new
  1735. // Configuration store will be happy with, and not report
  1736. // any errors to the pesky Event Log
  1737. //
  1738. // Return Value:
  1739. // TRUE - It worked correctly
  1740. // FALSE - It failed
  1741. //
  1742. BOOL
  1743. CXML_MBSchema_Upgrade::DoInternalWork(CItemList &ciList)
  1744. {
  1745. TSTR strMBSchemaPath;
  1746. if ( !GetSchemaPath( &strMBSchemaPath ) )
  1747. {
  1748. return FALSE;
  1749. }
  1750. return ParseFile( strMBSchemaPath.QueryStr() , ciList);
  1751. }
  1752. // function: CXML_MBSchema_Upgrade::MethodName
  1753. //
  1754. LPTSTR
  1755. CXML_MBSchema_Upgrade::GetMethodName()
  1756. {
  1757. return _T("XML_MBSchema_Upgrade");
  1758. }
  1759. // function: GetMetabasePath
  1760. //
  1761. // Retrieve the path to the metabase
  1762. //
  1763. // Parameters
  1764. // pstrPath - [OUT] The complete path to the metabase. (assumed to be og
  1765. // _MAX_PATH size)
  1766. BOOL
  1767. CXML_Base::GetMetabasePath(TSTR *pstrPath)
  1768. {
  1769. DWORD dwReturn;
  1770. if ( !pstrPath->Resize( MAX_PATH ) )
  1771. {
  1772. return FALSE;
  1773. }
  1774. dwReturn = GetSystemDirectory( pstrPath->QueryStr(), pstrPath->QuerySize() );
  1775. if ( ( dwReturn == 0 ) ||
  1776. ( dwReturn > pstrPath->QuerySize() )
  1777. )
  1778. {
  1779. // Function failed, or path was too long to append filename
  1780. return FALSE;
  1781. }
  1782. if ( !pstrPath->Append( CXMLBASE_METABASEPATH ) )
  1783. {
  1784. return FALSE;
  1785. }
  1786. return TRUE;
  1787. }
  1788. // function: GetSchemaPath
  1789. //
  1790. // Retrieve the path to the metabase schema
  1791. //
  1792. // Parameters
  1793. // pstrPath - [OUT] The complete path to the metabase. (assumed to be og
  1794. // _MAX_PATH size)
  1795. BOOL
  1796. CXML_Base::GetSchemaPath(TSTR *pstrPath)
  1797. {
  1798. DWORD dwReturn;
  1799. if ( !pstrPath->Resize( MAX_PATH ) )
  1800. {
  1801. return FALSE;
  1802. }
  1803. dwReturn = GetSystemDirectory( pstrPath->QueryStr(), pstrPath->QuerySize() );
  1804. if ( ( dwReturn == 0 ) ||
  1805. ( dwReturn > pstrPath->QuerySize() )
  1806. )
  1807. {
  1808. // Function failed, or path was too long to append filename
  1809. return FALSE;
  1810. }
  1811. if ( !pstrPath->Append( CXMLBASE_MBSCHEMAPATH ) )
  1812. {
  1813. return FALSE;
  1814. }
  1815. return TRUE;
  1816. }
  1817. // function: GetMethodName
  1818. //
  1819. // Return the method name for this class
  1820. LPTSTR
  1821. CXML_Metabase_VerifyVersion::GetMethodName()
  1822. {
  1823. return ( _T("XML_Metabase_VerifyVersion") );
  1824. }
  1825. // function: GetMethodName
  1826. //
  1827. // Return the method name for this class
  1828. LPTSTR
  1829. CXML_MBSchema_VerifyVersion::GetMethodName()
  1830. {
  1831. return ( _T("XML_MBSchema_VerifyVersion") );
  1832. }
  1833. // function: VerifyParameters:
  1834. //
  1835. // Verify that the parameters are correct fo VerifyVersion
  1836. BOOL
  1837. CXML_Metabase_VerifyVersion::VerifyParameters(CItemList &ciParams)
  1838. {
  1839. if ( ( ciParams.GetNumberOfItems() == 2 ) &&
  1840. ciParams.IsNumber(0) &&
  1841. ciParams.IsNumber(1)
  1842. )
  1843. {
  1844. return TRUE;
  1845. }
  1846. return FALSE;
  1847. }
  1848. // function: VerifyParameters:
  1849. //
  1850. // Verify that the parameters are correct fo VerifyVersion
  1851. BOOL
  1852. CXML_MBSchema_VerifyVersion::VerifyParameters(CItemList &ciParams)
  1853. {
  1854. if ( ( ciParams.GetNumberOfItems() == 2 ) &&
  1855. ciParams.IsNumber(0) &&
  1856. ciParams.IsNumber(1)
  1857. )
  1858. {
  1859. return TRUE;
  1860. }
  1861. return FALSE;
  1862. }
  1863. // function: IsFileWithinVersion
  1864. //
  1865. // Verify the a file is with a certain version. This is done by paring the xml of the file,
  1866. // extrapulation the verion, and making sure it is withing the bounds
  1867. //
  1868. // Parameters
  1869. // szFileName - The name of the xml file
  1870. // szItemName - The name of the item to search for
  1871. // szPropName - The name of the property that contains the version
  1872. // dwMinVer - The minimum version for it to return true
  1873. // dwMaxVer - The maximum version for it to return true
  1874. BOOL
  1875. CXML_Base::IsFileWithinVersion(LPTSTR szFileName, LPTSTR szItemName, LPTSTR szPropName, DWORD dwMinVer, DWORD dwMaxVer)
  1876. {
  1877. CXMLEdit XMLFile;
  1878. BOOL bFound = FALSE;
  1879. BOOL bRet = FALSE;
  1880. if (!XMLFile.Open(szFileName, FALSE))
  1881. {
  1882. return FALSE;
  1883. }
  1884. while ( XMLFile.MovetoNextItem() && !bFound )
  1885. {
  1886. // Look for the configuration tag
  1887. if (XMLFile.IsEqualItem( szItemName ))
  1888. {
  1889. XMLFile.MovetoFirstProperty();
  1890. do {
  1891. // Look for the xmlns tag that mentions the version #
  1892. if (XMLFile.IsEqualProperty( szPropName ) )
  1893. {
  1894. DWORD dwVersion = XMLFile.ExtractVersion( XMLFile.GetCurrentValue() );
  1895. bFound = TRUE;
  1896. if ( ( dwMinVer >= dwMinVer ) &&
  1897. ( dwMaxVer <= dwMaxVer )
  1898. )
  1899. {
  1900. bRet = TRUE;
  1901. }
  1902. }
  1903. } while ( XMLFile.MovetoNextProperty() && !bFound );
  1904. }
  1905. }
  1906. XMLFile.Close();
  1907. return bRet;
  1908. }
  1909. // function: CXML_Metabase_VerifyVersion::DoInternalWork
  1910. //
  1911. // Verify the versions are within the bounds that are sent in, so we
  1912. // know wether we should execure the next command or not, by returning
  1913. // TRUE or FALSE
  1914. //
  1915. // Parameters:
  1916. // ciList -
  1917. // 0 -Minimum Bound
  1918. // 1- Max Bound
  1919. BOOL
  1920. CXML_Metabase_VerifyVersion::DoInternalWork(CItemList &ciList)
  1921. {
  1922. TSTR strMetabasePath;
  1923. if ( !GetMetabasePath( &strMetabasePath ) )
  1924. {
  1925. return FALSE;
  1926. }
  1927. return IsFileWithinVersion( strMetabasePath.QueryStr(), // Filename
  1928. _T("configuration"), // Item name
  1929. _T("xmlns"), // Property Name
  1930. ciList.GetNumber(0), // Min
  1931. ciList.GetNumber(1) // Max
  1932. );
  1933. }
  1934. // function: CXML_MBSchema_VerifyVersion::DoInternalWork
  1935. //
  1936. // Verify the versions are within the bounds that are sent in, so we
  1937. // know wether we should execure the next command or not, by returning
  1938. // TRUE or FALSE
  1939. //
  1940. // Parameters:
  1941. // ciList -
  1942. // 0 -Minimum Bound
  1943. // 1- Max Bound
  1944. BOOL
  1945. CXML_MBSchema_VerifyVersion::DoInternalWork(CItemList &ciList)
  1946. {
  1947. TSTR strSchemaPath;
  1948. if ( !GetSchemaPath( &strSchemaPath ) )
  1949. {
  1950. return FALSE;
  1951. }
  1952. return IsFileWithinVersion( strSchemaPath.QueryStr(), // Filename
  1953. _T("MetaData"), // Item name
  1954. _T("xmlns"), // Property Name
  1955. ciList.GetNumber(0), // Min
  1956. ciList.GetNumber(1) // Max
  1957. );
  1958. }
  1959. // function: ExtractVersion
  1960. //
  1961. // Extract the Version number out of a string extracted from the metabase
  1962. //
  1963. // Parameters
  1964. // szVersion - String version, such as "urn:microsoft-catalog:XML_Metabase_V1_0"
  1965. //
  1966. // RETURN
  1967. // A Verison #
  1968. DWORD
  1969. CXMLEdit::ExtractVersion(LPBYTE szVersion)
  1970. {
  1971. DWORD dwVer = 0;
  1972. if (!szVersion)
  1973. {
  1974. return 0;
  1975. }
  1976. while ( !IsTerminator(XMLFile.GetChar(szVersion)) )
  1977. {
  1978. if ( XMLFile.GetChar(szVersion) == '_' )
  1979. {
  1980. XMLFile.GetNextChar(szVersion);
  1981. if ( XMLFile.GetChar(szVersion) == 'V' )
  1982. {
  1983. XMLFile.GetNextChar(szVersion);
  1984. break;
  1985. }
  1986. }
  1987. else
  1988. {
  1989. XMLFile.GetNextChar(szVersion);
  1990. }
  1991. }
  1992. if (IsTerminator(XMLFile.GetChar(szVersion)) )
  1993. {
  1994. return FALSE;
  1995. }
  1996. while ( ( XMLFile.GetChar(szVersion) >= '0' ) && ( XMLFile.GetChar(szVersion) <= '9' ) )
  1997. {
  1998. dwVer = dwVer + ( XMLFile.GetChar(szVersion) - '0' );
  1999. XMLFile.GetNextChar(szVersion);
  2000. }
  2001. return dwVer;
  2002. }