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.

633 lines
21 KiB

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