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.

664 lines
20 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. ssgenctx.cpp
  5. Abstract:
  6. String section generation context object implementation.
  7. Author:
  8. Michael J. Grier (MGrier) 23-Feb-2000
  9. Revision History:
  10. --*/
  11. #include "stdinc.h"
  12. #include <windows.h>
  13. #include "sxsp.h"
  14. #include "ssgenctx.h"
  15. typedef struct _CALLBACKDATA
  16. {
  17. union
  18. {
  19. STRING_SECTION_GENERATION_CONTEXT_CBDATA_GETDATASIZE GetDataSize;
  20. STRING_SECTION_GENERATION_CONTEXT_CBDATA_GETDATA GetData;
  21. STRING_SECTION_GENERATION_CONTEXT_CBDATA_ENTRYDELETED EntryDeleted;
  22. STRING_SECTION_GENERATION_CONTEXT_CBDATA_GETUSERDATASIZE GetUserDataSize;
  23. STRING_SECTION_GENERATION_CONTEXT_CBDATA_GETUSERDATA GetUserData;
  24. } u;
  25. } CALLBACKDATA, *PCALLBACKDATA;
  26. BOOL CSSGenCtx::Create(
  27. PSTRING_SECTION_GENERATION_CONTEXT *SSGenContext,
  28. ULONG DataFormatVersion,
  29. BOOL CaseInSensitive,
  30. STRING_SECTION_GENERATION_CONTEXT_CALLBACK_FUNCTION CallbackFunction,
  31. PVOID CallbackContext
  32. )
  33. {
  34. BOOL fSuccess = FALSE;
  35. FN_TRACE_WIN32(fSuccess);
  36. CSSGenCtx *pSSGenCtx;
  37. IFALLOCFAILED_EXIT(pSSGenCtx = new CSSGenCtx);
  38. pSSGenCtx->m_CallbackFunction = CallbackFunction;
  39. pSSGenCtx->m_CallbackContext = CallbackContext;
  40. pSSGenCtx->m_CaseInSensitive = (CaseInSensitive != FALSE);
  41. pSSGenCtx->m_DataFormatVersion = DataFormatVersion;
  42. *SSGenContext = (PSTRING_SECTION_GENERATION_CONTEXT) pSSGenCtx;
  43. fSuccess = TRUE;
  44. Exit:
  45. return fSuccess;
  46. }
  47. CSSGenCtx::CSSGenCtx() : m_DoneAdding(false)
  48. {
  49. m_FirstEntry = NULL;
  50. m_LastEntry = NULL;
  51. m_EntryCount = 0;
  52. m_HashTableSize = 0;
  53. }
  54. CSSGenCtx::~CSSGenCtx()
  55. {
  56. CSxsPreserveLastError ple;
  57. CALLBACKDATA CBData;
  58. Entry *pEntry = m_FirstEntry;
  59. while (pEntry != NULL)
  60. {
  61. Entry *pNext = pEntry->m_Next;
  62. CBData.u.EntryDeleted.DataContext = pEntry->m_DataContext;
  63. (*m_CallbackFunction)(
  64. m_CallbackContext,
  65. STRING_SECTION_GENERATION_CONTEXT_CALLBACK_REASON_ENTRYDELETED,
  66. &CBData);
  67. FUSION_DELETE_SINGLETON(pEntry);
  68. pEntry = pNext;
  69. }
  70. ple.Restore();
  71. }
  72. BOOL
  73. CSSGenCtx::Add(
  74. PCWSTR String,
  75. SIZE_T Cch,
  76. PVOID DataContext,
  77. ULONG AssemblyRosterIndex,
  78. DWORD DuplicateErrorCode
  79. )
  80. {
  81. BOOL fSuccess = FALSE;
  82. FN_TRACE_WIN32(fSuccess);
  83. ULONG PseudoKey = 0;
  84. Entry *pEntry = NULL;
  85. PARAMETER_CHECK(DuplicateErrorCode != ERROR_SUCCESS);
  86. INTERNAL_ERROR_CHECK(!m_DoneAdding);
  87. if ((String != NULL) && (String[0] == L'\0'))
  88. String = NULL;
  89. IFW32FALSE_EXIT(::SxspHashString(String, Cch, &PseudoKey, m_CaseInSensitive));
  90. for (pEntry = m_FirstEntry; pEntry != NULL; pEntry = pEntry->m_Next)
  91. {
  92. if ((pEntry->m_PseudoKey == PseudoKey) &&
  93. (pEntry->m_StringBuffer.Cch() == Cch) &&
  94. (::FusionpCompareStrings(
  95. String,
  96. Cch,
  97. pEntry->m_StringBuffer,
  98. Cch,
  99. m_CaseInSensitive) == 0))
  100. {
  101. ::FusionpSetLastWin32Error(DuplicateErrorCode);
  102. pEntry = NULL;
  103. goto Exit;
  104. }
  105. }
  106. IFALLOCFAILED_EXIT(pEntry = new Entry);
  107. if (!pEntry->Initialize(String, Cch, PseudoKey, DataContext, AssemblyRosterIndex))
  108. goto Exit;
  109. if (m_LastEntry == NULL)
  110. m_FirstEntry = pEntry;
  111. else
  112. m_LastEntry->m_Next = pEntry;
  113. m_LastEntry = pEntry;
  114. pEntry = NULL;
  115. m_EntryCount++;
  116. fSuccess = TRUE;
  117. Exit:
  118. FUSION_DELETE_SINGLETON(pEntry);
  119. return fSuccess;
  120. }
  121. BOOL
  122. CSSGenCtx::Find(
  123. PCWSTR String,
  124. SIZE_T Cch,
  125. PVOID *DataContext,
  126. BOOL *Found
  127. )
  128. {
  129. BOOL fSuccess = FALSE;
  130. FN_TRACE_WIN32(fSuccess);
  131. ULONG PseudoKey = 0;
  132. Entry *pEntry = NULL;
  133. if (DataContext != NULL)
  134. *DataContext = NULL;
  135. if (Found != NULL)
  136. *Found = FALSE;
  137. if ((String != NULL) && (String[0] == L'\0'))
  138. String = NULL;
  139. PARAMETER_CHECK(Found != NULL);
  140. PARAMETER_CHECK((Cch == 0) || (String != NULL));
  141. IFW32FALSE_EXIT(::SxspHashString(String, Cch, &PseudoKey, m_CaseInSensitive));
  142. for (pEntry = m_FirstEntry; pEntry != NULL; pEntry = pEntry->m_Next)
  143. {
  144. if ((pEntry->m_PseudoKey == PseudoKey) &&
  145. (pEntry->m_StringBuffer.Cch() == Cch) &&
  146. (::FusionpCompareStrings(
  147. String,
  148. Cch,
  149. pEntry->m_StringBuffer,
  150. Cch,
  151. m_CaseInSensitive) == 0))
  152. break;
  153. }
  154. if (pEntry != NULL)
  155. {
  156. *Found = TRUE;
  157. if (DataContext != NULL)
  158. *DataContext = pEntry->m_DataContext;
  159. }
  160. fSuccess = TRUE;
  161. Exit:
  162. return fSuccess;
  163. }
  164. BOOL
  165. CSSGenCtx::DoneAdding()
  166. {
  167. if (!m_DoneAdding)
  168. {
  169. // This is where to really figure out the optimal hash table size
  170. // first level guess...
  171. if (m_EntryCount < 3)
  172. m_HashTableSize = 0;
  173. else if (m_EntryCount < 15)
  174. m_HashTableSize = 3;
  175. else if (m_EntryCount < 100)
  176. m_HashTableSize = 11;
  177. else
  178. m_HashTableSize = 101;
  179. m_DoneAdding = true;
  180. }
  181. return TRUE;
  182. }
  183. BOOL
  184. CSSGenCtx::GetSectionSize(
  185. PSIZE_T SizeOut
  186. )
  187. {
  188. BOOL fSuccess = FALSE;
  189. FN_TRACE_WIN32(fSuccess);
  190. SIZE_T UserDataSize = 0;
  191. SIZE_T HeaderSize = 0;
  192. SIZE_T EntryListSize = 0;
  193. SIZE_T EntryDataSize = 0;
  194. SIZE_T StringsSize = 0;
  195. SIZE_T HashTableSize = 0;
  196. CALLBACKDATA CBData;
  197. Entry *pEntry = NULL;
  198. if (SizeOut != NULL)
  199. *SizeOut = 0;
  200. PARAMETER_CHECK(SizeOut != NULL);
  201. HeaderSize = sizeof(ACTIVATION_CONTEXT_STRING_SECTION_HEADER);
  202. if (m_HashTableSize != 0)
  203. {
  204. //
  205. // The data for the hash table includes:
  206. //
  207. // 1. a small fixed sized struct representing the metadata for the hash
  208. // table (ACTIVATION_CONTEXT_STRING_SECTION_HASH_TABLE)
  209. //
  210. // 2. For each table bucket, a small struct pointing to the beginning of
  211. // the collision chain and the length of said chain
  212. // (ACTIVATION_CONTEXT_SECTION_STRING_HASH_BUCKET)
  213. //
  214. // 3. One entry in a collision chain per entry in the table. The entry
  215. // is a LONG offset from the beginning of the section.
  216. //
  217. HashTableSize = sizeof(ACTIVATION_CONTEXT_STRING_SECTION_HASH_TABLE) +
  218. (m_HashTableSize * sizeof(ACTIVATION_CONTEXT_STRING_SECTION_HASH_BUCKET)) +
  219. (m_EntryCount * sizeof(LONG));
  220. }
  221. CBData.u.GetUserDataSize.DataSize = 0;
  222. (*m_CallbackFunction)(m_CallbackContext, STRING_SECTION_GENERATION_CONTEXT_CALLBACK_REASON_GETUSERDATASIZE, &CBData);
  223. UserDataSize = ROUND_ACTCTXDATA_SIZE(CBData.u.GetUserDataSize.DataSize);
  224. EntryListSize = m_EntryCount * sizeof(ACTIVATION_CONTEXT_STRING_SECTION_ENTRY);
  225. for (pEntry = m_FirstEntry; pEntry != NULL; pEntry = pEntry->m_Next)
  226. {
  227. CBData.u.GetDataSize.DataContext = pEntry->m_DataContext;
  228. CBData.u.GetDataSize.DataSize = 0;
  229. (*m_CallbackFunction)(m_CallbackContext, STRING_SECTION_GENERATION_CONTEXT_CALLBACK_REASON_GETDATASIZE, &CBData);
  230. EntryDataSize += ROUND_ACTCTXDATA_SIZE(CBData.u.GetDataSize.DataSize);
  231. // Only allocate space for non-null strings. If the null string is a key in the table,
  232. // it takes up 0 bytes.
  233. if (pEntry->m_StringBuffer.Cch() != 0)
  234. StringsSize += ROUND_ACTCTXDATA_SIZE((pEntry->m_StringBuffer.Cch() + 1) * sizeof(WCHAR));
  235. }
  236. // If there's nothing to contain, don't even ask for space for the header.
  237. if ((UserDataSize == 0) && (m_EntryCount == 0))
  238. *SizeOut = 0;
  239. else
  240. *SizeOut = HeaderSize + UserDataSize + EntryListSize + EntryDataSize + StringsSize + HashTableSize;
  241. fSuccess = TRUE;
  242. Exit:
  243. return fSuccess;
  244. }
  245. BOOL
  246. CSSGenCtx::GetSectionData(
  247. SIZE_T BufferSize,
  248. PVOID Buffer,
  249. PSIZE_T BytesWritten
  250. )
  251. {
  252. BOOL fSuccess = FALSE;
  253. FN_TRACE_WIN32(fSuccess);
  254. SIZE_T BytesSoFar = 0;
  255. SIZE_T BytesLeft = BufferSize;
  256. PACTIVATION_CONTEXT_STRING_SECTION_HEADER Header;
  257. PACTIVATION_CONTEXT_STRING_SECTION_HASH_TABLE HashTable = NULL;
  258. PACTIVATION_CONTEXT_STRING_SECTION_HASH_BUCKET HashBucket = NULL;
  259. PLONG HashCollisionChain = NULL;
  260. CALLBACKDATA CBData;
  261. PVOID Cursor = NULL;
  262. SIZE_T RoundedSize;
  263. if (BytesWritten != NULL)
  264. *BytesWritten = 0;
  265. if (BytesLeft < sizeof(ACTIVATION_CONTEXT_STRING_SECTION_HEADER))
  266. {
  267. ::FusionpSetLastWin32Error(ERROR_INSUFFICIENT_BUFFER);
  268. goto Exit;
  269. }
  270. Header = (PACTIVATION_CONTEXT_STRING_SECTION_HEADER) Buffer;
  271. Cursor = (PVOID) (Header + 1);
  272. Header->Magic = ACTIVATION_CONTEXT_STRING_SECTION_MAGIC;
  273. Header->HeaderSize = sizeof(ACTIVATION_CONTEXT_STRING_SECTION_HEADER);
  274. Header->FormatVersion = ACTIVATION_CONTEXT_STRING_SECTION_FORMAT_WHISTLER;
  275. Header->DataFormatVersion = m_DataFormatVersion;
  276. Header->Flags = 0;
  277. if (m_CaseInSensitive)
  278. Header->Flags |= ACTIVATION_CONTEXT_STRING_SECTION_CASE_INSENSITIVE;
  279. Header->ElementCount = m_EntryCount;
  280. Header->ElementListOffset = 0; // filled in after we figure out the user data area
  281. Header->HashAlgorithm = SxspGetHashAlgorithm();
  282. Header->SearchStructureOffset = 0;
  283. Header->UserDataOffset = 0; // filled in below
  284. Header->UserDataSize = 0;
  285. BytesLeft -= sizeof(*Header);
  286. BytesSoFar += sizeof(*Header);
  287. CBData.u.GetUserDataSize.DataSize = 0;
  288. (*m_CallbackFunction)(m_CallbackContext, STRING_SECTION_GENERATION_CONTEXT_CALLBACK_REASON_GETUSERDATASIZE, &CBData);
  289. RoundedSize = ROUND_ACTCTXDATA_SIZE(CBData.u.GetUserDataSize.DataSize);
  290. if (RoundedSize > BytesLeft)
  291. {
  292. ::FusionpSetLastWin32Error(ERROR_INSUFFICIENT_BUFFER);
  293. goto Exit;
  294. }
  295. if (RoundedSize != 0)
  296. {
  297. CBData.u.GetUserData.SectionHeader = Header;
  298. CBData.u.GetUserData.BufferSize = RoundedSize;
  299. CBData.u.GetUserData.Buffer = Cursor;
  300. CBData.u.GetUserData.BytesWritten = 0;
  301. (*m_CallbackFunction)(m_CallbackContext, STRING_SECTION_GENERATION_CONTEXT_CALLBACK_REASON_GETUSERDATA, &CBData);
  302. ASSERT(CBData.u.GetUserData.BytesWritten <= RoundedSize);
  303. RoundedSize = ROUND_ACTCTXDATA_SIZE(CBData.u.GetUserData.BytesWritten);
  304. if (RoundedSize != 0)
  305. {
  306. BytesLeft -= RoundedSize;
  307. BytesSoFar += RoundedSize;
  308. Header->UserDataSize = static_cast<ULONG>(CBData.u.GetUserData.BytesWritten);
  309. Header->UserDataOffset = static_cast<LONG>(((LONG_PTR) Cursor) - ((LONG_PTR) Header));
  310. Cursor = (PVOID) (((ULONG_PTR) Cursor) + RoundedSize);
  311. }
  312. }
  313. // Finally the array of entries...
  314. if (m_EntryCount != 0)
  315. {
  316. PVOID DataCursor;
  317. PACTIVATION_CONTEXT_STRING_SECTION_ENTRY EntryArray;
  318. ULONG iEntry;
  319. Entry *SrcEntry;
  320. if (BytesLeft < (m_EntryCount * sizeof(ACTIVATION_CONTEXT_STRING_SECTION_ENTRY)))
  321. {
  322. ::FusionpSetLastWin32Error(ERROR_INSUFFICIENT_BUFFER);
  323. goto Exit;
  324. }
  325. BytesLeft -= (m_EntryCount * sizeof(ACTIVATION_CONTEXT_STRING_SECTION_ENTRY));
  326. BytesSoFar += (m_EntryCount * sizeof(ACTIVATION_CONTEXT_STRING_SECTION_ENTRY));
  327. EntryArray = (PACTIVATION_CONTEXT_STRING_SECTION_ENTRY) Cursor;
  328. Header->ElementListOffset = static_cast<LONG>(((LONG_PTR) EntryArray) - ((LONG_PTR) Header));
  329. DataCursor = (PVOID) (EntryArray + m_EntryCount);
  330. SrcEntry = m_FirstEntry;
  331. iEntry = 0;
  332. while (SrcEntry != NULL)
  333. {
  334. // Record the offset to this entry; we use it later during hash table population
  335. SrcEntry->m_EntryOffset = static_cast<LONG>(((LONG_PTR) &EntryArray[iEntry]) - ((LONG_PTR) Header));
  336. EntryArray[iEntry].PseudoKey = SrcEntry->m_PseudoKey;
  337. EntryArray[iEntry].AssemblyRosterIndex = SrcEntry->m_AssemblyRosterIndex;
  338. if (SrcEntry->m_StringBuffer.Cch() != 0)
  339. {
  340. const USHORT Cb = static_cast<USHORT>((SrcEntry->m_StringBuffer.Cch() + 1) * sizeof(WCHAR));
  341. RoundedSize = ROUND_ACTCTXDATA_SIZE(Cb);
  342. if (BytesLeft < RoundedSize)
  343. {
  344. ::FusionpSetLastWin32Error(ERROR_INSUFFICIENT_BUFFER);
  345. goto Exit;
  346. }
  347. EntryArray[iEntry].KeyLength = Cb - sizeof(WCHAR);
  348. EntryArray[iEntry].KeyOffset = static_cast<LONG>(((LONG_PTR) DataCursor) - ((LONG_PTR) Header));
  349. memcpy(
  350. DataCursor,
  351. static_cast<PCWSTR>(SrcEntry->m_StringBuffer),
  352. Cb);
  353. DataCursor = (PVOID) (((ULONG_PTR) DataCursor) + RoundedSize);
  354. BytesLeft -= Cb;
  355. BytesSoFar += Cb;
  356. }
  357. else
  358. {
  359. EntryArray[iEntry].KeyLength = 0;
  360. EntryArray[iEntry].KeyOffset = 0;
  361. }
  362. CBData.u.GetDataSize.DataContext = SrcEntry->m_DataContext;
  363. CBData.u.GetDataSize.DataSize = 0;
  364. (*m_CallbackFunction)(m_CallbackContext, STRING_SECTION_GENERATION_CONTEXT_CALLBACK_REASON_GETDATASIZE, &CBData);
  365. if (CBData.u.GetDataSize.DataSize != 0)
  366. {
  367. RoundedSize = ROUND_ACTCTXDATA_SIZE(CBData.u.GetDataSize.DataSize);
  368. if (BytesLeft < RoundedSize)
  369. {
  370. ::FusionpSetLastWin32Error(ERROR_INSUFFICIENT_BUFFER);
  371. goto Exit;
  372. }
  373. CBData.u.GetData.SectionHeader = Header;
  374. CBData.u.GetData.DataContext = SrcEntry->m_DataContext;
  375. CBData.u.GetData.BufferSize = RoundedSize;
  376. CBData.u.GetData.Buffer = DataCursor;
  377. CBData.u.GetData.BytesWritten = 0;
  378. (*m_CallbackFunction)(m_CallbackContext, STRING_SECTION_GENERATION_CONTEXT_CALLBACK_REASON_GETDATA, &CBData);
  379. if (CBData.u.GetData.BytesWritten != 0)
  380. {
  381. // If this assert fires, a contributor wrote past the bounds they
  382. // were given.
  383. ASSERT(CBData.u.GetData.BytesWritten <= RoundedSize);
  384. if (CBData.u.GetData.BytesWritten > RoundedSize)
  385. {
  386. // Probably we have memory corruption, but at least we'll bail and
  387. // avoid further scribbling on memory.
  388. ::FusionpDbgPrintEx(
  389. FUSION_DBG_LEVEL_ERROR,
  390. "SXS.DLL: String section data generation callback wrote more bytes than it should have. Bailing out and hoping memory isn't trashed.\n");
  391. ::FusionpSetLastWin32Error(ERROR_INTERNAL_ERROR);
  392. goto Exit;
  393. }
  394. RoundedSize = ROUND_ACTCTXDATA_SIZE(CBData.u.GetData.BytesWritten);
  395. BytesLeft -= RoundedSize;
  396. BytesSoFar += RoundedSize;
  397. EntryArray[iEntry].Offset = static_cast<LONG>(((LONG_PTR) DataCursor) - ((LONG_PTR) Header));
  398. EntryArray[iEntry].Length = static_cast<ULONG>(CBData.u.GetData.BytesWritten);
  399. DataCursor = (PVOID) (((ULONG_PTR) DataCursor) + RoundedSize);
  400. }
  401. else
  402. {
  403. EntryArray[iEntry].Offset = 0;
  404. EntryArray[iEntry].Length = 0;
  405. }
  406. }
  407. else
  408. {
  409. EntryArray[iEntry].Offset = 0;
  410. EntryArray[iEntry].Length = 0;
  411. }
  412. SrcEntry = SrcEntry->m_Next;
  413. iEntry++;
  414. }
  415. ASSERT(iEntry == m_EntryCount);
  416. // If we're not generating a hash table, let's sort 'em.
  417. if (m_HashTableSize == 0)
  418. {
  419. qsort(EntryArray, m_EntryCount, sizeof(ACTIVATION_CONTEXT_STRING_SECTION_ENTRY), &CSSGenCtx::CompareStringSectionEntries);
  420. Header->Flags |= ACTIVATION_CONTEXT_STRING_SECTION_ENTRIES_IN_PSEUDOKEY_ORDER;
  421. }
  422. Cursor = (PVOID) DataCursor;
  423. }
  424. // Write the hash table at the end. We do it here so that the placement of everything else is
  425. // already worked out.
  426. if (m_HashTableSize != 0)
  427. {
  428. ULONG iBucket;
  429. Entry *pEntry;
  430. ULONG cCollisions;
  431. if (BytesLeft < sizeof(ACTIVATION_CONTEXT_STRING_SECTION_HASH_TABLE))
  432. {
  433. ::FusionpSetLastWin32Error(ERROR_INSUFFICIENT_BUFFER);
  434. goto Exit;
  435. }
  436. HashTable = (PACTIVATION_CONTEXT_STRING_SECTION_HASH_TABLE) Cursor;
  437. Cursor = (PVOID) (HashTable + 1);
  438. BytesLeft -= sizeof(ACTIVATION_CONTEXT_STRING_SECTION_HASH_TABLE);
  439. BytesSoFar += sizeof(ACTIVATION_CONTEXT_STRING_SECTION_HASH_TABLE);
  440. if (BytesLeft < (m_HashTableSize * sizeof(ACTIVATION_CONTEXT_STRING_SECTION_HASH_BUCKET)))
  441. {
  442. ::FusionpSetLastWin32Error(ERROR_INSUFFICIENT_BUFFER);
  443. goto Exit;
  444. }
  445. HashBucket = (PACTIVATION_CONTEXT_STRING_SECTION_HASH_BUCKET) Cursor;
  446. Cursor = (PVOID) (HashBucket + m_HashTableSize);
  447. BytesLeft -= (m_HashTableSize * sizeof(ACTIVATION_CONTEXT_STRING_SECTION_HASH_BUCKET));
  448. BytesSoFar += (m_HashTableSize * sizeof(ACTIVATION_CONTEXT_STRING_SECTION_HASH_BUCKET));
  449. Header->SearchStructureOffset = static_cast<LONG>(((LONG_PTR) HashTable) - ((LONG_PTR) Header));
  450. HashTable->BucketTableEntryCount = m_HashTableSize;
  451. HashTable->BucketTableOffset = static_cast<LONG>(((LONG_PTR) HashBucket) - ((LONG_PTR) Header));
  452. if (BytesLeft < (m_EntryCount * sizeof(LONG)))
  453. {
  454. ::FusionpSetLastWin32Error(ERROR_INSUFFICIENT_BUFFER);
  455. goto Exit;
  456. }
  457. HashCollisionChain = (PLONG) Cursor;
  458. Cursor = (PVOID) (HashCollisionChain + m_EntryCount);
  459. BytesLeft -= (m_EntryCount * sizeof(LONG));
  460. BytesSoFar += (m_EntryCount * sizeof(LONG));
  461. // In a disgusting move, we need to iterate over the hash buckets (not elements)
  462. // finding which entries would go into the bucket so that we can build up the
  463. // collision chain.
  464. for (pEntry = m_FirstEntry; pEntry != NULL; pEntry = pEntry->m_Next)
  465. pEntry->m_HashBucketIndex = pEntry->m_PseudoKey % m_HashTableSize;
  466. cCollisions = 0;
  467. for (iBucket=0; iBucket<m_HashTableSize; iBucket++)
  468. {
  469. bool fFirstForThisBucket = true;
  470. HashBucket[iBucket].ChainCount = 0;
  471. HashBucket[iBucket].ChainOffset = 0;
  472. for (pEntry = m_FirstEntry; pEntry != NULL; pEntry = pEntry->m_Next)
  473. {
  474. if (pEntry->m_HashBucketIndex == iBucket)
  475. {
  476. if (fFirstForThisBucket)
  477. {
  478. HashBucket[iBucket].ChainOffset = static_cast<LONG>(((LONG_PTR) &HashCollisionChain[cCollisions]) - ((LONG_PTR) Header));
  479. fFirstForThisBucket = false;
  480. }
  481. HashBucket[iBucket].ChainCount++;
  482. HashCollisionChain[cCollisions++] = pEntry->m_EntryOffset;
  483. }
  484. }
  485. }
  486. }
  487. if (BytesWritten != NULL)
  488. *BytesWritten = BytesSoFar;
  489. fSuccess = TRUE;
  490. Exit:
  491. return fSuccess;
  492. }
  493. int
  494. __cdecl
  495. CSSGenCtx::CompareStringSectionEntries(
  496. const void *elem1,
  497. const void *elem2
  498. )
  499. {
  500. PCACTIVATION_CONTEXT_STRING_SECTION_ENTRY pEntry1 = reinterpret_cast<PCACTIVATION_CONTEXT_STRING_SECTION_ENTRY>(elem1);
  501. PCACTIVATION_CONTEXT_STRING_SECTION_ENTRY pEntry2 = reinterpret_cast<PCACTIVATION_CONTEXT_STRING_SECTION_ENTRY>(elem2);
  502. if (pEntry1->PseudoKey < pEntry2->PseudoKey)
  503. return -1;
  504. else if (pEntry1->PseudoKey == pEntry2->PseudoKey)
  505. return 0;
  506. return 1;
  507. }
  508. BOOL
  509. CSSGenCtx::Entry::Initialize(
  510. PCWSTR String,
  511. SIZE_T Cch,
  512. ULONG PseudoKey,
  513. PVOID DataContext,
  514. ULONG AssemblyRosterIndex
  515. )
  516. {
  517. BOOL fSuccess = FALSE;
  518. FN_TRACE_WIN32(fSuccess);
  519. IFW32FALSE_EXIT(m_StringBuffer.Win32Assign(String, Cch));
  520. m_DataContext = DataContext;
  521. m_PseudoKey = PseudoKey;
  522. m_AssemblyRosterIndex = AssemblyRosterIndex;
  523. fSuccess = TRUE;
  524. Exit:
  525. return fSuccess;
  526. }