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
23 #include "wine/port.h"
30 #define NONAMELESSUNION
31 #define NONAMELESSSTRUCT
34 #define NO_SHLWAPI_REG
35 #define NO_SHLWAPI_STREAM
41 #include "wine/unicode.h"
42 #include "wine/debug.h"
46 WINE_DEFAULT_DEBUG_CHANNEL(shell);
48 /* Get a function pointer from a DLL handle */
49 #define GET_FUNC(func, module, name, fail) \
52 if (!SHLWAPI_h##module && !(SHLWAPI_h##module = LoadLibraryA(#module ".dll"))) return fail; \
53 func = (fn##func)GetProcAddress(SHLWAPI_h##module, name); \
54 if (!func) return fail; \
58 extern HMODULE SHLWAPI_hmlang;
59 extern HINSTANCE shlwapi_hInstance;
61 typedef HRESULT (WINAPI *fnpConvertINetUnicodeToMultiByte)(LPDWORD,DWORD,LPCWSTR,LPINT,LPSTR,LPINT);
62 static fnpConvertINetUnicodeToMultiByte pConvertINetUnicodeToMultiByte;
64 static HRESULT WINAPI _SHStrDupAA(LPCSTR,LPSTR*);
65 static HRESULT WINAPI _SHStrDupAW(LPCWSTR,LPSTR*);
68 static void FillNumberFmt(NUMBERFMTW *fmt, LPWSTR decimal_buffer, int decimal_bufwlen,
69 LPWSTR thousand_buffer, int thousand_bufwlen)
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, decimal_bufwlen);
78 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, thousand_buffer, thousand_bufwlen);
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, sizeof decimal / sizeof (WCHAR),
118 thousand, sizeof thousand / sizeof (WCHAR));
124 *(--c) = '0' + (qdwValue%10);
126 } while (qdwValue > 0);
130 return GetNumberFormatW(LOCALE_USER_DEFAULT, 0, c, &fmt, pszBuf, cchBuf);
133 /*************************************************************************
134 * FormatDouble [internal]
136 * Format an integer according to the current locale. Prints the specified number of digits
137 * after the decimal point
140 * The number of bytes written on success or 0 on failure
142 static int FormatDouble(double value, int decimals, LPWSTR pszBuf, int cchBuf)
144 static const WCHAR flfmt[] = {'%','f',0};
147 WCHAR decimal[8], thousand[8];
149 snprintfW(buf, 64, flfmt, value);
151 FillNumberFmt(&fmt, decimal, sizeof decimal / sizeof (WCHAR),
152 thousand, sizeof thousand / sizeof (WCHAR));
153 fmt.NumDigits = decimals;
154 return GetNumberFormatW(LOCALE_USER_DEFAULT, 0, buf, &fmt, pszBuf, cchBuf);
157 /*************************************************************************
158 * SHLWAPI_ChrCmpHelperA
160 * Internal helper for SHLWAPI_ChrCmpA/ChrCMPIA.
163 * Both this function and its Unicode counterpart are very inefficient. To
164 * fix this, CompareString must be completely implemented and optimised
165 * first. Then the core character test can be taken out of that function and
166 * placed here, so that it need never be called at all. Until then, do not
167 * attempt to optimise this code unless you are willing to test that it
168 * still performs correctly.
170 static BOOL WINAPI SHLWAPI_ChrCmpHelperA(WORD ch1, WORD ch2, DWORD dwFlags)
172 char str1[3], str2[3];
174 str1[0] = LOBYTE(ch1);
175 if (IsDBCSLeadByte(str1[0]))
177 str1[1] = HIBYTE(ch1);
183 str2[0] = LOBYTE(ch2);
184 if (IsDBCSLeadByte(str2[0]))
186 str2[1] = HIBYTE(ch2);
192 return CompareStringA(GetThreadLocale(), dwFlags, str1, -1, str2, -1) - 2;
195 /*************************************************************************
196 * SHLWAPI_ChrCmpHelperW
198 * Internal helper for SHLWAPI_ChrCmpW/ChrCmpIW.
200 static BOOL WINAPI SHLWAPI_ChrCmpHelperW(WCHAR ch1, WCHAR ch2, DWORD dwFlags)
202 WCHAR str1[2], str2[2];
208 return CompareStringW(GetThreadLocale(), dwFlags, str1, 2, str2, 2) - 2;
211 /*************************************************************************
214 * Internal helper function.
216 static BOOL WINAPI SHLWAPI_ChrCmpA(WORD ch1, WORD ch2)
218 return SHLWAPI_ChrCmpHelperA(ch1, ch2, 0);
221 /*************************************************************************
222 * ChrCmpIA (SHLWAPI.385)
224 * Compare two characters, ignoring case.
227 * ch1 [I] First character to compare
228 * ch2 [I] Second character to compare
231 * FALSE, if the characters are equal.
232 * Non-zero otherwise.
234 BOOL WINAPI ChrCmpIA(WORD ch1, WORD ch2)
236 TRACE("(%d,%d)\n", ch1, ch2);
238 return SHLWAPI_ChrCmpHelperA(ch1, ch2, NORM_IGNORECASE);
241 /*************************************************************************
244 * Internal helper function.
246 static BOOL WINAPI SHLWAPI_ChrCmpW(WCHAR ch1, WCHAR ch2)
248 return SHLWAPI_ChrCmpHelperW(ch1, ch2, 0);
251 /*************************************************************************
252 * ChrCmpIW [SHLWAPI.386]
256 BOOL WINAPI ChrCmpIW(WCHAR ch1, WCHAR ch2)
258 return SHLWAPI_ChrCmpHelperW(ch1, ch2, NORM_IGNORECASE);
261 /*************************************************************************
262 * StrChrA [SHLWAPI.@]
264 * Find a given character in a string.
267 * lpszStr [I] String to search in.
268 * ch [I] Character to search for.
271 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
273 * Failure: NULL, if any arguments are invalid.
275 LPSTR WINAPI StrChrA(LPCSTR lpszStr, WORD ch)
277 TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch);
283 if (!SHLWAPI_ChrCmpA(*lpszStr, ch))
284 return (LPSTR)lpszStr;
285 lpszStr = CharNextA(lpszStr);
291 /*************************************************************************
292 * StrChrW [SHLWAPI.@]
296 LPWSTR WINAPI StrChrW(LPCWSTR lpszStr, WCHAR ch)
298 LPWSTR lpszRet = NULL;
300 TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch);
303 lpszRet = strchrW(lpszStr, ch);
307 /*************************************************************************
308 * StrChrIA [SHLWAPI.@]
310 * Find a given character in a string, ignoring case.
313 * lpszStr [I] String to search in.
314 * ch [I] Character to search for.
317 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
319 * Failure: NULL, if any arguments are invalid.
321 LPSTR WINAPI StrChrIA(LPCSTR lpszStr, WORD ch)
323 TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch);
329 if (!ChrCmpIA(*lpszStr, ch))
330 return (LPSTR)lpszStr;
331 lpszStr = CharNextA(lpszStr);
337 /*************************************************************************
338 * StrChrIW [SHLWAPI.@]
342 LPWSTR WINAPI StrChrIW(LPCWSTR lpszStr, WCHAR ch)
344 TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch);
351 if (toupperW(*lpszStr) == ch)
352 return (LPWSTR)lpszStr;
353 lpszStr = CharNextW(lpszStr);
357 return (LPWSTR)lpszStr;
360 /*************************************************************************
361 * StrCmpIW [SHLWAPI.@]
363 * Compare two strings, ignoring case.
366 * lpszStr [I] First string to compare
367 * lpszComp [I] Second string to compare
370 * An integer less than, equal to or greater than 0, indicating that
371 * lpszStr is less than, the same, or greater than lpszComp.
373 int WINAPI StrCmpIW(LPCWSTR lpszStr, LPCWSTR lpszComp)
377 TRACE("(%s,%s)\n", debugstr_w(lpszStr),debugstr_w(lpszComp));
379 iRet = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, lpszStr, -1, lpszComp, -1);
380 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
383 /*************************************************************************
384 * StrCmpNA [SHLWAPI.@]
386 * Compare two strings, up to a maximum length.
389 * lpszStr [I] First string to compare
390 * lpszComp [I] Second string to compare
391 * iLen [I] Maximum number of chars to compare.
394 * An integer less than, equal to or greater than 0, indicating that
395 * lpszStr is less than, the same, or greater than lpszComp.
397 INT WINAPI StrCmpNA(LPCSTR lpszStr, LPCSTR lpszComp, INT iLen)
401 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
403 iRet = CompareStringA(GetThreadLocale(), 0, lpszStr, iLen, lpszComp, iLen);
404 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
407 /*************************************************************************
408 * StrCmpNW [SHLWAPI.@]
412 INT WINAPI StrCmpNW(LPCWSTR lpszStr, LPCWSTR lpszComp, INT iLen)
416 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen);
418 iRet = CompareStringW(GetThreadLocale(), 0, lpszStr, iLen, lpszComp, iLen);
419 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
422 /*************************************************************************
423 * StrCmpNIA [SHLWAPI.@]
425 * Compare two strings, up to a maximum length, ignoring case.
428 * lpszStr [I] First string to compare
429 * lpszComp [I] Second string to compare
430 * iLen [I] Maximum number of chars to compare.
433 * An integer less than, equal to or greater than 0, indicating that
434 * lpszStr is less than, the same, or greater than lpszComp.
436 int WINAPI StrCmpNIA(LPCSTR lpszStr, LPCSTR lpszComp, int iLen)
440 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
442 iRet = CompareStringA(GetThreadLocale(), NORM_IGNORECASE, lpszStr, iLen, lpszComp, iLen);
443 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
446 /*************************************************************************
447 * StrCmpNIW [SHLWAPI.@]
451 INT WINAPI StrCmpNIW(LPCWSTR lpszStr, LPCWSTR lpszComp, int iLen)
455 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen);
457 iRet = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, lpszStr, iLen, lpszComp, iLen);
458 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
461 /*************************************************************************
462 * StrCmpW [SHLWAPI.@]
464 * Compare two strings.
467 * lpszStr [I] First string to compare
468 * lpszComp [I] Second string to compare
471 * An integer less than, equal to or greater than 0, indicating that
472 * lpszStr is less than, the same, or greater than lpszComp.
474 int WINAPI StrCmpW(LPCWSTR lpszStr, LPCWSTR lpszComp)
478 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszComp));
480 iRet = CompareStringW(GetThreadLocale(), 0, lpszStr, -1, lpszComp, -1);
481 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
484 /*************************************************************************
485 * StrCatW [SHLWAPI.@]
487 * Concatanate two strings.
490 * lpszStr [O] Initial string
491 * lpszSrc [I] String to concatanate
496 LPWSTR WINAPI StrCatW(LPWSTR lpszStr, LPCWSTR lpszSrc)
498 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSrc));
500 strcatW(lpszStr, lpszSrc);
504 /*************************************************************************
505 * StrCpyW [SHLWAPI.@]
507 * Copy a string to another string.
510 * lpszStr [O] Destination string
511 * lpszSrc [I] Source string
516 LPWSTR WINAPI StrCpyW(LPWSTR lpszStr, LPCWSTR lpszSrc)
518 TRACE("(%p,%s)\n", lpszStr, debugstr_w(lpszSrc));
520 strcpyW(lpszStr, lpszSrc);
524 /*************************************************************************
525 * StrCpyNW [SHLWAPI.@]
527 * Copy a string to another string, up to a maximum number of characters.
530 * lpszStr [O] Destination string
531 * lpszSrc [I] Source string
532 * iLen [I] Maximum number of chars to copy
537 LPWSTR WINAPI StrCpyNW(LPWSTR lpszStr, LPCWSTR lpszSrc, int iLen)
539 TRACE("(%p,%s,%i)\n", lpszStr, debugstr_w(lpszSrc), iLen);
541 lstrcpynW(lpszStr, lpszSrc, iLen);
547 /*************************************************************************
548 * SHLWAPI_StrStrHelperA
550 * Internal implementation of StrStrA/StrStrIA
552 static LPSTR WINAPI SHLWAPI_StrStrHelperA(LPCSTR lpszStr, LPCSTR lpszSearch,
553 int (*pStrCmpFn)(LPCSTR,LPCSTR,size_t))
557 if (!lpszStr || !lpszSearch || !*lpszSearch)
560 iLen = strlen(lpszSearch);
564 if (!pStrCmpFn(lpszStr, lpszSearch, iLen))
565 return (LPSTR)lpszStr;
566 lpszStr = CharNextA(lpszStr);
571 /*************************************************************************
572 * SHLWAPI_StrStrHelperW
574 * Internal implementation of StrStrW/StrStrIW
576 static LPWSTR WINAPI SHLWAPI_StrStrHelperW(LPCWSTR lpszStr, LPCWSTR lpszSearch,
577 int (*pStrCmpFn)(LPCWSTR,LPCWSTR,int))
581 if (!lpszStr || !lpszSearch || !*lpszSearch)
584 iLen = strlenW(lpszSearch);
588 if (!pStrCmpFn(lpszStr, lpszSearch, iLen))
589 return (LPWSTR)lpszStr;
590 lpszStr = CharNextW(lpszStr);
595 /*************************************************************************
596 * StrStrA [SHLWAPI.@]
598 * Find a substring within a string.
601 * lpszStr [I] String to search in
602 * lpszSearch [I] String to look for
605 * The start of lpszSearch within lpszStr, or NULL if not found.
607 LPSTR WINAPI StrStrA(LPCSTR lpszStr, LPCSTR lpszSearch)
609 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
611 return SHLWAPI_StrStrHelperA(lpszStr, lpszSearch, strncmp);
614 /*************************************************************************
615 * StrStrW [SHLWAPI.@]
619 LPWSTR WINAPI StrStrW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
621 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
623 return SHLWAPI_StrStrHelperW(lpszStr, lpszSearch, strncmpW);
626 /*************************************************************************
627 * StrRStrIA [SHLWAPI.@]
629 * Find the last occurrence of a substring within a string.
632 * lpszStr [I] String to search in
633 * lpszEnd [I] End of lpszStr
634 * lpszSearch [I] String to look for
637 * The last occurrence lpszSearch within lpszStr, or NULL if not found.
639 LPSTR WINAPI StrRStrIA(LPCSTR lpszStr, LPCSTR lpszEnd, LPCSTR lpszSearch)
644 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
646 if (!lpszStr || !lpszSearch || !*lpszSearch)
650 lpszEnd = lpszStr + lstrlenA(lpszStr);
651 if (lpszEnd == lpszStr)
654 if (IsDBCSLeadByte(*lpszSearch))
655 ch1 = *lpszSearch << 8 | (UCHAR)lpszSearch[1];
658 iLen = lstrlenA(lpszSearch);
662 lpszEnd = CharPrevA(lpszStr, lpszEnd);
663 ch2 = IsDBCSLeadByte(*lpszEnd)? *lpszEnd << 8 | (UCHAR)lpszEnd[1] : *lpszEnd;
664 if (!ChrCmpIA(ch1, ch2))
666 if (!StrCmpNIA(lpszEnd, lpszSearch, iLen))
667 return (LPSTR)lpszEnd;
669 } while (lpszEnd > lpszStr);
673 /*************************************************************************
674 * StrRStrIW [SHLWAPI.@]
678 LPWSTR WINAPI StrRStrIW(LPCWSTR lpszStr, LPCWSTR lpszEnd, LPCWSTR lpszSearch)
682 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
684 if (!lpszStr || !lpszSearch || !*lpszSearch)
688 lpszEnd = lpszStr + strlenW(lpszStr);
689 if (lpszEnd == lpszStr)
692 iLen = strlenW(lpszSearch);
696 lpszEnd = CharPrevW(lpszStr, lpszEnd);
697 if (!ChrCmpIW(*lpszSearch, *lpszEnd))
699 if (!StrCmpNIW(lpszEnd, lpszSearch, iLen))
700 return (LPWSTR)lpszEnd;
702 } while (lpszEnd > lpszStr);
706 /*************************************************************************
707 * StrStrIA [SHLWAPI.@]
709 * Find a substring within a string, ignoring case.
712 * lpszStr [I] String to search in
713 * lpszSearch [I] String to look for
716 * The start of lpszSearch within lpszStr, or NULL if not found.
718 LPSTR WINAPI StrStrIA(LPCSTR lpszStr, LPCSTR lpszSearch)
720 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
722 return SHLWAPI_StrStrHelperA(lpszStr, lpszSearch, strncasecmp);
725 /*************************************************************************
726 * StrStrIW [SHLWAPI.@]
730 LPWSTR WINAPI StrStrIW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
732 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
734 return SHLWAPI_StrStrHelperW(lpszStr, lpszSearch, strncmpiW);
737 /*************************************************************************
738 * StrToIntA [SHLWAPI.@]
740 * Read a signed integer from a string.
743 * lpszStr [I] String to read integer from
746 * The signed integer value represented by the string, or 0 if no integer is
750 * No leading space is allowed before the number, although a leading '-' is.
752 int WINAPI StrToIntA(LPCSTR lpszStr)
756 TRACE("(%s)\n", debugstr_a(lpszStr));
760 WARN("Invalid lpszStr would crash under Win32!\n");
764 if (*lpszStr == '-' || isdigit(*lpszStr))
765 StrToIntExA(lpszStr, 0, &iRet);
769 /*************************************************************************
770 * StrToIntW [SHLWAPI.@]
774 int WINAPI StrToIntW(LPCWSTR lpszStr)
778 TRACE("(%s)\n", debugstr_w(lpszStr));
782 WARN("Invalid lpszStr would crash under Win32!\n");
786 if (*lpszStr == '-' || isdigitW(*lpszStr))
787 StrToIntExW(lpszStr, 0, &iRet);
791 /*************************************************************************
792 * StrToIntExA [SHLWAPI.@]
794 * Read an integer from a string.
797 * lpszStr [I] String to read integer from
798 * dwFlags [I] Flags controlling the conversion
799 * lpiRet [O] Destination for read integer.
802 * Success: TRUE. lpiRet contains the integer value represented by the string.
803 * Failure: FALSE, if the string is invalid, or no number is present.
806 * Leading whitespace, '-' and '+' are allowed before the number. If
807 * dwFlags includes STIF_SUPPORT_HEX, hexadecimal numbers are allowed, if
808 * preceded by '0x'. If this flag is not set, or there is no '0x' prefix,
809 * the string is treated as a decimal string. A leading '-' is ignored for
810 * hexadecimal numbers.
812 BOOL WINAPI StrToIntExA(LPCSTR lpszStr, DWORD dwFlags, LPINT lpiRet)
814 BOOL bNegative = FALSE;
817 TRACE("(%s,%08X,%p)\n", debugstr_a(lpszStr), dwFlags, lpiRet);
819 if (!lpszStr || !lpiRet)
821 WARN("Invalid parameter would crash under Win32!\n");
824 if (dwFlags > STIF_SUPPORT_HEX)
826 WARN("Unknown flags (%08lX)!\n", dwFlags & ~STIF_SUPPORT_HEX);
829 /* Skip leading space, '+', '-' */
830 while (isspace(*lpszStr))
831 lpszStr = CharNextA(lpszStr);
838 else if (*lpszStr == '+')
841 if (dwFlags & STIF_SUPPORT_HEX &&
842 *lpszStr == '0' && tolower(lpszStr[1]) == 'x')
844 /* Read hex number */
847 if (!isxdigit(*lpszStr))
850 while (isxdigit(*lpszStr))
853 if (isdigit(*lpszStr))
854 iRet += (*lpszStr - '0');
856 iRet += 10 + (tolower(*lpszStr) - 'a');
863 /* Read decimal number */
864 if (!isdigit(*lpszStr))
867 while (isdigit(*lpszStr))
870 iRet += (*lpszStr - '0');
873 *lpiRet = bNegative ? -iRet : iRet;
877 /*************************************************************************
878 * StrToIntExW [SHLWAPI.@]
882 BOOL WINAPI StrToIntExW(LPCWSTR lpszStr, DWORD dwFlags, LPINT lpiRet)
884 BOOL bNegative = FALSE;
887 TRACE("(%s,%08X,%p)\n", debugstr_w(lpszStr), dwFlags, lpiRet);
889 if (!lpszStr || !lpiRet)
891 WARN("Invalid parameter would crash under Win32!\n");
894 if (dwFlags > STIF_SUPPORT_HEX)
896 WARN("Unknown flags (%08lX)!\n", dwFlags & ~STIF_SUPPORT_HEX);
899 /* Skip leading space, '+', '-' */
900 while (isspaceW(*lpszStr))
901 lpszStr = CharNextW(lpszStr);
908 else if (*lpszStr == '+')
911 if (dwFlags & STIF_SUPPORT_HEX &&
912 *lpszStr == '0' && tolowerW(lpszStr[1]) == 'x')
914 /* Read hex number */
917 if (!isxdigitW(*lpszStr))
920 while (isxdigitW(*lpszStr))
923 if (isdigitW(*lpszStr))
924 iRet += (*lpszStr - '0');
926 iRet += 10 + (tolowerW(*lpszStr) - 'a');
933 /* Read decimal number */
934 if (!isdigitW(*lpszStr))
937 while (isdigitW(*lpszStr))
940 iRet += (*lpszStr - '0');
943 *lpiRet = bNegative ? -iRet : iRet;
947 /*************************************************************************
948 * StrDupA [SHLWAPI.@]
950 * Duplicate a string.
953 * lpszStr [I] String to duplicate.
956 * Success: A pointer to a new string containing the contents of lpszStr
957 * Failure: NULL, if memory cannot be allocated
960 * The string memory is allocated with LocalAlloc(), and so should be released
961 * by calling LocalFree().
963 LPSTR WINAPI StrDupA(LPCSTR lpszStr)
968 TRACE("(%s)\n",debugstr_a(lpszStr));
970 iLen = lpszStr ? strlen(lpszStr) + 1 : 1;
971 lpszRet = (LPSTR)LocalAlloc(LMEM_FIXED, iLen);
976 memcpy(lpszRet, lpszStr, iLen);
983 /*************************************************************************
984 * StrDupW [SHLWAPI.@]
988 LPWSTR WINAPI StrDupW(LPCWSTR lpszStr)
993 TRACE("(%s)\n",debugstr_w(lpszStr));
995 iLen = (lpszStr ? strlenW(lpszStr) + 1 : 1) * sizeof(WCHAR);
996 lpszRet = (LPWSTR)LocalAlloc(LMEM_FIXED, iLen);
1001 memcpy(lpszRet, lpszStr, iLen);
1008 /*************************************************************************
1009 * SHLWAPI_StrSpnHelperA
1011 * Internal implementation of StrSpnA/StrCSpnA/StrCSpnIA
1013 static int WINAPI SHLWAPI_StrSpnHelperA(LPCSTR lpszStr, LPCSTR lpszMatch,
1014 LPSTR (WINAPI *pStrChrFn)(LPCSTR,WORD),
1017 LPCSTR lpszRead = lpszStr;
1018 if (lpszStr && *lpszStr && lpszMatch)
1022 LPCSTR lpszTest = pStrChrFn(lpszMatch, *lpszRead);
1024 if (!bInvert && !lpszTest)
1026 if (bInvert && lpszTest)
1028 lpszRead = CharNextA(lpszRead);
1031 return lpszRead - lpszStr;
1034 /*************************************************************************
1035 * SHLWAPI_StrSpnHelperW
1037 * Internal implementation of StrSpnW/StrCSpnW/StrCSpnIW
1039 static int WINAPI SHLWAPI_StrSpnHelperW(LPCWSTR lpszStr, LPCWSTR lpszMatch,
1040 LPWSTR (WINAPI *pStrChrFn)(LPCWSTR,WCHAR),
1043 LPCWSTR lpszRead = lpszStr;
1044 if (lpszStr && *lpszStr && lpszMatch)
1048 LPCWSTR lpszTest = pStrChrFn(lpszMatch, *lpszRead);
1050 if (!bInvert && !lpszTest)
1052 if (bInvert && lpszTest)
1054 lpszRead = CharNextW(lpszRead);
1057 return lpszRead - lpszStr;
1060 /*************************************************************************
1061 * StrSpnA [SHLWAPI.@]
1063 * Find the length of the start of a string that contains only certain
1067 * lpszStr [I] String to search
1068 * lpszMatch [I] Characters that can be in the substring
1071 * The length of the part of lpszStr containing only chars from lpszMatch,
1072 * or 0 if any parameter is invalid.
1074 int WINAPI StrSpnA(LPCSTR lpszStr, LPCSTR lpszMatch)
1076 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1078 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, FALSE);
1081 /*************************************************************************
1082 * StrSpnW [SHLWAPI.@]
1086 int WINAPI StrSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1088 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1090 return SHLWAPI_StrSpnHelperW(lpszStr, lpszMatch, StrChrW, FALSE);
1093 /*************************************************************************
1094 * StrCSpnA [SHLWAPI.@]
1096 * Find the length of the start of a string that does not contain certain
1100 * lpszStr [I] String to search
1101 * lpszMatch [I] Characters that cannot be in the substring
1104 * The length of the part of lpszStr containing only chars not in lpszMatch,
1105 * or 0 if any parameter is invalid.
1107 int WINAPI StrCSpnA(LPCSTR lpszStr, LPCSTR lpszMatch)
1109 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1111 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, TRUE);
1114 /*************************************************************************
1115 * StrCSpnW [SHLWAPI.@]
1119 int WINAPI StrCSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1121 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1123 return SHLWAPI_StrSpnHelperW(lpszStr, lpszMatch, StrChrW, TRUE);
1126 /*************************************************************************
1127 * StrCSpnIA [SHLWAPI.@]
1129 * Find the length of the start of a string that does not contain certain
1130 * characters, ignoring case.
1133 * lpszStr [I] String to search
1134 * lpszMatch [I] Characters that cannot be in the substring
1137 * The length of the part of lpszStr containing only chars not in lpszMatch,
1138 * or 0 if any parameter is invalid.
1140 int WINAPI StrCSpnIA(LPCSTR lpszStr, LPCSTR lpszMatch)
1142 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1144 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrIA, TRUE);
1147 /*************************************************************************
1148 * StrCSpnIW [SHLWAPI.@]
1152 int WINAPI StrCSpnIW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1154 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1156 return SHLWAPI_StrSpnHelperW(lpszStr, lpszMatch, StrChrIW, TRUE);
1159 /*************************************************************************
1160 * StrPBrkA [SHLWAPI.@]
1162 * Search a string for any of a group of characters.
1165 * lpszStr [I] String to search
1166 * lpszMatch [I] Characters to match
1169 * A pointer to the first matching character in lpszStr, or NULL if no
1172 LPSTR WINAPI StrPBrkA(LPCSTR lpszStr, LPCSTR lpszMatch)
1174 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1176 if (lpszStr && lpszMatch && *lpszMatch)
1180 if (StrChrA(lpszMatch, *lpszStr))
1181 return (LPSTR)lpszStr;
1182 lpszStr = CharNextA(lpszStr);
1188 /*************************************************************************
1189 * StrPBrkW [SHLWAPI.@]
1193 LPWSTR WINAPI StrPBrkW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1195 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1197 if (lpszStr && lpszMatch && *lpszMatch)
1201 if (StrChrW(lpszMatch, *lpszStr))
1202 return (LPWSTR)lpszStr;
1203 lpszStr = CharNextW(lpszStr);
1209 /*************************************************************************
1210 * SHLWAPI_StrRChrHelperA
1212 * Internal implementation of StrRChrA/StrRChrIA.
1214 static LPSTR WINAPI SHLWAPI_StrRChrHelperA(LPCSTR lpszStr,
1215 LPCSTR lpszEnd, WORD ch,
1216 BOOL (WINAPI *pChrCmpFn)(WORD,WORD))
1218 LPCSTR lpszRet = NULL;
1225 lpszEnd = lpszStr + lstrlenA(lpszStr);
1227 while (*lpszStr && lpszStr <= lpszEnd)
1229 ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr;
1231 if (!pChrCmpFn(ch, ch2))
1233 lpszStr = CharNextA(lpszStr);
1236 return (LPSTR)lpszRet;
1239 /*************************************************************************
1240 * SHLWAPI_StrRChrHelperW
1242 * Internal implementation of StrRChrW/StrRChrIW.
1244 static LPWSTR WINAPI SHLWAPI_StrRChrHelperW(LPCWSTR lpszStr,
1245 LPCWSTR lpszEnd, WCHAR ch,
1246 BOOL (WINAPI *pChrCmpFn)(WCHAR,WCHAR))
1248 LPCWSTR lpszRet = NULL;
1253 lpszEnd = lpszStr + strlenW(lpszStr);
1255 while (*lpszStr && lpszStr <= lpszEnd)
1257 if (!pChrCmpFn(ch, *lpszStr))
1259 lpszStr = CharNextW(lpszStr);
1262 return (LPWSTR)lpszRet;
1265 /**************************************************************************
1266 * StrRChrA [SHLWAPI.@]
1268 * Find the last occurrence of a character in string.
1271 * lpszStr [I] String to search in
1272 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1273 * ch [I] Character to search for.
1276 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1277 * or NULL if not found.
1278 * Failure: NULL, if any arguments are invalid.
1280 LPSTR WINAPI StrRChrA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch)
1282 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch);
1284 return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, SHLWAPI_ChrCmpA);
1287 /**************************************************************************
1288 * StrRChrW [SHLWAPI.@]
1292 LPWSTR WINAPI StrRChrW(LPCWSTR lpszStr, LPCWSTR lpszEnd, WORD ch)
1294 TRACE("(%s,%s,%x)\n", debugstr_w(lpszStr), debugstr_w(lpszEnd), ch);
1296 return SHLWAPI_StrRChrHelperW(lpszStr, lpszEnd, ch, SHLWAPI_ChrCmpW);
1299 /**************************************************************************
1300 * StrRChrIA [SHLWAPI.@]
1302 * Find the last occurrence of a character in string, ignoring case.
1305 * lpszStr [I] String to search in
1306 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1307 * ch [I] Character to search for.
1310 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1311 * or NULL if not found.
1312 * Failure: NULL, if any arguments are invalid.
1314 LPSTR WINAPI StrRChrIA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch)
1316 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch);
1318 return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, ChrCmpIA);
1321 /**************************************************************************
1322 * StrRChrIW [SHLWAPI.@]
1326 LPWSTR WINAPI StrRChrIW(LPCWSTR lpszStr, LPCWSTR lpszEnd, WORD ch)
1328 TRACE("(%s,%s,%x)\n", debugstr_w(lpszStr), debugstr_w(lpszEnd), ch);
1330 return SHLWAPI_StrRChrHelperW(lpszStr, lpszEnd, ch, ChrCmpIW);
1333 /*************************************************************************
1334 * StrCatBuffA [SHLWAPI.@]
1336 * Concatenate two strings together.
1339 * lpszStr [O] String to concatenate to
1340 * lpszCat [I] String to add to lpszCat
1341 * cchMax [I] Maximum number of characters for the whole string
1347 * cchMax determines the number of characters in the final length of the
1348 * string, not the number appended to lpszStr from lpszCat.
1350 LPSTR WINAPI StrCatBuffA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax)
1354 TRACE("(%p,%s,%d)\n", lpszStr, debugstr_a(lpszCat), cchMax);
1358 WARN("Invalid lpszStr would crash under Win32!\n");
1362 iLen = strlen(lpszStr);
1366 StrCpyNA(lpszStr + iLen, lpszCat, cchMax);
1370 /*************************************************************************
1371 * StrCatBuffW [SHLWAPI.@]
1375 LPWSTR WINAPI StrCatBuffW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax)
1379 TRACE("(%p,%s,%d)\n", lpszStr, debugstr_w(lpszCat), cchMax);
1383 WARN("Invalid lpszStr would crash under Win32!\n");
1387 iLen = strlenW(lpszStr);
1391 StrCpyNW(lpszStr + iLen, lpszCat, cchMax);
1395 /*************************************************************************
1396 * StrRetToBufA [SHLWAPI.@]
1398 * Convert a STRRET to a normal string.
1401 * lpStrRet [O] STRRET to convert
1402 * pIdl [I] ITEMIDLIST for lpStrRet->uType == STRRET_OFFSET
1403 * lpszDest [O] Destination for normal string
1404 * dwLen [I] Length of lpszDest
1407 * Success: S_OK. lpszDest contains up to dwLen characters of the string.
1408 * If lpStrRet is of type STRRET_WSTR, its memory is freed with
1409 * CoTaskMemFree() and its type set to STRRET_CSTRA.
1410 * Failure: E_FAIL, if any parameters are invalid.
1412 HRESULT WINAPI StrRetToBufA (LPSTRRET src, const ITEMIDLIST *pidl, LPSTR dest, UINT len)
1415 * This routine is identical to that in dlls/shell32/shellstring.c.
1416 * It was duplicated because not every version of Shlwapi.dll exports
1417 * StrRetToBufA. If you change one routine, change them both.
1419 TRACE("dest=%p len=0x%x strret=%p pidl=%p stub\n",dest,len,src,pidl);
1423 WARN("Invalid lpStrRet would crash under Win32!\n");
1437 WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, dest, len, NULL, NULL);
1438 CoTaskMemFree(src->u.pOleStr);
1442 lstrcpynA((LPSTR)dest, src->u.cStr, len);
1446 lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len);
1450 FIXME("unknown type!\n");
1456 /*************************************************************************
1457 * StrRetToBufW [SHLWAPI.@]
1461 HRESULT WINAPI StrRetToBufW (LPSTRRET src, const ITEMIDLIST *pidl, LPWSTR dest, UINT len)
1463 TRACE("dest=%p len=0x%x strret=%p pidl=%p stub\n",dest,len,src,pidl);
1467 WARN("Invalid lpStrRet would crash under Win32!\n");
1481 lstrcpynW((LPWSTR)dest, src->u.pOleStr, len);
1482 CoTaskMemFree(src->u.pOleStr);
1486 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
1493 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1,
1500 FIXME("unknown type!\n");
1506 /*************************************************************************
1507 * StrRetToStrA [SHLWAPI.@]
1509 * Converts a STRRET to a normal string.
1512 * lpStrRet [O] STRRET to convert
1513 * pidl [I] ITEMIDLIST for lpStrRet->uType == STRRET_OFFSET
1514 * ppszName [O] Destination for converted string
1517 * Success: S_OK. ppszName contains the new string, allocated with CoTaskMemAlloc().
1518 * Failure: E_FAIL, if any parameters are invalid.
1520 HRESULT WINAPI StrRetToStrA(LPSTRRET lpStrRet, const ITEMIDLIST *pidl, LPSTR *ppszName)
1522 HRESULT hRet = E_FAIL;
1524 switch (lpStrRet->uType)
1527 hRet = _SHStrDupAW(lpStrRet->u.pOleStr, ppszName);
1528 CoTaskMemFree(lpStrRet->u.pOleStr);
1532 hRet = _SHStrDupAA(lpStrRet->u.cStr, ppszName);
1536 hRet = _SHStrDupAA(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, ppszName);
1546 /*************************************************************************
1547 * StrRetToStrW [SHLWAPI.@]
1551 HRESULT WINAPI StrRetToStrW(LPSTRRET lpStrRet, const ITEMIDLIST *pidl, LPWSTR *ppszName)
1553 HRESULT hRet = E_FAIL;
1555 switch (lpStrRet->uType)
1558 hRet = SHStrDupW(lpStrRet->u.pOleStr, ppszName);
1559 CoTaskMemFree(lpStrRet->u.pOleStr);
1563 hRet = SHStrDupA(lpStrRet->u.cStr, ppszName);
1567 hRet = SHStrDupA(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, ppszName);
1577 /* Create an ASCII string copy using SysAllocString() */
1578 static HRESULT _SHStrDupAToBSTR(LPCSTR src, BSTR *pBstrOut)
1584 INT len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0);
1585 WCHAR* szTemp = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1589 MultiByteToWideChar(CP_ACP, 0, src, -1, szTemp, len);
1590 *pBstrOut = SysAllocString(szTemp);
1591 HeapFree(GetProcessHeap(), 0, szTemp);
1597 return E_OUTOFMEMORY;
1600 /*************************************************************************
1601 * StrRetToBSTR [SHLWAPI.@]
1603 * Converts a STRRET to a BSTR.
1606 * lpStrRet [O] STRRET to convert
1607 * pidl [I] ITEMIDLIST for lpStrRet->uType = STRRET_OFFSET
1608 * pBstrOut [O] Destination for converted BSTR
1611 * Success: S_OK. pBstrOut contains the new string.
1612 * Failure: E_FAIL, if any parameters are invalid.
1614 HRESULT WINAPI StrRetToBSTR(STRRET *lpStrRet, LPCITEMIDLIST pidl, BSTR* pBstrOut)
1616 HRESULT hRet = E_FAIL;
1618 switch (lpStrRet->uType)
1621 *pBstrOut = SysAllocString(lpStrRet->u.pOleStr);
1624 CoTaskMemFree(lpStrRet->u.pOleStr);
1628 hRet = _SHStrDupAToBSTR(lpStrRet->u.cStr, pBstrOut);
1632 hRet = _SHStrDupAToBSTR(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, pBstrOut);
1642 /*************************************************************************
1643 * StrFormatKBSizeA [SHLWAPI.@]
1645 * Create a formatted string containing a byte count in Kilobytes.
1648 * llBytes [I] Byte size to format
1649 * lpszDest [I] Destination for formatted string
1650 * cchMax [I] Size of lpszDest
1655 LPSTR WINAPI StrFormatKBSizeA(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax)
1659 if (!StrFormatKBSizeW(llBytes, wszBuf, 256))
1661 if (!WideCharToMultiByte(CP_ACP, 0, wszBuf, -1, lpszDest, cchMax, NULL, NULL))
1666 /*************************************************************************
1667 * StrFormatKBSizeW [SHLWAPI.@]
1669 * See StrFormatKBSizeA.
1671 LPWSTR WINAPI StrFormatKBSizeW(LONGLONG llBytes, LPWSTR lpszDest, UINT cchMax)
1673 static const WCHAR kb[] = {' ','K','B',0};
1674 LONGLONG llKB = (llBytes + 1023) >> 10;
1677 TRACE("(0x%s,%p,%d)\n", wine_dbgstr_longlong(llBytes), lpszDest, cchMax);
1679 if (!FormatInt(llKB, lpszDest, cchMax))
1682 len = lstrlenW(lpszDest);
1683 if (cchMax - len < 4)
1685 lstrcatW(lpszDest, kb);
1689 /*************************************************************************
1690 * StrNCatA [SHLWAPI.@]
1692 * Concatenate two strings together.
1695 * lpszStr [O] String to concatenate to
1696 * lpszCat [I] String to add to lpszCat
1697 * cchMax [I] Maximum number of characters to concatenate
1703 * cchMax determines the number of characters that are appended to lpszStr,
1704 * not the total length of the string.
1706 LPSTR WINAPI StrNCatA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax)
1708 LPSTR lpszRet = lpszStr;
1710 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszCat), cchMax);
1714 WARN("Invalid lpszStr would crash under Win32!\n");
1718 StrCpyNA(lpszStr + strlen(lpszStr), lpszCat, cchMax);
1722 /*************************************************************************
1723 * StrNCatW [SHLWAPI.@]
1727 LPWSTR WINAPI StrNCatW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax)
1729 LPWSTR lpszRet = lpszStr;
1731 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszCat), cchMax);
1735 WARN("Invalid lpszStr would crash under Win32\n");
1739 StrCpyNW(lpszStr + strlenW(lpszStr), lpszCat, cchMax);
1743 /*************************************************************************
1744 * StrTrimA [SHLWAPI.@]
1746 * Remove characters from the start and end of a string.
1749 * lpszStr [O] String to remove characters from
1750 * lpszTrim [I] Characters to remove from lpszStr
1753 * TRUE If lpszStr was valid and modified
1756 BOOL WINAPI StrTrimA(LPSTR lpszStr, LPCSTR lpszTrim)
1759 LPSTR lpszRead = lpszStr;
1762 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszTrim));
1764 if (lpszRead && *lpszRead)
1766 while (*lpszRead && StrChrA(lpszTrim, *lpszRead))
1767 lpszRead = CharNextA(lpszRead); /* Skip leading matches */
1769 dwLen = strlen(lpszRead);
1771 if (lpszRead != lpszStr)
1773 memmove(lpszStr, lpszRead, dwLen + 1);
1778 lpszRead = lpszStr + dwLen;
1779 while (StrChrA(lpszTrim, lpszRead[-1]))
1780 lpszRead = CharPrevA(lpszStr, lpszRead); /* Skip trailing matches */
1782 if (lpszRead != lpszStr + dwLen)
1792 /*************************************************************************
1793 * StrTrimW [SHLWAPI.@]
1797 BOOL WINAPI StrTrimW(LPWSTR lpszStr, LPCWSTR lpszTrim)
1800 LPWSTR lpszRead = lpszStr;
1803 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszTrim));
1805 if (lpszRead && *lpszRead)
1807 while (*lpszRead && StrChrW(lpszTrim, *lpszRead))
1808 lpszRead = CharNextW(lpszRead); /* Skip leading matches */
1810 dwLen = strlenW(lpszRead);
1812 if (lpszRead != lpszStr)
1814 memmove(lpszStr, lpszRead, (dwLen + 1) * sizeof(WCHAR));
1819 lpszRead = lpszStr + dwLen;
1820 while (StrChrW(lpszTrim, lpszRead[-1]))
1821 lpszRead = CharPrevW(lpszStr, lpszRead); /* Skip trailing matches */
1823 if (lpszRead != lpszStr + dwLen)
1833 /*************************************************************************
1834 * _SHStrDupAA [INTERNAL]
1836 * Duplicates a ASCII string to ASCII. The destination buffer is allocated.
1838 static HRESULT WINAPI _SHStrDupAA(LPCSTR src, LPSTR * dest)
1844 len = lstrlenA(src) + 1;
1845 *dest = CoTaskMemAlloc(len);
1851 lstrcpynA(*dest,src, len);
1857 TRACE("%s->(%p)\n", debugstr_a(src), *dest);
1861 /*************************************************************************
1862 * SHStrDupA [SHLWAPI.@]
1864 * Return a Unicode copy of a string, in memory allocated by CoTaskMemAlloc().
1867 * lpszStr [I] String to copy
1868 * lppszDest [O] Destination for the new string copy
1871 * Success: S_OK. lppszDest contains the new string in Unicode format.
1872 * Failure: E_OUTOFMEMORY, If any arguments are invalid or memory allocation
1875 HRESULT WINAPI SHStrDupA(LPCSTR lpszStr, LPWSTR * lppszDest)
1882 len = MultiByteToWideChar(0, 0, lpszStr, -1, 0, 0) * sizeof(WCHAR);
1883 *lppszDest = CoTaskMemAlloc(len);
1890 MultiByteToWideChar(0, 0, lpszStr, -1, *lppszDest, len/sizeof(WCHAR));
1894 hRet = E_OUTOFMEMORY;
1896 TRACE("%s->(%p)\n", debugstr_a(lpszStr), *lppszDest);
1900 /*************************************************************************
1901 * _SHStrDupAW [INTERNAL]
1903 * Duplicates a UNICODE to a ASCII string. The destination buffer is allocated.
1905 static HRESULT WINAPI _SHStrDupAW(LPCWSTR src, LPSTR * dest)
1911 len = WideCharToMultiByte(CP_ACP, 0, src, -1, NULL, 0, NULL, NULL);
1912 *dest = CoTaskMemAlloc(len);
1918 WideCharToMultiByte(CP_ACP, 0, src, -1, *dest, len, NULL, NULL);
1924 TRACE("%s->(%p)\n", debugstr_w(src), *dest);
1928 /*************************************************************************
1929 * SHStrDupW [SHLWAPI.@]
1933 HRESULT WINAPI SHStrDupW(LPCWSTR src, LPWSTR * dest)
1939 len = (lstrlenW(src) + 1) * sizeof(WCHAR);
1940 *dest = CoTaskMemAlloc(len);
1946 memcpy(*dest, src, len);
1952 TRACE("%s->(%p)\n", debugstr_w(src), *dest);
1956 /*************************************************************************
1957 * SHLWAPI_WriteReverseNum
1959 * Internal helper for SHLWAPI_WriteTimeClass.
1961 inline static LPWSTR SHLWAPI_WriteReverseNum(LPWSTR lpszOut, DWORD dwNum)
1965 /* Write a decimal number to a string, backwards */
1968 DWORD dwNextDigit = dwNum % 10;
1969 *lpszOut-- = '0' + dwNextDigit;
1970 dwNum = (dwNum - dwNextDigit) / 10;
1971 } while (dwNum > 0);
1976 /*************************************************************************
1977 * SHLWAPI_FormatSignificant
1979 * Internal helper for SHLWAPI_WriteTimeClass.
1981 inline static int SHLWAPI_FormatSignificant(LPWSTR lpszNum, int dwDigits)
1983 /* Zero non significant digits, return remaining significant digits */
1987 if (--dwDigits == 0)
1997 /*************************************************************************
1998 * SHLWAPI_WriteTimeClass
2000 * Internal helper for StrFromTimeIntervalW.
2002 static int WINAPI SHLWAPI_WriteTimeClass(LPWSTR lpszOut, DWORD dwValue,
2003 UINT uClassStringId, int iDigits)
2005 WCHAR szBuff[64], *szOut = szBuff + 32;
2007 szOut = SHLWAPI_WriteReverseNum(szOut, dwValue);
2008 iDigits = SHLWAPI_FormatSignificant(szOut + 1, iDigits);
2010 LoadStringW(shlwapi_hInstance, uClassStringId, szBuff + 32, 32);
2011 strcatW(lpszOut, szOut);
2015 /*************************************************************************
2016 * StrFromTimeIntervalA [SHLWAPI.@]
2018 * Format a millisecond time interval into a string
2021 * lpszStr [O] Output buffer for formatted time interval
2022 * cchMax [I] Size of lpszStr
2023 * dwMS [I] Number of milliseconds
2024 * iDigits [I] Number of digits to print
2027 * The length of the formatted string, or 0 if any parameter is invalid.
2030 * This implementation mimics the Win32 behaviour of always writing a leading
2031 * space before the time interval begins.
2033 * iDigits is used to provide approximate times if accuracy is not important.
2034 * This number of digits will be written of the first non-zero time class
2035 * (hours/minutes/seconds). If this does not complete the time classification,
2036 * the remaining digits are changed to zeros (i.e. The time is _not_ rounded).
2037 * If there are digits remaining following the writing of a time class, the
2038 * next time class will be written.
2040 * For example, given dwMS represents 138 hours,43 minutes and 15 seconds, the
2041 * following will result from the given values of iDigits:
2043 *| iDigits 1 2 3 4 5 ...
2044 *| lpszStr "100 hr" "130 hr" "138 hr" "138 hr 40 min" "138 hr 43 min" ...
2046 INT WINAPI StrFromTimeIntervalA(LPSTR lpszStr, UINT cchMax, DWORD dwMS,
2051 TRACE("(%p,%d,%d,%d)\n", lpszStr, cchMax, dwMS, iDigits);
2053 if (lpszStr && cchMax)
2056 StrFromTimeIntervalW(szBuff, sizeof(szBuff)/sizeof(WCHAR), dwMS, iDigits);
2057 WideCharToMultiByte(CP_ACP,0,szBuff,-1,lpszStr,cchMax,0,0);
2063 /*************************************************************************
2064 * StrFromTimeIntervalW [SHLWAPI.@]
2066 * See StrFromTimeIntervalA.
2068 INT WINAPI StrFromTimeIntervalW(LPWSTR lpszStr, UINT cchMax, DWORD dwMS,
2073 TRACE("(%p,%d,%d,%d)\n", lpszStr, cchMax, dwMS, iDigits);
2075 if (lpszStr && cchMax)
2078 DWORD dwHours, dwMinutes;
2080 if (!iDigits || cchMax == 1)
2086 /* Calculate the time classes */
2087 dwMS = (dwMS + 500) / 1000;
2088 dwHours = dwMS / 3600;
2089 dwMS -= dwHours * 3600;
2090 dwMinutes = dwMS / 60;
2091 dwMS -= dwMinutes * 60;
2096 iDigits = SHLWAPI_WriteTimeClass(szCopy, dwHours, IDS_TIME_INTERVAL_HOURS, iDigits);
2098 if (dwMinutes && iDigits)
2099 iDigits = SHLWAPI_WriteTimeClass(szCopy, dwMinutes, IDS_TIME_INTERVAL_MINUTES, iDigits);
2101 if (iDigits) /* Always write seconds if we have significant digits */
2102 SHLWAPI_WriteTimeClass(szCopy, dwMS, IDS_TIME_INTERVAL_SECONDS, iDigits);
2104 lstrcpynW(lpszStr, szCopy, cchMax);
2105 iRet = strlenW(lpszStr);
2110 /*************************************************************************
2111 * StrIsIntlEqualA [SHLWAPI.@]
2113 * Compare two strings.
2116 * bCase [I] Whether to compare case sensitively
2117 * lpszStr [I] First string to compare
2118 * lpszComp [I] Second string to compare
2119 * iLen [I] Length to compare
2122 * TRUE If the strings are equal.
2125 BOOL WINAPI StrIsIntlEqualA(BOOL bCase, LPCSTR lpszStr, LPCSTR lpszComp,
2130 TRACE("(%d,%s,%s,%d)\n", bCase,
2131 debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
2133 /* FIXME: This flag is undocumented and unknown by our CompareString.
2134 * We need a define for it.
2136 dwFlags = 0x10000000;
2137 if (!bCase) dwFlags |= NORM_IGNORECASE;
2139 return (CompareStringA(GetThreadLocale(), dwFlags, lpszStr, iLen, lpszComp, iLen) == CSTR_EQUAL);
2142 /*************************************************************************
2143 * StrIsIntlEqualW [SHLWAPI.@]
2145 * See StrIsIntlEqualA.
2147 BOOL WINAPI StrIsIntlEqualW(BOOL bCase, LPCWSTR lpszStr, LPCWSTR lpszComp,
2152 TRACE("(%d,%s,%s,%d)\n", bCase,
2153 debugstr_w(lpszStr),debugstr_w(lpszComp), iLen);
2155 /* FIXME: This flag is undocumented and unknown by our CompareString.
2156 * We need a define for it.
2158 dwFlags = 0x10000000;
2159 if (!bCase) dwFlags |= NORM_IGNORECASE;
2161 return (CompareStringW(GetThreadLocale(), dwFlags, lpszStr, iLen, lpszComp, iLen) == CSTR_EQUAL);
2164 /*************************************************************************
2167 * Copy a string to another string, up to a maximum number of characters.
2170 * lpszDest [O] Destination string
2171 * lpszSrc [I] Source string
2172 * iLen [I] Maximum number of chars to copy
2175 * Success: A pointer to the last character written to lpszDest.
2176 * Failure: lpszDest, if any arguments are invalid.
2178 LPSTR WINAPI StrCpyNXA(LPSTR lpszDest, LPCSTR lpszSrc, int iLen)
2180 TRACE("(%p,%s,%i)\n", lpszDest, debugstr_a(lpszSrc), iLen);
2182 if (lpszDest && lpszSrc && iLen > 0)
2184 while ((iLen-- > 1) && *lpszSrc)
2185 *lpszDest++ = *lpszSrc++;
2192 /*************************************************************************
2195 * Unicode version of StrCpyNXA.
2197 LPWSTR WINAPI StrCpyNXW(LPWSTR lpszDest, LPCWSTR lpszSrc, int iLen)
2199 TRACE("(%p,%s,%i)\n", lpszDest, debugstr_w(lpszSrc), iLen);
2201 if (lpszDest && lpszSrc && iLen > 0)
2203 while ((iLen-- > 1) && *lpszSrc)
2204 *lpszDest++ = *lpszSrc++;
2211 /*************************************************************************
2212 * StrCmpLogicalW [SHLWAPI.@]
2214 * Compare two strings, ignoring case and comparing digits as numbers.
2217 * lpszStr [I] First string to compare
2218 * lpszComp [I] Second string to compare
2219 * iLen [I] Length to compare
2222 * TRUE If the strings are equal.
2225 INT WINAPI StrCmpLogicalW(LPCWSTR lpszStr, LPCWSTR lpszComp)
2229 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszComp));
2231 if (lpszStr && lpszComp)
2237 else if (isdigitW(*lpszStr))
2241 if (!isdigitW(*lpszComp))
2244 /* Compare the numbers */
2245 StrToIntExW(lpszStr, 0, &iStr);
2246 StrToIntExW(lpszComp, 0, &iComp);
2250 else if (iStr > iComp)
2254 while (isdigitW(*lpszStr))
2256 while (isdigitW(*lpszComp))
2259 else if (isdigitW(*lpszComp))
2263 iDiff = SHLWAPI_ChrCmpHelperW(*lpszStr,*lpszComp,NORM_IGNORECASE);
2279 /* Structure for formatting byte strings */
2280 typedef struct tagSHLWAPI_BYTEFORMATS
2287 } SHLWAPI_BYTEFORMATS;
2289 /*************************************************************************
2290 * StrFormatByteSizeW [SHLWAPI.@]
2292 * Create a string containing an abbreviated byte count of up to 2^63-1.
2295 * llBytes [I] Byte size to format
2296 * lpszDest [I] Destination for formatted string
2297 * cchMax [I] Size of lpszDest
2303 * There is no StrFormatByteSize64W function, it is called StrFormatByteSizeW().
2305 LPWSTR WINAPI StrFormatByteSizeW(LONGLONG llBytes, LPWSTR lpszDest, UINT cchMax)
2307 #define KB ((ULONGLONG)1024)
2309 #define GB (KB*KB*KB)
2310 #define TB (KB*KB*KB*KB)
2311 #define PB (KB*KB*KB*KB*KB)
2313 static const SHLWAPI_BYTEFORMATS bfFormats[] =
2315 { 10*KB, 10.24, 100.0, 2, 'K' }, /* 10 KB */
2316 { 100*KB, 102.4, 10.0, 1, 'K' }, /* 100 KB */
2317 { 1000*KB, 1024.0, 1.0, 0, 'K' }, /* 1000 KB */
2318 { 10*MB, 10485.76, 100.0, 2, 'M' }, /* 10 MB */
2319 { 100*MB, 104857.6, 10.0, 1, 'M' }, /* 100 MB */
2320 { 1000*MB, 1048576.0, 1.0, 0, 'M' }, /* 1000 MB */
2321 { 10*GB, 10737418.24, 100.0, 2, 'G' }, /* 10 GB */
2322 { 100*GB, 107374182.4, 10.0, 1, 'G' }, /* 100 GB */
2323 { 1000*GB, 1073741824.0, 1.0, 0, 'G' }, /* 1000 GB */
2324 { 10*TB, 10485.76, 100.0, 2, 'T' }, /* 10 TB */
2325 { 100*TB, 104857.6, 10.0, 1, 'T' }, /* 100 TB */
2326 { 1000*TB, 1048576.0, 1.0, 0, 'T' }, /* 1000 TB */
2327 { 10*PB, 10737418.24, 100.00, 2, 'P' }, /* 10 PB */
2328 { 100*PB, 107374182.4, 10.00, 1, 'P' }, /* 100 PB */
2329 { 1000*PB, 1073741824.0, 1.00, 0, 'P' }, /* 1000 PB */
2330 { 0, 10995116277.76, 100.00, 2, 'E' } /* EB's, catch all */
2332 WCHAR wszAdd[] = {' ','?','B',0};
2336 TRACE("(0x%s,%p,%d)\n", wine_dbgstr_longlong(llBytes), lpszDest, cchMax);
2338 if (!lpszDest || !cchMax)
2341 if (llBytes < 1024) /* 1K */
2343 WCHAR wszBytesFormat[64];
2344 LoadStringW(shlwapi_hInstance, IDS_BYTES_FORMAT, wszBytesFormat, 64);
2345 snprintfW(lpszDest, cchMax, wszBytesFormat, (long)llBytes);
2349 /* Note that if this loop completes without finding a match, i will be
2350 * pointing at the last entry, which is a catch all for > 1000 PB
2352 while (i < sizeof(bfFormats) / sizeof(SHLWAPI_BYTEFORMATS) - 1)
2354 if (llBytes < bfFormats[i].dLimit)
2358 /* Above 1 TB we encounter problems with FP accuracy. So for amounts above
2359 * this number we integer shift down by 1 MB first. The table above has
2360 * the divisors scaled down from the '< 10 TB' entry onwards, to account
2361 * for this. We also add a small fudge factor to get the correct result for
2362 * counts that lie exactly on a 1024 byte boundary.
2365 dBytes = (double)(llBytes >> 20) + 0.001; /* Scale down by I MB */
2367 dBytes = (double)llBytes + 0.00001;
2369 dBytes = floor(dBytes / bfFormats[i].dDivisor) / bfFormats[i].dNormaliser;
2371 if (!FormatDouble(dBytes, bfFormats[i].nDecimals, lpszDest, cchMax))
2373 wszAdd[1] = bfFormats[i].wPrefix;
2374 StrCatBuffW(lpszDest, wszAdd, cchMax);
2378 /*************************************************************************
2379 * StrFormatByteSize64A [SHLWAPI.@]
2381 * See StrFormatByteSizeW.
2383 LPSTR WINAPI StrFormatByteSize64A(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax)
2387 StrFormatByteSizeW(llBytes, wszBuff, sizeof(wszBuff)/sizeof(WCHAR));
2390 WideCharToMultiByte(CP_ACP, 0, wszBuff, -1, lpszDest, cchMax, 0, 0);
2394 /*************************************************************************
2395 * StrFormatByteSizeA [SHLWAPI.@]
2397 * Create a string containing an abbreviated byte count of up to 2^31-1.
2400 * dwBytes [I] Byte size to format
2401 * lpszDest [I] Destination for formatted string
2402 * cchMax [I] Size of lpszDest
2408 * The Ascii and Unicode versions of this function accept a different
2409 * integer type for dwBytes. See StrFormatByteSize64A().
2411 LPSTR WINAPI StrFormatByteSizeA(DWORD dwBytes, LPSTR lpszDest, UINT cchMax)
2413 TRACE("(%d,%p,%d)\n", dwBytes, lpszDest, cchMax);
2415 return StrFormatByteSize64A(dwBytes, lpszDest, cchMax);
2418 /*************************************************************************
2421 * Remove a hanging lead byte from the end of a string, if present.
2424 * lpStr [I] String to check for a hanging lead byte
2425 * size [I] Length of lpStr
2428 * Success: The new length of the string. Any hanging lead bytes are removed.
2429 * Failure: 0, if any parameters are invalid.
2431 DWORD WINAPI SHTruncateString(LPSTR lpStr, DWORD size)
2435 LPSTR lastByte = lpStr + size - 1;
2437 while(lpStr < lastByte)
2438 lpStr += IsDBCSLeadByte(*lpStr) ? 2 : 1;
2440 if(lpStr == lastByte && IsDBCSLeadByte(*lpStr))
2450 /*************************************************************************
2453 * Remove a single non-trailing ampersand ('&') from a string.
2456 * lpszStr [I/O] String to remove ampersand from.
2459 * The character after the first ampersand in lpszStr, or the first character
2460 * in lpszStr if there is no ampersand in the string.
2462 char WINAPI SHStripMneumonicA(LPCSTR lpszStr)
2464 LPSTR lpszIter, lpszTmp;
2467 TRACE("(%s)\n", debugstr_a(lpszStr));
2471 if ((lpszIter = StrChrA(lpszStr, '&')))
2473 lpszTmp = CharNextA(lpszIter);
2474 if (lpszTmp && *lpszTmp)
2476 if (*lpszTmp != '&')
2479 while (lpszIter && *lpszIter)
2481 lpszTmp = CharNextA(lpszIter);
2482 *lpszIter = *lpszTmp;
2491 /*************************************************************************
2494 * Unicode version of SHStripMneumonicA.
2496 WCHAR WINAPI SHStripMneumonicW(LPCWSTR lpszStr)
2498 LPWSTR lpszIter, lpszTmp;
2501 TRACE("(%s)\n", debugstr_w(lpszStr));
2505 if ((lpszIter = StrChrW(lpszStr, '&')))
2507 lpszTmp = CharNextW(lpszIter);
2508 if (lpszTmp && *lpszTmp)
2510 if (*lpszTmp != '&')
2513 while (lpszIter && *lpszIter)
2515 lpszTmp = CharNextW(lpszIter);
2516 *lpszIter = *lpszTmp;
2525 /*************************************************************************
2528 * Convert an Ascii string to Unicode.
2531 * dwCp [I] Code page for the conversion
2532 * lpSrcStr [I] Source Ascii string to convert
2533 * lpDstStr [O] Destination for converted Unicode string
2534 * iLen [I] Length of lpDstStr
2537 * The return value of the MultiByteToWideChar() function called on lpSrcStr.
2539 DWORD WINAPI SHAnsiToUnicodeCP(DWORD dwCp, LPCSTR lpSrcStr, LPWSTR lpDstStr, int iLen)
2543 dwRet = MultiByteToWideChar(dwCp, 0, lpSrcStr, -1, lpDstStr, iLen);
2544 TRACE("%s->%s,ret=%d\n", debugstr_a(lpSrcStr), debugstr_w(lpDstStr), dwRet);
2548 /*************************************************************************
2551 * Convert an Ascii string to Unicode.
2554 * lpSrcStr [I] Source Ascii string to convert
2555 * lpDstStr [O] Destination for converted Unicode string
2556 * iLen [I] Length of lpDstStr
2559 * The return value of the MultiByteToWideChar() function called on lpSrcStr.
2562 * This function simply calls SHAnsiToUnicodeCP with code page CP_ACP.
2564 DWORD WINAPI SHAnsiToUnicode(LPCSTR lpSrcStr, LPWSTR lpDstStr, int iLen)
2566 return SHAnsiToUnicodeCP(CP_ACP, lpSrcStr, lpDstStr, iLen);
2569 /*************************************************************************
2572 * Convert a Unicode string to Ascii.
2575 * CodePage [I] Code page to use for the conversion
2576 * lpSrcStr [I] Source Unicode string to convert
2577 * lpDstStr [O] Destination for converted Ascii string
2578 * lpiLen [I/O] Input length of lpDstStr/destination for length of lpDstStr
2581 * Success: The number of characters that result from the conversion.
2584 INT WINAPI SHUnicodeToAnsiCP(UINT CodePage, LPCWSTR lpSrcStr, LPSTR lpDstStr,
2587 static const WCHAR emptyW[] = { '\0' };
2591 if (!lpDstStr || !lpiLen)
2599 len = strlenW(lpSrcStr) + 1;
2604 CodePage = CP_UTF8; /* Fall through... */
2605 case 0x0000C350: /* FIXME: CP_ #define */
2610 INT nWideCharCount = len - 1;
2612 GET_FUNC(pConvertINetUnicodeToMultiByte, mlang, "ConvertINetUnicodeToMultiByte", 0);
2613 if (!pConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &nWideCharCount, lpDstStr,
2617 if (nWideCharCount < len - 1)
2619 mem = HeapAlloc(GetProcessHeap(), 0, *lpiLen);
2625 if (pConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &len, mem, lpiLen))
2627 SHTruncateString(mem, *lpiLen);
2628 lstrcpynA(lpDstStr, mem, *lpiLen + 1);
2629 HeapFree(GetProcessHeap(), 0, mem);
2632 HeapFree(GetProcessHeap(), 0, mem);
2635 lpDstStr[*lpiLen] = '\0';
2642 reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, lpDstStr,
2643 *lpiLen, NULL, NULL);
2645 if (!reqLen && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
2647 reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, NULL, 0, NULL, NULL);
2650 mem = HeapAlloc(GetProcessHeap(), 0, reqLen);
2653 reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, mem,
2654 reqLen, NULL, NULL);
2656 reqLen = SHTruncateString(mem, *lpiLen);
2659 lstrcpynA(lpDstStr, mem, *lpiLen);
2661 HeapFree(GetProcessHeap(), 0, mem);
2668 /*************************************************************************
2671 * Convert a Unicode string to Ascii.
2674 * lpSrcStr [I] Source Unicode string to convert
2675 * lpDstStr [O] Destination for converted Ascii string
2676 * iLen [O] Length of lpDstStr in characters
2679 * See SHUnicodeToAnsiCP
2682 * This function simply calls SHUnicodeToAnsiCP() with CodePage = CP_ACP.
2684 INT WINAPI SHUnicodeToAnsi(LPCWSTR lpSrcStr, LPSTR lpDstStr, INT iLen)
2688 return SHUnicodeToAnsiCP(CP_ACP, lpSrcStr, lpDstStr, &myint);
2691 /*************************************************************************
2694 * Copy one string to another.
2697 * lpszSrc [I] Source string to copy
2698 * lpszDst [O] Destination for copy
2699 * iLen [I] Length of lpszDst in characters
2702 * The length of the copied string, including the terminating NUL. lpszDst
2703 * contains iLen characters of lpszSrc.
2705 DWORD WINAPI SHAnsiToAnsi(LPCSTR lpszSrc, LPSTR lpszDst, int iLen)
2709 TRACE("(%s,%p,0x%08x)\n", debugstr_a(lpszSrc), lpszDst, iLen);
2711 lpszRet = StrCpyNXA(lpszDst, lpszSrc, iLen);
2712 return lpszRet - lpszDst + 1;
2715 /*************************************************************************
2718 * Unicode version of SSHAnsiToAnsi.
2720 DWORD WINAPI SHUnicodeToUnicode(LPCWSTR lpszSrc, LPWSTR lpszDst, int iLen)
2724 TRACE("(%s,%p,0x%08x)\n", debugstr_w(lpszSrc), lpszDst, iLen);
2726 lpszRet = StrCpyNXW(lpszDst, lpszSrc, iLen);
2727 return lpszRet - lpszDst + 1;
2730 /*************************************************************************
2733 * Determine if an Ascii string converts to Unicode and back identically.
2736 * lpSrcStr [I] Source Unicode string to convert
2737 * lpDst [O] Destination for resulting Ascii string
2738 * iLen [I] Length of lpDst in characters
2741 * TRUE, since Ascii strings always convert identically.
2743 BOOL WINAPI DoesStringRoundTripA(LPCSTR lpSrcStr, LPSTR lpDst, INT iLen)
2745 lstrcpynA(lpDst, lpSrcStr, iLen);
2749 /*************************************************************************
2752 * Determine if a Unicode string converts to Ascii and back identically.
2755 * lpSrcStr [I] Source Unicode string to convert
2756 * lpDst [O] Destination for resulting Ascii string
2757 * iLen [I] Length of lpDst in characters
2760 * TRUE, if lpSrcStr converts to Ascii and back identically,
2763 BOOL WINAPI DoesStringRoundTripW(LPCWSTR lpSrcStr, LPSTR lpDst, INT iLen)
2765 WCHAR szBuff[MAX_PATH];
2767 SHUnicodeToAnsi(lpSrcStr, lpDst, iLen);
2768 SHAnsiToUnicode(lpDst, szBuff, MAX_PATH);
2769 return !strcmpW(lpSrcStr, szBuff);
2772 /*************************************************************************
2773 * SHLoadIndirectString [SHLWAPI.@]
2775 * If passed a string that begins with '@', extract the string from the
2776 * appropriate resource, otherwise do a straight copy.
2779 HRESULT WINAPI SHLoadIndirectString(LPCWSTR src, LPWSTR dst, UINT dst_len, void **reserved)
2781 WCHAR *dllname = NULL;
2782 HMODULE hmod = NULL;
2783 HRESULT hr = E_FAIL;
2785 TRACE("(%s %p %08x %p)\n", debugstr_w(src), dst, dst_len, reserved);
2793 dllname = StrDupW(src + 1);
2794 index_str = strchrW(dllname, ',');
2796 if(!index_str) goto end;
2800 index = atoiW(index_str);
2802 hmod = LoadLibraryW(dllname);
2807 if(LoadStringW(hmod, -index, dst, dst_len))
2811 FIXME("can't handle non-negative indices (%d)\n", index);
2816 lstrcpynW(dst, src, dst_len);
2820 TRACE("returning %s\n", debugstr_w(dst));
2822 if(hmod) FreeLibrary(hmod);
2823 HeapFree(GetProcessHeap(), 0, dllname);