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.

222 lines
6.8 KiB

  1. //
  2. // txtcache.cpp
  3. //
  4. #include "private.h"
  5. #include "txtcache.h"
  6. long CProcessTextCache::_lCacheMutex = -1;
  7. ITextStoreACP *CProcessTextCache::_ptsi = NULL;
  8. LONG CProcessTextCache::_acpStart;
  9. LONG CProcessTextCache::_acpEnd;
  10. WCHAR CProcessTextCache::_achPlain[CACHE_SIZE_TEXT];
  11. TS_RUNINFO CProcessTextCache::_rgRunInfo[CACHE_SIZE_RUNINFO];
  12. ULONG CProcessTextCache::_ulRunInfoLen;
  13. //+---------------------------------------------------------------------------
  14. //
  15. // GetText
  16. //
  17. // Wrapper for GetText that uses a cache.
  18. //----------------------------------------------------------------------------
  19. HRESULT CProcessTextCache::GetText(ITextStoreACP *ptsi, LONG acpStart, LONG acpEnd,
  20. WCHAR *pchPlain, ULONG cchPlainReq, ULONG *pcchPlainOut,
  21. TS_RUNINFO *prgRunInfo, ULONG ulRunInfoReq, ULONG *pulRunInfoOut,
  22. LONG *pacpNext)
  23. {
  24. #ifdef DEBUG
  25. // use these guys to verify the cache in debug
  26. WCHAR *dbg_pchPlain;
  27. LONG dbg_acpStart = acpStart;
  28. LONG dbg_acpEnd = acpEnd;
  29. ULONG dbg_cchPlainReq = cchPlainReq;
  30. ULONG dbg_cchPlainOut;
  31. TS_RUNINFO *dbg_prgRunInfo;
  32. ULONG dbg_ulRunInfoReq = ulRunInfoReq;
  33. ULONG dbg_ulRunInfoOut;
  34. LONG dbg_acpNext;
  35. #endif
  36. ULONG cch;
  37. ULONG cchBase;
  38. LONG acpBase;
  39. ULONG i;
  40. ULONG iDst;
  41. ULONG iOffset;
  42. int dStartEnd;
  43. HRESULT hr;
  44. // don't block if the mutex is held, just call the real GetText
  45. if (InterlockedIncrement(&_lCacheMutex) != 0)
  46. goto RealGetText;
  47. // if its a really big request, don't try to use the cache
  48. // the way we set things up, once we decide to use the cache we only ask
  49. // for CACHE_SIZE_TEXT chunks of text at a time, no matter what
  50. // the code would still be correct without this test, but probably slower
  51. if (acpEnd < 0 && cchPlainReq > CACHE_SIZE_TEXT)
  52. goto RealGetText;
  53. // need to reset the cache?
  54. if (_ptsi != ptsi || // no cache
  55. _acpStart > acpStart || _acpEnd <= acpStart) // is any of the text in the cache?
  56. {
  57. _ptsi = NULL; // invalidate the cache in case the GetText fails
  58. _acpStart = max(0, acpStart - CACHE_PRELOAD_COUNT);
  59. hr = ptsi->GetText(_acpStart, -1, _achPlain, ARRAYSIZE(_achPlain), &cch,
  60. _rgRunInfo, ARRAYSIZE(_rgRunInfo), &_ulRunInfoLen, &_acpEnd);
  61. if (hr != S_OK)
  62. goto RealGetText;
  63. // we have a good cache
  64. _ptsi = ptsi;
  65. }
  66. // return something from the cache
  67. if (pcchPlainOut != NULL)
  68. {
  69. *pcchPlainOut = 0;
  70. }
  71. if (pulRunInfoOut != NULL)
  72. {
  73. *pulRunInfoOut = 0;
  74. }
  75. // find a start point
  76. // in the first run?
  77. acpBase = _acpStart;
  78. cchBase = 0;
  79. iDst = 0;
  80. for (i=0; i<_ulRunInfoLen; i++)
  81. {
  82. if (acpStart == acpEnd)
  83. break;
  84. dStartEnd = acpEnd - acpStart;
  85. iOffset = acpStart - acpBase;
  86. acpBase += _rgRunInfo[i].uCount;
  87. cch = 0;
  88. if (iOffset >= _rgRunInfo[i].uCount)
  89. {
  90. if (_rgRunInfo[i].type != TS_RT_OPAQUE)
  91. {
  92. cchBase += _rgRunInfo[i].uCount;
  93. }
  94. continue;
  95. }
  96. if (ulRunInfoReq > 0)
  97. {
  98. cch = _rgRunInfo[i].uCount - iOffset;
  99. if (dStartEnd > 0 &&
  100. iOffset + dStartEnd < _rgRunInfo[i].uCount)
  101. {
  102. cch = dStartEnd;
  103. }
  104. prgRunInfo[iDst].uCount = cch;
  105. prgRunInfo[iDst].type = _rgRunInfo[i].type;
  106. (*pulRunInfoOut)++;
  107. }
  108. if (cchPlainReq > 0 &&
  109. _rgRunInfo[i].type != TS_RT_OPAQUE)
  110. {
  111. cch = min(cchPlainReq, _rgRunInfo[i].uCount - iOffset);
  112. if (dStartEnd > 0 &&
  113. iOffset + dStartEnd < _rgRunInfo[i].uCount)
  114. {
  115. cch = min(cchPlainReq, (ULONG)dStartEnd);
  116. }
  117. memcpy(pchPlain+*pcchPlainOut, _achPlain+cchBase+iOffset, sizeof(WCHAR)*cch);
  118. *pcchPlainOut += cch;
  119. if (ulRunInfoReq > 0)
  120. {
  121. // might have truncated the run based on pchPlain buffer size, so fix it
  122. prgRunInfo[iDst].uCount = cch;
  123. }
  124. cchPlainReq -= cch;
  125. cchBase += cch + iOffset;
  126. if (cchPlainReq == 0)
  127. {
  128. ulRunInfoReq = 1; // force a break below
  129. }
  130. }
  131. if (cch == 0)
  132. break;
  133. acpStart += cch;
  134. iDst++;
  135. if (ulRunInfoReq > 0)
  136. {
  137. if (--ulRunInfoReq == 0)
  138. break;
  139. }
  140. }
  141. *pacpNext = acpStart;
  142. InterlockedDecrement(&_lCacheMutex);
  143. #ifdef DEBUG
  144. // verify the cache worked
  145. if (dbg_acpEnd <= _acpEnd) // this simple check won't work if the GetText was truncated
  146. {
  147. dbg_pchPlain = (WCHAR *)cicMemAlloc(sizeof(WCHAR)*dbg_cchPlainReq);
  148. if (dbg_pchPlain)
  149. {
  150. // there's a bug in word where it will write to dbg_ulRunInfoReq even when dbg_ulRunInfoReq is zero,
  151. // if it is non-NULL
  152. dbg_prgRunInfo = dbg_ulRunInfoReq ? (TS_RUNINFO *)cicMemAlloc(sizeof(TS_RUNINFO)*dbg_ulRunInfoReq) : NULL;
  153. if (dbg_prgRunInfo || !dbg_ulRunInfoReq)
  154. {
  155. hr = ptsi->GetText(dbg_acpStart, dbg_acpEnd, dbg_pchPlain, dbg_cchPlainReq, &dbg_cchPlainOut,
  156. dbg_prgRunInfo, dbg_ulRunInfoReq, &dbg_ulRunInfoOut, &dbg_acpNext);
  157. Assert(hr == S_OK);
  158. if (dbg_cchPlainReq > 0)
  159. {
  160. Assert(dbg_cchPlainOut == *pcchPlainOut);
  161. Assert(memcmp(dbg_pchPlain, pchPlain, dbg_cchPlainOut*sizeof(WCHAR)) == 0);
  162. }
  163. if (dbg_ulRunInfoReq > 0)
  164. {
  165. Assert(dbg_ulRunInfoOut == *pulRunInfoOut);
  166. Assert(memcmp(dbg_prgRunInfo, prgRunInfo, sizeof(TS_RUNINFO)*dbg_ulRunInfoOut) == 0);
  167. }
  168. Assert(dbg_acpNext == *pacpNext);
  169. cicMemFree(dbg_prgRunInfo);
  170. }
  171. else
  172. {
  173. // could not allocate mem.
  174. Assert(0);
  175. }
  176. cicMemFree(dbg_pchPlain);
  177. }
  178. else
  179. {
  180. // could not allocate mem.
  181. Assert(0);
  182. }
  183. }
  184. #endif
  185. return S_OK;
  186. RealGetText:
  187. InterlockedDecrement(&_lCacheMutex);
  188. return ptsi->GetText(acpStart, acpEnd, pchPlain, cchPlainReq, pcchPlainOut,
  189. prgRunInfo, ulRunInfoReq, pulRunInfoOut, pacpNext);
  190. }