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.

632 lines
14 KiB

  1. /*
  2. * @doc INTERNAL
  3. *
  4. * @module - FORMAT.C
  5. * CCharFormatArray and CParaFormatArray classes |
  6. *
  7. * Authors:
  8. * Original RichEdit code: David R. Fulmer
  9. * Christian Fortini
  10. * Murray Sargent
  11. *
  12. * Copyright (c) 1995-1998, Microsoft Corporation. All rights reserved.
  13. */
  14. #include "_common.h"
  15. #include "_format.h"
  16. ASSERTDATA
  17. // =============================== CFixArrayBase =================================
  18. CFixArrayBase::CFixArrayBase(
  19. LONG cbElem)
  20. {
  21. TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CFixArrayBase::CFixArrayBase");
  22. _prgel = NULL;
  23. _cel = 0;
  24. _ielFirstFree = 0;
  25. _cbElem = cbElem + sizeof(LONG_PTR); // Use LONG_PTR to get proper alignment on Win64
  26. }
  27. /*
  28. * CFixArrayBase::Add()
  29. *
  30. * @mfunc
  31. * Return index of new element, reallocing if necessary
  32. *
  33. * @rdesc
  34. * Index of new element.
  35. *
  36. * @comm
  37. * Free elements are maintained in place as a linked list indexed
  38. * by a chain of ref-count entries with their sign bits set and the
  39. * rest of the entry giving the index of the next element on the
  40. * free list. The list is terminated by a 0 entry. This approach
  41. * enables element 0 to be on the free list.
  42. */
  43. LONG CFixArrayBase::Add()
  44. {
  45. TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CFixArrayBase::Add");
  46. char *pel;
  47. LONG iel, ielRet;
  48. if(_ielFirstFree) // Return first element of free list
  49. {
  50. ielRet = _ielFirstFree & ~FLBIT;
  51. _ielFirstFree = RefCount(ielRet);
  52. }
  53. else // All lower positions taken: need
  54. { // to add another celGrow elements
  55. pel = (char*)PvReAlloc(_prgel, (_cel + celGrow) * _cbElem);
  56. if(!pel)
  57. return -1;
  58. // Clear out the *end* of the newly allocated memory
  59. ZeroMemory(pel + _cel*_cbElem, celGrow*_cbElem);
  60. _prgel = pel;
  61. ielRet = _cel; // Return first one added
  62. iel = _cel + 1;
  63. _cel += celGrow;
  64. // Add elements _cel+1 thru _cel+celGrow-1 to free list. The last
  65. // of these retains a 0, stored by fZeroFill in Alloc
  66. _ielFirstFree = iel | FLBIT;
  67. for(pel = (char *)&RefCount(iel);
  68. ++iel < _cel;
  69. pel += _cbElem)
  70. {
  71. *(INT *)pel = iel | FLBIT;
  72. }
  73. }
  74. return ielRet;
  75. }
  76. void CFixArrayBase::Free(
  77. LONG iel)
  78. {
  79. TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CFixArrayBase::Free(iel)");
  80. // Simply add it to free list
  81. RefCount(iel) = _ielFirstFree;
  82. _ielFirstFree = iel | FLBIT;
  83. }
  84. void CFixArrayBase::Free()
  85. {
  86. TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CFixArrayBase::Free()");
  87. #ifdef DEBUG
  88. // Only do this validation if all the ped's are gone. Visual basic shutsdown apps
  89. // without freeing all the resources so this safety check is necessary.
  90. if (0 == W32->GetRefs())
  91. {
  92. // Display MessageBox if any CCharFormats, CParaFormats, or CTabs have
  93. // reference counts > 0. This only happens if an error has occurred.
  94. BOOL fComplained = FALSE;
  95. for(LONG iel = 0; iel < Count(); iel++)
  96. {
  97. while(RefCount(iel) > 0)
  98. {
  99. if (!fComplained)
  100. {
  101. fComplained = TRUE;
  102. AssertSz(FALSE, _cbElem == sizeof(CCharFormat) + sizeof(LONG_PTR) ? "CCharFormat not free" :
  103. _cbElem == sizeof(CParaFormat) + sizeof(LONG_PTR) ? "CParaFormat not free" :
  104. "CTabs not free");
  105. }
  106. Release(iel);
  107. }
  108. }
  109. }
  110. #endif
  111. FreePv(_prgel);
  112. _prgel = NULL;
  113. _cel = 0;
  114. _ielFirstFree = 0;
  115. }
  116. HRESULT CFixArrayBase::Deref(
  117. LONG iel,
  118. const void **ppel) const
  119. {
  120. Assert(ppel);
  121. AssertSz(iel >= 0,
  122. "CFixArrayBase::Deref: bad element index" );
  123. AssertSz(*(LONG *)(_prgel + (iel + 1) * _cbElem - 4) > 0,
  124. "CFixArrayBase::Deref: element index has bad ref count");
  125. if(!ppel)
  126. return E_INVALIDARG;
  127. *ppel = Elem(iel);
  128. return S_OK;
  129. }
  130. /*
  131. * CFixArrayBase::RefCount(iel)
  132. *
  133. * @mfunc
  134. * The reference count for an element is stored as a LONG immediately
  135. * following the element in the CFixArray. If the element isn't used
  136. * i.e., is free, then the reference count is used as a link to the
  137. * next free element. The last free element in this list has a 0
  138. * "reference count", which terminates the list.
  139. *
  140. * The ref count follows the element instead of preceding it because
  141. * this allows Elem(iel) to avoid an extra addition. Elem() is used
  142. * widely in the code.
  143. *
  144. * @rdesc
  145. * Ptr to reference count
  146. */
  147. LONG & CFixArrayBase::RefCount(
  148. LONG iel)
  149. {
  150. Assert(iel < Count());
  151. return (LONG &)(*(_prgel + (iel + 1) * _cbElem - 4));
  152. }
  153. LONG CFixArrayBase::Release(
  154. LONG iel)
  155. {
  156. LONG cRef = -1;
  157. if(iel >= 0) // Ignore default iel
  158. {
  159. CLock lock;
  160. CheckFreeChain();
  161. AssertSz(RefCount(iel) > 0, "CFixArrayBase::Release(): already free");
  162. cRef = --RefCount(iel);
  163. if(!cRef) // Entry no longer referenced
  164. Free(iel); // Add it to the free chain
  165. }
  166. return cRef;
  167. }
  168. LONG CFixArrayBase::AddRef(
  169. LONG iel)
  170. {
  171. LONG cRef = -1;
  172. if(iel >= 0)
  173. {
  174. CLock lock;
  175. CheckFreeChain();
  176. AssertSz(RefCount(iel) > 0, "CFixArrayBase::AddRef(): add ref to free elem");
  177. cRef = ++RefCount(iel);
  178. }
  179. return cRef;
  180. }
  181. LONG CFixArrayBase::Find(
  182. const void *pel)
  183. {
  184. CheckFreeChain();
  185. for(LONG iel = 0; iel < Count(); iel++)
  186. {
  187. // RefCount < 0 means entry not in use and is index of next free entry.
  188. // RefCount = 0 marks last free element in list. _cbElem = sizeof(ELEM)
  189. // plus sizeof(RefCount), which is a LONG.
  190. if (RefCount(iel) > 0 &&
  191. !CompareMemory(Elem(iel), pel, _cbElem - sizeof(LONG_PTR)))
  192. {
  193. return iel;
  194. }
  195. }
  196. return -1;
  197. }
  198. HRESULT CFixArrayBase::Cache(
  199. const void *pel,
  200. LONG * piel)
  201. {
  202. TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CParaFormatArray::Cache");
  203. CLock lock;
  204. LONG iel = Find(pel);
  205. if(iel >= 0)
  206. RefCount(iel)++;
  207. else
  208. {
  209. iel = Add();
  210. if(iel < 0)
  211. return E_OUTOFMEMORY;
  212. CopyMemory(Elem(iel), pel, _cbElem - sizeof(LONG_PTR));
  213. RefCount(iel) = 1;
  214. }
  215. CheckFreeChain();
  216. if(piel)
  217. *piel = iel;
  218. return S_OK;
  219. }
  220. #ifdef DEBUG
  221. void CFixArrayBase::CheckFreeChainFn(
  222. LPSTR szFile,
  223. INT nLine)
  224. {
  225. TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CFixArrayBase::CheckFreeChainFn");
  226. LONG cel = 0;
  227. LONG iel = _ielFirstFree;
  228. LONG ielT;
  229. while(iel)
  230. {
  231. Assert(iel < 0);
  232. ielT = RefCount(iel & ~FLBIT);
  233. if((LONG)(ielT & ~FLBIT) > _cel)
  234. Tracef(TRCSEVERR, "AttCheckFreeChainCF(): elem %ld points to out of range elem %ld", iel, ielT);
  235. iel = ielT;
  236. if(++cel > _cel)
  237. {
  238. AssertSzFn("CFixArrayBase::CheckFreeChain() - CF free chain seems to contain an infinite loop", szFile, nLine);
  239. return;
  240. }
  241. }
  242. }
  243. #endif
  244. // =========================== CCharFormatArray ===========================================
  245. HRESULT CCharFormatArray::Deref(
  246. LONG iCF,
  247. const CCharFormat **ppCF) const
  248. {
  249. TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CCharFormatArray::Deref");
  250. return CFixArrayBase::Deref(iCF, (const void **)ppCF);
  251. }
  252. LONG CCharFormatArray::Release(
  253. LONG iCF)
  254. {
  255. TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CCharFormatArray::ReleaseFormat");
  256. return CFixArrayBase::Release(iCF);
  257. }
  258. LONG CCharFormatArray::AddRef(
  259. LONG iCF)
  260. {
  261. TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CCharFormatArray::AddRefFormat");
  262. return CFixArrayBase::AddRef(iCF);
  263. }
  264. void CCharFormatArray::Destroy()
  265. {
  266. delete this;
  267. }
  268. LONG CCharFormatArray::Find(
  269. const CCharFormat *pCF)
  270. {
  271. TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CCharFormatArray::Find");
  272. LONG iCF;
  273. #define QUICKCRCSEARCHSIZE 15 // Must be 2^n - 1 for quick MOD
  274. // operation, it is a simple hash.
  275. static struct {
  276. BYTE bCRC;
  277. LONG iCF;
  278. } quickCrcSearch[QUICKCRCSEARCHSIZE+1];
  279. BYTE bCRC;
  280. WORD hashKey;
  281. CheckFreeChain();
  282. // Check our cache before going sequential
  283. bCRC = (BYTE)pCF->_iFont;
  284. hashKey = (WORD)(bCRC & QUICKCRCSEARCHSIZE);
  285. if(bCRC == quickCrcSearch[hashKey].bCRC)
  286. {
  287. iCF = quickCrcSearch[hashKey].iCF - 1;
  288. if (iCF >= 0 && iCF < Count() && RefCount(iCF) > 0 &&
  289. !CompareMemory(Elem(iCF), pCF, sizeof(CCharFormat)))
  290. {
  291. return iCF;
  292. }
  293. }
  294. for(iCF = 0; iCF < Count(); iCF++)
  295. {
  296. if(RefCount(iCF) > 0 && !CompareMemory(Elem(iCF), pCF, sizeof(CCharFormat)))
  297. {
  298. quickCrcSearch[hashKey].bCRC = bCRC;
  299. quickCrcSearch[hashKey].iCF = iCF + 1;
  300. return iCF;
  301. }
  302. }
  303. return -1;
  304. }
  305. HRESULT CCharFormatArray::Cache(
  306. const CCharFormat *pCF,
  307. LONG* piCF)
  308. {
  309. TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CCharFormatArray::Cache");
  310. CLock lock;
  311. LONG iCF = Find(pCF);
  312. if(iCF >= 0)
  313. RefCount(iCF)++;
  314. else
  315. {
  316. iCF = Add();
  317. if(iCF < 0)
  318. return E_OUTOFMEMORY;
  319. *Elem(iCF) = *pCF; // Set entry iCF to *pCF
  320. RefCount(iCF) = 1;
  321. }
  322. CheckFreeChain();
  323. if(piCF)
  324. *piCF = iCF;
  325. return S_OK;
  326. }
  327. // =============================== CParaFormatArray ===========================================
  328. HRESULT CParaFormatArray::Deref(
  329. LONG iPF,
  330. const CParaFormat **ppPF) const
  331. {
  332. TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CParaFormatArray::Deref");
  333. return CFixArrayBase::Deref(iPF, (const void **)ppPF);
  334. }
  335. LONG CParaFormatArray::Release(
  336. LONG iPF)
  337. {
  338. TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CParaFormatArray::ReleaseFormat");
  339. CLock lock;
  340. LONG cRef = CFixArrayBase::Release(iPF);
  341. #ifdef TABS
  342. if(!cRef)
  343. GetTabsCache()->Release(Elem(iPF)->_iTabs);
  344. #endif
  345. return cRef;
  346. }
  347. LONG CParaFormatArray::AddRef(
  348. LONG iPF)
  349. {
  350. TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CParaFormatArray::AddRefFormat");
  351. return CFixArrayBase::AddRef(iPF);
  352. }
  353. void CParaFormatArray::Destroy()
  354. {
  355. delete this;
  356. }
  357. HRESULT CParaFormatArray::Cache(
  358. const CParaFormat *pPF,
  359. LONG *piPF)
  360. {
  361. TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CParaFormatArray::Cache");
  362. HRESULT hr = CFixArrayBase::Cache((const void *)pPF, piPF);
  363. #ifdef TABS
  364. if(hr == NOERROR && RefCount(*piPF) == 1)
  365. GetTabsCache()->AddRef(pPF->_iTabs);
  366. #endif
  367. return hr;
  368. }
  369. // =============================== CTabsArray ===========================================
  370. CTabsArray::~CTabsArray()
  371. {
  372. for(LONG iTabs = 0; iTabs < Count(); iTabs++)
  373. {
  374. // It shouldn't be necessary to release any tabs, since when all
  375. // controls are gone, no reference counts should be > 0.
  376. while(RefCount(iTabs) > 0)
  377. {
  378. #ifdef DEBUG
  379. // Only do this validation if all the ped's are gone. Visual basic shutsdown apps
  380. // without freeing all the resources so this safety check is necessary.
  381. AssertSz(0 != W32->GetRefs(), "CTabs not free");
  382. #endif
  383. Release(iTabs);
  384. }
  385. }
  386. }
  387. const LONG *CTabsArray::Deref(
  388. LONG iTabs) const
  389. {
  390. TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CTabsArray::Deref");
  391. return iTabs >= 0 ? Elem(iTabs)->_prgxTabs : NULL;
  392. }
  393. LONG CTabsArray::Release(
  394. LONG iTabs)
  395. {
  396. TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CTabsArray::Release");
  397. LONG cRef = CFixArrayBase::Release(iTabs);
  398. if(!cRef)
  399. FreePv(Elem(iTabs)->_prgxTabs);
  400. return cRef;
  401. }
  402. LONG CTabsArray::AddRef(
  403. LONG iTabs)
  404. {
  405. TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CTabsArray::AddRef");
  406. return CFixArrayBase::AddRef(iTabs);
  407. }
  408. LONG CTabsArray::Find(
  409. const LONG *prgxTabs,
  410. LONG cTab)
  411. {
  412. CheckFreeChain();
  413. CTabs *pTab;
  414. for(LONG iel = 0; iel < Count(); iel++)
  415. {
  416. // RefCount < 0 means entry not in use and is index of next free entry.
  417. // RefCount = 0 marks last free element in list. _cbElem = sizeof(ELEM)
  418. // plus sizeof(RefCount), which is a LONG.
  419. if(RefCount(iel) > 0)
  420. {
  421. pTab = Elem(iel);
  422. if (pTab->_cTab == cTab &&
  423. !CompareMemory(pTab->_prgxTabs, prgxTabs, cTab*sizeof(LONG)))
  424. {
  425. return iel;
  426. }
  427. }
  428. }
  429. return -1;
  430. }
  431. LONG CTabsArray::Cache(
  432. const LONG *prgxTabs,
  433. LONG cTab)
  434. {
  435. TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CTabsArray::Cache");
  436. if(!cTab)
  437. return -1; // No tabs defined: use default
  438. CLock lock;
  439. LONG iTabs = Find(prgxTabs, cTab);
  440. if(iTabs >= 0)
  441. RefCount(iTabs)++;
  442. else
  443. {
  444. iTabs = Add();
  445. if(iTabs < 0) // Out of memory: use default
  446. return -1;
  447. CTabs *pTabs = Elem(iTabs);
  448. LONG cb = sizeof(LONG)*cTab;
  449. pTabs->_prgxTabs = (LONG *)PvAlloc(cb, GMEM_FIXED);
  450. if(!pTabs->_prgxTabs)
  451. return -1; // Out of memory: use default
  452. CopyMemory(pTabs->_prgxTabs, prgxTabs, cb);
  453. pTabs->_cTab = cTab;
  454. RefCount(iTabs) = 1;
  455. }
  456. return iTabs;
  457. }
  458. // ================================== Factories ===========================================
  459. static ICharFormatCache *pCFCache = NULL; // CCharFormat cache
  460. static IParaFormatCache *pPFCache = NULL; // CParaFormat cache
  461. static CTabsArray * pTabsCache = NULL; // CTabs cache
  462. ICharFormatCache *GetCharFormatCache()
  463. {
  464. return pCFCache;
  465. }
  466. IParaFormatCache *GetParaFormatCache()
  467. {
  468. return pPFCache;
  469. }
  470. CTabsArray *GetTabsCache()
  471. {
  472. return pTabsCache;
  473. }
  474. HRESULT CreateFormatCaches() // Called by DllMain()
  475. {
  476. TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CreateFormatCaches");
  477. CLock lock;
  478. pCFCache = new CCharFormatArray();
  479. if(!pCFCache)
  480. return E_OUTOFMEMORY;
  481. pPFCache = new CParaFormatArray();
  482. if(!pPFCache)
  483. {
  484. delete pCFCache;
  485. return E_OUTOFMEMORY;
  486. }
  487. pTabsCache = new CTabsArray();
  488. if(!pTabsCache)
  489. {
  490. delete pCFCache;
  491. delete pPFCache;
  492. return E_OUTOFMEMORY;
  493. }
  494. return S_OK;
  495. }
  496. HRESULT DestroyFormatCaches() // Called by DllMain()
  497. {
  498. TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "DeleteFormatCaches");
  499. if (pCFCache)
  500. pCFCache->Destroy();
  501. if (pPFCache)
  502. pPFCache->Destroy();
  503. if (pTabsCache)
  504. delete pTabsCache;
  505. return NOERROR;
  506. }
  507. /*
  508. * ReleaseFormats(iCF, iPF)
  509. *
  510. * @mfunc
  511. * Release char and para formats corresponding to the indices <p iCF>
  512. * and <p iPF>, respectively
  513. */
  514. void ReleaseFormats (
  515. LONG iCF, //@parm CCharFormat index for releasing
  516. LONG iPF) //@parm CParaFormat index for releasing
  517. {
  518. AssertSz(pCFCache && pPFCache,
  519. "ReleaseFormats: uninitialized format caches");
  520. if (iCF != -1)
  521. pCFCache->Release(iCF);
  522. if (iPF != -1)
  523. pPFCache->Release(iPF);
  524. }