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.

591 lines
13 KiB

  1. // STRUTIL.CPP
  2. //
  3. // Assorted string utility functions for use in NetMeeting components.
  4. // Derived from STRCORE.CPP.
  5. #include "precomp.h"
  6. #include <cstring.hpp>
  7. // global helper functions for Unicode support in a DBCS environment
  8. int UnicodeCompare(PCWSTR s, PCWSTR t)
  9. {
  10. // Treat NULL pointers like empty strings
  11. // at the bottom of the collating order.
  12. if (IsEmptyStringW(t)) {
  13. if (IsEmptyStringW(s)) {
  14. return 0;
  15. }
  16. else {
  17. return 1;
  18. }
  19. }
  20. // Done with empty string cases,
  21. // so now do real compare.
  22. for ( ; *s == *t; s++, t++) {
  23. if (!*s) {
  24. return 0;
  25. }
  26. }
  27. return (*s > *t) ? 1 : -1;
  28. }
  29. PWSTR NewUnicodeString(PCWSTR _wszText)
  30. {
  31. PWSTR wszText = NULL;
  32. UINT nChar;
  33. if (_wszText) {
  34. nChar = lstrlenW(_wszText) + 1;
  35. wszText = new WCHAR[nChar];
  36. if (wszText) {
  37. CopyMemory((void *)wszText,
  38. _wszText,
  39. nChar * sizeof(WCHAR));
  40. }
  41. }
  42. return wszText;
  43. }
  44. PWSTR DBCSToUnicode(UINT uCodePage, PCSTR szText)
  45. {
  46. int nChar;
  47. PWSTR wszText = NULL;
  48. if (szText) {
  49. nChar = MultiByteToWideChar(uCodePage,
  50. 0, // character-type options
  51. szText,
  52. -1, // NULL terminated string
  53. NULL, // return buffer (not used)
  54. 0); // getting length of Unicode string
  55. if (nChar) {
  56. wszText = new WCHAR[nChar];
  57. if (wszText) {
  58. nChar = MultiByteToWideChar(uCodePage,
  59. 0, // character-type options
  60. szText,
  61. -1, // NULL terminated string
  62. wszText, // return buffer
  63. nChar); // length of return buffer
  64. if (!nChar) {
  65. delete wszText;
  66. wszText = NULL;
  67. }
  68. }
  69. }
  70. }
  71. return wszText;
  72. }
  73. PSTR UnicodeToDBCS(UINT uCodePage, PCWSTR wszText)
  74. {
  75. int nChar;
  76. PSTR szText = NULL;
  77. if (wszText) {
  78. nChar = WideCharToMultiByte(uCodePage,
  79. 0, // character-type options
  80. wszText,
  81. -1, // NULL terminated string
  82. NULL, // return buffer (not used)
  83. 0, // getting length of DBCS string
  84. NULL,
  85. NULL);
  86. if (nChar) {
  87. szText = new CHAR[nChar];
  88. if (szText) {
  89. nChar = WideCharToMultiByte(uCodePage,
  90. 0, // character-type options
  91. wszText,
  92. -1, // NULL terminated string
  93. szText, // return buffer
  94. nChar, // length of return buffer
  95. NULL,
  96. NULL);
  97. if (!nChar) {
  98. delete szText;
  99. szText = NULL;
  100. }
  101. }
  102. }
  103. }
  104. return szText;
  105. }
  106. BOOL UnicodeIsNumber(PCWSTR wszText)
  107. {
  108. // If there are no characters, then treat it as not being a number.
  109. if (!wszText || !*wszText) {
  110. return FALSE;
  111. }
  112. // If any characters are not digits, then return FALSE.
  113. do {
  114. if ((*wszText < L'0') || (*wszText > L'9')) {
  115. return FALSE;
  116. }
  117. } while(*++wszText);
  118. // Got here so all characters are digits.
  119. return TRUE;
  120. }
  121. /* G U I D T O S Z */
  122. /*----------------------------------------------------------------------------
  123. %%Function: GuidToSz
  124. Convert the guid to a special hex string.
  125. Assumes lpchDest has space for at least sizeof(GUID)*2 +6 chars.
  126. LENGTH_SZGUID_FORMATTED is 30 and includes space for the null terminator.
  127. Note the difference between this and UuidToString (or StringFromGUID2)
  128. GUID Format: {12345678-1234-1234-1234567890123456}
  129. ----------------------------------------------------------------------------*/
  130. VOID GuidToSz(GUID * pguid, LPTSTR lpchDest)
  131. {
  132. ASSERT(NULL != pguid);
  133. ASSERT(NULL != lpchDest);
  134. wsprintf(lpchDest, TEXT("{%08X-%04X-%04X-%02X%02X-"),
  135. pguid->Data1, pguid->Data2, pguid->Data3, pguid->Data4[0], pguid->Data4[1]);
  136. lpchDest += 1+8+1+4+1+4+1+2+2+1;
  137. for (int i = 2; i < 8; i++)
  138. {
  139. wsprintf(lpchDest, TEXT("%02X"), pguid->Data4[i]);
  140. lpchDest += 2;
  141. }
  142. lstrcpy(lpchDest, TEXT("}") );
  143. }
  144. /* S Z F I N D L A S T C H */
  145. /*----------------------------------------------------------------------------
  146. %%Function: SzFindLastCh
  147. Returns a pointer to the ch within the lpsz or NULL if not found
  148. ----------------------------------------------------------------------------*/
  149. LPTSTR SzFindLastCh(LPTSTR lpsz, TCHAR ch)
  150. {
  151. LPTSTR lpchRet;
  152. for (lpchRet = NULL; *lpsz; lpsz = CharNext(lpsz))
  153. {
  154. if (ch == *lpsz)
  155. lpchRet = lpsz;
  156. }
  157. return lpchRet;
  158. }
  159. /* T R I M S Z */
  160. /*-------------------------------------------------------------------------
  161. %%Function: TrimSz
  162. Trim the whitespace around string.
  163. Returns the number of characters in the string.
  164. (chars/bytes in ANSI and DBCS, WCHARs/words in UNICODE)
  165. -------------------------------------------------------------------------*/
  166. UINT TrimSz(PTCHAR psz)
  167. {
  168. UINT ich; // character index into rgwCharType
  169. PTCHAR pchFirst;
  170. PTCHAR pchLast;
  171. PTCHAR pchCurr;
  172. WORD rgwCharType[MAX_PATH];
  173. if ((NULL == psz) || (0 == lstrlen(psz)))
  174. {
  175. return 0;
  176. }
  177. if (!GetStringTypeEx(LOCALE_SYSTEM_DEFAULT, CT_CTYPE1, psz, -1, rgwCharType))
  178. {
  179. WARNING_OUT(("TrimSz: Problem with GetStringTypeEx"));
  180. return 0;
  181. }
  182. // search for first non-space
  183. pchFirst = psz;
  184. ich = 0;
  185. while (_T('\0') != *pchFirst)
  186. {
  187. if (!(C1_SPACE & rgwCharType[ich]))
  188. break;
  189. pchFirst = CharNext(pchFirst);
  190. ich++;
  191. }
  192. if (_T('\0') == *pchFirst)
  193. {
  194. // The entire string is empty!
  195. *psz = _T('\0');
  196. return 0;
  197. }
  198. // search for last non-space
  199. pchCurr = pchFirst;
  200. pchLast = pchCurr;
  201. while (_T('\0') != *pchCurr)
  202. {
  203. if (!(C1_SPACE & rgwCharType[ich]))
  204. {
  205. pchLast = pchCurr;
  206. }
  207. pchCurr = CharNext(pchCurr);
  208. ich++;
  209. }
  210. ASSERT(_T('\0') != *pchLast);
  211. // Null terminate the string
  212. pchLast = CharNext(pchLast);
  213. *pchLast = _T('\0');
  214. // Update the original string
  215. lstrcpy(psz, pchFirst);
  216. // Return the new length
  217. return lstrlen(psz);
  218. }
  219. // Implement lstrcpyW when not on a Unicode platform
  220. #if !defined(UNICODE)
  221. /* L S T R C P Y W */
  222. /*-------------------------------------------------------------------------
  223. %%Function: LStrCpyW
  224. -------------------------------------------------------------------------*/
  225. LPWSTR LStrCpyW(LPWSTR pszDest, LPWSTR pszSrc)
  226. {
  227. ASSERT(NULL != pszDest);
  228. ASSERT(NULL != pszSrc);
  229. if ((NULL != pszDest) && (NULL != pszSrc))
  230. {
  231. LPWSTR pszT = pszDest;
  232. while (0 != (*pszT++ = *pszSrc++))
  233. ;
  234. }
  235. return pszDest;
  236. }
  237. /* L S T R C P Y N W */
  238. /*-------------------------------------------------------------------------
  239. %%Function: LStrCpyNW
  240. -------------------------------------------------------------------------*/
  241. LPWSTR LStrCpyNW(LPWSTR pszDest, LPCWSTR pszSrc, INT iMaxLength)
  242. {
  243. ASSERT(NULL != pszDest);
  244. ASSERT(NULL != pszSrc);
  245. if ((NULL != pszDest) && (NULL != pszSrc))
  246. {
  247. LPWSTR pszT = pszDest;
  248. while ((--iMaxLength > 0) &&
  249. (0 != (*pszT++ = *pszSrc++)))
  250. {
  251. /*EXPLICIT */ ;
  252. }
  253. if (0 == iMaxLength)
  254. {
  255. *pszT = L'\0';
  256. }
  257. }
  258. return pszDest;
  259. }
  260. #endif // !defined(UNICODE)
  261. /* _ S T R C H R */
  262. /*-------------------------------------------------------------------------
  263. %%Function: _StrChr
  264. -------------------------------------------------------------------------*/
  265. LPCTSTR _StrChr ( LPCTSTR pcsz, TCHAR c )
  266. {
  267. LPCTSTR pcszFound = NULL;
  268. if (pcsz)
  269. {
  270. while (*pcsz)
  271. {
  272. if (*pcsz == c)
  273. {
  274. pcszFound = pcsz;
  275. break;
  276. }
  277. pcsz = CharNext(pcsz);
  278. }
  279. }
  280. return pcszFound;
  281. }
  282. /* _ S T R C M P N */
  283. /*-------------------------------------------------------------------------
  284. %%Function: _StrCmpN
  285. This does a case-sensitive compare of two strings, pcsz1 and pcsz2, of
  286. at most cchMax characters. If we reach the end of either string, we
  287. also stop, and the strings match if the other string is also at its end.
  288. This function is NOT DBCS safe.
  289. -------------------------------------------------------------------------*/
  290. int _StrCmpN(LPCTSTR pcsz1, LPCTSTR pcsz2, UINT cchMax)
  291. {
  292. UINT ich;
  293. for (ich = 0; ich < cchMax; ich++)
  294. {
  295. if (*pcsz1 != *pcsz2)
  296. {
  297. // No match.
  298. return((*pcsz1 > *pcsz2) ? 1 : -1);
  299. }
  300. //
  301. // Are we at the end (if we're here, both strings are at the
  302. // end. If only one is, the above compare code kicks in.
  303. //
  304. if ('\0' == *pcsz1)
  305. return 0;
  306. pcsz1++;
  307. pcsz2++;
  308. }
  309. // If we get here, cchMax characters matched, so success.
  310. return 0;
  311. }
  312. /* _ S T R S T R */
  313. /*-------------------------------------------------------------------------
  314. %%Function: _StrStr
  315. -------------------------------------------------------------------------*/
  316. // BUGBUG - This function is *not* DBCS-safe
  317. LPCTSTR _StrStr (LPCTSTR pcsz1, LPCTSTR pcsz2)
  318. {
  319. PTSTR pszcp = (PTSTR) pcsz1;
  320. PTSTR pszs1, pszs2;
  321. if ( !*pcsz2 )
  322. return pcsz1;
  323. while (*pszcp)
  324. {
  325. pszs1 = pszcp;
  326. pszs2 = (PTSTR) pcsz2;
  327. while ( *pszs1 && *pszs2 && !(*pszs1-*pszs2) )
  328. pszs1++, pszs2++;
  329. if (!*pszs2)
  330. return pszcp;
  331. pszcp++;
  332. }
  333. return NULL;
  334. }
  335. /* _ S T R S T R */
  336. /*-------------------------------------------------------------------------
  337. %%Function: _StrStr
  338. -------------------------------------------------------------------------*/
  339. // BUGBUG - This function is *not* DBCS-safe
  340. LPCWSTR _StrStrW(LPCWSTR pcsz1, LPCWSTR pcsz2)
  341. {
  342. PWSTR pszcp = (PWSTR) pcsz1;
  343. while (*pszcp)
  344. {
  345. PWSTR psz1 = pszcp;
  346. PWSTR psz2 = (PWSTR) pcsz2;
  347. while ( *psz1 && *psz2 && !(*psz1-*psz2) )
  348. {
  349. psz1++;
  350. psz2++;
  351. }
  352. if (!*psz2)
  353. return pszcp;
  354. pszcp++;
  355. }
  356. return NULL;
  357. }
  358. /* _ S T R P B R K */
  359. /*-------------------------------------------------------------------------
  360. %%Function: _StrPbrkA, _StrPbrkW
  361. Private, DBCS-safe version of CRT strpbrk function. Like strchr but
  362. accepts more than one character for which to search. The ANSI version
  363. does not support searching for DBCS chars.
  364. In the Unicode version, we do a nested search. In the ANSI version,
  365. we build up a table of chars and use this to scan the string.
  366. -------------------------------------------------------------------------*/
  367. LPSTR _StrPbrkA(LPCSTR pcszString, LPCSTR pcszSearch)
  368. {
  369. ASSERT(NULL != pcszString && NULL != pcszSearch);
  370. BYTE rgbSearch[(UCHAR_MAX + 1) / CHAR_BIT];
  371. ZeroMemory(rgbSearch, sizeof(rgbSearch));
  372. // Scan the search string
  373. while ('\0' != *pcszSearch)
  374. {
  375. ASSERT(!IsDBCSLeadByte(*pcszSearch));
  376. // Set the appropriate bit in the appropriate byte
  377. rgbSearch[*pcszSearch / CHAR_BIT] |= (1 << (*pcszSearch % CHAR_BIT));
  378. pcszSearch++;
  379. }
  380. // Scan the source string, compare to the bits in the search array
  381. while ('\0' != *pcszString)
  382. {
  383. if (rgbSearch[*pcszString / CHAR_BIT] & (1 << (*pcszString % CHAR_BIT)))
  384. {
  385. // We have a match
  386. return (LPSTR) pcszString;
  387. }
  388. pcszString = CharNextA(pcszString);
  389. }
  390. // If we get here, there was no match
  391. return NULL;
  392. }
  393. LPWSTR _StrPbrkW(LPCWSTR pcszString, LPCWSTR pcszSearch)
  394. {
  395. ASSERT(NULL != pcszString && NULL != pcszSearch);
  396. // Scan the string, matching each character against those in the search string
  397. while (L'\0' != *pcszString)
  398. {
  399. LPCWSTR pcszCurrent = pcszSearch;
  400. while (L'\0' != *pcszCurrent)
  401. {
  402. if (*pcszString == *pcszCurrent)
  403. {
  404. // We have a match
  405. return (LPWSTR) pcszString;
  406. }
  407. // pcszCurrent = CharNextW(pcszCurrent);
  408. pcszCurrent++;
  409. }
  410. // pcszString = CharNextW(pcszString);
  411. pcszString++;
  412. }
  413. // If we get here, there was no match
  414. return NULL;
  415. }
  416. // BUGBUG - Are DecimalStringToUINT and StrToInt the same?
  417. /* D E C I M A L S T R I N G T O U I N T */
  418. /*-------------------------------------------------------------------------
  419. %%Function: DecimalStringToUINT
  420. -------------------------------------------------------------------------*/
  421. UINT DecimalStringToUINT(LPCTSTR pcszString)
  422. {
  423. ASSERT(pcszString);
  424. UINT uRet = 0;
  425. LPTSTR pszStr = (LPTSTR) pcszString;
  426. while (_T('\0') != pszStr[0])
  427. {
  428. ASSERT((pszStr[0] >= _T('0')) &&
  429. (pszStr[0] <= _T('9')));
  430. uRet = (10 * uRet) + (BYTE) (pszStr[0] - _T('0'));
  431. pszStr++; // NOTE: DBCS characters are not allowed!
  432. }
  433. return uRet;
  434. }
  435. /****************************************************************************
  436. FUNCTION: StrToInt
  437. PURPOSE: The atoi equivalent, to avoid using the C runtime lib
  438. PARAMETERS: lpSrc - pointer to a source string to convert to integer
  439. RETURNS: 0 for failure, the integer otherwise
  440. (what if the string was converted to 0 ?)
  441. ****************************************************************************/
  442. int WINAPI RtStrToInt(LPCTSTR lpSrc) // atoi()
  443. {
  444. int n = 0;
  445. BOOL bNeg = FALSE;
  446. if (*lpSrc == _T('-')) {
  447. bNeg = TRUE;
  448. lpSrc++;
  449. }
  450. while (((*lpSrc) >= _T('0') && (*lpSrc) <= _T('9')))
  451. {
  452. n *= 10;
  453. n += *lpSrc - _T('0');
  454. lpSrc++;
  455. }
  456. return bNeg ? -n : n;
  457. }
  458. /* _ S T R L W R W */
  459. /*-------------------------------------------------------------------------
  460. %%Function: _StrLwrW
  461. -------------------------------------------------------------------------*/
  462. // BUGBUG - This function does *not* handle all UNICODE character sets
  463. LPWSTR _StrLwrW(LPWSTR pwszSrc)
  464. {
  465. for (PWSTR pwszCur = pwszSrc; (L'\0' != *pwszCur); pwszCur++)
  466. {
  467. if ( (*pwszCur >= L'A') && (*pwszCur <= L'Z') )
  468. {
  469. *pwszCur = *pwszCur - L'A' + L'a';
  470. }
  471. }
  472. return pwszSrc;
  473. }