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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #define COM_NO_WINDOWS_H
24 #include "wine/port.h"
31 #define NONAMELESSUNION
32 #define NONAMELESSSTRUCT
35 #define NO_SHLWAPI_REG
36 #define NO_SHLWAPI_STREAM
42 #include "wine/unicode.h"
43 #include "wine/debug.h"
47 WINE_DEFAULT_DEBUG_CHANNEL(shell);
49 /* Get a function pointer from a DLL handle */
50 #define GET_FUNC(func, module, name, fail) \
53 if (!SHLWAPI_h##module && !(SHLWAPI_h##module = LoadLibraryA(#module ".dll"))) return fail; \
54 func = (fn##func)GetProcAddress(SHLWAPI_h##module, name); \
55 if (!func) return fail; \
59 extern HMODULE SHLWAPI_hmlang;
60 extern HINSTANCE shlwapi_hInstance;
62 typedef HRESULT (WINAPI *fnpConvertINetUnicodeToMultiByte)(LPDWORD,DWORD,LPCWSTR,LPINT,LPSTR,LPINT);
63 static fnpConvertINetUnicodeToMultiByte pConvertINetUnicodeToMultiByte;
65 static HRESULT WINAPI _SHStrDupAA(LPCSTR,LPSTR*);
66 static HRESULT WINAPI _SHStrDupAW(LPCWSTR,LPSTR*);
69 static void FillNumberFmt(NUMBERFMTW *fmt, WCHAR decimal_buffer[8], WCHAR thousand_buffer[8])
74 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_ILZERO|LOCALE_RETURN_NUMBER, (LPWSTR)&fmt->LeadingZero, sizeof(fmt->LeadingZero)/sizeof(WCHAR));
75 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_INEGNUMBER|LOCALE_RETURN_NUMBER, (LPWSTR)&fmt->LeadingZero, sizeof(fmt->NegativeOrder)/sizeof(WCHAR));
77 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, decimal_buffer, sizeof(decimal_buffer)/sizeof(WCHAR));
78 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, thousand_buffer, sizeof(thousand_buffer)/sizeof(WCHAR));
79 fmt->lpThousandSep = thousand_buffer;
80 fmt->lpDecimalSep = decimal_buffer;
83 * Converting grouping string to number as described on
84 * http://blogs.msdn.com/oldnewthing/archive/2006/04/18/578251.aspx
87 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SGROUPING, grouping, sizeof(grouping)/sizeof(WCHAR));
88 for (c = grouping; *c; c++)
89 if (*c >= '0' && *c < '9')
92 fmt->Grouping += *c - '0';
95 if (fmt->Grouping % 10 == 0)
101 /*************************************************************************
102 * FormatInt [internal]
104 * Format an integer according to the current locale
107 * The number of bytes written on success or 0 on failure
109 static int FormatInt(LONGLONG qdwValue, LPWSTR pszBuf, int cchBuf)
112 WCHAR decimal[8], thousand[8];
115 BOOL neg = (qdwValue < 0);
117 FillNumberFmt(&fmt, decimal, thousand);
123 *(--c) = '0' + (qdwValue%10);
125 } while (qdwValue > 0);
129 return GetNumberFormatW(LOCALE_USER_DEFAULT, 0, c, &fmt, pszBuf, cchBuf);
132 /*************************************************************************
133 * FormatDouble [internal]
135 * Format an integer according to the current locale. Prints the specified number of digits
136 * after the decimal point
139 * The number of bytes written on success or 0 on failure
141 static int FormatDouble(double value, int decimals, LPWSTR pszBuf, int cchBuf)
143 static const WCHAR flfmt[] = {'%','f',0};
146 WCHAR decimal[8], thousand[8];
148 snprintfW(buf, 64, flfmt, value);
150 FillNumberFmt(&fmt, decimal, thousand);
151 fmt.NumDigits = decimals;
152 return GetNumberFormatW(LOCALE_USER_DEFAULT, 0, buf, &fmt, pszBuf, cchBuf);
155 /*************************************************************************
156 * SHLWAPI_ChrCmpHelperA
158 * Internal helper for SHLWAPI_ChrCmpA/ChrCMPIA.
161 * Both this function and its Unicode counterpart are very inneficient. To
162 * fix this, CompareString must be completely implemented and optimised
163 * first. Then the core character test can be taken out of that function and
164 * placed here, so that it need never be called at all. Until then, do not
165 * attempt to optimise this code unless you are willing to test that it
166 * still performs correctly.
168 static BOOL WINAPI SHLWAPI_ChrCmpHelperA(WORD ch1, WORD ch2, DWORD dwFlags)
170 char str1[3], str2[3];
172 str1[0] = LOBYTE(ch1);
173 if (IsDBCSLeadByte(str1[0]))
175 str1[1] = HIBYTE(ch1);
181 str2[0] = LOBYTE(ch2);
182 if (IsDBCSLeadByte(str2[0]))
184 str2[1] = HIBYTE(ch2);
190 return CompareStringA(GetThreadLocale(), dwFlags, str1, -1, str2, -1) - 2;
193 /*************************************************************************
194 * SHLWAPI_ChrCmpHelperW
196 * Internal helper for SHLWAPI_ChrCmpW/ChrCmpIW.
198 static BOOL WINAPI SHLWAPI_ChrCmpHelperW(WCHAR ch1, WCHAR ch2, DWORD dwFlags)
200 WCHAR str1[2], str2[2];
206 return CompareStringW(GetThreadLocale(), dwFlags, str1, 2, str2, 2) - 2;
209 /*************************************************************************
212 * Internal helper function.
214 static BOOL WINAPI SHLWAPI_ChrCmpA(WORD ch1, WORD ch2)
216 return SHLWAPI_ChrCmpHelperA(ch1, ch2, 0);
219 /*************************************************************************
220 * ChrCmpIA (SHLWAPI.385)
222 * Compare two characters, ignoring case.
225 * ch1 [I] First character to compare
226 * ch2 [I] Second character to compare
229 * FALSE, if the characters are equal.
230 * Non-zero otherwise.
232 BOOL WINAPI ChrCmpIA(WORD ch1, WORD ch2)
234 TRACE("(%d,%d)\n", ch1, ch2);
236 return SHLWAPI_ChrCmpHelperA(ch1, ch2, NORM_IGNORECASE);
239 /*************************************************************************
242 * Internal helper function.
244 static BOOL WINAPI SHLWAPI_ChrCmpW(WCHAR ch1, WCHAR ch2)
246 return SHLWAPI_ChrCmpHelperW(ch1, ch2, 0);
249 /*************************************************************************
250 * ChrCmpIW [SHLWAPI.386]
254 BOOL WINAPI ChrCmpIW(WCHAR ch1, WCHAR ch2)
256 return SHLWAPI_ChrCmpHelperW(ch1, ch2, NORM_IGNORECASE);
259 /*************************************************************************
260 * StrChrA [SHLWAPI.@]
262 * Find a given character in a string.
265 * lpszStr [I] String to search in.
266 * ch [I] Character to search for.
269 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
271 * Failure: NULL, if any arguments are invalid.
273 LPSTR WINAPI StrChrA(LPCSTR lpszStr, WORD ch)
275 TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch);
281 if (!SHLWAPI_ChrCmpA(*lpszStr, ch))
282 return (LPSTR)lpszStr;
283 lpszStr = CharNextA(lpszStr);
289 /*************************************************************************
290 * StrChrW [SHLWAPI.@]
294 LPWSTR WINAPI StrChrW(LPCWSTR lpszStr, WCHAR ch)
296 LPWSTR lpszRet = NULL;
298 TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch);
301 lpszRet = strchrW(lpszStr, ch);
305 /*************************************************************************
306 * StrChrIA [SHLWAPI.@]
308 * Find a given character in a string, ignoring case.
311 * lpszStr [I] String to search in.
312 * ch [I] Character to search for.
315 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
317 * Failure: NULL, if any arguments are invalid.
319 LPSTR WINAPI StrChrIA(LPCSTR lpszStr, WORD ch)
321 TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch);
327 if (!ChrCmpIA(*lpszStr, ch))
328 return (LPSTR)lpszStr;
329 lpszStr = CharNextA(lpszStr);
335 /*************************************************************************
336 * StrChrIW [SHLWAPI.@]
340 LPWSTR WINAPI StrChrIW(LPCWSTR lpszStr, WCHAR ch)
342 TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch);
349 if (toupperW(*lpszStr) == ch)
350 return (LPWSTR)lpszStr;
351 lpszStr = CharNextW(lpszStr);
355 return (LPWSTR)lpszStr;
358 /*************************************************************************
359 * StrCmpIW [SHLWAPI.@]
361 * Compare two strings, ignoring case.
364 * lpszStr [I] First string to compare
365 * lpszComp [I] Second string to compare
368 * An integer less than, equal to or greater than 0, indicating that
369 * lpszStr is less than, the same, or greater than lpszComp.
371 int WINAPI StrCmpIW(LPCWSTR lpszStr, LPCWSTR lpszComp)
375 TRACE("(%s,%s)\n", debugstr_w(lpszStr),debugstr_w(lpszComp));
377 iRet = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, lpszStr, -1, lpszComp, -1);
378 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
381 /*************************************************************************
382 * StrCmpNA [SHLWAPI.@]
384 * Compare two strings, up to a maximum length.
387 * lpszStr [I] First string to compare
388 * lpszComp [I] Second string to compare
389 * iLen [I] Maximum number of chars to compare.
392 * An integer less than, equal to or greater than 0, indicating that
393 * lpszStr is less than, the same, or greater than lpszComp.
395 INT WINAPI StrCmpNA(LPCSTR lpszStr, LPCSTR lpszComp, INT iLen)
399 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
401 iRet = CompareStringA(GetThreadLocale(), 0, lpszStr, iLen, lpszComp, iLen);
402 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
405 /*************************************************************************
406 * StrCmpNW [SHLWAPI.@]
410 INT WINAPI StrCmpNW(LPCWSTR lpszStr, LPCWSTR lpszComp, INT iLen)
414 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen);
416 iRet = CompareStringW(GetThreadLocale(), 0, lpszStr, iLen, lpszComp, iLen);
417 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
420 /*************************************************************************
421 * StrCmpNIA [SHLWAPI.@]
423 * Compare two strings, up to a maximum length, ignoring case.
426 * lpszStr [I] First string to compare
427 * lpszComp [I] Second string to compare
428 * iLen [I] Maximum number of chars to compare.
431 * An integer less than, equal to or greater than 0, indicating that
432 * lpszStr is less than, the same, or greater than lpszComp.
434 int WINAPI StrCmpNIA(LPCSTR lpszStr, LPCSTR lpszComp, int iLen)
438 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
440 iRet = CompareStringA(GetThreadLocale(), NORM_IGNORECASE, lpszStr, iLen, lpszComp, iLen);
441 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
444 /*************************************************************************
445 * StrCmpNIW [SHLWAPI.@]
449 INT WINAPI StrCmpNIW(LPCWSTR lpszStr, LPCWSTR lpszComp, int iLen)
453 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen);
455 iRet = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, lpszStr, iLen, lpszComp, iLen);
456 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
459 /*************************************************************************
460 * StrCmpW [SHLWAPI.@]
462 * Compare two strings.
465 * lpszStr [I] First string to compare
466 * lpszComp [I] Second string to compare
469 * An integer less than, equal to or greater than 0, indicating that
470 * lpszStr is less than, the same, or greater than lpszComp.
472 int WINAPI StrCmpW(LPCWSTR lpszStr, LPCWSTR lpszComp)
476 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszComp));
478 iRet = CompareStringW(GetThreadLocale(), 0, lpszStr, -1, lpszComp, -1);
479 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
482 /*************************************************************************
483 * StrCatW [SHLWAPI.@]
485 * Concatanate two strings.
488 * lpszStr [O] Initial string
489 * lpszSrc [I] String to concatanate
494 LPWSTR WINAPI StrCatW(LPWSTR lpszStr, LPCWSTR lpszSrc)
496 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSrc));
498 strcatW(lpszStr, lpszSrc);
502 /*************************************************************************
503 * StrCpyW [SHLWAPI.@]
505 * Copy a string to another string.
508 * lpszStr [O] Destination string
509 * lpszSrc [I] Source string
514 LPWSTR WINAPI StrCpyW(LPWSTR lpszStr, LPCWSTR lpszSrc)
516 TRACE("(%p,%s)\n", lpszStr, debugstr_w(lpszSrc));
518 strcpyW(lpszStr, lpszSrc);
522 /*************************************************************************
523 * StrCpyNW [SHLWAPI.@]
525 * Copy a string to another string, up to a maximum number of characters.
528 * lpszStr [O] Destination string
529 * lpszSrc [I] Source string
530 * iLen [I] Maximum number of chars to copy
535 LPWSTR WINAPI StrCpyNW(LPWSTR lpszStr, LPCWSTR lpszSrc, int iLen)
537 TRACE("(%p,%s,%i)\n", lpszStr, debugstr_w(lpszSrc), iLen);
539 lstrcpynW(lpszStr, lpszSrc, iLen);
545 /*************************************************************************
546 * SHLWAPI_StrStrHelperA
548 * Internal implementation of StrStrA/StrStrIA
550 static LPSTR WINAPI SHLWAPI_StrStrHelperA(LPCSTR lpszStr, LPCSTR lpszSearch,
551 int (*pStrCmpFn)(LPCSTR,LPCSTR,size_t))
555 if (!lpszStr || !lpszSearch || !*lpszSearch)
558 iLen = strlen(lpszSearch);
562 if (!pStrCmpFn(lpszStr, lpszSearch, iLen))
563 return (LPSTR)lpszStr;
564 lpszStr = CharNextA(lpszStr);
569 /*************************************************************************
570 * SHLWAPI_StrStrHelperW
572 * Internal implementation of StrStrW/StrStrIW
574 static LPWSTR WINAPI SHLWAPI_StrStrHelperW(LPCWSTR lpszStr, LPCWSTR lpszSearch,
575 int (*pStrCmpFn)(LPCWSTR,LPCWSTR,int))
579 if (!lpszStr || !lpszSearch || !*lpszSearch)
582 iLen = strlenW(lpszSearch);
586 if (!pStrCmpFn(lpszStr, lpszSearch, iLen))
587 return (LPWSTR)lpszStr;
588 lpszStr = CharNextW(lpszStr);
593 /*************************************************************************
594 * StrStrA [SHLWAPI.@]
596 * Find a substring within a string.
599 * lpszStr [I] String to search in
600 * lpszSearch [I] String to look for
603 * The start of lpszSearch within lpszStr, or NULL if not found.
605 LPSTR WINAPI StrStrA(LPCSTR lpszStr, LPCSTR lpszSearch)
607 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
609 return SHLWAPI_StrStrHelperA(lpszStr, lpszSearch, strncmp);
612 /*************************************************************************
613 * StrStrW [SHLWAPI.@]
617 LPWSTR WINAPI StrStrW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
619 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
621 return SHLWAPI_StrStrHelperW(lpszStr, lpszSearch, strncmpW);
624 /*************************************************************************
625 * StrRStrIA [SHLWAPI.@]
627 * Find the last occurrence of a substring within a string.
630 * lpszStr [I] String to search in
631 * lpszEnd [I] End of lpszStr
632 * lpszSearch [I] String to look for
635 * The last occurrence lpszSearch within lpszStr, or NULL if not found.
637 LPSTR WINAPI StrRStrIA(LPCSTR lpszStr, LPCSTR lpszEnd, LPCSTR lpszSearch)
639 LPSTR lpszRet = NULL;
643 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
645 if (!lpszStr || !lpszSearch || !*lpszSearch)
649 lpszEnd = lpszStr + lstrlenA(lpszStr);
651 if (IsDBCSLeadByte(*lpszSearch))
652 ch1 = *lpszSearch << 8 | lpszSearch[1];
655 iLen = lstrlenA(lpszSearch);
657 while (lpszStr <= lpszEnd && *lpszStr)
659 ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr;
660 if (!ChrCmpIA(ch1, ch2))
662 if (!StrCmpNIA(lpszStr, lpszSearch, iLen))
663 lpszRet = (LPSTR)lpszStr;
665 lpszStr = CharNextA(lpszStr);
670 /*************************************************************************
671 * StrRStrIW [SHLWAPI.@]
675 LPWSTR WINAPI StrRStrIW(LPCWSTR lpszStr, LPCWSTR lpszEnd, LPCWSTR lpszSearch)
677 LPWSTR lpszRet = NULL;
680 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
682 if (!lpszStr || !lpszSearch || !*lpszSearch)
686 lpszEnd = lpszStr + strlenW(lpszStr);
688 iLen = strlenW(lpszSearch);
690 while (lpszStr <= lpszEnd && *lpszStr)
692 if (!ChrCmpIW(*lpszSearch, *lpszStr))
694 if (!StrCmpNIW(lpszStr, lpszSearch, iLen))
695 lpszRet = (LPWSTR)lpszStr;
697 lpszStr = CharNextW(lpszStr);
702 /*************************************************************************
703 * StrStrIA [SHLWAPI.@]
705 * Find a substring within a string, ignoring case.
708 * lpszStr [I] String to search in
709 * lpszSearch [I] String to look for
712 * The start of lpszSearch within lpszStr, or NULL if not found.
714 LPSTR WINAPI StrStrIA(LPCSTR lpszStr, LPCSTR lpszSearch)
716 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
718 return SHLWAPI_StrStrHelperA(lpszStr, lpszSearch, strncasecmp);
721 /*************************************************************************
722 * StrStrIW [SHLWAPI.@]
726 LPWSTR WINAPI StrStrIW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
728 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
730 return SHLWAPI_StrStrHelperW(lpszStr, lpszSearch, strncmpiW);
733 /*************************************************************************
734 * StrToIntA [SHLWAPI.@]
736 * Read a signed integer from a string.
739 * lpszStr [I] String to read integer from
742 * The signed integer value represented by the string, or 0 if no integer is
746 * No leading space is allowed before the number, although a leading '-' is.
748 int WINAPI StrToIntA(LPCSTR lpszStr)
752 TRACE("(%s)\n", debugstr_a(lpszStr));
756 WARN("Invalid lpszStr would crash under Win32!\n");
760 if (*lpszStr == '-' || isdigit(*lpszStr))
761 StrToIntExA(lpszStr, 0, &iRet);
765 /*************************************************************************
766 * StrToIntW [SHLWAPI.@]
770 int WINAPI StrToIntW(LPCWSTR lpszStr)
774 TRACE("(%s)\n", debugstr_w(lpszStr));
778 WARN("Invalid lpszStr would crash under Win32!\n");
782 if (*lpszStr == '-' || isdigitW(*lpszStr))
783 StrToIntExW(lpszStr, 0, &iRet);
787 /*************************************************************************
788 * StrToIntExA [SHLWAPI.@]
790 * Read an integer from a string.
793 * lpszStr [I] String to read integer from
794 * dwFlags [I] Flags controlling the conversion
795 * lpiRet [O] Destination for read integer.
798 * Success: TRUE. lpiRet contains the integer value represented by the string.
799 * Failure: FALSE, if the string is invalid, or no number is present.
802 * Leading whitespace, '-' and '+' are allowed before the number. If
803 * dwFlags includes STIF_SUPPORT_HEX, hexadecimal numbers are allowed, if
804 * preceded by '0x'. If this flag is not set, or there is no '0x' prefix,
805 * the string is treated as a decimal string. A leading '-' is ignored for
806 * hexadecimal numbers.
808 BOOL WINAPI StrToIntExA(LPCSTR lpszStr, DWORD dwFlags, LPINT lpiRet)
810 BOOL bNegative = FALSE;
813 TRACE("(%s,%08lX,%p)\n", debugstr_a(lpszStr), dwFlags, lpiRet);
815 if (!lpszStr || !lpiRet)
817 WARN("Invalid parameter would crash under Win32!\n");
820 if (dwFlags > STIF_SUPPORT_HEX)
822 WARN("Unknown flags (%08lX)!\n", dwFlags & ~STIF_SUPPORT_HEX);
825 /* Skip leading space, '+', '-' */
826 while (isspace(*lpszStr))
827 lpszStr = CharNextA(lpszStr);
834 else if (*lpszStr == '+')
837 if (dwFlags & STIF_SUPPORT_HEX &&
838 *lpszStr == '0' && tolower(lpszStr[1]) == 'x')
840 /* Read hex number */
843 if (!isxdigit(*lpszStr))
846 while (isxdigit(*lpszStr))
849 if (isdigit(*lpszStr))
850 iRet += (*lpszStr - '0');
852 iRet += 10 + (tolower(*lpszStr) - 'a');
859 /* Read decimal number */
860 if (!isdigit(*lpszStr))
863 while (isdigit(*lpszStr))
866 iRet += (*lpszStr - '0');
869 *lpiRet = bNegative ? -iRet : iRet;
873 /*************************************************************************
874 * StrToIntExW [SHLWAPI.@]
878 BOOL WINAPI StrToIntExW(LPCWSTR lpszStr, DWORD dwFlags, LPINT lpiRet)
880 BOOL bNegative = FALSE;
883 TRACE("(%s,%08lX,%p)\n", debugstr_w(lpszStr), dwFlags, lpiRet);
885 if (!lpszStr || !lpiRet)
887 WARN("Invalid parameter would crash under Win32!\n");
890 if (dwFlags > STIF_SUPPORT_HEX)
892 WARN("Unknown flags (%08lX)!\n", dwFlags & ~STIF_SUPPORT_HEX);
895 /* Skip leading space, '+', '-' */
896 while (isspaceW(*lpszStr))
897 lpszStr = CharNextW(lpszStr);
904 else if (*lpszStr == '+')
907 if (dwFlags & STIF_SUPPORT_HEX &&
908 *lpszStr == '0' && tolowerW(lpszStr[1]) == 'x')
910 /* Read hex number */
913 if (!isxdigitW(*lpszStr))
916 while (isxdigitW(*lpszStr))
919 if (isdigitW(*lpszStr))
920 iRet += (*lpszStr - '0');
922 iRet += 10 + (tolowerW(*lpszStr) - 'a');
929 /* Read decimal number */
930 if (!isdigitW(*lpszStr))
933 while (isdigitW(*lpszStr))
936 iRet += (*lpszStr - '0');
939 *lpiRet = bNegative ? -iRet : iRet;
943 /*************************************************************************
944 * StrDupA [SHLWAPI.@]
946 * Duplicate a string.
949 * lpszStr [I] String to duplicate.
952 * Success: A pointer to a new string containing the contents of lpszStr
953 * Failure: NULL, if memory cannot be allocated
956 * The string memory is allocated with LocalAlloc(), and so should be released
957 * by calling LocalFree().
959 LPSTR WINAPI StrDupA(LPCSTR lpszStr)
964 TRACE("(%s)\n",debugstr_a(lpszStr));
966 iLen = lpszStr ? strlen(lpszStr) + 1 : 1;
967 lpszRet = (LPSTR)LocalAlloc(LMEM_FIXED, iLen);
972 memcpy(lpszRet, lpszStr, iLen);
979 /*************************************************************************
980 * StrDupW [SHLWAPI.@]
984 LPWSTR WINAPI StrDupW(LPCWSTR lpszStr)
989 TRACE("(%s)\n",debugstr_w(lpszStr));
991 iLen = (lpszStr ? strlenW(lpszStr) + 1 : 1) * sizeof(WCHAR);
992 lpszRet = (LPWSTR)LocalAlloc(LMEM_FIXED, iLen);
997 memcpy(lpszRet, lpszStr, iLen);
1004 /*************************************************************************
1005 * SHLWAPI_StrSpnHelperA
1007 * Internal implementation of StrSpnA/StrCSpnA/StrCSpnIA
1009 static int WINAPI SHLWAPI_StrSpnHelperA(LPCSTR lpszStr, LPCSTR lpszMatch,
1010 LPSTR (WINAPI *pStrChrFn)(LPCSTR,WORD),
1013 LPCSTR lpszRead = lpszStr;
1014 if (lpszStr && *lpszStr && lpszMatch)
1018 LPCSTR lpszTest = pStrChrFn(lpszMatch, *lpszRead);
1020 if (!bInvert && !lpszTest)
1022 if (bInvert && lpszTest)
1024 lpszRead = CharNextA(lpszRead);
1027 return lpszRead - lpszStr;
1030 /*************************************************************************
1031 * SHLWAPI_StrSpnHelperW
1033 * Internal implementation of StrSpnW/StrCSpnW/StrCSpnIW
1035 static int WINAPI SHLWAPI_StrSpnHelperW(LPCWSTR lpszStr, LPCWSTR lpszMatch,
1036 LPWSTR (WINAPI *pStrChrFn)(LPCWSTR,WCHAR),
1039 LPCWSTR lpszRead = lpszStr;
1040 if (lpszStr && *lpszStr && lpszMatch)
1044 LPCWSTR lpszTest = pStrChrFn(lpszMatch, *lpszRead);
1046 if (!bInvert && !lpszTest)
1048 if (bInvert && lpszTest)
1050 lpszRead = CharNextW(lpszRead);
1053 return lpszRead - lpszStr;
1056 /*************************************************************************
1057 * StrSpnA [SHLWAPI.@]
1059 * Find the length of the start of a string that contains only certain
1063 * lpszStr [I] String to search
1064 * lpszMatch [I] Characters that can be in the substring
1067 * The length of the part of lpszStr containing only chars from lpszMatch,
1068 * or 0 if any parameter is invalid.
1070 int WINAPI StrSpnA(LPCSTR lpszStr, LPCSTR lpszMatch)
1072 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1074 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, FALSE);
1077 /*************************************************************************
1078 * StrSpnW [SHLWAPI.@]
1082 int WINAPI StrSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1084 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1086 return SHLWAPI_StrSpnHelperW(lpszStr, lpszMatch, StrChrW, FALSE);
1089 /*************************************************************************
1090 * StrCSpnA [SHLWAPI.@]
1092 * Find the length of the start of a string that does not contain certain
1096 * lpszStr [I] String to search
1097 * lpszMatch [I] Characters that cannot be in the substring
1100 * The length of the part of lpszStr containing only chars not in lpszMatch,
1101 * or 0 if any parameter is invalid.
1103 int WINAPI StrCSpnA(LPCSTR lpszStr, LPCSTR lpszMatch)
1105 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1107 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, TRUE);
1110 /*************************************************************************
1111 * StrCSpnW [SHLWAPI.@]
1115 int WINAPI StrCSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1117 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1119 return SHLWAPI_StrSpnHelperW(lpszStr, lpszMatch, StrChrW, TRUE);
1122 /*************************************************************************
1123 * StrCSpnIA [SHLWAPI.@]
1125 * Find the length of the start of a string that does not contain certain
1126 * characters, ignoring case.
1129 * lpszStr [I] String to search
1130 * lpszMatch [I] Characters that cannot be in the substring
1133 * The length of the part of lpszStr containing only chars not in lpszMatch,
1134 * or 0 if any parameter is invalid.
1136 int WINAPI StrCSpnIA(LPCSTR lpszStr, LPCSTR lpszMatch)
1138 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1140 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrIA, TRUE);
1143 /*************************************************************************
1144 * StrCSpnIW [SHLWAPI.@]
1148 int WINAPI StrCSpnIW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1150 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1152 return SHLWAPI_StrSpnHelperW(lpszStr, lpszMatch, StrChrIW, TRUE);
1155 /*************************************************************************
1156 * StrPBrkA [SHLWAPI.@]
1158 * Search a string for any of a group of characters.
1161 * lpszStr [I] String to search
1162 * lpszMatch [I] Characters to match
1165 * A pointer to the first matching character in lpszStr, or NULL if no
1168 LPSTR WINAPI StrPBrkA(LPCSTR lpszStr, LPCSTR lpszMatch)
1170 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1172 if (lpszStr && lpszMatch && *lpszMatch)
1176 if (StrChrA(lpszMatch, *lpszStr))
1177 return (LPSTR)lpszStr;
1178 lpszStr = CharNextA(lpszStr);
1184 /*************************************************************************
1185 * StrPBrkW [SHLWAPI.@]
1189 LPWSTR WINAPI StrPBrkW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1191 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1193 if (lpszStr && lpszMatch && *lpszMatch)
1197 if (StrChrW(lpszMatch, *lpszStr))
1198 return (LPWSTR)lpszStr;
1199 lpszStr = CharNextW(lpszStr);
1205 /*************************************************************************
1206 * SHLWAPI_StrRChrHelperA
1208 * Internal implementation of StrRChrA/StrRChrIA.
1210 static LPSTR WINAPI SHLWAPI_StrRChrHelperA(LPCSTR lpszStr,
1211 LPCSTR lpszEnd, WORD ch,
1212 BOOL (WINAPI *pChrCmpFn)(WORD,WORD))
1214 LPCSTR lpszRet = NULL;
1221 lpszEnd = lpszStr + lstrlenA(lpszStr);
1223 while (*lpszStr && lpszStr <= lpszEnd)
1225 ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr;
1227 if (!pChrCmpFn(ch, ch2))
1229 lpszStr = CharNextA(lpszStr);
1232 return (LPSTR)lpszRet;
1235 /*************************************************************************
1236 * SHLWAPI_StrRChrHelperW
1238 * Internal implementation of StrRChrW/StrRChrIW.
1240 static LPWSTR WINAPI SHLWAPI_StrRChrHelperW(LPCWSTR lpszStr,
1241 LPCWSTR lpszEnd, WCHAR ch,
1242 BOOL (WINAPI *pChrCmpFn)(WCHAR,WCHAR))
1244 LPCWSTR lpszRet = NULL;
1249 lpszEnd = lpszStr + strlenW(lpszStr);
1251 while (*lpszStr && lpszStr <= lpszEnd)
1253 if (!pChrCmpFn(ch, *lpszStr))
1255 lpszStr = CharNextW(lpszStr);
1258 return (LPWSTR)lpszRet;
1261 /**************************************************************************
1262 * StrRChrA [SHLWAPI.@]
1264 * Find the last occurrence of a character in string.
1267 * lpszStr [I] String to search in
1268 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1269 * ch [I] Character to search for.
1272 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1273 * or NULL if not found.
1274 * Failure: NULL, if any arguments are invalid.
1276 LPSTR WINAPI StrRChrA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch)
1278 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch);
1280 return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, SHLWAPI_ChrCmpA);
1283 /**************************************************************************
1284 * StrRChrW [SHLWAPI.@]
1288 LPWSTR WINAPI StrRChrW(LPCWSTR lpszStr, LPCWSTR lpszEnd, WORD ch)
1290 TRACE("(%s,%s,%x)\n", debugstr_w(lpszStr), debugstr_w(lpszEnd), ch);
1292 return SHLWAPI_StrRChrHelperW(lpszStr, lpszEnd, ch, SHLWAPI_ChrCmpW);
1295 /**************************************************************************
1296 * StrRChrIA [SHLWAPI.@]
1298 * Find the last occurrence of a character in string, ignoring case.
1301 * lpszStr [I] String to search in
1302 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1303 * ch [I] Character to search for.
1306 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1307 * or NULL if not found.
1308 * Failure: NULL, if any arguments are invalid.
1310 LPSTR WINAPI StrRChrIA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch)
1312 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch);
1314 return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, ChrCmpIA);
1317 /**************************************************************************
1318 * StrRChrIW [SHLWAPI.@]
1322 LPWSTR WINAPI StrRChrIW(LPCWSTR lpszStr, LPCWSTR lpszEnd, WORD ch)
1324 TRACE("(%s,%s,%x)\n", debugstr_w(lpszStr), debugstr_w(lpszEnd), ch);
1326 return SHLWAPI_StrRChrHelperW(lpszStr, lpszEnd, ch, ChrCmpIW);
1329 /*************************************************************************
1330 * StrCatBuffA [SHLWAPI.@]
1332 * Concatenate two strings together.
1335 * lpszStr [O] String to concatenate to
1336 * lpszCat [I] String to add to lpszCat
1337 * cchMax [I] Maximum number of characters for the whole string
1343 * cchMax determines the number of characters in the final length of the
1344 * string, not the number appended to lpszStr from lpszCat.
1346 LPSTR WINAPI StrCatBuffA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax)
1350 TRACE("(%p,%s,%d)\n", lpszStr, debugstr_a(lpszCat), cchMax);
1354 WARN("Invalid lpszStr would crash under Win32!\n");
1358 iLen = strlen(lpszStr);
1362 StrCpyNA(lpszStr + iLen, lpszCat, cchMax);
1366 /*************************************************************************
1367 * StrCatBuffW [SHLWAPI.@]
1371 LPWSTR WINAPI StrCatBuffW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax)
1375 TRACE("(%p,%s,%d)\n", lpszStr, debugstr_w(lpszCat), cchMax);
1379 WARN("Invalid lpszStr would crash under Win32!\n");
1383 iLen = strlenW(lpszStr);
1387 StrCpyNW(lpszStr + iLen, lpszCat, cchMax);
1391 /*************************************************************************
1392 * StrRetToBufA [SHLWAPI.@]
1394 * Convert a STRRET to a normal string.
1397 * lpStrRet [O] STRRET to convert
1398 * pIdl [I] ITEMIDLIST for lpStrRet->uType == STRRET_OFFSET
1399 * lpszDest [O] Destination for normal string
1400 * dwLen [I] Length of lpszDest
1403 * Success: S_OK. lpszDest contains up to dwLen characters of the string.
1404 * If lpStrRet is of type STRRET_WSTR, its memory is freed with
1405 * CoTaskMemFree() and its type set to STRRET_CSTRA.
1406 * Failure: E_FAIL, if any parameters are invalid.
1408 HRESULT WINAPI StrRetToBufA (LPSTRRET src, const ITEMIDLIST *pidl, LPSTR dest, UINT len)
1411 * This routine is identical to that in dlls/shell32/shellstring.c.
1412 * It was duplicated because not every version of Shlwapi.dll exports
1413 * StrRetToBufA. If you change one routine, change them both.
1415 TRACE("dest=%p len=0x%x strret=%p pidl=%p stub\n",dest,len,src,pidl);
1419 WARN("Invalid lpStrRet would crash under Win32!\n");
1433 WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, dest, len, NULL, NULL);
1434 CoTaskMemFree(src->u.pOleStr);
1438 lstrcpynA((LPSTR)dest, src->u.cStr, len);
1442 lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len);
1446 FIXME("unknown type!\n");
1452 /*************************************************************************
1453 * StrRetToBufW [SHLWAPI.@]
1457 HRESULT WINAPI StrRetToBufW (LPSTRRET src, const ITEMIDLIST *pidl, LPWSTR dest, UINT len)
1459 TRACE("dest=%p len=0x%x strret=%p pidl=%p stub\n",dest,len,src,pidl);
1463 WARN("Invalid lpStrRet would crash under Win32!\n");
1477 lstrcpynW((LPWSTR)dest, src->u.pOleStr, len);
1478 CoTaskMemFree(src->u.pOleStr);
1482 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
1489 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1,
1496 FIXME("unknown type!\n");
1502 /*************************************************************************
1503 * StrRetToStrA [SHLWAPI.@]
1505 * Converts a STRRET to a normal string.
1508 * lpStrRet [O] STRRET to convert
1509 * pidl [I] ITEMIDLIST for lpStrRet->uType == STRRET_OFFSET
1510 * ppszName [O] Destination for converted string
1513 * Success: S_OK. ppszName contains the new string, allocated with CoTaskMemAlloc().
1514 * Failure: E_FAIL, if any parameters are invalid.
1516 HRESULT WINAPI StrRetToStrA(LPSTRRET lpStrRet, const ITEMIDLIST *pidl, LPSTR *ppszName)
1518 HRESULT hRet = E_FAIL;
1520 switch (lpStrRet->uType)
1523 hRet = _SHStrDupAW(lpStrRet->u.pOleStr, ppszName);
1524 CoTaskMemFree(lpStrRet->u.pOleStr);
1528 hRet = _SHStrDupAA(lpStrRet->u.cStr, ppszName);
1532 hRet = _SHStrDupAA(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, ppszName);
1542 /*************************************************************************
1543 * StrRetToStrW [SHLWAPI.@]
1547 HRESULT WINAPI StrRetToStrW(LPSTRRET lpStrRet, const ITEMIDLIST *pidl, LPWSTR *ppszName)
1549 HRESULT hRet = E_FAIL;
1551 switch (lpStrRet->uType)
1554 hRet = SHStrDupW(lpStrRet->u.pOleStr, ppszName);
1555 CoTaskMemFree(lpStrRet->u.pOleStr);
1559 hRet = SHStrDupA(lpStrRet->u.cStr, ppszName);
1563 hRet = SHStrDupA(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, ppszName);
1573 /* Create an ASCII string copy using SysAllocString() */
1574 static HRESULT _SHStrDupAToBSTR(LPCSTR src, BSTR *pBstrOut)
1580 INT len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0);
1581 WCHAR* szTemp = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1585 MultiByteToWideChar(CP_ACP, 0, src, -1, szTemp, len);
1586 *pBstrOut = SysAllocString(szTemp);
1587 HeapFree(GetProcessHeap(), 0, szTemp);
1593 return E_OUTOFMEMORY;
1596 /*************************************************************************
1597 * StrRetToBSTR [SHLWAPI.@]
1599 * Converts a STRRET to a BSTR.
1602 * lpStrRet [O] STRRET to convert
1603 * pidl [I] ITEMIDLIST for lpStrRet->uType = STRRET_OFFSET
1604 * pBstrOut [O] Destination for converted BSTR
1607 * Success: S_OK. pBstrOut contains the new string.
1608 * Failure: E_FAIL, if any parameters are invalid.
1610 HRESULT WINAPI StrRetToBSTR(STRRET *lpStrRet, LPCITEMIDLIST pidl, BSTR* pBstrOut)
1612 HRESULT hRet = E_FAIL;
1614 switch (lpStrRet->uType)
1617 *pBstrOut = SysAllocString(lpStrRet->u.pOleStr);
1620 CoTaskMemFree(lpStrRet->u.pOleStr);
1624 hRet = _SHStrDupAToBSTR(lpStrRet->u.cStr, pBstrOut);
1628 hRet = _SHStrDupAToBSTR(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, pBstrOut);
1638 /*************************************************************************
1639 * StrFormatKBSizeA [SHLWAPI.@]
1641 * Create a formatted string containing a byte count in Kilobytes.
1644 * llBytes [I] Byte size to format
1645 * lpszDest [I] Destination for formatted string
1646 * cchMax [I] Size of lpszDest
1651 LPSTR WINAPI StrFormatKBSizeA(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax)
1655 if (!StrFormatKBSizeW(llBytes, wszBuf, 256))
1657 if (!WideCharToMultiByte(CP_ACP, 0, wszBuf, -1, lpszDest, cchMax, NULL, NULL))
1662 /*************************************************************************
1663 * StrFormatKBSizeW [SHLWAPI.@]
1665 * See StrFormatKBSizeA.
1667 LPWSTR WINAPI StrFormatKBSizeW(LONGLONG llBytes, LPWSTR lpszDest, UINT cchMax)
1669 static const WCHAR kb[] = {' ','K','B',0};
1670 LONGLONG llKB = (llBytes + 1023) >> 10;
1673 TRACE("(0x%s,%p,%d)\n", wine_dbgstr_longlong(llBytes), lpszDest, cchMax);
1675 if (!FormatInt(llKB, lpszDest, cchMax))
1678 len = lstrlenW(lpszDest);
1679 if (cchMax - len < 4)
1681 lstrcatW(lpszDest, kb);
1685 /*************************************************************************
1686 * StrNCatA [SHLWAPI.@]
1688 * Concatenate two strings together.
1691 * lpszStr [O] String to concatenate to
1692 * lpszCat [I] String to add to lpszCat
1693 * cchMax [I] Maximum number of characters to concatenate
1699 * cchMax determines the number of characters that are appended to lpszStr,
1700 * not the total length of the string.
1702 LPSTR WINAPI StrNCatA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax)
1704 LPSTR lpszRet = lpszStr;
1706 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszCat), cchMax);
1710 WARN("Invalid lpszStr would crash under Win32!\n");
1714 StrCpyNA(lpszStr + strlen(lpszStr), lpszCat, cchMax);
1718 /*************************************************************************
1719 * StrNCatW [SHLWAPI.@]
1723 LPWSTR WINAPI StrNCatW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax)
1725 LPWSTR lpszRet = lpszStr;
1727 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszCat), cchMax);
1731 WARN("Invalid lpszStr would crash under Win32\n");
1735 StrCpyNW(lpszStr + strlenW(lpszStr), lpszCat, cchMax);
1739 /*************************************************************************
1740 * StrTrimA [SHLWAPI.@]
1742 * Remove characters from the start and end of a string.
1745 * lpszStr [O] String to remove characters from
1746 * lpszTrim [I] Characters to remove from lpszStr
1749 * TRUE If lpszStr was valid and modified
1752 BOOL WINAPI StrTrimA(LPSTR lpszStr, LPCSTR lpszTrim)
1755 LPSTR lpszRead = lpszStr;
1758 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszTrim));
1760 if (lpszRead && *lpszRead)
1762 while (*lpszRead && StrChrA(lpszTrim, *lpszRead))
1763 lpszRead = CharNextA(lpszRead); /* Skip leading matches */
1765 dwLen = strlen(lpszRead);
1767 if (lpszRead != lpszStr)
1769 memmove(lpszStr, lpszRead, dwLen + 1);
1774 lpszRead = lpszStr + dwLen;
1775 while (StrChrA(lpszTrim, lpszRead[-1]))
1776 lpszRead = CharPrevA(lpszStr, lpszRead); /* Skip trailing matches */
1778 if (lpszRead != lpszStr + dwLen)
1788 /*************************************************************************
1789 * StrTrimW [SHLWAPI.@]
1793 BOOL WINAPI StrTrimW(LPWSTR lpszStr, LPCWSTR lpszTrim)
1796 LPWSTR lpszRead = lpszStr;
1799 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszTrim));
1801 if (lpszRead && *lpszRead)
1803 while (*lpszRead && StrChrW(lpszTrim, *lpszRead))
1804 lpszRead = CharNextW(lpszRead); /* Skip leading matches */
1806 dwLen = strlenW(lpszRead);
1808 if (lpszRead != lpszStr)
1810 memmove(lpszStr, lpszRead, (dwLen + 1) * sizeof(WCHAR));
1815 lpszRead = lpszStr + dwLen;
1816 while (StrChrW(lpszTrim, lpszRead[-1]))
1817 lpszRead = CharPrevW(lpszStr, lpszRead); /* Skip trailing matches */
1819 if (lpszRead != lpszStr + dwLen)
1829 /*************************************************************************
1830 * _SHStrDupAA [INTERNAL]
1832 * Duplicates a ASCII string to ASCII. The destination buffer is allocated.
1834 static HRESULT WINAPI _SHStrDupAA(LPCSTR src, LPSTR * dest)
1840 len = lstrlenA(src) + 1;
1841 *dest = CoTaskMemAlloc(len);
1847 lstrcpynA(*dest,src, len);
1853 TRACE("%s->(%p)\n", debugstr_a(src), *dest);
1857 /*************************************************************************
1858 * SHStrDupA [SHLWAPI.@]
1860 * Return a Unicode copy of a string, in memory allocated by CoTaskMemAlloc().
1863 * lpszStr [I] String to copy
1864 * lppszDest [O] Destination for the new string copy
1867 * Success: S_OK. lppszDest contains the new string in Unicode format.
1868 * Failure: E_OUTOFMEMORY, If any arguments are invalid or memory allocation
1871 HRESULT WINAPI SHStrDupA(LPCSTR lpszStr, LPWSTR * lppszDest)
1878 len = MultiByteToWideChar(0, 0, lpszStr, -1, 0, 0) * sizeof(WCHAR);
1879 *lppszDest = CoTaskMemAlloc(len);
1886 MultiByteToWideChar(0, 0, lpszStr, -1, *lppszDest, len/sizeof(WCHAR));
1890 hRet = E_OUTOFMEMORY;
1892 TRACE("%s->(%p)\n", debugstr_a(lpszStr), *lppszDest);
1896 /*************************************************************************
1897 * _SHStrDupAW [INTERNAL]
1899 * Duplicates a UNICODE to a ASCII string. The destination buffer is allocated.
1901 static HRESULT WINAPI _SHStrDupAW(LPCWSTR src, LPSTR * dest)
1907 len = WideCharToMultiByte(CP_ACP, 0, src, -1, NULL, 0, NULL, NULL);
1908 *dest = CoTaskMemAlloc(len);
1914 WideCharToMultiByte(CP_ACP, 0, src, -1, *dest, len, NULL, NULL);
1920 TRACE("%s->(%p)\n", debugstr_w(src), *dest);
1924 /*************************************************************************
1925 * SHStrDupW [SHLWAPI.@]
1929 HRESULT WINAPI SHStrDupW(LPCWSTR src, LPWSTR * dest)
1935 len = (lstrlenW(src) + 1) * sizeof(WCHAR);
1936 *dest = CoTaskMemAlloc(len);
1942 memcpy(*dest, src, len);
1948 TRACE("%s->(%p)\n", debugstr_w(src), *dest);
1952 /*************************************************************************
1953 * SHLWAPI_WriteReverseNum
1955 * Internal helper for SHLWAPI_WriteTimeClass.
1957 inline static LPWSTR SHLWAPI_WriteReverseNum(LPWSTR lpszOut, DWORD dwNum)
1961 /* Write a decimal number to a string, backwards */
1964 DWORD dwNextDigit = dwNum % 10;
1965 *lpszOut-- = '0' + dwNextDigit;
1966 dwNum = (dwNum - dwNextDigit) / 10;
1967 } while (dwNum > 0);
1972 /*************************************************************************
1973 * SHLWAPI_FormatSignificant
1975 * Internal helper for SHLWAPI_WriteTimeClass.
1977 inline static int SHLWAPI_FormatSignificant(LPWSTR lpszNum, int dwDigits)
1979 /* Zero non significant digits, return remaining significant digits */
1983 if (--dwDigits == 0)
1993 /*************************************************************************
1994 * SHLWAPI_WriteTimeClass
1996 * Internal helper for StrFromTimeIntervalW.
1998 static int WINAPI SHLWAPI_WriteTimeClass(LPWSTR lpszOut, DWORD dwValue,
1999 UINT uClassStringId, int iDigits)
2001 WCHAR szBuff[64], *szOut = szBuff + 32;
2003 szOut = SHLWAPI_WriteReverseNum(szOut, dwValue);
2004 iDigits = SHLWAPI_FormatSignificant(szOut + 1, iDigits);
2006 LoadStringW(shlwapi_hInstance, uClassStringId, szBuff + 32, 32);
2007 strcatW(lpszOut, szOut);
2011 /*************************************************************************
2012 * StrFromTimeIntervalA [SHLWAPI.@]
2014 * Format a millisecond time interval into a string
2017 * lpszStr [O] Output buffer for formatted time interval
2018 * cchMax [I] Size of lpszStr
2019 * dwMS [I] Number of milliseconds
2020 * iDigits [I] Number of digits to print
2023 * The length of the formatted string, or 0 if any parameter is invalid.
2026 * This implementation mimics the Win32 behaviour of always writing a leading
2027 * space before the time interval begins.
2029 * iDigits is used to provide approximate times if accuracy is not important.
2030 * This number of digits will be written of the first non-zero time class
2031 * (hours/minutes/seconds). If this does not complete the time classification,
2032 * the remaining digits are changed to zeros (i.e. The time is _not_ rounded).
2033 * If there are digits remaining following the writing of a time class, the
2034 * next time class will be written.
2036 * For example, given dwMS represents 138 hours,43 minutes and 15 seconds, the
2037 * following will result from the given values of iDigits:
2039 *| iDigits 1 2 3 4 5 ...
2040 *| lpszStr "100 hr" "130 hr" "138 hr" "138 hr 40 min" "138 hr 43 min" ...
2042 INT WINAPI StrFromTimeIntervalA(LPSTR lpszStr, UINT cchMax, DWORD dwMS,
2047 TRACE("(%p,%d,%ld,%d)\n", lpszStr, cchMax, dwMS, iDigits);
2049 if (lpszStr && cchMax)
2052 StrFromTimeIntervalW(szBuff, sizeof(szBuff)/sizeof(WCHAR), dwMS, iDigits);
2053 WideCharToMultiByte(CP_ACP,0,szBuff,-1,lpszStr,cchMax,0,0);
2059 /*************************************************************************
2060 * StrFromTimeIntervalW [SHLWAPI.@]
2062 * See StrFromTimeIntervalA.
2064 INT WINAPI StrFromTimeIntervalW(LPWSTR lpszStr, UINT cchMax, DWORD dwMS,
2069 TRACE("(%p,%d,%ld,%d)\n", lpszStr, cchMax, dwMS, iDigits);
2071 if (lpszStr && cchMax)
2074 DWORD dwHours, dwMinutes;
2076 if (!iDigits || cchMax == 1)
2082 /* Calculate the time classes */
2083 dwMS = (dwMS + 500) / 1000;
2084 dwHours = dwMS / 3600;
2085 dwMS -= dwHours * 3600;
2086 dwMinutes = dwMS / 60;
2087 dwMS -= dwMinutes * 60;
2092 iDigits = SHLWAPI_WriteTimeClass(szCopy, dwHours, IDS_TIME_INTERVAL_HOURS, iDigits);
2094 if (dwMinutes && iDigits)
2095 iDigits = SHLWAPI_WriteTimeClass(szCopy, dwMinutes, IDS_TIME_INTERVAL_MINUTES, iDigits);
2097 if (iDigits) /* Always write seconds if we have significant digits */
2098 SHLWAPI_WriteTimeClass(szCopy, dwMS, IDS_TIME_INTERVAL_SECONDS, iDigits);
2100 lstrcpynW(lpszStr, szCopy, cchMax);
2101 iRet = strlenW(lpszStr);
2106 /*************************************************************************
2107 * StrIsIntlEqualA [SHLWAPI.@]
2109 * Compare two strings.
2112 * bCase [I] Whether to compare case sensitively
2113 * lpszStr [I] First string to compare
2114 * lpszComp [I] Second string to compare
2115 * iLen [I] Length to compare
2118 * TRUE If the strings are equal.
2121 BOOL WINAPI StrIsIntlEqualA(BOOL bCase, LPCSTR lpszStr, LPCSTR lpszComp,
2126 TRACE("(%d,%s,%s,%d)\n", bCase,
2127 debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
2129 /* FIXME: This flag is undocumented and unknown by our CompareString.
2130 * We need a define for it.
2132 dwFlags = 0x10000000;
2133 if (!bCase) dwFlags |= NORM_IGNORECASE;
2135 return (CompareStringA(GetThreadLocale(), dwFlags, lpszStr, iLen, lpszComp, iLen) == CSTR_EQUAL);
2138 /*************************************************************************
2139 * StrIsIntlEqualW [SHLWAPI.@]
2141 * See StrIsIntlEqualA.
2143 BOOL WINAPI StrIsIntlEqualW(BOOL bCase, LPCWSTR lpszStr, LPCWSTR lpszComp,
2148 TRACE("(%d,%s,%s,%d)\n", bCase,
2149 debugstr_w(lpszStr),debugstr_w(lpszComp), iLen);
2151 /* FIXME: This flag is undocumented and unknown by our CompareString.
2152 * We need a define for it.
2154 dwFlags = 0x10000000;
2155 if (!bCase) dwFlags |= NORM_IGNORECASE;
2157 return (CompareStringW(GetThreadLocale(), dwFlags, lpszStr, iLen, lpszComp, iLen) == CSTR_EQUAL);
2160 /*************************************************************************
2163 * Copy a string to another string, up to a maximum number of characters.
2166 * lpszDest [O] Destination string
2167 * lpszSrc [I] Source string
2168 * iLen [I] Maximum number of chars to copy
2171 * Success: A pointer to the last character written to lpszDest..
2172 * Failure: lpszDest, if any arguments are invalid.
2174 LPSTR WINAPI StrCpyNXA(LPSTR lpszDest, LPCSTR lpszSrc, int iLen)
2176 TRACE("(%p,%s,%i)\n", lpszDest, debugstr_a(lpszSrc), iLen);
2178 if (lpszDest && lpszSrc && iLen > 0)
2180 while ((iLen-- > 1) && *lpszSrc)
2181 *lpszDest++ = *lpszSrc++;
2188 /*************************************************************************
2191 * Unicode version of StrCpyNXA.
2193 LPWSTR WINAPI StrCpyNXW(LPWSTR lpszDest, LPCWSTR lpszSrc, int iLen)
2195 TRACE("(%p,%s,%i)\n", lpszDest, debugstr_w(lpszSrc), iLen);
2197 if (lpszDest && lpszSrc && iLen > 0)
2199 while ((iLen-- > 1) && *lpszSrc)
2200 *lpszDest++ = *lpszSrc++;
2207 /*************************************************************************
2208 * StrCmpLogicalW [SHLWAPI.@]
2210 * Compare two strings, ignoring case and comparing digits as numbers.
2213 * lpszStr [I] First string to compare
2214 * lpszComp [I] Second string to compare
2215 * iLen [I] Length to compare
2218 * TRUE If the strings are equal.
2221 INT WINAPI StrCmpLogicalW(LPCWSTR lpszStr, LPCWSTR lpszComp)
2225 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszComp));
2227 if (lpszStr && lpszComp)
2233 else if (isdigitW(*lpszStr))
2237 if (!isdigitW(*lpszComp))
2240 /* Compare the numbers */
2241 StrToIntExW(lpszStr, 0, &iStr);
2242 StrToIntExW(lpszComp, 0, &iComp);
2246 else if (iStr > iComp)
2250 while (isdigitW(*lpszStr))
2252 while (isdigitW(*lpszComp))
2255 else if (isdigitW(*lpszComp))
2259 iDiff = SHLWAPI_ChrCmpHelperW(*lpszStr,*lpszComp,NORM_IGNORECASE);
2275 /* Structure for formatting byte strings */
2276 typedef struct tagSHLWAPI_BYTEFORMATS
2283 } SHLWAPI_BYTEFORMATS;
2285 /*************************************************************************
2286 * StrFormatByteSizeW [SHLWAPI.@]
2288 * Create a string containing an abbreviated byte count of up to 2^63-1.
2291 * llBytes [I] Byte size to format
2292 * lpszDest [I] Destination for formatted string
2293 * cchMax [I] Size of lpszDest
2299 * There is no StrFormatByteSize64W function, it is called StrFormatByteSizeW().
2301 LPWSTR WINAPI StrFormatByteSizeW(LONGLONG llBytes, LPWSTR lpszDest, UINT cchMax)
2303 #define KB ((ULONGLONG)1024)
2305 #define GB (KB*KB*KB)
2306 #define TB (KB*KB*KB*KB)
2307 #define PB (KB*KB*KB*KB*KB)
2309 static const SHLWAPI_BYTEFORMATS bfFormats[] =
2311 { 10*KB, 10.24, 100.0, 2, 'K' }, /* 10 KB */
2312 { 100*KB, 102.4, 10.0, 1, 'K' }, /* 100 KB */
2313 { 1000*KB, 1024.0, 1.0, 0, 'K' }, /* 1000 KB */
2314 { 10*MB, 10485.76, 100.0, 2, 'M' }, /* 10 MB */
2315 { 100*MB, 104857.6, 10.0, 1, 'M' }, /* 100 MB */
2316 { 1000*MB, 1048576.0, 1.0, 0, 'M' }, /* 1000 MB */
2317 { 10*GB, 10737418.24, 100.0, 2, 'G' }, /* 10 GB */
2318 { 100*GB, 107374182.4, 10.0, 1, 'G' }, /* 100 GB */
2319 { 1000*GB, 1073741824.0, 1.0, 0, 'G' }, /* 1000 GB */
2320 { 10*TB, 10485.76, 100.0, 2, 'T' }, /* 10 TB */
2321 { 100*TB, 104857.6, 10.0, 1, 'T' }, /* 100 TB */
2322 { 1000*TB, 1048576.0, 1.0, 0, 'T' }, /* 1000 TB */
2323 { 10*PB, 10737418.24, 100.00, 2, 'P' }, /* 10 PB */
2324 { 100*PB, 107374182.4, 10.00, 1, 'P' }, /* 100 PB */
2325 { 1000*PB, 1073741824.0, 1.00, 0, 'P' }, /* 1000 PB */
2326 { 0, 10995116277.76, 100.00, 2, 'E' } /* EB's, catch all */
2328 WCHAR wszAdd[] = {' ','?','B',0};
2332 TRACE("(0x%s,%p,%d)\n", wine_dbgstr_longlong(llBytes), lpszDest, cchMax);
2334 if (!lpszDest || !cchMax)
2337 if (llBytes < 1024) /* 1K */
2339 WCHAR wszBytesFormat[64];
2340 LoadStringW(shlwapi_hInstance, IDS_BYTES_FORMAT, wszBytesFormat, 64);
2341 snprintfW(lpszDest, cchMax, wszBytesFormat, (long)llBytes);
2345 /* Note that if this loop completes without finding a match, i will be
2346 * pointing at the last entry, which is a catch all for > 1000 PB
2348 while (i < sizeof(bfFormats) / sizeof(SHLWAPI_BYTEFORMATS) - 1)
2350 if (llBytes < bfFormats[i].dLimit)
2354 /* Above 1 TB we encounter problems with FP accuracy. So for amounts above
2355 * this number we integer shift down by 1 MB first. The table above has
2356 * the divisors scaled down from the '< 10 TB' entry onwards, to account
2357 * for this. We also add a small fudge factor to get the correct result for
2358 * counts that lie exactly on a 1024 byte boundary.
2361 dBytes = (double)(llBytes >> 20) + 0.001; /* Scale down by I MB */
2363 dBytes = (double)llBytes + 0.00001;
2365 dBytes = floor(dBytes / bfFormats[i].dDivisor) / bfFormats[i].dNormaliser;
2367 if (!FormatDouble(dBytes, bfFormats[i].nDecimals, lpszDest, cchMax))
2369 wszAdd[1] = bfFormats[i].wPrefix;
2370 StrCatBuffW(lpszDest, wszAdd, cchMax);
2374 /*************************************************************************
2375 * StrFormatByteSize64A [SHLWAPI.@]
2377 * See StrFormatByteSizeW.
2379 LPSTR WINAPI StrFormatByteSize64A(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax)
2383 StrFormatByteSizeW(llBytes, wszBuff, sizeof(wszBuff)/sizeof(WCHAR));
2386 WideCharToMultiByte(CP_ACP, 0, wszBuff, -1, lpszDest, cchMax, 0, 0);
2390 /*************************************************************************
2391 * StrFormatByteSizeA [SHLWAPI.@]
2393 * Create a string containing an abbreviated byte count of up to 2^31-1.
2396 * dwBytes [I] Byte size to format
2397 * lpszDest [I] Destination for formatted string
2398 * cchMax [I] Size of lpszDest
2404 * The Ascii and Unicode versions of this function accept a different
2405 * integer type for dwBytes. See StrFormatByteSize64A().
2407 LPSTR WINAPI StrFormatByteSizeA(DWORD dwBytes, LPSTR lpszDest, UINT cchMax)
2409 TRACE("(%ld,%p,%d)\n", dwBytes, lpszDest, cchMax);
2411 return StrFormatByteSize64A(dwBytes, lpszDest, cchMax);
2414 /*************************************************************************
2417 * Remove a hanging lead byte from the end of a string, if present.
2420 * lpStr [I] String to check for a hanging lead byte
2421 * size [I] Length of lpStr
2424 * Success: The new length of the string. Any hanging lead bytes are removed.
2425 * Failure: 0, if any parameters are invalid.
2427 DWORD WINAPI SHTruncateString(LPSTR lpStr, DWORD size)
2431 LPSTR lastByte = lpStr + size - 1;
2433 while(lpStr < lastByte)
2434 lpStr += IsDBCSLeadByte(*lpStr) ? 2 : 1;
2436 if(lpStr == lastByte && IsDBCSLeadByte(*lpStr))
2446 /*************************************************************************
2449 * Remove a single non-trailing ampersand ('&') from a string.
2452 * lpszStr [I/O] String to remove ampersand from.
2455 * The character after the first ampersand in lpszStr, or the first character
2456 * in lpszStr if there is no ampersand in the string.
2458 char WINAPI SHStripMneumonicA(LPCSTR lpszStr)
2460 LPSTR lpszIter, lpszTmp;
2463 TRACE("(%s)\n", debugstr_a(lpszStr));
2467 if ((lpszIter = StrChrA(lpszStr, '&')))
2469 lpszTmp = CharNextA(lpszIter);
2470 if (lpszTmp && *lpszTmp)
2472 if (*lpszTmp != '&')
2475 while (lpszIter && *lpszIter)
2477 lpszTmp = CharNextA(lpszIter);
2478 *lpszIter = *lpszTmp;
2487 /*************************************************************************
2490 * Unicode version of SHStripMneumonicA.
2492 WCHAR WINAPI SHStripMneumonicW(LPCWSTR lpszStr)
2494 LPWSTR lpszIter, lpszTmp;
2497 TRACE("(%s)\n", debugstr_w(lpszStr));
2501 if ((lpszIter = StrChrW(lpszStr, '&')))
2503 lpszTmp = CharNextW(lpszIter);
2504 if (lpszTmp && *lpszTmp)
2506 if (*lpszTmp != '&')
2509 while (lpszIter && *lpszIter)
2511 lpszTmp = CharNextW(lpszIter);
2512 *lpszIter = *lpszTmp;
2521 /*************************************************************************
2524 * Convert an Ascii string to Unicode.
2527 * dwCp [I] Code page for the conversion
2528 * lpSrcStr [I] Source Ascii string to convert
2529 * lpDstStr [O] Destination for converted Unicode string
2530 * iLen [I] Length of lpDstStr
2533 * The return value of the MultiByteToWideChar() function called on lpSrcStr.
2535 DWORD WINAPI SHAnsiToUnicodeCP(DWORD dwCp, LPCSTR lpSrcStr, LPWSTR lpDstStr, int iLen)
2539 dwRet = MultiByteToWideChar(dwCp, 0, lpSrcStr, -1, lpDstStr, iLen);
2540 TRACE("%s->%s,ret=%ld\n", debugstr_a(lpSrcStr), debugstr_w(lpDstStr), dwRet);
2544 /*************************************************************************
2547 * Convert an Ascii string to Unicode.
2550 * lpSrcStr [I] Source Ascii string to convert
2551 * lpDstStr [O] Destination for converted Unicode string
2552 * iLen [I] Length of lpDstStr
2555 * The return value of the MultiByteToWideChar() function called on lpSrcStr.
2558 * This function simply calls SHAnsiToUnicodeCP with code page CP_ACP.
2560 DWORD WINAPI SHAnsiToUnicode(LPCSTR lpSrcStr, LPWSTR lpDstStr, int iLen)
2562 return SHAnsiToUnicodeCP(CP_ACP, lpSrcStr, lpDstStr, iLen);
2565 /*************************************************************************
2568 * Convert a Unicode string to Ascii.
2571 * CodePage [I] Code page to use for the conversion
2572 * lpSrcStr [I] Source Unicode string to convert
2573 * lpDstStr [O] Destination for converted Ascii string
2574 * lpiLen [I/O] Input length of lpDstStr/destination for length of lpDstStr
2577 * Success: The number of characters that result from the conversion.
2580 INT WINAPI SHUnicodeToAnsiCP(UINT CodePage, LPCWSTR lpSrcStr, LPSTR lpDstStr,
2583 static const WCHAR emptyW[] = { '\0' };
2587 if (!lpDstStr || !lpiLen)
2595 len = strlenW(lpSrcStr) + 1;
2600 CodePage = CP_UTF8; /* Fall through... */
2601 case 0x0000C350: /* FIXME: CP_ #define */
2606 INT nWideCharCount = len - 1;
2608 GET_FUNC(pConvertINetUnicodeToMultiByte, mlang, "ConvertINetUnicodeToMultiByte", 0);
2609 if (!pConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &nWideCharCount, lpDstStr,
2613 if (nWideCharCount < len - 1)
2615 mem = HeapAlloc(GetProcessHeap(), 0, *lpiLen);
2621 if (pConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &len, mem, lpiLen))
2623 SHTruncateString(mem, *lpiLen);
2624 lstrcpynA(lpDstStr, mem, *lpiLen + 1);
2625 HeapFree(GetProcessHeap(), 0, mem);
2628 HeapFree(GetProcessHeap(), 0, mem);
2631 lpDstStr[*lpiLen] = '\0';
2638 reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, lpDstStr,
2639 *lpiLen, NULL, NULL);
2641 if (!reqLen && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
2643 reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, NULL, 0, NULL, NULL);
2646 mem = HeapAlloc(GetProcessHeap(), 0, reqLen);
2649 reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, mem,
2650 reqLen, NULL, NULL);
2652 reqLen = SHTruncateString(mem, *lpiLen);
2655 lstrcpynA(lpDstStr, mem, *lpiLen);
2657 HeapFree(GetProcessHeap(), 0, mem);
2664 /*************************************************************************
2667 * Convert a Unicode string to Ascii.
2670 * lpSrcStr [I] Source Unicode string to convert
2671 * lpDstStr [O] Destination for converted Ascii string
2672 * iLen [O] Length of lpDstStr in characters
2675 * See SHUnicodeToAnsiCP
2678 * This function simply calls SHUnicodeToAnsiCP() with CodePage = CP_ACP.
2680 INT WINAPI SHUnicodeToAnsi(LPCWSTR lpSrcStr, LPSTR lpDstStr, INT iLen)
2684 return SHUnicodeToAnsiCP(CP_ACP, lpSrcStr, lpDstStr, &myint);
2687 /*************************************************************************
2690 * Copy one string to another.
2693 * lpszSrc [I] Source string to copy
2694 * lpszDst [O] Destination for copy
2695 * iLen [I] Length of lpszDst in characters
2698 * The length of the copied string, including the terminating NUL. lpszDst
2699 * contains iLen characters of lpszSrc.
2701 DWORD WINAPI SHAnsiToAnsi(LPCSTR lpszSrc, LPSTR lpszDst, int iLen)
2705 TRACE("(%s,%p,0x%08x)\n", debugstr_a(lpszSrc), lpszDst, iLen);
2707 lpszRet = StrCpyNXA(lpszDst, lpszSrc, iLen);
2708 return lpszRet - lpszDst + 1;
2711 /*************************************************************************
2714 * Unicode version of SSHAnsiToAnsi.
2716 DWORD WINAPI SHUnicodeToUnicode(LPCWSTR lpszSrc, LPWSTR lpszDst, int iLen)
2720 TRACE("(%s,%p,0x%08x)\n", debugstr_w(lpszSrc), lpszDst, iLen);
2722 lpszRet = StrCpyNXW(lpszDst, lpszSrc, iLen);
2723 return lpszRet - lpszDst + 1;
2726 /*************************************************************************
2729 * Determine if an Ascii string converts to Unicode and back identically.
2732 * lpSrcStr [I] Source Unicode string to convert
2733 * lpDst [O] Destination for resulting Ascii string
2734 * iLen [I] Length of lpDst in characters
2737 * TRUE, since Ascii strings always convert identically.
2739 BOOL WINAPI DoesStringRoundTripA(LPCSTR lpSrcStr, LPSTR lpDst, INT iLen)
2741 lstrcpynA(lpDst, lpSrcStr, iLen);
2745 /*************************************************************************
2748 * Determine if a Unicode string converts to Ascii and back identically.
2751 * lpSrcStr [I] Source Unicode string to convert
2752 * lpDst [O] Destination for resulting Ascii string
2753 * iLen [I] Length of lpDst in characters
2756 * TRUE, if lpSrcStr converts to Ascii and back identically,
2759 BOOL WINAPI DoesStringRoundTripW(LPCWSTR lpSrcStr, LPSTR lpDst, INT iLen)
2761 WCHAR szBuff[MAX_PATH];
2763 SHUnicodeToAnsi(lpSrcStr, lpDst, iLen);
2764 SHAnsiToUnicode(lpDst, szBuff, MAX_PATH);
2765 return !strcmpW(lpSrcStr, szBuff);
2768 /*************************************************************************
2769 * SHLoadIndirectString [SHLWAPI.@]
2771 * If passed a string that begins with a '@' extract the string from the
2772 * appropriate resource, otherwise do a straight copy.
2775 HRESULT WINAPI SHLoadIndirectString(LPCWSTR src, LPWSTR dst, UINT dst_len, void **reserved)
2777 WCHAR *dllname = NULL;
2778 HMODULE hmod = NULL;
2779 HRESULT hr = E_FAIL;
2781 TRACE("(%s %p %08x %p)\n", debugstr_w(src), dst, dst_len, reserved);
2789 dllname = StrDupW(src + 1);
2790 index_str = strchrW(dllname, ',');
2792 if(!index_str) goto end;
2796 index = atoiW(index_str);
2798 hmod = LoadLibraryW(dllname);
2803 if(LoadStringW(hmod, -index, dst, dst_len))
2807 FIXME("can't handle non-negative indicies (%d)\n", index);
2812 lstrcpynW(dst, src, dst_len);
2816 TRACE("returing %s\n", debugstr_w(dst));
2818 if(hmod) FreeLibrary(hmod);
2819 HeapFree(GetProcessHeap(), 0, dllname);