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
23 #include "wine/port.h"
37 #define NO_SHLWAPI_STREAM
40 #include "wine/unicode.h"
41 #include "wine/debug.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(shell);
45 static HRESULT WINAPI _SHStrDupAA(LPCSTR src, LPSTR * dest);
46 static HRESULT WINAPI _SHStrDupAW(LPCWSTR src, LPSTR * dest);
48 /*************************************************************************
49 * SHLWAPI_ChrCmpHelperA
51 * Internal helper for SHLWAPI_ChrCmpA/ChrCMPIA.
54 * Both this function and its Unicode counterpart are very inneficient. To
55 * fix this, CompareString must be completely implemented and optimised
56 * first. Then the core character test can be taken out of that function and
57 * placed here, so that it need never be called at all. Until then, do not
58 * attempt to optimise this code unless you are willing to test that it
59 * still performs correctly.
61 static BOOL WINAPI SHLWAPI_ChrCmpHelperA(WORD ch1, WORD ch2, DWORD dwFlags)
63 char str1[3], str2[3];
65 str1[0] = LOBYTE(ch1);
66 if (IsDBCSLeadByte(ch1))
68 str1[1] = HIBYTE(ch1);
74 str2[0] = LOBYTE(ch2);
75 if (IsDBCSLeadByte(ch2))
77 str2[1] = HIBYTE(ch2);
83 return CompareStringA(GetThreadLocale(), dwFlags, str1, -1, str2, -1) - 2;
86 /*************************************************************************
87 * SHLWAPI_ChrCmpHelperW
89 * Internal helper for SHLWAPI_ChrCmpW/ChrCmpIW.
91 static BOOL WINAPI SHLWAPI_ChrCmpHelperW(WCHAR ch1, WCHAR ch2, DWORD dwFlags)
93 WCHAR str1[2], str2[2];
99 return CompareStringW(GetThreadLocale(), dwFlags, str1, 2, str2, 2) - 2;
102 /*************************************************************************
105 * Internal helper function.
107 static BOOL WINAPI SHLWAPI_ChrCmpA(WORD ch1, WORD ch2)
109 return SHLWAPI_ChrCmpHelperA(ch1, ch2, 0);
112 /*************************************************************************
113 * ChrCmpIA [SHLWAPI.385]
115 * Compare two characters, ignoring case.
118 * ch1 [I] First character to compare
119 * ch2 [I] Second character to compare
122 * FALSE, if the characters are equal.
123 * Non-zero otherwise.
125 BOOL WINAPI ChrCmpIA(WORD ch1, WORD ch2)
127 TRACE("(%d,%d)\n", ch1, ch2);
129 return SHLWAPI_ChrCmpHelperA(ch1, ch2, NORM_IGNORECASE);
132 /*************************************************************************
135 * Internal helper function.
137 static BOOL WINAPI SHLWAPI_ChrCmpW(WCHAR ch1, WCHAR ch2)
139 return SHLWAPI_ChrCmpHelperW(ch1, ch2, 0);
142 /*************************************************************************
143 * ChrCmpIW [SHLWAPI.386]
147 BOOL WINAPI ChrCmpIW(WCHAR ch1, WCHAR ch2)
149 return SHLWAPI_ChrCmpHelperW(ch1, ch2, NORM_IGNORECASE);
152 /*************************************************************************
153 * StrChrA [SHLWAPI.@]
155 * Find a given character in a string.
158 * lpszStr [I] String to search in.
159 * ch [I] Character to search for.
162 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
164 * Failure: NULL, if any arguments are invalid.
166 LPSTR WINAPI StrChrA(LPCSTR lpszStr, WORD ch)
168 TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch);
174 if (!SHLWAPI_ChrCmpA(*lpszStr, ch))
175 return (LPSTR)lpszStr;
176 lpszStr = CharNextA(lpszStr);
182 /*************************************************************************
183 * StrChrW [SHLWAPI.@]
187 LPWSTR WINAPI StrChrW(LPCWSTR lpszStr, WCHAR ch)
189 LPWSTR lpszRet = NULL;
191 TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch);
194 lpszRet = strchrW(lpszStr, ch);
198 /*************************************************************************
199 * StrChrIA [SHLWAPI.@]
201 * Find a given character in a string, ignoring case.
204 * lpszStr [I] String to search in.
205 * ch [I] Character to search for.
208 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
210 * Failure: NULL, if any arguments are invalid.
212 LPSTR WINAPI StrChrIA(LPCSTR lpszStr, WORD ch)
214 TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch);
220 if (!ChrCmpIA(*lpszStr, ch))
221 return (LPSTR)lpszStr;
222 lpszStr = CharNextA(lpszStr);
228 /*************************************************************************
229 * StrChrIW [SHLWAPI.@]
233 LPWSTR WINAPI StrChrIW(LPCWSTR lpszStr, WCHAR ch)
235 TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch);
242 if (toupperW(*lpszStr) == ch)
243 return (LPWSTR)lpszStr;
244 lpszStr = CharNextW(lpszStr);
248 return (LPWSTR)lpszStr;
251 /*************************************************************************
252 * StrCmpIW [SHLWAPI.@]
254 * Compare two strings, ignoring case.
257 * lpszStr [I] First string to compare
258 * lpszComp [I] Second string to compare
261 * An integer less than, equal to or greater than 0, indicating that
262 * lpszStr is less than, the same, or greater than lpszComp.
264 int WINAPI StrCmpIW(LPCWSTR lpszStr, LPCWSTR lpszComp)
268 TRACE("(%s,%s)\n", debugstr_w(lpszStr),debugstr_w(lpszComp));
270 iRet = strcmpiW(lpszStr, lpszComp);
271 return iRet < 0 ? -1 : iRet ? 1 : 0;
274 /*************************************************************************
275 * SHLWAPI_StrCmpNHelperA
277 * Internal helper for StrCmpNA/StrCmpNIA.
279 static INT WINAPI SHLWAPI_StrCmpNHelperA(LPCSTR lpszStr, LPCSTR lpszComp,
281 BOOL (WINAPI *pChrCmpFn)(WORD,WORD))
297 ch1 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr;
298 ch2 = IsDBCSLeadByte(*lpszComp)? *lpszComp << 8 | lpszComp[1] : *lpszComp;
300 if ((iDiff = pChrCmpFn(ch1, ch2)) < 0)
304 else if (!*lpszStr && !*lpszComp)
307 lpszStr = CharNextA(lpszStr);
308 lpszComp = CharNextA(lpszComp);
313 /*************************************************************************
314 * StrCmpNA [SHLWAPI.@]
316 * Compare two strings, up to a maximum length.
319 * lpszStr [I] First string to compare
320 * lpszComp [I] Second string to compare
321 * iLen [I] Maximum number of chars to compare.
324 * An integer less than, equal to or greater than 0, indicating that
325 * lpszStr is less than, the same, or greater than lpszComp.
327 INT WINAPI StrCmpNA(LPCSTR lpszStr, LPCSTR lpszComp, INT iLen)
329 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
331 return SHLWAPI_StrCmpNHelperA(lpszStr, lpszComp, iLen, SHLWAPI_ChrCmpA);
334 /*************************************************************************
335 * StrCmpNW [SHLWAPI.@]
339 INT WINAPI StrCmpNW(LPCWSTR lpszStr, LPCWSTR lpszComp, INT iLen)
343 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen);
345 iRet = strncmpW(lpszStr, lpszComp, iLen);
346 return iRet < 0 ? -1 : iRet ? 1 : 0;
349 /*************************************************************************
350 * StrCmpNIA [SHLWAPI.@]
352 * Compare two strings, up to a maximum length, ignoring case.
355 * lpszStr [I] First string to compare
356 * lpszComp [I] Second string to compare
357 * iLen [I] Maximum number of chars to compare.
360 * An integer less than, equal to or greater than 0, indicating that
361 * lpszStr is less than, the same, or greater than lpszComp.
364 * The Win32 version of this function is _completely_ broken for cases
365 * where iLen is greater than the length of lpszComp. Examples:
367 * StrCmpNIA("foo.gif", "foo", 5) is -1 under Win32; Should return 1.
368 * StrCmpNIA("\", "\\", 3) is 0 under Win32; Should return -1.
369 * StrCmpNIA("\", "\..\foo\", 3) is 1 under Win32; Should return -1.
371 * This implementation behaves correctly, since it is unlikely any
372 * applications actually rely on this function being broken.
374 int WINAPI StrCmpNIA(LPCSTR lpszStr, LPCSTR lpszComp, int iLen)
376 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
378 return SHLWAPI_StrCmpNHelperA(lpszStr, lpszComp, iLen, ChrCmpIA);
381 /*************************************************************************
382 * StrCmpNIW [SHLWAPI.@]
386 INT WINAPI StrCmpNIW(LPCWSTR lpszStr, LPCWSTR lpszComp, int iLen)
390 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen);
392 iRet = strncmpiW(lpszStr, lpszComp, iLen);
393 return iRet < 0 ? -1 : iRet ? 1 : 0;
396 /*************************************************************************
397 * StrCmpW [SHLWAPI.@]
399 * Compare two strings.
402 * lpszStr [I] First string to compare
403 * lpszComp [I] Second string to compare
406 * An integer less than, equal to or greater than 0, indicating that
407 * lpszStr is less than, the same, or greater than lpszComp.
409 int WINAPI StrCmpW(LPCWSTR lpszStr, LPCWSTR lpszComp)
413 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszComp));
415 iRet = strcmpW(lpszStr, lpszComp);
416 return iRet < 0 ? -1 : iRet ? 1 : 0;
419 /*************************************************************************
420 * StrCatW [SHLWAPI.@]
422 * Concatanate two strings.
425 * lpszStr [O] Initial string
426 * lpszSrc [I] String to concatanate
431 LPWSTR WINAPI StrCatW(LPWSTR lpszStr, LPCWSTR lpszSrc)
433 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSrc));
435 strcatW(lpszStr, lpszSrc);
439 /*************************************************************************
440 * StrCpyW [SHLWAPI.@]
442 * Copy a string to another string.
445 * lpszStr [O] Destination string
446 * lpszSrc [I] Source string
451 LPWSTR WINAPI StrCpyW(LPWSTR lpszStr, LPCWSTR lpszSrc)
453 TRACE("(%p,%s)\n", lpszStr, debugstr_w(lpszSrc));
455 strcpyW(lpszStr, lpszSrc);
459 /*************************************************************************
460 * StrCpyNW [SHLWAPI.@]
462 * Copy a string to another string, up to a maximum number of characters.
465 * lpszStr [O] Destination string
466 * lpszSrc [I] Source string
467 * iLen [I] Maximum number of chars to copy
472 LPWSTR WINAPI StrCpyNW(LPWSTR lpszStr, LPCWSTR lpszSrc, int iLen)
474 TRACE("(%p,%s,%i)\n", lpszStr, debugstr_w(lpszSrc), iLen);
476 lstrcpynW(lpszStr, lpszSrc, iLen);
482 /*************************************************************************
483 * SHLWAPI_StrStrHelperA
485 * Internal implementation of StrStrA/StrStrIA
487 static LPSTR WINAPI SHLWAPI_StrStrHelperA(LPCSTR lpszStr, LPCSTR lpszSearch,
488 int (*pStrCmpFn)(LPCSTR,LPCSTR,size_t))
492 if (!lpszStr || !lpszSearch || !*lpszSearch)
495 iLen = strlen(lpszSearch);
499 if (!pStrCmpFn(lpszStr, lpszSearch, iLen))
500 return (LPSTR)lpszStr;
501 lpszStr = CharNextA(lpszStr);
506 /*************************************************************************
507 * SHLWAPI_StrStrHelperW
509 * Internal implementation of StrStrW/StrStrIW
511 static LPWSTR WINAPI SHLWAPI_StrStrHelperW(LPCWSTR lpszStr, LPCWSTR lpszSearch,
512 int (*pStrCmpFn)(LPCWSTR,LPCWSTR,int))
516 if (!lpszStr || !lpszSearch || !*lpszSearch)
519 iLen = strlenW(lpszSearch);
523 if (!pStrCmpFn(lpszStr, lpszSearch, iLen))
524 return (LPWSTR)lpszStr;
525 lpszStr = CharNextW(lpszStr);
530 /*************************************************************************
531 * StrStrA [SHLWAPI.@]
533 * Find a substring within a string.
536 * lpszStr [I] String to search in
537 * lpszSearch [I] String to look for
540 * The start of lpszSearch within lpszStr, or NULL if not found.
542 LPSTR WINAPI StrStrA(LPCSTR lpszStr, LPCSTR lpszSearch)
544 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
546 return SHLWAPI_StrStrHelperA(lpszStr, lpszSearch, strncmp);
549 /*************************************************************************
550 * StrStrW [SHLWAPI.@]
554 LPWSTR WINAPI StrStrW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
556 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
558 return SHLWAPI_StrStrHelperW(lpszStr, lpszSearch, strncmpW);
561 /*************************************************************************
562 * StrRStrIA [SHLWAPI.@]
564 * Find the last occurence of a substring within a string.
567 * lpszStr [I] String to search in
568 * lpszEnd [I] End of lpszStr
569 * lpszSearch [I] String to look for
572 * The last occurence lpszSearch within lpszStr, or NULL if not found.
574 LPSTR WINAPI StrRStrIA(LPCSTR lpszStr, LPCSTR lpszEnd, LPCSTR lpszSearch)
576 LPSTR lpszRet = NULL;
580 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
582 if (!lpszStr || !lpszSearch || !*lpszSearch)
586 lpszEnd = lpszStr + lstrlenA(lpszStr);
588 if (IsDBCSLeadByte(*lpszSearch))
589 ch1 = *lpszSearch << 8 | lpszSearch[1];
592 iLen = lstrlenA(lpszSearch);
594 while (lpszStr <= lpszEnd && *lpszStr)
596 ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr;
597 if (!ChrCmpIA(ch1, ch2))
599 if (!StrCmpNIA(lpszStr, lpszSearch, iLen))
600 lpszRet = (LPSTR)lpszStr;
602 lpszStr = CharNextA(lpszStr);
607 /*************************************************************************
608 * StrRStrIW [SHLWAPI.@]
612 LPWSTR WINAPI StrRStrIW(LPCWSTR lpszStr, LPCWSTR lpszEnd, LPCWSTR lpszSearch)
614 LPWSTR lpszRet = NULL;
617 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
619 if (!lpszStr || !lpszSearch || !*lpszSearch)
623 lpszEnd = lpszStr + strlenW(lpszStr);
625 iLen = strlenW(lpszSearch);
627 while (lpszStr <= lpszEnd && *lpszStr)
629 if (!ChrCmpIA(*lpszSearch, *lpszStr))
631 if (!StrCmpNIW(lpszStr, lpszSearch, iLen))
632 lpszRet = (LPWSTR)lpszStr;
634 lpszStr = CharNextW(lpszStr);
639 /*************************************************************************
640 * StrStrIA [SHLWAPI.@]
642 * Find a substring within a string, ignoring case.
645 * lpszStr [I] String to search in
646 * lpszSearch [I] String to look for
649 * The start of lpszSearch within lpszStr, or NULL if not found.
651 LPSTR WINAPI StrStrIA(LPCSTR lpszStr, LPCSTR lpszSearch)
653 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
655 return SHLWAPI_StrStrHelperA(lpszStr, lpszSearch, strncasecmp);
658 /*************************************************************************
659 * StrStrIW [SHLWAPI.@]
663 LPWSTR WINAPI StrStrIW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
665 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
667 return SHLWAPI_StrStrHelperW(lpszStr, lpszSearch, strncmpiW);
670 /*************************************************************************
671 * StrToIntA [SHLWAPI.@]
673 * Read an integer from a string.
676 * lpszStr [I] String to read integer from
679 * The integer value represented by the string, or 0 if no integer is
683 * No leading space is allowed before the number, although a leading '-' is.
685 int WINAPI StrToIntA(LPCSTR lpszStr)
689 TRACE("(%s)\n", debugstr_a(lpszStr));
693 WARN("Invalid lpszStr would crash under Win32!\n");
697 if (*lpszStr == '-' || isdigit(*lpszStr))
698 StrToIntExA(lpszStr, 0, &iRet);
702 /*************************************************************************
703 * StrToIntW [SHLWAPI.@]
707 int WINAPI StrToIntW(LPCWSTR lpszStr)
711 TRACE("(%s)\n", debugstr_w(lpszStr));
715 WARN("Invalid lpszStr would crash under Win32!\n");
719 if (*lpszStr == '-' || isdigitW(*lpszStr))
720 StrToIntExW(lpszStr, 0, &iRet);
724 /*************************************************************************
725 * StrToIntExA [SHLWAPI.@]
727 * Read an integer from a string.
730 * lpszStr [I] String to read integer from
731 * dwFlags [I] Flags controlling the conversion
732 * lpiRet [O] Destination for read integer.
735 * Success: TRUE. lpiRet contains the integer value represented by the string.
736 * Failure: FALSE, if the string is invalid, or no number is present.
739 * Leading whitespace, '-' and '+' are allowed before the number. If
740 * dwFlags includes STIF_SUPPORT_HEX, hexidecimal numbers are allowed, if
741 * preceeded by '0x'. If this flag is not set, or there is no '0x' prefix,
742 * the string is treated as a decimal string. A leading '-' is ignored for
743 * hexidecimal numbers.
745 BOOL WINAPI StrToIntExA(LPCSTR lpszStr, DWORD dwFlags, LPINT lpiRet)
747 BOOL bNegative = FALSE;
750 TRACE("(%s,%08lX,%p)\n", debugstr_a(lpszStr), dwFlags, lpiRet);
752 if (!lpszStr || !lpiRet)
754 WARN("Invalid parameter would crash under Win32!\n");
757 if (dwFlags > STIF_SUPPORT_HEX)
759 WARN("Unknown flags (%08lX)!\n", dwFlags & ~STIF_SUPPORT_HEX);
762 /* Skip leading space, '+', '-' */
763 while (isspace(*lpszStr))
764 lpszStr = CharNextA(lpszStr);
771 else if (*lpszStr == '+')
774 if (dwFlags & STIF_SUPPORT_HEX &&
775 *lpszStr == '0' && tolower(lpszStr[1]) == 'x')
777 /* Read hex number */
780 if (!isxdigit(*lpszStr))
783 while (isxdigit(*lpszStr))
786 if (isdigit(*lpszStr))
787 iRet += (*lpszStr - '0');
789 iRet += 10 + (tolower(*lpszStr) - 'a');
796 /* Read decimal number */
797 if (!isdigit(*lpszStr))
800 while (isdigit(*lpszStr))
803 iRet += (*lpszStr - '0');
806 *lpiRet = bNegative ? -iRet : iRet;
810 /*************************************************************************
811 * StrToIntExW [SHLWAPI.@]
815 BOOL WINAPI StrToIntExW(LPCWSTR lpszStr, DWORD dwFlags, LPINT lpiRet)
817 BOOL bNegative = FALSE;
820 TRACE("(%s,%08lX,%p)\n", debugstr_w(lpszStr), dwFlags, lpiRet);
822 if (!lpszStr || !lpiRet)
824 WARN("Invalid parameter would crash under Win32!\n");
827 if (dwFlags > STIF_SUPPORT_HEX)
829 WARN("Unknown flags (%08lX)!\n", dwFlags & ~STIF_SUPPORT_HEX);
832 /* Skip leading space, '+', '-' */
833 while (isspaceW(*lpszStr))
834 lpszStr = CharNextW(lpszStr);
841 else if (*lpszStr == '+')
844 if (dwFlags & STIF_SUPPORT_HEX &&
845 *lpszStr == '0' && tolowerW(lpszStr[1]) == 'x')
847 /* Read hex number */
850 if (!isxdigitW(*lpszStr))
853 while (isxdigitW(*lpszStr))
856 if (isdigitW(*lpszStr))
857 iRet += (*lpszStr - '0');
859 iRet += 10 + (tolowerW(*lpszStr) - 'a');
866 /* Read decimal number */
867 if (!isdigitW(*lpszStr))
870 while (isdigitW(*lpszStr))
873 iRet += (*lpszStr - '0');
876 *lpiRet = bNegative ? -iRet : iRet;
880 /*************************************************************************
881 * StrDupA [SHLWAPI.@]
883 * Duplicate a string.
886 * lpszStr [I] String to duplicate.
889 * Success: A pointer to a new string containing the contents of lpszStr
890 * Failure: NULL, if memory cannot be allocated
893 * The string memory is allocated with LocalAlloc, and so should be released
894 * by calling LocalFree.
896 LPSTR WINAPI StrDupA(LPCSTR lpszStr)
901 TRACE("(%s)\n",debugstr_a(lpszStr));
903 iLen = lpszStr ? strlen(lpszStr) + 1 : 1;
904 lpszRet = (LPSTR)LocalAlloc(LMEM_FIXED, iLen);
909 memcpy(lpszRet, lpszStr, iLen);
916 /*************************************************************************
917 * StrDupW [SHLWAPI.@]
921 LPWSTR WINAPI StrDupW(LPCWSTR lpszStr)
926 TRACE("(%s)\n",debugstr_w(lpszStr));
928 iLen = (lpszStr ? strlenW(lpszStr) + 1 : 1) * sizeof(WCHAR);
929 lpszRet = (LPWSTR)LocalAlloc(LMEM_FIXED, iLen);
934 memcpy(lpszRet, lpszStr, iLen);
941 /*************************************************************************
942 * SHLWAPI_StrSpnHelperA
944 * Internal implementation of StrSpnA/StrCSpnA/StrCSpnIA
946 static int WINAPI SHLWAPI_StrSpnHelperA(LPCSTR lpszStr, LPCSTR lpszMatch,
947 LPSTR (WINAPI *pStrChrFn)(LPCSTR,WORD),
950 LPCSTR lpszRead = lpszStr;
951 if (lpszStr && *lpszStr && lpszMatch)
955 LPCSTR lpszTest = pStrChrFn(lpszMatch, *lpszRead);
957 if (!bInvert && !lpszTest)
959 if (bInvert && lpszTest)
961 lpszRead = CharNextA(lpszRead);
964 return lpszRead - lpszStr;
967 /*************************************************************************
968 * SHLWAPI_StrSpnHelperW
970 * Internal implementation of StrSpnW/StrCSpnW/StrCSpnIW
972 static int WINAPI SHLWAPI_StrSpnHelperW(LPCWSTR lpszStr, LPCWSTR lpszMatch,
973 LPWSTR (WINAPI *pStrChrFn)(LPCWSTR,WCHAR),
976 LPCWSTR lpszRead = lpszStr;
977 if (lpszStr && *lpszStr && lpszMatch)
981 LPCWSTR lpszTest = pStrChrFn(lpszMatch, *lpszRead);
983 if (!bInvert && !lpszTest)
985 if (bInvert && lpszTest)
987 lpszRead = CharNextW(lpszRead);
990 return lpszRead - lpszStr;
993 /*************************************************************************
994 * StrSpnA [SHLWAPI.@]
996 * Find the length of the start of a string that contains only certain
1000 * lpszStr [I] String to search
1001 * lpszMatch [I] Characters that can be in the substring
1004 * The length of the part of lpszStr containing only chars from lpszMatch,
1005 * or 0 if any parameter is invalid.
1007 int WINAPI StrSpnA(LPCSTR lpszStr, LPCSTR lpszMatch)
1009 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1011 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, FALSE);
1014 /*************************************************************************
1015 * StrSpnW [SHLWAPI.@]
1019 int WINAPI StrSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1021 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1023 return SHLWAPI_StrSpnHelperW(lpszStr, lpszMatch, StrChrW, FALSE);
1026 /*************************************************************************
1027 * StrCSpnA [SHLWAPI.@]
1029 * Find the length of the start of a string that does not contain certain
1033 * lpszStr [I] String to search
1034 * lpszMatch [I] Characters that cannot be in the substring
1037 * The length of the part of lpszStr containing only chars not in lpszMatch,
1038 * or 0 if any parameter is invalid.
1040 int WINAPI StrCSpnA(LPCSTR lpszStr, LPCSTR lpszMatch)
1042 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1044 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, TRUE);
1047 /*************************************************************************
1048 * StrCSpnW [SHLWAPI.@]
1052 int WINAPI StrCSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1054 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1056 return SHLWAPI_StrSpnHelperW(lpszStr, lpszMatch, StrChrW, TRUE);
1059 /*************************************************************************
1060 * StrCSpnIA [SHLWAPI.@]
1062 * Find the length of the start of a string that does not contain certain
1063 * characters, ignoring case.
1066 * lpszStr [I] String to search
1067 * lpszMatch [I] Characters that cannot be in the substring
1070 * The length of the part of lpszStr containing only chars not in lpszMatch,
1071 * or 0 if any parameter is invalid.
1073 int WINAPI StrCSpnIA(LPCSTR lpszStr, LPCSTR lpszMatch)
1075 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1077 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrIA, TRUE);
1080 /*************************************************************************
1081 * StrCSpnIW [SHLWAPI.@]
1085 int WINAPI StrCSpnIW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1087 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1089 return SHLWAPI_StrSpnHelperW(lpszStr, lpszMatch, StrChrIW, TRUE);
1092 /*************************************************************************
1093 * StrPBrkA [SHLWAPI.@]
1095 * Search a string for any of a group of characters.
1098 * lpszStr [I] String to search
1099 * lpszMatch [I] Characters to match
1102 * A pointer to the first matching character in lpszStr, or NULL if no
1105 LPSTR WINAPI StrPBrkA(LPCSTR lpszStr, LPCSTR lpszMatch)
1107 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1109 if (lpszStr && lpszMatch && *lpszMatch)
1113 if (StrChrA(lpszMatch, *lpszStr))
1114 return (LPSTR)lpszStr;
1115 lpszStr = CharNextA(lpszStr);
1121 /*************************************************************************
1122 * StrPBrkW [SHLWAPI.@]
1126 LPWSTR WINAPI StrPBrkW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1128 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1130 if (lpszStr && lpszMatch && *lpszMatch)
1134 if (StrChrW(lpszMatch, *lpszStr))
1135 return (LPWSTR)lpszStr;
1136 lpszStr = CharNextW(lpszStr);
1142 /*************************************************************************
1143 * SHLWAPI_StrRChrHelperA
1145 * Internal implementation of StrRChrA/StrRChrIA.
1147 static LPSTR WINAPI SHLWAPI_StrRChrHelperA(LPCSTR lpszStr,
1148 LPCSTR lpszEnd, WORD ch,
1149 BOOL (WINAPI *pChrCmpFn)(WORD,WORD))
1151 LPCSTR lpszRet = NULL;
1158 lpszEnd = lpszStr + lstrlenA(lpszStr);
1160 while (*lpszStr && lpszStr <= lpszEnd)
1162 ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr;
1164 if (!pChrCmpFn(ch, ch2))
1166 lpszStr = CharNextA(lpszStr);
1169 return (LPSTR)lpszRet;
1172 /*************************************************************************
1173 * SHLWAPI_StrRChrHelperW
1175 * Internal implementation of StrRChrW/StrRChrIW.
1177 static LPWSTR WINAPI SHLWAPI_StrRChrHelperW(LPCWSTR lpszStr,
1178 LPCWSTR lpszEnd, WCHAR ch,
1179 BOOL (WINAPI *pChrCmpFn)(WCHAR,WCHAR))
1181 LPCWSTR lpszRet = NULL;
1186 lpszEnd = lpszStr + strlenW(lpszStr);
1188 while (*lpszStr && lpszStr <= lpszEnd)
1190 if (!pChrCmpFn(ch, *lpszStr))
1192 lpszStr = CharNextW(lpszStr);
1195 return (LPWSTR)lpszRet;
1198 /**************************************************************************
1199 * StrRChrA [SHLWAPI.@]
1201 * Find the last occurence of a character in string.
1204 * lpszStr [I] String to search in
1205 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1206 * ch [I] Character to search for.
1209 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1210 * or NULL if not found.
1211 * Failure: NULL, if any arguments are invalid.
1213 LPSTR WINAPI StrRChrA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch)
1215 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch);
1217 return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, SHLWAPI_ChrCmpA);
1220 /**************************************************************************
1221 * StrRChrW [SHLWAPI.@]
1225 LPWSTR WINAPI StrRChrW(LPCWSTR lpszStr, LPCWSTR lpszEnd, WORD ch)
1227 TRACE("(%s,%s,%x)\n", debugstr_w(lpszStr), debugstr_w(lpszEnd), ch);
1229 return SHLWAPI_StrRChrHelperW(lpszStr, lpszEnd, ch, SHLWAPI_ChrCmpW);
1232 /**************************************************************************
1233 * StrRChrIA [SHLWAPI.@]
1235 * Find the last occurence of a character in string, ignoring case.
1238 * lpszStr [I] String to search in
1239 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1240 * ch [I] Character to search for.
1243 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1244 * or NULL if not found.
1245 * Failure: NULL, if any arguments are invalid.
1247 LPSTR WINAPI StrRChrIA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch)
1249 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch);
1251 return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, ChrCmpIA);
1254 /**************************************************************************
1255 * StrRChrIW [SHLWAPI.@]
1259 LPWSTR WINAPI StrRChrIW(LPCWSTR lpszStr, LPCWSTR lpszEnd, WORD ch)
1261 TRACE("(%s,%s,%x)\n", debugstr_w(lpszStr), debugstr_w(lpszEnd), ch);
1263 return SHLWAPI_StrRChrHelperW(lpszStr, lpszEnd, ch, ChrCmpIW);
1266 /*************************************************************************
1267 * StrCatBuffA [SHLWAPI.@]
1269 * Concatenate two strings together.
1272 * lpszStr [O] String to concatenate to
1273 * lpszCat [I] String to add to lpszCat
1274 * cchMax [I] Maximum number of characters for the whole string
1280 * cchMax dtermines the number of characters in the final length of the
1281 * string, not the number appended to lpszStr from lpszCat.
1283 LPSTR WINAPI StrCatBuffA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax)
1287 TRACE("(%p,%s,%d)\n", lpszStr, debugstr_a(lpszCat), cchMax);
1291 WARN("Invalid lpszStr would crash under Win32!\n");
1295 iLen = strlen(lpszStr);
1299 StrCpyNA(lpszStr + iLen, lpszCat, cchMax);
1303 /*************************************************************************
1304 * StrCatBuffW [SHLWAPI.@]
1308 LPWSTR WINAPI StrCatBuffW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax)
1312 TRACE("(%p,%s,%d)\n", lpszStr, debugstr_w(lpszCat), cchMax);
1316 WARN("Invalid lpszStr would crash under Win32!\n");
1320 iLen = strlenW(lpszStr);
1324 StrCpyNW(lpszStr + iLen, lpszCat, cchMax);
1328 /*************************************************************************
1329 * StrRetToBufA [SHLWAPI.@]
1331 * Convert a STRRET to a normal string.
1334 * lpStrRet [O] STRRET to convert
1335 * pIdl [I] ITEMIDLIST for lpStrRet->uType = STRRET_OFFSETA
1336 * lpszDest [O] Destination for normal string
1337 * dwLen [I] Length of lpszDest
1340 * Success: S_OK. lpszDest contains up to dwLen characters of the string.
1341 * If lpStrRet is of type STRRET_WSTR, its memory is freed with
1342 * CoTaskMemFree and its type set to STRRET_CSTRA.
1343 * Failure: E_FAIL, if any parameters are invalid.
1345 HRESULT WINAPI StrRetToBufA (LPSTRRET src, const ITEMIDLIST *pidl, LPSTR dest, DWORD len)
1348 * This routine is identical to that in dlls/shell32/shellstring.c.
1349 * It was duplicated because not every version of Shlwapi.dll exports
1350 * StrRetToBufA. If you change one routine, change them both.
1352 TRACE("dest=%p len=0x%lx strret=%p pidl=%p stub\n",dest,len,src,pidl);
1356 WARN("Invalid lpStrRet would crash under Win32!\n");
1370 WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, dest, len, NULL, NULL);
1371 CoTaskMemFree(src->u.pOleStr);
1375 lstrcpynA((LPSTR)dest, src->u.cStr, len);
1379 lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len);
1383 FIXME("unknown type!\n");
1389 /*************************************************************************
1390 * StrRetToBufW [SHLWAPI.@]
1394 HRESULT WINAPI StrRetToBufW (LPSTRRET src, const ITEMIDLIST *pidl, LPWSTR dest, DWORD len)
1396 TRACE("dest=%p len=0x%lx strret=%p pidl=%p stub\n",dest,len,src,pidl);
1400 WARN("Invalid lpStrRet would crash under Win32!\n");
1414 lstrcpynW((LPWSTR)dest, src->u.pOleStr, len);
1415 CoTaskMemFree(src->u.pOleStr);
1419 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
1426 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1,
1433 FIXME("unknown type!\n");
1439 /*************************************************************************
1440 * StrRetToStrA [SHLWAPI.@]
1442 * converts a STRRET to a normal string
1444 HRESULT WINAPI StrRetToStrA(LPSTRRET pstr, const ITEMIDLIST * pidl, LPSTR* ppszName)
1446 HRESULT ret = E_FAIL;
1448 switch (pstr->uType) {
1450 ret = _SHStrDupAW(pstr->u.pOleStr, ppszName);
1451 CoTaskMemFree(pstr->u.pOleStr);
1455 ret = _SHStrDupAA(pstr->u.cStr, ppszName);
1459 ret = _SHStrDupAA(((LPCSTR)&pidl->mkid)+pstr->u.uOffset, ppszName);
1468 /*************************************************************************
1469 * StrRetToStrW [SHLWAPI.@]
1471 * converts a STRRET to a normal string
1473 HRESULT WINAPI StrRetToStrW(LPSTRRET pstr, const ITEMIDLIST * pidl, LPWSTR* ppszName)
1475 HRESULT ret = E_FAIL;
1477 switch (pstr->uType) {
1479 ret = SHStrDupW(pstr->u.pOleStr, ppszName);
1480 CoTaskMemFree(pstr->u.pOleStr);
1484 ret = SHStrDupA(pstr->u.cStr, ppszName);
1488 ret = SHStrDupA(((LPCSTR)&pidl->mkid)+pstr->u.uOffset, ppszName);
1497 /*************************************************************************
1498 * StrFormatKBSizeA [SHLWAPI.@]
1500 * Create a formatted string containing a byte count in Kilobytes.
1503 * llBytes [I] Byte size to format
1504 * lpszDest [I] Destination for formatted string
1505 * cchMax [I] Size of lpszDest
1510 LPSTR WINAPI StrFormatKBSizeA(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax)
1512 char szBuff[256], *szOut = szBuff + sizeof(szBuff) - 1;
1513 LONGLONG ulKB = (llBytes + 1023) >> 10;
1515 TRACE("(%lld,%p,%d)\n", llBytes, lpszDest, cchMax);
1524 LONGLONG ulNextDigit = ulKB % 10;
1525 *szOut-- = '0' + ulNextDigit;
1526 ulKB = (ulKB - ulNextDigit) / 10;
1529 strncpy(lpszDest, szOut + 1, cchMax);
1533 /*************************************************************************
1534 * StrFormatKBSizeW [SHLWAPI.@]
1536 * See StrFormatKBSizeA.
1538 LPWSTR WINAPI StrFormatKBSizeW(LONGLONG llBytes, LPWSTR lpszDest, UINT cchMax)
1540 WCHAR szBuff[256], *szOut = szBuff + sizeof(szBuff) - 1;
1541 LONGLONG ulKB = (llBytes + 1023) >> 10;
1543 TRACE("(%lld,%p,%d)\n", llBytes, lpszDest, cchMax);
1552 LONGLONG ulNextDigit = ulKB % 10;
1553 *szOut-- = '0' + ulNextDigit;
1554 ulKB = (ulKB - ulNextDigit) / 10;
1557 strncpyW(lpszDest, szOut + 1, cchMax);
1561 /*************************************************************************
1562 * StrNCatA [SHLWAPI.@]
1564 * Concatenate two strings together.
1567 * lpszStr [O] String to concatenate to
1568 * lpszCat [I] String to add to lpszCat
1569 * cchMax [I] Maximum number of characters to concatenate
1575 * cchMax dtermines the number of characters that are appended to lpszStr,
1576 * not the total length of the string.
1578 LPSTR WINAPI StrNCatA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax)
1580 LPSTR lpszRet = lpszStr;
1582 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszCat), cchMax);
1586 WARN("Invalid lpszStr would crash under Win32!\n");
1590 StrCpyNA(lpszStr + strlen(lpszStr), lpszCat, cchMax);
1594 /*************************************************************************
1595 * StrNCatW [SHLWAPI.@]
1599 LPWSTR WINAPI StrNCatW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax)
1601 LPWSTR lpszRet = lpszStr;
1603 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszCat), cchMax);
1607 WARN("Invalid lpszStr would crash under Win32\n");
1611 StrCpyNW(lpszStr + strlenW(lpszStr), lpszCat, cchMax);
1615 /*************************************************************************
1616 * StrTrimA [SHLWAPI.@]
1618 * Remove characters from the start and end of a string.
1621 * lpszStr [O] String to remove characters from
1622 * lpszTrim [I] Characters to remove from lpszStr
1625 * TRUE If lpszStr was valid and modified
1628 BOOL WINAPI StrTrimA(LPSTR lpszStr, LPCSTR lpszTrim)
1631 LPSTR lpszRead = lpszStr;
1634 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszTrim));
1636 if (lpszRead && *lpszRead)
1638 while (*lpszRead && StrChrA(lpszTrim, *lpszRead))
1639 lpszRead = CharNextA(lpszRead); /* Skip leading matches */
1641 dwLen = strlen(lpszRead);
1643 if (lpszRead != lpszStr)
1645 memmove(lpszStr, lpszRead, dwLen + 1);
1650 lpszRead = lpszStr + dwLen;
1651 while (StrChrA(lpszTrim, lpszRead[-1]))
1652 lpszRead = CharPrevA(lpszStr, lpszRead); /* Skip trailing matches */
1654 if (lpszRead != lpszStr + dwLen)
1664 /*************************************************************************
1665 * StrTrimW [SHLWAPI.@]
1669 BOOL WINAPI StrTrimW(LPWSTR lpszStr, LPCWSTR lpszTrim)
1672 LPWSTR lpszRead = lpszStr;
1675 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszTrim));
1677 if (lpszRead && *lpszRead)
1679 while (*lpszRead && StrChrW(lpszTrim, *lpszRead))
1680 lpszRead = CharNextW(lpszRead); /* Skip leading matches */
1682 dwLen = strlenW(lpszRead);
1684 if (lpszRead != lpszStr)
1686 memmove(lpszStr, lpszRead, (dwLen + 1) * sizeof(WCHAR));
1691 lpszRead = lpszStr + dwLen;
1692 while (StrChrW(lpszTrim, lpszRead[-1]))
1693 lpszRead = CharPrevW(lpszStr, lpszRead); /* Skip trailing matches */
1695 if (lpszRead != lpszStr + dwLen)
1705 /*************************************************************************
1706 * _SHStrDupA [INTERNAL]
1708 * Duplicates a ASCII string to ASCII. The destination buffer is allocated.
1710 static HRESULT WINAPI _SHStrDupAA(LPCSTR src, LPSTR * dest)
1716 len = lstrlenA(src);
1717 *dest = CoTaskMemAlloc(len);
1723 lstrcpynA(*dest,src, len);
1729 TRACE("%s->(%p)\n", debugstr_a(src), *dest);
1733 /*************************************************************************
1736 * Return a Unicode copy of a string, in memory allocated by CoTaskMemAlloc.
1739 * lpszStr [I] String to copy
1740 * lppszDest [O] Destination for the new string copy
1743 * Success: S_OK. lppszDest contains the new string in Unicode format.
1744 * Failure: E_OUTOFMEMORY, If any arguments are invalid or memory allocation
1747 HRESULT WINAPI SHStrDupA(LPCSTR src, LPWSTR * dest)
1753 len = (MultiByteToWideChar(0,0,src,-1,0,0) + 1)* sizeof(WCHAR);
1754 *dest = CoTaskMemAlloc(len);
1760 MultiByteToWideChar(0,0,src,-1,*dest,len);
1766 TRACE("%s->(%p)\n", debugstr_a(src), *dest);
1770 /*************************************************************************
1771 * _SHStrDupAW [INTERNAL]
1773 * Duplicates a UNICODE to a ASCII string. The destination buffer is allocated.
1775 static HRESULT WINAPI _SHStrDupAW(LPCWSTR src, LPSTR * dest)
1781 len = WideCharToMultiByte(CP_ACP, 0, src, -1, NULL, 0, NULL, NULL);
1782 *dest = CoTaskMemAlloc(len);
1788 WideCharToMultiByte(CP_ACP, 0, src, -1, *dest, len, NULL, NULL);
1794 TRACE("%s->(%p)\n", debugstr_w(src), *dest);
1798 /*************************************************************************
1803 HRESULT WINAPI SHStrDupW(LPCWSTR src, LPWSTR * dest)
1809 len = (lstrlenW(src) + 1) * sizeof(WCHAR);
1810 *dest = CoTaskMemAlloc(len);
1816 memcpy(*dest, src, len);
1822 TRACE("%s->(%p)\n", debugstr_w(src), *dest);
1826 /*************************************************************************
1827 * SHLWAPI_WriteReverseNum
1829 * Internal helper for SHLWAPI_WriteTimeClass.
1831 inline static LPWSTR SHLWAPI_WriteReverseNum(LPWSTR lpszOut, DWORD dwNum)
1835 /* Write a decimal number to a string, backwards */
1838 DWORD dwNextDigit = dwNum % 10;
1839 *lpszOut-- = '0' + dwNextDigit;
1840 dwNum = (dwNum - dwNextDigit) / 10;
1841 } while (dwNum > 0);
1846 /*************************************************************************
1847 * SHLWAPI_FormatSignificant
1849 * Internal helper for SHLWAPI_WriteTimeClass.
1851 inline static int SHLWAPI_FormatSignificant(LPWSTR lpszNum, int dwDigits)
1853 /* Zero non significant digits, return remaining significant digits */
1857 if (--dwDigits == 0)
1867 /*************************************************************************
1868 * SHLWAPI_WriteTimeClass
1870 * Internal helper for StrFromTimeIntervalW.
1872 static int SHLWAPI_WriteTimeClass(LPWSTR lpszOut, DWORD dwValue,
1873 LPCWSTR lpszClass, int iDigits)
1875 WCHAR szBuff[64], *szOut = szBuff + 32;
1877 szOut = SHLWAPI_WriteReverseNum(szOut, dwValue);
1878 iDigits = SHLWAPI_FormatSignificant(szOut + 1, iDigits);
1880 strcpyW(szBuff + 32, lpszClass);
1881 strcatW(lpszOut, szOut);
1885 /*************************************************************************
1886 * StrFromTimeIntervalA [SHLWAPI.@]
1888 * Format a millisecond time interval into a string
1891 * lpszStr [O] Output buffer for formatted time interval
1892 * cchMax [I] Size of lpszStr
1893 * dwMS [I] Number of milliseconds
1894 * iDigits [I] Number of digits to print
1897 * The length of the formatted string, or 0 if any parameter is invalid.
1900 * This implementation mimics the Win32 behaviour of always writing a leading
1901 * space before the time interval begins.
1902 * iDigits is used to provide approximate times if accuracy is not important.
1903 * This number of digits will be written of the first non-zero time class
1904 * (hours/minutes/seconds). If this does not complete the time classification,
1905 * the remaining digits are changed to zeros (i.e. The time is _not_ rounded).
1906 * If there are digits remaining following the writing of a time class, the
1907 * next time class will be written.
1908 * For example, given dwMS represents 138 hours,43 minutes and 15 seconds, the
1909 * following will result from the given values of iDigits:
1911 * iDigits 1 2 3 4 5 ...
1912 * lpszStr "100 hr" "130 hr" "138 hr" "138 hr 40 min" "138 hr 43 min" ...
1914 INT WINAPI StrFromTimeIntervalA(LPSTR lpszStr, UINT cchMax, DWORD dwMS,
1919 TRACE("(%p,%d,%ld,%d)\n", lpszStr, cchMax, dwMS, iDigits);
1921 if (lpszStr && cchMax)
1924 StrFromTimeIntervalW(szBuff, sizeof(szBuff)/sizeof(WCHAR), dwMS, iDigits);
1925 WideCharToMultiByte(CP_ACP,0,szBuff,-1,lpszStr,cchMax,0,0);
1931 /*************************************************************************
1932 * StrFromTimeIntervalW [SHLWAPI.@]
1934 * See StrFromTimeIntervalA.
1936 INT WINAPI StrFromTimeIntervalW(LPWSTR lpszStr, UINT cchMax, DWORD dwMS,
1939 static const WCHAR szHr[] = {' ','h','r','\0'};
1940 static const WCHAR szMin[] = {' ','m','i','n','\0'};
1941 static const WCHAR szSec[] = {' ','s','e','c','\0'};
1944 TRACE("(%p,%d,%ld,%d)\n", lpszStr, cchMax, dwMS, iDigits);
1946 if (lpszStr && cchMax)
1949 DWORD dwHours, dwMinutes;
1951 if (!iDigits || cchMax == 1)
1957 /* Calculate the time classes */
1958 dwMS = (dwMS + 500) / 1000;
1959 dwHours = dwMS / 3600;
1960 dwMS -= dwHours * 3600;
1961 dwMinutes = dwMS / 60;
1962 dwMS -= dwMinutes * 60;
1967 iDigits = SHLWAPI_WriteTimeClass(szCopy, dwHours, szHr, iDigits);
1969 if (dwMinutes && iDigits)
1970 iDigits = SHLWAPI_WriteTimeClass(szCopy, dwMinutes, szMin, iDigits);
1972 if (iDigits) /* Always write seconds if we have significant digits */
1973 SHLWAPI_WriteTimeClass(szCopy, dwMS, szSec, iDigits);
1975 strncpyW(lpszStr, szCopy, cchMax);
1976 iRet = strlenW(lpszStr);
1981 /*************************************************************************
1982 * StrIsIntlEqualA [SHLWAPI.@]
1984 * Compare two strings.
1987 * bCase [I] Whether to compare case sensitively
1988 * lpszStr [I] First string to compare
1989 * lpszComp [I] Second string to compare
1990 * iLen [I] Length to compare
1993 * TRUE If the strings are equal.
1996 BOOL WINAPI StrIsIntlEqualA(BOOL bCase, LPCSTR lpszStr, LPCSTR lpszComp,
1999 DWORD dwFlags = LOCALE_USE_CP_ACP;
2002 TRACE("(%d,%s,%s,%d)\n", bCase,
2003 debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
2005 /* FIXME: These flags are undocumented and unknown by our CompareString.
2006 * We need defines for them.
2008 dwFlags |= bCase ? 0x10000000 : 0x10000001;
2010 iRet = CompareStringA(GetThreadLocale(),
2011 dwFlags, lpszStr, iLen, lpszComp, iLen);
2014 iRet = CompareStringA(2048, dwFlags, lpszStr, iLen, lpszComp, iLen);
2016 return iRet == 2 ? TRUE : FALSE;
2019 /*************************************************************************
2020 * StrIsIntlEqualW [SHLWAPI.@]
2022 * See StrIsIntlEqualA.
2024 BOOL WINAPI StrIsIntlEqualW(BOOL bCase, LPCWSTR lpszStr, LPCWSTR lpszComp,
2030 TRACE("(%d,%s,%s,%d)\n", bCase,
2031 debugstr_w(lpszStr),debugstr_w(lpszComp), iLen);
2033 /* FIXME: These flags are undocumented and unknown by our CompareString.
2034 * We need defines for them.
2036 dwFlags = bCase ? 0x10000000 : 0x10000001;
2038 iRet = CompareStringW(GetThreadLocale(),
2039 dwFlags, lpszStr, iLen, lpszComp, iLen);
2042 iRet = CompareStringW(2048, dwFlags, lpszStr, iLen, lpszComp, iLen);
2044 return iRet == 2 ? TRUE : FALSE;
2047 /*************************************************************************
2050 * Copy a string to another string, up to a maximum number of characters.
2053 * lpszDest [O] Destination string
2054 * lpszSrc [I] Source string
2055 * iLen [I] Maximum number of chars to copy
2058 * Success: A pointer to the last character written.
2059 * Failure: lpszDest, if any arguments are invalid.
2061 LPSTR WINAPI SHLWAPI_399(LPSTR lpszDest, LPCSTR lpszSrc, int iLen)
2063 TRACE("(%p,%s,%i)\n", lpszDest, debugstr_a(lpszSrc), iLen);
2065 if (lpszDest && lpszSrc && iLen > 0)
2067 while ((iLen-- > 1) && *lpszSrc)
2068 *lpszDest++ = *lpszSrc++;
2075 /*************************************************************************
2078 * Unicode version of SHLWAPI_399.
2080 LPWSTR WINAPI SHLWAPI_400(LPWSTR lpszDest, LPCWSTR lpszSrc, int iLen)
2082 TRACE("(%p,%s,%i)\n", lpszDest, debugstr_w(lpszSrc), iLen);
2084 if (lpszDest && lpszSrc && iLen > 0)
2086 while ((iLen-- > 1) && *lpszSrc)
2087 *lpszDest++ = *lpszSrc++;
2094 /*************************************************************************
2095 * StrCmpLogicalW [SHLWAPI.@]
2097 * Compare two strings, ignoring case and comparing digits as numbers.
2100 * lpszStr [I] First string to compare
2101 * lpszComp [I] Second string to compare
2102 * iLen [I] Length to compare
2105 * TRUE If the strings are equal.
2108 INT WINAPI StrCmpLogicalW(LPCWSTR lpszStr, LPCWSTR lpszComp)
2112 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszComp));
2114 if (lpszStr && lpszComp)
2120 else if (isdigitW(*lpszStr))
2124 if (!isdigitW(*lpszComp))
2127 /* Compare the numbers */
2128 StrToIntExW(lpszStr, 0, &iStr);
2129 StrToIntExW(lpszComp, 0, &iComp);
2133 else if (iStr > iComp)
2137 while (isdigitW(*lpszStr))
2139 while (isdigitW(*lpszComp))
2142 else if (isdigitW(*lpszComp))
2146 iDiff = SHLWAPI_ChrCmpHelperA(*lpszStr,*lpszComp,NORM_IGNORECASE);
2162 /* Structure for formatting byte strings */
2163 typedef struct tagSHLWAPI_BYTEFORMATS
2170 } SHLWAPI_BYTEFORMATS;
2172 /*************************************************************************
2173 * StrFormatByteSize64A [SHLWAPI.@]
2175 * Create a string containing an abbreviated byte count of up to 2^63-1.
2178 * llBytes [I] Byte size to format
2179 * lpszDest [I] Destination for formatted string
2180 * cchMax [I] Size of lpszDest
2186 * There is no StrFormatByteSize64W function, it is called StrFormatByteSizeW.
2188 LPSTR WINAPI StrFormatByteSize64A(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax)
2190 static const char szBytes[] = "%ld bytes";
2191 static const char sz3_0[] = "%3.0f";
2192 static const char sz3_1[] = "%3.1f";
2193 static const char sz3_2[] = "%3.2f";
2195 static const SHLWAPI_BYTEFORMATS bfFormats[] =
2197 { 10240, 10.24, 100.0, sz3_2, 'K' }, /* 10 KB */
2198 { 102400, 102.4, 10.0, sz3_1, 'K' }, /* 100 KB */
2199 { 1024000, 1024.0, 1.0, sz3_0, 'K' }, /* 1000 KB */
2200 { 10485760, 10485.76, 100.0, sz3_2, 'M' }, /* 10 MB */
2201 { 104857600, 104857.6, 10.0, sz3_1, 'M' }, /* 100 MB */
2202 { 1048576000, 1048576.0, 1.0, sz3_0, 'M' }, /* 1000 MB */
2203 { 10737418240, 10737418.24, 100.0, sz3_2, 'G' }, /* 10 GB */
2204 { 107374182400, 107374182.4, 10.0, sz3_1, 'G' }, /* 100 GB */
2205 { 1073741824000, 1073741824.0, 1.0, sz3_0, 'G' }, /* 1000 GB */
2206 { 10995116277760, 10485.76, 100.0, sz3_2, 'T' }, /* 10 TB */
2207 { 109951162777600, 104857.6, 10.0, sz3_1, 'T' }, /* 100 TB */
2208 { 1099511627776000, 1048576.0, 1.0, sz3_0, 'T' }, /* 1000 TB */
2209 { 11258999068426240, 10737418.24, 100.00, sz3_2, 'P' }, /* 10 PB */
2210 { 112589990684262400, 107374182.4, 10.00, sz3_1, 'P' }, /* 100 PB */
2211 { 1125899906842624000, 1073741824.0, 1.00, sz3_0, 'P' }, /* 1000 PB */
2212 { 0, 10995116277.76, 100.00, sz3_2, 'E' } /* EB's, catch all */
2219 TRACE("(%lld,%p,%d)\n", llBytes, lpszDest, cchMax);
2221 if (!lpszDest || !cchMax)
2224 if (llBytes < 1024) /* 1K */
2226 snprintf (lpszDest, cchMax, szBytes, (long)llBytes);
2230 /* Note that if this loop completes without finding a match, i will be
2231 * pointing at the last entry, which is a catch all for > 1000 PB
2233 while (i < sizeof(bfFormats) / sizeof(SHLWAPI_BYTEFORMATS) - 1)
2235 if (llBytes < bfFormats[i].dLimit)
2239 /* Above 1 TB we encounter problems with FP accuracy. So for amounts above
2240 * this number we integer shift down by 1 MB first. The table above has
2241 * the divisors scaled down from the '< 10 TB' entry onwards, to account
2242 * for this. We also add a small fudge factor to get the correct result for
2243 * counts that lie exactly on a 1024 byte boundary.
2246 dBytes = (double)(llBytes >> 20) + 0.001; /* Scale down by I MB */
2248 dBytes = (double)llBytes + 0.00001;
2250 dBytes = floor(dBytes / bfFormats[i].dDivisor) / bfFormats[i].dNormaliser;
2252 sprintf(szBuff, bfFormats[i].lpszFormat, dBytes);
2254 szAdd[1] = bfFormats[i].wPrefix;
2257 strcat(szBuff, szAdd);
2258 strncpy(lpszDest, szBuff, cchMax);
2262 /*************************************************************************
2263 * StrFormatByteSizeW [SHLWAPI.@]
2265 * See StrFormatByteSize64A.
2267 LPWSTR WINAPI StrFormatByteSizeW(LONGLONG llBytes, LPWSTR lpszDest,
2272 StrFormatByteSize64A(llBytes, szBuff, sizeof(szBuff));
2275 MultiByteToWideChar(CP_ACP, 0, szBuff, -1, lpszDest, cchMax);
2279 /*************************************************************************
2280 * StrFormatByteSizeA [SHLWAPI.@]
2282 * Create a string containing an abbreviated byte count of up to 2^31-1.
2285 * dwBytes [I] Byte size to format
2286 * lpszDest [I] Destination for formatted string
2287 * cchMax [I] Size of lpszDest
2293 * The ASCII and Unicode versions of this function accept a different
2294 * integer size for dwBytes. See StrFormatByteSize64A.
2296 LPSTR WINAPI StrFormatByteSizeA(DWORD dwBytes, LPSTR lpszDest, UINT cchMax)
2298 TRACE("(%ld,%p,%d)\n", dwBytes, lpszDest, cchMax);
2300 return StrFormatByteSize64A(dwBytes, lpszDest, cchMax);