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"
32 #define NONAMELESSUNION
33 #define NONAMELESSSTRUCT
40 #define NO_SHLWAPI_STREAM
43 #include "wine/unicode.h"
44 #include "wine/debug.h"
46 WINE_DEFAULT_DEBUG_CHANNEL(shell);
48 static HRESULT WINAPI _SHStrDupAA(LPCSTR src, LPSTR * dest);
49 static HRESULT WINAPI _SHStrDupAW(LPCWSTR src, LPSTR * dest);
51 /*************************************************************************
52 * SHLWAPI_ChrCmpHelperA
54 * Internal helper for SHLWAPI_ChrCmpA/ChrCMPIA.
57 * Both this function and its Unicode counterpart are very inneficient. To
58 * fix this, CompareString must be completely implemented and optimised
59 * first. Then the core character test can be taken out of that function and
60 * placed here, so that it need never be called at all. Until then, do not
61 * attempt to optimise this code unless you are willing to test that it
62 * still performs correctly.
64 static BOOL WINAPI SHLWAPI_ChrCmpHelperA(WORD ch1, WORD ch2, DWORD dwFlags)
66 char str1[3], str2[3];
68 str1[0] = LOBYTE(ch1);
69 if (IsDBCSLeadByte(ch1))
71 str1[1] = HIBYTE(ch1);
77 str2[0] = LOBYTE(ch2);
78 if (IsDBCSLeadByte(ch2))
80 str2[1] = HIBYTE(ch2);
86 return CompareStringA(GetThreadLocale(), dwFlags, str1, -1, str2, -1) - 2;
89 /*************************************************************************
90 * SHLWAPI_ChrCmpHelperW
92 * Internal helper for SHLWAPI_ChrCmpW/ChrCmpIW.
94 static BOOL WINAPI SHLWAPI_ChrCmpHelperW(WCHAR ch1, WCHAR ch2, DWORD dwFlags)
96 WCHAR str1[2], str2[2];
102 return CompareStringW(GetThreadLocale(), dwFlags, str1, 2, str2, 2) - 2;
105 /*************************************************************************
108 * Internal helper function.
110 static BOOL WINAPI SHLWAPI_ChrCmpA(WORD ch1, WORD ch2)
112 return SHLWAPI_ChrCmpHelperA(ch1, ch2, 0);
115 /*************************************************************************
116 * ChrCmpIA [SHLWAPI.385]
118 * Compare two characters, ignoring case.
121 * ch1 [I] First character to compare
122 * ch2 [I] Second character to compare
125 * FALSE, if the characters are equal.
126 * Non-zero otherwise.
128 BOOL WINAPI ChrCmpIA(WORD ch1, WORD ch2)
130 TRACE("(%d,%d)\n", ch1, ch2);
132 return SHLWAPI_ChrCmpHelperA(ch1, ch2, NORM_IGNORECASE);
135 /*************************************************************************
138 * Internal helper function.
140 static BOOL WINAPI SHLWAPI_ChrCmpW(WCHAR ch1, WCHAR ch2)
142 return SHLWAPI_ChrCmpHelperW(ch1, ch2, 0);
145 /*************************************************************************
146 * ChrCmpIW [SHLWAPI.386]
150 BOOL WINAPI ChrCmpIW(WCHAR ch1, WCHAR ch2)
152 return SHLWAPI_ChrCmpHelperW(ch1, ch2, NORM_IGNORECASE);
155 /*************************************************************************
156 * StrChrA [SHLWAPI.@]
158 * Find a given character in a string.
161 * lpszStr [I] String to search in.
162 * ch [I] Character to search for.
165 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
167 * Failure: NULL, if any arguments are invalid.
169 LPSTR WINAPI StrChrA(LPCSTR lpszStr, WORD ch)
171 TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch);
177 if (!SHLWAPI_ChrCmpA(*lpszStr, ch))
178 return (LPSTR)lpszStr;
179 lpszStr = CharNextA(lpszStr);
185 /*************************************************************************
186 * StrChrW [SHLWAPI.@]
190 LPWSTR WINAPI StrChrW(LPCWSTR lpszStr, WCHAR ch)
192 LPWSTR lpszRet = NULL;
194 TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch);
197 lpszRet = strchrW(lpszStr, ch);
201 /*************************************************************************
202 * StrChrIA [SHLWAPI.@]
204 * Find a given character in a string, ignoring case.
207 * lpszStr [I] String to search in.
208 * ch [I] Character to search for.
211 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
213 * Failure: NULL, if any arguments are invalid.
215 LPSTR WINAPI StrChrIA(LPCSTR lpszStr, WORD ch)
217 TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch);
223 if (!ChrCmpIA(*lpszStr, ch))
224 return (LPSTR)lpszStr;
225 lpszStr = CharNextA(lpszStr);
231 /*************************************************************************
232 * StrChrIW [SHLWAPI.@]
236 LPWSTR WINAPI StrChrIW(LPCWSTR lpszStr, WCHAR ch)
238 TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch);
245 if (toupperW(*lpszStr) == ch)
246 return (LPWSTR)lpszStr;
247 lpszStr = CharNextW(lpszStr);
251 return (LPWSTR)lpszStr;
254 /*************************************************************************
255 * StrCmpIW [SHLWAPI.@]
257 * Compare two strings, ignoring case.
260 * lpszStr [I] First string to compare
261 * lpszComp [I] Second string to compare
264 * An integer less than, equal to or greater than 0, indicating that
265 * lpszStr is less than, the same, or greater than lpszComp.
267 int WINAPI StrCmpIW(LPCWSTR lpszStr, LPCWSTR lpszComp)
271 TRACE("(%s,%s)\n", debugstr_w(lpszStr),debugstr_w(lpszComp));
273 iRet = strcmpiW(lpszStr, lpszComp);
274 return iRet < 0 ? -1 : iRet ? 1 : 0;
277 /*************************************************************************
278 * SHLWAPI_StrCmpNHelperA
280 * Internal helper for StrCmpNA/StrCmpNIA.
282 static INT WINAPI SHLWAPI_StrCmpNHelperA(LPCSTR lpszStr, LPCSTR lpszComp,
284 BOOL (WINAPI *pChrCmpFn)(WORD,WORD))
300 ch1 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr;
301 ch2 = IsDBCSLeadByte(*lpszComp)? *lpszComp << 8 | lpszComp[1] : *lpszComp;
303 if ((iDiff = pChrCmpFn(ch1, ch2)) < 0)
307 else if (!*lpszStr && !*lpszComp)
310 lpszStr = CharNextA(lpszStr);
311 lpszComp = CharNextA(lpszComp);
316 /*************************************************************************
317 * StrCmpNA [SHLWAPI.@]
319 * Compare two strings, up to a maximum length.
322 * lpszStr [I] First string to compare
323 * lpszComp [I] Second string to compare
324 * iLen [I] Maximum number of chars to compare.
327 * An integer less than, equal to or greater than 0, indicating that
328 * lpszStr is less than, the same, or greater than lpszComp.
330 INT WINAPI StrCmpNA(LPCSTR lpszStr, LPCSTR lpszComp, INT iLen)
332 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
334 return SHLWAPI_StrCmpNHelperA(lpszStr, lpszComp, iLen, SHLWAPI_ChrCmpA);
337 /*************************************************************************
338 * StrCmpNW [SHLWAPI.@]
342 INT WINAPI StrCmpNW(LPCWSTR lpszStr, LPCWSTR lpszComp, INT iLen)
346 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen);
348 iRet = strncmpW(lpszStr, lpszComp, iLen);
349 return iRet < 0 ? -1 : iRet ? 1 : 0;
352 /*************************************************************************
353 * StrCmpNIA [SHLWAPI.@]
355 * Compare two strings, up to a maximum length, ignoring case.
358 * lpszStr [I] First string to compare
359 * lpszComp [I] Second string to compare
360 * iLen [I] Maximum number of chars to compare.
363 * An integer less than, equal to or greater than 0, indicating that
364 * lpszStr is less than, the same, or greater than lpszComp.
367 * The Win32 version of this function is _completely_ broken for cases
368 * where iLen is greater than the length of lpszComp. Examples:
370 * StrCmpNIA("foo.gif", "foo", 5) is -1 under Win32; Should return 1.
371 * StrCmpNIA("\", "\\", 3) is 0 under Win32; Should return -1.
372 * StrCmpNIA("\", "\..\foo\", 3) is 1 under Win32; Should return -1.
374 * This implementation behaves correctly, since it is unlikely any
375 * applications actually rely on this function being broken.
377 int WINAPI StrCmpNIA(LPCSTR lpszStr, LPCSTR lpszComp, int iLen)
379 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
381 return SHLWAPI_StrCmpNHelperA(lpszStr, lpszComp, iLen, ChrCmpIA);
384 /*************************************************************************
385 * StrCmpNIW [SHLWAPI.@]
389 INT WINAPI StrCmpNIW(LPCWSTR lpszStr, LPCWSTR lpszComp, int iLen)
393 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen);
395 iRet = strncmpiW(lpszStr, lpszComp, iLen);
396 return iRet < 0 ? -1 : iRet ? 1 : 0;
399 /*************************************************************************
400 * StrCmpW [SHLWAPI.@]
402 * Compare two strings.
405 * lpszStr [I] First string to compare
406 * lpszComp [I] Second string to compare
409 * An integer less than, equal to or greater than 0, indicating that
410 * lpszStr is less than, the same, or greater than lpszComp.
412 int WINAPI StrCmpW(LPCWSTR lpszStr, LPCWSTR lpszComp)
416 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszComp));
418 iRet = strcmpW(lpszStr, lpszComp);
419 return iRet < 0 ? -1 : iRet ? 1 : 0;
422 /*************************************************************************
423 * StrCatW [SHLWAPI.@]
425 * Concatanate two strings.
428 * lpszStr [O] Initial string
429 * lpszSrc [I] String to concatanate
434 LPWSTR WINAPI StrCatW(LPWSTR lpszStr, LPCWSTR lpszSrc)
436 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSrc));
438 strcatW(lpszStr, lpszSrc);
442 /*************************************************************************
443 * StrCpyW [SHLWAPI.@]
445 * Copy a string to another string.
448 * lpszStr [O] Destination string
449 * lpszSrc [I] Source string
454 LPWSTR WINAPI StrCpyW(LPWSTR lpszStr, LPCWSTR lpszSrc)
456 TRACE("(%p,%s)\n", lpszStr, debugstr_w(lpszSrc));
458 strcpyW(lpszStr, lpszSrc);
462 /*************************************************************************
463 * StrCpyNW [SHLWAPI.@]
465 * Copy a string to another string, up to a maximum number of characters.
468 * lpszStr [O] Destination string
469 * lpszSrc [I] Source string
470 * iLen [I] Maximum number of chars to copy
475 LPWSTR WINAPI StrCpyNW(LPWSTR lpszStr, LPCWSTR lpszSrc, int iLen)
477 TRACE("(%p,%s,%i)\n", lpszStr, debugstr_w(lpszSrc), iLen);
479 lstrcpynW(lpszStr, lpszSrc, iLen);
485 /*************************************************************************
486 * SHLWAPI_StrStrHelperA
488 * Internal implementation of StrStrA/StrStrIA
490 static LPSTR WINAPI SHLWAPI_StrStrHelperA(LPCSTR lpszStr, LPCSTR lpszSearch,
491 int (*pStrCmpFn)(LPCSTR,LPCSTR,size_t))
495 if (!lpszStr || !lpszSearch || !*lpszSearch)
498 iLen = strlen(lpszSearch);
502 if (!pStrCmpFn(lpszStr, lpszSearch, iLen))
503 return (LPSTR)lpszStr;
504 lpszStr = CharNextA(lpszStr);
509 /*************************************************************************
510 * SHLWAPI_StrStrHelperW
512 * Internal implementation of StrStrW/StrStrIW
514 static LPWSTR WINAPI SHLWAPI_StrStrHelperW(LPCWSTR lpszStr, LPCWSTR lpszSearch,
515 int (*pStrCmpFn)(LPCWSTR,LPCWSTR,int))
519 if (!lpszStr || !lpszSearch || !*lpszSearch)
522 iLen = strlenW(lpszSearch);
526 if (!pStrCmpFn(lpszStr, lpszSearch, iLen))
527 return (LPWSTR)lpszStr;
528 lpszStr = CharNextW(lpszStr);
533 /*************************************************************************
534 * StrStrA [SHLWAPI.@]
536 * Find a substring within a string.
539 * lpszStr [I] String to search in
540 * lpszSearch [I] String to look for
543 * The start of lpszSearch within lpszStr, or NULL if not found.
545 LPSTR WINAPI StrStrA(LPCSTR lpszStr, LPCSTR lpszSearch)
547 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
549 return SHLWAPI_StrStrHelperA(lpszStr, lpszSearch, strncmp);
552 /*************************************************************************
553 * StrStrW [SHLWAPI.@]
557 LPWSTR WINAPI StrStrW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
559 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
561 return SHLWAPI_StrStrHelperW(lpszStr, lpszSearch, strncmpW);
564 /*************************************************************************
565 * StrRStrIA [SHLWAPI.@]
567 * Find the last occurence of a substring within a string.
570 * lpszStr [I] String to search in
571 * lpszEnd [I] End of lpszStr
572 * lpszSearch [I] String to look for
575 * The last occurence lpszSearch within lpszStr, or NULL if not found.
577 LPSTR WINAPI StrRStrIA(LPCSTR lpszStr, LPCSTR lpszEnd, LPCSTR lpszSearch)
579 LPSTR lpszRet = NULL;
583 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
585 if (!lpszStr || !lpszSearch || !*lpszSearch)
589 lpszEnd = lpszStr + lstrlenA(lpszStr);
591 if (IsDBCSLeadByte(*lpszSearch))
592 ch1 = *lpszSearch << 8 | lpszSearch[1];
595 iLen = lstrlenA(lpszSearch);
597 while (lpszStr <= lpszEnd && *lpszStr)
599 ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr;
600 if (!ChrCmpIA(ch1, ch2))
602 if (!StrCmpNIA(lpszStr, lpszSearch, iLen))
603 lpszRet = (LPSTR)lpszStr;
605 lpszStr = CharNextA(lpszStr);
610 /*************************************************************************
611 * StrRStrIW [SHLWAPI.@]
615 LPWSTR WINAPI StrRStrIW(LPCWSTR lpszStr, LPCWSTR lpszEnd, LPCWSTR lpszSearch)
617 LPWSTR lpszRet = NULL;
620 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
622 if (!lpszStr || !lpszSearch || !*lpszSearch)
626 lpszEnd = lpszStr + strlenW(lpszStr);
628 iLen = strlenW(lpszSearch);
630 while (lpszStr <= lpszEnd && *lpszStr)
632 if (!ChrCmpIA(*lpszSearch, *lpszStr))
634 if (!StrCmpNIW(lpszStr, lpszSearch, iLen))
635 lpszRet = (LPWSTR)lpszStr;
637 lpszStr = CharNextW(lpszStr);
642 /*************************************************************************
643 * StrStrIA [SHLWAPI.@]
645 * Find a substring within a string, ignoring case.
648 * lpszStr [I] String to search in
649 * lpszSearch [I] String to look for
652 * The start of lpszSearch within lpszStr, or NULL if not found.
654 LPSTR WINAPI StrStrIA(LPCSTR lpszStr, LPCSTR lpszSearch)
656 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
658 return SHLWAPI_StrStrHelperA(lpszStr, lpszSearch, strncasecmp);
661 /*************************************************************************
662 * StrStrIW [SHLWAPI.@]
666 LPWSTR WINAPI StrStrIW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
668 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
670 return SHLWAPI_StrStrHelperW(lpszStr, lpszSearch, strncmpiW);
673 /*************************************************************************
674 * StrToIntA [SHLWAPI.@]
676 * Read an integer from a string.
679 * lpszStr [I] String to read integer from
682 * The integer value represented by the string, or 0 if no integer is
686 * No leading space is allowed before the number, although a leading '-' is.
688 int WINAPI StrToIntA(LPCSTR lpszStr)
692 TRACE("(%s)\n", debugstr_a(lpszStr));
696 WARN("Invalid lpszStr would crash under Win32!\n");
700 if (*lpszStr == '-' || isdigit(*lpszStr))
701 StrToIntExA(lpszStr, 0, &iRet);
705 /*************************************************************************
706 * StrToIntW [SHLWAPI.@]
710 int WINAPI StrToIntW(LPCWSTR lpszStr)
714 TRACE("(%s)\n", debugstr_w(lpszStr));
718 WARN("Invalid lpszStr would crash under Win32!\n");
722 if (*lpszStr == '-' || isdigitW(*lpszStr))
723 StrToIntExW(lpszStr, 0, &iRet);
727 /*************************************************************************
728 * StrToIntExA [SHLWAPI.@]
730 * Read an integer from a string.
733 * lpszStr [I] String to read integer from
734 * dwFlags [I] Flags controlling the conversion
735 * lpiRet [O] Destination for read integer.
738 * Success: TRUE. lpiRet contains the integer value represented by the string.
739 * Failure: FALSE, if the string is invalid, or no number is present.
742 * Leading whitespace, '-' and '+' are allowed before the number. If
743 * dwFlags includes STIF_SUPPORT_HEX, hexidecimal numbers are allowed, if
744 * preceeded by '0x'. If this flag is not set, or there is no '0x' prefix,
745 * the string is treated as a decimal string. A leading '-' is ignored for
746 * hexidecimal numbers.
748 BOOL WINAPI StrToIntExA(LPCSTR lpszStr, DWORD dwFlags, LPINT lpiRet)
750 BOOL bNegative = FALSE;
753 TRACE("(%s,%08lX,%p)\n", debugstr_a(lpszStr), dwFlags, lpiRet);
755 if (!lpszStr || !lpiRet)
757 WARN("Invalid parameter would crash under Win32!\n");
760 if (dwFlags > STIF_SUPPORT_HEX)
762 WARN("Unknown flags (%08lX)!\n", dwFlags & ~STIF_SUPPORT_HEX);
765 /* Skip leading space, '+', '-' */
766 while (isspace(*lpszStr))
767 lpszStr = CharNextA(lpszStr);
774 else if (*lpszStr == '+')
777 if (dwFlags & STIF_SUPPORT_HEX &&
778 *lpszStr == '0' && tolower(lpszStr[1]) == 'x')
780 /* Read hex number */
783 if (!isxdigit(*lpszStr))
786 while (isxdigit(*lpszStr))
789 if (isdigit(*lpszStr))
790 iRet += (*lpszStr - '0');
792 iRet += 10 + (tolower(*lpszStr) - 'a');
799 /* Read decimal number */
800 if (!isdigit(*lpszStr))
803 while (isdigit(*lpszStr))
806 iRet += (*lpszStr - '0');
809 *lpiRet = bNegative ? -iRet : iRet;
813 /*************************************************************************
814 * StrToIntExW [SHLWAPI.@]
818 BOOL WINAPI StrToIntExW(LPCWSTR lpszStr, DWORD dwFlags, LPINT lpiRet)
820 BOOL bNegative = FALSE;
823 TRACE("(%s,%08lX,%p)\n", debugstr_w(lpszStr), dwFlags, lpiRet);
825 if (!lpszStr || !lpiRet)
827 WARN("Invalid parameter would crash under Win32!\n");
830 if (dwFlags > STIF_SUPPORT_HEX)
832 WARN("Unknown flags (%08lX)!\n", dwFlags & ~STIF_SUPPORT_HEX);
835 /* Skip leading space, '+', '-' */
836 while (isspaceW(*lpszStr))
837 lpszStr = CharNextW(lpszStr);
844 else if (*lpszStr == '+')
847 if (dwFlags & STIF_SUPPORT_HEX &&
848 *lpszStr == '0' && tolowerW(lpszStr[1]) == 'x')
850 /* Read hex number */
853 if (!isxdigitW(*lpszStr))
856 while (isxdigitW(*lpszStr))
859 if (isdigitW(*lpszStr))
860 iRet += (*lpszStr - '0');
862 iRet += 10 + (tolowerW(*lpszStr) - 'a');
869 /* Read decimal number */
870 if (!isdigitW(*lpszStr))
873 while (isdigitW(*lpszStr))
876 iRet += (*lpszStr - '0');
879 *lpiRet = bNegative ? -iRet : iRet;
883 /*************************************************************************
884 * StrDupA [SHLWAPI.@]
886 * Duplicate a string.
889 * lpszStr [I] String to duplicate.
892 * Success: A pointer to a new string containing the contents of lpszStr
893 * Failure: NULL, if memory cannot be allocated
896 * The string memory is allocated with LocalAlloc, and so should be released
897 * by calling LocalFree.
899 LPSTR WINAPI StrDupA(LPCSTR lpszStr)
904 TRACE("(%s)\n",debugstr_a(lpszStr));
906 iLen = lpszStr ? strlen(lpszStr) + 1 : 1;
907 lpszRet = (LPSTR)LocalAlloc(LMEM_FIXED, iLen);
912 memcpy(lpszRet, lpszStr, iLen);
919 /*************************************************************************
920 * StrDupW [SHLWAPI.@]
924 LPWSTR WINAPI StrDupW(LPCWSTR lpszStr)
929 TRACE("(%s)\n",debugstr_w(lpszStr));
931 iLen = (lpszStr ? strlenW(lpszStr) + 1 : 1) * sizeof(WCHAR);
932 lpszRet = (LPWSTR)LocalAlloc(LMEM_FIXED, iLen);
937 memcpy(lpszRet, lpszStr, iLen);
944 /*************************************************************************
945 * SHLWAPI_StrSpnHelperA
947 * Internal implementation of StrSpnA/StrCSpnA/StrCSpnIA
949 static int WINAPI SHLWAPI_StrSpnHelperA(LPCSTR lpszStr, LPCSTR lpszMatch,
950 LPSTR (WINAPI *pStrChrFn)(LPCSTR,WORD),
953 LPCSTR lpszRead = lpszStr;
954 if (lpszStr && *lpszStr && lpszMatch)
958 LPCSTR lpszTest = pStrChrFn(lpszMatch, *lpszRead);
960 if (!bInvert && !lpszTest)
962 if (bInvert && lpszTest)
964 lpszRead = CharNextA(lpszRead);
967 return lpszRead - lpszStr;
970 /*************************************************************************
971 * SHLWAPI_StrSpnHelperW
973 * Internal implementation of StrSpnW/StrCSpnW/StrCSpnIW
975 static int WINAPI SHLWAPI_StrSpnHelperW(LPCWSTR lpszStr, LPCWSTR lpszMatch,
976 LPWSTR (WINAPI *pStrChrFn)(LPCWSTR,WCHAR),
979 LPCWSTR lpszRead = lpszStr;
980 if (lpszStr && *lpszStr && lpszMatch)
984 LPCWSTR lpszTest = pStrChrFn(lpszMatch, *lpszRead);
986 if (!bInvert && !lpszTest)
988 if (bInvert && lpszTest)
990 lpszRead = CharNextW(lpszRead);
993 return lpszRead - lpszStr;
996 /*************************************************************************
997 * StrSpnA [SHLWAPI.@]
999 * Find the length of the start of a string that contains only certain
1003 * lpszStr [I] String to search
1004 * lpszMatch [I] Characters that can be in the substring
1007 * The length of the part of lpszStr containing only chars from lpszMatch,
1008 * or 0 if any parameter is invalid.
1010 int WINAPI StrSpnA(LPCSTR lpszStr, LPCSTR lpszMatch)
1012 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1014 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, FALSE);
1017 /*************************************************************************
1018 * StrSpnW [SHLWAPI.@]
1022 int WINAPI StrSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1024 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1026 return SHLWAPI_StrSpnHelperW(lpszStr, lpszMatch, StrChrW, FALSE);
1029 /*************************************************************************
1030 * StrCSpnA [SHLWAPI.@]
1032 * Find the length of the start of a string that does not contain certain
1036 * lpszStr [I] String to search
1037 * lpszMatch [I] Characters that cannot be in the substring
1040 * The length of the part of lpszStr containing only chars not in lpszMatch,
1041 * or 0 if any parameter is invalid.
1043 int WINAPI StrCSpnA(LPCSTR lpszStr, LPCSTR lpszMatch)
1045 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1047 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, TRUE);
1050 /*************************************************************************
1051 * StrCSpnW [SHLWAPI.@]
1055 int WINAPI StrCSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1057 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1059 return SHLWAPI_StrSpnHelperW(lpszStr, lpszMatch, StrChrW, TRUE);
1062 /*************************************************************************
1063 * StrCSpnIA [SHLWAPI.@]
1065 * Find the length of the start of a string that does not contain certain
1066 * characters, ignoring case.
1069 * lpszStr [I] String to search
1070 * lpszMatch [I] Characters that cannot be in the substring
1073 * The length of the part of lpszStr containing only chars not in lpszMatch,
1074 * or 0 if any parameter is invalid.
1076 int WINAPI StrCSpnIA(LPCSTR lpszStr, LPCSTR lpszMatch)
1078 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1080 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrIA, TRUE);
1083 /*************************************************************************
1084 * StrCSpnIW [SHLWAPI.@]
1088 int WINAPI StrCSpnIW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1090 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1092 return SHLWAPI_StrSpnHelperW(lpszStr, lpszMatch, StrChrIW, TRUE);
1095 /*************************************************************************
1096 * StrPBrkA [SHLWAPI.@]
1098 * Search a string for any of a group of characters.
1101 * lpszStr [I] String to search
1102 * lpszMatch [I] Characters to match
1105 * A pointer to the first matching character in lpszStr, or NULL if no
1108 LPSTR WINAPI StrPBrkA(LPCSTR lpszStr, LPCSTR lpszMatch)
1110 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1112 if (lpszStr && lpszMatch && *lpszMatch)
1116 if (StrChrA(lpszMatch, *lpszStr))
1117 return (LPSTR)lpszStr;
1118 lpszStr = CharNextA(lpszStr);
1124 /*************************************************************************
1125 * StrPBrkW [SHLWAPI.@]
1129 LPWSTR WINAPI StrPBrkW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1131 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1133 if (lpszStr && lpszMatch && *lpszMatch)
1137 if (StrChrW(lpszMatch, *lpszStr))
1138 return (LPWSTR)lpszStr;
1139 lpszStr = CharNextW(lpszStr);
1145 /*************************************************************************
1146 * SHLWAPI_StrRChrHelperA
1148 * Internal implementation of StrRChrA/StrRChrIA.
1150 static LPSTR WINAPI SHLWAPI_StrRChrHelperA(LPCSTR lpszStr,
1151 LPCSTR lpszEnd, WORD ch,
1152 BOOL (WINAPI *pChrCmpFn)(WORD,WORD))
1154 LPCSTR lpszRet = NULL;
1161 lpszEnd = lpszStr + lstrlenA(lpszStr);
1163 while (*lpszStr && lpszStr <= lpszEnd)
1165 ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr;
1167 if (!pChrCmpFn(ch, ch2))
1169 lpszStr = CharNextA(lpszStr);
1172 return (LPSTR)lpszRet;
1175 /*************************************************************************
1176 * SHLWAPI_StrRChrHelperW
1178 * Internal implementation of StrRChrW/StrRChrIW.
1180 static LPWSTR WINAPI SHLWAPI_StrRChrHelperW(LPCWSTR lpszStr,
1181 LPCWSTR lpszEnd, WCHAR ch,
1182 BOOL (WINAPI *pChrCmpFn)(WCHAR,WCHAR))
1184 LPCWSTR lpszRet = NULL;
1189 lpszEnd = lpszStr + strlenW(lpszStr);
1191 while (*lpszStr && lpszStr <= lpszEnd)
1193 if (!pChrCmpFn(ch, *lpszStr))
1195 lpszStr = CharNextW(lpszStr);
1198 return (LPWSTR)lpszRet;
1201 /**************************************************************************
1202 * StrRChrA [SHLWAPI.@]
1204 * Find the last occurence of a character in string.
1207 * lpszStr [I] String to search in
1208 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1209 * ch [I] Character to search for.
1212 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1213 * or NULL if not found.
1214 * Failure: NULL, if any arguments are invalid.
1216 LPSTR WINAPI StrRChrA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch)
1218 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch);
1220 return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, SHLWAPI_ChrCmpA);
1223 /**************************************************************************
1224 * StrRChrW [SHLWAPI.@]
1228 LPWSTR WINAPI StrRChrW(LPCWSTR lpszStr, LPCWSTR lpszEnd, WORD ch)
1230 TRACE("(%s,%s,%x)\n", debugstr_w(lpszStr), debugstr_w(lpszEnd), ch);
1232 return SHLWAPI_StrRChrHelperW(lpszStr, lpszEnd, ch, SHLWAPI_ChrCmpW);
1235 /**************************************************************************
1236 * StrRChrIA [SHLWAPI.@]
1238 * Find the last occurence of a character in string, ignoring case.
1241 * lpszStr [I] String to search in
1242 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1243 * ch [I] Character to search for.
1246 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1247 * or NULL if not found.
1248 * Failure: NULL, if any arguments are invalid.
1250 LPSTR WINAPI StrRChrIA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch)
1252 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch);
1254 return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, ChrCmpIA);
1257 /**************************************************************************
1258 * StrRChrIW [SHLWAPI.@]
1262 LPWSTR WINAPI StrRChrIW(LPCWSTR lpszStr, LPCWSTR lpszEnd, WORD ch)
1264 TRACE("(%s,%s,%x)\n", debugstr_w(lpszStr), debugstr_w(lpszEnd), ch);
1266 return SHLWAPI_StrRChrHelperW(lpszStr, lpszEnd, ch, ChrCmpIW);
1269 /*************************************************************************
1270 * StrCatBuffA [SHLWAPI.@]
1272 * Concatenate two strings together.
1275 * lpszStr [O] String to concatenate to
1276 * lpszCat [I] String to add to lpszCat
1277 * cchMax [I] Maximum number of characters for the whole string
1283 * cchMax dtermines the number of characters in the final length of the
1284 * string, not the number appended to lpszStr from lpszCat.
1286 LPSTR WINAPI StrCatBuffA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax)
1290 TRACE("(%p,%s,%d)\n", lpszStr, debugstr_a(lpszCat), cchMax);
1294 WARN("Invalid lpszStr would crash under Win32!\n");
1298 iLen = strlen(lpszStr);
1302 StrCpyNA(lpszStr + iLen, lpszCat, cchMax);
1306 /*************************************************************************
1307 * StrCatBuffW [SHLWAPI.@]
1311 LPWSTR WINAPI StrCatBuffW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax)
1315 TRACE("(%p,%s,%d)\n", lpszStr, debugstr_w(lpszCat), cchMax);
1319 WARN("Invalid lpszStr would crash under Win32!\n");
1323 iLen = strlenW(lpszStr);
1327 StrCpyNW(lpszStr + iLen, lpszCat, cchMax);
1331 /*************************************************************************
1332 * StrRetToBufA [SHLWAPI.@]
1334 * Convert a STRRET to a normal string.
1337 * lpStrRet [O] STRRET to convert
1338 * pIdl [I] ITEMIDLIST for lpStrRet->uType = STRRET_OFFSETA
1339 * lpszDest [O] Destination for normal string
1340 * dwLen [I] Length of lpszDest
1343 * Success: S_OK. lpszDest contains up to dwLen characters of the string.
1344 * If lpStrRet is of type STRRET_WSTR, its memory is freed with
1345 * CoTaskMemFree and its type set to STRRET_CSTRA.
1346 * Failure: E_FAIL, if any parameters are invalid.
1348 HRESULT WINAPI StrRetToBufA (LPSTRRET src, const ITEMIDLIST *pidl, LPSTR dest, DWORD len)
1351 * This routine is identical to that in dlls/shell32/shellstring.c.
1352 * It was duplicated because not every version of Shlwapi.dll exports
1353 * StrRetToBufA. If you change one routine, change them both.
1355 TRACE("dest=%p len=0x%lx strret=%p pidl=%p stub\n",dest,len,src,pidl);
1359 WARN("Invalid lpStrRet would crash under Win32!\n");
1373 WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, dest, len, NULL, NULL);
1374 CoTaskMemFree(src->u.pOleStr);
1378 lstrcpynA((LPSTR)dest, src->u.cStr, len);
1382 lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len);
1386 FIXME("unknown type!\n");
1392 /*************************************************************************
1393 * StrRetToBufW [SHLWAPI.@]
1397 HRESULT WINAPI StrRetToBufW (LPSTRRET src, const ITEMIDLIST *pidl, LPWSTR dest, DWORD len)
1399 TRACE("dest=%p len=0x%lx strret=%p pidl=%p stub\n",dest,len,src,pidl);
1403 WARN("Invalid lpStrRet would crash under Win32!\n");
1417 lstrcpynW((LPWSTR)dest, src->u.pOleStr, len);
1418 CoTaskMemFree(src->u.pOleStr);
1422 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
1429 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1,
1436 FIXME("unknown type!\n");
1442 /*************************************************************************
1443 * StrRetToStrA [SHLWAPI.@]
1445 * converts a STRRET to a normal string
1447 HRESULT WINAPI StrRetToStrA(LPSTRRET pstr, const ITEMIDLIST * pidl, LPSTR* ppszName)
1449 HRESULT ret = E_FAIL;
1451 switch (pstr->uType) {
1453 ret = _SHStrDupAW(pstr->u.pOleStr, ppszName);
1454 CoTaskMemFree(pstr->u.pOleStr);
1458 ret = _SHStrDupAA(pstr->u.cStr, ppszName);
1462 ret = _SHStrDupAA(((LPCSTR)&pidl->mkid)+pstr->u.uOffset, ppszName);
1471 /*************************************************************************
1472 * StrRetToStrW [SHLWAPI.@]
1474 * converts a STRRET to a normal string
1476 HRESULT WINAPI StrRetToStrW(LPSTRRET pstr, const ITEMIDLIST * pidl, LPWSTR* ppszName)
1478 HRESULT ret = E_FAIL;
1480 switch (pstr->uType) {
1482 ret = SHStrDupW(pstr->u.pOleStr, ppszName);
1483 CoTaskMemFree(pstr->u.pOleStr);
1487 ret = SHStrDupA(pstr->u.cStr, ppszName);
1491 ret = SHStrDupA(((LPCSTR)&pidl->mkid)+pstr->u.uOffset, ppszName);
1500 /*************************************************************************
1501 * StrFormatKBSizeA [SHLWAPI.@]
1503 * Create a formatted string containing a byte count in Kilobytes.
1506 * llBytes [I] Byte size to format
1507 * lpszDest [I] Destination for formatted string
1508 * cchMax [I] Size of lpszDest
1513 LPSTR WINAPI StrFormatKBSizeA(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax)
1515 char szBuff[256], *szOut = szBuff + sizeof(szBuff) - 1;
1516 LONGLONG ulKB = (llBytes + 1023) >> 10;
1518 TRACE("(%lld,%p,%d)\n", llBytes, lpszDest, cchMax);
1527 LONGLONG ulNextDigit = ulKB % 10;
1528 *szOut-- = '0' + ulNextDigit;
1529 ulKB = (ulKB - ulNextDigit) / 10;
1532 strncpy(lpszDest, szOut + 1, cchMax);
1536 /*************************************************************************
1537 * StrFormatKBSizeW [SHLWAPI.@]
1539 * See StrFormatKBSizeA.
1541 LPWSTR WINAPI StrFormatKBSizeW(LONGLONG llBytes, LPWSTR lpszDest, UINT cchMax)
1543 WCHAR szBuff[256], *szOut = szBuff + sizeof(szBuff) - 1;
1544 LONGLONG ulKB = (llBytes + 1023) >> 10;
1546 TRACE("(%lld,%p,%d)\n", llBytes, lpszDest, cchMax);
1555 LONGLONG ulNextDigit = ulKB % 10;
1556 *szOut-- = '0' + ulNextDigit;
1557 ulKB = (ulKB - ulNextDigit) / 10;
1560 strncpyW(lpszDest, szOut + 1, cchMax);
1564 /*************************************************************************
1565 * StrNCatA [SHLWAPI.@]
1567 * Concatenate two strings together.
1570 * lpszStr [O] String to concatenate to
1571 * lpszCat [I] String to add to lpszCat
1572 * cchMax [I] Maximum number of characters to concatenate
1578 * cchMax dtermines the number of characters that are appended to lpszStr,
1579 * not the total length of the string.
1581 LPSTR WINAPI StrNCatA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax)
1583 LPSTR lpszRet = lpszStr;
1585 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszCat), cchMax);
1589 WARN("Invalid lpszStr would crash under Win32!\n");
1593 StrCpyNA(lpszStr + strlen(lpszStr), lpszCat, cchMax);
1597 /*************************************************************************
1598 * StrNCatW [SHLWAPI.@]
1602 LPWSTR WINAPI StrNCatW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax)
1604 LPWSTR lpszRet = lpszStr;
1606 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszCat), cchMax);
1610 WARN("Invalid lpszStr would crash under Win32\n");
1614 StrCpyNW(lpszStr + strlenW(lpszStr), lpszCat, cchMax);
1618 /*************************************************************************
1619 * StrTrimA [SHLWAPI.@]
1621 * Remove characters from the start and end of a string.
1624 * lpszStr [O] String to remove characters from
1625 * lpszTrim [I] Characters to remove from lpszStr
1628 * TRUE If lpszStr was valid and modified
1631 BOOL WINAPI StrTrimA(LPSTR lpszStr, LPCSTR lpszTrim)
1634 LPSTR lpszRead = lpszStr;
1637 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszTrim));
1639 if (lpszRead && *lpszRead)
1641 while (*lpszRead && StrChrA(lpszTrim, *lpszRead))
1642 lpszRead = CharNextA(lpszRead); /* Skip leading matches */
1644 dwLen = strlen(lpszRead);
1646 if (lpszRead != lpszStr)
1648 memmove(lpszStr, lpszRead, dwLen + 1);
1653 lpszRead = lpszStr + dwLen;
1654 while (StrChrA(lpszTrim, lpszRead[-1]))
1655 lpszRead = CharPrevA(lpszStr, lpszRead); /* Skip trailing matches */
1657 if (lpszRead != lpszStr + dwLen)
1667 /*************************************************************************
1668 * StrTrimW [SHLWAPI.@]
1672 BOOL WINAPI StrTrimW(LPWSTR lpszStr, LPCWSTR lpszTrim)
1675 LPWSTR lpszRead = lpszStr;
1678 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszTrim));
1680 if (lpszRead && *lpszRead)
1682 while (*lpszRead && StrChrW(lpszTrim, *lpszRead))
1683 lpszRead = CharNextW(lpszRead); /* Skip leading matches */
1685 dwLen = strlenW(lpszRead);
1687 if (lpszRead != lpszStr)
1689 memmove(lpszStr, lpszRead, (dwLen + 1) * sizeof(WCHAR));
1694 lpszRead = lpszStr + dwLen;
1695 while (StrChrW(lpszTrim, lpszRead[-1]))
1696 lpszRead = CharPrevW(lpszStr, lpszRead); /* Skip trailing matches */
1698 if (lpszRead != lpszStr + dwLen)
1708 /*************************************************************************
1709 * _SHStrDupA [INTERNAL]
1711 * Duplicates a ASCII string to ASCII. The destination buffer is allocated.
1713 static HRESULT WINAPI _SHStrDupAA(LPCSTR src, LPSTR * dest)
1719 len = lstrlenA(src);
1720 *dest = CoTaskMemAlloc(len);
1726 lstrcpynA(*dest,src, len);
1732 TRACE("%s->(%p)\n", debugstr_a(src), *dest);
1736 /*************************************************************************
1739 * Return a Unicode copy of a string, in memory allocated by CoTaskMemAlloc.
1742 * lpszStr [I] String to copy
1743 * lppszDest [O] Destination for the new string copy
1746 * Success: S_OK. lppszDest contains the new string in Unicode format.
1747 * Failure: E_OUTOFMEMORY, If any arguments are invalid or memory allocation
1750 HRESULT WINAPI SHStrDupA(LPCSTR src, LPWSTR * dest)
1756 len = (MultiByteToWideChar(0,0,src,-1,0,0) + 1)* sizeof(WCHAR);
1757 *dest = CoTaskMemAlloc(len);
1763 MultiByteToWideChar(0,0,src,-1,*dest,len);
1769 TRACE("%s->(%p)\n", debugstr_a(src), *dest);
1773 /*************************************************************************
1774 * _SHStrDupAW [INTERNAL]
1776 * Duplicates a UNICODE to a ASCII string. The destination buffer is allocated.
1778 static HRESULT WINAPI _SHStrDupAW(LPCWSTR src, LPSTR * dest)
1784 len = WideCharToMultiByte(CP_ACP, 0, src, -1, NULL, 0, NULL, NULL);
1785 *dest = CoTaskMemAlloc(len);
1791 WideCharToMultiByte(CP_ACP, 0, src, -1, *dest, len, NULL, NULL);
1797 TRACE("%s->(%p)\n", debugstr_w(src), *dest);
1801 /*************************************************************************
1806 HRESULT WINAPI SHStrDupW(LPCWSTR src, LPWSTR * dest)
1812 len = (lstrlenW(src) + 1) * sizeof(WCHAR);
1813 *dest = CoTaskMemAlloc(len);
1819 memcpy(*dest, src, len);
1825 TRACE("%s->(%p)\n", debugstr_w(src), *dest);
1829 /*************************************************************************
1830 * SHLWAPI_WriteReverseNum
1832 * Internal helper for SHLWAPI_WriteTimeClass.
1834 inline static LPWSTR SHLWAPI_WriteReverseNum(LPWSTR lpszOut, DWORD dwNum)
1838 /* Write a decimal number to a string, backwards */
1841 DWORD dwNextDigit = dwNum % 10;
1842 *lpszOut-- = '0' + dwNextDigit;
1843 dwNum = (dwNum - dwNextDigit) / 10;
1844 } while (dwNum > 0);
1849 /*************************************************************************
1850 * SHLWAPI_FormatSignificant
1852 * Internal helper for SHLWAPI_WriteTimeClass.
1854 inline static int SHLWAPI_FormatSignificant(LPWSTR lpszNum, int dwDigits)
1856 /* Zero non significant digits, return remaining significant digits */
1860 if (--dwDigits == 0)
1870 /*************************************************************************
1871 * SHLWAPI_WriteTimeClass
1873 * Internal helper for StrFromTimeIntervalW.
1875 static int SHLWAPI_WriteTimeClass(LPWSTR lpszOut, DWORD dwValue,
1876 LPCWSTR lpszClass, int iDigits)
1878 WCHAR szBuff[64], *szOut = szBuff + 32;
1880 szOut = SHLWAPI_WriteReverseNum(szOut, dwValue);
1881 iDigits = SHLWAPI_FormatSignificant(szOut + 1, iDigits);
1883 strcpyW(szBuff + 32, lpszClass);
1884 strcatW(lpszOut, szOut);
1888 /*************************************************************************
1889 * StrFromTimeIntervalA [SHLWAPI.@]
1891 * Format a millisecond time interval into a string
1894 * lpszStr [O] Output buffer for formatted time interval
1895 * cchMax [I] Size of lpszStr
1896 * dwMS [I] Number of milliseconds
1897 * iDigits [I] Number of digits to print
1900 * The length of the formatted string, or 0 if any parameter is invalid.
1903 * This implementation mimics the Win32 behaviour of always writing a leading
1904 * space before the time interval begins.
1905 * iDigits is used to provide approximate times if accuracy is not important.
1906 * This number of digits will be written of the first non-zero time class
1907 * (hours/minutes/seconds). If this does not complete the time classification,
1908 * the remaining digits are changed to zeros (i.e. The time is _not_ rounded).
1909 * If there are digits remaining following the writing of a time class, the
1910 * next time class will be written.
1911 * For example, given dwMS represents 138 hours,43 minutes and 15 seconds, the
1912 * following will result from the given values of iDigits:
1914 * iDigits 1 2 3 4 5 ...
1915 * lpszStr "100 hr" "130 hr" "138 hr" "138 hr 40 min" "138 hr 43 min" ...
1917 INT WINAPI StrFromTimeIntervalA(LPSTR lpszStr, UINT cchMax, DWORD dwMS,
1922 TRACE("(%p,%d,%ld,%d)\n", lpszStr, cchMax, dwMS, iDigits);
1924 if (lpszStr && cchMax)
1927 StrFromTimeIntervalW(szBuff, sizeof(szBuff)/sizeof(WCHAR), dwMS, iDigits);
1928 WideCharToMultiByte(CP_ACP,0,szBuff,-1,lpszStr,cchMax,0,0);
1934 /*************************************************************************
1935 * StrFromTimeIntervalW [SHLWAPI.@]
1937 * See StrFromTimeIntervalA.
1939 INT WINAPI StrFromTimeIntervalW(LPWSTR lpszStr, UINT cchMax, DWORD dwMS,
1942 static const WCHAR szHr[] = {' ','h','r','\0'};
1943 static const WCHAR szMin[] = {' ','m','i','n','\0'};
1944 static const WCHAR szSec[] = {' ','s','e','c','\0'};
1947 TRACE("(%p,%d,%ld,%d)\n", lpszStr, cchMax, dwMS, iDigits);
1949 if (lpszStr && cchMax)
1952 DWORD dwHours, dwMinutes;
1954 if (!iDigits || cchMax == 1)
1960 /* Calculate the time classes */
1961 dwMS = (dwMS + 500) / 1000;
1962 dwHours = dwMS / 3600;
1963 dwMS -= dwHours * 3600;
1964 dwMinutes = dwMS / 60;
1965 dwMS -= dwMinutes * 60;
1970 iDigits = SHLWAPI_WriteTimeClass(szCopy, dwHours, szHr, iDigits);
1972 if (dwMinutes && iDigits)
1973 iDigits = SHLWAPI_WriteTimeClass(szCopy, dwMinutes, szMin, iDigits);
1975 if (iDigits) /* Always write seconds if we have significant digits */
1976 SHLWAPI_WriteTimeClass(szCopy, dwMS, szSec, iDigits);
1978 strncpyW(lpszStr, szCopy, cchMax);
1979 iRet = strlenW(lpszStr);
1984 /*************************************************************************
1985 * StrIsIntlEqualA [SHLWAPI.@]
1987 * Compare two strings.
1990 * bCase [I] Whether to compare case sensitively
1991 * lpszStr [I] First string to compare
1992 * lpszComp [I] Second string to compare
1993 * iLen [I] Length to compare
1996 * TRUE If the strings are equal.
1999 BOOL WINAPI StrIsIntlEqualA(BOOL bCase, LPCSTR lpszStr, LPCSTR lpszComp,
2002 DWORD dwFlags = LOCALE_USE_CP_ACP;
2005 TRACE("(%d,%s,%s,%d)\n", bCase,
2006 debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
2008 /* FIXME: These flags are undocumented and unknown by our CompareString.
2009 * We need defines for them.
2011 dwFlags |= bCase ? 0x10000000 : 0x10000001;
2013 iRet = CompareStringA(GetThreadLocale(),
2014 dwFlags, lpszStr, iLen, lpszComp, iLen);
2017 iRet = CompareStringA(2048, dwFlags, lpszStr, iLen, lpszComp, iLen);
2019 return iRet == 2 ? TRUE : FALSE;
2022 /*************************************************************************
2023 * StrIsIntlEqualW [SHLWAPI.@]
2025 * See StrIsIntlEqualA.
2027 BOOL WINAPI StrIsIntlEqualW(BOOL bCase, LPCWSTR lpszStr, LPCWSTR lpszComp,
2033 TRACE("(%d,%s,%s,%d)\n", bCase,
2034 debugstr_w(lpszStr),debugstr_w(lpszComp), iLen);
2036 /* FIXME: These flags are undocumented and unknown by our CompareString.
2037 * We need defines for them.
2039 dwFlags = bCase ? 0x10000000 : 0x10000001;
2041 iRet = CompareStringW(GetThreadLocale(),
2042 dwFlags, lpszStr, iLen, lpszComp, iLen);
2045 iRet = CompareStringW(2048, dwFlags, lpszStr, iLen, lpszComp, iLen);
2047 return iRet == 2 ? TRUE : FALSE;
2050 /*************************************************************************
2053 * Copy a string to another string, up to a maximum number of characters.
2056 * lpszDest [O] Destination string
2057 * lpszSrc [I] Source string
2058 * iLen [I] Maximum number of chars to copy
2061 * Success: A pointer to the last character written.
2062 * Failure: lpszDest, if any arguments are invalid.
2064 LPSTR WINAPI SHLWAPI_399(LPSTR lpszDest, LPCSTR lpszSrc, int iLen)
2066 TRACE("(%p,%s,%i)\n", lpszDest, debugstr_a(lpszSrc), iLen);
2068 if (lpszDest && lpszSrc && iLen > 0)
2070 while ((iLen-- > 1) && *lpszSrc)
2071 *lpszDest++ = *lpszSrc++;
2078 /*************************************************************************
2081 * Unicode version of SHLWAPI_399.
2083 LPWSTR WINAPI SHLWAPI_400(LPWSTR lpszDest, LPCWSTR lpszSrc, int iLen)
2085 TRACE("(%p,%s,%i)\n", lpszDest, debugstr_w(lpszSrc), iLen);
2087 if (lpszDest && lpszSrc && iLen > 0)
2089 while ((iLen-- > 1) && *lpszSrc)
2090 *lpszDest++ = *lpszSrc++;
2097 /*************************************************************************
2098 * StrCmpLogicalW [SHLWAPI.@]
2100 * Compare two strings, ignoring case and comparing digits as numbers.
2103 * lpszStr [I] First string to compare
2104 * lpszComp [I] Second string to compare
2105 * iLen [I] Length to compare
2108 * TRUE If the strings are equal.
2111 INT WINAPI StrCmpLogicalW(LPCWSTR lpszStr, LPCWSTR lpszComp)
2115 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszComp));
2117 if (lpszStr && lpszComp)
2123 else if (isdigitW(*lpszStr))
2127 if (!isdigitW(*lpszComp))
2130 /* Compare the numbers */
2131 StrToIntExW(lpszStr, 0, &iStr);
2132 StrToIntExW(lpszComp, 0, &iComp);
2136 else if (iStr > iComp)
2140 while (isdigitW(*lpszStr))
2142 while (isdigitW(*lpszComp))
2145 else if (isdigitW(*lpszComp))
2149 iDiff = SHLWAPI_ChrCmpHelperA(*lpszStr,*lpszComp,NORM_IGNORECASE);
2165 /* Structure for formatting byte strings */
2166 typedef struct tagSHLWAPI_BYTEFORMATS
2173 } SHLWAPI_BYTEFORMATS;
2175 /*************************************************************************
2176 * StrFormatByteSize64A [SHLWAPI.@]
2178 * Create a string containing an abbreviated byte count of up to 2^63-1.
2181 * llBytes [I] Byte size to format
2182 * lpszDest [I] Destination for formatted string
2183 * cchMax [I] Size of lpszDest
2189 * There is no StrFormatByteSize64W function, it is called StrFormatByteSizeW.
2191 LPSTR WINAPI StrFormatByteSize64A(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax)
2193 static const char szBytes[] = "%ld bytes";
2194 static const char sz3_0[] = "%3.0f";
2195 static const char sz3_1[] = "%3.1f";
2196 static const char sz3_2[] = "%3.2f";
2198 static const SHLWAPI_BYTEFORMATS bfFormats[] =
2200 { 10240, 10.24, 100.0, sz3_2, 'K' }, /* 10 KB */
2201 { 102400, 102.4, 10.0, sz3_1, 'K' }, /* 100 KB */
2202 { 1024000, 1024.0, 1.0, sz3_0, 'K' }, /* 1000 KB */
2203 { 10485760, 10485.76, 100.0, sz3_2, 'M' }, /* 10 MB */
2204 { 104857600, 104857.6, 10.0, sz3_1, 'M' }, /* 100 MB */
2205 { 1048576000, 1048576.0, 1.0, sz3_0, 'M' }, /* 1000 MB */
2206 { 10737418240, 10737418.24, 100.0, sz3_2, 'G' }, /* 10 GB */
2207 { 107374182400, 107374182.4, 10.0, sz3_1, 'G' }, /* 100 GB */
2208 { 1073741824000, 1073741824.0, 1.0, sz3_0, 'G' }, /* 1000 GB */
2209 { 10995116277760, 10485.76, 100.0, sz3_2, 'T' }, /* 10 TB */
2210 { 109951162777600, 104857.6, 10.0, sz3_1, 'T' }, /* 100 TB */
2211 { 1099511627776000, 1048576.0, 1.0, sz3_0, 'T' }, /* 1000 TB */
2212 { 11258999068426240, 10737418.24, 100.00, sz3_2, 'P' }, /* 10 PB */
2213 { 112589990684262400, 107374182.4, 10.00, sz3_1, 'P' }, /* 100 PB */
2214 { 1125899906842624000, 1073741824.0, 1.00, sz3_0, 'P' }, /* 1000 PB */
2215 { 0, 10995116277.76, 100.00, sz3_2, 'E' } /* EB's, catch all */
2222 TRACE("(%lld,%p,%d)\n", llBytes, lpszDest, cchMax);
2224 if (!lpszDest || !cchMax)
2227 if (llBytes < 1024) /* 1K */
2229 snprintf (lpszDest, cchMax, szBytes, (long)llBytes);
2233 /* Note that if this loop completes without finding a match, i will be
2234 * pointing at the last entry, which is a catch all for > 1000 PB
2236 while (i < sizeof(bfFormats) / sizeof(SHLWAPI_BYTEFORMATS) - 1)
2238 if (llBytes < bfFormats[i].dLimit)
2242 /* Above 1 TB we encounter problems with FP accuracy. So for amounts above
2243 * this number we integer shift down by 1 MB first. The table above has
2244 * the divisors scaled down from the '< 10 TB' entry onwards, to account
2245 * for this. We also add a small fudge factor to get the correct result for
2246 * counts that lie exactly on a 1024 byte boundary.
2249 dBytes = (double)(llBytes >> 20) + 0.001; /* Scale down by I MB */
2251 dBytes = (double)llBytes + 0.00001;
2253 dBytes = floor(dBytes / bfFormats[i].dDivisor) / bfFormats[i].dNormaliser;
2255 sprintf(szBuff, bfFormats[i].lpszFormat, dBytes);
2257 szAdd[1] = bfFormats[i].wPrefix;
2260 strcat(szBuff, szAdd);
2261 strncpy(lpszDest, szBuff, cchMax);
2265 /*************************************************************************
2266 * StrFormatByteSizeW [SHLWAPI.@]
2268 * See StrFormatByteSize64A.
2270 LPWSTR WINAPI StrFormatByteSizeW(LONGLONG llBytes, LPWSTR lpszDest,
2275 StrFormatByteSize64A(llBytes, szBuff, sizeof(szBuff));
2278 MultiByteToWideChar(CP_ACP, 0, szBuff, -1, lpszDest, cchMax);
2282 /*************************************************************************
2283 * StrFormatByteSizeA [SHLWAPI.@]
2285 * Create a string containing an abbreviated byte count of up to 2^31-1.
2288 * dwBytes [I] Byte size to format
2289 * lpszDest [I] Destination for formatted string
2290 * cchMax [I] Size of lpszDest
2296 * The ASCII and Unicode versions of this function accept a different
2297 * integer size for dwBytes. See StrFormatByteSize64A.
2299 LPSTR WINAPI StrFormatByteSizeA(DWORD dwBytes, LPSTR lpszDest, UINT cchMax)
2301 TRACE("(%ld,%p,%d)\n", dwBytes, lpszDest, cchMax);
2303 return StrFormatByteSize64A(dwBytes, lpszDest, cchMax);