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.

761 lines
20 KiB

  1. //---------------------------------------------------------------------------
  2. //
  3. // Copyright (c) Microsoft Corporation 1993-1994
  4. //
  5. // File: atoms.c
  6. //
  7. // This files contains the atom list code.
  8. //
  9. // History:
  10. // 01-31-94 ScottH Moved from cache.c
  11. //
  12. //---------------------------------------------------------------------------
  13. ///////////////////////////////////////////////////// INCLUDES
  14. #include "brfprv.h" // common headers
  15. ///////////////////////////////////////////////////// TYPEDEFS
  16. typedef struct tagA_ITEM
  17. {
  18. int atom; // index into hdsa
  19. LPTSTR psz; // allocated
  20. UINT ucRef;
  21. } A_ITEM; // item for atom table
  22. typedef struct tagATOMTABLE
  23. {
  24. CRITICAL_SECTION cs;
  25. HDSA hdsa; // Actual list of A_ITEMs
  26. HDPA hdpa; // List into hdsa (sorted). Values are indexes, not pointers
  27. HDPA hdpaFree; // Free list. Values are indexes, not pointers.
  28. } ATOMTABLE;
  29. #define Atom_EnterCS(this) EnterCriticalSection(&(this)->cs)
  30. #define Atom_LeaveCS(this) LeaveCriticalSection(&(this)->cs)
  31. #define ATOM_GROW 32
  32. #define Cache_Bogus(this) (!(this)->hdpa || !(this)->hdpaFree || !(this)->hdsa)
  33. // Given an index into the DPA, get the pointer to the DSA
  34. //
  35. #define MyGetPtr(this, idpa) DSA_GetItemPtr((this)->hdsa, PtrToUlong(DPA_FastGetPtr((this)->hdpa, idpa)))
  36. ///////////////////////////////////////////////////// MODULE DATA
  37. static ATOMTABLE s_atomtable;
  38. #ifdef DEBUG
  39. /*----------------------------------------------------------
  40. Purpose: Validates the given atom is within the atomtable's range
  41. Returns: --
  42. Cond: --
  43. */
  44. void PUBLIC Atom_ValidateFn(
  45. int atom)
  46. {
  47. ATOMTABLE * this = &s_atomtable;
  48. BOOL bError = FALSE;
  49. Atom_EnterCS(this);
  50. {
  51. if (atom >= DSA_GetItemCount(this->hdsa) ||
  52. atom < 0)
  53. {
  54. bError = TRUE;
  55. }
  56. }
  57. Atom_LeaveCS(this);
  58. if (bError)
  59. {
  60. // This is a problem!
  61. //
  62. DEBUG_MSG(TF_ERROR, TEXT("err BRIEFCASE: atom %d is out of range!"), atom);
  63. DEBUG_BREAK(BF_ONVALIDATE);
  64. }
  65. }
  66. /*----------------------------------------------------------
  67. Purpose: Dump the table contents
  68. Returns: --
  69. Cond: For debugging purposes
  70. */
  71. void PUBLIC Atom_DumpAll()
  72. {
  73. ATOMTABLE * this = &s_atomtable;
  74. Atom_EnterCS(this);
  75. {
  76. if (IsFlagSet(g_uDumpFlags, DF_ATOMS))
  77. {
  78. A_ITEM * pitem;
  79. int idpa;
  80. int cItem;
  81. ASSERT(this);
  82. ASSERT(this->hdsa != NULL);
  83. cItem = DPA_GetPtrCount(this->hdpa);
  84. for (idpa = 0; idpa < cItem; idpa++)
  85. {
  86. pitem = MyGetPtr(this, idpa);
  87. // The zero'th entry is reserved, so skip it
  88. if (pitem->atom == 0)
  89. continue;
  90. TRACE_MSG(TF_ALWAYS, TEXT("ATOM: Atom %d [%u]: %s"),
  91. pitem->atom, pitem->ucRef, pitem->psz);
  92. }
  93. }
  94. }
  95. Atom_LeaveCS(this);
  96. }
  97. #endif
  98. /*----------------------------------------------------------
  99. Purpose: Compare A_ITEMs
  100. Returns: -1 if <, 0 if ==, 1 if >
  101. Cond: --
  102. */
  103. int CALLBACK _export Atom_CompareIndexes(
  104. LPVOID lpv1,
  105. LPVOID lpv2,
  106. LPARAM lParam)
  107. {
  108. int i1 = PtrToUlong(lpv1);
  109. int i2 = PtrToUlong(lpv2);
  110. HDSA hdsa = (HDSA)lParam;
  111. A_ITEM * pitem1 = DSA_GetItemPtr(hdsa, i1);
  112. A_ITEM * pitem2 = DSA_GetItemPtr(hdsa, i2);
  113. ASSERT(pitem1);
  114. ASSERT(pitem2);
  115. return lstrcmpi(pitem1->psz, pitem2->psz);
  116. }
  117. /*----------------------------------------------------------
  118. Purpose: Compare A_ITEMs
  119. Returns: -1 if <, 0 if ==, 1 if >
  120. Cond: --
  121. */
  122. int CALLBACK _export Atom_Compare(
  123. LPVOID lpv1,
  124. LPVOID lpv2,
  125. LPARAM lParam)
  126. {
  127. // HACK: we know the first param is the address to a struct
  128. // that contains the search criteria. The second is an index
  129. // into the DSA.
  130. //
  131. int i2 = PtrToUlong(lpv2);
  132. HDSA hdsa = (HDSA)lParam;
  133. A_ITEM * pitem1 = (A_ITEM *)lpv1;
  134. A_ITEM * pitem2 = DSA_GetItemPtr(hdsa, i2);
  135. ASSERT(pitem1);
  136. ASSERT(pitem2);
  137. return lstrcmpi(pitem1->psz, pitem2->psz);
  138. }
  139. /*----------------------------------------------------------
  140. Purpose: Initialize the atom table
  141. Returns: TRUE on success
  142. Cond: --
  143. */
  144. BOOL PUBLIC Atom_Init()
  145. {
  146. BOOL bRet;
  147. ATOMTABLE * this = &s_atomtable;
  148. ASSERT(this);
  149. ZeroInit(this, ATOMTABLE);
  150. bRet = InitializeCriticalSectionAndSpinCount(&this->cs, 0);
  151. if (bRet)
  152. {
  153. Atom_EnterCS(this);
  154. {
  155. if ((this->hdsa = DSA_Create(sizeof(A_ITEM), ATOM_GROW)) != NULL)
  156. {
  157. if ((this->hdpa = DPA_Create(ATOM_GROW)) == NULL)
  158. {
  159. DSA_Destroy(this->hdsa);
  160. this->hdsa = NULL;
  161. }
  162. else
  163. {
  164. if ((this->hdpaFree = DPA_Create(ATOM_GROW)) == NULL)
  165. {
  166. DPA_Destroy(this->hdpa);
  167. DSA_Destroy(this->hdsa);
  168. this->hdpa = NULL;
  169. this->hdsa = NULL;
  170. }
  171. else
  172. {
  173. // We've successfully initialized. Keep the zero'th
  174. // atom reserved. This way null atoms will not accidentally
  175. // munge data.
  176. //
  177. int atom = Atom_Add(TEXT("SHDD"));
  178. ASSERT(atom == 0);
  179. }
  180. }
  181. }
  182. bRet = this->hdsa != NULL;
  183. }
  184. Atom_LeaveCS(this);
  185. }
  186. return bRet;
  187. }
  188. /*----------------------------------------------------------
  189. Purpose: Destroy the atom table
  190. Returns: --
  191. Cond: --
  192. */
  193. void PUBLIC Atom_Term()
  194. {
  195. ATOMTABLE * this = &s_atomtable;
  196. Atom_EnterCS(this);
  197. {
  198. if (this->hdpa != NULL)
  199. {
  200. A_ITEM * pitem;
  201. int idpa;
  202. int cItem;
  203. ASSERT(this->hdsa != NULL);
  204. cItem = DPA_GetPtrCount(this->hdpa);
  205. for (idpa = 0; idpa < cItem; idpa++)
  206. {
  207. pitem = MyGetPtr(this, idpa);
  208. // The zero'th entry is reserved, so skip it
  209. if (pitem->atom == 0)
  210. continue;
  211. Str_SetPtr(&pitem->psz, NULL);
  212. }
  213. DPA_Destroy(this->hdpa);
  214. this->hdpa = NULL;
  215. }
  216. if (this->hdpaFree != NULL)
  217. {
  218. DPA_Destroy(this->hdpaFree);
  219. this->hdpaFree = NULL;
  220. }
  221. if (this->hdsa != NULL)
  222. {
  223. DSA_Destroy(this->hdsa);
  224. this->hdsa = NULL;
  225. }
  226. }
  227. Atom_LeaveCS(this);
  228. DeleteCriticalSection(&this->cs);
  229. }
  230. /*----------------------------------------------------------
  231. Purpose: Add a string to the atom table. If the string already
  232. exists, return its atom.
  233. Returns: Atom
  234. ATOM_ERR on failure
  235. Cond: Reference count is incremented always
  236. */
  237. int PUBLIC Atom_Add(
  238. LPCTSTR psz)
  239. {
  240. ATOMTABLE * this = &s_atomtable;
  241. A_ITEM * pitem = NULL;
  242. A_ITEM item;
  243. int atomRet = ATOM_ERR;
  244. int idpa;
  245. int cItem;
  246. int cFree;
  247. ASSERT(psz);
  248. Atom_EnterCS(this);
  249. {
  250. int iItem;
  251. DEBUG_CODE( iItem = -1; )
  252. // Search for the string in the atom table first.
  253. // If we find it, return the atom.
  254. //
  255. item.psz = (LPTSTR)(LPVOID)psz;
  256. idpa = DPA_Search(this->hdpa, &item, 0, Atom_Compare, (LPARAM)this->hdsa, DPAS_SORTED);
  257. if (idpa != -1)
  258. {
  259. // String is already in table
  260. //
  261. pitem = MyGetPtr(this, idpa);
  262. pitem->ucRef++;
  263. atomRet = pitem->atom;
  264. ASSERT(IsSzEqual(psz, pitem->psz));
  265. VALIDATE_ATOM(pitem->atom);
  266. }
  267. else
  268. {
  269. // Add the string to the table. Take any available entry
  270. // from the free list first. Otherwise allocate more space
  271. // in the table. Then add a ptr to the sorted ptr list.
  272. //
  273. cFree = DPA_GetPtrCount(this->hdpaFree);
  274. if (cFree > 0)
  275. {
  276. // Use a free entry
  277. //
  278. cFree--;
  279. iItem = PtrToUlong(DPA_DeletePtr(this->hdpaFree, cFree));
  280. pitem = DSA_GetItemPtr(this->hdsa, iItem);
  281. // atom field for pitem should already be set
  282. VALIDATE_ATOM(pitem->atom);
  283. }
  284. else
  285. {
  286. // Allocate a new entry. item has bogus data in it.
  287. // That's okay, we fill in good stuff below.
  288. //
  289. cItem = DSA_GetItemCount(this->hdsa);
  290. if ((iItem = DSA_InsertItem(this->hdsa, cItem+1, &item)) != -1)
  291. {
  292. pitem = DSA_GetItemPtr(this->hdsa, iItem);
  293. pitem->atom = iItem;
  294. VALIDATE_ATOM(pitem->atom);
  295. }
  296. }
  297. // Fill in the info
  298. //
  299. if (pitem)
  300. {
  301. pitem->ucRef = 1;
  302. pitem->psz = 0;
  303. if (!Str_SetPtr(&pitem->psz, psz))
  304. goto Add_Fail;
  305. // Add the new entry to the ptr list and sort
  306. //
  307. cItem = DPA_GetPtrCount(this->hdpa);
  308. if (DPA_InsertPtr(this->hdpa, cItem+1, IntToPtr(iItem)) == -1)
  309. goto Add_Fail;
  310. DPA_Sort(this->hdpa, Atom_CompareIndexes, (LPARAM)this->hdsa);
  311. atomRet = pitem->atom;
  312. TRACE_MSG(TF_ATOM, TEXT("ATOM Adding %d [%u]: %s"), atomRet, pitem->ucRef, pitem->psz);
  313. }
  314. }
  315. Add_Fail:
  316. // Add the entry to the free list and fail. If even this fails,
  317. // then we simply lose some slight efficiency, but this is not
  318. // a memory leak.
  319. //
  320. #ifdef DEBUG
  321. if (atomRet == ATOM_ERR)
  322. TRACE_MSG(TF_ATOM, TEXT("ATOM **Failed adding %s"), psz);
  323. #endif
  324. if (atomRet == ATOM_ERR && pitem)
  325. {
  326. ASSERT(iItem != -1);
  327. DPA_InsertPtr(this->hdpaFree, cFree+1, IntToPtr(iItem));
  328. }
  329. }
  330. Atom_LeaveCS(this);
  331. return atomRet;
  332. }
  333. /*----------------------------------------------------------
  334. Purpose: Increment the reference count of this atom.
  335. Returns: Last count
  336. 0 if the atom doesn't exist
  337. Cond: --
  338. */
  339. UINT PUBLIC Atom_AddRef(
  340. int atom)
  341. {
  342. ATOMTABLE * this = &s_atomtable;
  343. UINT cRef;
  344. if (!Atom_IsValid(atom))
  345. {
  346. ASSERT(0);
  347. return 0;
  348. }
  349. VALIDATE_ATOM(atom);
  350. Atom_EnterCS(this);
  351. {
  352. A_ITEM * pitem = DSA_GetItemPtr(this->hdsa, atom);
  353. if (pitem)
  354. {
  355. cRef = pitem->ucRef++;
  356. }
  357. else
  358. {
  359. cRef = 0;
  360. }
  361. }
  362. Atom_LeaveCS(this);
  363. return cRef;
  364. }
  365. /*----------------------------------------------------------
  366. Purpose: Delete a string from the atom table.
  367. If the reference count is not zero, we do nothing.
  368. Returns: --
  369. Cond: N.b. Decrements the reference count.
  370. */
  371. void PUBLIC Atom_Delete(
  372. int atom)
  373. {
  374. ATOMTABLE * this = &s_atomtable;
  375. A_ITEM * pitem;
  376. if (!Atom_IsValid(atom))
  377. {
  378. ASSERT(0);
  379. return;
  380. }
  381. VALIDATE_ATOM(atom);
  382. Atom_EnterCS(this);
  383. {
  384. pitem = DSA_GetItemPtr(this->hdsa, atom);
  385. if (pitem)
  386. {
  387. int idpa;
  388. int cFree;
  389. ASSERT(pitem->atom == atom);
  390. // Is the reference count already at zero?
  391. if (0 == pitem->ucRef)
  392. {
  393. // Yes; somebody is calling Atom_Delete one-too-many times!
  394. DEBUG_CODE( TRACE_MSG(TF_ATOM, TEXT("ATOM Deleting %d once-too-many!!"),
  395. pitem->atom); )
  396. ASSERT(0);
  397. }
  398. else if (0 == --pitem->ucRef)
  399. {
  400. // Yes
  401. idpa = DPA_GetPtrIndex(this->hdpa, IntToPtr(atom)); // linear search
  402. DEBUG_CODE( TRACE_MSG(TF_ATOM, TEXT("ATOM Deleting %d: %s"),
  403. pitem->atom, pitem->psz ? pitem->psz : (LPCTSTR)TEXT("NULL")); )
  404. ASSERT(atom == (int)DPA_GetPtr(this->hdpa, idpa));
  405. if (DPA_ERR != idpa)
  406. {
  407. DPA_DeletePtr(this->hdpa, idpa);
  408. ASSERT(pitem->psz);
  409. Str_SetPtr(&pitem->psz, NULL);
  410. DEBUG_CODE( pitem->psz = NULL; )
  411. }
  412. else
  413. {
  414. ASSERT(0); // Should never get here
  415. }
  416. // Add ptr to the free list. If this fails, we simply
  417. // lose some efficiency in reusing this portion of the cache.
  418. // This is not a memory leak.
  419. //
  420. cFree = DPA_GetPtrCount(this->hdpaFree);
  421. DPA_InsertPtr(this->hdpaFree, cFree+1, IntToPtr(atom));
  422. }
  423. }
  424. }
  425. Atom_LeaveCS(this);
  426. }
  427. /*----------------------------------------------------------
  428. Purpose: Replace the string corresponding with the atom with
  429. another string. The atom will not change.
  430. Returns: TRUE on success
  431. Cond: --
  432. */
  433. BOOL PUBLIC Atom_Replace(
  434. int atom,
  435. LPCTSTR pszNew)
  436. {
  437. ATOMTABLE * this = &s_atomtable;
  438. BOOL bRet = FALSE;
  439. A_ITEM * pitem;
  440. ASSERT(pszNew);
  441. if (!Atom_IsValid(atom))
  442. {
  443. return FALSE;
  444. }
  445. VALIDATE_ATOM(atom);
  446. Atom_EnterCS(this);
  447. {
  448. pitem = DSA_GetItemPtr(this->hdsa, atom);
  449. if (pitem)
  450. {
  451. ASSERT(atom == pitem->atom);
  452. ASSERT(pitem->psz);
  453. DEBUG_CODE( TRACE_MSG(TF_ATOM, TEXT("ATOM Change %d [%u]: %s -> %s"),
  454. atom, pitem->ucRef, pitem->psz, pszNew); )
  455. if (Str_SetPtr(&pitem->psz, pszNew))
  456. {
  457. DPA_Sort(this->hdpa, Atom_CompareIndexes, (LPARAM)this->hdsa);
  458. bRet = TRUE;
  459. }
  460. #ifdef DEBUG
  461. else
  462. TRACE_MSG(TF_ATOM, TEXT("ATOM **Change failed"));
  463. #endif
  464. }
  465. }
  466. Atom_LeaveCS(this);
  467. return bRet;
  468. }
  469. /*----------------------------------------------------------
  470. Purpose: Translate all atoms with that contain the partial
  471. string atomOld with the partial string atomNew.
  472. Returns: TRUE on success
  473. Cond: --
  474. */
  475. BOOL PUBLIC Atom_Translate(
  476. int atomOld,
  477. int atomNew)
  478. {
  479. BOOL bRet = FALSE;
  480. ATOMTABLE * this = &s_atomtable;
  481. A_ITEM * pitem;
  482. int idpa;
  483. int cItem;
  484. int atomSave = 0;
  485. int cchOld;
  486. LPCTSTR psz;
  487. LPCTSTR pszOld;
  488. LPCTSTR pszNew;
  489. LPCTSTR pszRest;
  490. TCHAR sz[MAXPATHLEN];
  491. if ( !(Atom_IsValid(atomOld) && Atom_IsValid(atomNew)) )
  492. {
  493. return FALSE;
  494. }
  495. Atom_EnterCS(this);
  496. {
  497. pszOld = Atom_GetName(atomOld);
  498. cchOld = lstrlen(pszOld);
  499. pszNew = Atom_GetName(atomNew);
  500. cItem = DPA_GetPtrCount(this->hdpa);
  501. for (idpa = 0; idpa < cItem; idpa++)
  502. {
  503. pitem = MyGetPtr(this, idpa);
  504. ASSERT(pitem);
  505. if (pitem->atom == 0)
  506. continue; // skip reserved atom
  507. if (atomOld == pitem->atom)
  508. {
  509. atomSave = pitem->atom; // Save this one for last
  510. continue;
  511. }
  512. psz = Atom_GetName(pitem->atom);
  513. ASSERT(psz);
  514. if (PathIsPrefix(psz, pszOld) && lstrlen(psz) >= cchOld)
  515. {
  516. // Translate this atom
  517. //
  518. pszRest = psz + cchOld; // whack up the path
  519. PathCombine(sz, pszNew, pszRest);
  520. DEBUG_CODE( TRACE_MSG(TF_ATOM, TEXT("ATOM Translate %d [%u]: %s -> %s"),
  521. pitem->atom, pitem->ucRef, pitem->psz, (LPCTSTR)sz); )
  522. if (!Str_SetPtr(&pitem->psz, sz))
  523. goto Translate_Fail;
  524. }
  525. }
  526. ASSERT(Atom_IsValid(atomSave)); // this means trouble
  527. VALIDATE_ATOM(atomSave);
  528. pitem = DSA_GetItemPtr(this->hdsa, atomSave);
  529. if (pitem)
  530. {
  531. ASSERT(atomSave == pitem->atom);
  532. ASSERT(pitem->psz);
  533. DEBUG_CODE( TRACE_MSG(TF_ATOM, TEXT("ATOM Translate %d [%u]: %s -> %s"),
  534. pitem->atom, pitem->ucRef, pitem->psz, pszNew); )
  535. if (!Str_SetPtr(&pitem->psz, pszNew))
  536. goto Translate_Fail;
  537. }
  538. bRet = TRUE;
  539. Translate_Fail:
  540. ASSERT(bRet);
  541. // Sort here, even on a fail, so we correctly sort whatever
  542. // got translated before the failure.
  543. //
  544. DPA_Sort(this->hdpa, Atom_CompareIndexes, (LPARAM)this->hdsa);
  545. }
  546. Atom_LeaveCS(this);
  547. return bRet;
  548. }
  549. /*----------------------------------------------------------
  550. Purpose: Search for a string in the atom table and return the atom
  551. Returns: Atom
  552. ATOM_ERR if the string is not in the table
  553. Cond: Reference count is NOT incremented
  554. */
  555. int PUBLIC Atom_Find(
  556. LPCTSTR psz)
  557. {
  558. ATOMTABLE * this = &s_atomtable;
  559. A_ITEM item;
  560. A_ITEM * pitem;
  561. int atomRet = ATOM_ERR;
  562. int idpa;
  563. ASSERT(psz);
  564. Atom_EnterCS(this);
  565. {
  566. item.psz = (LPTSTR)(LPVOID)psz;
  567. idpa = DPA_Search(this->hdpa, &item, 0, Atom_Compare, (LPARAM)this->hdsa,
  568. DPAS_SORTED);
  569. if (idpa != -1)
  570. {
  571. pitem = MyGetPtr(this, idpa);
  572. atomRet = pitem->atom;
  573. DEBUG_CODE( TRACE_MSG(TF_ATOM, TEXT("ATOM Find %s. Found %d [%u]: %s"),
  574. psz, pitem->atom, pitem->ucRef, pitem->psz); )
  575. ASSERT(IsSzEqual(psz, pitem->psz));
  576. }
  577. #ifdef DEBUG
  578. else
  579. TRACE_MSG(TF_ATOM, TEXT("ATOM **Not found %s"), psz);
  580. #endif
  581. }
  582. Atom_LeaveCS(this);
  583. return atomRet;
  584. }
  585. /*----------------------------------------------------------
  586. Purpose: Get the string for this atom
  587. Returns: Ptr to the string
  588. NULL if the atom is bogus
  589. Cond: The caller must serialize this.
  590. */
  591. LPCTSTR PUBLIC Atom_GetName(
  592. int atom)
  593. {
  594. ATOMTABLE * this = &s_atomtable;
  595. LPCTSTR pszRet = NULL;
  596. A_ITEM * pitem;
  597. VALIDATE_ATOM(atom);
  598. Atom_EnterCS(this);
  599. {
  600. pitem = DSA_GetItemPtr(this->hdsa, atom);
  601. if (pitem)
  602. {
  603. pszRet = pitem->psz;
  604. DEBUG_CODE( TRACE_MSG(TF_ATOM, TEXT("ATOM Getting name %d [%u]: %s"),
  605. atom, pitem->ucRef, pszRet); )
  606. ASSERT(atom == pitem->atom);
  607. }
  608. #ifdef DEBUG
  609. else
  610. TRACE_MSG(TF_ATOM, TEXT("ATOM **Cannot get %d"), atom);
  611. #endif
  612. }
  613. Atom_LeaveCS(this);
  614. return pszRet;
  615. }
  616. /*----------------------------------------------------------
  617. Purpose: Return TRUE if atom2 is a partial path match of atom1.
  618. Returns: boolean
  619. Cond: Requires atom1 and atom2 to be valid.
  620. */
  621. BOOL PUBLIC Atom_IsPartialMatch(
  622. int atom1,
  623. int atom2)
  624. {
  625. LPCTSTR psz1 = Atom_GetName(atom1);
  626. LPCTSTR psz2 = Atom_GetName(atom2);
  627. ASSERT(psz1);
  628. ASSERT(psz2);
  629. return PathIsPrefix(psz2, psz1);
  630. }