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.

533 lines
12 KiB

  1. /////////////////////////////////////////////////////////////////////////////
  2. // Copyright (C) 1993-1998 Microsoft Corporation. All Rights Reserved.
  3. //
  4. // MODULE: find.cpp
  5. //
  6. // PURPOSE:
  7. //
  8. #include "pch.hxx"
  9. #include "mru.h"
  10. #define NTHSTRING(p, n) (*((LPTSTR FAR *)((LPBYTE)p) + n))
  11. #define NTHDATA(p, n) (*((LPBYTE FAR *)((LPBYTE)p) + n))
  12. #define NUM_OVERHEAD 3
  13. #define MAX_MRU_INDEXSTR 15
  14. // For Binary data, we stick the size of the data at the beginning and store
  15. // the whole thing in one go.
  16. // Use this macro to get the original size of the data
  17. #define DATASIZE(p) (*((LPDWORD) p))
  18. // Use this macro to get a pointer to the original data
  19. #define DATAPDATA(p) (p + sizeof(DWORD))
  20. #define DATAPDATAEX(p) ((LPDWORD)(((DWORD_PTR) p) + sizeof(DWORD)))
  21. #define MAX_CHAR 126
  22. #define BASE_CHAR TEXT('a')
  23. CMRUList::CMRUList()
  24. {
  25. m_uMax = 0;
  26. m_fFlags = 0;
  27. m_pszSubKey = 0;
  28. m_hKey = 0;
  29. m_rgpszMRU = NULL;
  30. m_pszOrder = NULL;
  31. }
  32. CMRUList::~CMRUList()
  33. {
  34. SafeMemFree(m_pszSubKey);
  35. SafeMemFree(m_pszOrder);
  36. if (m_hKey)
  37. RegCloseKey(m_hKey);
  38. FreeList();
  39. }
  40. const TCHAR c_szRegMRU[] = _T("MRU List");
  41. //
  42. // FUNCTION: CMRUList::CreateList()
  43. //
  44. // PURPOSE: Creates and initializes the MRUL list
  45. //
  46. // PARAMETERS:
  47. // UINT uMaxEntries
  48. // UINT fFlags
  49. // LPCSTR pszSubKey
  50. //
  51. // RETURN VALUE:
  52. // BOOL
  53. //
  54. BOOL CMRUList::CreateList(UINT uMaxEntries, UINT fFlags, LPCSTR pszSubKey)
  55. {
  56. TraceCall("CMRUList::CreateList");
  57. return (CreateListLazy(uMaxEntries, fFlags, pszSubKey, NULL, 0, NULL));
  58. }
  59. //
  60. // FUNCTION: CreateListLazy()
  61. //
  62. // PURPOSE: Initializes the MRU list by telling the class how many entries
  63. // to store, where they are stored, and some flags.
  64. //
  65. // PARAMETERS:
  66. // [in] uMaxEntries
  67. // [in] fFlags
  68. // [in] pszSubKey
  69. //
  70. // RETURN VALUE:
  71. // BOOL
  72. //
  73. BOOL CMRUList::CreateListLazy(UINT uMaxEntries, UINT fFlags, LPCSTR pszSubKey,
  74. const void *pData, UINT cbData, LPINT piSlot)
  75. {
  76. TCHAR szOrder[126];
  77. DWORD dwType;
  78. DWORD cb;
  79. LPTSTR pszNewOrder;
  80. LPTSTR pszTemp;
  81. TCHAR sz[10];
  82. LPBYTE pVal;
  83. DWORD dwDisp = 0;
  84. TraceCall("CreateList");
  85. // Save some of this
  86. m_uMax = uMaxEntries;
  87. m_fFlags = fFlags;
  88. m_pszSubKey = PszDupA(pszSubKey);
  89. // Make sure uMax is < 126 so we don't use extended chars
  90. if (m_uMax > MAX_CHAR - BASE_CHAR)
  91. m_uMax = MAX_CHAR - BASE_CHAR;
  92. // Open the registry
  93. if (ERROR_SUCCESS != AthUserCreateKey(pszSubKey, KEY_ALL_ACCESS, &m_hKey, &dwDisp))
  94. goto exit;
  95. // Do we already have a stored MRU Index?
  96. cb = ARRAYSIZE(szOrder);
  97. if (ERROR_SUCCESS != RegQueryValueEx(m_hKey, c_szRegMRU, NULL, &dwType, (LPBYTE) szOrder, &cb))
  98. {
  99. // If we didn't find it then do this to initialize the list to be empty.
  100. *szOrder = 0;
  101. }
  102. // Uppercase is not allowed
  103. CharLower(szOrder);
  104. // Allocate room for the order list and the list of strings.
  105. if (!MemAlloc((LPVOID *) &m_rgpszMRU, uMaxEntries * sizeof(LPTSTR)))
  106. goto exit;
  107. ZeroMemory(m_rgpszMRU, uMaxEntries * sizeof(LPTSTR));
  108. // Allocate the order list
  109. if (!MemAlloc((LPVOID *) &m_pszOrder, sizeof(TCHAR) * (m_uMax + 1)))
  110. goto exit;
  111. ZeroMemory(m_pszOrder, (m_uMax + 1) * sizeof(TCHAR));
  112. // Traverse through the MRU list, adding strings to the end of the list.
  113. for (pszTemp = szOrder, pszNewOrder = m_pszOrder; ; ++pszTemp)
  114. {
  115. // Stop when we get to the end of the list
  116. sz[0] = *pszTemp;
  117. sz[1] = 0;
  118. if (!sz[0])
  119. break;
  120. // Check if in range and if we already have used this letter
  121. if ((UINT) (sz[0] - BASE_CHAR) >= m_uMax || m_rgpszMRU[sz[0] - BASE_CHAR])
  122. continue;
  123. // Get the value from the registry
  124. cb = 0;
  125. // First find the size
  126. if ((RegQueryValueEx(m_hKey, sz, NULL, &dwType, NULL, &cb) != ERROR_SUCCESS)
  127. || (dwType != REG_SZ))
  128. continue;
  129. cb *= sizeof(TCHAR);
  130. if (!MemAlloc((LPVOID *) &pVal, cb))
  131. continue;
  132. // Now really get it
  133. if (RegQueryValueEx(m_hKey, sz, NULL, &dwType, (LPBYTE) pVal, &cb) != ERROR_SUCCESS)
  134. continue;
  135. // Note that blank elements are not allowed in the list
  136. if (*((LPTSTR) pVal))
  137. {
  138. m_rgpszMRU[sz[0] - BASE_CHAR] = (LPTSTR) pVal;
  139. *pszNewOrder++ = sz[0];
  140. }
  141. else
  142. MemFree(pVal);
  143. }
  144. // NULL terminate the order list
  145. *pszNewOrder = '\0';
  146. if (pData && piSlot)
  147. {
  148. // If we failed to find it, put -1 in it
  149. if (!(m_fFlags & MRU_LAZY))
  150. {
  151. *piSlot = -1;
  152. }
  153. }
  154. exit:
  155. if (!m_rgpszMRU && m_hKey)
  156. {
  157. RegCloseKey(m_hKey);
  158. m_hKey = NULL;
  159. }
  160. return (TRUE);
  161. }
  162. BOOL CMRUList::_IsSameData(BYTE FAR *pVal, const void FAR *pData, UINT cbData)
  163. {
  164. int cbUseSize;
  165. // If there's something other than a mem compare, don't require the sizes
  166. // to be equal in order to complete.
  167. if (m_fFlags & MRU_BINARY)
  168. {
  169. if (DATASIZE(pVal) != cbData)
  170. return (FALSE);
  171. return (0 == _IMemCmp(pData, DATAPDATA(pVal), cbData));
  172. }
  173. else
  174. {
  175. return (0 == lstrcmpi((LPCSTR) pData, (LPCSTR) DATAPDATA(pVal)));
  176. }
  177. }
  178. int CDECL CMRUList::_IMemCmp(const void *pBuf1, const void *pBuf2, size_t cb)
  179. {
  180. UINT i;
  181. const BYTE *lpb1, *lpb2;
  182. Assert(pBuf1);
  183. Assert(pBuf2);
  184. lpb1 = (const BYTE *)pBuf1; lpb2 = (const BYTE *)pBuf2;
  185. for (i=0; i < cb; i++)
  186. {
  187. if (*lpb1 > *lpb2)
  188. return 1;
  189. else if (*lpb1 < *lpb2)
  190. return -1;
  191. lpb1++;
  192. lpb2++;
  193. }
  194. return 0;
  195. }
  196. //
  197. // FUNCTION: CMRUList::FreeList()
  198. //
  199. // PURPOSE:
  200. //
  201. // PARAMETERS:
  202. // void
  203. //
  204. // RETURN VALUE:
  205. // void
  206. //
  207. void CMRUList::FreeList(void)
  208. {
  209. int i;
  210. LPBYTE *pTemp;
  211. TraceCall("CMRUList::FreeList");
  212. if (m_fFlags & MRU_BINARY)
  213. pTemp = &NTHDATA(m_rgpszMRU, 0);
  214. else
  215. pTemp = (LPBYTE *) &NTHSTRING(m_rgpszMRU, 0);
  216. if (m_fFlags & MRU_ORDERDIRTY)
  217. {
  218. // _SaveOrder();
  219. }
  220. for (i = m_uMax - 1; i >= 0; --i, ++pTemp)
  221. {
  222. SafeMemFree(*pTemp);
  223. }
  224. SafeMemFree(m_rgpszMRU);
  225. }
  226. //
  227. // FUNCTION: CMRUList::AddString()
  228. //
  229. // PURPOSE: Writes the specified string into the MRU list
  230. //
  231. // PARAMETERS:
  232. // [in] pszString - string to add
  233. //
  234. // RETURN VALUE:
  235. // Returns -1 if it was not inserted.
  236. //
  237. int CMRUList::AddString(LPCSTR pszString)
  238. {
  239. TCHAR cFirst;
  240. int iSlot = -1;
  241. LPTSTR *ppszTemp;
  242. LPTSTR pszTemp = 0;
  243. int i;
  244. BOOL fShouldWrite;
  245. TraceCall("CMRUList::AddString");
  246. fShouldWrite = !(m_fFlags & MRU_CACHEWRITE);
  247. // Check to see if the string already exists in the list
  248. for (i = 0, ppszTemp = m_rgpszMRU; (UINT) i < m_uMax; i++, ppszTemp++)
  249. {
  250. if (*ppszTemp)
  251. {
  252. if (0 == lstrcmpi(pszString, (LPCTSTR) *ppszTemp))
  253. {
  254. // Found it, so don't do the write
  255. cFirst = i + BASE_CHAR;
  256. iSlot = i;
  257. goto found;
  258. }
  259. }
  260. }
  261. // Attempt to find an unsed entry. Count up the used entries at the same
  262. // time.
  263. for (i = 0, ppszTemp = m_rgpszMRU; ; i++, ppszTemp++)
  264. {
  265. // If we hit the end of the list
  266. if ((UINT) i >= m_uMax)
  267. {
  268. // Use the entry at the end of the order array
  269. cFirst = m_pszOrder[m_uMax - 1];
  270. ppszTemp = &(m_rgpszMRU[cFirst - BASE_CHAR]);
  271. break;
  272. }
  273. // Is the entry empty?
  274. if (!*ppszTemp)
  275. {
  276. cFirst = i + BASE_CHAR;
  277. break;
  278. }
  279. }
  280. // Copy the string
  281. if (_SetPtr(ppszTemp, pszString))
  282. {
  283. TCHAR szTemp[2];
  284. iSlot = (int) (cFirst - BASE_CHAR);
  285. szTemp[0] = cFirst;
  286. szTemp[1] = '\0';
  287. RegSetValueEx(m_hKey, szTemp, 0L, REG_SZ, (CONST BYTE *) pszString,
  288. sizeof(TCHAR) * (lstrlen(pszString) + 1));
  289. fShouldWrite = TRUE;
  290. }
  291. found:
  292. // Remove any previous reference to cFirst
  293. pszTemp = StrChr(m_pszOrder, cFirst);
  294. if (pszTemp)
  295. {
  296. DWORD cchSize = (lstrlen(pszTemp) + 1);
  297. StrCpyN(pszTemp, (pszTemp + 1), cchSize);
  298. }
  299. // If we moved or inserted, update the order array
  300. if (iSlot != -1)
  301. {
  302. // Shift everything over and put cFirst at the front
  303. MoveMemory(m_pszOrder + 1, m_pszOrder, m_uMax * sizeof(TCHAR));
  304. m_pszOrder[0] = cFirst;
  305. }
  306. // If we need to write, do it
  307. if (fShouldWrite)
  308. {
  309. RegSetValueEx(m_hKey, c_szRegMRU, 0L, REG_SZ, (CONST BYTE *) m_pszOrder,
  310. sizeof(TCHAR) * (lstrlen(m_pszOrder) + 1));
  311. m_fFlags &= ~MRU_ORDERDIRTY;
  312. }
  313. else
  314. {
  315. m_fFlags |= MRU_ORDERDIRTY;
  316. }
  317. return (iSlot);
  318. }
  319. //
  320. // FUNCTION: CMRUList::RemoveString()
  321. //
  322. // PURPOSE: Removes the specified string from the MRU list
  323. //
  324. // PARAMETERS:
  325. // [in] pszString - string to remove
  326. //
  327. // RETURN VALUE:
  328. // Returns -1 if it was not removed.
  329. //
  330. int CMRUList::RemoveString(LPCSTR pszString)
  331. {
  332. INT iRet = -1;
  333. BOOL fShouldWrite = FALSE;
  334. int i = 0;
  335. LPTSTR * ppszTemp = NULL;
  336. TCHAR cFirst = '\0';
  337. LPTSTR pszTemp = 0;
  338. TCHAR szTemp[2];
  339. TraceCall("CMRUList::RemoveString");
  340. if (NULL == pszString)
  341. {
  342. iRet = -1;
  343. goto exit;
  344. }
  345. fShouldWrite = !(m_fFlags & MRU_CACHEWRITE);
  346. // See if the string is in the MRU list
  347. for (i = 0, ppszTemp = m_rgpszMRU; (UINT) i < m_uMax; i++, ppszTemp++)
  348. {
  349. if (*ppszTemp)
  350. {
  351. if (0 == lstrcmpi(pszString, (LPCTSTR) *ppszTemp))
  352. {
  353. // Found it, so don't do the write
  354. cFirst = i + BASE_CHAR;
  355. iRet = i;
  356. break;
  357. }
  358. }
  359. }
  360. // We didn't find anything
  361. if ((UINT) i >= m_uMax)
  362. {
  363. iRet = -1;
  364. goto exit;
  365. }
  366. // Remove any previous reference to cFirst
  367. pszTemp = StrChr(m_pszOrder, cFirst);
  368. if (pszTemp)
  369. {
  370. DWORD cchSize = (lstrlen(pszTemp) + 1);
  371. StrCpyN(pszTemp, (pszTemp + 1), cchSize);
  372. }
  373. // Copy the string
  374. if (_SetPtr(ppszTemp, NULL))
  375. {
  376. szTemp[0] = cFirst;
  377. szTemp[1] = '\0';
  378. RegDeleteValue(m_hKey, szTemp);
  379. fShouldWrite = TRUE;
  380. }
  381. // If we need to write, do it
  382. if (fShouldWrite)
  383. {
  384. RegSetValueEx(m_hKey, c_szRegMRU, 0L, REG_SZ, (CONST BYTE *) m_pszOrder,
  385. sizeof(TCHAR) * (lstrlen(m_pszOrder) + 1));
  386. m_fFlags &= ~MRU_ORDERDIRTY;
  387. }
  388. else
  389. {
  390. m_fFlags |= MRU_ORDERDIRTY;
  391. }
  392. exit:
  393. return (iRet);
  394. }
  395. int CMRUList::EnumList(int nItem, LPTSTR psz, UINT uLen)
  396. {
  397. int nItems = -1;
  398. LPTSTR pszTemp;
  399. LPBYTE pData;
  400. if (m_rgpszMRU)
  401. {
  402. nItems = lstrlen(m_pszOrder);
  403. if (nItems < 0 || !psz)
  404. return (nItems);
  405. if (nItem < nItems)
  406. {
  407. pszTemp = m_rgpszMRU[m_pszOrder[nItem] - BASE_CHAR];
  408. if (!pszTemp)
  409. return (-1);
  410. StrCpyN(psz, pszTemp, uLen);
  411. nItems = lstrlen(pszTemp);
  412. }
  413. else
  414. {
  415. nItems = -1;
  416. }
  417. }
  418. return (nItems);
  419. }
  420. BOOL CMRUList::_SetPtr(LPSTR * ppszCurrent, LPCSTR pszNew)
  421. {
  422. int cchLength;
  423. LPSTR pszOld;
  424. LPSTR pszNewCopy = NULL;
  425. if (pszNew)
  426. {
  427. cchLength = lstrlenA(pszNew);
  428. // alloc a new buffer w/ room for the null terminator
  429. MemAlloc((LPVOID *) &pszNewCopy, ((cchLength + 1) * sizeof(TCHAR)));
  430. if (!pszNewCopy)
  431. return FALSE;
  432. StrCpyNA(pszNewCopy, pszNew, cchLength + 1);
  433. }
  434. pszOld = (LPSTR) InterlockedExchangePointer((LPVOID *)ppszCurrent, (LPVOID *)pszNewCopy);
  435. if (pszOld)
  436. MemFree(pszOld);
  437. return TRUE;
  438. }