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"
31 #define NONAMELESSUNION
32 #define NONAMELESSSTRUCT
35 #define NO_SHLWAPI_REG
36 #define NO_SHLWAPI_STREAM
41 #include "wine/unicode.h"
42 #include "wine/debug.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(shell);
46 static HRESULT WINAPI _SHStrDupAA(LPCSTR,LPSTR*);
47 static HRESULT WINAPI _SHStrDupAW(LPCWSTR,LPSTR*);
49 /*************************************************************************
50 * SHLWAPI_ChrCmpHelperA
52 * Internal helper for SHLWAPI_ChrCmpA/ChrCMPIA.
55 * Both this function and its Unicode counterpart are very inneficient. To
56 * fix this, CompareString must be completely implemented and optimised
57 * first. Then the core character test can be taken out of that function and
58 * placed here, so that it need never be called at all. Until then, do not
59 * attempt to optimise this code unless you are willing to test that it
60 * still performs correctly.
62 static BOOL WINAPI SHLWAPI_ChrCmpHelperA(WORD ch1, WORD ch2, DWORD dwFlags)
64 char str1[3], str2[3];
66 str1[0] = LOBYTE(ch1);
67 if (IsDBCSLeadByte(ch1))
69 str1[1] = HIBYTE(ch1);
75 str2[0] = LOBYTE(ch2);
76 if (IsDBCSLeadByte(ch2))
78 str2[1] = HIBYTE(ch2);
84 return CompareStringA(GetThreadLocale(), dwFlags, str1, -1, str2, -1) - 2;
87 /*************************************************************************
88 * SHLWAPI_ChrCmpHelperW
90 * Internal helper for SHLWAPI_ChrCmpW/ChrCmpIW.
92 static BOOL WINAPI SHLWAPI_ChrCmpHelperW(WCHAR ch1, WCHAR ch2, DWORD dwFlags)
94 WCHAR str1[2], str2[2];
100 return CompareStringW(GetThreadLocale(), dwFlags, str1, 2, str2, 2) - 2;
103 /*************************************************************************
106 * Internal helper function.
108 static BOOL WINAPI SHLWAPI_ChrCmpA(WORD ch1, WORD ch2)
110 return SHLWAPI_ChrCmpHelperA(ch1, ch2, 0);
113 /*************************************************************************
114 * ChrCmpIA (SHLWAPI.385)
116 * Compare two characters, ignoring case.
119 * ch1 [I] First character to compare
120 * ch2 [I] Second character to compare
123 * FALSE, if the characters are equal.
124 * Non-zero otherwise.
126 BOOL WINAPI ChrCmpIA(WORD ch1, WORD ch2)
128 TRACE("(%d,%d)\n", ch1, ch2);
130 return SHLWAPI_ChrCmpHelperA(ch1, ch2, NORM_IGNORECASE);
133 /*************************************************************************
136 * Internal helper function.
138 static BOOL WINAPI SHLWAPI_ChrCmpW(WCHAR ch1, WCHAR ch2)
140 return SHLWAPI_ChrCmpHelperW(ch1, ch2, 0);
143 /*************************************************************************
144 * ChrCmpIW [SHLWAPI.386]
148 BOOL WINAPI ChrCmpIW(WCHAR ch1, WCHAR ch2)
150 return SHLWAPI_ChrCmpHelperW(ch1, ch2, NORM_IGNORECASE);
153 /*************************************************************************
154 * StrChrA [SHLWAPI.@]
156 * Find a given character in a string.
159 * lpszStr [I] String to search in.
160 * ch [I] Character to search for.
163 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
165 * Failure: NULL, if any arguments are invalid.
167 LPSTR WINAPI StrChrA(LPCSTR lpszStr, WORD ch)
169 TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch);
175 if (!SHLWAPI_ChrCmpA(*lpszStr, ch))
176 return (LPSTR)lpszStr;
177 lpszStr = CharNextA(lpszStr);
183 /*************************************************************************
184 * StrChrW [SHLWAPI.@]
188 LPWSTR WINAPI StrChrW(LPCWSTR lpszStr, WCHAR ch)
190 LPWSTR lpszRet = NULL;
192 TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch);
195 lpszRet = strchrW(lpszStr, ch);
199 /*************************************************************************
200 * StrChrIA [SHLWAPI.@]
202 * Find a given character in a string, ignoring case.
205 * lpszStr [I] String to search in.
206 * ch [I] Character to search for.
209 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
211 * Failure: NULL, if any arguments are invalid.
213 LPSTR WINAPI StrChrIA(LPCSTR lpszStr, WORD ch)
215 TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch);
221 if (!ChrCmpIA(*lpszStr, ch))
222 return (LPSTR)lpszStr;
223 lpszStr = CharNextA(lpszStr);
229 /*************************************************************************
230 * StrChrIW [SHLWAPI.@]
234 LPWSTR WINAPI StrChrIW(LPCWSTR lpszStr, WCHAR ch)
236 TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch);
243 if (toupperW(*lpszStr) == ch)
244 return (LPWSTR)lpszStr;
245 lpszStr = CharNextW(lpszStr);
249 return (LPWSTR)lpszStr;
252 /*************************************************************************
253 * StrCmpIW [SHLWAPI.@]
255 * Compare two strings, ignoring case.
258 * lpszStr [I] First string to compare
259 * lpszComp [I] Second string to compare
262 * An integer less than, equal to or greater than 0, indicating that
263 * lpszStr is less than, the same, or greater than lpszComp.
265 int WINAPI StrCmpIW(LPCWSTR lpszStr, LPCWSTR lpszComp)
269 TRACE("(%s,%s)\n", debugstr_w(lpszStr),debugstr_w(lpszComp));
271 iRet = strcmpiW(lpszStr, lpszComp);
272 return iRet < 0 ? -1 : iRet ? 1 : 0;
275 /*************************************************************************
276 * SHLWAPI_StrCmpNHelperA
278 * Internal helper for StrCmpNA/StrCmpNIA.
280 static INT WINAPI SHLWAPI_StrCmpNHelperA(LPCSTR lpszStr, LPCSTR lpszComp,
282 BOOL (WINAPI *pChrCmpFn)(WORD,WORD))
298 ch1 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr;
299 ch2 = IsDBCSLeadByte(*lpszComp)? *lpszComp << 8 | lpszComp[1] : *lpszComp;
301 if ((iDiff = pChrCmpFn(ch1, ch2)) < 0)
305 else if (!*lpszStr && !*lpszComp)
308 lpszStr = CharNextA(lpszStr);
309 lpszComp = CharNextA(lpszComp);
314 /*************************************************************************
315 * StrCmpNA [SHLWAPI.@]
317 * Compare two strings, up to a maximum length.
320 * lpszStr [I] First string to compare
321 * lpszComp [I] Second string to compare
322 * iLen [I] Maximum number of chars to compare.
325 * An integer less than, equal to or greater than 0, indicating that
326 * lpszStr is less than, the same, or greater than lpszComp.
328 INT WINAPI StrCmpNA(LPCSTR lpszStr, LPCSTR lpszComp, INT iLen)
330 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
332 return SHLWAPI_StrCmpNHelperA(lpszStr, lpszComp, iLen, SHLWAPI_ChrCmpA);
335 /*************************************************************************
336 * StrCmpNW [SHLWAPI.@]
340 INT WINAPI StrCmpNW(LPCWSTR lpszStr, LPCWSTR lpszComp, INT iLen)
344 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen);
346 iRet = strncmpW(lpszStr, lpszComp, iLen);
347 return iRet < 0 ? -1 : iRet ? 1 : 0;
350 /*************************************************************************
351 * StrCmpNIA [SHLWAPI.@]
353 * Compare two strings, up to a maximum length, ignoring case.
356 * lpszStr [I] First string to compare
357 * lpszComp [I] Second string to compare
358 * iLen [I] Maximum number of chars to compare.
361 * An integer less than, equal to or greater than 0, indicating that
362 * lpszStr is less than, the same, or greater than lpszComp.
365 * The Win32 version of this function is _completely_ broken for cases
366 * where iLen is greater than the length of lpszComp. Examples:
368 *| StrCmpNIA("foo.gif", "foo", 5) is -1 under Win32; Should return 1.
369 *| StrCmpNIA("\", "\\", 3) is 0 under Win32; Should return -1.
370 *| StrCmpNIA("\", "\..\foo\", 3) is 1 under Win32; Should return -1.
372 * This implementation behaves correctly, since it is unlikely any
373 * applications actually rely on this function being broken.
375 int WINAPI StrCmpNIA(LPCSTR lpszStr, LPCSTR lpszComp, int iLen)
377 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
379 return SHLWAPI_StrCmpNHelperA(lpszStr, lpszComp, iLen, ChrCmpIA);
382 /*************************************************************************
383 * StrCmpNIW [SHLWAPI.@]
387 INT WINAPI StrCmpNIW(LPCWSTR lpszStr, LPCWSTR lpszComp, int iLen)
391 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen);
393 iRet = strncmpiW(lpszStr, lpszComp, iLen);
394 return iRet < 0 ? -1 : iRet ? 1 : 0;
397 /*************************************************************************
398 * StrCmpW [SHLWAPI.@]
400 * Compare two strings.
403 * lpszStr [I] First string to compare
404 * lpszComp [I] Second string to compare
407 * An integer less than, equal to or greater than 0, indicating that
408 * lpszStr is less than, the same, or greater than lpszComp.
410 int WINAPI StrCmpW(LPCWSTR lpszStr, LPCWSTR lpszComp)
414 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszComp));
416 iRet = strcmpW(lpszStr, lpszComp);
417 return iRet < 0 ? -1 : iRet ? 1 : 0;
420 /*************************************************************************
421 * StrCatW [SHLWAPI.@]
423 * Concatanate two strings.
426 * lpszStr [O] Initial string
427 * lpszSrc [I] String to concatanate
432 LPWSTR WINAPI StrCatW(LPWSTR lpszStr, LPCWSTR lpszSrc)
434 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSrc));
436 strcatW(lpszStr, lpszSrc);
440 /*************************************************************************
441 * StrCpyW [SHLWAPI.@]
443 * Copy a string to another string.
446 * lpszStr [O] Destination string
447 * lpszSrc [I] Source string
452 LPWSTR WINAPI StrCpyW(LPWSTR lpszStr, LPCWSTR lpszSrc)
454 TRACE("(%p,%s)\n", lpszStr, debugstr_w(lpszSrc));
456 strcpyW(lpszStr, lpszSrc);
460 /*************************************************************************
461 * StrCpyNW [SHLWAPI.@]
463 * Copy a string to another string, up to a maximum number of characters.
466 * lpszStr [O] Destination string
467 * lpszSrc [I] Source string
468 * iLen [I] Maximum number of chars to copy
473 LPWSTR WINAPI StrCpyNW(LPWSTR lpszStr, LPCWSTR lpszSrc, int iLen)
475 TRACE("(%p,%s,%i)\n", lpszStr, debugstr_w(lpszSrc), iLen);
477 lstrcpynW(lpszStr, lpszSrc, iLen);
483 /*************************************************************************
484 * SHLWAPI_StrStrHelperA
486 * Internal implementation of StrStrA/StrStrIA
488 static LPSTR WINAPI SHLWAPI_StrStrHelperA(LPCSTR lpszStr, LPCSTR lpszSearch,
489 int (*pStrCmpFn)(LPCSTR,LPCSTR,size_t))
493 if (!lpszStr || !lpszSearch || !*lpszSearch)
496 iLen = strlen(lpszSearch);
500 if (!pStrCmpFn(lpszStr, lpszSearch, iLen))
501 return (LPSTR)lpszStr;
502 lpszStr = CharNextA(lpszStr);
507 /*************************************************************************
508 * SHLWAPI_StrStrHelperW
510 * Internal implementation of StrStrW/StrStrIW
512 static LPWSTR WINAPI SHLWAPI_StrStrHelperW(LPCWSTR lpszStr, LPCWSTR lpszSearch,
513 int (*pStrCmpFn)(LPCWSTR,LPCWSTR,int))
517 if (!lpszStr || !lpszSearch || !*lpszSearch)
520 iLen = strlenW(lpszSearch);
524 if (!pStrCmpFn(lpszStr, lpszSearch, iLen))
525 return (LPWSTR)lpszStr;
526 lpszStr = CharNextW(lpszStr);
531 /*************************************************************************
532 * StrStrA [SHLWAPI.@]
534 * Find a substring within a string.
537 * lpszStr [I] String to search in
538 * lpszSearch [I] String to look for
541 * The start of lpszSearch within lpszStr, or NULL if not found.
543 LPSTR WINAPI StrStrA(LPCSTR lpszStr, LPCSTR lpszSearch)
545 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
547 return SHLWAPI_StrStrHelperA(lpszStr, lpszSearch, strncmp);
550 /*************************************************************************
551 * StrStrW [SHLWAPI.@]
555 LPWSTR WINAPI StrStrW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
557 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
559 return SHLWAPI_StrStrHelperW(lpszStr, lpszSearch, strncmpW);
562 /*************************************************************************
563 * StrRStrIA [SHLWAPI.@]
565 * Find the last occurence of a substring within a string.
568 * lpszStr [I] String to search in
569 * lpszEnd [I] End of lpszStr
570 * lpszSearch [I] String to look for
573 * The last occurence lpszSearch within lpszStr, or NULL if not found.
575 LPSTR WINAPI StrRStrIA(LPCSTR lpszStr, LPCSTR lpszEnd, LPCSTR lpszSearch)
577 LPSTR lpszRet = NULL;
581 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
583 if (!lpszStr || !lpszSearch || !*lpszSearch)
587 lpszEnd = lpszStr + lstrlenA(lpszStr);
589 if (IsDBCSLeadByte(*lpszSearch))
590 ch1 = *lpszSearch << 8 | lpszSearch[1];
593 iLen = lstrlenA(lpszSearch);
595 while (lpszStr <= lpszEnd && *lpszStr)
597 ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr;
598 if (!ChrCmpIA(ch1, ch2))
600 if (!StrCmpNIA(lpszStr, lpszSearch, iLen))
601 lpszRet = (LPSTR)lpszStr;
603 lpszStr = CharNextA(lpszStr);
608 /*************************************************************************
609 * StrRStrIW [SHLWAPI.@]
613 LPWSTR WINAPI StrRStrIW(LPCWSTR lpszStr, LPCWSTR lpszEnd, LPCWSTR lpszSearch)
615 LPWSTR lpszRet = NULL;
618 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
620 if (!lpszStr || !lpszSearch || !*lpszSearch)
624 lpszEnd = lpszStr + strlenW(lpszStr);
626 iLen = strlenW(lpszSearch);
628 while (lpszStr <= lpszEnd && *lpszStr)
630 if (!ChrCmpIA(*lpszSearch, *lpszStr))
632 if (!StrCmpNIW(lpszStr, lpszSearch, iLen))
633 lpszRet = (LPWSTR)lpszStr;
635 lpszStr = CharNextW(lpszStr);
640 /*************************************************************************
641 * StrStrIA [SHLWAPI.@]
643 * Find a substring within a string, ignoring case.
646 * lpszStr [I] String to search in
647 * lpszSearch [I] String to look for
650 * The start of lpszSearch within lpszStr, or NULL if not found.
652 LPSTR WINAPI StrStrIA(LPCSTR lpszStr, LPCSTR lpszSearch)
654 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
656 return SHLWAPI_StrStrHelperA(lpszStr, lpszSearch, strncasecmp);
659 /*************************************************************************
660 * StrStrIW [SHLWAPI.@]
664 LPWSTR WINAPI StrStrIW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
666 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
668 return SHLWAPI_StrStrHelperW(lpszStr, lpszSearch, strncmpiW);
671 /*************************************************************************
672 * StrToIntA [SHLWAPI.@]
674 * Read an integer from a string.
677 * lpszStr [I] String to read integer from
680 * The integer value represented by the string, or 0 if no integer is
684 * No leading space is allowed before the number, although a leading '-' is.
686 int WINAPI StrToIntA(LPCSTR lpszStr)
690 TRACE("(%s)\n", debugstr_a(lpszStr));
694 WARN("Invalid lpszStr would crash under Win32!\n");
698 if (*lpszStr == '-' || isdigit(*lpszStr))
699 StrToIntExA(lpszStr, 0, &iRet);
703 /*************************************************************************
704 * StrToIntW [SHLWAPI.@]
708 int WINAPI StrToIntW(LPCWSTR lpszStr)
712 TRACE("(%s)\n", debugstr_w(lpszStr));
716 WARN("Invalid lpszStr would crash under Win32!\n");
720 if (*lpszStr == '-' || isdigitW(*lpszStr))
721 StrToIntExW(lpszStr, 0, &iRet);
725 /*************************************************************************
726 * StrToIntExA [SHLWAPI.@]
728 * Read an integer from a string.
731 * lpszStr [I] String to read integer from
732 * dwFlags [I] Flags controlling the conversion
733 * lpiRet [O] Destination for read integer.
736 * Success: TRUE. lpiRet contains the integer value represented by the string.
737 * Failure: FALSE, if the string is invalid, or no number is present.
740 * Leading whitespace, '-' and '+' are allowed before the number. If
741 * dwFlags includes STIF_SUPPORT_HEX, hexidecimal numbers are allowed, if
742 * preceeded by '0x'. If this flag is not set, or there is no '0x' prefix,
743 * the string is treated as a decimal string. A leading '-' is ignored for
744 * hexidecimal numbers.
746 BOOL WINAPI StrToIntExA(LPCSTR lpszStr, DWORD dwFlags, LPINT lpiRet)
748 BOOL bNegative = FALSE;
751 TRACE("(%s,%08lX,%p)\n", debugstr_a(lpszStr), dwFlags, lpiRet);
753 if (!lpszStr || !lpiRet)
755 WARN("Invalid parameter would crash under Win32!\n");
758 if (dwFlags > STIF_SUPPORT_HEX)
760 WARN("Unknown flags (%08lX)!\n", dwFlags & ~STIF_SUPPORT_HEX);
763 /* Skip leading space, '+', '-' */
764 while (isspace(*lpszStr))
765 lpszStr = CharNextA(lpszStr);
772 else if (*lpszStr == '+')
775 if (dwFlags & STIF_SUPPORT_HEX &&
776 *lpszStr == '0' && tolower(lpszStr[1]) == 'x')
778 /* Read hex number */
781 if (!isxdigit(*lpszStr))
784 while (isxdigit(*lpszStr))
787 if (isdigit(*lpszStr))
788 iRet += (*lpszStr - '0');
790 iRet += 10 + (tolower(*lpszStr) - 'a');
797 /* Read decimal number */
798 if (!isdigit(*lpszStr))
801 while (isdigit(*lpszStr))
804 iRet += (*lpszStr - '0');
807 *lpiRet = bNegative ? -iRet : iRet;
811 /*************************************************************************
812 * StrToIntExW [SHLWAPI.@]
816 BOOL WINAPI StrToIntExW(LPCWSTR lpszStr, DWORD dwFlags, LPINT lpiRet)
818 BOOL bNegative = FALSE;
821 TRACE("(%s,%08lX,%p)\n", debugstr_w(lpszStr), dwFlags, lpiRet);
823 if (!lpszStr || !lpiRet)
825 WARN("Invalid parameter would crash under Win32!\n");
828 if (dwFlags > STIF_SUPPORT_HEX)
830 WARN("Unknown flags (%08lX)!\n", dwFlags & ~STIF_SUPPORT_HEX);
833 /* Skip leading space, '+', '-' */
834 while (isspaceW(*lpszStr))
835 lpszStr = CharNextW(lpszStr);
842 else if (*lpszStr == '+')
845 if (dwFlags & STIF_SUPPORT_HEX &&
846 *lpszStr == '0' && tolowerW(lpszStr[1]) == 'x')
848 /* Read hex number */
851 if (!isxdigitW(*lpszStr))
854 while (isxdigitW(*lpszStr))
857 if (isdigitW(*lpszStr))
858 iRet += (*lpszStr - '0');
860 iRet += 10 + (tolowerW(*lpszStr) - 'a');
867 /* Read decimal number */
868 if (!isdigitW(*lpszStr))
871 while (isdigitW(*lpszStr))
874 iRet += (*lpszStr - '0');
877 *lpiRet = bNegative ? -iRet : iRet;
881 /*************************************************************************
882 * StrDupA [SHLWAPI.@]
884 * Duplicate a string.
887 * lpszStr [I] String to duplicate.
890 * Success: A pointer to a new string containing the contents of lpszStr
891 * Failure: NULL, if memory cannot be allocated
894 * The string memory is allocated with LocalAlloc(), and so should be released
895 * by calling LocalFree().
897 LPSTR WINAPI StrDupA(LPCSTR lpszStr)
902 TRACE("(%s)\n",debugstr_a(lpszStr));
904 iLen = lpszStr ? strlen(lpszStr) + 1 : 1;
905 lpszRet = (LPSTR)LocalAlloc(LMEM_FIXED, iLen);
910 memcpy(lpszRet, lpszStr, iLen);
917 /*************************************************************************
918 * StrDupW [SHLWAPI.@]
922 LPWSTR WINAPI StrDupW(LPCWSTR lpszStr)
927 TRACE("(%s)\n",debugstr_w(lpszStr));
929 iLen = (lpszStr ? strlenW(lpszStr) + 1 : 1) * sizeof(WCHAR);
930 lpszRet = (LPWSTR)LocalAlloc(LMEM_FIXED, iLen);
935 memcpy(lpszRet, lpszStr, iLen);
942 /*************************************************************************
943 * SHLWAPI_StrSpnHelperA
945 * Internal implementation of StrSpnA/StrCSpnA/StrCSpnIA
947 static int WINAPI SHLWAPI_StrSpnHelperA(LPCSTR lpszStr, LPCSTR lpszMatch,
948 LPSTR (WINAPI *pStrChrFn)(LPCSTR,WORD),
951 LPCSTR lpszRead = lpszStr;
952 if (lpszStr && *lpszStr && lpszMatch)
956 LPCSTR lpszTest = pStrChrFn(lpszMatch, *lpszRead);
958 if (!bInvert && !lpszTest)
960 if (bInvert && lpszTest)
962 lpszRead = CharNextA(lpszRead);
965 return lpszRead - lpszStr;
968 /*************************************************************************
969 * SHLWAPI_StrSpnHelperW
971 * Internal implementation of StrSpnW/StrCSpnW/StrCSpnIW
973 static int WINAPI SHLWAPI_StrSpnHelperW(LPCWSTR lpszStr, LPCWSTR lpszMatch,
974 LPWSTR (WINAPI *pStrChrFn)(LPCWSTR,WCHAR),
977 LPCWSTR lpszRead = lpszStr;
978 if (lpszStr && *lpszStr && lpszMatch)
982 LPCWSTR lpszTest = pStrChrFn(lpszMatch, *lpszRead);
984 if (!bInvert && !lpszTest)
986 if (bInvert && lpszTest)
988 lpszRead = CharNextW(lpszRead);
991 return lpszRead - lpszStr;
994 /*************************************************************************
995 * StrSpnA [SHLWAPI.@]
997 * Find the length of the start of a string that contains only certain
1001 * lpszStr [I] String to search
1002 * lpszMatch [I] Characters that can be in the substring
1005 * The length of the part of lpszStr containing only chars from lpszMatch,
1006 * or 0 if any parameter is invalid.
1008 int WINAPI StrSpnA(LPCSTR lpszStr, LPCSTR lpszMatch)
1010 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1012 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, FALSE);
1015 /*************************************************************************
1016 * StrSpnW [SHLWAPI.@]
1020 int WINAPI StrSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1022 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1024 return SHLWAPI_StrSpnHelperW(lpszStr, lpszMatch, StrChrW, FALSE);
1027 /*************************************************************************
1028 * StrCSpnA [SHLWAPI.@]
1030 * Find the length of the start of a string that does not contain certain
1034 * lpszStr [I] String to search
1035 * lpszMatch [I] Characters that cannot be in the substring
1038 * The length of the part of lpszStr containing only chars not in lpszMatch,
1039 * or 0 if any parameter is invalid.
1041 int WINAPI StrCSpnA(LPCSTR lpszStr, LPCSTR lpszMatch)
1043 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1045 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, TRUE);
1048 /*************************************************************************
1049 * StrCSpnW [SHLWAPI.@]
1053 int WINAPI StrCSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1055 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1057 return SHLWAPI_StrSpnHelperW(lpszStr, lpszMatch, StrChrW, TRUE);
1060 /*************************************************************************
1061 * StrCSpnIA [SHLWAPI.@]
1063 * Find the length of the start of a string that does not contain certain
1064 * characters, ignoring case.
1067 * lpszStr [I] String to search
1068 * lpszMatch [I] Characters that cannot be in the substring
1071 * The length of the part of lpszStr containing only chars not in lpszMatch,
1072 * or 0 if any parameter is invalid.
1074 int WINAPI StrCSpnIA(LPCSTR lpszStr, LPCSTR lpszMatch)
1076 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1078 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrIA, TRUE);
1081 /*************************************************************************
1082 * StrCSpnIW [SHLWAPI.@]
1086 int WINAPI StrCSpnIW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1088 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1090 return SHLWAPI_StrSpnHelperW(lpszStr, lpszMatch, StrChrIW, TRUE);
1093 /*************************************************************************
1094 * StrPBrkA [SHLWAPI.@]
1096 * Search a string for any of a group of characters.
1099 * lpszStr [I] String to search
1100 * lpszMatch [I] Characters to match
1103 * A pointer to the first matching character in lpszStr, or NULL if no
1106 LPSTR WINAPI StrPBrkA(LPCSTR lpszStr, LPCSTR lpszMatch)
1108 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1110 if (lpszStr && lpszMatch && *lpszMatch)
1114 if (StrChrA(lpszMatch, *lpszStr))
1115 return (LPSTR)lpszStr;
1116 lpszStr = CharNextA(lpszStr);
1122 /*************************************************************************
1123 * StrPBrkW [SHLWAPI.@]
1127 LPWSTR WINAPI StrPBrkW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1129 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1131 if (lpszStr && lpszMatch && *lpszMatch)
1135 if (StrChrW(lpszMatch, *lpszStr))
1136 return (LPWSTR)lpszStr;
1137 lpszStr = CharNextW(lpszStr);
1143 /*************************************************************************
1144 * SHLWAPI_StrRChrHelperA
1146 * Internal implementation of StrRChrA/StrRChrIA.
1148 static LPSTR WINAPI SHLWAPI_StrRChrHelperA(LPCSTR lpszStr,
1149 LPCSTR lpszEnd, WORD ch,
1150 BOOL (WINAPI *pChrCmpFn)(WORD,WORD))
1152 LPCSTR lpszRet = NULL;
1159 lpszEnd = lpszStr + lstrlenA(lpszStr);
1161 while (*lpszStr && lpszStr <= lpszEnd)
1163 ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr;
1165 if (!pChrCmpFn(ch, ch2))
1167 lpszStr = CharNextA(lpszStr);
1170 return (LPSTR)lpszRet;
1173 /*************************************************************************
1174 * SHLWAPI_StrRChrHelperW
1176 * Internal implementation of StrRChrW/StrRChrIW.
1178 static LPWSTR WINAPI SHLWAPI_StrRChrHelperW(LPCWSTR lpszStr,
1179 LPCWSTR lpszEnd, WCHAR ch,
1180 BOOL (WINAPI *pChrCmpFn)(WCHAR,WCHAR))
1182 LPCWSTR lpszRet = NULL;
1187 lpszEnd = lpszStr + strlenW(lpszStr);
1189 while (*lpszStr && lpszStr <= lpszEnd)
1191 if (!pChrCmpFn(ch, *lpszStr))
1193 lpszStr = CharNextW(lpszStr);
1196 return (LPWSTR)lpszRet;
1199 /**************************************************************************
1200 * StrRChrA [SHLWAPI.@]
1202 * Find the last occurence of a character in string.
1205 * lpszStr [I] String to search in
1206 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1207 * ch [I] Character to search for.
1210 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1211 * or NULL if not found.
1212 * Failure: NULL, if any arguments are invalid.
1214 LPSTR WINAPI StrRChrA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch)
1216 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch);
1218 return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, SHLWAPI_ChrCmpA);
1221 /**************************************************************************
1222 * StrRChrW [SHLWAPI.@]
1226 LPWSTR WINAPI StrRChrW(LPCWSTR lpszStr, LPCWSTR lpszEnd, WORD ch)
1228 TRACE("(%s,%s,%x)\n", debugstr_w(lpszStr), debugstr_w(lpszEnd), ch);
1230 return SHLWAPI_StrRChrHelperW(lpszStr, lpszEnd, ch, SHLWAPI_ChrCmpW);
1233 /**************************************************************************
1234 * StrRChrIA [SHLWAPI.@]
1236 * Find the last occurence of a character in string, ignoring case.
1239 * lpszStr [I] String to search in
1240 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1241 * ch [I] Character to search for.
1244 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1245 * or NULL if not found.
1246 * Failure: NULL, if any arguments are invalid.
1248 LPSTR WINAPI StrRChrIA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch)
1250 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch);
1252 return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, ChrCmpIA);
1255 /**************************************************************************
1256 * StrRChrIW [SHLWAPI.@]
1260 LPWSTR WINAPI StrRChrIW(LPCWSTR lpszStr, LPCWSTR lpszEnd, WORD ch)
1262 TRACE("(%s,%s,%x)\n", debugstr_w(lpszStr), debugstr_w(lpszEnd), ch);
1264 return SHLWAPI_StrRChrHelperW(lpszStr, lpszEnd, ch, ChrCmpIW);
1267 /*************************************************************************
1268 * StrCatBuffA [SHLWAPI.@]
1270 * Concatenate two strings together.
1273 * lpszStr [O] String to concatenate to
1274 * lpszCat [I] String to add to lpszCat
1275 * cchMax [I] Maximum number of characters for the whole string
1281 * cchMax determines the number of characters in the final length of the
1282 * string, not the number appended to lpszStr from lpszCat.
1284 LPSTR WINAPI StrCatBuffA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax)
1288 TRACE("(%p,%s,%d)\n", lpszStr, debugstr_a(lpszCat), cchMax);
1292 WARN("Invalid lpszStr would crash under Win32!\n");
1296 iLen = strlen(lpszStr);
1300 StrCpyNA(lpszStr + iLen, lpszCat, cchMax);
1304 /*************************************************************************
1305 * StrCatBuffW [SHLWAPI.@]
1309 LPWSTR WINAPI StrCatBuffW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax)
1313 TRACE("(%p,%s,%d)\n", lpszStr, debugstr_w(lpszCat), cchMax);
1317 WARN("Invalid lpszStr would crash under Win32!\n");
1321 iLen = strlenW(lpszStr);
1325 StrCpyNW(lpszStr + iLen, lpszCat, cchMax);
1329 /*************************************************************************
1330 * StrRetToBufA [SHLWAPI.@]
1332 * Convert a STRRET to a normal string.
1335 * lpStrRet [O] STRRET to convert
1336 * pIdl [I] ITEMIDLIST for lpStrRet->uType = STRRET_OFFSETA
1337 * lpszDest [O] Destination for normal string
1338 * dwLen [I] Length of lpszDest
1341 * Success: S_OK. lpszDest contains up to dwLen characters of the string.
1342 * If lpStrRet is of type STRRET_WSTR, its memory is freed with
1343 * CoTaskMemFree() and its type set to STRRET_CSTRA.
1344 * Failure: E_FAIL, if any parameters are invalid.
1346 HRESULT WINAPI StrRetToBufA (LPSTRRET src, const ITEMIDLIST *pidl, LPSTR dest, DWORD len)
1349 * This routine is identical to that in dlls/shell32/shellstring.c.
1350 * It was duplicated because not every version of Shlwapi.dll exports
1351 * StrRetToBufA. If you change one routine, change them both.
1353 TRACE("dest=%p len=0x%lx strret=%p pidl=%p stub\n",dest,len,src,pidl);
1357 WARN("Invalid lpStrRet would crash under Win32!\n");
1371 WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, dest, len, NULL, NULL);
1372 CoTaskMemFree(src->u.pOleStr);
1376 lstrcpynA((LPSTR)dest, src->u.cStr, len);
1380 lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len);
1384 FIXME("unknown type!\n");
1390 /*************************************************************************
1391 * StrRetToBufW [SHLWAPI.@]
1395 HRESULT WINAPI StrRetToBufW (LPSTRRET src, const ITEMIDLIST *pidl, LPWSTR dest, DWORD len)
1397 TRACE("dest=%p len=0x%lx strret=%p pidl=%p stub\n",dest,len,src,pidl);
1401 WARN("Invalid lpStrRet would crash under Win32!\n");
1415 lstrcpynW((LPWSTR)dest, src->u.pOleStr, len);
1416 CoTaskMemFree(src->u.pOleStr);
1420 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
1427 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1,
1434 FIXME("unknown type!\n");
1440 /*************************************************************************
1441 * StrRetToStrA [SHLWAPI.@]
1443 * Converts a STRRET to a normal string.
1446 * lpStrRet [O] STRRET to convert
1447 * pidl [I] ITEMIDLIST for lpStrRet->uType = STRRET_OFFSETA
1448 * ppszName [O] Destination for converted string
1451 * Success: S_OK. ppszName contains the new string, allocated with CoTaskMemAlloc().
1452 * Failure: E_FAIL, if any parameters are invalid.
1454 HRESULT WINAPI StrRetToStrA(LPSTRRET lpStrRet, const ITEMIDLIST *pidl, LPSTR *ppszName)
1456 HRESULT hRet = E_FAIL;
1458 switch (lpStrRet->uType)
1461 hRet = _SHStrDupAW(lpStrRet->u.pOleStr, ppszName);
1462 CoTaskMemFree(lpStrRet->u.pOleStr);
1466 hRet = _SHStrDupAA(lpStrRet->u.cStr, ppszName);
1470 hRet = _SHStrDupAA(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, ppszName);
1480 /*************************************************************************
1481 * StrRetToStrW [SHLWAPI.@]
1485 HRESULT WINAPI StrRetToStrW(LPSTRRET lpStrRet, const ITEMIDLIST *pidl, LPWSTR *ppszName)
1487 HRESULT hRet = E_FAIL;
1489 switch (lpStrRet->uType)
1492 hRet = SHStrDupW(lpStrRet->u.pOleStr, ppszName);
1493 CoTaskMemFree(lpStrRet->u.pOleStr);
1497 hRet = SHStrDupA(lpStrRet->u.cStr, ppszName);
1501 hRet = SHStrDupA(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, ppszName);
1511 /*************************************************************************
1512 * StrFormatKBSizeA [SHLWAPI.@]
1514 * Create a formatted string containing a byte count in Kilobytes.
1517 * llBytes [I] Byte size to format
1518 * lpszDest [I] Destination for formatted string
1519 * cchMax [I] Size of lpszDest
1524 LPSTR WINAPI StrFormatKBSizeA(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax)
1526 char szBuff[256], *szOut = szBuff + sizeof(szBuff) - 1;
1527 LONGLONG ulKB = (llBytes + 1023) >> 10;
1529 TRACE("(%lld,%p,%d)\n", llBytes, lpszDest, cchMax);
1538 LONGLONG ulNextDigit = ulKB % 10;
1539 *szOut-- = '0' + ulNextDigit;
1540 ulKB = (ulKB - ulNextDigit) / 10;
1543 strncpy(lpszDest, szOut + 1, cchMax);
1547 /*************************************************************************
1548 * StrFormatKBSizeW [SHLWAPI.@]
1550 * See StrFormatKBSizeA.
1552 LPWSTR WINAPI StrFormatKBSizeW(LONGLONG llBytes, LPWSTR lpszDest, UINT cchMax)
1554 WCHAR szBuff[256], *szOut = szBuff + sizeof(szBuff)/sizeof(WCHAR) - 1;
1555 LONGLONG ulKB = (llBytes + 1023) >> 10;
1557 TRACE("(%lld,%p,%d)\n", llBytes, lpszDest, cchMax);
1566 LONGLONG ulNextDigit = ulKB % 10;
1567 *szOut-- = '0' + ulNextDigit;
1568 ulKB = (ulKB - ulNextDigit) / 10;
1571 strncpyW(lpszDest, szOut + 1, cchMax);
1575 /*************************************************************************
1576 * StrNCatA [SHLWAPI.@]
1578 * Concatenate two strings together.
1581 * lpszStr [O] String to concatenate to
1582 * lpszCat [I] String to add to lpszCat
1583 * cchMax [I] Maximum number of characters to concatenate
1589 * cchMax determines the number of characters that are appended to lpszStr,
1590 * not the total length of the string.
1592 LPSTR WINAPI StrNCatA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax)
1594 LPSTR lpszRet = lpszStr;
1596 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszCat), cchMax);
1600 WARN("Invalid lpszStr would crash under Win32!\n");
1604 StrCpyNA(lpszStr + strlen(lpszStr), lpszCat, cchMax);
1608 /*************************************************************************
1609 * StrNCatW [SHLWAPI.@]
1613 LPWSTR WINAPI StrNCatW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax)
1615 LPWSTR lpszRet = lpszStr;
1617 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszCat), cchMax);
1621 WARN("Invalid lpszStr would crash under Win32\n");
1625 StrCpyNW(lpszStr + strlenW(lpszStr), lpszCat, cchMax);
1629 /*************************************************************************
1630 * StrTrimA [SHLWAPI.@]
1632 * Remove characters from the start and end of a string.
1635 * lpszStr [O] String to remove characters from
1636 * lpszTrim [I] Characters to remove from lpszStr
1639 * TRUE If lpszStr was valid and modified
1642 BOOL WINAPI StrTrimA(LPSTR lpszStr, LPCSTR lpszTrim)
1645 LPSTR lpszRead = lpszStr;
1648 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszTrim));
1650 if (lpszRead && *lpszRead)
1652 while (*lpszRead && StrChrA(lpszTrim, *lpszRead))
1653 lpszRead = CharNextA(lpszRead); /* Skip leading matches */
1655 dwLen = strlen(lpszRead);
1657 if (lpszRead != lpszStr)
1659 memmove(lpszStr, lpszRead, dwLen + 1);
1664 lpszRead = lpszStr + dwLen;
1665 while (StrChrA(lpszTrim, lpszRead[-1]))
1666 lpszRead = CharPrevA(lpszStr, lpszRead); /* Skip trailing matches */
1668 if (lpszRead != lpszStr + dwLen)
1678 /*************************************************************************
1679 * StrTrimW [SHLWAPI.@]
1683 BOOL WINAPI StrTrimW(LPWSTR lpszStr, LPCWSTR lpszTrim)
1686 LPWSTR lpszRead = lpszStr;
1689 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszTrim));
1691 if (lpszRead && *lpszRead)
1693 while (*lpszRead && StrChrW(lpszTrim, *lpszRead))
1694 lpszRead = CharNextW(lpszRead); /* Skip leading matches */
1696 dwLen = strlenW(lpszRead);
1698 if (lpszRead != lpszStr)
1700 memmove(lpszStr, lpszRead, (dwLen + 1) * sizeof(WCHAR));
1705 lpszRead = lpszStr + dwLen;
1706 while (StrChrW(lpszTrim, lpszRead[-1]))
1707 lpszRead = CharPrevW(lpszStr, lpszRead); /* Skip trailing matches */
1709 if (lpszRead != lpszStr + dwLen)
1719 /*************************************************************************
1720 * _SHStrDupAA [INTERNAL]
1722 * Duplicates a ASCII string to ASCII. The destination buffer is allocated.
1724 static HRESULT WINAPI _SHStrDupAA(LPCSTR src, LPSTR * dest)
1730 len = lstrlenA(src) + 1;
1731 *dest = CoTaskMemAlloc(len);
1737 lstrcpynA(*dest,src, len);
1743 TRACE("%s->(%p)\n", debugstr_a(src), *dest);
1747 /*************************************************************************
1748 * SHStrDupA [SHLWAPI.@]
1750 * Return a Unicode copy of a string, in memory allocated by CoTaskMemAlloc().
1753 * lpszStr [I] String to copy
1754 * lppszDest [O] Destination for the new string copy
1757 * Success: S_OK. lppszDest contains the new string in Unicode format.
1758 * Failure: E_OUTOFMEMORY, If any arguments are invalid or memory allocation
1761 HRESULT WINAPI SHStrDupA(LPCSTR lpszStr, LPWSTR * lppszDest)
1768 len = MultiByteToWideChar(0, 0, lpszStr, -1, 0, 0) * sizeof(WCHAR);
1769 *lppszDest = CoTaskMemAlloc(len);
1776 MultiByteToWideChar(0, 0, lpszStr, -1, *lppszDest, len);
1780 hRet = E_OUTOFMEMORY;
1782 TRACE("%s->(%p)\n", debugstr_a(lpszStr), *lppszDest);
1786 /*************************************************************************
1787 * _SHStrDupAW [INTERNAL]
1789 * Duplicates a UNICODE to a ASCII string. The destination buffer is allocated.
1791 static HRESULT WINAPI _SHStrDupAW(LPCWSTR src, LPSTR * dest)
1797 len = WideCharToMultiByte(CP_ACP, 0, src, -1, NULL, 0, NULL, NULL);
1798 *dest = CoTaskMemAlloc(len);
1804 WideCharToMultiByte(CP_ACP, 0, src, -1, *dest, len, NULL, NULL);
1810 TRACE("%s->(%p)\n", debugstr_w(src), *dest);
1814 /*************************************************************************
1815 * SHStrDupW [SHLWAPI.@]
1819 HRESULT WINAPI SHStrDupW(LPCWSTR src, LPWSTR * dest)
1825 len = (lstrlenW(src) + 1) * sizeof(WCHAR);
1826 *dest = CoTaskMemAlloc(len);
1832 memcpy(*dest, src, len);
1838 TRACE("%s->(%p)\n", debugstr_w(src), *dest);
1842 /*************************************************************************
1843 * SHLWAPI_WriteReverseNum
1845 * Internal helper for SHLWAPI_WriteTimeClass.
1847 inline static LPWSTR SHLWAPI_WriteReverseNum(LPWSTR lpszOut, DWORD dwNum)
1851 /* Write a decimal number to a string, backwards */
1854 DWORD dwNextDigit = dwNum % 10;
1855 *lpszOut-- = '0' + dwNextDigit;
1856 dwNum = (dwNum - dwNextDigit) / 10;
1857 } while (dwNum > 0);
1862 /*************************************************************************
1863 * SHLWAPI_FormatSignificant
1865 * Internal helper for SHLWAPI_WriteTimeClass.
1867 inline static int SHLWAPI_FormatSignificant(LPWSTR lpszNum, int dwDigits)
1869 /* Zero non significant digits, return remaining significant digits */
1873 if (--dwDigits == 0)
1883 /*************************************************************************
1884 * SHLWAPI_WriteTimeClass
1886 * Internal helper for StrFromTimeIntervalW.
1888 static int WINAPI SHLWAPI_WriteTimeClass(LPWSTR lpszOut, DWORD dwValue,
1889 LPCWSTR lpszClass, int iDigits)
1891 WCHAR szBuff[64], *szOut = szBuff + 32;
1893 szOut = SHLWAPI_WriteReverseNum(szOut, dwValue);
1894 iDigits = SHLWAPI_FormatSignificant(szOut + 1, iDigits);
1896 strcpyW(szBuff + 32, lpszClass);
1897 strcatW(lpszOut, szOut);
1901 /*************************************************************************
1902 * StrFromTimeIntervalA [SHLWAPI.@]
1904 * Format a millisecond time interval into a string
1907 * lpszStr [O] Output buffer for formatted time interval
1908 * cchMax [I] Size of lpszStr
1909 * dwMS [I] Number of milliseconds
1910 * iDigits [I] Number of digits to print
1913 * The length of the formatted string, or 0 if any parameter is invalid.
1916 * This implementation mimics the Win32 behaviour of always writing a leading
1917 * space before the time interval begins.
1919 * iDigits is used to provide approximate times if accuracy is not important.
1920 * This number of digits will be written of the first non-zero time class
1921 * (hours/minutes/seconds). If this does not complete the time classification,
1922 * the remaining digits are changed to zeros (i.e. The time is _not_ rounded).
1923 * If there are digits remaining following the writing of a time class, the
1924 * next time class will be written.
1926 * For example, given dwMS represents 138 hours,43 minutes and 15 seconds, the
1927 * following will result from the given values of iDigits:
1929 *| iDigits 1 2 3 4 5 ...
1930 *| lpszStr "100 hr" "130 hr" "138 hr" "138 hr 40 min" "138 hr 43 min" ...
1932 INT WINAPI StrFromTimeIntervalA(LPSTR lpszStr, UINT cchMax, DWORD dwMS,
1937 TRACE("(%p,%d,%ld,%d)\n", lpszStr, cchMax, dwMS, iDigits);
1939 if (lpszStr && cchMax)
1942 StrFromTimeIntervalW(szBuff, sizeof(szBuff)/sizeof(WCHAR), dwMS, iDigits);
1943 WideCharToMultiByte(CP_ACP,0,szBuff,-1,lpszStr,cchMax,0,0);
1949 /*************************************************************************
1950 * StrFromTimeIntervalW [SHLWAPI.@]
1952 * See StrFromTimeIntervalA.
1954 INT WINAPI StrFromTimeIntervalW(LPWSTR lpszStr, UINT cchMax, DWORD dwMS,
1957 static const WCHAR szHr[] = {' ','h','r','\0'};
1958 static const WCHAR szMin[] = {' ','m','i','n','\0'};
1959 static const WCHAR szSec[] = {' ','s','e','c','\0'};
1962 TRACE("(%p,%d,%ld,%d)\n", lpszStr, cchMax, dwMS, iDigits);
1964 if (lpszStr && cchMax)
1967 DWORD dwHours, dwMinutes;
1969 if (!iDigits || cchMax == 1)
1975 /* Calculate the time classes */
1976 dwMS = (dwMS + 500) / 1000;
1977 dwHours = dwMS / 3600;
1978 dwMS -= dwHours * 3600;
1979 dwMinutes = dwMS / 60;
1980 dwMS -= dwMinutes * 60;
1985 iDigits = SHLWAPI_WriteTimeClass(szCopy, dwHours, szHr, iDigits);
1987 if (dwMinutes && iDigits)
1988 iDigits = SHLWAPI_WriteTimeClass(szCopy, dwMinutes, szMin, iDigits);
1990 if (iDigits) /* Always write seconds if we have significant digits */
1991 SHLWAPI_WriteTimeClass(szCopy, dwMS, szSec, iDigits);
1993 strncpyW(lpszStr, szCopy, cchMax);
1994 iRet = strlenW(lpszStr);
1999 /*************************************************************************
2000 * StrIsIntlEqualA [SHLWAPI.@]
2002 * Compare two strings.
2005 * bCase [I] Whether to compare case sensitively
2006 * lpszStr [I] First string to compare
2007 * lpszComp [I] Second string to compare
2008 * iLen [I] Length to compare
2011 * TRUE If the strings are equal.
2014 BOOL WINAPI StrIsIntlEqualA(BOOL bCase, LPCSTR lpszStr, LPCSTR lpszComp,
2017 DWORD dwFlags = LOCALE_USE_CP_ACP;
2020 TRACE("(%d,%s,%s,%d)\n", bCase,
2021 debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
2023 /* FIXME: These flags are undocumented and unknown by our CompareString.
2024 * We need defines for them.
2026 dwFlags |= bCase ? 0x10000000 : 0x10000001;
2028 iRet = CompareStringA(GetThreadLocale(),
2029 dwFlags, lpszStr, iLen, lpszComp, iLen);
2032 iRet = CompareStringA(2048, dwFlags, lpszStr, iLen, lpszComp, iLen);
2034 return iRet == 2 ? TRUE : FALSE;
2037 /*************************************************************************
2038 * StrIsIntlEqualW [SHLWAPI.@]
2040 * See StrIsIntlEqualA.
2042 BOOL WINAPI StrIsIntlEqualW(BOOL bCase, LPCWSTR lpszStr, LPCWSTR lpszComp,
2048 TRACE("(%d,%s,%s,%d)\n", bCase,
2049 debugstr_w(lpszStr),debugstr_w(lpszComp), iLen);
2051 /* FIXME: These flags are undocumented and unknown by our CompareString.
2052 * We need defines for them.
2054 dwFlags = bCase ? 0x10000000 : 0x10000001;
2056 iRet = CompareStringW(GetThreadLocale(),
2057 dwFlags, lpszStr, iLen, lpszComp, iLen);
2060 iRet = CompareStringW(2048, dwFlags, lpszStr, iLen, lpszComp, iLen);
2062 return iRet == 2 ? TRUE : FALSE;
2065 /*************************************************************************
2068 * Copy a string to another string, up to a maximum number of characters.
2071 * lpszDest [O] Destination string
2072 * lpszSrc [I] Source string
2073 * iLen [I] Maximum number of chars to copy
2076 * Success: A pointer to the last character written.
2077 * Failure: lpszDest, if any arguments are invalid.
2079 LPSTR WINAPI StrCpyNXA(LPSTR lpszDest, LPCSTR lpszSrc, int iLen)
2081 TRACE("(%p,%s,%i)\n", lpszDest, debugstr_a(lpszSrc), iLen);
2083 if (lpszDest && lpszSrc && iLen > 0)
2085 while ((iLen-- > 1) && *lpszSrc)
2086 *lpszDest++ = *lpszSrc++;
2093 /*************************************************************************
2096 * Unicode version of StrCpyNXA.
2098 LPWSTR WINAPI StrCpyNXW(LPWSTR lpszDest, LPCWSTR lpszSrc, int iLen)
2100 TRACE("(%p,%s,%i)\n", lpszDest, debugstr_w(lpszSrc), iLen);
2102 if (lpszDest && lpszSrc && iLen > 0)
2104 while ((iLen-- > 1) && *lpszSrc)
2105 *lpszDest++ = *lpszSrc++;
2112 /*************************************************************************
2113 * StrCmpLogicalW [SHLWAPI.@]
2115 * Compare two strings, ignoring case and comparing digits as numbers.
2118 * lpszStr [I] First string to compare
2119 * lpszComp [I] Second string to compare
2120 * iLen [I] Length to compare
2123 * TRUE If the strings are equal.
2126 INT WINAPI StrCmpLogicalW(LPCWSTR lpszStr, LPCWSTR lpszComp)
2130 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszComp));
2132 if (lpszStr && lpszComp)
2138 else if (isdigitW(*lpszStr))
2142 if (!isdigitW(*lpszComp))
2145 /* Compare the numbers */
2146 StrToIntExW(lpszStr, 0, &iStr);
2147 StrToIntExW(lpszComp, 0, &iComp);
2151 else if (iStr > iComp)
2155 while (isdigitW(*lpszStr))
2157 while (isdigitW(*lpszComp))
2160 else if (isdigitW(*lpszComp))
2164 iDiff = SHLWAPI_ChrCmpHelperA(*lpszStr,*lpszComp,NORM_IGNORECASE);
2180 /* Structure for formatting byte strings */
2181 typedef struct tagSHLWAPI_BYTEFORMATS
2188 } SHLWAPI_BYTEFORMATS;
2190 /*************************************************************************
2191 * StrFormatByteSize64A [SHLWAPI.@]
2193 * Create a string containing an abbreviated byte count of up to 2^63-1.
2196 * llBytes [I] Byte size to format
2197 * lpszDest [I] Destination for formatted string
2198 * cchMax [I] Size of lpszDest
2204 * There is no StrFormatByteSize64W function, it is called StrFormatByteSizeW().
2206 LPSTR WINAPI StrFormatByteSize64A(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax)
2208 static const char szBytes[] = "%ld bytes";
2209 static const char sz3_0[] = "%3.0f";
2210 static const char sz3_1[] = "%3.1f";
2211 static const char sz3_2[] = "%3.2f";
2213 #define KB ((ULONGLONG)1024)
2215 #define GB (KB*KB*KB)
2216 #define TB (KB*KB*KB*KB)
2217 #define PB (KB*KB*KB*KB*KB)
2219 static const SHLWAPI_BYTEFORMATS bfFormats[] =
2221 { 10*KB, 10.24, 100.0, sz3_2, 'K' }, /* 10 KB */
2222 { 100*KB, 102.4, 10.0, sz3_1, 'K' }, /* 100 KB */
2223 { 1000*KB, 1024.0, 1.0, sz3_0, 'K' }, /* 1000 KB */
2224 { 10*MB, 10485.76, 100.0, sz3_2, 'M' }, /* 10 MB */
2225 { 100*MB, 104857.6, 10.0, sz3_1, 'M' }, /* 100 MB */
2226 { 1000*MB, 1048576.0, 1.0, sz3_0, 'M' }, /* 1000 MB */
2227 { 10*GB, 10737418.24, 100.0, sz3_2, 'G' }, /* 10 GB */
2228 { 100*GB, 107374182.4, 10.0, sz3_1, 'G' }, /* 100 GB */
2229 { 1000*GB, 1073741824.0, 1.0, sz3_0, 'G' }, /* 1000 GB */
2230 { 10*TB, 10485.76, 100.0, sz3_2, 'T' }, /* 10 TB */
2231 { 100*TB, 104857.6, 10.0, sz3_1, 'T' }, /* 100 TB */
2232 { 1000*TB, 1048576.0, 1.0, sz3_0, 'T' }, /* 1000 TB */
2233 { 10*PB, 10737418.24, 100.00, sz3_2, 'P' }, /* 10 PB */
2234 { 100*PB, 107374182.4, 10.00, sz3_1, 'P' }, /* 100 PB */
2235 { 1000*PB, 1073741824.0, 1.00, sz3_0, 'P' }, /* 1000 PB */
2236 { 0, 10995116277.76, 100.00, sz3_2, 'E' } /* EB's, catch all */
2243 TRACE("(%lld,%p,%d)\n", llBytes, lpszDest, cchMax);
2245 if (!lpszDest || !cchMax)
2248 if (llBytes < 1024) /* 1K */
2250 snprintf (lpszDest, cchMax, szBytes, (long)llBytes);
2254 /* Note that if this loop completes without finding a match, i will be
2255 * pointing at the last entry, which is a catch all for > 1000 PB
2257 while (i < sizeof(bfFormats) / sizeof(SHLWAPI_BYTEFORMATS) - 1)
2259 if (llBytes < bfFormats[i].dLimit)
2263 /* Above 1 TB we encounter problems with FP accuracy. So for amounts above
2264 * this number we integer shift down by 1 MB first. The table above has
2265 * the divisors scaled down from the '< 10 TB' entry onwards, to account
2266 * for this. We also add a small fudge factor to get the correct result for
2267 * counts that lie exactly on a 1024 byte boundary.
2270 dBytes = (double)(llBytes >> 20) + 0.001; /* Scale down by I MB */
2272 dBytes = (double)llBytes + 0.00001;
2274 dBytes = floor(dBytes / bfFormats[i].dDivisor) / bfFormats[i].dNormaliser;
2276 sprintf(szBuff, bfFormats[i].lpszFormat, dBytes);
2278 szAdd[1] = bfFormats[i].wPrefix;
2281 strcat(szBuff, szAdd);
2282 strncpy(lpszDest, szBuff, cchMax);
2286 /*************************************************************************
2287 * StrFormatByteSizeW [SHLWAPI.@]
2289 * See StrFormatByteSize64A.
2291 LPWSTR WINAPI StrFormatByteSizeW(LONGLONG llBytes, LPWSTR lpszDest,
2296 StrFormatByteSize64A(llBytes, szBuff, sizeof(szBuff));
2299 MultiByteToWideChar(CP_ACP, 0, szBuff, -1, lpszDest, cchMax);
2303 /*************************************************************************
2304 * StrFormatByteSizeA [SHLWAPI.@]
2306 * Create a string containing an abbreviated byte count of up to 2^31-1.
2309 * dwBytes [I] Byte size to format
2310 * lpszDest [I] Destination for formatted string
2311 * cchMax [I] Size of lpszDest
2317 * The Ascii and Unicode versions of this function accept a different
2318 * integer type for dwBytes. See StrFormatByteSize64A().
2320 LPSTR WINAPI StrFormatByteSizeA(DWORD dwBytes, LPSTR lpszDest, UINT cchMax)
2322 TRACE("(%ld,%p,%d)\n", dwBytes, lpszDest, cchMax);
2324 return StrFormatByteSize64A(dwBytes, lpszDest, cchMax);
2327 /*************************************************************************
2330 * Remove a single non-trailing ampersand ('&') from a string.
2333 * lpszStr [I/O] String to remove ampersand from.
2336 * The character after the first ampersand in lpszStr, or the first character
2337 * in lpszStr if there is no ampersand in the string.
2339 char WINAPI SHStripMneumonicA(LPCSTR lpszStr)
2341 LPSTR lpszIter, lpszTmp;
2344 TRACE("(%s)\n", debugstr_a(lpszStr));
2348 if ((lpszIter = StrChrA(lpszStr, '&')))
2350 lpszTmp = CharNextA(lpszIter);
2351 if (lpszTmp && *lpszTmp)
2353 if (*lpszTmp != '&')
2356 while (lpszIter && *lpszIter)
2358 lpszTmp = CharNextA(lpszIter);
2359 *lpszIter = *lpszTmp;