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.

1212 lines
29 KiB

  1. // Copyright (C) Microsoft Corporation 1993-1997
  2. #include "header.H"
  3. #ifndef _CTABLE_INCLUDED
  4. #include "ctable.h"
  5. #endif
  6. const int TABLE_ALLOC_SIZE = 4096; // allocate in page increments
  7. const int MAX_POINTERS = (1024 * 1024); // 1 meg, 260,000+ strings
  8. const int MAX_STRINGS = (10 * 1024 * 1024) - 4096L; // 10 megs
  9. // Align on 32 bits for Intel, 64 bits for MIPS
  10. #ifdef _X86_
  11. const int ALIGNMENT = 4;
  12. #else
  13. const int ALIGNMENT = 8;
  14. #endif
  15. #ifdef _DEBUG
  16. int g_cbTableAllocated;
  17. int g_cbTableReserved;
  18. int g_cTables;
  19. #endif
  20. CTable::CTable()
  21. {
  22. cbMaxBase = MAX_STRINGS;
  23. cbMaxTable = MAX_POINTERS;
  24. InitializeTable();
  25. #ifdef _DEBUG
  26. g_cTables++;
  27. #endif
  28. }
  29. // Use this constructor to reduce reserved memory
  30. CTable::CTable(int cbStrings)
  31. {
  32. cbMaxBase = cbStrings;
  33. cbMaxTable = cbStrings / 4;
  34. InitializeTable();
  35. #ifdef _DEBUG
  36. g_cTables++;
  37. #endif
  38. }
  39. /***************************************************************************
  40. FUNCTION: =
  41. PURPOSE: Copies a table -- only works with tables containing ONLY
  42. strings. Won't work with tables that combined data with
  43. the strings.
  44. PARAMETERS:
  45. tblSrc
  46. RETURNS:
  47. COMMENTS:
  48. MODIFICATION DATES:
  49. 26-Mar-1994 [ralphw]
  50. ***************************************************************************/
  51. #pragma warning(disable:4172) // returning address of local variable or temporary
  52. const CTable& CTable::operator =(const CTable& tblSrc)
  53. {
  54. Empty();
  55. int srcpos = 1;
  56. while (srcpos < tblSrc.endpos) {
  57. if (endpos >= maxpos)
  58. IncreaseTableBuffer();
  59. if (endpos >= maxpos)
  60. {
  61. return NULL;
  62. }
  63. if ((ppszTable[endpos] =
  64. TableMalloc((int)strlen(tblSrc.ppszTable[srcpos]) + 1)) == NULL) {
  65. OOM();
  66. return *this;
  67. }
  68. strcpy(ppszTable[endpos++], tblSrc.ppszTable[srcpos++]);
  69. }
  70. return *this;
  71. }
  72. /***************************************************************************
  73. FUNCTION: ~CTable
  74. PURPOSE: Close the table and free all memory associated with it
  75. RETURNS:
  76. COMMENTS:
  77. MODIFICATION DATES:
  78. 26-Feb-1990 [ralphw]
  79. 27-Mar-1990 [ralphw]
  80. Pass the address of the handle, so that we can set it to NULL.
  81. This eliminates the chance of using a handle after it's memory
  82. has been freed.
  83. ***************************************************************************/
  84. CTable::~CTable()
  85. {
  86. Cleanup();
  87. #ifdef _DEBUG
  88. g_cTables--;
  89. #endif
  90. }
  91. void CTable::Cleanup(void)
  92. {
  93. if (pszBase) {
  94. VirtualFree(pszBase, cbStrings, MEM_DECOMMIT);
  95. VirtualFree(pszBase, 0, MEM_RELEASE);
  96. }
  97. if (ppszTable) {
  98. VirtualFree(ppszTable, cbPointers, MEM_DECOMMIT);
  99. VirtualFree(ppszTable, 0, MEM_RELEASE);
  100. }
  101. if (m_pFreed)
  102. lcClearFree(&m_pFreed);
  103. #ifdef _DEBUG
  104. g_cbTableAllocated -= (cbPointers + cbStrings);
  105. g_cbTableReserved -= (cbMaxBase + cbMaxTable);
  106. #endif
  107. }
  108. /***************************************************************************
  109. FUNCTION: CTable::Empty
  110. PURPOSE: Empties the current table by freeing all memory, then
  111. recreating the table using the default size
  112. PARAMETERS:
  113. void
  114. RETURNS:
  115. COMMENTS:
  116. MODIFICATION DATES:
  117. 22-Feb-1994 [ralphw]
  118. ***************************************************************************/
  119. void CTable::Empty(void)
  120. {
  121. Cleanup();
  122. InitializeTable();
  123. }
  124. /***************************************************************************
  125. FUNCTION: GetString
  126. PURPOSE: get a line from the table
  127. RETURNS: FALSE if there are no more lines
  128. COMMENTS:
  129. If no strings have been placed into the table, the return value
  130. is FALSE.
  131. MODIFICATION DATES:
  132. 01-Jan-1990 [ralphw]
  133. ***************************************************************************/
  134. BOOL CTable::GetString(PSTR pszDst)
  135. {
  136. *pszDst = 0; // clear the line no matter what happens
  137. if (curpos >= endpos)
  138. return FALSE;
  139. strcpy(pszDst, (PCSTR) ppszTable[curpos++]);
  140. return TRUE;
  141. }
  142. BOOL CTable::GetString(PSTR pszDst, int pos) const
  143. {
  144. *pszDst = 0; // clear the line no matter what happens
  145. if (pos >= endpos || pos == 0)
  146. return FALSE;
  147. strcpy(pszDst, (PCSTR) ppszTable[pos]);
  148. return TRUE;
  149. }
  150. BOOL CTable::GetIntAndString(int* plVal, PSTR pszDst)
  151. {
  152. *pszDst = 0; // clear the line no matter what happens
  153. if (curpos >= endpos)
  154. return FALSE;
  155. *plVal = *(int *) ppszTable[curpos];
  156. strcpy(pszDst, (PCSTR) ppszTable[curpos++] + sizeof(int));
  157. return TRUE;
  158. }
  159. /***************************************************************************
  160. FUNCTION: AddString
  161. PURPOSE: Add a string to a table
  162. RETURNS:
  163. COMMENTS:
  164. MODIFICATION DATES:
  165. 01-Jan-1990 [ralphw]
  166. ***************************************************************************/
  167. int CTable::AddString(PCSTR pszString)
  168. {
  169. if (!pszString)
  170. return 0;
  171. if (endpos >= maxpos)
  172. IncreaseTableBuffer();
  173. if (endpos >= maxpos)
  174. return 0;
  175. if ((ppszTable[endpos] =
  176. TableMalloc((int)strlen(pszString) + 1)) == NULL)
  177. return 0;
  178. strcpy(ppszTable[endpos], pszString);
  179. return endpos++;
  180. }
  181. int CTable::AddString(PCWSTR pszString)
  182. {
  183. if (!pszString)
  184. return 0;
  185. if (endpos >= maxpos)
  186. IncreaseTableBuffer();
  187. if (endpos >= maxpos)
  188. return 0;
  189. if ((ppszTable[endpos] =
  190. TableMalloc((int)lstrlenW(pszString) + 2)) == NULL)
  191. return 0;
  192. lstrcpyW((PWSTR) ppszTable[endpos], pszString);
  193. return endpos++;
  194. }
  195. int CTable::AddData(int cb, const void* pdata)
  196. {
  197. if (endpos >= maxpos)
  198. IncreaseTableBuffer();
  199. if (endpos >= maxpos)
  200. return 0;
  201. if ((ppszTable[endpos] = TableMalloc(cb)) == NULL)
  202. return 0;
  203. if (pdata)
  204. CopyMemory(ppszTable[endpos], pdata, cb);
  205. return endpos++;
  206. }
  207. int CTable::AddIntAndString(int lVal, PCSTR pszString)
  208. {
  209. if (endpos >= maxpos)
  210. IncreaseTableBuffer();
  211. if (endpos >= maxpos)
  212. return 0;
  213. if ((ppszTable[endpos] =
  214. TableMalloc((int)strlen(pszString) + 1 + (int)sizeof(int))) == NULL)
  215. return 0;
  216. *(int*) ppszTable[endpos] = lVal;
  217. strcpy(ppszTable[endpos] + sizeof(int), pszString);
  218. return endpos++;
  219. }
  220. /***************************************************************************
  221. FUNCTION: IncreaseTableBuffer
  222. PURPOSE: Called when we need more room for string pointers
  223. PARAMETERS:
  224. RETURNS:
  225. COMMENTS:
  226. MODIFICATION DATES:
  227. 23-Feb-1992 [ralphw]
  228. ***************************************************************************/
  229. void CTable::IncreaseTableBuffer(void)
  230. {
  231. ASSERT(cbPointers < cbMaxTable);
  232. if (!VirtualAlloc((PBYTE) ppszTable + cbPointers, TABLE_ALLOC_SIZE,
  233. MEM_COMMIT, PAGE_READWRITE)) {
  234. OOM();
  235. return;
  236. }
  237. cbPointers += TABLE_ALLOC_SIZE;
  238. #ifdef _DEBUG
  239. g_cbTableAllocated += TABLE_ALLOC_SIZE;
  240. #endif
  241. maxpos = cbPointers / sizeof(PSTR);
  242. }
  243. /***************************************************************************
  244. FUNCTION: TableMalloc
  245. PURPOSE: Suballocate memory
  246. RETURNS:
  247. pointer to the memory
  248. COMMENTS:
  249. Instead of allocating memory for each string, memory is used from 4K
  250. blocks. When the table is freed, all memory is freed as a single
  251. unit. This has the advantage of speed for adding strings, speed for
  252. freeing all strings, and low memory overhead to save strings.
  253. MODIFICATION DATES:
  254. 26-Feb-1990 [ralphw]
  255. 26-Mar-1994 [ralphw]
  256. Ported to 32-bits
  257. ***************************************************************************/
  258. PSTR CTable::TableMalloc(int cb)
  259. {
  260. /*
  261. * Align allocation request so that all allocations fall on an
  262. * alignment boundary (32 bits for Intel, 64 bits for MIPS).
  263. */
  264. cb = (cb & (ALIGNMENT - 1)) ?
  265. cb / ALIGNMENT * ALIGNMENT + ALIGNMENT : cb;
  266. if (m_pFreed) {
  267. // First look for an exact match
  268. for (int i = 0; i < m_cFreedItems; i++) {
  269. ASSERT_COMMENT(m_pFreed[i].cb, "This memory has been used again -- it shouldn't be in the array");
  270. if (cb > m_pFreed[i].cb)
  271. break;
  272. if (cb == m_pFreed[i].cb)
  273. goto GotAMatch;
  274. }
  275. // Couldn't find an exact match, so find the first one that fits
  276. for (i--; i >= 0; i--) {
  277. ASSERT_COMMENT(m_pFreed[i].cb, "This memory has been used again -- it shouldn't be in the array");
  278. if (cb < m_pFreed[i].cb) {
  279. // If there's more then 32 bytes left, then suballoc
  280. if (cb + 32 < m_pFreed[i].cb) {
  281. PSTR psz = (PSTR) m_pFreed[i].pMem;
  282. m_pFreed[i].pMem += cb;
  283. m_pFreed[i].cb -= cb;
  284. // Keep the sizes sorted
  285. QSort(m_pFreed, m_cFreedItems, sizeof(TABLE_FREED_MEMORY),
  286. CompareIntPointers);
  287. return psz;
  288. }
  289. GotAMatch:
  290. m_cFreedItems--;
  291. PSTR psz = (PSTR) m_pFreed[i].pMem;
  292. if (i < m_cFreedItems) {
  293. MemMove(&m_pFreed[i], &m_pFreed[i + 1],
  294. sizeof(TABLE_FREED_MEMORY) * (m_cFreedItems - i));
  295. #ifdef _DEBUG
  296. m_pFreed[m_cFreedItems].cb = 0;
  297. #endif
  298. }
  299. #ifdef _DEBUG
  300. else
  301. m_pFreed[i].cb = 0;
  302. #endif
  303. return psz;
  304. }
  305. }
  306. }
  307. if (CurOffset + cb >= cbStrings) {
  308. int cbNew = cbStrings + TABLE_ALLOC_SIZE;
  309. while (cbNew < CurOffset + cb)
  310. cbNew += TABLE_ALLOC_SIZE;
  311. // We rely on VirtualAlloc to fail if cbStrings exceeds cbMaxBase
  312. if(cbNew > cbMaxBase)
  313. {
  314. ASSERT_COMMENT(FALSE, "Table memory overflow");
  315. return NULL;
  316. }
  317. if (!VirtualAlloc(pszBase + cbStrings, cbNew - cbStrings,
  318. MEM_COMMIT, PAGE_READWRITE)) {
  319. ASSERT_COMMENT(FALSE, "Table memory overflow");
  320. OOM();
  321. return NULL;
  322. }
  323. #ifdef _DEBUG
  324. g_cbTableAllocated += (cbNew - cbStrings);
  325. #endif
  326. cbStrings = cbNew;
  327. }
  328. int offset = CurOffset;
  329. CurOffset += cb;
  330. return pszBase + offset;
  331. }
  332. /***************************************************************************
  333. FUNCTION: SetPosition
  334. PURPOSE: Sets the position for reading from the table
  335. RETURNS:
  336. COMMENTS:
  337. MODIFICATION DATES:
  338. 26-Feb-1990 [ralphw]
  339. 16-Oct-1990 [ralphw]
  340. If table position is to large, set to the end of the table,
  341. not the last line.
  342. ***************************************************************************/
  343. BOOL FASTCALL CTable::SetPosition(int pos)
  344. {
  345. if (pos >= endpos)
  346. pos = endpos;
  347. curpos = ((pos == 0) ? 1 : pos);
  348. return TRUE;
  349. }
  350. /***************************************************************************
  351. FUNCTION: CTable::IsHashInTable
  352. PURPOSE: Find out if the hash number exists in the table
  353. PARAMETERS:
  354. hash
  355. RETURNS:
  356. COMMENTS:
  357. Assumes case-insensitive hash number, and no collisions
  358. MODIFICATION DATES:
  359. 05-Feb-1997 [ralphw]
  360. ***************************************************************************/
  361. int CTable::IsHashInTable(HASH hash)
  362. {
  363. for (int i = 1; i < endpos; i++) {
  364. if (hash == *(HASH *) ppszTable[i])
  365. return i;
  366. }
  367. return 0;
  368. }
  369. /***************************************************************************
  370. FUNCTION: IsStringInTable
  371. PURPOSE: Determine if the string is already in the table
  372. RETURNS: position if the string is already in the table,
  373. 0 if the string isn't found
  374. COMMENTS:
  375. The comparison is case-insensitive, and is considerably
  376. slower then IsCSStringInTable
  377. if lcid has been set, NLS string comparisons are used
  378. MODIFICATION DATES:
  379. 02-Mar-1990 [ralphw]
  380. ***************************************************************************/
  381. int CTable::IsStringInTable(PCSTR pszString) const
  382. {
  383. int i;
  384. if (!lcid) {
  385. /*
  386. * Skip over as many strings as we can by just checking the first
  387. * letter. This avoids the overhead of the _strcmpi() function call.
  388. */
  389. char chLower = ToLower(*pszString);
  390. char chUpper = ToUpper(*pszString);
  391. for (i = 1; i < endpos; i++) {
  392. if ((*ppszTable[i] == chLower || *ppszTable[i] == chUpper)
  393. && lstrcmpi(ppszTable[i], pszString) == 0)
  394. return i;
  395. }
  396. }
  397. else { // Use NLS string comparison
  398. for (i = 1; i < endpos; i++) {
  399. if (CompareStringA(lcid, fsCompareI | NORM_IGNORECASE,
  400. pszString, -1, ppszTable[i], -1) == 1)
  401. return i;
  402. }
  403. }
  404. return 0;
  405. }
  406. /***************************************************************************
  407. FUNCTION: CTable::IsCSStringInTable
  408. PURPOSE: Case-sensitive search for a string in a table
  409. PARAMETERS:
  410. pszString
  411. RETURNS:
  412. COMMENTS:
  413. MODIFICATION DATES:
  414. 12-Jun-1994 [ralphw]
  415. ***************************************************************************/
  416. int CTable::IsCSStringInTable(PCSTR pszString) const
  417. {
  418. char szBuf[sizeof(DWORD) + 1];
  419. DWORD cmp;
  420. if (strlen(pszString) < sizeof(DWORD)) {
  421. ZeroMemory(szBuf, sizeof(DWORD) + 1);
  422. strcpy(szBuf, pszString);
  423. cmp = *(DWORD*) szBuf;
  424. }
  425. else
  426. cmp = *(DWORD*) pszString;
  427. for (int i = 1; i < endpos; i++) {
  428. if (cmp == *(DWORD*) ppszTable[i] &&
  429. strcmp(ppszTable[i], pszString) == 0)
  430. return i;
  431. }
  432. return 0;
  433. }
  434. int CTable::IsStringInTable(HASH hash, PCSTR pszString) const
  435. {
  436. for (int i = 1; i < endpos; i++) {
  437. if (hash == *(HASH *) ppszTable[i] &&
  438. // this avoids the very rare hash collision
  439. strcmp(ppszTable[i] + sizeof(HASH), pszString) == 0)
  440. return i;
  441. }
  442. return 0;
  443. }
  444. /***************************************************************************
  445. FUNCTION: AddDblToTable
  446. PURPOSE: Add two strings to the table
  447. RETURNS:
  448. COMMENTS:
  449. This function checks to see if the second string has already been
  450. added, and if so, it merely sets the pointer to the original string,
  451. rather then allocating memory for a new copy of the string.
  452. MODIFICATION DATES:
  453. 08-Mar-1991 [ralphw]
  454. ***************************************************************************/
  455. int CTable::AddString(PCSTR pszStr1, PCSTR pszStr2)
  456. {
  457. int ui;
  458. AddString(pszStr1);
  459. if ((ui = IsSecondaryStringInTable(pszStr2)) != 0) {
  460. if (endpos >= maxpos)
  461. IncreaseTableBuffer();
  462. ppszTable[endpos++] = ppszTable[ui];
  463. return endpos - 1;
  464. }
  465. else {
  466. return AddString(pszStr2);
  467. }
  468. }
  469. /***************************************************************************
  470. FUNCTION: IsPrimaryStringInTable
  471. PURPOSE:
  472. RETURNS:
  473. COMMENTS:
  474. MODIFICATION DATES:
  475. 03-Apr-1991 [ralphw]
  476. ***************************************************************************/
  477. int CTable::IsPrimaryStringInTable(PCSTR pszString) const
  478. {
  479. int i;
  480. /*
  481. * Skip over as many strings as we can by just checking the first
  482. * letter. This avoids the overhead of the _strcmpi() function call.
  483. * Since the strings aren't necessarily alphabetized, we must trudge
  484. * through the entire table using the _strcmpi() as soon as the first
  485. * character matches.
  486. */
  487. char chLower = ToLower(*pszString);
  488. char chUpper = ToUpper(*pszString);
  489. for (i = 1; i < endpos; i += 2) {
  490. if (*ppszTable[i] == chLower || *ppszTable[i] == chUpper)
  491. break;
  492. }
  493. for (; i < endpos; i += 2) {
  494. if (lstrcmpi(ppszTable[i], pszString) == 0)
  495. return i;
  496. }
  497. return 0;
  498. }
  499. /***************************************************************************
  500. FUNCTION: IsSecondaryStringInTable
  501. PURPOSE:
  502. RETURNS:
  503. COMMENTS:
  504. MODIFICATION DATES:
  505. 03-Apr-1991 [ralphw]
  506. ***************************************************************************/
  507. int CTable::IsSecondaryStringInTable(PCSTR pszString) const
  508. {
  509. int i;
  510. /*
  511. * Skip over as many strings as we can by just checking the first
  512. * letter. This avoids the overhead of the _strcmpi() function call.
  513. * Since the strings aren't necessarily alphabetized, we must trudge
  514. * through the entire table using the _strcmpi() as soon as the first
  515. * character matches.
  516. */
  517. char chLower = ToLower(*pszString);
  518. char chUpper = ToUpper(*pszString);
  519. for (i = 2; i < endpos; i += 2) {
  520. if (*ppszTable[i] == chLower || *ppszTable[i] == chUpper)
  521. break;
  522. }
  523. for (; i < endpos; i += 2) {
  524. if (lstrcmpi(ppszTable[i], pszString) == 0)
  525. return i;
  526. }
  527. return 0;
  528. }
  529. /***************************************************************************
  530. FUNCTION: SortTable
  531. PURPOSE: Sort the current buffer
  532. RETURNS:
  533. COMMENTS:
  534. MODIFICATION DATES:
  535. 01-Jan-1990 [ralphw]
  536. ***************************************************************************/
  537. void CTable::SortTable(int sortoffset)
  538. {
  539. if (endpos < 3) // don't sort one entry
  540. return;
  541. m_sortoffset = sortoffset;
  542. if (lcid) {
  543. fsSortFlags = fsCompare;
  544. doLcidSort(1, (int) endpos - 1);
  545. }
  546. else
  547. doSort(1, (int) endpos - 1);
  548. }
  549. /***************************************************************************
  550. FUNCTION: doSort
  551. PURPOSE:
  552. RETURNS:
  553. COMMENTS:
  554. Use QSORT algorithm
  555. MODIFICATION DATES:
  556. 27-Mar-1990 [ralphw]
  557. ***************************************************************************/
  558. void CTable::doSort(int left, int right)
  559. {
  560. int last;
  561. if (left >= right) // return if nothing to sort
  562. return;
  563. // REVIEW: should be a flag before trying this -- we may already know
  564. // that they won't be in order.
  565. // Only sort if there are elements out of order.
  566. j = right - 1;
  567. while (j >= left) {
  568. // REVIEW: strcmp is NOT case-sensitive!!!
  569. if (strcmp(ppszTable[j] + m_sortoffset,
  570. ppszTable[j + 1] + m_sortoffset) > 0)
  571. break;
  572. else
  573. j--;
  574. }
  575. if (j < left)
  576. return;
  577. sTmp = (left + right) / 2;
  578. pszTmp = ppszTable[left];
  579. ppszTable[left] = ppszTable[sTmp];
  580. ppszTable[sTmp] = pszTmp;
  581. last = left;
  582. for (j = left + 1; j <= right; j++) {
  583. if (strcmp(ppszTable[j] + m_sortoffset,
  584. ppszTable[left] + m_sortoffset) < 0) {
  585. sTmp = ++last;
  586. pszTmp = ppszTable[sTmp];
  587. ppszTable[sTmp] = ppszTable[j];
  588. ppszTable[j] = pszTmp;
  589. }
  590. }
  591. pszTmp = ppszTable[left];
  592. ppszTable[left] = ppszTable[last];
  593. ppszTable[last] = pszTmp;
  594. /*
  595. * REVIEW: we need to add some sort of stack depth check to prevent
  596. * overflow of the stack.
  597. */
  598. if (left < last - 1)
  599. doSort(left, last - 1);
  600. if (last + 1 < right)
  601. doSort(last + 1, right);
  602. }
  603. /***************************************************************************
  604. FUNCTION: CTable::doLcidSort
  605. PURPOSE: Sort using CompareStringA
  606. PARAMETERS:
  607. left
  608. right
  609. RETURNS:
  610. COMMENTS:
  611. MODIFICATION DATES:
  612. 03-Jun-1994 [ralphw]
  613. ***************************************************************************/
  614. void CTable::doLcidSort(int left, int right)
  615. {
  616. int last;
  617. #ifdef _DEBUG
  618. static BOOL fWarned = FALSE;
  619. if (!fWarned) {
  620. char szBuf[256];
  621. wsprintf(szBuf, "*** fsSortFlags == %u", fsSortFlags);
  622. DBWIN(szBuf);
  623. fWarned = TRUE;
  624. }
  625. #endif
  626. if (left >= right) // return if nothing to sort
  627. return;
  628. // REVIEW: should be a flag before trying this -- we may already know
  629. // that they won't be in order.
  630. // Only sort if there are elements out of order.
  631. j = right - 1;
  632. while (j >= left) {
  633. if (CompareStringA(lcid, fsSortFlags, ppszTable[j] + m_sortoffset, -1,
  634. ppszTable[j + 1] + m_sortoffset, -1) > 2)
  635. break;
  636. else
  637. j--;
  638. }
  639. if (j < left)
  640. return;
  641. sTmp = (left + right) / 2;
  642. pszTmp = ppszTable[left];
  643. ppszTable[left] = ppszTable[sTmp];
  644. ppszTable[sTmp] = pszTmp;
  645. last = left;
  646. for (j = left + 1; j <= right; j++) {
  647. if (CompareStringA(lcid, fsSortFlags, ppszTable[j] + m_sortoffset, -1,
  648. ppszTable[left] + m_sortoffset, -1) < 2) {
  649. sTmp = ++last;
  650. pszTmp = ppszTable[sTmp];
  651. ppszTable[sTmp] = ppszTable[j];
  652. ppszTable[j] = pszTmp;
  653. }
  654. }
  655. pszTmp = ppszTable[left];
  656. ppszTable[left] = ppszTable[last];
  657. ppszTable[last] = pszTmp;
  658. if (left < last - 1)
  659. doLcidSort(left, last - 1);
  660. if (last + 1 < right)
  661. doLcidSort(last + 1, right);
  662. }
  663. /***************************************************************************
  664. FUNCTION: CTable::InitializeTable
  665. PURPOSE: Initializes the table
  666. PARAMETERS:
  667. uInitialSize
  668. RETURNS:
  669. COMMENTS:
  670. Called by constructor and Empty()
  671. MODIFICATION DATES:
  672. 23-Feb-1994 [ralphw]
  673. ***************************************************************************/
  674. void CTable::InitializeTable(void)
  675. {
  676. // Allocate memory for the strings
  677. pszBase = (PSTR) VirtualAlloc(NULL, cbMaxBase, MEM_RESERVE,
  678. PAGE_READWRITE);
  679. if (!pszBase) {
  680. ASSERT_COMMENT(FALSE, "Out of virtual address space");
  681. OOM();
  682. return;
  683. }
  684. if (!VirtualAlloc(pszBase, cbStrings = TABLE_ALLOC_SIZE, MEM_COMMIT,
  685. PAGE_READWRITE))
  686. OOM();
  687. // Allocate memory for the string pointers
  688. ppszTable = (PSTR *) VirtualAlloc(NULL, cbMaxTable, MEM_RESERVE,
  689. PAGE_READWRITE);
  690. if (!ppszTable) {
  691. OOM();
  692. return;
  693. }
  694. if (!VirtualAlloc(ppszTable, cbPointers = TABLE_ALLOC_SIZE, MEM_COMMIT,
  695. PAGE_READWRITE))
  696. OOM();
  697. #ifdef _DEBUG
  698. g_cbTableAllocated += (cbStrings + cbPointers);
  699. g_cbTableReserved += (cbMaxBase + cbMaxTable);
  700. #endif
  701. curpos = 1; // set to one so that sorting works
  702. endpos = 1;
  703. maxpos = cbPointers / sizeof(PSTR);
  704. CurOffset = 0;
  705. lcid = 0;
  706. m_pFreed = NULL;
  707. }
  708. void FASTCALL CTable::SetSorting(LCID lcid, DWORD fsCompareI, DWORD fsCompare)
  709. {
  710. this->lcid = lcid;
  711. this->fsCompareI = fsCompareI;
  712. this->fsCompare = fsCompare;
  713. }
  714. /***************************************************************************
  715. FUNCTION: CTable::AddIndexHitString
  716. PURPOSE: Add an index, a hit number, and a string
  717. PARAMETERS:
  718. index
  719. hit
  720. pszString
  721. RETURNS:
  722. COMMENTS:
  723. MODIFICATION DATES:
  724. 27-Oct-1993 [ralphw]
  725. ***************************************************************************/
  726. void CTable::AddIndexHitString(UINT index, UINT hit, PCSTR pszString)
  727. {
  728. if (endpos >= maxpos)
  729. IncreaseTableBuffer();
  730. if ((ppszTable[endpos] =
  731. TableMalloc((int)strlen(pszString) + 1 + (int)sizeof(UINT) * 2)) == NULL)
  732. return;
  733. *(UINT*) ppszTable[endpos] = index;
  734. *(UINT*) (ppszTable[endpos] + sizeof(UINT)) = hit;
  735. strcpy(ppszTable[endpos++] + sizeof(UINT) * 2, pszString);
  736. }
  737. /***************************************************************************
  738. FUNCTION: SortTablei
  739. PURPOSE: Case-insensitive sort
  740. RETURNS:
  741. COMMENTS:
  742. MODIFICATION DATES:
  743. 01-Jan-1990 [ralphw]
  744. ***************************************************************************/
  745. void CTable::SortTablei(int sortoffset)
  746. {
  747. if (endpos < 3) // don't sort one entry
  748. return;
  749. m_sortoffset = sortoffset;
  750. if (!lcid)
  751. lcid = g_lcidSystem;
  752. ASSERT(lcid);
  753. fsSortFlags = fsCompareI | NORM_IGNORECASE;
  754. doLcidSort(1, endpos - 1);
  755. // REVIEW: what is this for?
  756. #if 0
  757. int pos;
  758. for (pos = 1; pos < endpos - 2; pos++) {
  759. if (strlen(ppszTable[pos]) ==
  760. strlen(ppszTable[pos + 1]) &&
  761. CompareStringA(lcid, fsCompare, ppszTable[pos] + m_sortoffset, -1,
  762. ppszTable[pos + 1] + m_sortoffset, -1) == 3) {
  763. PSTR pszTmp = ppszTable[pos];
  764. ppszTable[pos] = ppszTable[pos + 1];
  765. ppszTable[pos + 1] = pszTmp;
  766. if (pos > 2)
  767. pos -= 2;
  768. }
  769. }
  770. #endif
  771. }
  772. UINT CTable::GetPosFromPtr(PCSTR psz)
  773. {
  774. int pos = 1;
  775. do {
  776. if (psz == ppszTable[pos])
  777. return pos;
  778. } while (++pos < endpos);
  779. return 0;
  780. }
  781. /***************************************************************************
  782. FUNCTION: ReplaceString
  783. PURPOSE: Replaces the current string at the specified position with
  784. a new string
  785. RETURNS: TRUE if the function is successful, FALSE if an error occurred.
  786. An error occurs if the specified position is beyond the end
  787. of the table.
  788. COMMENTS:
  789. If the new string is the same size or smaller then the original
  790. string, then it is copied over the original string. Otherwise,
  791. a new string buffer is allocated, and the pointer for the specified
  792. position is changed to point to the new buffer. Note that the old
  793. string's memory is not freed -- it simply becomes unavailable.
  794. MODIFICATION DATES:
  795. 08-Oct-1991 [ralphw]
  796. Updated to transfer associated line number
  797. ***************************************************************************/
  798. BOOL CTable::ReplaceString(const char * pszNewString, int pos)
  799. {
  800. if (pos > endpos)
  801. return FALSE;
  802. if (pos == 0)
  803. pos = 1;
  804. /*
  805. * If the new string is larger then the old string, then allocate a
  806. * new buffer for it.
  807. */
  808. if (strlen(pszNewString) > (size_t) strlen(ppszTable[pos])) {
  809. if ((ppszTable[pos] =
  810. TableMalloc((int)strlen(pszNewString) + 1)) == NULL)
  811. return FALSE;
  812. }
  813. strcpy(ppszTable[pos], pszNewString);
  814. return TRUE;
  815. }
  816. void CTable::FreeMemory(PCSTR psz, int cb)
  817. {
  818. if (cb == -1)
  819. cb = (int)strlen(psz) + 1;
  820. /*
  821. * Change the size of cb to match what would have been originally
  822. * allocated. See TableMalloc().
  823. */
  824. cb = (cb & (ALIGNMENT - 1)) ?
  825. cb / ALIGNMENT * ALIGNMENT + ALIGNMENT : cb;
  826. if (!m_pFreed) {
  827. m_cFreedMax = 5;
  828. m_cFreedItems = 0;
  829. m_pFreed = (TABLE_FREED_MEMORY*) lcMalloc(m_cFreedMax * sizeof(TABLE_FREED_MEMORY));
  830. }
  831. else if (m_cFreedItems >= m_cFreedMax) {
  832. m_cFreedMax += 5;
  833. m_pFreed = (TABLE_FREED_MEMORY*) lcReAlloc(m_pFreed, m_cFreedMax * sizeof(TABLE_FREED_MEMORY));
  834. }
  835. m_pFreed[m_cFreedItems].cb = cb;
  836. m_pFreed[m_cFreedItems].pMem = psz;
  837. m_cFreedItems++;
  838. // Keep the sizes sorted
  839. QSort(m_pFreed, m_cFreedItems, sizeof(TABLE_FREED_MEMORY), CompareIntPointers);
  840. }
  841. //////////////////////////////////////////////////////////////////////////
  842. // CWTable
  843. //////////////////////////////////////////////////////////////////////////
  844. void CWTable::_CWTable( UINT CodePage )
  845. {
  846. m_CodePage = CodePage;
  847. }
  848. CWTable::CWTable( UINT CodePage )
  849. {
  850. _CWTable( CodePage );
  851. }
  852. CWTable::CWTable(int cbStrings, UINT CodePage ) : CTable( cbStrings )
  853. {
  854. _CWTable( CodePage );
  855. }
  856. CWTable::~CWTable()
  857. {
  858. }
  859. /***************************************************************************
  860. FUNCTION: GetStringW
  861. PURPOSE: Gets a Unicode version fo the stored string.
  862. RETURNS: S_OK if the function is successful, S_FALSE otherwise.
  863. COMMENTS: Stored string must be MBCS.
  864. MODIFICATION DATES:
  865. 08-Sep-1998 [paulti]
  866. ***************************************************************************/
  867. HRESULT CWTable::GetStringW( int pos, WCHAR* pwsz, int cch )
  868. {
  869. CHAR* psz = CTable::GetPointer( pos );
  870. int iReturn = MultiByteToWideChar( m_CodePage, 0, psz, (int)strlen(psz), pwsz, cch );
  871. if( iReturn == 0 )
  872. return S_FALSE;
  873. pwsz[iReturn] = 0;
  874. return S_OK;
  875. }
  876. /***************************************************************************
  877. FUNCTION: GetHashStringW
  878. PURPOSE: Gets a Unicode versions of the string when the both a Hash
  879. and a string pair are stored.
  880. RETURNS: S_OK if the function is successful, S_FALSE otherwise.
  881. COMMENTS: Stored string must be MBCS.
  882. MODIFICATION DATES:
  883. 08-Sep-1998 [paulti]
  884. ***************************************************************************/
  885. HRESULT CWTable::GetHashStringW( int pos, WCHAR* pwsz, int cch )
  886. {
  887. CHAR* psz = CTable::GetHashStringPointer( pos );
  888. int iReturn = MultiByteToWideChar( m_CodePage, 0, psz, (int)strlen(psz), pwsz, cch );
  889. if( iReturn == 0 )
  890. return S_FALSE;
  891. pwsz[iReturn] = 0;
  892. return S_OK;
  893. }