2 * Shlwapi string functions
4 * Copyright 1998 Juergen Schmied
5 * Copyright 2002 Jon Griffiths
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #define COM_NO_WINDOWS_H
24 #include "wine/port.h"
30 #define NONAMELESSUNION
31 #define NONAMELESSSTRUCT
33 #define NO_SHLWAPI_REG
34 #define NO_SHLWAPI_STREAM
37 #include "wine/unicode.h"
38 #include "wine/debug.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(shell);
42 static HRESULT WINAPI _SHStrDupAA(LPCSTR,LPSTR*);
43 static HRESULT WINAPI _SHStrDupAW(LPCWSTR,LPSTR*);
45 /*************************************************************************
46 * SHLWAPI_ChrCmpHelperA
48 * Internal helper for SHLWAPI_ChrCmpA/ChrCMPIA.
51 * Both this function and its Unicode counterpart are very inneficient. To
52 * fix this, CompareString must be completely implemented and optimised
53 * first. Then the core character test can be taken out of that function and
54 * placed here, so that it need never be called at all. Until then, do not
55 * attempt to optimise this code unless you are willing to test that it
56 * still performs correctly.
58 static BOOL WINAPI SHLWAPI_ChrCmpHelperA(WORD ch1, WORD ch2, DWORD dwFlags)
60 char str1[3], str2[3];
62 str1[0] = LOBYTE(ch1);
63 if (IsDBCSLeadByte(ch1))
65 str1[1] = HIBYTE(ch1);
71 str2[0] = LOBYTE(ch2);
72 if (IsDBCSLeadByte(ch2))
74 str2[1] = HIBYTE(ch2);
80 return CompareStringA(GetThreadLocale(), dwFlags, str1, -1, str2, -1) - 2;
83 /*************************************************************************
84 * SHLWAPI_ChrCmpHelperW
86 * Internal helper for SHLWAPI_ChrCmpW/ChrCmpIW.
88 static BOOL WINAPI SHLWAPI_ChrCmpHelperW(WCHAR ch1, WCHAR ch2, DWORD dwFlags)
90 WCHAR str1[2], str2[2];
96 return CompareStringW(GetThreadLocale(), dwFlags, str1, 2, str2, 2) - 2;
99 /*************************************************************************
102 * Internal helper function.
104 static BOOL WINAPI SHLWAPI_ChrCmpA(WORD ch1, WORD ch2)
106 return SHLWAPI_ChrCmpHelperA(ch1, ch2, 0);
109 /*************************************************************************
110 * ChrCmpIA (SHLWAPI.385)
112 * Compare two characters, ignoring case.
115 * ch1 [I] First character to compare
116 * ch2 [I] Second character to compare
119 * FALSE, if the characters are equal.
120 * Non-zero otherwise.
122 BOOL WINAPI ChrCmpIA(WORD ch1, WORD ch2)
124 TRACE("(%d,%d)\n", ch1, ch2);
126 return SHLWAPI_ChrCmpHelperA(ch1, ch2, NORM_IGNORECASE);
129 /*************************************************************************
132 * Internal helper function.
134 static BOOL WINAPI SHLWAPI_ChrCmpW(WCHAR ch1, WCHAR ch2)
136 return SHLWAPI_ChrCmpHelperW(ch1, ch2, 0);
139 /*************************************************************************
140 * ChrCmpIW [SHLWAPI.386]
144 BOOL WINAPI ChrCmpIW(WCHAR ch1, WCHAR ch2)
146 return SHLWAPI_ChrCmpHelperW(ch1, ch2, NORM_IGNORECASE);
149 /*************************************************************************
150 * StrChrA [SHLWAPI.@]
152 * Find a given character in a string.
155 * lpszStr [I] String to search in.
156 * ch [I] Character to search for.
159 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
161 * Failure: NULL, if any arguments are invalid.
163 LPSTR WINAPI StrChrA(LPCSTR lpszStr, WORD ch)
165 TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch);
171 if (!SHLWAPI_ChrCmpA(*lpszStr, ch))
172 return (LPSTR)lpszStr;
173 lpszStr = CharNextA(lpszStr);
179 /*************************************************************************
180 * StrChrW [SHLWAPI.@]
184 LPWSTR WINAPI StrChrW(LPCWSTR lpszStr, WCHAR ch)
186 LPWSTR lpszRet = NULL;
188 TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch);
191 lpszRet = strchrW(lpszStr, ch);
195 /*************************************************************************
196 * StrChrIA [SHLWAPI.@]
198 * Find a given character in a string, ignoring case.
201 * lpszStr [I] String to search in.
202 * ch [I] Character to search for.
205 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
207 * Failure: NULL, if any arguments are invalid.
209 LPSTR WINAPI StrChrIA(LPCSTR lpszStr, WORD ch)
211 TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch);
217 if (!ChrCmpIA(*lpszStr, ch))
218 return (LPSTR)lpszStr;
219 lpszStr = CharNextA(lpszStr);
225 /*************************************************************************
226 * StrChrIW [SHLWAPI.@]
230 LPWSTR WINAPI StrChrIW(LPCWSTR lpszStr, WCHAR ch)
232 TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch);
239 if (toupperW(*lpszStr) == ch)
240 return (LPWSTR)lpszStr;
241 lpszStr = CharNextW(lpszStr);
245 return (LPWSTR)lpszStr;
248 /*************************************************************************
249 * StrCmpIW [SHLWAPI.@]
251 * Compare two strings, ignoring case.
254 * lpszStr [I] First string to compare
255 * lpszComp [I] Second string to compare
258 * An integer less than, equal to or greater than 0, indicating that
259 * lpszStr is less than, the same, or greater than lpszComp.
261 int WINAPI StrCmpIW(LPCWSTR lpszStr, LPCWSTR lpszComp)
265 TRACE("(%s,%s)\n", debugstr_w(lpszStr),debugstr_w(lpszComp));
267 iRet = strcmpiW(lpszStr, lpszComp);
268 return iRet < 0 ? -1 : iRet ? 1 : 0;
271 /*************************************************************************
272 * SHLWAPI_StrCmpNHelperA
274 * Internal helper for StrCmpNA/StrCmpNIA.
276 static INT WINAPI SHLWAPI_StrCmpNHelperA(LPCSTR lpszStr, LPCSTR lpszComp,
278 BOOL (WINAPI *pChrCmpFn)(WORD,WORD))
294 ch1 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr;
295 ch2 = IsDBCSLeadByte(*lpszComp)? *lpszComp << 8 | lpszComp[1] : *lpszComp;
297 if ((iDiff = pChrCmpFn(ch1, ch2)) < 0)
301 else if (!*lpszStr && !*lpszComp)
304 lpszStr = CharNextA(lpszStr);
305 lpszComp = CharNextA(lpszComp);
310 /*************************************************************************
311 * StrCmpNA [SHLWAPI.@]
313 * Compare two strings, up to a maximum length.
316 * lpszStr [I] First string to compare
317 * lpszComp [I] Second string to compare
318 * iLen [I] Maximum number of chars to compare.
321 * An integer less than, equal to or greater than 0, indicating that
322 * lpszStr is less than, the same, or greater than lpszComp.
324 INT WINAPI StrCmpNA(LPCSTR lpszStr, LPCSTR lpszComp, INT iLen)
326 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
328 return SHLWAPI_StrCmpNHelperA(lpszStr, lpszComp, iLen, SHLWAPI_ChrCmpA);
331 /*************************************************************************
332 * StrCmpNW [SHLWAPI.@]
336 INT WINAPI StrCmpNW(LPCWSTR lpszStr, LPCWSTR lpszComp, INT iLen)
340 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen);
342 iRet = strncmpW(lpszStr, lpszComp, iLen);
343 return iRet < 0 ? -1 : iRet ? 1 : 0;
346 /*************************************************************************
347 * StrCmpNIA [SHLWAPI.@]
349 * Compare two strings, up to a maximum length, ignoring case.
352 * lpszStr [I] First string to compare
353 * lpszComp [I] Second string to compare
354 * iLen [I] Maximum number of chars to compare.
357 * An integer less than, equal to or greater than 0, indicating that
358 * lpszStr is less than, the same, or greater than lpszComp.
361 * The Win32 version of this function is _completely_ broken for cases
362 * where iLen is greater than the length of lpszComp. Examples:
364 *| StrCmpNIA("foo.gif", "foo", 5) is -1 under Win32; Should return 1.
365 *| StrCmpNIA("\", "\\", 3) is 0 under Win32; Should return -1.
366 *| StrCmpNIA("\", "\..\foo\", 3) is 1 under Win32; Should return -1.
368 * This implementation behaves correctly, since it is unlikely any
369 * applications actually rely on this function being broken.
371 int WINAPI StrCmpNIA(LPCSTR lpszStr, LPCSTR lpszComp, int iLen)
373 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
375 return SHLWAPI_StrCmpNHelperA(lpszStr, lpszComp, iLen, ChrCmpIA);
378 /*************************************************************************
379 * StrCmpNIW [SHLWAPI.@]
383 INT WINAPI StrCmpNIW(LPCWSTR lpszStr, LPCWSTR lpszComp, int iLen)
387 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen);
389 iRet = strncmpiW(lpszStr, lpszComp, iLen);
390 return iRet < 0 ? -1 : iRet ? 1 : 0;
393 /*************************************************************************
394 * StrCmpW [SHLWAPI.@]
396 * Compare two strings.
399 * lpszStr [I] First string to compare
400 * lpszComp [I] Second string to compare
403 * An integer less than, equal to or greater than 0, indicating that
404 * lpszStr is less than, the same, or greater than lpszComp.
406 int WINAPI StrCmpW(LPCWSTR lpszStr, LPCWSTR lpszComp)
410 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszComp));
412 iRet = strcmpW(lpszStr, lpszComp);
413 return iRet < 0 ? -1 : iRet ? 1 : 0;
416 /*************************************************************************
417 * StrCatW [SHLWAPI.@]
419 * Concatanate two strings.
422 * lpszStr [O] Initial string
423 * lpszSrc [I] String to concatanate
428 LPWSTR WINAPI StrCatW(LPWSTR lpszStr, LPCWSTR lpszSrc)
430 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSrc));
432 strcatW(lpszStr, lpszSrc);
436 /*************************************************************************
437 * StrCpyW [SHLWAPI.@]
439 * Copy a string to another string.
442 * lpszStr [O] Destination string
443 * lpszSrc [I] Source string
448 LPWSTR WINAPI StrCpyW(LPWSTR lpszStr, LPCWSTR lpszSrc)
450 TRACE("(%p,%s)\n", lpszStr, debugstr_w(lpszSrc));
452 strcpyW(lpszStr, lpszSrc);
456 /*************************************************************************
457 * StrCpyNW [SHLWAPI.@]
459 * Copy a string to another string, up to a maximum number of characters.
462 * lpszStr [O] Destination string
463 * lpszSrc [I] Source string
464 * iLen [I] Maximum number of chars to copy
469 LPWSTR WINAPI StrCpyNW(LPWSTR lpszStr, LPCWSTR lpszSrc, int iLen)
471 TRACE("(%p,%s,%i)\n", lpszStr, debugstr_w(lpszSrc), iLen);
473 lstrcpynW(lpszStr, lpszSrc, iLen);
479 /*************************************************************************
480 * SHLWAPI_StrStrHelperA
482 * Internal implementation of StrStrA/StrStrIA
484 static LPSTR WINAPI SHLWAPI_StrStrHelperA(LPCSTR lpszStr, LPCSTR lpszSearch,
485 int (*pStrCmpFn)(LPCSTR,LPCSTR,size_t))
489 if (!lpszStr || !lpszSearch || !*lpszSearch)
492 iLen = strlen(lpszSearch);
496 if (!pStrCmpFn(lpszStr, lpszSearch, iLen))
497 return (LPSTR)lpszStr;
498 lpszStr = CharNextA(lpszStr);
503 /*************************************************************************
504 * SHLWAPI_StrStrHelperW
506 * Internal implementation of StrStrW/StrStrIW
508 static LPWSTR WINAPI SHLWAPI_StrStrHelperW(LPCWSTR lpszStr, LPCWSTR lpszSearch,
509 int (*pStrCmpFn)(LPCWSTR,LPCWSTR,int))
513 if (!lpszStr || !lpszSearch || !*lpszSearch)
516 iLen = strlenW(lpszSearch);
520 if (!pStrCmpFn(lpszStr, lpszSearch, iLen))
521 return (LPWSTR)lpszStr;
522 lpszStr = CharNextW(lpszStr);
527 /*************************************************************************
528 * StrStrA [SHLWAPI.@]
530 * Find a substring within a string.
533 * lpszStr [I] String to search in
534 * lpszSearch [I] String to look for
537 * The start of lpszSearch within lpszStr, or NULL if not found.
539 LPSTR WINAPI StrStrA(LPCSTR lpszStr, LPCSTR lpszSearch)
541 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
543 return SHLWAPI_StrStrHelperA(lpszStr, lpszSearch, strncmp);
546 /*************************************************************************
547 * StrStrW [SHLWAPI.@]
551 LPWSTR WINAPI StrStrW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
553 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
555 return SHLWAPI_StrStrHelperW(lpszStr, lpszSearch, strncmpW);
558 /*************************************************************************
559 * StrRStrIA [SHLWAPI.@]
561 * Find the last occurence of a substring within a string.
564 * lpszStr [I] String to search in
565 * lpszEnd [I] End of lpszStr
566 * lpszSearch [I] String to look for
569 * The last occurence lpszSearch within lpszStr, or NULL if not found.
571 LPSTR WINAPI StrRStrIA(LPCSTR lpszStr, LPCSTR lpszEnd, LPCSTR lpszSearch)
573 LPSTR lpszRet = NULL;
577 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
579 if (!lpszStr || !lpszSearch || !*lpszSearch)
583 lpszEnd = lpszStr + lstrlenA(lpszStr);
585 if (IsDBCSLeadByte(*lpszSearch))
586 ch1 = *lpszSearch << 8 | lpszSearch[1];
589 iLen = lstrlenA(lpszSearch);
591 while (lpszStr <= lpszEnd && *lpszStr)
593 ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr;
594 if (!ChrCmpIA(ch1, ch2))
596 if (!StrCmpNIA(lpszStr, lpszSearch, iLen))
597 lpszRet = (LPSTR)lpszStr;
599 lpszStr = CharNextA(lpszStr);
604 /*************************************************************************
605 * StrRStrIW [SHLWAPI.@]
609 LPWSTR WINAPI StrRStrIW(LPCWSTR lpszStr, LPCWSTR lpszEnd, LPCWSTR lpszSearch)
611 LPWSTR lpszRet = NULL;
614 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
616 if (!lpszStr || !lpszSearch || !*lpszSearch)
620 lpszEnd = lpszStr + strlenW(lpszStr);
622 iLen = strlenW(lpszSearch);
624 while (lpszStr <= lpszEnd && *lpszStr)
626 if (!ChrCmpIA(*lpszSearch, *lpszStr))
628 if (!StrCmpNIW(lpszStr, lpszSearch, iLen))
629 lpszRet = (LPWSTR)lpszStr;
631 lpszStr = CharNextW(lpszStr);
636 /*************************************************************************
637 * StrStrIA [SHLWAPI.@]
639 * Find a substring within a string, ignoring case.
642 * lpszStr [I] String to search in
643 * lpszSearch [I] String to look for
646 * The start of lpszSearch within lpszStr, or NULL if not found.
648 LPSTR WINAPI StrStrIA(LPCSTR lpszStr, LPCSTR lpszSearch)
650 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
652 return SHLWAPI_StrStrHelperA(lpszStr, lpszSearch, strncasecmp);
655 /*************************************************************************
656 * StrStrIW [SHLWAPI.@]
660 LPWSTR WINAPI StrStrIW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
662 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
664 return SHLWAPI_StrStrHelperW(lpszStr, lpszSearch, strncmpiW);
667 /*************************************************************************
668 * StrToIntA [SHLWAPI.@]
670 * Read an integer from a string.
673 * lpszStr [I] String to read integer from
676 * The integer value represented by the string, or 0 if no integer is
680 * No leading space is allowed before the number, although a leading '-' is.
682 int WINAPI StrToIntA(LPCSTR lpszStr)
686 TRACE("(%s)\n", debugstr_a(lpszStr));
690 WARN("Invalid lpszStr would crash under Win32!\n");
694 if (*lpszStr == '-' || isdigit(*lpszStr))
695 StrToIntExA(lpszStr, 0, &iRet);
699 /*************************************************************************
700 * StrToIntW [SHLWAPI.@]
704 int WINAPI StrToIntW(LPCWSTR lpszStr)
708 TRACE("(%s)\n", debugstr_w(lpszStr));
712 WARN("Invalid lpszStr would crash under Win32!\n");
716 if (*lpszStr == '-' || isdigitW(*lpszStr))
717 StrToIntExW(lpszStr, 0, &iRet);
721 /*************************************************************************
722 * StrToIntExA [SHLWAPI.@]
724 * Read an integer from a string.
727 * lpszStr [I] String to read integer from
728 * dwFlags [I] Flags controlling the conversion
729 * lpiRet [O] Destination for read integer.
732 * Success: TRUE. lpiRet contains the integer value represented by the string.
733 * Failure: FALSE, if the string is invalid, or no number is present.
736 * Leading whitespace, '-' and '+' are allowed before the number. If
737 * dwFlags includes STIF_SUPPORT_HEX, hexidecimal numbers are allowed, if
738 * preceeded by '0x'. If this flag is not set, or there is no '0x' prefix,
739 * the string is treated as a decimal string. A leading '-' is ignored for
740 * hexidecimal numbers.
742 BOOL WINAPI StrToIntExA(LPCSTR lpszStr, DWORD dwFlags, LPINT lpiRet)
744 BOOL bNegative = FALSE;
747 TRACE("(%s,%08lX,%p)\n", debugstr_a(lpszStr), dwFlags, lpiRet);
749 if (!lpszStr || !lpiRet)
751 WARN("Invalid parameter would crash under Win32!\n");
754 if (dwFlags > STIF_SUPPORT_HEX)
756 WARN("Unknown flags (%08lX)!\n", dwFlags & ~STIF_SUPPORT_HEX);
759 /* Skip leading space, '+', '-' */
760 while (isspace(*lpszStr))
761 lpszStr = CharNextA(lpszStr);
768 else if (*lpszStr == '+')
771 if (dwFlags & STIF_SUPPORT_HEX &&
772 *lpszStr == '0' && tolower(lpszStr[1]) == 'x')
774 /* Read hex number */
777 if (!isxdigit(*lpszStr))
780 while (isxdigit(*lpszStr))
783 if (isdigit(*lpszStr))
784 iRet += (*lpszStr - '0');
786 iRet += 10 + (tolower(*lpszStr) - 'a');
793 /* Read decimal number */
794 if (!isdigit(*lpszStr))
797 while (isdigit(*lpszStr))
800 iRet += (*lpszStr - '0');
803 *lpiRet = bNegative ? -iRet : iRet;
807 /*************************************************************************
808 * StrToIntExW [SHLWAPI.@]
812 BOOL WINAPI StrToIntExW(LPCWSTR lpszStr, DWORD dwFlags, LPINT lpiRet)
814 BOOL bNegative = FALSE;
817 TRACE("(%s,%08lX,%p)\n", debugstr_w(lpszStr), dwFlags, lpiRet);
819 if (!lpszStr || !lpiRet)
821 WARN("Invalid parameter would crash under Win32!\n");
824 if (dwFlags > STIF_SUPPORT_HEX)
826 WARN("Unknown flags (%08lX)!\n", dwFlags & ~STIF_SUPPORT_HEX);
829 /* Skip leading space, '+', '-' */
830 while (isspaceW(*lpszStr))
831 lpszStr = CharNextW(lpszStr);
838 else if (*lpszStr == '+')
841 if (dwFlags & STIF_SUPPORT_HEX &&
842 *lpszStr == '0' && tolowerW(lpszStr[1]) == 'x')
844 /* Read hex number */
847 if (!isxdigitW(*lpszStr))
850 while (isxdigitW(*lpszStr))
853 if (isdigitW(*lpszStr))
854 iRet += (*lpszStr - '0');
856 iRet += 10 + (tolowerW(*lpszStr) - 'a');
863 /* Read decimal number */
864 if (!isdigitW(*lpszStr))
867 while (isdigitW(*lpszStr))
870 iRet += (*lpszStr - '0');
873 *lpiRet = bNegative ? -iRet : iRet;
877 /*************************************************************************
878 * StrDupA [SHLWAPI.@]
880 * Duplicate a string.
883 * lpszStr [I] String to duplicate.
886 * Success: A pointer to a new string containing the contents of lpszStr
887 * Failure: NULL, if memory cannot be allocated
890 * The string memory is allocated with LocalAlloc(), and so should be released
891 * by calling LocalFree().
893 LPSTR WINAPI StrDupA(LPCSTR lpszStr)
898 TRACE("(%s)\n",debugstr_a(lpszStr));
900 iLen = lpszStr ? strlen(lpszStr) + 1 : 1;
901 lpszRet = (LPSTR)LocalAlloc(LMEM_FIXED, iLen);
906 memcpy(lpszRet, lpszStr, iLen);
913 /*************************************************************************
914 * StrDupW [SHLWAPI.@]
918 LPWSTR WINAPI StrDupW(LPCWSTR lpszStr)
923 TRACE("(%s)\n",debugstr_w(lpszStr));
925 iLen = (lpszStr ? strlenW(lpszStr) + 1 : 1) * sizeof(WCHAR);
926 lpszRet = (LPWSTR)LocalAlloc(LMEM_FIXED, iLen);
931 memcpy(lpszRet, lpszStr, iLen);
938 /*************************************************************************
939 * SHLWAPI_StrSpnHelperA
941 * Internal implementation of StrSpnA/StrCSpnA/StrCSpnIA
943 static int WINAPI SHLWAPI_StrSpnHelperA(LPCSTR lpszStr, LPCSTR lpszMatch,
944 LPSTR (WINAPI *pStrChrFn)(LPCSTR,WORD),
947 LPCSTR lpszRead = lpszStr;
948 if (lpszStr && *lpszStr && lpszMatch)
952 LPCSTR lpszTest = pStrChrFn(lpszMatch, *lpszRead);
954 if (!bInvert && !lpszTest)
956 if (bInvert && lpszTest)
958 lpszRead = CharNextA(lpszRead);
961 return lpszRead - lpszStr;
964 /*************************************************************************
965 * SHLWAPI_StrSpnHelperW
967 * Internal implementation of StrSpnW/StrCSpnW/StrCSpnIW
969 static int WINAPI SHLWAPI_StrSpnHelperW(LPCWSTR lpszStr, LPCWSTR lpszMatch,
970 LPWSTR (WINAPI *pStrChrFn)(LPCWSTR,WCHAR),
973 LPCWSTR lpszRead = lpszStr;
974 if (lpszStr && *lpszStr && lpszMatch)
978 LPCWSTR lpszTest = pStrChrFn(lpszMatch, *lpszRead);
980 if (!bInvert && !lpszTest)
982 if (bInvert && lpszTest)
984 lpszRead = CharNextW(lpszRead);
987 return lpszRead - lpszStr;
990 /*************************************************************************
991 * StrSpnA [SHLWAPI.@]
993 * Find the length of the start of a string that contains only certain
997 * lpszStr [I] String to search
998 * lpszMatch [I] Characters that can be in the substring
1001 * The length of the part of lpszStr containing only chars from lpszMatch,
1002 * or 0 if any parameter is invalid.
1004 int WINAPI StrSpnA(LPCSTR lpszStr, LPCSTR lpszMatch)
1006 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1008 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, FALSE);
1011 /*************************************************************************
1012 * StrSpnW [SHLWAPI.@]
1016 int WINAPI StrSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1018 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1020 return SHLWAPI_StrSpnHelperW(lpszStr, lpszMatch, StrChrW, FALSE);
1023 /*************************************************************************
1024 * StrCSpnA [SHLWAPI.@]
1026 * Find the length of the start of a string that does not contain certain
1030 * lpszStr [I] String to search
1031 * lpszMatch [I] Characters that cannot be in the substring
1034 * The length of the part of lpszStr containing only chars not in lpszMatch,
1035 * or 0 if any parameter is invalid.
1037 int WINAPI StrCSpnA(LPCSTR lpszStr, LPCSTR lpszMatch)
1039 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1041 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, TRUE);
1044 /*************************************************************************
1045 * StrCSpnW [SHLWAPI.@]
1049 int WINAPI StrCSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1051 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1053 return SHLWAPI_StrSpnHelperW(lpszStr, lpszMatch, StrChrW, TRUE);
1056 /*************************************************************************
1057 * StrCSpnIA [SHLWAPI.@]
1059 * Find the length of the start of a string that does not contain certain
1060 * characters, ignoring case.
1063 * lpszStr [I] String to search
1064 * lpszMatch [I] Characters that cannot be in the substring
1067 * The length of the part of lpszStr containing only chars not in lpszMatch,
1068 * or 0 if any parameter is invalid.
1070 int WINAPI StrCSpnIA(LPCSTR lpszStr, LPCSTR lpszMatch)
1072 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1074 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrIA, TRUE);
1077 /*************************************************************************
1078 * StrCSpnIW [SHLWAPI.@]
1082 int WINAPI StrCSpnIW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1084 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1086 return SHLWAPI_StrSpnHelperW(lpszStr, lpszMatch, StrChrIW, TRUE);
1089 /*************************************************************************
1090 * StrPBrkA [SHLWAPI.@]
1092 * Search a string for any of a group of characters.
1095 * lpszStr [I] String to search
1096 * lpszMatch [I] Characters to match
1099 * A pointer to the first matching character in lpszStr, or NULL if no
1102 LPSTR WINAPI StrPBrkA(LPCSTR lpszStr, LPCSTR lpszMatch)
1104 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1106 if (lpszStr && lpszMatch && *lpszMatch)
1110 if (StrChrA(lpszMatch, *lpszStr))
1111 return (LPSTR)lpszStr;
1112 lpszStr = CharNextA(lpszStr);
1118 /*************************************************************************
1119 * StrPBrkW [SHLWAPI.@]
1123 LPWSTR WINAPI StrPBrkW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1125 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1127 if (lpszStr && lpszMatch && *lpszMatch)
1131 if (StrChrW(lpszMatch, *lpszStr))
1132 return (LPWSTR)lpszStr;
1133 lpszStr = CharNextW(lpszStr);
1139 /*************************************************************************
1140 * SHLWAPI_StrRChrHelperA
1142 * Internal implementation of StrRChrA/StrRChrIA.
1144 static LPSTR WINAPI SHLWAPI_StrRChrHelperA(LPCSTR lpszStr,
1145 LPCSTR lpszEnd, WORD ch,
1146 BOOL (WINAPI *pChrCmpFn)(WORD,WORD))
1148 LPCSTR lpszRet = NULL;
1155 lpszEnd = lpszStr + lstrlenA(lpszStr);
1157 while (*lpszStr && lpszStr <= lpszEnd)
1159 ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr;
1161 if (!pChrCmpFn(ch, ch2))
1163 lpszStr = CharNextA(lpszStr);
1166 return (LPSTR)lpszRet;
1169 /*************************************************************************
1170 * SHLWAPI_StrRChrHelperW
1172 * Internal implementation of StrRChrW/StrRChrIW.
1174 static LPWSTR WINAPI SHLWAPI_StrRChrHelperW(LPCWSTR lpszStr,
1175 LPCWSTR lpszEnd, WCHAR ch,
1176 BOOL (WINAPI *pChrCmpFn)(WCHAR,WCHAR))
1178 LPCWSTR lpszRet = NULL;
1183 lpszEnd = lpszStr + strlenW(lpszStr);
1185 while (*lpszStr && lpszStr <= lpszEnd)
1187 if (!pChrCmpFn(ch, *lpszStr))
1189 lpszStr = CharNextW(lpszStr);
1192 return (LPWSTR)lpszRet;
1195 /**************************************************************************
1196 * StrRChrA [SHLWAPI.@]
1198 * Find the last occurence of a character in string.
1201 * lpszStr [I] String to search in
1202 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1203 * ch [I] Character to search for.
1206 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1207 * or NULL if not found.
1208 * Failure: NULL, if any arguments are invalid.
1210 LPSTR WINAPI StrRChrA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch)
1212 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch);
1214 return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, SHLWAPI_ChrCmpA);
1217 /**************************************************************************
1218 * StrRChrW [SHLWAPI.@]
1222 LPWSTR WINAPI StrRChrW(LPCWSTR lpszStr, LPCWSTR lpszEnd, WORD ch)
1224 TRACE("(%s,%s,%x)\n", debugstr_w(lpszStr), debugstr_w(lpszEnd), ch);
1226 return SHLWAPI_StrRChrHelperW(lpszStr, lpszEnd, ch, SHLWAPI_ChrCmpW);
1229 /**************************************************************************
1230 * StrRChrIA [SHLWAPI.@]
1232 * Find the last occurence of a character in string, ignoring case.
1235 * lpszStr [I] String to search in
1236 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1237 * ch [I] Character to search for.
1240 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1241 * or NULL if not found.
1242 * Failure: NULL, if any arguments are invalid.
1244 LPSTR WINAPI StrRChrIA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch)
1246 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch);
1248 return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, ChrCmpIA);
1251 /**************************************************************************
1252 * StrRChrIW [SHLWAPI.@]
1256 LPWSTR WINAPI StrRChrIW(LPCWSTR lpszStr, LPCWSTR lpszEnd, WORD ch)
1258 TRACE("(%s,%s,%x)\n", debugstr_w(lpszStr), debugstr_w(lpszEnd), ch);
1260 return SHLWAPI_StrRChrHelperW(lpszStr, lpszEnd, ch, ChrCmpIW);
1263 /*************************************************************************
1264 * StrCatBuffA [SHLWAPI.@]
1266 * Concatenate two strings together.
1269 * lpszStr [O] String to concatenate to
1270 * lpszCat [I] String to add to lpszCat
1271 * cchMax [I] Maximum number of characters for the whole string
1277 * cchMax determines the number of characters in the final length of the
1278 * string, not the number appended to lpszStr from lpszCat.
1280 LPSTR WINAPI StrCatBuffA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax)
1284 TRACE("(%p,%s,%d)\n", lpszStr, debugstr_a(lpszCat), cchMax);
1288 WARN("Invalid lpszStr would crash under Win32!\n");
1292 iLen = strlen(lpszStr);
1296 StrCpyNA(lpszStr + iLen, lpszCat, cchMax);
1300 /*************************************************************************
1301 * StrCatBuffW [SHLWAPI.@]
1305 LPWSTR WINAPI StrCatBuffW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax)
1309 TRACE("(%p,%s,%d)\n", lpszStr, debugstr_w(lpszCat), cchMax);
1313 WARN("Invalid lpszStr would crash under Win32!\n");
1317 iLen = strlenW(lpszStr);
1321 StrCpyNW(lpszStr + iLen, lpszCat, cchMax);
1325 /*************************************************************************
1326 * StrRetToBufA [SHLWAPI.@]
1328 * Convert a STRRET to a normal string.
1331 * lpStrRet [O] STRRET to convert
1332 * pIdl [I] ITEMIDLIST for lpStrRet->uType = STRRET_OFFSETA
1333 * lpszDest [O] Destination for normal string
1334 * dwLen [I] Length of lpszDest
1337 * Success: S_OK. lpszDest contains up to dwLen characters of the string.
1338 * If lpStrRet is of type STRRET_WSTR, its memory is freed with
1339 * CoTaskMemFree() and its type set to STRRET_CSTRA.
1340 * Failure: E_FAIL, if any parameters are invalid.
1342 HRESULT WINAPI StrRetToBufA (LPSTRRET src, const ITEMIDLIST *pidl, LPSTR dest, DWORD len)
1345 * This routine is identical to that in dlls/shell32/shellstring.c.
1346 * It was duplicated because not every version of Shlwapi.dll exports
1347 * StrRetToBufA. If you change one routine, change them both.
1349 TRACE("dest=%p len=0x%lx strret=%p pidl=%p stub\n",dest,len,src,pidl);
1353 WARN("Invalid lpStrRet would crash under Win32!\n");
1367 WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, dest, len, NULL, NULL);
1368 CoTaskMemFree(src->u.pOleStr);
1372 lstrcpynA((LPSTR)dest, src->u.cStr, len);
1376 lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len);
1380 FIXME("unknown type!\n");
1386 /*************************************************************************
1387 * StrRetToBufW [SHLWAPI.@]
1391 HRESULT WINAPI StrRetToBufW (LPSTRRET src, const ITEMIDLIST *pidl, LPWSTR dest, DWORD len)
1393 TRACE("dest=%p len=0x%lx strret=%p pidl=%p stub\n",dest,len,src,pidl);
1397 WARN("Invalid lpStrRet would crash under Win32!\n");
1411 lstrcpynW((LPWSTR)dest, src->u.pOleStr, len);
1412 CoTaskMemFree(src->u.pOleStr);
1416 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
1423 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1,
1430 FIXME("unknown type!\n");
1436 /*************************************************************************
1437 * StrRetToStrA [SHLWAPI.@]
1439 * Converts a STRRET to a normal string.
1442 * lpStrRet [O] STRRET to convert
1443 * pidl [I] ITEMIDLIST for lpStrRet->uType = STRRET_OFFSETA
1444 * ppszName [O] Destination for converted string
1447 * Success: S_OK. ppszName contains the new string, allocated with CoTaskMemAlloc().
1448 * Failure: E_FAIL, if any parameters are invalid.
1450 HRESULT WINAPI StrRetToStrA(LPSTRRET lpStrRet, const ITEMIDLIST *pidl, LPSTR *ppszName)
1452 HRESULT hRet = E_FAIL;
1454 switch (lpStrRet->uType)
1457 hRet = _SHStrDupAW(lpStrRet->u.pOleStr, ppszName);
1458 CoTaskMemFree(lpStrRet->u.pOleStr);
1462 hRet = _SHStrDupAA(lpStrRet->u.cStr, ppszName);
1466 hRet = _SHStrDupAA(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, ppszName);
1476 /*************************************************************************
1477 * StrRetToStrW [SHLWAPI.@]
1481 HRESULT WINAPI StrRetToStrW(LPSTRRET lpStrRet, const ITEMIDLIST *pidl, LPWSTR *ppszName)
1483 HRESULT hRet = E_FAIL;
1485 switch (lpStrRet->uType)
1488 hRet = SHStrDupW(lpStrRet->u.pOleStr, ppszName);
1489 CoTaskMemFree(lpStrRet->u.pOleStr);
1493 hRet = SHStrDupA(lpStrRet->u.cStr, ppszName);
1497 hRet = SHStrDupA(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, ppszName);
1507 /*************************************************************************
1508 * StrFormatKBSizeA [SHLWAPI.@]
1510 * Create a formatted string containing a byte count in Kilobytes.
1513 * llBytes [I] Byte size to format
1514 * lpszDest [I] Destination for formatted string
1515 * cchMax [I] Size of lpszDest
1520 LPSTR WINAPI StrFormatKBSizeA(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax)
1522 char szBuff[256], *szOut = szBuff + sizeof(szBuff) - 1;
1523 LONGLONG ulKB = (llBytes + 1023) >> 10;
1525 TRACE("(%lld,%p,%d)\n", llBytes, lpszDest, cchMax);
1534 LONGLONG ulNextDigit = ulKB % 10;
1535 *szOut-- = '0' + ulNextDigit;
1536 ulKB = (ulKB - ulNextDigit) / 10;
1539 strncpy(lpszDest, szOut + 1, cchMax);
1543 /*************************************************************************
1544 * StrFormatKBSizeW [SHLWAPI.@]
1546 * See StrFormatKBSizeA.
1548 LPWSTR WINAPI StrFormatKBSizeW(LONGLONG llBytes, LPWSTR lpszDest, UINT cchMax)
1550 WCHAR szBuff[256], *szOut = szBuff + sizeof(szBuff)/sizeof(WCHAR) - 1;
1551 LONGLONG ulKB = (llBytes + 1023) >> 10;
1553 TRACE("(%lld,%p,%d)\n", llBytes, lpszDest, cchMax);
1562 LONGLONG ulNextDigit = ulKB % 10;
1563 *szOut-- = '0' + ulNextDigit;
1564 ulKB = (ulKB - ulNextDigit) / 10;
1567 strncpyW(lpszDest, szOut + 1, cchMax);
1571 /*************************************************************************
1572 * StrNCatA [SHLWAPI.@]
1574 * Concatenate two strings together.
1577 * lpszStr [O] String to concatenate to
1578 * lpszCat [I] String to add to lpszCat
1579 * cchMax [I] Maximum number of characters to concatenate
1585 * cchMax determines the number of characters that are appended to lpszStr,
1586 * not the total length of the string.
1588 LPSTR WINAPI StrNCatA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax)
1590 LPSTR lpszRet = lpszStr;
1592 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszCat), cchMax);
1596 WARN("Invalid lpszStr would crash under Win32!\n");
1600 StrCpyNA(lpszStr + strlen(lpszStr), lpszCat, cchMax);
1604 /*************************************************************************
1605 * StrNCatW [SHLWAPI.@]
1609 LPWSTR WINAPI StrNCatW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax)
1611 LPWSTR lpszRet = lpszStr;
1613 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszCat), cchMax);
1617 WARN("Invalid lpszStr would crash under Win32\n");
1621 StrCpyNW(lpszStr + strlenW(lpszStr), lpszCat, cchMax);
1625 /*************************************************************************
1626 * StrTrimA [SHLWAPI.@]
1628 * Remove characters from the start and end of a string.
1631 * lpszStr [O] String to remove characters from
1632 * lpszTrim [I] Characters to remove from lpszStr
1635 * TRUE If lpszStr was valid and modified
1638 BOOL WINAPI StrTrimA(LPSTR lpszStr, LPCSTR lpszTrim)
1641 LPSTR lpszRead = lpszStr;
1644 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszTrim));
1646 if (lpszRead && *lpszRead)
1648 while (*lpszRead && StrChrA(lpszTrim, *lpszRead))
1649 lpszRead = CharNextA(lpszRead); /* Skip leading matches */
1651 dwLen = strlen(lpszRead);
1653 if (lpszRead != lpszStr)
1655 memmove(lpszStr, lpszRead, dwLen + 1);
1660 lpszRead = lpszStr + dwLen;
1661 while (StrChrA(lpszTrim, lpszRead[-1]))
1662 lpszRead = CharPrevA(lpszStr, lpszRead); /* Skip trailing matches */
1664 if (lpszRead != lpszStr + dwLen)
1674 /*************************************************************************
1675 * StrTrimW [SHLWAPI.@]
1679 BOOL WINAPI StrTrimW(LPWSTR lpszStr, LPCWSTR lpszTrim)
1682 LPWSTR lpszRead = lpszStr;
1685 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszTrim));
1687 if (lpszRead && *lpszRead)
1689 while (*lpszRead && StrChrW(lpszTrim, *lpszRead))
1690 lpszRead = CharNextW(lpszRead); /* Skip leading matches */
1692 dwLen = strlenW(lpszRead);
1694 if (lpszRead != lpszStr)
1696 memmove(lpszStr, lpszRead, (dwLen + 1) * sizeof(WCHAR));
1701 lpszRead = lpszStr + dwLen;
1702 while (StrChrW(lpszTrim, lpszRead[-1]))
1703 lpszRead = CharPrevW(lpszStr, lpszRead); /* Skip trailing matches */
1705 if (lpszRead != lpszStr + dwLen)
1715 /*************************************************************************
1716 * _SHStrDupAA [INTERNAL]
1718 * Duplicates a ASCII string to ASCII. The destination buffer is allocated.
1720 static HRESULT WINAPI _SHStrDupAA(LPCSTR src, LPSTR * dest)
1726 len = lstrlenA(src) + 1;
1727 *dest = CoTaskMemAlloc(len);
1733 lstrcpynA(*dest,src, len);
1739 TRACE("%s->(%p)\n", debugstr_a(src), *dest);
1743 /*************************************************************************
1746 * Return a Unicode copy of a string, in memory allocated by CoTaskMemAlloc().
1749 * lpszStr [I] String to copy
1750 * lppszDest [O] Destination for the new string copy
1753 * Success: S_OK. lppszDest contains the new string in Unicode format.
1754 * Failure: E_OUTOFMEMORY, If any arguments are invalid or memory allocation
1757 HRESULT WINAPI SHStrDupA(LPCSTR lpszStr, LPWSTR * lppszDest)
1764 len = MultiByteToWideChar(0, 0, lpszStr, -1, 0, 0) * sizeof(WCHAR);
1765 *lppszDest = CoTaskMemAlloc(len);
1772 MultiByteToWideChar(0, 0, lpszStr, -1, *lppszDest, len);
1776 hRet = E_OUTOFMEMORY;
1778 TRACE("%s->(%p)\n", debugstr_a(lpszStr), *lppszDest);
1782 /*************************************************************************
1783 * _SHStrDupAW [INTERNAL]
1785 * Duplicates a UNICODE to a ASCII string. The destination buffer is allocated.
1787 static HRESULT WINAPI _SHStrDupAW(LPCWSTR src, LPSTR * dest)
1793 len = WideCharToMultiByte(CP_ACP, 0, src, -1, NULL, 0, NULL, NULL);
1794 *dest = CoTaskMemAlloc(len);
1800 WideCharToMultiByte(CP_ACP, 0, src, -1, *dest, len, NULL, NULL);
1806 TRACE("%s->(%p)\n", debugstr_w(src), *dest);
1810 /*************************************************************************
1815 HRESULT WINAPI SHStrDupW(LPCWSTR src, LPWSTR * dest)
1821 len = (lstrlenW(src) + 1) * sizeof(WCHAR);
1822 *dest = CoTaskMemAlloc(len);
1828 memcpy(*dest, src, len);
1834 TRACE("%s->(%p)\n", debugstr_w(src), *dest);
1838 /*************************************************************************
1839 * SHLWAPI_WriteReverseNum
1841 * Internal helper for SHLWAPI_WriteTimeClass.
1843 inline static LPWSTR SHLWAPI_WriteReverseNum(LPWSTR lpszOut, DWORD dwNum)
1847 /* Write a decimal number to a string, backwards */
1850 DWORD dwNextDigit = dwNum % 10;
1851 *lpszOut-- = '0' + dwNextDigit;
1852 dwNum = (dwNum - dwNextDigit) / 10;
1853 } while (dwNum > 0);
1858 /*************************************************************************
1859 * SHLWAPI_FormatSignificant
1861 * Internal helper for SHLWAPI_WriteTimeClass.
1863 inline static int SHLWAPI_FormatSignificant(LPWSTR lpszNum, int dwDigits)
1865 /* Zero non significant digits, return remaining significant digits */
1869 if (--dwDigits == 0)
1879 /*************************************************************************
1880 * SHLWAPI_WriteTimeClass
1882 * Internal helper for StrFromTimeIntervalW.
1884 static int WINAPI SHLWAPI_WriteTimeClass(LPWSTR lpszOut, DWORD dwValue,
1885 LPCWSTR lpszClass, int iDigits)
1887 WCHAR szBuff[64], *szOut = szBuff + 32;
1889 szOut = SHLWAPI_WriteReverseNum(szOut, dwValue);
1890 iDigits = SHLWAPI_FormatSignificant(szOut + 1, iDigits);
1892 strcpyW(szBuff + 32, lpszClass);
1893 strcatW(lpszOut, szOut);
1897 /*************************************************************************
1898 * StrFromTimeIntervalA [SHLWAPI.@]
1900 * Format a millisecond time interval into a string
1903 * lpszStr [O] Output buffer for formatted time interval
1904 * cchMax [I] Size of lpszStr
1905 * dwMS [I] Number of milliseconds
1906 * iDigits [I] Number of digits to print
1909 * The length of the formatted string, or 0 if any parameter is invalid.
1912 * This implementation mimics the Win32 behaviour of always writing a leading
1913 * space before the time interval begins.
1915 * iDigits is used to provide approximate times if accuracy is not important.
1916 * This number of digits will be written of the first non-zero time class
1917 * (hours/minutes/seconds). If this does not complete the time classification,
1918 * the remaining digits are changed to zeros (i.e. The time is _not_ rounded).
1919 * If there are digits remaining following the writing of a time class, the
1920 * next time class will be written.
1922 * For example, given dwMS represents 138 hours,43 minutes and 15 seconds, the
1923 * following will result from the given values of iDigits:
1925 *| iDigits 1 2 3 4 5 ...
1926 *| lpszStr "100 hr" "130 hr" "138 hr" "138 hr 40 min" "138 hr 43 min" ...
1928 INT WINAPI StrFromTimeIntervalA(LPSTR lpszStr, UINT cchMax, DWORD dwMS,
1933 TRACE("(%p,%d,%ld,%d)\n", lpszStr, cchMax, dwMS, iDigits);
1935 if (lpszStr && cchMax)
1938 StrFromTimeIntervalW(szBuff, sizeof(szBuff)/sizeof(WCHAR), dwMS, iDigits);
1939 WideCharToMultiByte(CP_ACP,0,szBuff,-1,lpszStr,cchMax,0,0);
1945 /*************************************************************************
1946 * StrFromTimeIntervalW [SHLWAPI.@]
1948 * See StrFromTimeIntervalA.
1950 INT WINAPI StrFromTimeIntervalW(LPWSTR lpszStr, UINT cchMax, DWORD dwMS,
1953 static const WCHAR szHr[] = {' ','h','r','\0'};
1954 static const WCHAR szMin[] = {' ','m','i','n','\0'};
1955 static const WCHAR szSec[] = {' ','s','e','c','\0'};
1958 TRACE("(%p,%d,%ld,%d)\n", lpszStr, cchMax, dwMS, iDigits);
1960 if (lpszStr && cchMax)
1963 DWORD dwHours, dwMinutes;
1965 if (!iDigits || cchMax == 1)
1971 /* Calculate the time classes */
1972 dwMS = (dwMS + 500) / 1000;
1973 dwHours = dwMS / 3600;
1974 dwMS -= dwHours * 3600;
1975 dwMinutes = dwMS / 60;
1976 dwMS -= dwMinutes * 60;
1981 iDigits = SHLWAPI_WriteTimeClass(szCopy, dwHours, szHr, iDigits);
1983 if (dwMinutes && iDigits)
1984 iDigits = SHLWAPI_WriteTimeClass(szCopy, dwMinutes, szMin, iDigits);
1986 if (iDigits) /* Always write seconds if we have significant digits */
1987 SHLWAPI_WriteTimeClass(szCopy, dwMS, szSec, iDigits);
1989 strncpyW(lpszStr, szCopy, cchMax);
1990 iRet = strlenW(lpszStr);
1995 /*************************************************************************
1996 * StrIsIntlEqualA [SHLWAPI.@]
1998 * Compare two strings.
2001 * bCase [I] Whether to compare case sensitively
2002 * lpszStr [I] First string to compare
2003 * lpszComp [I] Second string to compare
2004 * iLen [I] Length to compare
2007 * TRUE If the strings are equal.
2010 BOOL WINAPI StrIsIntlEqualA(BOOL bCase, LPCSTR lpszStr, LPCSTR lpszComp,
2013 DWORD dwFlags = LOCALE_USE_CP_ACP;
2016 TRACE("(%d,%s,%s,%d)\n", bCase,
2017 debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
2019 /* FIXME: These flags are undocumented and unknown by our CompareString.
2020 * We need defines for them.
2022 dwFlags |= bCase ? 0x10000000 : 0x10000001;
2024 iRet = CompareStringA(GetThreadLocale(),
2025 dwFlags, lpszStr, iLen, lpszComp, iLen);
2028 iRet = CompareStringA(2048, dwFlags, lpszStr, iLen, lpszComp, iLen);
2030 return iRet == 2 ? TRUE : FALSE;
2033 /*************************************************************************
2034 * StrIsIntlEqualW [SHLWAPI.@]
2036 * See StrIsIntlEqualA.
2038 BOOL WINAPI StrIsIntlEqualW(BOOL bCase, LPCWSTR lpszStr, LPCWSTR lpszComp,
2044 TRACE("(%d,%s,%s,%d)\n", bCase,
2045 debugstr_w(lpszStr),debugstr_w(lpszComp), iLen);
2047 /* FIXME: These flags are undocumented and unknown by our CompareString.
2048 * We need defines for them.
2050 dwFlags = bCase ? 0x10000000 : 0x10000001;
2052 iRet = CompareStringW(GetThreadLocale(),
2053 dwFlags, lpszStr, iLen, lpszComp, iLen);
2056 iRet = CompareStringW(2048, dwFlags, lpszStr, iLen, lpszComp, iLen);
2058 return iRet == 2 ? TRUE : FALSE;
2061 /*************************************************************************
2064 * Copy a string to another string, up to a maximum number of characters.
2067 * lpszDest [O] Destination string
2068 * lpszSrc [I] Source string
2069 * iLen [I] Maximum number of chars to copy
2072 * Success: A pointer to the last character written.
2073 * Failure: lpszDest, if any arguments are invalid.
2075 LPSTR WINAPI SHLWAPI_399(LPSTR lpszDest, LPCSTR lpszSrc, int iLen)
2077 TRACE("(%p,%s,%i)\n", lpszDest, debugstr_a(lpszSrc), iLen);
2079 if (lpszDest && lpszSrc && iLen > 0)
2081 while ((iLen-- > 1) && *lpszSrc)
2082 *lpszDest++ = *lpszSrc++;
2089 /*************************************************************************
2092 * Unicode version of SHLWAPI_399.
2094 LPWSTR WINAPI SHLWAPI_400(LPWSTR lpszDest, LPCWSTR lpszSrc, int iLen)
2096 TRACE("(%p,%s,%i)\n", lpszDest, debugstr_w(lpszSrc), iLen);
2098 if (lpszDest && lpszSrc && iLen > 0)
2100 while ((iLen-- > 1) && *lpszSrc)
2101 *lpszDest++ = *lpszSrc++;
2108 /*************************************************************************
2109 * StrCmpLogicalW [SHLWAPI.@]
2111 * Compare two strings, ignoring case and comparing digits as numbers.
2114 * lpszStr [I] First string to compare
2115 * lpszComp [I] Second string to compare
2116 * iLen [I] Length to compare
2119 * TRUE If the strings are equal.
2122 INT WINAPI StrCmpLogicalW(LPCWSTR lpszStr, LPCWSTR lpszComp)
2126 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszComp));
2128 if (lpszStr && lpszComp)
2134 else if (isdigitW(*lpszStr))
2138 if (!isdigitW(*lpszComp))
2141 /* Compare the numbers */
2142 StrToIntExW(lpszStr, 0, &iStr);
2143 StrToIntExW(lpszComp, 0, &iComp);
2147 else if (iStr > iComp)
2151 while (isdigitW(*lpszStr))
2153 while (isdigitW(*lpszComp))
2156 else if (isdigitW(*lpszComp))
2160 iDiff = SHLWAPI_ChrCmpHelperA(*lpszStr,*lpszComp,NORM_IGNORECASE);
2176 /* Structure for formatting byte strings */
2177 typedef struct tagSHLWAPI_BYTEFORMATS
2184 } SHLWAPI_BYTEFORMATS;
2186 /*************************************************************************
2187 * StrFormatByteSize64A [SHLWAPI.@]
2189 * Create a string containing an abbreviated byte count of up to 2^63-1.
2192 * llBytes [I] Byte size to format
2193 * lpszDest [I] Destination for formatted string
2194 * cchMax [I] Size of lpszDest
2200 * There is no StrFormatByteSize64W function, it is called StrFormatByteSizeW().
2202 LPSTR WINAPI StrFormatByteSize64A(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax)
2204 static const char szBytes[] = "%ld bytes";
2205 static const char sz3_0[] = "%3.0f";
2206 static const char sz3_1[] = "%3.1f";
2207 static const char sz3_2[] = "%3.2f";
2209 #define KB ((ULONGLONG)1024)
2211 #define GB (KB*KB*KB)
2212 #define TB (KB*KB*KB*KB)
2213 #define PB (KB*KB*KB*KB*KB)
2215 static const SHLWAPI_BYTEFORMATS bfFormats[] =
2217 { 10*KB, 10.24, 100.0, sz3_2, 'K' }, /* 10 KB */
2218 { 100*KB, 102.4, 10.0, sz3_1, 'K' }, /* 100 KB */
2219 { 1000*KB, 1024.0, 1.0, sz3_0, 'K' }, /* 1000 KB */
2220 { 10*MB, 10485.76, 100.0, sz3_2, 'M' }, /* 10 MB */
2221 { 100*MB, 104857.6, 10.0, sz3_1, 'M' }, /* 100 MB */
2222 { 1000*MB, 1048576.0, 1.0, sz3_0, 'M' }, /* 1000 MB */
2223 { 10*GB, 10737418.24, 100.0, sz3_2, 'G' }, /* 10 GB */
2224 { 100*GB, 107374182.4, 10.0, sz3_1, 'G' }, /* 100 GB */
2225 { 1000*GB, 1073741824.0, 1.0, sz3_0, 'G' }, /* 1000 GB */
2226 { 10*TB, 10485.76, 100.0, sz3_2, 'T' }, /* 10 TB */
2227 { 100*TB, 104857.6, 10.0, sz3_1, 'T' }, /* 100 TB */
2228 { 1000*TB, 1048576.0, 1.0, sz3_0, 'T' }, /* 1000 TB */
2229 { 10*PB, 10737418.24, 100.00, sz3_2, 'P' }, /* 10 PB */
2230 { 100*PB, 107374182.4, 10.00, sz3_1, 'P' }, /* 100 PB */
2231 { 1000*PB, 1073741824.0, 1.00, sz3_0, 'P' }, /* 1000 PB */
2232 { 0, 10995116277.76, 100.00, sz3_2, 'E' } /* EB's, catch all */
2239 TRACE("(%lld,%p,%d)\n", llBytes, lpszDest, cchMax);
2241 if (!lpszDest || !cchMax)
2244 if (llBytes < 1024) /* 1K */
2246 snprintf (lpszDest, cchMax, szBytes, (long)llBytes);
2250 /* Note that if this loop completes without finding a match, i will be
2251 * pointing at the last entry, which is a catch all for > 1000 PB
2253 while (i < sizeof(bfFormats) / sizeof(SHLWAPI_BYTEFORMATS) - 1)
2255 if (llBytes < bfFormats[i].dLimit)
2259 /* Above 1 TB we encounter problems with FP accuracy. So for amounts above
2260 * this number we integer shift down by 1 MB first. The table above has
2261 * the divisors scaled down from the '< 10 TB' entry onwards, to account
2262 * for this. We also add a small fudge factor to get the correct result for
2263 * counts that lie exactly on a 1024 byte boundary.
2266 dBytes = (double)(llBytes >> 20) + 0.001; /* Scale down by I MB */
2268 dBytes = (double)llBytes + 0.00001;
2270 dBytes = floor(dBytes / bfFormats[i].dDivisor) / bfFormats[i].dNormaliser;
2272 sprintf(szBuff, bfFormats[i].lpszFormat, dBytes);
2274 szAdd[1] = bfFormats[i].wPrefix;
2277 strcat(szBuff, szAdd);
2278 strncpy(lpszDest, szBuff, cchMax);
2282 /*************************************************************************
2283 * StrFormatByteSizeW [SHLWAPI.@]
2285 * See StrFormatByteSize64A.
2287 LPWSTR WINAPI StrFormatByteSizeW(LONGLONG llBytes, LPWSTR lpszDest,
2292 StrFormatByteSize64A(llBytes, szBuff, sizeof(szBuff));
2295 MultiByteToWideChar(CP_ACP, 0, szBuff, -1, lpszDest, cchMax);
2299 /*************************************************************************
2300 * StrFormatByteSizeA [SHLWAPI.@]
2302 * Create a string containing an abbreviated byte count of up to 2^31-1.
2305 * dwBytes [I] Byte size to format
2306 * lpszDest [I] Destination for formatted string
2307 * cchMax [I] Size of lpszDest
2313 * The Ascii and Unicode versions of this function accept a different
2314 * integer type for dwBytes. See StrFormatByteSize64A().
2316 LPSTR WINAPI StrFormatByteSizeA(DWORD dwBytes, LPSTR lpszDest, UINT cchMax)
2318 TRACE("(%ld,%p,%d)\n", dwBytes, lpszDest, cchMax);
2320 return StrFormatByteSize64A(dwBytes, lpszDest, cchMax);
2323 /*************************************************************************
2324 * SHLWAPI_203 [SHLWAPI.203]
2326 * Remove a single non-trailing ampersand ('&') from a string.
2329 * lpszStr [I/O] String to remove ampersand from.
2332 * The character after the first ampersand in lpszStr, or the first character
2333 * in lpszStr if there is no ampersand in the string.
2335 char WINAPI SHLWAPI_203(LPCSTR lpszStr)
2337 LPSTR lpszIter, lpszTmp;
2340 TRACE("(%s)\n", debugstr_a(lpszStr));
2344 if ((lpszIter = StrChrA(lpszStr, '&')))
2346 lpszTmp = CharNextA(lpszIter);
2347 if (lpszTmp && *lpszTmp)
2349 if (*lpszTmp != '&')
2352 while (lpszIter && *lpszIter)
2354 lpszTmp = CharNextA(lpszIter);
2355 *lpszIter = *lpszTmp;