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.

1053 lines
26 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. Common.cpp
  5. Abstract:
  6. Common functions for all modules
  7. Notes:
  8. None
  9. History:
  10. 12/15/1999 linstev Created
  11. 01/10/2000 linstev Format to new style
  12. --*/
  13. #include <stdio.h>
  14. #include "ShimHook.h"
  15. #ifdef DBG
  16. extern DEBUGLEVEL GetDebugLevel();
  17. #endif
  18. /*++
  19. Function Description:
  20. Print a formatted string using DebugOutputString.
  21. Arguments:
  22. IN dwDetail - Detail level above which no print will occur
  23. IN pszFmt - Format string
  24. Return Value:
  25. None
  26. History:
  27. 11/01/1999 markder Created
  28. --*/
  29. #ifdef DBG
  30. VOID
  31. __cdecl
  32. DebugPrintf(
  33. DEBUGLEVEL dwDetail,
  34. LPSTR pszFmt,
  35. ...
  36. )
  37. {
  38. char szT[1024];
  39. va_list arglist;
  40. if (dwDetail <= GetDebugLevel())
  41. {
  42. switch (dwDetail)
  43. {
  44. case eDbgLevelError:
  45. OutputDebugStringA ("[FAIL] ");
  46. break;
  47. case eDbgLevelWarning:
  48. OutputDebugStringA ("[WARN] ");
  49. break;
  50. case eDbgLevelUser:
  51. OutputDebugStringA ("[USER] ");
  52. break;
  53. case eDbgLevelInfo:
  54. OutputDebugStringA ("[INFO] ");
  55. break;
  56. }
  57. va_start(arglist, pszFmt);
  58. _vsnprintf(szT, 1023, pszFmt, arglist);
  59. szT[1023] = 0;
  60. va_end(arglist);
  61. OutputDebugStringA(szT);
  62. }
  63. }
  64. /*++
  65. Function Description:
  66. Assert that prints file and line number.
  67. Arguments:
  68. IN dwDetail - Detail level above which no print will occur
  69. IN pszFmt - Format string
  70. Return Value:
  71. None
  72. History:
  73. 11/01/1999 markder Created
  74. --*/
  75. VOID
  76. DebugAssert(
  77. LPSTR szFile,
  78. DWORD dwLine,
  79. BOOL bAssert,
  80. LPSTR szHelpString
  81. )
  82. {
  83. if (!bAssert )
  84. {
  85. int i;
  86. for (i=0; i<80; i++) DPF(eDbgLevelError, "+");
  87. DPF(eDbgLevelError, "\n");
  88. DPF(eDbgLevelError, "FILE: %s\n", szFile);
  89. DPF(eDbgLevelError, "LINE: %d\n", dwLine);
  90. DPF(eDbgLevelError, "ASSERT: %s\n", szHelpString);
  91. for (i=0; i<80; i++) DPF(eDbgLevelError, "+");
  92. DPF(eDbgLevelError, "\n");
  93. #ifdef _X86_
  94. __asm int 3;
  95. #else
  96. #pragma message ("Not implented on IA64")
  97. #endif
  98. }
  99. }
  100. #endif
  101. /*++
  102. Function Description:
  103. Determine if a file resides on a CD Rom drive
  104. Arguments:
  105. IN wszFileName - Filename including path
  106. Return Value:
  107. TRUE if file is on CD drive
  108. History:
  109. 01/10/2000 linstev Updated
  110. --*/
  111. BOOL
  112. IsOnCDRomA(LPCSTR szFileName)
  113. {
  114. CHAR szDrive[4];
  115. CHAR *szCurDir = NULL;
  116. DWORD dwCurDirSize = 0;
  117. if (szFileName[1] == ':')
  118. {
  119. szDrive[0] = szFileName[0];
  120. szDrive[1] = ':';
  121. szDrive[2] = '\\';
  122. szDrive[3] = '\0';
  123. }
  124. else if (!(szFileName[0] == '\\' && szFileName[1] == '\\'))
  125. {
  126. // Not UNC naming, must be a relative path
  127. dwCurDirSize = GetCurrentDirectoryA(0, szCurDir);
  128. if (dwCurDirSize)
  129. {
  130. szCurDir = (PCHAR)LocalAlloc( LPTR, dwCurDirSize * sizeof(CHAR));
  131. dwCurDirSize = GetCurrentDirectoryA( dwCurDirSize, szCurDir);
  132. if (dwCurDirSize && !(szCurDir[0] == '\\' && szCurDir[1] == '\\'))
  133. {
  134. szDrive[0] = szCurDir[0];
  135. szDrive[1] = ':';
  136. szDrive[2] = '\\';
  137. szDrive[3] = '\0';
  138. }
  139. LocalFree( szCurDir );
  140. szCurDir = NULL;
  141. }
  142. }
  143. return (GetDriveTypeA(szDrive) == DRIVE_CDROM);
  144. }
  145. /*++
  146. Function Description:
  147. Determine if a file resides on a CD Rom drive
  148. Arguments:
  149. IN wszFileName - Filename including path
  150. Return Value:
  151. TRUE if file is on CD drive
  152. History:
  153. 01/10/2000 linstev Updated
  154. --*/
  155. BOOL
  156. IsOnCDRomW(IN LPCWSTR wszFileName)
  157. {
  158. WCHAR wszDrive[4];
  159. WCHAR *wszCurDir = NULL;
  160. DWORD dwCurDirSize = 0;
  161. if (wszFileName[1] == L':')
  162. {
  163. wszDrive[0] = wszFileName[0];
  164. wszDrive[1] = L':';
  165. wszDrive[2] = L'\\';
  166. wszDrive[3] = L'\0';
  167. }
  168. else if (!(wszFileName[0] == L'\\' && wszFileName[1] == L'\\'))
  169. {
  170. // Not UNC naming, must be a relative path
  171. dwCurDirSize = GetCurrentDirectoryW(0, wszCurDir);
  172. if (dwCurDirSize)
  173. {
  174. wszCurDir = (PWCHAR)LocalAlloc( LPTR, dwCurDirSize * sizeof(WCHAR));
  175. dwCurDirSize = GetCurrentDirectoryW( dwCurDirSize, wszCurDir );
  176. if (dwCurDirSize && !(wszCurDir[0] == L'\\' && wszCurDir[1] == L'\\'))
  177. {
  178. wszDrive[0] = wszCurDir[0];
  179. wszDrive[1] = L':';
  180. wszDrive[2] = L'\\';
  181. wszDrive[3] = L'\0';
  182. }
  183. LocalFree(wszCurDir);
  184. wszCurDir = NULL;
  185. }
  186. }
  187. return (GetDriveTypeW(wszDrive) == DRIVE_CDROM);
  188. }
  189. /*++
  190. Function Description:
  191. Removes all "\ " and replaces with "\".
  192. Arguments:
  193. IN pszOldPath - String to scan
  194. OUT pszNewPath - Resultant string
  195. Return Value:
  196. None
  197. History:
  198. 01/10/2000 linstev Updated
  199. --*/
  200. VOID
  201. MassagePathA(
  202. LPCSTR pszOldPath,
  203. LPSTR pszNewPath
  204. )
  205. {
  206. PCHAR pszTempBuffer;
  207. PCHAR pszPointer;
  208. LONG nOldPos, nNewPos, nOldStringLen;
  209. BOOL bAtSeparator = TRUE;
  210. nOldStringLen = strlen(pszOldPath);
  211. pszTempBuffer = (PCHAR) LocalAlloc(LPTR, nOldStringLen + 1);
  212. pszPointer = pszTempBuffer;
  213. nNewPos = nOldStringLen;
  214. for (nOldPos = nOldStringLen - 1; nOldPos >= 0; nOldPos--)
  215. {
  216. if (pszOldPath[ nOldPos ] == '\\')
  217. {
  218. bAtSeparator = TRUE;
  219. }
  220. else
  221. {
  222. if (pszOldPath[nOldPos] == ' ' && bAtSeparator)
  223. {
  224. continue;
  225. }
  226. else
  227. {
  228. bAtSeparator = FALSE;
  229. }
  230. }
  231. pszPointer[--nNewPos] = pszOldPath[nOldPos];
  232. }
  233. pszPointer += nNewPos;
  234. strcpy(pszNewPath, pszPointer);
  235. LocalFree(pszTempBuffer);
  236. }
  237. /*++
  238. Function Description:
  239. Removes all L"\ " and replaces with L"\".
  240. Arguments:
  241. IN pwszOldPath - String to scan
  242. OUT pwszNewPath - Resultant string
  243. Return Value:
  244. None
  245. History:
  246. 01/10/2000 linstev Updated
  247. --*/
  248. VOID
  249. MassagePathW(
  250. LPCWSTR pwszOldPath,
  251. LPWSTR pwszNewPath
  252. )
  253. {
  254. PWCHAR pwszTempBuffer;
  255. PWCHAR pwszPointer;
  256. LONG nOldPos, nNewPos, nOldStringLen;
  257. BOOL bAtSeparator = TRUE;
  258. nOldStringLen = wcslen(pwszOldPath);
  259. pwszTempBuffer = (PWCHAR) LocalAlloc(LPTR, (nOldStringLen + 1) * sizeof(WCHAR));
  260. pwszPointer = pwszTempBuffer;
  261. nNewPos = nOldStringLen;
  262. for (nOldPos = nOldStringLen - 1; nOldPos >= 0; nOldPos--)
  263. {
  264. if (pwszOldPath[ nOldPos ] == L'\\')
  265. {
  266. bAtSeparator = TRUE;
  267. }
  268. else
  269. {
  270. if (pwszOldPath[nOldPos] == L' ' && bAtSeparator)
  271. {
  272. continue;
  273. }
  274. else
  275. {
  276. bAtSeparator = FALSE;
  277. }
  278. }
  279. pwszPointer[--nNewPos] = pwszOldPath[nOldPos];
  280. }
  281. pwszPointer += nNewPos;
  282. wcscpy(pwszNewPath, pwszPointer);
  283. LocalFree(pwszTempBuffer);
  284. }
  285. /*++
  286. Function Description:
  287. Duplicate a string into malloc memory.
  288. Arguments:
  289. IN strToCopy - String to copy
  290. Return Value:
  291. String in malloc memory
  292. History:
  293. 01/10/2000 linstev Updated
  294. 02/14/2000 robkenny Converted from VirtualAlloc to malloc
  295. --*/
  296. char *
  297. StringDuplicateA(const char *strToCopy)
  298. {
  299. size_t strToCopySize = (strlen(strToCopy) + 1) * sizeof(strToCopy[0]);
  300. char * strDuplicate = (char *) malloc(strToCopySize);
  301. memcpy(strDuplicate, strToCopy, strToCopySize);
  302. return strDuplicate;
  303. }
  304. /*++
  305. Function Description:
  306. Duplicate a string into malloc memory.
  307. Arguments:
  308. IN wstrToCopy - String to copy
  309. Return Value:
  310. String in malloc memory
  311. History:
  312. 01/10/2000 linstev Updated
  313. 02/14/2000 robkenny Converted from VirtualAlloc to malloc
  314. --*/
  315. wchar_t *
  316. StringDuplicateW(const wchar_t *wstrToCopy)
  317. {
  318. size_t wstrToCopySize = (wcslen(wstrToCopy) + 1) * sizeof(wstrToCopy[0]);
  319. wchar_t * wstrDuplicate = (wchar_t *) malloc(wstrToCopySize);
  320. memcpy(wstrDuplicate, wstrToCopy, wstrToCopySize);
  321. return wstrDuplicate;
  322. }
  323. /*++
  324. Function Description:
  325. Skip leading whitespace
  326. Arguments:
  327. IN str - String to scan
  328. Return Value:
  329. None
  330. History:
  331. 01/10/2000 linstev Updated
  332. --*/
  333. VOID
  334. SkipBlanksA(const char *& str)
  335. {
  336. // Skip leading whitespace
  337. static const char * WhiteSpaceString = " \t";
  338. str += strspn(str, WhiteSpaceString);
  339. }
  340. /*++
  341. Function Description:
  342. Skip leading whitespace
  343. Arguments:
  344. IN str - String to scan
  345. Return Value:
  346. None
  347. History:
  348. 01/10/2000 linstev Updated
  349. --*/
  350. VOID
  351. SkipBlanksW(const WCHAR *& str)
  352. {
  353. // Skip leading whitespace
  354. static const WCHAR * WhiteSpaceString = L" \t";
  355. str += wcsspn(str, WhiteSpaceString);
  356. }
  357. /*++
  358. Function Description:
  359. Find the first occurance of strCharSet in string
  360. Case insensitive
  361. Arguments:
  362. IN string - String to search
  363. IN strCharSet - String to search for
  364. Return Value:
  365. First occurance or NULL
  366. History:
  367. 12/01/1999 robkenny Created
  368. 12/15/1999 linstev Reformatted
  369. --*/
  370. char*
  371. __cdecl
  372. stristr(
  373. IN const char* string,
  374. IN const char* strCharSet
  375. )
  376. {
  377. char * pszRet = NULL;
  378. long nstringLen = strlen(string) + 1;
  379. long nstrCharSetLen = strlen(strCharSet) + 1;
  380. char * szTemp_string = (char *) malloc(nstringLen);
  381. char * szTemp_strCharSet = (char *) malloc(nstrCharSetLen);
  382. if ((!szTemp_string) || (!szTemp_strCharSet))
  383. {
  384. goto Fail;
  385. }
  386. strcpy(szTemp_string, string);
  387. strcpy(szTemp_strCharSet, strCharSet);
  388. _strlwr(szTemp_string);
  389. _strlwr(szTemp_strCharSet);
  390. pszRet = strstr(szTemp_string, szTemp_strCharSet);
  391. if (pszRet)
  392. {
  393. pszRet = ((char *) string) + (pszRet - szTemp_string);
  394. }
  395. Fail:
  396. if (szTemp_string)
  397. {
  398. free(szTemp_string);
  399. }
  400. if (szTemp_strCharSet)
  401. {
  402. free(szTemp_strCharSet);
  403. }
  404. return pszRet;
  405. }
  406. /*++
  407. Function Description:
  408. Find the first occurance of strCharSet in string
  409. Case insensitive
  410. Arguments:
  411. IN string - String to search
  412. IN strCharSet - String to search for
  413. Return Value:
  414. First occurance or NULL
  415. History:
  416. 12/01/1999 robkenny Created
  417. 12/15/1999 linstev Reformatted
  418. --*/
  419. WCHAR*
  420. __cdecl
  421. wcsistr(
  422. IN const WCHAR* string,
  423. IN const WCHAR* strCharSet
  424. )
  425. {
  426. WCHAR * pszRet = NULL;
  427. long nstringLen = wcslen(string) + 1;
  428. long nstrCharSetLen = wcslen(strCharSet) + 1;
  429. WCHAR * szTemp_string = (WCHAR *) malloc(nstringLen * sizeof(WCHAR));
  430. WCHAR * szTemp_strCharSet = (WCHAR *) malloc(nstrCharSetLen * sizeof(WCHAR));
  431. if ((!szTemp_string) || (!szTemp_strCharSet))
  432. {
  433. goto Fail;
  434. }
  435. wcscpy(szTemp_string, string);
  436. wcscpy(szTemp_strCharSet, strCharSet);
  437. _wcslwr(szTemp_string);
  438. _wcslwr(szTemp_strCharSet);
  439. pszRet = wcsstr(szTemp_string, szTemp_strCharSet);
  440. if (pszRet)
  441. {
  442. pszRet = ((WCHAR *) string) + (pszRet - szTemp_string);
  443. }
  444. Fail:
  445. if (szTemp_string)
  446. {
  447. free(szTemp_string);
  448. }
  449. if( szTemp_strCharSet )
  450. {
  451. free(szTemp_strCharSet);
  452. }
  453. return pszRet;
  454. }
  455. /*++
  456. Func: SafeStringCopyA
  457. Params: lpDest Destination string
  458. nDestSize size in chars of lpDest
  459. lpSrc Original string
  460. nSrcLen Number of chars to copy
  461. Return: int Number of chars copied into lpDest
  462. Desc: Copy lpSrc into lpDest without overflowing the buffer
  463. --*/
  464. int SafeStringCopyA(char * lpDest, DWORD nDestSize, const char * lpSrc, DWORD nSrcLen)
  465. {
  466. size_t nCharsToCopy = __min(nSrcLen, nDestSize);
  467. if (nCharsToCopy > 0)
  468. {
  469. strncpy(lpDest, lpSrc, nCharsToCopy);
  470. }
  471. return nCharsToCopy;
  472. }
  473. /*++
  474. Func: SafeStringCopyW
  475. Params: lpDest Destination string
  476. nDestSize size in chars of lpDest
  477. lpSrc Original string
  478. nSrcLen Number of chars to copy
  479. Return: int Number of chars copied into lpDest
  480. Desc: Copy lpSrc into lpDest without overflowing the buffer
  481. --*/
  482. int SafeStringCopyW(WCHAR * lpDest, DWORD nDestSize, const WCHAR * lpSrc, DWORD nSrcLen)
  483. {
  484. size_t nCharsToCopy = __min(nSrcLen, nDestSize);
  485. if (nCharsToCopy > 0)
  486. {
  487. wcsncpy(lpDest, lpSrc, nCharsToCopy);
  488. }
  489. return nCharsToCopy;
  490. }
  491. typedef WCHAR * (__cdecl * _pfn_StrStrW)( const WCHAR * string, const WCHAR * strCharSet );
  492. typedef char * (__cdecl * _pfn_StrStrA)( const char * string, const char * strCharSet );
  493. /*++
  494. Func: StringSubstituteRoutineA
  495. Params: lpOrig Original string
  496. lpMatch Sub-string to look for
  497. lpSubstitute string to replace lpMatch
  498. lpCorrected the corrected string, may be NULL if (dwCorrectedSize == 0)
  499. dwCorrectedSize maximum size of lpCorrected.
  500. If 0, then routine returns number of chars necessasry for substitution
  501. nCorrectedLen Number of chars placed into lpCorrected. If the buffer
  502. was large enough, this == (wcslen(lpCorrected) + 1)
  503. nCorrectedTotalSize Number of total chars that should have been copied.
  504. This == dwCorrectedSize if lpCorrected was large enough.
  505. StringSubStringRoutine String comparison routine
  506. Return: BOOL Return TRUE if this routine replaced 1 or more matches
  507. Desc: Replace the all occurances of lpMatch with lpSubstitute in lpOrig, placing output into lpCorrected
  508. This routine is CASE SENSITIVE!
  509. --*/
  510. BOOL StringSubstituteRoutineA(
  511. const char * lpOrig,
  512. const char * lpMatch,
  513. const char * lpSubstitute,
  514. DWORD dwCorrectedSize,
  515. char * lpCorrected,
  516. DWORD * nCorrectedLen,
  517. DWORD * nCorrectedTotalSize,
  518. _pfn_StrStrA StringSubStringRoutine)
  519. {
  520. BOOL bStringChanged = FALSE;
  521. DWORD nCharsShouldHaveCopied = 0; // Size of resulting string (might exceed )
  522. size_t nCharsCopied = 0;
  523. char * lpMatchInString = StringSubStringRoutine( lpOrig, lpMatch );
  524. if (lpMatchInString != NULL)
  525. {
  526. // Replace lpMatch with lpSubstitute.
  527. // Make sure we do not overrun the output buffer.
  528. size_t nCharsToCopy; // How many chars we can safely copy (always <= nCopyLen)
  529. // Copy the unmodified chars at the beginning of the string
  530. nCharsToCopy = lpMatchInString - lpOrig;
  531. nCharsCopied += SafeStringCopyA(lpCorrected + nCharsShouldHaveCopied, dwCorrectedSize - nCharsCopied, lpOrig, nCharsToCopy);
  532. nCharsShouldHaveCopied += nCharsToCopy;
  533. // The substitution string
  534. nCharsToCopy = strlen(lpSubstitute);
  535. nCharsCopied += SafeStringCopyA(lpCorrected + nCharsShouldHaveCopied, dwCorrectedSize - nCharsCopied, lpSubstitute, nCharsToCopy);
  536. nCharsShouldHaveCopied += nCharsToCopy;
  537. char * lpOrigAfterMatch = lpMatchInString + strlen(lpMatch);
  538. // Recursively replace the remainder of the string
  539. DWORD nSmallerSize;
  540. DWORD nSmallerTotal;
  541. StringSubstituteA(lpOrigAfterMatch, lpMatch, lpSubstitute, dwCorrectedSize - nCharsCopied, lpCorrected + nCharsShouldHaveCopied, &nSmallerSize, &nSmallerTotal);
  542. nCharsCopied += nSmallerSize;
  543. nCharsShouldHaveCopied += nSmallerTotal;
  544. bStringChanged = TRUE;
  545. // Recusion is cool: the remainder of the string is copied "automatically" for us in the else statement
  546. }
  547. else
  548. {
  549. nCharsShouldHaveCopied = strlen(lpOrig) + 1;
  550. nCharsCopied = SafeStringCopyA(lpCorrected, dwCorrectedSize, lpOrig, nCharsShouldHaveCopied);
  551. }
  552. // Make sure we have placed the 0 char at the end of the string
  553. if (nCharsCopied != nCharsShouldHaveCopied && nCharsCopied > 0)
  554. {
  555. lpCorrected[nCharsCopied-1] = 0;
  556. }
  557. if (nCorrectedLen != NULL)
  558. *nCorrectedLen = nCharsCopied;
  559. if (nCorrectedTotalSize != NULL)
  560. *nCorrectedTotalSize = nCharsShouldHaveCopied;
  561. return bStringChanged;
  562. }
  563. /*++
  564. Func: StringSubstituteW
  565. Params: lpOrig Original string
  566. lpMatch Sub-string to look for
  567. lpSubstitute string to replace lpMatch
  568. lpCorrected the corrected string, may be NULL if (dwCorrectedSize == 0)
  569. dwCorrectedSize maximum size of lpCorrected.
  570. If 0, then routine returns number of chars necessasry for substitution
  571. nCorrectedLen Number of chars placed into lpCorrected. If the buffer
  572. was large enough, this == (wcslen(lpCorrected) + 1)
  573. nCorrectedTotalSize Number of total chars that should have been copied.
  574. This == dwCorrectedSize if lpCorrected was large enough.
  575. StringSubStringRoutine String comparison routine
  576. Return: BOOL Return TRUE if this routine replaced 1 or more matches
  577. Desc: Replace the all occurances of lpMatch with lpSubstitute in lpOrig, placing output into lpCorrected.
  578. This routine is CASE SENSITIVE!
  579. --*/
  580. BOOL StringSubstituteRoutineW(
  581. const WCHAR * lpOrig,
  582. const WCHAR * lpMatch,
  583. const WCHAR * lpSubstitute,
  584. WCHAR * lpCorrected,
  585. DWORD dwCorrectedSize,
  586. DWORD * nCorrectedLen,
  587. DWORD * nCorrectedTotalSize,
  588. _pfn_StrStrW StringSubStringRoutine)
  589. {
  590. BOOL bStringChanged = FALSE;
  591. DWORD nCharsShouldHaveCopied = 0; // Size of resulting string (might exceed )
  592. size_t nCharsCopied = 0;
  593. WCHAR * lpMatchInString = StringSubStringRoutine( lpOrig, lpMatch );
  594. if (lpMatchInString != NULL)
  595. {
  596. // Replace lpMatch with lpSubstitute.
  597. // Make sure we do not overrun the output buffer.
  598. size_t nCharsToCopy; // How many chars we can safely copy (always <= nCopyLen)
  599. // Copy the unmodified chars at the beginning of the string
  600. nCharsToCopy = lpMatchInString - lpOrig;
  601. nCharsCopied += SafeStringCopyW(lpCorrected + nCharsShouldHaveCopied, dwCorrectedSize - nCharsCopied, lpOrig, nCharsToCopy);
  602. nCharsShouldHaveCopied += nCharsToCopy;
  603. // The substitution string
  604. nCharsToCopy = wcslen(lpSubstitute);
  605. nCharsCopied += SafeStringCopyW(lpCorrected + nCharsShouldHaveCopied, dwCorrectedSize - nCharsCopied, lpSubstitute, nCharsToCopy);
  606. nCharsShouldHaveCopied += nCharsToCopy;
  607. WCHAR * lpOrigAfterMatch = lpMatchInString + wcslen(lpMatch);
  608. // Recursively replace the remainder of the string
  609. DWORD nSmallerSize;
  610. DWORD nSmallerTotal;
  611. StringSubstituteW(lpOrigAfterMatch, lpMatch, lpSubstitute, lpCorrected + nCharsShouldHaveCopied, dwCorrectedSize - nCharsCopied, &nSmallerSize, &nSmallerTotal);
  612. nCharsCopied += nSmallerSize;
  613. nCharsShouldHaveCopied += nSmallerTotal;
  614. bStringChanged = TRUE;
  615. // Recursion is cool: the remainder of the string is copied "automatically" for us in the else statement
  616. }
  617. else
  618. {
  619. nCharsShouldHaveCopied = wcslen(lpOrig) + 1;
  620. nCharsCopied = SafeStringCopyW(lpCorrected, dwCorrectedSize, lpOrig, nCharsShouldHaveCopied);
  621. }
  622. // Make sure we have placed the 0 char at the end of the string
  623. if (nCharsCopied != nCharsShouldHaveCopied && nCharsCopied > 0)
  624. {
  625. lpCorrected[nCharsCopied-1] = 0;
  626. }
  627. if (nCorrectedLen != NULL)
  628. *nCorrectedLen = nCharsCopied;
  629. if (nCorrectedTotalSize != NULL)
  630. *nCorrectedTotalSize = nCharsShouldHaveCopied;
  631. return bStringChanged;
  632. }
  633. /*++
  634. Func: StringISubstituteA
  635. Params: lpOrig Original string
  636. lpMatch Sub-string to look for
  637. lpSubstitute string to replace lpMatch
  638. lpCorrected the corrected string, may be NULL if (dwCorrectedSize == 0)
  639. dwCorrectedSize maximum size of lpCorrected.
  640. If 0, then routine returns number of chars necessasry for substitution
  641. nCorrectedLen Number of chars placed into lpCorrected. If the buffer
  642. was large enough, this == (wcslen(lpCorrected) + 1)
  643. nCorrectedTotalSize Number of total chars that should have been copied.
  644. This == dwCorrectedSize if lpCorrected was large enough.
  645. Return: BOOL Return TRUE if this routine replaced 1 or more matches
  646. Desc: Replace the all occurances of lpMatch with lpSubstitute in lpOrig, placing output into lpCorrected
  647. This routine is CASE SENSITIVE!
  648. --*/
  649. BOOL StringSubstituteA(
  650. const char * lpOrig,
  651. const char * lpMatch,
  652. const char * lpSubstitute,
  653. DWORD dwCorrectedSize,
  654. char * lpCorrected,
  655. DWORD * nCorrectedLen,
  656. DWORD * nCorrectedTotalSize)
  657. {
  658. return StringSubstituteRoutineA(
  659. lpOrig,
  660. lpMatch,
  661. lpSubstitute,
  662. dwCorrectedSize,
  663. lpCorrected,
  664. nCorrectedLen,
  665. nCorrectedTotalSize,
  666. strstr);
  667. }
  668. /*++
  669. Func: StringISubstituteA
  670. Params: lpOrig Original string
  671. lpMatch Sub-string to look for
  672. lpSubstitute string to replace lpMatch
  673. lpCorrected the corrected string, may be NULL if (dwCorrectedSize == 0)
  674. dwCorrectedSize maximum size of lpCorrected.
  675. If 0, then routine returns number of chars necessasry for substitution
  676. nCorrectedLen Number of chars placed into lpCorrected. If the buffer
  677. was large enough, this == (wcslen(lpCorrected) + 1)
  678. nCorrectedTotalSize Number of total chars that should have been copied.
  679. This == dwCorrectedSize if lpCorrected was large enough.
  680. Return: BOOL Return TRUE if this routine replaced 1 or more matches
  681. Desc: Replace the all occurances of lpMatch with lpSubstitute in lpOrig, placing output into lpCorrected
  682. This routine is CASE SENSITIVE!
  683. --*/
  684. BOOL StringISubstituteA(
  685. const char * lpOrig,
  686. const char * lpMatch,
  687. const char * lpSubstitute,
  688. DWORD dwCorrectedSize,
  689. char * lpCorrected,
  690. DWORD * nCorrectedLen,
  691. DWORD * nCorrectedTotalSize)
  692. {
  693. return StringSubstituteRoutineA(
  694. lpOrig,
  695. lpMatch,
  696. lpSubstitute,
  697. dwCorrectedSize,
  698. lpCorrected,
  699. nCorrectedLen,
  700. nCorrectedTotalSize,
  701. stristr);
  702. }
  703. /*++
  704. Func: StringSubstituteW
  705. Params: lpOrig Original string
  706. lpMatch Sub-string to look for
  707. lpSubstitute string to replace lpMatch
  708. lpCorrected the corrected string, may be NULL if (dwCorrectedSize == 0)
  709. dwCorrectedSize maximum size of lpCorrected.
  710. If 0, then routine returns number of chars necessasry for substitution
  711. nCorrectedLen Number of chars placed into lpCorrected. If the buffer
  712. was large enough, this == (wcslen(lpCorrected) + 1)
  713. nCorrectedTotalSize Number of total chars that should have been copied.
  714. This == dwCorrectedSize if lpCorrected was large enough.
  715. Return: BOOL Return TRUE if this routine replaced 1 or more matches
  716. Desc: Replace the all occurances of lpMatch with lpSubstitute in lpOrig, placing output into lpCorrected.
  717. This routine is CASE IN-SENSITIVE!
  718. --*/
  719. BOOL StringSubstituteW(
  720. const WCHAR * lpOrig,
  721. const WCHAR * lpMatch,
  722. const WCHAR * lpSubstitute,
  723. WCHAR * lpCorrected,
  724. DWORD dwCorrectedSize,
  725. DWORD * nCorrectedLen,
  726. DWORD * nCorrectedTotalSize)
  727. {
  728. return StringSubstituteRoutineW(
  729. lpOrig,
  730. lpMatch,
  731. lpSubstitute,
  732. lpCorrected,
  733. dwCorrectedSize,
  734. nCorrectedLen,
  735. nCorrectedTotalSize,
  736. wcsstr);
  737. }
  738. /*++
  739. Func: StringISubstituteW
  740. Params: lpOrig Original string
  741. lpMatch Sub-string to look for
  742. lpSubstitute string to replace lpMatch
  743. lpCorrected the corrected string, may be NULL if (dwCorrectedSize == 0)
  744. dwCorrectedSize maximum size of lpCorrected.
  745. If 0, then routine returns number of chars necessasry for substitution
  746. nCorrectedLen Number of chars placed into lpCorrected. If the buffer
  747. was large enough, this == (wcslen(lpCorrected) + 1)
  748. nCorrectedTotalSize Number of total chars that should have been copied.
  749. This == dwCorrectedSize if lpCorrected was large enough.
  750. Return: BOOL Return TRUE if this routine replaced 1 or more matches
  751. Desc: Replace the all occurances of lpMatch with lpSubstitute in lpOrig, placing output into lpCorrected.
  752. This routine is CASE IN-SENSITIVE!
  753. --*/
  754. BOOL StringISubstituteW(
  755. const WCHAR * lpOrig,
  756. const WCHAR * lpMatch,
  757. const WCHAR * lpSubstitute,
  758. WCHAR * lpCorrected,
  759. DWORD dwCorrectedSize,
  760. DWORD * nCorrectedLen,
  761. DWORD * nCorrectedTotalSize)
  762. {
  763. return StringSubstituteRoutineW(
  764. lpOrig,
  765. lpMatch,
  766. lpSubstitute,
  767. lpCorrected,
  768. dwCorrectedSize,
  769. nCorrectedLen,
  770. nCorrectedTotalSize,
  771. wcsistr);
  772. }