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.

2741 lines
77 KiB

  1. //============================================================================
  2. //
  3. // DBCS and UNICODE aware string routines
  4. //
  5. //
  6. //============================================================================
  7. #include "priv.h"
  8. #include "ids.h"
  9. #include <winnlsp.h> // Get private NORM_ flag for StrEqIntl()
  10. #include <mluisupp.h>
  11. #include "varutil.h"
  12. BOOL UnicodeFromAnsi(LPWSTR *, LPCSTR, LPWSTR, int);
  13. #define IS_DIGITA(ch) InRange(ch, '0', '9')
  14. #define IS_DIGITW(ch) InRange(ch, L'0', L'9')
  15. #define DM_INTERVAL 0
  16. #ifdef UNIX
  17. #ifdef BIG_ENDIAN
  18. #define READNATIVEWORD(x) MAKEWORD(*(char*)(x), *(char*)((char*)(x) + 1))
  19. #else
  20. #define READNATIVEWORD(x) MAKEWORD(*(char*)((char*)(x) + 1), *(char*)(x))
  21. #endif
  22. #else
  23. #define READNATIVEWORD(x) (*(UNALIGNED WORD *)x)
  24. #endif
  25. __inline BOOL IsAsciiA(char ch)
  26. {
  27. return !(ch & 0x80);
  28. }
  29. __inline BOOL IsAsciiW(WCHAR ch)
  30. {
  31. return ch < 128;
  32. }
  33. __inline char Ascii_ToLowerA(char ch)
  34. {
  35. return (ch >= 'A' && ch <= 'Z') ? (ch - 'A' + 'a') : ch;
  36. }
  37. __inline WCHAR Ascii_ToLowerW(WCHAR ch)
  38. {
  39. return (ch >= L'A' && ch <= L'Z') ? (ch - L'A' + L'a') : ch;
  40. }
  41. // WARNING: all of these APIs do not setup DS, so you can not access
  42. // any data in the default data seg of this DLL.
  43. //
  44. // do not create any global variables... talk to chrisg if you don't
  45. // understand thid
  46. /*
  47. * ChrCmp - Case sensitive character comparison for DBCS
  48. * Assumes w1, wMatch are characters to be compared
  49. * Return FALSE if they match, TRUE if no match
  50. */
  51. __inline BOOL ChrCmpA_inline(WORD w1, WORD wMatch)
  52. {
  53. /* Most of the time this won't match, so test it first for speed.
  54. */
  55. if (LOBYTE(w1) == LOBYTE(wMatch))
  56. {
  57. if (IsDBCSLeadByte(LOBYTE(w1)))
  58. {
  59. return(w1 != wMatch);
  60. }
  61. return FALSE;
  62. }
  63. return TRUE;
  64. }
  65. __inline BOOL ChrCmpW_inline(WCHAR w1, WCHAR wMatch)
  66. {
  67. return(!(w1 == wMatch));
  68. }
  69. /*
  70. * ChrCmpI - Case insensitive character comparison for DBCS
  71. * Assumes w1, wMatch are characters to be compared;
  72. * HIBYTE of wMatch is 0 if not a DBC
  73. * Return FALSE if match, TRUE if not
  74. */
  75. BOOL ChrCmpIA(WORD w1, WORD wMatch)
  76. {
  77. char sz1[3], sz2[3];
  78. if (IsDBCSLeadByte(sz1[0] = LOBYTE(w1)))
  79. {
  80. sz1[1] = HIBYTE(w1);
  81. sz1[2] = '\0';
  82. }
  83. else
  84. sz1[1] = '\0';
  85. #if defined(MWBIG_ENDIAN)
  86. sz2[0] = LOBYTE(wMatch);
  87. sz2[1] = HIBYTE(wMatch);
  88. #else
  89. *(WORD *)sz2 = wMatch;
  90. #endif
  91. sz2[2] = '\0';
  92. return lstrcmpiA(sz1, sz2);
  93. }
  94. BOOL ChrCmpIW(WCHAR w1, WCHAR wMatch)
  95. {
  96. WCHAR sz1[2], sz2[2];
  97. sz1[0] = w1;
  98. sz1[1] = '\0';
  99. sz2[0] = wMatch;
  100. sz2[1] = '\0';
  101. return StrCmpIW(sz1, sz2);
  102. }
  103. LPWSTR Shlwapi_StrCpyW(LPWSTR pszDst, LPCWSTR pszSrc)
  104. {
  105. LPWSTR psz = pszDst;
  106. RIPMSG(NULL!=pszDst, "StrCpyW: Caller passed invalid pszDst");
  107. RIPMSG(pszSrc && IS_VALID_STRING_PTRW(pszSrc, -1), "StrCpyW: Caller passed invalid pszSrc");
  108. if (pszDst && pszSrc)
  109. {
  110. while (*pszDst++ = *pszSrc++)
  111. ;
  112. }
  113. return psz;
  114. }
  115. //*** StrCpyNX[AW] -- just like StrCpyN[AW], but returns ptr to EOS
  116. // NOTES
  117. // do we really need 'A' version? (for now we do for shell32 on 'old'
  118. // platforms that we test on but don't ship)
  119. LPSTR StrCpyNXA(LPSTR pszDst, LPCSTR pszSrc, int cchMax)
  120. {
  121. RIPMSG(cchMax >= 0, "StrCpyNXA: Caller passed bad cchMax");
  122. RIPMSG(cchMax < 0 || (pszDst && IS_VALID_WRITE_BUFFER(pszDst, char, cchMax)), "StrCpyNXA: Caller passed bad pszDst");
  123. RIPMSG(pszSrc && IS_VALID_STRING_PTRA(pszSrc, -1), "StrCpyNXA: Caller passed bad pszSrc");
  124. // NOTE: Cannot use DEBUGWhackPathBuffer before copying because src and
  125. // dest might overlap. Must delay whacking until after we're done.
  126. if (0 < cchMax)
  127. {
  128. if (!pszSrc)
  129. goto NullItOut;
  130. // Leave room for the null terminator
  131. while (0 < --cchMax)
  132. {
  133. if (!(*pszDst++ = *pszSrc++))
  134. {
  135. --pszDst;
  136. break;
  137. }
  138. }
  139. cchMax++;
  140. // in the cchMax>1 case, pszDst already points at the NULL, but reassigning it doesn't hurt
  141. NullItOut:
  142. // Whack the unused part of the buffer
  143. DEBUGWhackPathBufferA(pszDst, cchMax);
  144. *pszDst = '\0';
  145. }
  146. return pszDst;
  147. }
  148. LPWSTR StrCpyNXW(LPWSTR pszDst, LPCWSTR pszSrc, int cchMax)
  149. {
  150. RIPMSG(cchMax >= 0, "StrCpyNXW: Caller passed bad cchMax");
  151. RIPMSG(cchMax < 0 || (pszDst && IS_VALID_WRITE_BUFFER(pszDst, WCHAR, cchMax)), "StrCpyNXW: Caller passed bad pszDst");
  152. RIPMSG(pszSrc && IS_VALID_STRING_PTRW(pszSrc, -1), "StrCpyNXW: Caller passed bad pszSrc");
  153. // NOTE: Cannot use DEBUGWhackPathBuffer before copying because src and
  154. // dest might overlap. Must delay whacking until after we're done.
  155. if (0 < cchMax)
  156. {
  157. if (!pszSrc) // a test app passed in a NULL src ptr and we faulted, let's not fault here.
  158. goto NullItOut;
  159. // Leave room for the null terminator
  160. while (0 < --cchMax)
  161. {
  162. if (!(*pszDst++ = *pszSrc++))
  163. {
  164. --pszDst;
  165. break;
  166. }
  167. }
  168. cchMax++;
  169. // in the cchMax>1 case, pszDst already points at the NULL, but reassigning it doesn't hurt
  170. NullItOut:
  171. // Whack the unused part of the buffer
  172. DEBUGWhackPathBufferW(pszDst, cchMax);
  173. *pszDst = L'\0';
  174. }
  175. return pszDst;
  176. }
  177. LPWSTR StrCpyNW(LPWSTR pszDst, LPCWSTR pszSrc, int cchMax)
  178. {
  179. StrCpyNXW(pszDst, pszSrc, cchMax);
  180. return pszDst;
  181. }
  182. LPWSTR Shlwapi_StrCatW(LPWSTR pszDst, LPCWSTR pszSrc)
  183. {
  184. LPWSTR psz = pszDst;
  185. RIPMSG(pszDst && IS_VALID_STRING_PTRW(pszDst, -1), "StrCatW: Caller passed invalid pszDst");
  186. RIPMSG(pszSrc && IS_VALID_STRING_PTRW(pszSrc, -1), "StrCatW: Caller passed invalid pszSrc");
  187. if (pszDst && pszSrc)
  188. {
  189. while (0 != *pszDst)
  190. pszDst++;
  191. while (*pszDst++ = *pszSrc++)
  192. ;
  193. }
  194. return psz;
  195. }
  196. LWSTDAPI_(LPWSTR) StrCatBuffW(LPWSTR pszDest, LPCWSTR pszSrc, int cchDestBuffSize)
  197. {
  198. RIPMSG(pszDest && IS_VALID_STRING_PTRW(pszDest, -1), "StrCatBuffW: Caller passed invalid pszDest");
  199. RIPMSG(pszSrc && IS_VALID_STRING_PTRW(pszSrc, -1), "StrCatBuffW: Caller passed invalid pszSrc");
  200. RIPMSG(cchDestBuffSize >= 0, "StrCatBuffW: Caller passed invalid cchDestBuffSize");
  201. RIPMSG(!(pszDest && IS_VALID_STRING_PTRW(pszDest, -1)) || cchDestBuffSize<0 || lstrlenW(pszDest)<cchDestBuffSize, "StrCatBuffW: Caller passed odd pszDest - string larger than cchDestBuffSize!");
  202. DEBUGWhackPathStringW(pszDest, cchDestBuffSize);
  203. if (pszDest && pszSrc)
  204. {
  205. LPWSTR psz = pszDest;
  206. // we walk forward till we find the end of pszDest, subtracting
  207. // from cchDestBuffSize as we go.
  208. while (*psz)
  209. {
  210. psz++;
  211. cchDestBuffSize--;
  212. }
  213. if (cchDestBuffSize > 0)
  214. {
  215. // call the shlwapi function here because win95 does not have lstrcpynW
  216. StrCpyNW(psz, pszSrc, cchDestBuffSize);
  217. }
  218. }
  219. return pszDest;
  220. }
  221. LWSTDAPI_(LPSTR) StrCatBuffA(LPSTR pszDest, LPCSTR pszSrc, int cchDestBuffSize)
  222. {
  223. RIPMSG(pszDest && IS_VALID_STRING_PTRA(pszDest, -1), "StrCatBuffA: Caller passed invalid pszDest");
  224. RIPMSG(pszSrc && IS_VALID_STRING_PTRA(pszSrc, -1), "StrCatBuffA: Caller passed invalid pszSrc");
  225. RIPMSG(cchDestBuffSize >= 0, "StrCatBuffA: Caller passed invalid cchDestBuffSize");
  226. RIPMSG(!(pszDest && IS_VALID_STRING_PTRA(pszDest, -1)) || cchDestBuffSize<0 || lstrlen(pszDest)<cchDestBuffSize, "StrCatBuffA: Caller passed odd pszDest - string larger than cchDestBuffSize!");
  227. DEBUGWhackPathStringA(pszDest, cchDestBuffSize);
  228. if (pszDest && pszSrc)
  229. {
  230. LPSTR psz = pszDest;
  231. // we walk forward till we find the end of pszDest, subtracting
  232. // from cchDestBuffSize as we go.
  233. while (*psz)
  234. {
  235. psz++;
  236. cchDestBuffSize--;
  237. }
  238. if (cchDestBuffSize > 0)
  239. {
  240. // Let kernel do the work for us.
  241. //
  242. // WARNING: We might generate a truncated DBCS sting becuase kernel's lstrcpynA
  243. // dosent check for this. Ask me if I care.
  244. lstrcpynA(psz, pszSrc, cchDestBuffSize);
  245. }
  246. }
  247. return pszDest;
  248. }
  249. /* StrNCat(front, back, count) - append count chars of back onto front
  250. */
  251. LPSTR Shlwapi_StrNCatA(LPSTR front, LPCSTR back, int cchMax)
  252. {
  253. LPSTR start = front;
  254. RIPMSG(front && IS_VALID_STRING_PTRA(front, -1), "StrNCatA: Caller passed invalid front");
  255. RIPMSG(back && IS_VALID_STRING_PTRA(front, cchMax), "StrNCatA: Caller passed invalid back");
  256. RIPMSG(cchMax >= 0, "StrNCatA: Caller passed invalid cchMax");
  257. if (front && back)
  258. {
  259. while (*front++)
  260. ;
  261. front--;
  262. lstrcpyn(front, back, cchMax);
  263. }
  264. return(start);
  265. }
  266. LPWSTR Shlwapi_StrNCatW(LPWSTR front, LPCWSTR back, int cchMax)
  267. {
  268. LPWSTR start = front;
  269. RIPMSG(front && IS_VALID_STRING_PTRW(front, -1), "StrNCatW: Caller passed invalid front");
  270. RIPMSG(back && IS_VALID_STRING_PTRW(front, cchMax), "StrNCatW: Caller passed invalid back");
  271. RIPMSG(cchMax >= 0, "StrNCatW: Caller passed invalid cchMax");
  272. if (front && back)
  273. {
  274. while (*front++)
  275. ;
  276. front--;
  277. StrCpyNW(front, back, cchMax);
  278. }
  279. return(start);
  280. }
  281. /*
  282. * StrChr - Find first occurrence of character in string
  283. * Assumes lpStart points to start of null terminated string
  284. * wMatch is the character to match
  285. * returns ptr to the first occurrence of ch in str, NULL if not found.
  286. */
  287. LPSTR _StrChrA(LPCSTR lpStart, WORD wMatch, BOOL fMBCS)
  288. {
  289. if (fMBCS) {
  290. for ( ; *lpStart; lpStart = AnsiNext(lpStart))
  291. {
  292. if (!ChrCmpA_inline(READNATIVEWORD(lpStart), wMatch))
  293. return((LPSTR)lpStart);
  294. }
  295. } else {
  296. for ( ; *lpStart; lpStart++)
  297. {
  298. if ((BYTE)*lpStart == LOBYTE(wMatch)) {
  299. return((LPSTR)lpStart);
  300. }
  301. }
  302. }
  303. return (NULL);
  304. }
  305. LPSTR StrChrA(LPCSTR lpStart, WORD wMatch)
  306. {
  307. CPINFO cpinfo;
  308. RIPMSG(lpStart && IS_VALID_STRING_PTR(lpStart, -1), "StrChrA: caller passed bad lpStart");
  309. if (!lpStart)
  310. return NULL;
  311. return _StrChrA(lpStart, wMatch, GetCPInfo(CP_ACP, &cpinfo) && cpinfo.LeadByte[0]);
  312. }
  313. #ifdef ALIGNMENT_SCENARIO
  314. LPWSTR StrChrSlowW(const UNALIGNED WCHAR *lpStart, WCHAR wMatch)
  315. {
  316. for ( ; *lpStart; lpStart++)
  317. {
  318. if (!ChrCmpW_inline(*lpStart, wMatch))
  319. {
  320. return((LPWSTR)lpStart);
  321. }
  322. }
  323. return NULL;
  324. }
  325. #endif
  326. LPWSTR StrChrW(LPCWSTR lpStart, WCHAR wMatch)
  327. {
  328. RIPMSG(lpStart && IS_VALID_STRING_PTRW(lpStart, -1), "StrChrW: caller passed bad lpStart");
  329. if (!lpStart)
  330. return NULL;
  331. //
  332. // raymondc
  333. // Apparently, somebody is passing unaligned strings to StrChrW.
  334. // Find out who and make them stop.
  335. //
  336. RIPMSG(!((ULONG_PTR)lpStart & 1), "StrChrW: caller passed UNALIGNED lpStart"); // Assert alignedness
  337. #ifdef ALIGNMENT_SCENARIO
  338. //
  339. // Since unaligned strings arrive so rarely, put the slow
  340. // version in a separate function so the common case stays
  341. // fast. Believe it or not, we call StrChrW so often that
  342. // it is now a performance-sensitive function!
  343. //
  344. if ((ULONG_PTR)lpStart & 1)
  345. return StrChrSlowW(lpStart, wMatch);
  346. #endif
  347. for ( ; *lpStart; lpStart++)
  348. {
  349. if (!ChrCmpW_inline(*lpStart, wMatch))
  350. {
  351. return((LPWSTR)lpStart);
  352. }
  353. }
  354. return (NULL);
  355. }
  356. /*
  357. * StrChrN - Find first occurrence of character in string
  358. * Assumes lpStart points to start of null terminated string
  359. * wMatch is the character to match
  360. * returns ptr to the first occurrence of ch in str, NULL if not found.
  361. */
  362. #ifdef ALIGNMENT_SCENARIO
  363. LPWSTR StrChrSlowNW(const UNALIGNED WCHAR *lpStart, WCHAR wMatch, UINT cchMax)
  364. {
  365. LPCWSTR lpSentinel = lpStart + cchMax;
  366. for ( ; *lpStart && lpStart < lpSentinel; lpStart++)
  367. {
  368. if (!ChrCmpW_inline(*lpStart, wMatch))
  369. {
  370. return((LPWSTR)lpStart);
  371. }
  372. }
  373. }
  374. #endif
  375. LPWSTR StrChrNW(LPCWSTR lpStart, WCHAR wMatch, UINT cchMax)
  376. {
  377. LPCWSTR lpSentinel = lpStart + cchMax;
  378. RIPMSG(lpStart && IS_VALID_STRING_PTRW(lpStart, -1), "StrChrNW: caller passed bad lpStart");
  379. if (!lpStart)
  380. return NULL;
  381. //
  382. // raymondc
  383. // Apparently, somebody is passing unaligned strings to StrChrW.
  384. // Find out who and make them stop.
  385. //
  386. RIPMSG(!((ULONG_PTR)lpStart & 1), "StrChrNW: caller passed UNALIGNED lpStart"); // Assert alignedness
  387. #ifdef ALIGNMENT_SCENARIO
  388. //
  389. // Since unaligned strings arrive so rarely, put the slow
  390. // version in a separate function so the common case stays
  391. // fast. Believe it or not, we call StrChrW so often that
  392. // it is now a performance-sensitive function!
  393. //
  394. if ((ULONG_PTR)lpStart & 1)
  395. return StrChrSlowNW(lpStart, wMatch, cchMax);
  396. #endif
  397. for ( ; *lpStart && lpStart<lpSentinel; lpStart++)
  398. {
  399. if (!ChrCmpW_inline(*lpStart, wMatch))
  400. {
  401. return((LPWSTR)lpStart);
  402. }
  403. }
  404. return (NULL);
  405. }
  406. /*
  407. * StrRChr - Find last occurrence of character in string
  408. * Assumes lpStart points to start of string
  409. * lpEnd points to end of string (NOT included in search)
  410. * wMatch is the character to match
  411. * returns ptr to the last occurrence of ch in str, NULL if not found.
  412. */
  413. LPSTR StrRChrA(LPCSTR lpStart, LPCSTR lpEnd, WORD wMatch)
  414. {
  415. LPCSTR lpFound = NULL;
  416. RIPMSG(lpStart && IS_VALID_STRING_PTR(lpStart, -1), "StrRChrA: caller passed bad lpStart");
  417. RIPMSG(!lpEnd || lpEnd <= lpStart + lstrlenA(lpStart), "StrRChrA: caller passed bad lpEnd");
  418. // don't need to check for NULL lpStart
  419. if (!lpEnd)
  420. lpEnd = lpStart + lstrlenA(lpStart);
  421. for ( ; lpStart < lpEnd; lpStart = AnsiNext(lpStart))
  422. {
  423. // (ChrCmp returns FALSE when characters match)
  424. if (!ChrCmpA_inline(READNATIVEWORD(lpStart), wMatch))
  425. lpFound = lpStart;
  426. }
  427. return ((LPSTR)lpFound);
  428. }
  429. LPWSTR StrRChrW(LPCWSTR lpStart, LPCWSTR lpEnd, WCHAR wMatch)
  430. {
  431. LPCWSTR lpFound = NULL;
  432. RIPMSG(lpStart && IS_VALID_STRING_PTRW(lpStart, -1), "StrRChrW: caller passed bad lpStart");
  433. RIPMSG(!lpEnd || lpEnd <= lpStart + lstrlenW(lpStart), "StrRChrW: caller passed bad lpEnd");
  434. // don't need to check for NULL lpStart
  435. if (!lpEnd)
  436. lpEnd = lpStart + lstrlenW(lpStart);
  437. for ( ; lpStart < lpEnd; lpStart++)
  438. {
  439. if (!ChrCmpW_inline(*lpStart, wMatch))
  440. lpFound = lpStart;
  441. }
  442. return ((LPWSTR)lpFound);
  443. }
  444. /*
  445. * StrChrI - Find first occurrence of character in string, case insensitive
  446. * Assumes lpStart points to start of null terminated string
  447. * wMatch is the character to match
  448. * returns ptr to the first occurrence of ch in str, NULL if not found.
  449. */
  450. LPSTR StrChrIA(LPCSTR lpStart, WORD wMatch)
  451. {
  452. RIPMSG(lpStart && IS_VALID_STRING_PTRA(lpStart, -1), "StrChrIA: caller passed bad lpStart");
  453. if (lpStart)
  454. {
  455. wMatch = (UINT)(IsDBCSLeadByte(LOBYTE(wMatch)) ? wMatch : LOBYTE(wMatch));
  456. for ( ; *lpStart; lpStart = AnsiNext(lpStart))
  457. {
  458. if (!ChrCmpIA(READNATIVEWORD(lpStart), wMatch))
  459. return((LPSTR)lpStart);
  460. }
  461. }
  462. return (NULL);
  463. }
  464. LPWSTR StrChrIW(LPCWSTR lpStart, WCHAR wMatch)
  465. {
  466. RIPMSG(lpStart && IS_VALID_STRING_PTRW(lpStart, -1), "StrChrIW: caller passed bad lpStart");
  467. if (lpStart)
  468. {
  469. for ( ; *lpStart; lpStart++)
  470. {
  471. if (!ChrCmpIW(*lpStart, wMatch))
  472. return((LPWSTR)lpStart);
  473. }
  474. }
  475. return (NULL);
  476. }
  477. /*
  478. * StrChrNI - Find first occurrence of character in string, case insensitive, counted
  479. *
  480. */
  481. LPWSTR StrChrNIW(LPCWSTR lpStart, WCHAR wMatch, UINT cchMax)
  482. {
  483. RIPMSG(lpStart && IS_VALID_STRING_PTRW(lpStart, -1), "StrChrNIW: caller passed bad lpStart");
  484. if (lpStart)
  485. {
  486. LPCWSTR lpSentinel = lpStart + cchMax;
  487. for ( ; *lpStart && lpStart < lpSentinel; lpStart++)
  488. {
  489. if (!ChrCmpIW(*lpStart, wMatch))
  490. return((LPWSTR)lpStart);
  491. }
  492. }
  493. return (NULL);
  494. }
  495. /*
  496. * StrRChrI - Find last occurrence of character in string, case insensitive
  497. * Assumes lpStart points to start of string
  498. * lpEnd points to end of string (NOT included in search)
  499. * wMatch is the character to match
  500. * returns ptr to the last occurrence of ch in str, NULL if not found.
  501. */
  502. LPSTR StrRChrIA(LPCSTR lpStart, LPCSTR lpEnd, WORD wMatch)
  503. {
  504. LPCSTR lpFound = NULL;
  505. RIPMSG(lpStart && IS_VALID_STRING_PTRA(lpStart, -1), "StrRChrIA: caller passed bad lpStart");
  506. RIPMSG(!lpEnd || lpEnd <= lpStart + lstrlenA(lpStart), "StrRChrIA: caller passed bad lpEnd");
  507. if (!lpEnd)
  508. lpEnd = lpStart + lstrlenA(lpStart);
  509. wMatch = (UINT)(IsDBCSLeadByte(LOBYTE(wMatch)) ? wMatch : LOBYTE(wMatch));
  510. for ( ; lpStart < lpEnd; lpStart = AnsiNext(lpStart))
  511. {
  512. if (!ChrCmpIA(READNATIVEWORD(lpStart), wMatch))
  513. lpFound = lpStart;
  514. }
  515. return ((LPSTR)lpFound);
  516. }
  517. LPWSTR StrRChrIW(LPCWSTR lpStart, LPCWSTR lpEnd, WCHAR wMatch)
  518. {
  519. LPCWSTR lpFound = NULL;
  520. RIPMSG(lpStart && IS_VALID_STRING_PTRW(lpStart, -1), "StrRChrIW: caller passed bad lpStart");
  521. RIPMSG(!lpEnd || lpEnd <= lpStart + lstrlenW(lpStart), "StrRChrIW: caller passed bad lpEnd");
  522. if (!lpEnd)
  523. lpEnd = lpStart + lstrlenW(lpStart);
  524. for ( ; lpStart < lpEnd; lpStart++)
  525. {
  526. if (!ChrCmpIW(*lpStart, wMatch))
  527. lpFound = lpStart;
  528. }
  529. return ((LPWSTR)lpFound);
  530. }
  531. /*----------------------------------------------------------
  532. Purpose: Returns a pointer to the first occurrence of a character
  533. in psz that belongs to the set of characters in pszSet.
  534. The search does not include the null terminator.
  535. If psz contains no characters that are in the set of
  536. characters in pszSet, this function returns NULL.
  537. This function is DBCS-safe.
  538. Returns: see above
  539. Cond: --
  540. */
  541. LPSTR StrPBrkA(LPCSTR psz, LPCSTR pszSet)
  542. {
  543. RIPMSG(psz && IS_VALID_STRING_PTRA(psz, -1), "StrPBrkA: caller passed bad psz");
  544. RIPMSG(pszSet && IS_VALID_STRING_PTRA(pszSet, -1), "StrPBrkA: caller passed bad pszSet");
  545. if (psz && pszSet)
  546. {
  547. while (*psz)
  548. {
  549. LPCSTR pszSetT;
  550. for (pszSetT = pszSet; *pszSetT; pszSetT = CharNextA(pszSetT))
  551. {
  552. if (*psz == *pszSetT)
  553. {
  554. // Found first character that matches
  555. return (LPSTR)psz; // Const -> non-const
  556. }
  557. }
  558. psz = CharNextA(psz);
  559. }
  560. }
  561. return NULL;
  562. }
  563. /*----------------------------------------------------------
  564. Purpose: Returns a pointer to the first occurrence of a character
  565. in psz that belongs to the set of characters in pszSet.
  566. The search does not include the null terminator.
  567. Returns: see above
  568. Cond: --
  569. */
  570. LPWSTR WINAPI StrPBrkW(LPCWSTR psz, LPCWSTR pszSet)
  571. {
  572. RIPMSG(psz && IS_VALID_STRING_PTRW(psz, -1), "StrPBrkA: caller passed bad psz");
  573. RIPMSG(pszSet && IS_VALID_STRING_PTRW(pszSet, -1), "StrPBrkA: caller passed bad pszSet");
  574. if (psz && pszSet)
  575. {
  576. while (*psz)
  577. {
  578. LPCWSTR pszSetT;
  579. for (pszSetT = pszSet; *pszSetT; pszSetT++)
  580. {
  581. if (*psz == *pszSetT)
  582. {
  583. // Found first character that matches
  584. return (LPWSTR)psz; // Const -> non-const
  585. }
  586. }
  587. psz++;
  588. }
  589. }
  590. return NULL;
  591. }
  592. int WINAPI StrToIntA(LPCSTR lpSrc)
  593. {
  594. RIPMSG(lpSrc && IS_VALID_STRING_PTRA(lpSrc, -1), "StrToIntA: Caller passed bad lpSrc");
  595. if (lpSrc)
  596. {
  597. int n = 0;
  598. BOOL bNeg = FALSE;
  599. if (*lpSrc == '-')
  600. {
  601. bNeg = TRUE;
  602. lpSrc++;
  603. }
  604. while (IS_DIGITA(*lpSrc))
  605. {
  606. n *= 10;
  607. n += *lpSrc - '0';
  608. lpSrc++;
  609. }
  610. return bNeg ? -n : n;
  611. }
  612. return 0;
  613. }
  614. int WINAPI StrToIntW(LPCWSTR lpSrc)
  615. {
  616. RIPMSG(lpSrc && IS_VALID_STRING_PTRW(lpSrc, -1), "StrToIntW: Caller passed bad lpSrc");
  617. if (lpSrc)
  618. {
  619. int n = 0;
  620. BOOL bNeg = FALSE;
  621. if (*lpSrc == L'-')
  622. {
  623. bNeg = TRUE;
  624. lpSrc++;
  625. }
  626. while (IS_DIGITW(*lpSrc))
  627. {
  628. n *= 10;
  629. n += *lpSrc - L'0';
  630. lpSrc++;
  631. }
  632. return bNeg ? -n : n;
  633. }
  634. return 0;
  635. }
  636. /*----------------------------------------------------------
  637. Purpose: Special verion of atoi. Supports hexadecimal too.
  638. If this function returns FALSE, *phRet is set to 0.
  639. Returns: TRUE if the string is a number, or contains a partial number
  640. FALSE if the string is not a number
  641. dwFlags are STIF_ bitfield
  642. Cond: --
  643. */
  644. BOOL WINAPI StrToInt64ExW(LPCWSTR pszString, DWORD dwFlags, LONGLONG *pllRet)
  645. {
  646. BOOL bRet;
  647. RIPMSG(pszString && IS_VALID_STRING_PTRW(pszString, -1), "StrToInt64ExW: caller passed bad pszString");
  648. if (pszString)
  649. {
  650. LONGLONG n;
  651. BOOL bNeg = FALSE;
  652. LPCWSTR psz;
  653. LPCWSTR pszAdj;
  654. // Skip leading whitespace
  655. //
  656. for (psz = pszString; *psz == L' ' || *psz == L'\n' || *psz == L'\t'; psz++)
  657. ;
  658. // Determine possible explicit signage
  659. //
  660. if (*psz == L'+' || *psz == L'-')
  661. {
  662. bNeg = (*psz == L'+') ? FALSE : TRUE;
  663. psz++;
  664. }
  665. // Or is this hexadecimal?
  666. //
  667. pszAdj = psz+1;
  668. if ((STIF_SUPPORT_HEX & dwFlags) &&
  669. *psz == L'0' && (*pszAdj == L'x' || *pszAdj == L'X'))
  670. {
  671. // Yes
  672. // (Never allow negative sign with hexadecimal numbers)
  673. bNeg = FALSE;
  674. psz = pszAdj+1;
  675. pszAdj = psz;
  676. // Do the conversion
  677. //
  678. for (n = 0; ; psz++)
  679. {
  680. if (IS_DIGITW(*psz))
  681. n = 0x10 * n + *psz - L'0';
  682. else
  683. {
  684. WCHAR ch = *psz;
  685. int n2;
  686. if (ch >= L'a')
  687. ch -= L'a' - L'A';
  688. n2 = ch - L'A' + 0xA;
  689. if (n2 >= 0xA && n2 <= 0xF)
  690. n = 0x10 * n + n2;
  691. else
  692. break;
  693. }
  694. }
  695. // Return TRUE if there was at least one digit
  696. bRet = (psz != pszAdj);
  697. }
  698. else
  699. {
  700. // No
  701. pszAdj = psz;
  702. // Do the conversion
  703. for (n = 0; IS_DIGITW(*psz); psz++)
  704. n = 10 * n + *psz - L'0';
  705. // Return TRUE if there was at least one digit
  706. bRet = (psz != pszAdj);
  707. }
  708. if (pllRet)
  709. {
  710. *pllRet = bNeg ? -n : n;
  711. }
  712. }
  713. else
  714. {
  715. bRet = FALSE;
  716. }
  717. return bRet;
  718. }
  719. /*----------------------------------------------------------
  720. Purpose: ansi wrapper for StrToInt64ExW.
  721. Returns: see StrToInt64ExW
  722. Cond: --
  723. */
  724. BOOL WINAPI StrToInt64ExA(
  725. LPCSTR pszString,
  726. DWORD dwFlags, // STIF_ bitfield
  727. LONGLONG FAR * pllRet)
  728. {
  729. BOOL bRet;
  730. RIPMSG(pszString && IS_VALID_STRING_PTRA(pszString, -1), "StrToInt64ExA: caller passed bad pszString");
  731. if (pszString)
  732. {
  733. // Most strings will simply use this temporary buffer, but UnicodeFromAnsi
  734. // will allocate a buffer if the supplied string is bigger.
  735. WCHAR szBuf[MAX_PATH];
  736. LPWSTR pwszString;
  737. bRet = UnicodeFromAnsi(&pwszString, pszString, szBuf, SIZECHARS(szBuf));
  738. if (bRet)
  739. {
  740. bRet = StrToInt64ExW(pwszString, dwFlags, pllRet);
  741. UnicodeFromAnsi(&pwszString, NULL, szBuf, 0);
  742. }
  743. }
  744. else
  745. {
  746. bRet = FALSE;
  747. }
  748. return bRet;
  749. }
  750. /*----------------------------------------------------------
  751. Purpose: Calls StrToInt64ExA (the real work horse), and
  752. then casts down to an int.
  753. Returns: see StrToInt64ExA
  754. */
  755. BOOL WINAPI StrToIntExA(
  756. LPCSTR pszString,
  757. DWORD dwFlags,
  758. int *piRet)
  759. {
  760. LONGLONG llVal;
  761. BOOL fReturn;
  762. RIPMSG(pszString && IS_VALID_STRING_PTRA(pszString, -1), "StrToIntExA: caller passed bad pszString");
  763. fReturn = StrToInt64ExA(pszString, dwFlags, &llVal);
  764. *piRet = fReturn ? (int)llVal : 0;
  765. return(fReturn);
  766. }
  767. /*----------------------------------------------------------
  768. Purpose: Calls StrToInt64ExW (the real work horse), and
  769. then casts down to an int.
  770. Returns: see StrToInt64ExW
  771. */
  772. BOOL WINAPI StrToIntExW(
  773. LPCWSTR pwszString,
  774. DWORD dwFlags, // STIF_ bitfield
  775. int FAR * piRet)
  776. {
  777. LONGLONG llVal;
  778. BOOL fReturn;
  779. RIPMSG(pwszString && IS_VALID_STRING_PTRW(pwszString, -1), "StrToIntExW: caller passed bad pwszString");
  780. fReturn = StrToInt64ExW(pwszString, dwFlags, &llVal);
  781. *piRet = fReturn ? (int)llVal : 0;
  782. return(fReturn);
  783. }
  784. /*----------------------------------------------------------
  785. Purpose: Returns an integer value specifying the length of
  786. the substring in psz that consists entirely of
  787. characters in pszSet. If psz begins with a character
  788. not in pszSet, then this function returns 0.
  789. This is a DBCS-safe version of the CRT strspn().
  790. Returns: see above
  791. Cond: --
  792. */
  793. int StrSpnA(LPCSTR psz, LPCSTR pszSet)
  794. {
  795. LPCSTR pszT = psz;
  796. RIPMSG(psz && IS_VALID_STRING_PTRA(psz, -1), "StrSpnA: caller passed bad psz");
  797. RIPMSG(pszSet && IS_VALID_STRING_PTRA(pszSet, -1), "StrSpnA: caller passed bad pszSet");
  798. if (psz && pszSet)
  799. {
  800. // Go thru the string to be inspected
  801. for ( ; *pszT; pszT = CharNextA(pszT))
  802. {
  803. LPCSTR pszSetT;
  804. // Go thru the char set
  805. for (pszSetT = pszSet; *pszSetT; pszSetT = CharNextA(pszSetT))
  806. {
  807. if (*pszSetT == *pszT)
  808. {
  809. if ( !IsDBCSLeadByte(*pszSetT) )
  810. {
  811. break; // Chars match
  812. }
  813. else if (pszSetT[1] == pszT[1])
  814. {
  815. break; // Chars match
  816. }
  817. }
  818. }
  819. // End of char set?
  820. if (0 == *pszSetT)
  821. {
  822. break; // Yes, no match on this inspected char
  823. }
  824. }
  825. }
  826. return (int)(pszT - psz);
  827. }
  828. /*----------------------------------------------------------
  829. Purpose: Returns an integer value specifying the length of
  830. the substring in psz that consists entirely of
  831. characters in pszSet. If psz begins with a character
  832. not in pszSet, then this function returns 0.
  833. This is a DBCS-safe version of the CRT strspn().
  834. Returns: see above
  835. Cond: --
  836. */
  837. STDAPI_(int) StrSpnW(LPCWSTR psz, LPCWSTR pszSet)
  838. {
  839. LPCWSTR pszT = psz;
  840. RIPMSG(psz && IS_VALID_STRING_PTRW(psz, -1), "StrSpnW: caller passed bad psz");
  841. RIPMSG(pszSet && IS_VALID_STRING_PTRW(pszSet, -1), "StrSpnW: caller passed bad pszSet");
  842. if (psz && pszSet)
  843. {
  844. // Go thru the string to be inspected
  845. for ( ; *pszT; pszT++)
  846. {
  847. LPCWSTR pszSetT;
  848. // Go thru the char set
  849. for (pszSetT = pszSet; *pszSetT != *pszT; pszSetT++)
  850. {
  851. if (0 == *pszSetT)
  852. {
  853. // Reached end of char set without finding a match
  854. return (int)(pszT - psz);
  855. }
  856. }
  857. }
  858. }
  859. return (int)(pszT - psz);
  860. }
  861. // StrCSpn: return index to first char of lpStr that is present in lpSet.
  862. // Includes the NUL in the comparison; if no lpSet chars are found, returns
  863. // the index to the NUL in lpStr.
  864. // Just like CRT strcspn.
  865. //
  866. int StrCSpnA(LPCSTR lpStr, LPCSTR lpSet)
  867. {
  868. LPCSTR lp = lpStr;
  869. RIPMSG(lpStr && IS_VALID_STRING_PTRA(lpStr, -1), "StrCSpnA: Caller passed bad lpStr");
  870. RIPMSG(lpSet && IS_VALID_STRING_PTRA(lpSet, -1), "StrCSpnA: Caller passed bad lpSet");
  871. if (lpStr && lpSet)
  872. {
  873. // nature of the beast: O(lpStr*lpSet) work
  874. while (*lp)
  875. {
  876. if (StrChrA(lpSet, READNATIVEWORD(lp)))
  877. return (int)(lp-lpStr);
  878. lp = AnsiNext(lp);
  879. }
  880. }
  881. return (int)(lp-lpStr); // ==lstrlen(lpStr)
  882. }
  883. int StrCSpnW(LPCWSTR lpStr, LPCWSTR lpSet)
  884. {
  885. LPCWSTR lp = lpStr;
  886. RIPMSG(lpStr && IS_VALID_STRING_PTRW(lpStr, -1), "StrCSpnW: Caller passed bad lpStr");
  887. RIPMSG(lpSet && IS_VALID_STRING_PTRW(lpSet, -1), "StrCSpnW: Caller passed bad lpSet");
  888. if (lpStr && lpSet)
  889. {
  890. // nature of the beast: O(lpStr*lpSet) work
  891. while (*lp)
  892. {
  893. if (StrChrW(lpSet, *lp))
  894. return (int)(lp-lpStr);
  895. lp++;
  896. }
  897. }
  898. return (int)(lp-lpStr); // ==lstrlen(lpStr)
  899. }
  900. // StrCSpnI: case-insensitive version of StrCSpn.
  901. //
  902. int StrCSpnIA(LPCSTR lpStr, LPCSTR lpSet)
  903. {
  904. LPCSTR lp = lpStr;
  905. RIPMSG(lpStr && IS_VALID_STRING_PTRA(lpStr, -1), "StrCSpnIA: Caller passed bad lpStr");
  906. RIPMSG(lpSet && IS_VALID_STRING_PTRA(lpSet, -1), "StrCSpnIA: Caller passed bad lpSet");
  907. if (lpStr && lpSet)
  908. {
  909. // nature of the beast: O(lpStr*lpSet) work
  910. while (*lp)
  911. {
  912. if (StrChrIA(lpSet, READNATIVEWORD(lp)))
  913. return (int)(lp-lpStr);
  914. lp = AnsiNext(lp);
  915. }
  916. }
  917. return (int)(lp-lpStr); // ==lstrlen(lpStr)
  918. }
  919. int StrCSpnIW(LPCWSTR lpStr, LPCWSTR lpSet)
  920. {
  921. LPCWSTR lp = lpStr;
  922. RIPMSG(lpStr && IS_VALID_STRING_PTRW(lpStr, -1), "StrCSpnIW: Caller passed bad lpStr");
  923. RIPMSG(lpSet && IS_VALID_STRING_PTRW(lpSet, -1), "StrCSpnIW: Caller passed bad lpSet");
  924. if (lpStr && lpSet)
  925. {
  926. // nature of the beast: O(lpStr*lpSet) work
  927. while (*lp)
  928. {
  929. if (StrChrIW(lpSet, *lp))
  930. return (int)(lp-lpStr);
  931. lp++;
  932. }
  933. }
  934. return (int)(lp-lpStr); // ==lstrlen(lpStr)
  935. }
  936. /*
  937. * StrCmpN - Compare n bytes
  938. *
  939. * returns See lstrcmp return values.
  940. */
  941. int _StrCmpNA(LPCSTR lpStr1, LPCSTR lpStr2, int nChar, BOOL fMBCS)
  942. {
  943. if (lpStr1 && lpStr2)
  944. {
  945. LPCSTR lpszEnd = lpStr1 + nChar;
  946. char sz1[4];
  947. char sz2[4];
  948. if (fMBCS) {
  949. for ( ; (lpszEnd > lpStr1) && (*lpStr1 || *lpStr2); lpStr1 = AnsiNext(lpStr1), lpStr2 = AnsiNext(lpStr2)) {
  950. WORD w1;
  951. WORD w2;
  952. // If either pointer is at the null terminator already,
  953. // we want to copy just one byte to make sure we don't read
  954. // past the buffer (might be at a page boundary).
  955. w1 = (*lpStr1) ? READNATIVEWORD(lpStr1) : 0;
  956. w2 = (*lpStr2) ? READNATIVEWORD(lpStr2) : 0;
  957. // (ChrCmpA returns FALSE if the characters match)
  958. // Do the characters match?
  959. if (ChrCmpA_inline(w1, w2))
  960. {
  961. // No; determine the lexical value of the comparison
  962. // (since ChrCmp just returns true/false).
  963. // Since the character may be a DBCS character; we
  964. // copy two bytes into each temporary buffer
  965. // (in preparation for the lstrcmp call).
  966. (*(WORD *)sz1) = w1;
  967. (*(WORD *)sz2) = w2;
  968. // Add null terminators to temp buffers
  969. *AnsiNext(sz1) = 0;
  970. *AnsiNext(sz2) = 0;
  971. return lstrcmpA(sz1, sz2);
  972. }
  973. }
  974. } else {
  975. for ( ; (lpszEnd > lpStr1) && (*lpStr1 || *lpStr2); lpStr1++, lpStr2++) {
  976. if (*lpStr1 != *lpStr2) {
  977. // No; determine the lexical value of the comparison
  978. // (since ChrCmp just returns true/false).
  979. sz1[0] = *lpStr1;
  980. sz2[0] = *lpStr2;
  981. sz1[1] = sz2[1] = '\0';
  982. return lstrcmpA(sz1, sz2);
  983. }
  984. }
  985. }
  986. }
  987. return 0;
  988. }
  989. STDAPI_(int) StrCmpNA(LPCSTR psz1, LPCSTR psz2, int nChar)
  990. {
  991. CPINFO cpinfo;
  992. RIPMSG(nChar == 0 || (psz1 && IS_VALID_STRING_PTRA(psz1, nChar)), "StrCmpNA: Caller passed bad psz1");
  993. RIPMSG(nChar == 0 || (psz2 && IS_VALID_STRING_PTRA(psz2, nChar)), "StrCmpNA: Caller passed bad psz2");
  994. RIPMSG(nChar >= 0, "StrCmpNA: caller passed bad nChar");
  995. return _StrCmpNA(psz1, psz2, nChar, GetCPInfo(CP_ACP, &cpinfo) && cpinfo.LeadByte[0]);
  996. }
  997. // cch1 and cch2 are the maximum # of chars to compare
  998. int _StrCmpLocaleW(DWORD dwFlags, LPCWSTR psz1, int cch1, LPCWSTR psz2, int cch2)
  999. {
  1000. int i = CompareStringW(GetThreadLocale(), dwFlags, psz1, cch1, psz2, cch2);
  1001. if (!i)
  1002. {
  1003. i = CompareStringW(LOCALE_SYSTEM_DEFAULT, dwFlags, psz1, cch1, psz2, cch2);
  1004. }
  1005. return i - CSTR_EQUAL;
  1006. }
  1007. int _StrCmpLocaleA(DWORD dwFlags, LPCSTR psz1, int cch1, LPCSTR psz2, int cch2)
  1008. {
  1009. int i = CompareStringA(GetThreadLocale(), dwFlags, psz1, cch1, psz2, cch2);
  1010. if (!i)
  1011. {
  1012. i = CompareStringA(LOCALE_SYSTEM_DEFAULT, dwFlags, psz1, cch1, psz2, cch2);
  1013. }
  1014. return i - CSTR_EQUAL;
  1015. }
  1016. STDAPI_(int) StrCmpNW(LPCWSTR psz1, LPCWSTR psz2, int nChar)
  1017. {
  1018. RIPMSG(nChar==0 || (psz1 && IS_VALID_STRING_PTRW(psz1, nChar)), "StrCmpNW: Caller passed bad psz1");
  1019. RIPMSG(nChar==0 || (psz2 && IS_VALID_STRING_PTRW(psz2, nChar)), "StrCmpNW: Caller passed bad psz2");
  1020. RIPMSG(nChar>=0, "StrCmpNA: caller passed bad nChar");
  1021. return _StrCmpLocaleW(NORM_STOP_ON_NULL, psz1, nChar, psz2, nChar);
  1022. }
  1023. /*
  1024. * Compare n bytes, case insensitive
  1025. *
  1026. * returns See lstrcmpi return values.
  1027. */
  1028. int StrCmpNIA(LPCSTR psz1, LPCSTR psz2, int nChar)
  1029. {
  1030. int nChar1, nChar2;
  1031. RIPMSG(nChar==0 || (psz1 && IS_VALID_STRING_PTRA(psz1, nChar)), "StrCmpNIA: Caller passed bad psz1");
  1032. RIPMSG(nChar==0 || (psz2 && IS_VALID_STRING_PTRA(psz2, nChar)), "StrCmpNIA: Caller passed bad psz2");
  1033. RIPMSG(nChar>=0, "StrCmpNIA: caller passed bad nChar");
  1034. // Include the (nChar && (!psz1 || !psz2)) cases here so we go through the
  1035. // validation layer and return the appropriate invalid parameter error code
  1036. // instead of faulting on Win95.
  1037. //
  1038. // NOTE! That this means that StrCmpNI(NULL, NULL, 0) on NT returns -2
  1039. // but StrCmpNI(NULL, NULL, 0) on Win9x returns 0. This has always been
  1040. // the case -- changing it is too scary for app compat reasons.
  1041. //
  1042. // NORM_STOP_ON_NULL is not supported by the ANSI version on NT
  1043. // so we have to emulate it
  1044. if (nChar && (!psz1 || !psz2))
  1045. {
  1046. // This is the error scenario we are forcing through
  1047. nChar1 = nChar;
  1048. nChar2 = nChar;
  1049. }
  1050. else
  1051. {
  1052. // nChar1 = min(nChar, lstrlen(psz1))
  1053. // except that the "for" loop will not read more than nChar
  1054. // characters from psz1 because psz1 might not be NULL-terminated
  1055. for (nChar1 = 0; nChar1 < nChar && psz1[nChar1]; nChar1++) { }
  1056. // And similarly for nChar2
  1057. for (nChar2 = 0; nChar2 < nChar && psz2[nChar2]; nChar2++) { }
  1058. }
  1059. return _StrCmpLocaleA(NORM_IGNORECASE, psz1, nChar1, psz2, nChar2);
  1060. }
  1061. int StrCmpNIW(LPCWSTR psz1, LPCWSTR psz2, int nChar)
  1062. {
  1063. RIPMSG(nChar==0 || (psz1 && IS_VALID_STRING_PTRW(psz1, nChar)), "StrCmpNIW: Caller passed bad psz1");
  1064. RIPMSG(nChar==0 || (psz2 && IS_VALID_STRING_PTRW(psz2, nChar)), "StrCmpNIW: Caller passed bad psz2");
  1065. RIPMSG(nChar>=0, "StrCmpNW: caller passed bad nChar");
  1066. return _StrCmpLocaleW(NORM_IGNORECASE | NORM_STOP_ON_NULL, psz1, nChar, psz2, nChar);
  1067. }
  1068. /*
  1069. * StrRStrI - Search for last occurrence of a substring
  1070. *
  1071. * Assumes lpSource points to the null terminated source string
  1072. * lpLast points to where to search from in the source string
  1073. * lpLast is not included in the search
  1074. * lpSrch points to string to search for
  1075. * returns last occurrence of string if successful; NULL otherwise
  1076. */
  1077. LPSTR StrRStrIA(LPCSTR lpSource, LPCSTR lpLast, LPCSTR lpSrch)
  1078. {
  1079. LPCSTR lpFound = NULL;
  1080. RIPMSG(lpSource && IS_VALID_STRING_PTRA(lpSource, -1), "StrRStrIA: Caller passed bad lpSource");
  1081. RIPMSG(!lpLast || (IS_VALID_STRING_PTRA(lpLast, -1) && lpLast>=lpSource && lpLast<=lpSource+lstrlenA(lpSource)), "StrRStrIA: Caller passed bad lpLast");
  1082. RIPMSG(lpSrch && IS_VALID_STRING_PTRA(lpSrch, -1) && *lpSrch, "StrRStrIA: Caller passed bad lpSrch");
  1083. if (!lpLast)
  1084. lpLast = lpSource + lstrlenA(lpSource);
  1085. if (lpSource && lpSrch && *lpSrch)
  1086. {
  1087. WORD wMatch;
  1088. UINT uLen;
  1089. LPCSTR lpStart;
  1090. wMatch = READNATIVEWORD(lpSrch);
  1091. wMatch = (UINT)(IsDBCSLeadByte(LOBYTE(wMatch)) ? wMatch : LOBYTE(wMatch));
  1092. uLen = lstrlenA(lpSrch);
  1093. lpStart = lpSource;
  1094. while (*lpStart && (lpStart < lpLast))
  1095. {
  1096. if (!ChrCmpIA(READNATIVEWORD(lpStart), wMatch))
  1097. {
  1098. if (StrCmpNIA(lpStart, lpSrch, uLen) == 0)
  1099. lpFound = lpStart;
  1100. }
  1101. lpStart = AnsiNext(lpStart);
  1102. }
  1103. }
  1104. return((LPSTR)lpFound);
  1105. }
  1106. LPWSTR StrRStrIW(LPCWSTR lpSource, LPCWSTR lpLast, LPCWSTR lpSrch)
  1107. {
  1108. LPCWSTR lpFound = NULL;
  1109. RIPMSG(lpSource && IS_VALID_STRING_PTRW(lpSource, -1), "StrRStrIW: Caller passed bad lpSource");
  1110. RIPMSG(!lpLast || (IS_VALID_STRING_PTRW(lpLast, -1) && lpLast>=lpSource && lpLast<=lpSource+lstrlenW(lpSource)), "StrRStrIW: Caller passed bad lpLast");
  1111. RIPMSG(lpSrch && IS_VALID_STRING_PTRW(lpSrch, -1) && *lpSrch, "StrRStrIW: Caller passed bad lpSrch");
  1112. if (!lpLast)
  1113. lpLast = lpSource + lstrlenW(lpSource);
  1114. if (lpSource && lpSrch && *lpSrch)
  1115. {
  1116. WCHAR wMatch;
  1117. UINT uLen;
  1118. LPCWSTR lpStart;
  1119. wMatch = *lpSrch;
  1120. uLen = lstrlenW(lpSrch);
  1121. lpStart = lpSource;
  1122. while (*lpStart && (lpStart < lpLast))
  1123. {
  1124. if (!ChrCmpIW(*lpStart, wMatch))
  1125. {
  1126. if (StrCmpNIW(lpStart, lpSrch, uLen) == 0)
  1127. lpFound = lpStart;
  1128. }
  1129. lpStart++;
  1130. }
  1131. }
  1132. return((LPWSTR)lpFound);
  1133. }
  1134. /*
  1135. * StrStr - Search for first occurrence of a substring
  1136. *
  1137. * Assumes lpSource points to source string
  1138. * lpSrch points to string to search for
  1139. * returns first occurrence of string if successful; NULL otherwise
  1140. */
  1141. LPSTR StrStrA(LPCSTR lpFirst, LPCSTR lpSrch)
  1142. {
  1143. RIPMSG(lpFirst && IS_VALID_STRING_PTRA(lpFirst, -1), "StrStrA: Caller passed bad lpFirst");
  1144. RIPMSG(lpSrch && IS_VALID_STRING_PTRA(lpSrch, -1), "StrStrA: Caller passed bad lpSrch");
  1145. if (lpFirst && lpSrch)
  1146. {
  1147. UINT uLen;
  1148. WORD wMatch;
  1149. CPINFO cpinfo;
  1150. BOOL fMBCS = GetCPInfo(CP_ACP, &cpinfo) && cpinfo.LeadByte[0];
  1151. uLen = (UINT)lstrlenA(lpSrch);
  1152. wMatch = READNATIVEWORD(lpSrch);
  1153. for ( ; (lpFirst=_StrChrA(lpFirst, wMatch, fMBCS))!=0 && _StrCmpNA(lpFirst, lpSrch, uLen, fMBCS);
  1154. lpFirst=AnsiNext(lpFirst))
  1155. continue; /* continue until we hit the end of the string or get a match */
  1156. return((LPSTR)lpFirst);
  1157. }
  1158. return(NULL);
  1159. }
  1160. LPWSTR StrStrW(LPCWSTR lpFirst, LPCWSTR lpSrch)
  1161. {
  1162. RIPMSG(lpFirst && IS_VALID_STRING_PTRW(lpFirst, -1), "StrStrW: Caller passed bad lpFirst");
  1163. RIPMSG(lpSrch && IS_VALID_STRING_PTRW(lpSrch, -1), "StrStrW: Caller passed bad lpSrch");
  1164. if (lpFirst && lpSrch)
  1165. {
  1166. UINT uLen;
  1167. WCHAR wMatch;
  1168. uLen = (UINT)lstrlenW(lpSrch);
  1169. wMatch = *lpSrch;
  1170. for ( ; (lpFirst=StrChrW(lpFirst, wMatch))!=0 && StrCmpNW(lpFirst, lpSrch, uLen);
  1171. lpFirst++)
  1172. continue; /* continue until we hit the end of the string or get a match */
  1173. return (LPWSTR)lpFirst;
  1174. }
  1175. return NULL;
  1176. }
  1177. /*
  1178. * StrStrN - Search for first occurrence of a substring
  1179. *
  1180. * Assumes lpSource points to source string
  1181. * lpSrch points to string to search for
  1182. * returns first occurrence of string if successful; NULL otherwise
  1183. */
  1184. LPWSTR StrStrNW(LPCWSTR lpFirst, LPCWSTR lpSrch, UINT cchMax)
  1185. {
  1186. RIPMSG(lpFirst && IS_VALID_STRING_PTRW(lpFirst, cchMax), "StrStrW: Caller passed bad lpFirst");
  1187. RIPMSG(lpSrch && IS_VALID_STRING_PTRW(lpSrch, cchMax), "StrStrW: Caller passed bad lpSrch");
  1188. if (lpFirst && lpSrch)
  1189. {
  1190. UINT uLen;
  1191. WCHAR wMatch;
  1192. LPCWSTR lpSentinel = lpFirst+cchMax;
  1193. uLen = (UINT)lstrlenW(lpSrch);
  1194. wMatch = *lpSrch;
  1195. // the first two conditions in this loop signify failure when they eval to false,
  1196. // while the third condition signifies success. We need to special case the second
  1197. // condition at the end of the function because it doesn't automatically cause the
  1198. // right value to be returned
  1199. while((lpFirst=StrChrNW(lpFirst, wMatch, cchMax))!=0 && cchMax>=uLen &&StrCmpNW(lpFirst, lpSrch, uLen))
  1200. {
  1201. lpFirst++;
  1202. cchMax=(UINT)(lpSentinel-lpFirst);
  1203. }/* continue until we hit the end of the string or get a match */
  1204. if(cchMax<uLen)
  1205. return NULL;// we ran out of space
  1206. return (LPWSTR)lpFirst;
  1207. }
  1208. return NULL;
  1209. }
  1210. /*
  1211. * StrStrI - Search for first occurrence of a substring, case insensitive
  1212. *
  1213. * Assumes lpFirst points to source string
  1214. * lpSrch points to string to search for
  1215. * returns first occurrence of string if successful; NULL otherwise
  1216. */
  1217. LPSTR StrStrIA(LPCSTR lpFirst, LPCSTR lpSrch)
  1218. {
  1219. RIPMSG(lpFirst && IS_VALID_STRING_PTRA(lpFirst, -1), "StrStrIA: Caller passed bad lpFirst");
  1220. RIPMSG(lpSrch && IS_VALID_STRING_PTRA(lpSrch, -1), "StrStrIA: Caller passed bad lpSrch");
  1221. if (lpFirst && lpSrch)
  1222. {
  1223. UINT uLen = (UINT)lstrlenA(lpSrch);
  1224. WORD wMatch = READNATIVEWORD(lpSrch);
  1225. for ( ; (lpFirst = StrChrIA(lpFirst, wMatch)) != 0 && StrCmpNIA(lpFirst, lpSrch, uLen);
  1226. lpFirst=AnsiNext(lpFirst))
  1227. continue; /* continue until we hit the end of the string or get a match */
  1228. return (LPSTR)lpFirst;
  1229. }
  1230. return NULL;
  1231. }
  1232. LPWSTR StrStrIW(LPCWSTR lpFirst, LPCWSTR lpSrch)
  1233. {
  1234. RIPMSG(lpFirst && IS_VALID_STRING_PTRW(lpFirst, -1), "StrStrIW: Caller passed bad lpFirst");
  1235. RIPMSG(lpSrch && IS_VALID_STRING_PTRW(lpSrch, -1), "StrStrIW: Caller passed bad lpSrch");
  1236. if (lpFirst && lpSrch)
  1237. {
  1238. UINT uLen = (UINT)lstrlenW(lpSrch);
  1239. WCHAR wMatch = *lpSrch;
  1240. for ( ; (lpFirst = StrChrIW(lpFirst, wMatch)) != 0 && StrCmpNIW(lpFirst, lpSrch, uLen);
  1241. lpFirst++)
  1242. continue; /* continue until we hit the end of the string or get a match */
  1243. return (LPWSTR)lpFirst;
  1244. }
  1245. return NULL;
  1246. }
  1247. /*
  1248. * StrStrNI - Search for first occurrence of a substring, case insensitive, counted
  1249. *
  1250. * Assumes lpFirst points to source string
  1251. * lpSrch points to string to search for
  1252. * returns first occurrence of string if successful; NULL otherwise
  1253. */
  1254. LPWSTR StrStrNIW(LPCWSTR lpFirst, LPCWSTR lpSrch, UINT cchMax)
  1255. {
  1256. RIPMSG(lpFirst && IS_VALID_STRING_PTRW(lpFirst, cchMax), "StrStrNIW: Caller passed bad lpFirst");
  1257. RIPMSG(lpSrch && IS_VALID_STRING_PTRW(lpSrch, cchMax), "StrStrNIW: Caller passed bad lpSrch");
  1258. if (lpFirst && lpSrch)
  1259. {
  1260. UINT uLen = (UINT)lstrlenW(lpSrch);
  1261. WCHAR wMatch = *lpSrch;
  1262. LPCWSTR lpSentinel = lpFirst+cchMax;
  1263. // the first two conditions in this loop signify failure when they eval to false,
  1264. // while the third condition signifies success. We need to special case the second
  1265. // condition at the end of the function because it doesn't automatically cause the
  1266. // right value to be returned
  1267. while((lpFirst = StrChrNIW(lpFirst, wMatch, cchMax)) != 0 && cchMax >= uLen && StrCmpNIW(lpFirst, lpSrch, uLen))
  1268. {
  1269. lpFirst++;
  1270. cchMax = (UINT)(lpSentinel - lpFirst);
  1271. }/* continue until we hit the end of the string or get a match */
  1272. if(cchMax<uLen)
  1273. return NULL;// we ran out of space
  1274. return (LPWSTR)lpFirst;
  1275. }
  1276. return NULL;
  1277. }
  1278. LPSTR StrDupA(LPCSTR psz)
  1279. {
  1280. LPSTR pszRet = NULL;
  1281. RIPMSG(psz && IS_VALID_STRING_PTRA(psz, -1), "StrDupA: Caller passed invalid psz");
  1282. if (psz)
  1283. {
  1284. int cch = lstrlenA(psz) + 1;
  1285. pszRet = (LPSTR)LocalAlloc(LPTR, cch * sizeof(char));
  1286. if (pszRet)
  1287. {
  1288. StringCchCopyA(pszRet, cch, psz);
  1289. }
  1290. }
  1291. return pszRet;
  1292. }
  1293. LPWSTR StrDupW(LPCWSTR psz)
  1294. {
  1295. LPWSTR pszRet = NULL;
  1296. RIPMSG(psz && IS_VALID_STRING_PTRW(psz, -1), "StrDupW: Caller passed invalid psz");
  1297. if (psz)
  1298. {
  1299. int cch = lstrlenW(psz) + 1;
  1300. pszRet = (LPWSTR)LocalAlloc(LPTR, cch * sizeof(WCHAR));
  1301. if (pszRet)
  1302. {
  1303. StringCchCopyW(pszRet, cch, psz);
  1304. }
  1305. }
  1306. return pszRet;
  1307. }
  1308. void _StrOut(LPSTR pszDest, int cchDest, HMODULE hmod, UINT idRes, DWORD* pdwTimeS, int* pdigits, UINT iDiv)
  1309. {
  1310. *pszDest = '\0';
  1311. if (*pdigits)
  1312. {
  1313. DWORD dwCur = *pdwTimeS/iDiv;
  1314. if (dwCur || iDiv==1)
  1315. {
  1316. DWORD dwBase;
  1317. CHAR szBuf[64], szTemplate[64];
  1318. LPSTR pszBuf = szBuf;
  1319. *pdwTimeS -= dwCur*iDiv;
  1320. for (dwBase=1; dwCur/(dwBase*10); dwBase*=10);
  1321. DebugMsg(DM_INTERVAL, TEXT("dwCur, dwBase, *pdwTimeS = %d, %d, %d"), dwCur, dwBase, *pdwTimeS);
  1322. //
  1323. // LATER: We could use atoi if we mathematically trancate
  1324. // the numbers based on digits.
  1325. //
  1326. for (;dwBase; dwBase/=10, pszBuf++)
  1327. {
  1328. if (*pdigits)
  1329. {
  1330. DWORD i = dwCur/dwBase;
  1331. dwCur -= i*dwBase;
  1332. *pszBuf = '0'+(unsigned short)i;
  1333. (*pdigits)--;
  1334. }
  1335. else
  1336. {
  1337. *pszBuf = '0';
  1338. }
  1339. }
  1340. *pszBuf = '\0';
  1341. MLLoadStringA(idRes, szTemplate, ARRAYSIZE(szTemplate));
  1342. StringCchPrintfA(pszDest, cchDest, szTemplate, szBuf);
  1343. }
  1344. }
  1345. }
  1346. void _StrOutW(LPWSTR pszDest, int cchDest, HMODULE hmod, UINT idRes, DWORD* pdwTimeS, int* pdigits, UINT iDiv)
  1347. {
  1348. *pszDest = L'\0';
  1349. if (*pdigits)
  1350. {
  1351. DWORD dwCur = *pdwTimeS/iDiv;
  1352. if (dwCur || iDiv==1)
  1353. {
  1354. DWORD dwBase;
  1355. WCHAR wszBuf[64], wszTemplate[64];
  1356. LPWSTR pwszBuf = wszBuf;
  1357. *pdwTimeS -= dwCur*iDiv;
  1358. for (dwBase=1; dwCur/(dwBase*10); dwBase*=10);
  1359. DebugMsg(DM_INTERVAL, TEXT("dwCur, dwBase, *pdwTimeS = %d, %d, %d"), dwCur, dwBase, *pdwTimeS);
  1360. //
  1361. // LATER: We could use atoi if we mathematically trancate
  1362. // the numbers based on digits.
  1363. //
  1364. for (;dwBase; dwBase/=10, pwszBuf++)
  1365. {
  1366. if (*pdigits)
  1367. {
  1368. DWORD i = dwCur/dwBase;
  1369. dwCur -= i*dwBase;
  1370. *pwszBuf = L'0'+(unsigned short)i;
  1371. (*pdigits)--;
  1372. }
  1373. else
  1374. {
  1375. *pwszBuf = L'0';
  1376. }
  1377. }
  1378. *pwszBuf = L'\0';
  1379. MLLoadStringW(idRes, wszTemplate, ARRAYSIZE(wszTemplate));
  1380. StringCchPrintfW(pszDest, cchDest, wszTemplate, wszBuf);
  1381. }
  1382. }
  1383. }
  1384. BOOL _StrFromTimeInterval(LPSTR pszBuf, int cchBuf, DWORD dwTimeMS, int digits)
  1385. {
  1386. char szTemp[128];
  1387. DWORD dwTimeS = (dwTimeMS+500)/1000;
  1388. DebugMsg(DM_INTERVAL, TEXT("dwTimeS = %d"), dwTimeS);
  1389. _StrOut(szTemp, ARRAYSIZE(szTemp), g_hinst, IDS_HOUR, &dwTimeS, &digits, 3600);
  1390. StringCchCopyA(pszBuf, cchBuf, szTemp);
  1391. _StrOut(szTemp, ARRAYSIZE(szTemp), g_hinst, IDS_MIN, &dwTimeS, &digits, 60);
  1392. StringCchCatA(pszBuf, cchBuf, szTemp);
  1393. _StrOut(szTemp, ARRAYSIZE(szTemp), g_hinst, IDS_SEC, &dwTimeS, &digits, 1);
  1394. StringCchCatA(pszBuf, cchBuf, szTemp);
  1395. return TRUE;
  1396. }
  1397. BOOL _StrFromTimeIntervalW(LPWSTR pwszBuf, int cchBuf, DWORD dwTimeMS, int digits)
  1398. {
  1399. WCHAR szTemp[128];
  1400. DWORD dwTimeS = (dwTimeMS+500)/1000;
  1401. DebugMsg(DM_INTERVAL, TEXT("dwTimeS = %d"), dwTimeS);
  1402. _StrOutW(szTemp, ARRAYSIZE(szTemp), g_hinst, IDS_HOUR, &dwTimeS, &digits, 3600);
  1403. StringCchCopyW(pwszBuf, cchBuf, szTemp);
  1404. _StrOutW(szTemp, ARRAYSIZE(szTemp), g_hinst, IDS_MIN, &dwTimeS, &digits, 60);
  1405. StringCchCatW(pwszBuf, cchBuf, szTemp);
  1406. _StrOutW(szTemp, ARRAYSIZE(szTemp), g_hinst, IDS_SEC, &dwTimeS, &digits, 1);
  1407. StringCchCatW(pwszBuf, cchBuf, szTemp);
  1408. return TRUE;
  1409. }
  1410. //
  1411. // This API converts a given time-interval (in msec) into a human readable
  1412. // string.
  1413. //
  1414. // Parameters:
  1415. // pszOut -- Specifies the string buffer. NULL is valid to query size.
  1416. // cchMax -- Specifies the size of buffer in char/WCHAR
  1417. // dwTimeMS -- Specifies the time interval in msec
  1418. // digits -- Specifies the minimum number of digits to be displayed
  1419. //
  1420. // Returns:
  1421. // Number of characters in the buffer (not including the terminator).
  1422. //
  1423. // Exmaples:
  1424. // dwTimeMS digits output
  1425. // 34000 3 34 sec
  1426. // 34000 2 34 sec
  1427. // 34000 1 30 sec
  1428. // 74000 3 1 min 14 sec
  1429. // 74000 2 1 min 10 sec
  1430. // 74000 1 1 min
  1431. //
  1432. int StrFromTimeIntervalA(LPSTR pszOut, UINT cchMax, DWORD dwTimeMS, int digits)
  1433. {
  1434. CHAR szBuf[256];
  1435. int cchRet = 0;
  1436. RIPMSG(!pszOut || IS_VALID_WRITE_BUFFER(pszOut, char, cchMax), "StrFromTimeIntervalA: Caller passed invalid pszOut");
  1437. DEBUGWhackPathBufferA(pszOut, cchMax);
  1438. if (_StrFromTimeInterval(szBuf, ARRAYSIZE(szBuf), dwTimeMS, digits))
  1439. {
  1440. if (pszOut)
  1441. {
  1442. lstrcpynA(pszOut, szBuf, cchMax);
  1443. cchRet = lstrlenA(pszOut);
  1444. }
  1445. else
  1446. {
  1447. cchRet = lstrlenA(szBuf);
  1448. }
  1449. }
  1450. return cchRet;
  1451. }
  1452. int StrFromTimeIntervalW(LPWSTR pwszOut, UINT cchMax, DWORD dwTimeMS, int digits)
  1453. {
  1454. WCHAR wszBuf[256];
  1455. int cchRet = 0;
  1456. RIPMSG(!pwszOut || IS_VALID_WRITE_BUFFER(pwszOut, WCHAR, cchMax), "StrFromTimeIntervalW: Caller passed invalid pszOut");
  1457. DEBUGWhackPathBufferW(pwszOut, cchMax);
  1458. if (_StrFromTimeIntervalW(wszBuf, ARRAYSIZE(wszBuf), dwTimeMS, digits))
  1459. {
  1460. if (pwszOut)
  1461. {
  1462. lstrcpynW(pwszOut, wszBuf, cchMax);
  1463. cchRet = lstrlenW(pwszOut);
  1464. }
  1465. else
  1466. {
  1467. cchRet = lstrlenW(wszBuf);
  1468. }
  1469. }
  1470. return cchRet;
  1471. }
  1472. /*
  1473. * IntlStrEq
  1474. *
  1475. * returns TRUE if strings are equal, FALSE if not
  1476. */
  1477. BOOL StrIsIntlEqualA(BOOL fCaseSens, LPCSTR lpString1, LPCSTR lpString2, int nChar)
  1478. {
  1479. DWORD dwFlags = fCaseSens ? LOCALE_USE_CP_ACP : (NORM_IGNORECASE | LOCALE_USE_CP_ACP);
  1480. RIPMSG(lpString1 && IS_VALID_STRING_PTRA(lpString1, nChar), "StrIsIntlEqualA: Caller passed invalid lpString1");
  1481. RIPMSG(lpString2 && IS_VALID_STRING_PTRA(lpString2, nChar), "StrIsIntlEqualA: Caller passed invalid lpString2");
  1482. RIPMSG(nChar >= -1, "StrIsIntlEqualA: Caller passed invalid nChar");
  1483. dwFlags |= NORM_STOP_ON_NULL; // only supported on NT
  1484. return 0 == _StrCmpLocaleA(dwFlags, lpString1, nChar, lpString2, nChar);
  1485. }
  1486. BOOL StrIsIntlEqualW(BOOL fCaseSens, LPCWSTR psz1, LPCWSTR psz2, int nChar)
  1487. {
  1488. RIPMSG(psz1 && IS_VALID_STRING_PTRW(psz1, nChar), "StrIsIntlEqualW: Caller passed invalid psz1");
  1489. RIPMSG(psz2 && IS_VALID_STRING_PTRW(psz2, nChar), "StrIsIntlEqualW: Caller passed invalid psz2");
  1490. RIPMSG(nChar >= -1, "StrIsIntlEqualW: Caller passed invalid nChar");
  1491. return 0 == _StrCmpLocaleW(fCaseSens ? NORM_STOP_ON_NULL : NORM_IGNORECASE | NORM_STOP_ON_NULL,
  1492. psz1, nChar, psz2, nChar);
  1493. }
  1494. // This is stolen from shell32 - util.c
  1495. #define LODWORD(_qw) (DWORD)(_qw)
  1496. const short c_aOrders[] = {IDS_BYTES, IDS_ORDERKB, IDS_ORDERMB,
  1497. IDS_ORDERGB, IDS_ORDERTB, IDS_ORDERPB, IDS_ORDEREB};
  1498. void Int64ToStr(LONGLONG n, LPWSTR lpBuffer)
  1499. {
  1500. WCHAR szTemp[40];
  1501. LONGLONG iChr;
  1502. iChr = 0;
  1503. do {
  1504. szTemp[iChr++] = L'0' + (WCHAR)(n % 10);
  1505. n = n / 10;
  1506. } while (n != 0);
  1507. do {
  1508. iChr--;
  1509. *lpBuffer++ = szTemp[iChr];
  1510. } while (iChr != 0);
  1511. *lpBuffer++ = L'\0';
  1512. }
  1513. //
  1514. // Obtain NLS info about how numbers should be grouped.
  1515. //
  1516. // The annoying thing is that LOCALE_SGROUPING and NUMBERFORMAT
  1517. // have different ways of specifying number grouping.
  1518. //
  1519. // LOCALE NUMBERFMT Sample Country
  1520. //
  1521. // 3;0 3 1,234,567 United States
  1522. // 3;2;0 32 12,34,567 India
  1523. // 3 30 1234,567 ??
  1524. //
  1525. // Not my idea. That's the way it works.
  1526. //
  1527. // Bonus treat - Win9x doesn't support complex number formats,
  1528. // so we return only the first number.
  1529. //
  1530. UINT GetNLSGrouping(void)
  1531. {
  1532. UINT grouping;
  1533. LPWSTR psz;
  1534. WCHAR szGrouping[32];
  1535. // If no locale info, then assume Western style thousands
  1536. if (!GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SGROUPING, szGrouping, ARRAYSIZE(szGrouping)))
  1537. return 3;
  1538. grouping = 0;
  1539. psz = szGrouping;
  1540. for (;;)
  1541. {
  1542. if (*psz == L'0') break; // zero - stop
  1543. else if ((UINT)(*psz - L'0') < 10) // digit - accumulate it
  1544. grouping = grouping * 10 + (UINT)(*psz - L'0');
  1545. else if (*psz) // punctuation - ignore it
  1546. { }
  1547. else // end of string, no "0" found
  1548. {
  1549. grouping = grouping * 10; // put zero on end (see examples)
  1550. break; // and finished
  1551. }
  1552. psz++;
  1553. }
  1554. return grouping;
  1555. }
  1556. // Sizes of various stringized numbers
  1557. #define MAX_INT64_SIZE 30 // 2^64 is less than 30 chars long
  1558. #define MAX_COMMA_NUMBER_SIZE (MAX_INT64_SIZE + 10)
  1559. // takes a DWORD add commas etc to it and puts the result in the buffer
  1560. LPWSTR CommifyString(LONGLONG n, LPWSTR pszBuf, UINT cchBuf)
  1561. {
  1562. WCHAR szNum[MAX_COMMA_NUMBER_SIZE], szSep[5];
  1563. NUMBERFMTW nfmt;
  1564. nfmt.NumDigits = 0;
  1565. nfmt.LeadingZero = 0;
  1566. nfmt.Grouping = GetNLSGrouping();
  1567. GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, szSep, ARRAYSIZE(szSep));
  1568. nfmt.lpDecimalSep = nfmt.lpThousandSep = szSep;
  1569. nfmt.NegativeOrder = 0;
  1570. Int64ToStr(n, szNum);
  1571. if (GetNumberFormatW(LOCALE_USER_DEFAULT, 0, szNum, &nfmt, pszBuf, cchBuf) == 0)
  1572. StrCpyNW(pszBuf, szNum, cchBuf);
  1573. return pszBuf;
  1574. }
  1575. /* converts numbers into sort formats
  1576. * 532 -> 523 bytes
  1577. * 1340 -> 1.3KB
  1578. * 23506 -> 23.5KB
  1579. * -> 2.4MB
  1580. * -> 5.2GB
  1581. */
  1582. LPWSTR StrFormatByteSizeW(LONGLONG n, LPWSTR pszBuf, UINT cchBuf)
  1583. {
  1584. RIPMSG(pszBuf && IS_VALID_WRITE_BUFFER(pszBuf, WCHAR, cchBuf), "StrFormatByteSizeW: Caller passed invalid pszBuf");
  1585. DEBUGWhackPathBufferW(pszBuf, cchBuf);
  1586. if (pszBuf)
  1587. {
  1588. WCHAR szWholeNum[32], szOrder[32];
  1589. int iOrder;
  1590. // If the size is less than 1024, then the order should be bytes we have nothing
  1591. // more to figure out
  1592. if (n < 1024)
  1593. {
  1594. wnsprintfW(szWholeNum, ARRAYSIZE(szWholeNum), L"%d", LODWORD(n));
  1595. iOrder = 0;
  1596. }
  1597. else
  1598. {
  1599. UINT uInt, uLen, uDec;
  1600. WCHAR szFormat[8];
  1601. // Find the right order
  1602. for (iOrder = 1; iOrder < ARRAYSIZE(c_aOrders) -1 && n >= 1000L * 1024L; n >>= 10, iOrder++);
  1603. /* do nothing */
  1604. uInt = LODWORD(n >> 10);
  1605. CommifyString(uInt, szWholeNum, ARRAYSIZE(szWholeNum));
  1606. uLen = lstrlenW(szWholeNum);
  1607. if (uLen < 3)
  1608. {
  1609. uDec = LODWORD(n - (LONGLONG)uInt * 1024L) * 1000 / 1024;
  1610. // At this point, uDec should be between 0 and 1000
  1611. // we want get the top one (or two) digits.
  1612. uDec /= 10;
  1613. if (uLen == 2)
  1614. uDec /= 10;
  1615. // Note that we need to set the format before getting the
  1616. // intl char.
  1617. StringCchCopyW(szFormat, ARRAYSIZE(szFormat), L"%02d");
  1618. szFormat[2] = TEXT('0') + 3 - uLen;
  1619. GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL,
  1620. szWholeNum + uLen, ARRAYSIZE(szWholeNum) - uLen);
  1621. uLen = lstrlenW(szWholeNum);
  1622. wnsprintfW(szWholeNum + uLen, ARRAYSIZE(szWholeNum) - uLen, szFormat, uDec);
  1623. }
  1624. }
  1625. MLLoadStringW(c_aOrders[iOrder], szOrder, ARRAYSIZE(szOrder));
  1626. wnsprintfW(pszBuf, cchBuf, szOrder, szWholeNum);
  1627. }
  1628. return pszBuf;
  1629. }
  1630. // dw - the nubmer to be converted
  1631. // pszBuf - buffer for the resulting string
  1632. // cchBuf - Max characters in Buffer
  1633. LPSTR StrFormatByteSize64A(LONGLONG dw, LPSTR pszBuf, UINT cchBuf)
  1634. {
  1635. WCHAR szT[32];
  1636. DEBUGWhackPathBuffer(pszBuf, cchBuf);
  1637. StrFormatByteSizeW(dw, szT, SIZECHARS(szT));
  1638. SHUnicodeToAnsi(szT, pszBuf, cchBuf);
  1639. return pszBuf;
  1640. }
  1641. LPSTR StrFormatByteSizeA(DWORD dw, LPSTR pszBuf, UINT cchBuf)
  1642. {
  1643. return StrFormatByteSize64A((LONGLONG)dw, pszBuf, cchBuf);
  1644. }
  1645. LPWSTR StrFormatKBSizeW(LONGLONG n, LPWSTR pszBuf, UINT cchBuf)
  1646. {
  1647. RIPMSG(pszBuf && IS_VALID_WRITE_BUFFER(pszBuf, WCHAR, cchBuf), "StrFormatKBSizeW: Caller passed invalid pszBuf");
  1648. DEBUGWhackPathBufferW(pszBuf, cchBuf);
  1649. if (pszBuf)
  1650. {
  1651. static WCHAR s_szOrder[16] = {0};
  1652. WCHAR szNum[64];
  1653. if (s_szOrder[0] == TEXT('\0'))
  1654. LoadStringW(HINST_THISDLL, IDS_ORDERKB, s_szOrder, ARRAYSIZE(s_szOrder));
  1655. CommifyString((n + 1023) / 1024, szNum, ARRAYSIZE(szNum));
  1656. wnsprintfW(pszBuf, cchBuf, s_szOrder, szNum);
  1657. }
  1658. return pszBuf;
  1659. }
  1660. LPSTR StrFormatKBSizeA(LONGLONG n, LPSTR pszBuf, UINT cchBuf)
  1661. {
  1662. WCHAR szNum[64];
  1663. DEBUGWhackPathBufferA(pszBuf, cchBuf);
  1664. StrFormatKBSizeW(n, szNum, ARRAYSIZE(szNum));
  1665. SHUnicodeToAnsi(szNum, pszBuf, cchBuf);
  1666. return pszBuf;
  1667. }
  1668. // Win95 does not support the wide-char version of lstrcmp, lstrcmpi
  1669. // Wrapper for lstrcmpW so it works on Win95
  1670. int StrCmpW(LPCWSTR pwsz1, LPCWSTR pwsz2)
  1671. {
  1672. RIPMSG(pwsz1 && IS_VALID_STRING_PTRW(pwsz1, -1), "StrCmpW: Caller passed invalid pwsz1");
  1673. RIPMSG(pwsz2 && IS_VALID_STRING_PTRW(pwsz2, -1), "StrCmpW: Caller passed invalid pwsz2");
  1674. return _StrCmpLocaleW(0, pwsz1, -1, pwsz2, -1);
  1675. }
  1676. // Wrapper for lstrcmpiW so it works on Win95
  1677. int StrCmpIW(LPCWSTR pwsz1, LPCWSTR pwsz2)
  1678. {
  1679. RIPMSG(pwsz1 && IS_VALID_STRING_PTRW(pwsz1, -1), "StrCmpIW: Caller passed invalid pwsz1");
  1680. RIPMSG(pwsz2 && IS_VALID_STRING_PTRW(pwsz2, -1), "StrCmpIW: Caller passed invalid pwsz2");
  1681. return _StrCmpLocaleW(NORM_IGNORECASE, pwsz1, -1, pwsz2, -1);
  1682. }
  1683. /*----------------------------------------------------------
  1684. Purpose: Trim the string pszTrimMe of any leading or trailing
  1685. characters that are in pszTrimChars.
  1686. Returns: TRUE if anything was stripped
  1687. */
  1688. STDAPI_(BOOL) StrTrimA(IN OUT LPSTR pszTrimMe, LPCSTR pszTrimChars)
  1689. {
  1690. BOOL bRet = FALSE;
  1691. RIPMSG(pszTrimMe && IS_VALID_STRING_PTRA(pszTrimMe, -1), "StrTrimA: Caller passed invalid pszTrimMe");
  1692. RIPMSG(pszTrimChars && IS_VALID_STRING_PTRA(pszTrimChars, -1), "StrTrimA: Caller passed invalid pszTrimChars");
  1693. if (pszTrimMe && pszTrimChars)
  1694. {
  1695. LPSTR psz;
  1696. LPSTR pszStartMeat;
  1697. LPSTR pszMark = NULL;
  1698. /* Trim leading characters. */
  1699. psz = pszTrimMe;
  1700. while (*psz && StrChrA(pszTrimChars, READNATIVEWORD(psz)))
  1701. psz = CharNextA(psz);
  1702. pszStartMeat = psz;
  1703. /* Trim trailing characters. */
  1704. // (The old algorithm used to start from the end and go
  1705. // backwards, but that is piggy because DBCS version of
  1706. // CharPrev iterates from the beginning of the string
  1707. // on every call.)
  1708. while (*psz)
  1709. {
  1710. if (StrChrA(pszTrimChars, READNATIVEWORD(psz)))
  1711. {
  1712. if (!pszMark)
  1713. {
  1714. pszMark = psz;
  1715. }
  1716. }
  1717. else
  1718. {
  1719. pszMark = NULL;
  1720. }
  1721. psz = CharNextA(psz);
  1722. }
  1723. // Any trailing characters to clip?
  1724. if (pszMark)
  1725. {
  1726. // Yes
  1727. *pszMark = '\0';
  1728. bRet = TRUE;
  1729. }
  1730. /* Relocate stripped string. */
  1731. if (pszStartMeat > pszTrimMe)
  1732. {
  1733. /* (+ 1) for null terminator. */
  1734. MoveMemory(pszTrimMe, pszStartMeat, CbFromCchA(lstrlenA(pszStartMeat) + 1));
  1735. bRet = TRUE;
  1736. }
  1737. else
  1738. ASSERT(pszStartMeat == pszTrimMe);
  1739. ASSERT(IS_VALID_STRING_PTRA(pszTrimMe, -1));
  1740. }
  1741. return bRet;
  1742. }
  1743. /*----------------------------------------------------------
  1744. Purpose: Trim the string pszTrimMe of any leading or trailing
  1745. characters that are in pszTrimChars.
  1746. Returns: TRUE if anything was stripped
  1747. */
  1748. STDAPI_(BOOL) StrTrimW(IN OUT LPWSTR pszTrimMe, LPCWSTR pszTrimChars)
  1749. {
  1750. BOOL bRet = FALSE;
  1751. RIPMSG(pszTrimMe && IS_VALID_STRING_PTRW(pszTrimMe, -1), "StrTrimW: Caller passed invalid pszTrimMe");
  1752. RIPMSG(pszTrimChars && IS_VALID_STRING_PTRW(pszTrimChars, -1), "StrTrimW: Caller passed invalid pszTrimChars");
  1753. if (pszTrimMe && pszTrimChars)
  1754. {
  1755. LPWSTR psz;
  1756. LPWSTR pszStartMeat;
  1757. LPWSTR pszMark = NULL;
  1758. /* Trim leading characters. */
  1759. psz = pszTrimMe;
  1760. while (*psz && StrChrW(pszTrimChars, *psz))
  1761. psz++;
  1762. pszStartMeat = psz;
  1763. /* Trim trailing characters. */
  1764. // (The old algorithm used to start from the end and go
  1765. // backwards, but that is piggy because DBCS version of
  1766. // CharPrev iterates from the beginning of the string
  1767. // on every call.)
  1768. while (*psz)
  1769. {
  1770. if (StrChrW(pszTrimChars, *psz))
  1771. {
  1772. if (!pszMark)
  1773. {
  1774. pszMark = psz;
  1775. }
  1776. }
  1777. else
  1778. {
  1779. pszMark = NULL;
  1780. }
  1781. psz++;
  1782. }
  1783. // Any trailing characters to clip?
  1784. if (pszMark)
  1785. {
  1786. // Yes
  1787. *pszMark = '\0';
  1788. bRet = TRUE;
  1789. }
  1790. /* Relocate stripped string. */
  1791. if (pszStartMeat > pszTrimMe)
  1792. {
  1793. /* (+ 1) for null terminator. */
  1794. MoveMemory(pszTrimMe, pszStartMeat, CbFromCchW(lstrlenW(pszStartMeat) + 1));
  1795. bRet = TRUE;
  1796. }
  1797. else
  1798. ASSERT(pszStartMeat == pszTrimMe);
  1799. ASSERT(IS_VALID_STRING_PTRW(pszTrimMe, -1));
  1800. }
  1801. return bRet;
  1802. }
  1803. /*----------------------------------------------------------
  1804. Purpose: Compare strings using C runtime (ASCII) collation rules.
  1805. Returns: < 0 if pch1 < pch2
  1806. = 0 if pch1 == pch2
  1807. > 0 if pch1 > pch2
  1808. */
  1809. LWSTDAPI_(int) StrCmpNCA(LPCSTR pch1, LPCSTR pch2, int n)
  1810. {
  1811. if (n == 0)
  1812. return 0;
  1813. while (--n && *pch1 && *pch1 == *pch2)
  1814. {
  1815. pch1++;
  1816. pch2++;
  1817. }
  1818. return *(unsigned char *)pch1 - *(unsigned char *)pch2;
  1819. }
  1820. /*----------------------------------------------------------
  1821. Purpose: Compare strings using C runtime (ASCII) collation rules.
  1822. Returns: < 0 if pch1 < pch2
  1823. = 0 if pch1 == pch2
  1824. > 0 if pch1 > pch2
  1825. */
  1826. LWSTDAPI_(int) StrCmpNCW(LPCWSTR pch1, LPCWSTR pch2, int n)
  1827. {
  1828. if (n == 0)
  1829. return 0;
  1830. while (--n && *pch1 && *pch1 == *pch2)
  1831. {
  1832. pch1++;
  1833. pch2++;
  1834. }
  1835. return *pch1 - *pch2;
  1836. }
  1837. /*----------------------------------------------------------
  1838. Purpose: Compare strings using C runtime (ASCII) collation rules.
  1839. Returns: < 0 if pch1 < pch2
  1840. = 0 if pch1 == pch2
  1841. > 0 if pch1 > pch2
  1842. */
  1843. LWSTDAPI_(int) StrCmpNICA(LPCSTR pch1, LPCSTR pch2, int n)
  1844. {
  1845. int ch1, ch2;
  1846. if (n != 0)
  1847. {
  1848. do {
  1849. ch1 = *pch1++;
  1850. if (ch1 >= 'A' && ch1 <= 'Z')
  1851. ch1 += 'a' - 'A';
  1852. ch2 = *pch2++;
  1853. if (ch2 >= 'A' && ch2 <= 'Z')
  1854. ch2 += 'a' - 'A';
  1855. } while ( --n && ch1 && (ch1 == ch2) );
  1856. return ch1 - ch2;
  1857. }
  1858. else
  1859. {
  1860. return 0;
  1861. }
  1862. }
  1863. /*----------------------------------------------------------
  1864. Purpose: Compare strings using C runtime (ASCII) collation rules.
  1865. Returns: < 0 if pch1 < pch2
  1866. = 0 if pch1 == pch2
  1867. > 0 if pch1 > pch2
  1868. */
  1869. LWSTDAPI_(int) StrCmpNICW(LPCWSTR pch1, LPCWSTR pch2, int n)
  1870. {
  1871. int ch1, ch2;
  1872. if (n != 0)
  1873. {
  1874. do {
  1875. ch1 = *pch1++;
  1876. if (ch1 >= L'A' && ch1 <= L'Z')
  1877. ch1 += L'a' - L'A';
  1878. ch2 = *pch2++;
  1879. if (ch2 >= L'A' && ch2 <= L'Z')
  1880. ch2 += L'a' - L'A';
  1881. } while ( --n && ch1 && (ch1 == ch2) );
  1882. return ch1 - ch2;
  1883. }
  1884. else
  1885. {
  1886. return 0;
  1887. }
  1888. }
  1889. /*----------------------------------------------------------
  1890. Purpose: Compare strings using C runtime (ASCII) collation rules.
  1891. Returns: < 0 if pch1 < pch2
  1892. = 0 if pch1 == pch2
  1893. > 0 if pch1 > pch2
  1894. */
  1895. LWSTDAPI_(int) StrCmpCA(LPCSTR pch1, LPCSTR pch2)
  1896. {
  1897. while (*pch1 && (*pch1 == *pch2))
  1898. {
  1899. ++pch1;
  1900. ++pch2;
  1901. }
  1902. return *(unsigned char *)pch1 - *(unsigned char *)pch2;
  1903. }
  1904. /*----------------------------------------------------------
  1905. Purpose: Compare strings using C runtime (ASCII) collation rules.
  1906. Returns: < 0 if pch1 < pch2
  1907. = 0 if pch1 == pch2
  1908. > 0 if pch1 > pch2
  1909. */
  1910. LWSTDAPI_(int) StrCmpCW(LPCWSTR pch1, LPCWSTR pch2)
  1911. {
  1912. while (*pch1 && (*pch1 == *pch2))
  1913. {
  1914. ++pch1;
  1915. ++pch2;
  1916. }
  1917. return *pch1 - *pch2;
  1918. }
  1919. /*----------------------------------------------------------
  1920. Purpose: Compare strings using C runtime (ASCII) collation rules.
  1921. Returns: < 0 if pch1 < pch2
  1922. = 0 if pch1 == pch2
  1923. > 0 if pch1 > pch2
  1924. */
  1925. LWSTDAPI_(int) StrCmpICA(LPCSTR pch1, LPCSTR pch2)
  1926. {
  1927. int ch1, ch2;
  1928. do {
  1929. ch1 = *pch1++;
  1930. if (ch1 >= 'A' && ch1 <= 'Z')
  1931. ch1 += 'a' - 'A';
  1932. ch2 = *pch2++;
  1933. if (ch2 >= 'A' && ch2 <= 'Z')
  1934. ch2 += 'a' - 'A';
  1935. } while (ch1 && (ch1 == ch2));
  1936. return ch1 - ch2;
  1937. }
  1938. /*----------------------------------------------------------
  1939. Purpose: Compare strings using C runtime (ASCII) collation rules.
  1940. Returns: < 0 if pch1 < pch2
  1941. = 0 if pch1 == pch2
  1942. > 0 if pch1 > pch2
  1943. */
  1944. LWSTDAPI_(int) StrCmpICW(LPCWSTR pch1, LPCWSTR pch2)
  1945. {
  1946. int ch1, ch2;
  1947. do {
  1948. ch1 = *pch1++;
  1949. if (ch1 >= L'A' && ch1 <= L'Z')
  1950. ch1 += L'a' - L'A';
  1951. ch2 = *pch2++;
  1952. if (ch2 >= L'A' && ch2 <= L'Z')
  1953. ch2 += L'a' - L'A';
  1954. } while (ch1 && (ch1 == ch2));
  1955. return ch1 - ch2;
  1956. }
  1957. LWSTDAPI StrRetToStrW(STRRET *psr, LPCITEMIDLIST pidl, WCHAR **ppsz)
  1958. {
  1959. HRESULT hres = S_OK;
  1960. switch (psr->uType)
  1961. {
  1962. case STRRET_WSTR:
  1963. *ppsz = psr->pOleStr;
  1964. psr->pOleStr = NULL; // avoid alias
  1965. hres = *ppsz ? S_OK : E_FAIL;
  1966. break;
  1967. case STRRET_OFFSET:
  1968. hres = SHStrDupA(STRRET_OFFPTR(pidl, psr), ppsz);
  1969. break;
  1970. case STRRET_CSTR:
  1971. hres = SHStrDupA(psr->cStr, ppsz);
  1972. break;
  1973. default:
  1974. *ppsz = NULL;
  1975. hres = E_FAIL;
  1976. }
  1977. return hres;
  1978. }
  1979. LWSTDAPI StrRetToBSTR(STRRET *psr, LPCITEMIDLIST pidl, BSTR *pbstr)
  1980. {
  1981. switch (psr->uType)
  1982. {
  1983. case STRRET_WSTR:
  1984. {
  1985. LPWSTR psz = psr->pOleStr;
  1986. psr->pOleStr = NULL; // avoid alias
  1987. *pbstr = SysAllocString(psz);
  1988. CoTaskMemFree(psz);
  1989. break;
  1990. }
  1991. case STRRET_OFFSET:
  1992. *pbstr = SysAllocStringA(STRRET_OFFPTR(pidl, psr));
  1993. break;
  1994. case STRRET_CSTR:
  1995. *pbstr = SysAllocStringA(psr->cStr);
  1996. break;
  1997. default:
  1998. *pbstr = NULL;
  1999. return E_FAIL;
  2000. }
  2001. return (*pbstr) ? S_OK : E_OUTOFMEMORY;
  2002. }
  2003. HRESULT DupWideToAnsi(LPCWSTR pwsz, LPSTR *ppsz)
  2004. {
  2005. UINT cch = WideCharToMultiByte(CP_ACP, 0, pwsz, -1, NULL, 0, NULL, NULL) + 1;
  2006. *ppsz = CoTaskMemAlloc(cch * sizeof(**ppsz));
  2007. if (*ppsz)
  2008. {
  2009. SHUnicodeToAnsi(pwsz, *ppsz, cch);
  2010. return S_OK;
  2011. }
  2012. return E_OUTOFMEMORY;
  2013. }
  2014. HRESULT DupAnsiToAnsi(LPCSTR psz, LPSTR *ppsz)
  2015. {
  2016. int cch = lstrlenA(psz) + 1;
  2017. *ppsz = (LPSTR)CoTaskMemAlloc(cch * sizeof(**ppsz));
  2018. if (*ppsz)
  2019. {
  2020. StringCchCopyA(*ppsz, cch, psz);
  2021. return S_OK;
  2022. }
  2023. return E_OUTOFMEMORY;
  2024. }
  2025. LWSTDAPI StrRetToStrA(STRRET *psr, LPCITEMIDLIST pidl, CHAR **ppsz)
  2026. {
  2027. HRESULT hres;
  2028. LPWSTR pwsz;
  2029. switch (psr->uType)
  2030. {
  2031. case STRRET_WSTR:
  2032. hres = DupWideToAnsi(psr->pOleStr, ppsz);
  2033. pwsz = psr->pOleStr;
  2034. psr->pOleStr = NULL; // avoid alias
  2035. CoTaskMemFree(pwsz);
  2036. break;
  2037. case STRRET_OFFSET:
  2038. hres = DupAnsiToAnsi(STRRET_OFFPTR(pidl, psr), ppsz);
  2039. break;
  2040. case STRRET_CSTR:
  2041. hres = DupAnsiToAnsi(psr->cStr, ppsz);
  2042. break;
  2043. default:
  2044. *ppsz = NULL;
  2045. hres = E_FAIL;
  2046. }
  2047. return hres;
  2048. }
  2049. STDAPI StrRetToBufA(STRRET *psr, LPCITEMIDLIST pidl, LPSTR pszBuf, UINT cchBuf)
  2050. {
  2051. HRESULT hres = E_FAIL;
  2052. switch (psr->uType)
  2053. {
  2054. case STRRET_WSTR:
  2055. {
  2056. LPWSTR pszStr = psr->pOleStr; // temp copy because SHUnicodeToAnsi may overwrite buffer
  2057. if (pszStr)
  2058. {
  2059. SHUnicodeToAnsi(pszStr, pszBuf, cchBuf);
  2060. CoTaskMemFree(pszStr);
  2061. // Make sure no one thinks things are allocated still
  2062. psr->uType = STRRET_CSTR;
  2063. psr->cStr[0] = 0;
  2064. hres = S_OK;
  2065. }
  2066. }
  2067. break;
  2068. case STRRET_CSTR:
  2069. SHAnsiToAnsi(psr->cStr, pszBuf, cchBuf);
  2070. hres = S_OK;
  2071. break;
  2072. case STRRET_OFFSET:
  2073. if (pidl)
  2074. {
  2075. SHAnsiToAnsi(STRRET_OFFPTR(pidl, psr), pszBuf, cchBuf);
  2076. hres = S_OK;
  2077. }
  2078. break;
  2079. }
  2080. if (FAILED(hres) && cchBuf)
  2081. *pszBuf = 0;
  2082. return hres;
  2083. }
  2084. STDAPI StrRetToBufW(STRRET *psr, LPCITEMIDLIST pidl, LPWSTR pszBuf, UINT cchBuf)
  2085. {
  2086. HRESULT hres = E_FAIL;
  2087. switch (psr->uType)
  2088. {
  2089. case STRRET_WSTR:
  2090. {
  2091. LPWSTR pwszTmp = psr->pOleStr;
  2092. if (pwszTmp)
  2093. {
  2094. StrCpyNW(pszBuf, pwszTmp, cchBuf);
  2095. CoTaskMemFree(pwszTmp);
  2096. // Make sure no one thinks things are allocated still
  2097. psr->uType = STRRET_CSTR;
  2098. psr->cStr[0] = 0;
  2099. hres = S_OK;
  2100. }
  2101. }
  2102. break;
  2103. case STRRET_CSTR:
  2104. SHAnsiToUnicode(psr->cStr, pszBuf, cchBuf);
  2105. hres = S_OK;
  2106. break;
  2107. case STRRET_OFFSET:
  2108. if (pidl)
  2109. {
  2110. SHAnsiToUnicode(STRRET_OFFPTR(pidl, psr), pszBuf, cchBuf);
  2111. hres = S_OK;
  2112. }
  2113. break;
  2114. }
  2115. if (FAILED(hres) && cchBuf)
  2116. *pszBuf = 0;
  2117. return hres;
  2118. }
  2119. // dupe a string using the task allocator for returing from a COM interface
  2120. //
  2121. STDAPI SHStrDupA(LPCSTR psz, WCHAR **ppwsz)
  2122. {
  2123. WCHAR *pwsz;
  2124. DWORD cch;
  2125. RIPMSG(psz && IS_VALID_STRING_PTRA(psz, -1), "SHStrDupA: Caller passed invalid psz");
  2126. if (psz)
  2127. {
  2128. cch = MultiByteToWideChar(CP_ACP, 0, psz, -1, NULL, 0);
  2129. pwsz = (WCHAR *)CoTaskMemAlloc((cch + 1) * SIZEOF(WCHAR));
  2130. }
  2131. else
  2132. pwsz = NULL;
  2133. *((PVOID UNALIGNED64 *) ppwsz) = pwsz;
  2134. if (pwsz)
  2135. {
  2136. MultiByteToWideChar(CP_ACP, 0, psz, -1, *ppwsz, cch);
  2137. return S_OK;
  2138. }
  2139. return E_OUTOFMEMORY;
  2140. }
  2141. // dupe a string using the task allocator for returing from a COM interface
  2142. // Sometimes, due to structure packing, the pointer we get is not properly
  2143. // aligned for Win64, so we have to do UNALIGNED64.
  2144. //
  2145. STDAPI SHStrDupW(LPCWSTR psz, WCHAR **ppwsz)
  2146. {
  2147. WCHAR *pwsz;
  2148. int cb;
  2149. RIPMSG(psz && IS_VALID_STRING_PTRW(psz, -1), "SHStrDupW: Caller passed invalid psz");
  2150. if (psz)
  2151. {
  2152. cb = (lstrlenW(psz) + 1) * SIZEOF(WCHAR);
  2153. pwsz = (WCHAR *)CoTaskMemAlloc(cb);
  2154. }
  2155. else
  2156. pwsz = NULL;
  2157. *((PVOID UNALIGNED64 *) ppwsz) = pwsz;
  2158. if (pwsz)
  2159. {
  2160. CopyMemory(pwsz, psz, cb);
  2161. return S_OK;
  2162. }
  2163. return E_OUTOFMEMORY;
  2164. }
  2165. STDAPI_(int) StrCmpLogicalW(PCWSTR psz1, PCWSTR psz2)
  2166. {
  2167. int iRet = 0;
  2168. int iCmpNum = 0;
  2169. while (iRet == 0 && (*psz1 || *psz2))
  2170. {
  2171. int cch1 = 0;
  2172. int cch2 = 0;
  2173. BOOL fIsDigit1 = IS_DIGITW(*psz1);
  2174. BOOL fIsDigit2 = IS_DIGITW(*psz2);
  2175. ASSERT(fIsDigit1 == TRUE || fIsDigit1 == FALSE);
  2176. ASSERT(fIsDigit2 == TRUE || fIsDigit2 == FALSE);
  2177. // using bit wise XOR as logical XOR
  2178. // if the numbers are mismatched then n
  2179. if (fIsDigit1 ^ fIsDigit2)
  2180. {
  2181. iRet = _StrCmpLocaleW(NORM_IGNORECASE, psz1, -1, psz2, -1);
  2182. }
  2183. else if (fIsDigit1 && fIsDigit2)
  2184. {
  2185. int cchZero1 = 0;
  2186. int cchZero2 = 0;
  2187. // eat leading zeros
  2188. while (*psz1 == TEXT('0'))
  2189. {
  2190. psz1++;
  2191. cchZero1++;
  2192. }
  2193. while (*psz2 == TEXT('0'))
  2194. {
  2195. psz2++;
  2196. cchZero2++;
  2197. }
  2198. while (IS_DIGITW(psz1[cch1]))
  2199. cch1++;
  2200. while (IS_DIGITW(psz2[cch2]))
  2201. cch2++;
  2202. if (cch1 != cch2)
  2203. {
  2204. iRet = cch1 > cch2 ? 1 : -1;
  2205. }
  2206. else
  2207. {
  2208. // remember the first numerical difference
  2209. iRet = _StrCmpLocaleW(NORM_IGNORECASE, psz1, cch1, psz2, cch2);
  2210. if (iRet == 0 && iCmpNum == 0 && cchZero1 != cchZero2)
  2211. {
  2212. iCmpNum = cchZero2 > cchZero1 ? 1 : -1;
  2213. }
  2214. }
  2215. }
  2216. else
  2217. {
  2218. while (psz1[cch1] && !IS_DIGITW(psz1[cch1]))
  2219. cch1++;
  2220. while (psz2[cch2] && !IS_DIGITW(psz2[cch2]))
  2221. cch2++;
  2222. iRet = _StrCmpLocaleW(NORM_IGNORECASE, psz1, cch1, psz2, cch2);
  2223. }
  2224. // at this point they should be numbers or terminators or different
  2225. psz1 = &psz1[cch1];
  2226. psz2 = &psz2[cch2];
  2227. }
  2228. if (iRet == 0 && iCmpNum)
  2229. iRet = iCmpNum;
  2230. return iRet;
  2231. }
  2232. STDAPI_(DWORD) StrCatChainW(LPWSTR pszDst, DWORD cchDst, DWORD ichAt, LPCWSTR pszSrc)
  2233. {
  2234. RIPMSG(pszDst && IS_VALID_STRING_PTRW(pszDst, -1) && (DWORD)lstrlenW(pszDst)<cchDst && IS_VALID_WRITE_BUFFER(pszDst, WCHAR, cchDst), "StrCatChainW: Caller passed invalid pszDst");
  2235. RIPMSG(pszSrc && IS_VALID_STRING_PTRW(pszSrc, -1), "StrCatChainW: Caller passed invalid pszSrc");
  2236. if (ichAt == -1)
  2237. ichAt = lstrlenW(pszDst);
  2238. if (cchDst > 0)
  2239. {
  2240. #ifdef DEBUG
  2241. if (ichAt < cchDst)
  2242. DEBUGWhackPathBufferW(pszDst+ichAt, cchDst-ichAt);
  2243. #endif
  2244. while (ichAt < cchDst)
  2245. {
  2246. if (!(pszDst[ichAt] = *pszSrc++))
  2247. break;
  2248. ichAt++;
  2249. }
  2250. // check to make sure we copied a NULL
  2251. if (ichAt == cchDst)
  2252. pszDst[ichAt-1] = 0;
  2253. }
  2254. return ichAt;
  2255. }