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.

923 lines
21 KiB

  1. //***************************************************************************
  2. //
  3. // (c) 2000-2001 by Microsoft Corp. All Rights Reserved.
  4. //
  5. // INDEX.CPP
  6. //
  7. // 24-Oct-00 raymcc Integration layer to disk-based B-Tree
  8. //
  9. //***************************************************************************
  10. #include "precomp.h"
  11. #include <wbemcomn.h>
  12. #include <reposit.h>
  13. #include "a51tools.h"
  14. #include "index.h"
  15. #include <statsync.h>
  16. #include "btr.h"
  17. extern DWORD g_dwSecTlsIndex;
  18. //***************************************************************************
  19. //
  20. //***************************************************************************
  21. //
  22. //#define DEBUG
  23. static CLockableFlexArray<CStaticCritSec> g_aIterators;
  24. class CIteratorBatch
  25. {
  26. CFlexArray m_aStrings;
  27. BOOL m_bDone;
  28. DWORD m_dwCursor;
  29. public:
  30. CIteratorBatch();
  31. ~CIteratorBatch();
  32. BOOL Purge(LPSTR pszTarget);
  33. BOOL Add(LPSTR pszSrc); // Acquires memory
  34. void SetDone() { m_bDone = TRUE; }
  35. BOOL Next(LPSTR *pString);
  36. static DWORD PurgeAll(LPSTR pszDoomed);
  37. };
  38. //***************************************************************************
  39. //
  40. // CIteratorBatch::PurgeAll
  41. //
  42. //
  43. // Purges all iterators of a particular string. This happens when
  44. // a DeleteKey succeeds while there are outstanding enumerators; we want
  45. // to remove the key from all enumerators so that deleted objects
  46. // are not reported.
  47. //
  48. // This is required because the enumerators do "prefetch" and may
  49. // have been invoked considerably in advance of the delete
  50. //
  51. // Assumes prior concurrency control.
  52. //
  53. //***************************************************************************
  54. // ok
  55. DWORD CIteratorBatch::PurgeAll(LPSTR pszDoomed)
  56. {
  57. DWORD dwTotal = 0;
  58. g_aIterators.Lock();
  59. for (int i = 0; i < g_aIterators.Size(); i++)
  60. {
  61. CIteratorBatch *p = (CIteratorBatch *) g_aIterators[i];
  62. BOOL bRes = p->Purge(pszDoomed);
  63. if (bRes)
  64. dwTotal++;
  65. }
  66. g_aIterators.Unlock();
  67. return dwTotal;
  68. }
  69. //***************************************************************************
  70. //
  71. // CIteratorBatch::CIteratorBatch
  72. //
  73. //***************************************************************************
  74. // ok
  75. CIteratorBatch::CIteratorBatch()
  76. {
  77. m_bDone = FALSE;
  78. m_dwCursor = 0;
  79. }
  80. //***************************************************************************
  81. //
  82. // CIteratorBatch::Add
  83. //
  84. // Adds a string to the enumerator.
  85. //
  86. //***************************************************************************
  87. //
  88. BOOL CIteratorBatch::Add(LPSTR pszSrc)
  89. {
  90. if (m_aStrings.Size() == 0)
  91. {
  92. g_aIterators.Lock();
  93. int i = g_aIterators.Add(this);
  94. g_aIterators.Unlock();
  95. if (i)
  96. return FALSE;
  97. }
  98. int nRes = m_aStrings.Add(pszSrc);
  99. if (nRes)
  100. return FALSE;
  101. return TRUE;
  102. }
  103. //***************************************************************************
  104. //
  105. // CIteratorBatch::~CIteratorBatch
  106. //
  107. // Removes all remaining strings and deallocates them and removes
  108. // this iterator from the global list.
  109. //
  110. // Assumes prior concurrency control.
  111. //
  112. //***************************************************************************
  113. //
  114. CIteratorBatch::~CIteratorBatch()
  115. {
  116. for (int i = 0; i < m_aStrings.Size(); i++)
  117. {
  118. _BtrMemFree(m_aStrings[i]);
  119. }
  120. g_aIterators.Lock();
  121. for (i = 0; i < g_aIterators.Size(); i++)
  122. {
  123. if (g_aIterators[i] == this)
  124. {
  125. g_aIterators.RemoveAt(i);
  126. break;
  127. }
  128. }
  129. g_aIterators.Unlock();
  130. }
  131. //***************************************************************************
  132. //
  133. // CIteratorBatch::Purge
  134. //
  135. // Removes a specific string from the enumerator. Happens when a concurrent
  136. // delete succeeds; we have to remove the deleted key from the enumeration
  137. // for result set coherence.
  138. //
  139. // Assumes prior concurrency control.
  140. //
  141. // Returns FALSE if the string was not removed, TRUE if it was. The
  142. // return value is mostly a debugging aid.
  143. //
  144. //***************************************************************************
  145. // ok
  146. BOOL CIteratorBatch::Purge(
  147. LPSTR pszTarget
  148. )
  149. {
  150. int nSize = m_aStrings.Size();
  151. if (nSize == 0)
  152. return FALSE;
  153. // First, check the first/last strings against
  154. // the first character of the target. We can
  155. // avoid a lot of strcmp calls if the target
  156. // is lexcially outside the range of the contents of
  157. // the enumerator.
  158. // ==================================================
  159. LPSTR pszFirst = (LPSTR) m_aStrings[0];
  160. LPSTR pszLast = (LPSTR) m_aStrings[nSize-1];
  161. if (*pszTarget > *pszLast)
  162. return FALSE;
  163. if (*pszTarget < *pszFirst)
  164. return FALSE;
  165. // If here, there is a chance that we have the
  166. // string in the enumerator. Since all keys are
  167. // retrieved in lexical order, a simple binary
  168. // search is all we need.
  169. // =============================================
  170. int nPosition = 0;
  171. int l = 0, u = nSize - 1;
  172. while (l <= u)
  173. {
  174. int m = (l + u) / 2;
  175. // m is the current key to consider 0...n-1
  176. LPSTR pszCandidate = (LPSTR) m_aStrings[m];
  177. int nRes = strcmp(pszTarget, pszCandidate);
  178. // Decide which way to cut the array in half.
  179. // ==========================================
  180. if (nRes < 0)
  181. {
  182. u = m - 1;
  183. nPosition = u + 1;
  184. }
  185. else if (nRes > 0)
  186. {
  187. l = m + 1;
  188. nPosition = l;
  189. }
  190. else
  191. {
  192. // If here, we found the darn thing. Life is good.
  193. // Zap it and return!
  194. // ================================================
  195. _BtrMemFree(pszCandidate);
  196. m_aStrings.RemoveAt(m);
  197. return TRUE;
  198. }
  199. }
  200. return FALSE;
  201. }
  202. //***************************************************************************
  203. //
  204. // CIteratorBatch::Next
  205. //
  206. // Returns the next string from the enumeration prefetch.
  207. //
  208. //***************************************************************************
  209. //
  210. BOOL CIteratorBatch::Next(LPSTR *pMem)
  211. {
  212. if (m_aStrings.Size())
  213. {
  214. *pMem = (LPSTR) m_aStrings[0];
  215. m_aStrings.RemoveAt(0);
  216. return TRUE;
  217. }
  218. return FALSE;
  219. }
  220. //***************************************************************************
  221. //
  222. // CBtrIndex::CBtrIndex
  223. //
  224. //***************************************************************************
  225. //
  226. CBtrIndex::CBtrIndex()
  227. {
  228. m_dwPrefixLength = 0;
  229. }
  230. //***************************************************************************
  231. //
  232. // CBtrIndex::~CBtrIndex
  233. //
  234. //***************************************************************************
  235. //
  236. CBtrIndex::~CBtrIndex()
  237. {
  238. }
  239. long CBtrIndex::Shutdown(DWORD dwShutDownFlags)
  240. {
  241. long lRes;
  242. lRes = bt.Shutdown(dwShutDownFlags);
  243. if(lRes != ERROR_SUCCESS)
  244. return lRes;
  245. lRes = ps.Shutdown(dwShutDownFlags);
  246. if(lRes != ERROR_SUCCESS)
  247. return lRes;
  248. return ERROR_SUCCESS;
  249. }
  250. //***************************************************************************
  251. //
  252. // CBtrIndex::Initialize
  253. //
  254. //***************************************************************************
  255. //
  256. long CBtrIndex::Initialize(DWORD dwPrefixLength,
  257. LPCWSTR wszRepositoryDir,
  258. CPageSource* pSource)
  259. {
  260. // Initialize the files in question and map BTree into it.
  261. // =======================================================
  262. CFileName buf;
  263. if (buf == NULL)
  264. return ERROR_OUTOFMEMORY;
  265. StringCchCopyW(buf, buf.Length(),wszRepositoryDir);
  266. StringCchCatW(buf, buf.Length(), L"\\index.btr");
  267. DWORD dwRes = ps.Init(8192, buf, pSource);
  268. dwRes |= bt.Init(&ps);
  269. m_dwPrefixLength = dwPrefixLength;
  270. return long(dwRes);
  271. }
  272. //***************************************************************************
  273. //
  274. // CBtrIndex::Create
  275. //
  276. //***************************************************************************
  277. //
  278. long CBtrIndex::Create(LPCWSTR wszFileName)
  279. {
  280. DWORD dwRes;
  281. if (wszFileName == 0)
  282. return ERROR_INVALID_PARAMETER;
  283. wszFileName += m_dwPrefixLength;
  284. // Convert to ANSI
  285. // ================
  286. char *pAnsi = new char[wcslen(wszFileName) + 1];
  287. if (pAnsi == 0)
  288. return ERROR_NOT_ENOUGH_MEMORY;
  289. LPCWSTR pSrc = wszFileName;
  290. char *pDest = pAnsi;
  291. while (*pSrc)
  292. *pDest++ = (char) *pSrc++;
  293. *pDest = 0;
  294. try
  295. {
  296. dwRes = bt.InsertKey(pAnsi, 0);
  297. }
  298. catch (CX_MemoryException &)
  299. {
  300. dwRes = ERROR_OUTOFMEMORY;
  301. }
  302. delete [] pAnsi;
  303. if (dwRes == ERROR_ALREADY_EXISTS)
  304. dwRes = NO_ERROR;
  305. return long(dwRes);
  306. }
  307. //***************************************************************************
  308. //
  309. // CBtrIndex::Delete
  310. //
  311. // Deletes a key from the index
  312. //
  313. //***************************************************************************
  314. //
  315. long CBtrIndex::Delete(LPCWSTR wszFileName)
  316. {
  317. DWORD dwRes = 0;
  318. wszFileName += m_dwPrefixLength;
  319. // Convert to ANSI
  320. // ================
  321. char *pAnsi = new char[wcslen(wszFileName) + 1];
  322. if (pAnsi == 0)
  323. return ERROR_NOT_ENOUGH_MEMORY;
  324. LPCWSTR pSrc = wszFileName;
  325. char *pDest = pAnsi;
  326. while (*pSrc)
  327. *pDest++ = (char) *pSrc++;
  328. *pDest = 0;
  329. try
  330. {
  331. dwRes = bt.DeleteKey(pAnsi);
  332. if (dwRes == 0)
  333. CIteratorBatch::PurgeAll(pAnsi);
  334. }
  335. catch (CX_MemoryException &)
  336. {
  337. dwRes = ERROR_OUTOFMEMORY;
  338. }
  339. delete pAnsi;
  340. return long(dwRes);
  341. }
  342. //***************************************************************************
  343. //
  344. // CBtrIndex::CopyStringToWIN32_FIND_DATA
  345. //
  346. // Does an ANSI to UNICODE convert for the key string.
  347. //
  348. //***************************************************************************
  349. //
  350. BOOL CBtrIndex::CopyStringToWIN32_FIND_DATA(
  351. LPSTR pszKey,
  352. LPWSTR pszDest,
  353. bool bCopyFullPath
  354. )
  355. {
  356. LPSTR pszSuffix;
  357. if ( bCopyFullPath)
  358. {
  359. pszSuffix = pszKey;
  360. }
  361. else
  362. {
  363. pszSuffix = pszKey + strlen(pszKey) - 1;
  364. while (pszSuffix[-1] != '\\' && pszSuffix > pszKey)
  365. {
  366. pszSuffix--;
  367. }
  368. }
  369. // If here, a clean match.
  370. // =======================
  371. while (*pszSuffix)
  372. *pszDest++ = (wchar_t) *pszSuffix++;
  373. *pszDest = 0;
  374. return TRUE;
  375. }
  376. //***************************************************************************
  377. //
  378. // CBtrIndex::FindFirst
  379. //
  380. // Starts an enumeration
  381. //
  382. //***************************************************************************
  383. //
  384. long CBtrIndex::FindFirst(LPCWSTR wszPrefix, WIN32_FIND_DATAW* pfd,
  385. void** ppHandle)
  386. {
  387. BOOL bExclude = FALSE;
  388. if (TlsGetValue(g_dwSecTlsIndex))
  389. {
  390. WCHAR pCompare[] = L"KI_644C0907A53790A09D448C09530D58E6\\I_18BA379108CD7CCC2FA0FD754AD45A25";
  391. DWORD dwLenCompare = sizeof(pCompare)/sizeof(WCHAR) - 1;
  392. WCHAR * pEndCompare = pCompare + (dwLenCompare -1);
  393. DWORD dwLen = wcslen(wszPrefix);
  394. WCHAR * pEnd = (WCHAR *)wszPrefix+ (dwLen-1);
  395. do
  396. {
  397. if (*pEndCompare != *pEnd)
  398. break;
  399. else
  400. {
  401. pEndCompare--;
  402. pEnd--;
  403. }
  404. } while ((pCompare-1) != pEndCompare);
  405. if ((pCompare-1) == pEndCompare)
  406. {
  407. //OutputDebugStringA("Findfirst for __thisnamespace=@ called\n");
  408. bExclude = TRUE;
  409. }
  410. }
  411. DWORD dwRes;
  412. wszPrefix += m_dwPrefixLength;
  413. if(ppHandle)
  414. *ppHandle = INVALID_HANDLE_VALUE;
  415. pfd->cFileName[0] = 0;
  416. pfd->dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
  417. // Convert to ANSI
  418. // ================
  419. char *pAnsi = new char[wcslen(wszPrefix) + 1];
  420. if (pAnsi == 0)
  421. {
  422. return ERROR_NOT_ENOUGH_MEMORY;
  423. }
  424. CVectorDeleteMe<char> vdm(pAnsi);
  425. LPCWSTR pSrc = wszPrefix;
  426. char *pDest = pAnsi;
  427. while (*pSrc)
  428. *pDest++ = (char) *pSrc++;
  429. *pDest = 0;
  430. // Critical-section blocked.
  431. // =========================
  432. CBTreeIterator *pIt = new CBTreeIterator;
  433. if (!pIt)
  434. {
  435. return ERROR_NOT_ENOUGH_MEMORY;
  436. }
  437. try
  438. {
  439. dwRes = pIt->Init(&bt, pAnsi);
  440. }
  441. catch (CX_MemoryException &)
  442. {
  443. dwRes = ERROR_OUTOFMEMORY;
  444. }
  445. if (dwRes)
  446. {
  447. pIt->Release();
  448. return dwRes;
  449. }
  450. // Create CIteratorBatch.
  451. // ======================
  452. CIteratorBatch *pBatch = new CIteratorBatch;
  453. if (pBatch == 0)
  454. {
  455. pIt->Release();
  456. return ERROR_NOT_ENOUGH_MEMORY;
  457. }
  458. // Iterate and fill batcher.
  459. // =========================
  460. LPSTR pszKey = 0;
  461. int nMatchLen = strlen(pAnsi);
  462. long lRes = 0;
  463. for (;;)
  464. {
  465. lRes = pIt->Next(&pszKey);
  466. if (lRes == ERROR_NO_MORE_ITEMS)
  467. {
  468. //We hit the end of the BTree result set, so we need to ignore this error
  469. lRes = 0;
  470. break;
  471. }
  472. //If we hit an error we quit the loop
  473. if (lRes)
  474. break;
  475. // See if prefix matches.
  476. if (strncmp(pAnsi, pszKey, nMatchLen) != 0 || bExclude)
  477. {
  478. pIt->FreeString(pszKey);
  479. pBatch->SetDone();
  480. break;
  481. }
  482. if (!pBatch->Add(pszKey))
  483. {
  484. lRes = ERROR_OUTOFMEMORY;
  485. break;
  486. }
  487. if (ppHandle == NULL)
  488. break; //Only asked for 1 item! No need to try the next
  489. }
  490. pIt->Release();
  491. if (lRes == NO_ERROR)
  492. lRes = FindNext(pBatch, pfd);
  493. if (lRes == ERROR_NO_MORE_FILES)
  494. lRes = ERROR_FILE_NOT_FOUND;
  495. if (lRes == NO_ERROR)
  496. {
  497. if(ppHandle)
  498. {
  499. *ppHandle = (LPVOID *) pBatch;
  500. }
  501. else
  502. {
  503. //
  504. // Only asked for one --- close handle
  505. //
  506. delete pBatch;
  507. }
  508. }
  509. else
  510. {
  511. delete pBatch;
  512. }
  513. return lRes;
  514. }
  515. //***************************************************************************
  516. //
  517. // CBtrIndex::FindNext
  518. //
  519. // Continues an enumeration. Reads from the prefetch buffer.
  520. //
  521. //***************************************************************************
  522. //
  523. long CBtrIndex::FindNext(void* pHandle, WIN32_FIND_DATAW* pfd)
  524. {
  525. LPSTR pszString = 0;
  526. BOOL bRes;
  527. if (pHandle == 0 || pfd == 0 || pHandle == INVALID_HANDLE_VALUE)
  528. return ERROR_INVALID_PARAMETER;
  529. CIteratorBatch *pBatch = (CIteratorBatch *) pHandle;
  530. bRes = pBatch->Next(&pszString);
  531. if (bRes == FALSE)
  532. return ERROR_NO_MORE_FILES;
  533. CopyStringToWIN32_FIND_DATA(pszString, pfd->cFileName);
  534. pfd->dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
  535. if (pszString)
  536. _BtrMemFree(pszString);
  537. return ERROR_SUCCESS;
  538. }
  539. //***************************************************************************
  540. //
  541. // CBtrIndex::FindClose
  542. //
  543. // Closes an enumeration by deleting the 'hidden' pointer.
  544. //
  545. //***************************************************************************
  546. // ok
  547. long CBtrIndex::FindClose(void* pHandle)
  548. {
  549. if (pHandle == 0 || pHandle == INVALID_HANDLE_VALUE)
  550. return NO_ERROR;
  551. delete (CIteratorBatch *) pHandle;
  552. return ERROR_SUCCESS;
  553. }
  554. long CBtrIndex::InvalidateCache()
  555. {
  556. //
  557. // Re-read the admin page from disk. NOTE: this will need changing if more
  558. // caching is added!
  559. //
  560. DWORD dwRes = ps.ReadAdminPage();
  561. if (dwRes == NO_ERROR)
  562. dwRes = bt.InvalidateCache();
  563. return long(dwRes);
  564. }
  565. long CBtrIndex::FlushCaches()
  566. {
  567. return bt.FlushCaches();
  568. }
  569. long CBtrIndex::IndexEnumerationBegin(const wchar_t *wszSearchPrefix, void **ppHandle)
  570. {
  571. BOOL bExclude = FALSE;
  572. if (TlsGetValue(g_dwSecTlsIndex))
  573. {
  574. WCHAR pCompare[] = L"CI_644C0907A53790A09D448C09530D58E6";
  575. DWORD dwLenCompare = sizeof(pCompare)/sizeof(WCHAR) - 1;
  576. WCHAR * pEndCompare = pCompare + (dwLenCompare -1);
  577. DWORD dwLen = wcslen(wszSearchPrefix);
  578. WCHAR * pEnd = (WCHAR *)wszSearchPrefix+ (dwLen-1);
  579. while (*pEnd != L'\\') pEnd--;
  580. pEnd--;
  581. do
  582. {
  583. if (*pEndCompare != *pEnd)
  584. break;
  585. else
  586. {
  587. pEndCompare--;
  588. pEnd--;
  589. }
  590. } while ((pCompare-1) != pEndCompare);
  591. if ((pCompare-1) == pEndCompare)
  592. {
  593. //OutputDebugStringA("IndexEnumerationBegin for __thisnamespace called\n");
  594. bExclude = TRUE;
  595. }
  596. }
  597. DWORD dwRes = ERROR_SUCCESS;
  598. wszSearchPrefix += m_dwPrefixLength;
  599. if(ppHandle)
  600. *ppHandle = INVALID_HANDLE_VALUE;
  601. // Convert to ANSI
  602. // ================
  603. char *pAnsi = new char[wcslen(wszSearchPrefix) + 1];
  604. if (pAnsi == 0)
  605. {
  606. return ERROR_NOT_ENOUGH_MEMORY;
  607. }
  608. CVectorDeleteMe<char> vdm(pAnsi);
  609. LPCWSTR pSrc = wszSearchPrefix;
  610. char *pDest = pAnsi;
  611. while (*pSrc)
  612. *pDest++ = (char) *pSrc++;
  613. *pDest = 0;
  614. CBTreeIterator *pIt = new CBTreeIterator;
  615. if (!pIt)
  616. {
  617. return ERROR_NOT_ENOUGH_MEMORY;
  618. }
  619. try
  620. {
  621. dwRes = pIt->Init(&bt, pAnsi);
  622. }
  623. catch (CX_MemoryException &)
  624. {
  625. dwRes = ERROR_OUTOFMEMORY;
  626. }
  627. if (dwRes)
  628. {
  629. pIt->Release();
  630. return dwRes;
  631. }
  632. // Create CIteratorBatch.
  633. // ======================
  634. CIteratorBatch *pBatch = new CIteratorBatch;
  635. if (pBatch == 0)
  636. {
  637. pIt->Release();
  638. return ERROR_NOT_ENOUGH_MEMORY;
  639. }
  640. // Iterate and fill batcher.
  641. // =========================
  642. LPSTR pszKey = 0;
  643. int nMatchLen = strlen(pAnsi);
  644. for (int nCount = 0;;nCount++)
  645. {
  646. dwRes = pIt->Next(&pszKey);
  647. if (dwRes == ERROR_NO_MORE_ITEMS)
  648. {
  649. //We hit the end of the BTree result set, so we need to ignore this error
  650. dwRes = 0;
  651. break;
  652. }
  653. //If we hit an error we quit the loop
  654. if (dwRes)
  655. break;
  656. // See if prefix matches.
  657. if (strncmp(pAnsi, pszKey, nMatchLen) != 0 || bExclude)
  658. {
  659. pIt->FreeString(pszKey);
  660. pBatch->SetDone();
  661. break;
  662. }
  663. if (!pBatch->Add(pszKey))
  664. {
  665. dwRes = ERROR_OUTOFMEMORY;
  666. break;
  667. }
  668. }
  669. pIt->Release();
  670. if ((nCount == 0) && (dwRes == ERROR_SUCCESS))
  671. dwRes = ERROR_FILE_NOT_FOUND;
  672. if (dwRes == ERROR_SUCCESS)
  673. {
  674. if(ppHandle)
  675. {
  676. *ppHandle = (LPVOID *) pBatch;
  677. }
  678. else
  679. delete pBatch;
  680. }
  681. else
  682. delete pBatch;
  683. return dwRes;
  684. }
  685. long CBtrIndex::IndexEnumerationEnd(void *pHandle)
  686. {
  687. if (pHandle != INVALID_HANDLE_VALUE)
  688. delete (CIteratorBatch *) pHandle;
  689. return ERROR_SUCCESS;
  690. }
  691. long CBtrIndex::IndexEnumerationNext(void *pHandle, CFileName &wszFileName, bool bCopyFullPath)
  692. {
  693. LPSTR pszString = 0;
  694. BOOL bRes;
  695. if (pHandle == 0 || pHandle == INVALID_HANDLE_VALUE)
  696. return ERROR_INVALID_PARAMETER;
  697. CIteratorBatch *pBatch = (CIteratorBatch *) pHandle;
  698. bRes = pBatch->Next(&pszString);
  699. if (bRes == FALSE)
  700. return ERROR_NO_MORE_FILES;
  701. CopyStringToWIN32_FIND_DATA(pszString, wszFileName, bCopyFullPath);
  702. if (pszString)
  703. _BtrMemFree(pszString);
  704. return ERROR_SUCCESS;
  705. }
  706. //======================================================
  707. //
  708. // CBtrIndex::ReadNextIndex
  709. //
  710. // Description:
  711. //
  712. // Parameters:
  713. //
  714. // Returns:
  715. // ERROR_SUCCESS Success
  716. // ERROR_NO_MORE_ITEMS No more items
  717. // other errors as necessary
  718. //======================================================
  719. long CBtrIndex::ReadNextIndex(const wchar_t *wszSearch, CFileName &wszNextIndex)
  720. {
  721. DWORD dwRes = ERROR_SUCCESS;
  722. //Current usage doesn't need the prefix. If someone does in the future
  723. //you're going to have to add a flag to make this work!
  724. // wszSearch += m_dwPrefixLength;
  725. // Convert to ANSI
  726. char *pAnsi = new char[wcslen(wszSearch) + 1];
  727. if (pAnsi == 0)
  728. return ERROR_OUTOFMEMORY;
  729. CVectorDeleteMe<char> vdm(pAnsi);
  730. const wchar_t *pSrc = wszSearch;
  731. char *pDest = pAnsi;
  732. while (*pSrc)
  733. *pDest++ = (char) *pSrc++;
  734. *pDest = 0;
  735. CBTreeIterator *pIt = new CBTreeIterator;
  736. if (!pIt)
  737. return ERROR_OUTOFMEMORY;
  738. CTemplateReleaseMe<CBTreeIterator> rm(pIt);
  739. try
  740. {
  741. dwRes = pIt->Init(&bt, pAnsi);
  742. }
  743. catch (CX_MemoryException &)
  744. {
  745. dwRes = ERROR_OUTOFMEMORY;
  746. }
  747. if (dwRes)
  748. return dwRes;
  749. char *pszKey = 0;
  750. dwRes = pIt->Next(&pszKey);
  751. if (dwRes == 0)
  752. {
  753. //Copy result to out parameter
  754. wchar_t *pDest = wszNextIndex;
  755. char *pSrc= pszKey;
  756. while (*pSrc)
  757. *pDest++ = (wchar_t) *pSrc++;
  758. *pDest = 0;
  759. //delete the string
  760. pIt->FreeString(pszKey);
  761. }
  762. return dwRes;
  763. }