Source code of Windows XP (NT5)
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.

474 lines
11 KiB

  1. #include "stdinc.h"
  2. #include "stringpool.h"
  3. #include "debmacro.h"
  4. #include "fusiontrace.h"
  5. //
  6. // Implementation of the CStringPoolHeapSegment class:
  7. //
  8. BOOL
  9. CStringPoolHeapSegment::Initialize()
  10. {
  11. // Nothing to do today but a good placeholder
  12. return TRUE;
  13. }
  14. BOOL
  15. CStringPoolHeapSegment::Initialize(
  16. const WCHAR *StringIn,
  17. ULONG Cch,
  18. const WCHAR *&rpStringOut
  19. )
  20. {
  21. BOOL fSuccess = FALSE;
  22. FN_TRACE_WIN32(fSuccess);
  23. // You shouldn't have gotten here if this was a "big" allocation
  24. INTERNAL_ERROR_CHECK(Cch < NUMBER_OF(m_rgchBuffer));
  25. INTERNAL_ERROR_CHECK(m_cchUsed == 0);
  26. memcpy(m_rgchBuffer, StringIn, Cch * sizeof(WCHAR));
  27. m_cchUsed = Cch;
  28. rpStringOut = m_rgchBuffer;
  29. fSuccess = TRUE;
  30. Exit:
  31. return fSuccess;
  32. }
  33. BOOL
  34. CStringPoolHeapSegment::TryAllocString(
  35. const WCHAR *StringIn,
  36. ULONG Cch,
  37. const WCHAR *&rpStringOut
  38. )
  39. {
  40. BOOL fSuccess = FALSE;
  41. FN_TRACE_WIN32(fSuccess);
  42. // You shouldn't have gotten here if this was a "big" allocation
  43. INTERNAL_ERROR_CHECK(Cch < NUMBER_OF(m_rgchBuffer));
  44. rpStringOut = NULL;
  45. if ((NUMBER_OF(m_rgchBuffer) - m_cchUsed) >= Cch)
  46. {
  47. WCHAR *pwch = &m_rgchBuffer[m_cchUsed];
  48. memcpy(pwch, StringIn, Cch * sizeof(WCHAR));
  49. rpStringOut = pwch;
  50. m_cchUsed += Cch;
  51. }
  52. fSuccess = TRUE;
  53. Exit:
  54. return fSuccess;
  55. }
  56. //
  57. // Implementation of the CStringPoolSingletonString class:
  58. //
  59. BOOL
  60. CStringPoolSingletonString::Initialize(
  61. const WCHAR *StringIn,
  62. ULONG Cch,
  63. const WCHAR *&rpStringOut
  64. )
  65. {
  66. BOOL fSuccess = FALSE;
  67. FN_TRACE_WIN32(fSuccess);
  68. WCHAR *prgwch = NULL;
  69. INTERNAL_ERROR_CHECK(m_prgwch == NULL);
  70. if (Cch != 0)
  71. {
  72. prgwch = FUSION_NEW_ARRAY(WCHAR, Cch);
  73. memcpy(prgwch, StringIn, Cch * sizeof(WCHAR));
  74. m_prgwch = prgwch;
  75. }
  76. rpStringOut = prgwch;
  77. prgwch = NULL;
  78. fSuccess = TRUE;
  79. Exit:
  80. if (prgwch != NULL)
  81. FUSION_DELETE_ARRAY(prgwch);
  82. return fSuccess;
  83. }
  84. //
  85. // Implementation of the CStringPoolHeap class:
  86. //
  87. BOOL
  88. CStringPoolHeap::Initialize()
  89. {
  90. BOOL fSuccess = FALSE;
  91. FN_TRACE_WIN32(fSuccess);
  92. fSuccess = TRUE;
  93. // Exit:
  94. return fSuccess;
  95. }
  96. BOOL
  97. CStringPoolHeap::DupString(
  98. const WCHAR *StringIn,
  99. ULONG Cch,
  100. const WCHAR *&rpStringOut
  101. )
  102. {
  103. BOOL fSuccess = FALSE;
  104. FN_TRACE_WIN32(fSuccess);
  105. CStringPoolSingletonString *pSingleton = NULL;
  106. CStringPoolHeapSegment *pSegment = NULL;
  107. rpStringOut = NULL;
  108. if (Cch > CStringPoolHeapSegment::CchMax())
  109. {
  110. // It's too big to ever fit into a segment. Just allocate a singleton for it.
  111. IFALLOCFAILED_EXIT(pSingleton = new CStringPoolSingletonString);
  112. IFW32FALSE_EXIT(pSingleton->Initialize(StringIn, Cch, rpStringOut));
  113. m_dequeSingletons.AddToTail(pSingleton);
  114. pSingleton = NULL;
  115. }
  116. else
  117. {
  118. CDequeIterator<CStringPoolHeapSegment, FIELD_OFFSET(CStringPoolHeapSegment, m_leLinks)> iter(&m_dequeSegments);
  119. for (iter.Reset(); iter.More(); iter.Next())
  120. {
  121. IFW32FALSE_EXIT(iter->TryAllocString(StringIn, Cch, rpStringOut));
  122. if (rpStringOut != NULL)
  123. break;
  124. }
  125. if (rpStringOut == NULL)
  126. {
  127. // I guess we need a new heap segment...
  128. IFALLOCFAILED_EXIT(pSegment = new CStringPoolHeapSegment);
  129. IFW32FALSE_EXIT(pSegment->Initialize(StringIn, Cch, rpStringOut));
  130. INTERNAL_ERROR_CHECK(rpStringOut != NULL);
  131. m_dequeSegments.AddToHead(pSegment);
  132. pSegment = NULL;
  133. }
  134. }
  135. fSuccess = TRUE;
  136. Exit:
  137. if (pSingleton != NULL)
  138. FUSION_DELETE_SINGLETON(pSingleton);
  139. if (pSegment != NULL)
  140. FUSION_DELETE_SINGLETON(pSegment);
  141. return fSuccess;
  142. }
  143. //
  144. // Implementation of the CStringPoolEntry class:
  145. //
  146. BOOL
  147. CStringPoolEntry::Initialize(
  148. const WCHAR *StringIn,
  149. ULONG CchIn,
  150. ULONG ulPseudoKey,
  151. CStringPoolHeap &rStringHeap
  152. )
  153. {
  154. BOOL fSuccess = FALSE;
  155. FN_TRACE_WIN32(fSuccess);
  156. // Catch double initializations; a zero PseudoKey is pretty unlikely and we'll just miss the error in that
  157. // one case.
  158. INTERNAL_ERROR_CHECK(this->PseudoKey == 0);
  159. IFW32FALSE_EXIT(rStringHeap.DupString(StringIn, CchIn, this->Buffer));
  160. this->PseudoKey = ulPseudoKey;
  161. this->Length = CchIn * sizeof(WCHAR);
  162. fSuccess = TRUE;
  163. Exit:
  164. return fSuccess;
  165. }
  166. //
  167. // Implementation of the CStringPoolEntryClump class:
  168. //
  169. CStringPoolEntryClump::~CStringPoolEntryClump()
  170. {
  171. if (m_prgEntries != NULL)
  172. FUSION_DELETE_ARRAY(m_prgEntries);
  173. m_prgEntries = NULL;
  174. m_cEntriesAllocated = 0;
  175. m_cEntriesUsed = 0;
  176. }
  177. BOOL
  178. CStringPoolEntryClump::Initialize(
  179. ULONG cStringsToAllocate
  180. )
  181. {
  182. BOOL fSuccess = FALSE;
  183. FN_TRACE_WIN32(fSuccess);
  184. CStringPoolEntry *prgEntries = NULL;
  185. ASSERT(cStringsToAllocate != 0);
  186. PARAMETER_CHECK(cStringsToAllocate != 0);
  187. IFALLOCFAILED_EXIT(prgEntries = FUSION_NEW_ARRAY(CStringPoolEntry, cStringsToAllocate));
  188. m_prgEntries = prgEntries;
  189. prgEntries = NULL;
  190. m_cEntriesAllocated = cStringsToAllocate;
  191. m_cEntriesUsed = 0;
  192. fSuccess = TRUE;
  193. Exit:
  194. if (prgEntries != NULL)
  195. FUSION_DELETE_ARRAY(prgEntries);
  196. return fSuccess;
  197. }
  198. BOOL
  199. CStringPoolEntryClump::FindOrAddEntry(
  200. const WCHAR *StringIn,
  201. ULONG CchIn,
  202. ULONG ulPseudoKey,
  203. CStringPoolHeap &rStringHeap,
  204. ULONG &rulPosition,
  205. CStringPoolEntryClump::FindOrAddDisposition &rdisposition,
  206. const CStringPoolEntry *&rpEntry
  207. )
  208. {
  209. BOOL fSuccess = FALSE;
  210. FN_TRACE_WIN32(fSuccess);
  211. ULONG i;
  212. FindOrAddDisposition disposition = CStringPoolEntryClump::eInvalid;
  213. const ULONG BytesIn = CchIn * sizeof(WCHAR);
  214. rdisposition = CStringPoolEntryClump::eInvalid;
  215. rpEntry = NULL;
  216. for (i=0; i<m_cEntriesUsed; i++)
  217. {
  218. if (m_prgEntries[i].PseudoKey == ulPseudoKey)
  219. {
  220. if (m_prgEntries[i].Length == BytesIn)
  221. {
  222. if (memcmp(StringIn, m_prgEntries[i].Buffer, BytesIn) == 0)
  223. break;
  224. }
  225. }
  226. }
  227. if (i != m_cEntriesUsed)
  228. {
  229. // If we bailed out of the loop early, we must have found it.
  230. disposition = CStringPoolEntryClump::eFound;
  231. rulPosition = i;
  232. rpEntry = &m_prgEntries[i];
  233. }
  234. else
  235. {
  236. // It's not already there; is there space for it?
  237. if (m_cEntriesUsed != m_cEntriesAllocated)
  238. {
  239. IFW32FALSE_EXIT(m_prgEntries[m_cEntriesUsed].Initialize(StringIn, CchIn, ulPseudoKey, rStringHeap));
  240. disposition = CStringPoolEntryClump::eAdded;
  241. rpEntry = &m_prgEntries[m_cEntriesUsed];
  242. rulPosition = m_cEntriesUsed++;
  243. }
  244. else
  245. {
  246. // Nope, keep going...
  247. disposition = CStringPoolEntryClump::eNoRoom;
  248. }
  249. }
  250. rdisposition = disposition;
  251. fSuccess = TRUE;
  252. Exit:
  253. return fSuccess;
  254. }
  255. BOOL
  256. CStringPoolEntryClump::FillInStringArray(
  257. ULONG nArraySize,
  258. SXS_XML_STRING *prgStrings,
  259. ULONG iCurrent,
  260. ULONG &rcWritten
  261. )
  262. {
  263. BOOL fSuccess = FALSE;
  264. FN_TRACE_WIN32(fSuccess);
  265. ULONG i;
  266. rcWritten = 0;
  267. PARAMETER_CHECK(iCurrent < nArraySize);
  268. PARAMETER_CHECK((iCurrent + m_cEntriesUsed) <= nArraySize);
  269. for (i=0; i<m_cEntriesUsed; i++)
  270. prgStrings[iCurrent++] = m_prgEntries[i];
  271. rcWritten = m_cEntriesUsed;
  272. fSuccess = TRUE;
  273. Exit:
  274. return fSuccess;
  275. }
  276. CStringPool::~CStringPool()
  277. {
  278. m_dequeEntryClumps.Clear<CStringPool>(this, CStringPool::ClearDequeEntry);
  279. }
  280. BOOL
  281. CStringPool::Initialize()
  282. {
  283. BOOL fSuccess = FALSE;
  284. FN_TRACE_WIN32(fSuccess);
  285. INTERNAL_ERROR_CHECK(!m_fInitialized);
  286. IFW32FALSE_EXIT(m_StringHeap.Initialize());
  287. m_fInitialized = true;
  288. m_cEntries = 0;
  289. fSuccess = TRUE;
  290. Exit:
  291. return fSuccess;
  292. }
  293. BOOL
  294. CStringPool::Canonicalize(
  295. const WCHAR *StringIn,
  296. ULONG CchIn,
  297. ULONG ulPseudoKey,
  298. ULONG &rulPosition,
  299. const WCHAR *&rStringOut
  300. )
  301. {
  302. BOOL fSuccess = FALSE;
  303. FN_TRACE_WIN32(fSuccess);
  304. ULONG ulPosition = 1;
  305. CDequeIterator<CStringPoolEntryClump, FIELD_OFFSET(CStringPoolEntryClump, m_leEntryChain)> iter;
  306. CStringPoolEntryClump::FindOrAddDisposition disposition = CStringPoolEntryClump::eNoRoom;
  307. CStringPoolEntryClump *pNewClump = NULL;
  308. const CStringPoolEntry *pEntry = NULL;
  309. rulPosition = 0;
  310. rStringOut = NULL;
  311. iter.Rebind(&m_dequeEntryClumps);
  312. for (iter.Reset(); iter.More(); iter.Next())
  313. {
  314. ULONG i;
  315. IFW32FALSE_EXIT(iter->FindOrAddEntry(StringIn, CchIn, ulPseudoKey, m_StringHeap, i, disposition, pEntry));
  316. if ((disposition == CStringPoolEntryClump::eFound) || (disposition == CStringPoolEntryClump::eAdded))
  317. {
  318. if (disposition == CStringPoolEntryClump::eAdded)
  319. m_cEntries++;
  320. ulPosition += i;
  321. break;
  322. }
  323. else
  324. {
  325. // No room is equivalent to not found...
  326. ASSERT(disposition == CStringPoolEntryClump::eNoRoom);
  327. ulPosition += iter->EntriesUsed();
  328. disposition = CStringPoolEntryClump::eNoRoom;
  329. }
  330. }
  331. // If we get here with disposition == eNoRoom, we neither found it nor had room in an existing clump, so we need
  332. // to allocate a new clump...
  333. if (disposition == CStringPoolEntryClump::eNoRoom)
  334. {
  335. ULONG i;
  336. IFALLOCFAILED_EXIT(pNewClump = new CStringPoolEntryClump);
  337. IFW32FALSE_EXIT(pNewClump->Initialize());
  338. IFW32FALSE_EXIT(pNewClump->FindOrAddEntry(StringIn, CchIn, ulPseudoKey, m_StringHeap, i, disposition, pEntry));
  339. m_dequeEntryClumps.AddToTail(pNewClump);
  340. pNewClump = NULL;
  341. ASSERT(disposition == CStringPoolEntryClump::eAdded);
  342. ASSERT(i == 0);
  343. m_cEntries++;
  344. }
  345. INTERNAL_ERROR_CHECK(pEntry != NULL);
  346. rulPosition = ulPosition;
  347. rStringOut = pEntry->Buffer;
  348. fSuccess = TRUE;
  349. Exit:
  350. if (pNewClump != NULL)
  351. FUSION_DELETE_SINGLETON(pNewClump);
  352. return fSuccess;
  353. }
  354. BOOL
  355. CStringPool::FillInStringArray(
  356. ULONG nArraySize,
  357. SXS_XML_STRING *prgStrings,
  358. ULONG &rcWritten
  359. )
  360. {
  361. BOOL fSuccess = FALSE;
  362. FN_TRACE_WIN32(fSuccess);
  363. ULONG i;
  364. CDequeIterator<CStringPoolEntryClump, FIELD_OFFSET(CStringPoolEntryClump, m_leEntryChain)> iter;
  365. if (nArraySize < (m_cEntries + 1))
  366. {
  367. ::SetLastError(ERROR_INSUFFICIENT_BUFFER);
  368. goto Exit;
  369. }
  370. iter.Rebind(&m_dequeEntryClumps);
  371. // We start filling in at index 1, not zero. We'll manually set zero to be invalid.
  372. prgStrings[0].Flags = SXS_XML_STRING_FLAG_INVALID;
  373. prgStrings[0].PseudoKey = 0;
  374. prgStrings[0].Length = 0;
  375. prgStrings[0].Buffer = NULL;
  376. i = 1;
  377. for (iter.Reset(); iter.More(); iter.Next())
  378. {
  379. ULONG cWrittenThisClump = 0;
  380. IFW32FALSE_EXIT(iter->FillInStringArray(nArraySize, prgStrings, i, cWrittenThisClump));
  381. INTERNAL_ERROR_CHECK((i + cWrittenThisClump) <= nArraySize);
  382. i += cWrittenThisClump;
  383. }
  384. rcWritten = i;
  385. fSuccess = TRUE;
  386. Exit:
  387. return fSuccess;
  388. }