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, LPWSTR decimal_buffer, int decimal_bufwlen,
70 LPWSTR thousand_buffer, int thousand_bufwlen)
75 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_ILZERO|LOCALE_RETURN_NUMBER, (LPWSTR)&fmt->LeadingZero, sizeof(fmt->LeadingZero)/sizeof(WCHAR));
76 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_INEGNUMBER|LOCALE_RETURN_NUMBER, (LPWSTR)&fmt->LeadingZero, sizeof(fmt->NegativeOrder)/sizeof(WCHAR));
78 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, decimal_buffer, decimal_bufwlen);
79 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, thousand_buffer, thousand_bufwlen);
80 fmt->lpThousandSep = thousand_buffer;
81 fmt->lpDecimalSep = decimal_buffer;
84 * Converting grouping string to number as described on
85 * http://blogs.msdn.com/oldnewthing/archive/2006/04/18/578251.aspx
88 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SGROUPING, grouping, sizeof(grouping)/sizeof(WCHAR));
89 for (c = grouping; *c; c++)
90 if (*c >= '0' && *c < '9')
93 fmt->Grouping += *c - '0';
96 if (fmt->Grouping % 10 == 0)
102 /*************************************************************************
103 * FormatInt [internal]
105 * Format an integer according to the current locale
108 * The number of bytes written on success or 0 on failure
110 static int FormatInt(LONGLONG qdwValue, LPWSTR pszBuf, int cchBuf)
113 WCHAR decimal[8], thousand[8];
116 BOOL neg = (qdwValue < 0);
118 FillNumberFmt(&fmt, decimal, sizeof decimal / sizeof (WCHAR),
119 thousand, sizeof thousand / sizeof (WCHAR));
125 *(--c) = '0' + (qdwValue%10);
127 } while (qdwValue > 0);
131 return GetNumberFormatW(LOCALE_USER_DEFAULT, 0, c, &fmt, pszBuf, cchBuf);
134 /*************************************************************************
135 * FormatDouble [internal]
137 * Format an integer according to the current locale. Prints the specified number of digits
138 * after the decimal point
141 * The number of bytes written on success or 0 on failure
143 static int FormatDouble(double value, int decimals, LPWSTR pszBuf, int cchBuf)
145 static const WCHAR flfmt[] = {'%','f',0};
148 WCHAR decimal[8], thousand[8];
150 snprintfW(buf, 64, flfmt, value);
152 FillNumberFmt(&fmt, decimal, sizeof decimal / sizeof (WCHAR),
153 thousand, sizeof thousand / sizeof (WCHAR));
154 fmt.NumDigits = decimals;
155 return GetNumberFormatW(LOCALE_USER_DEFAULT, 0, buf, &fmt, pszBuf, cchBuf);
158 /*************************************************************************
159 * SHLWAPI_ChrCmpHelperA
161 * Internal helper for SHLWAPI_ChrCmpA/ChrCMPIA.
164 * Both this function and its Unicode counterpart are very inneficient. To
165 * fix this, CompareString must be completely implemented and optimised
166 * first. Then the core character test can be taken out of that function and
167 * placed here, so that it need never be called at all. Until then, do not
168 * attempt to optimise this code unless you are willing to test that it
169 * still performs correctly.
171 static BOOL WINAPI SHLWAPI_ChrCmpHelperA(WORD ch1, WORD ch2, DWORD dwFlags)
173 char str1[3], str2[3];
175 str1[0] = LOBYTE(ch1);
176 if (IsDBCSLeadByte(str1[0]))
178 str1[1] = HIBYTE(ch1);
184 str2[0] = LOBYTE(ch2);
185 if (IsDBCSLeadByte(str2[0]))
187 str2[1] = HIBYTE(ch2);
193 return CompareStringA(GetThreadLocale(), dwFlags, str1, -1, str2, -1) - 2;
196 /*************************************************************************
197 * SHLWAPI_ChrCmpHelperW
199 * Internal helper for SHLWAPI_ChrCmpW/ChrCmpIW.
201 static BOOL WINAPI SHLWAPI_ChrCmpHelperW(WCHAR ch1, WCHAR ch2, DWORD dwFlags)
203 WCHAR str1[2], str2[2];
209 return CompareStringW(GetThreadLocale(), dwFlags, str1, 2, str2, 2) - 2;
212 /*************************************************************************
215 * Internal helper function.
217 static BOOL WINAPI SHLWAPI_ChrCmpA(WORD ch1, WORD ch2)
219 return SHLWAPI_ChrCmpHelperA(ch1, ch2, 0);
222 /*************************************************************************
223 * ChrCmpIA (SHLWAPI.385)
225 * Compare two characters, ignoring case.
228 * ch1 [I] First character to compare
229 * ch2 [I] Second character to compare
232 * FALSE, if the characters are equal.
233 * Non-zero otherwise.
235 BOOL WINAPI ChrCmpIA(WORD ch1, WORD ch2)
237 TRACE("(%d,%d)\n", ch1, ch2);
239 return SHLWAPI_ChrCmpHelperA(ch1, ch2, NORM_IGNORECASE);
242 /*************************************************************************
245 * Internal helper function.
247 static BOOL WINAPI SHLWAPI_ChrCmpW(WCHAR ch1, WCHAR ch2)
249 return SHLWAPI_ChrCmpHelperW(ch1, ch2, 0);
252 /*************************************************************************
253 * ChrCmpIW [SHLWAPI.386]
257 BOOL WINAPI ChrCmpIW(WCHAR ch1, WCHAR ch2)
259 return SHLWAPI_ChrCmpHelperW(ch1, ch2, NORM_IGNORECASE);
262 /*************************************************************************
263 * StrChrA [SHLWAPI.@]
265 * Find a given character in a string.
268 * lpszStr [I] String to search in.
269 * ch [I] Character to search for.
272 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
274 * Failure: NULL, if any arguments are invalid.
276 LPSTR WINAPI StrChrA(LPCSTR lpszStr, WORD ch)
278 TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch);
284 if (!SHLWAPI_ChrCmpA(*lpszStr, ch))
285 return (LPSTR)lpszStr;
286 lpszStr = CharNextA(lpszStr);
292 /*************************************************************************
293 * StrChrW [SHLWAPI.@]
297 LPWSTR WINAPI StrChrW(LPCWSTR lpszStr, WCHAR ch)
299 LPWSTR lpszRet = NULL;
301 TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch);
304 lpszRet = strchrW(lpszStr, ch);
308 /*************************************************************************
309 * StrChrIA [SHLWAPI.@]
311 * Find a given character in a string, ignoring case.
314 * lpszStr [I] String to search in.
315 * ch [I] Character to search for.
318 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
320 * Failure: NULL, if any arguments are invalid.
322 LPSTR WINAPI StrChrIA(LPCSTR lpszStr, WORD ch)
324 TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch);
330 if (!ChrCmpIA(*lpszStr, ch))
331 return (LPSTR)lpszStr;
332 lpszStr = CharNextA(lpszStr);
338 /*************************************************************************
339 * StrChrIW [SHLWAPI.@]
343 LPWSTR WINAPI StrChrIW(LPCWSTR lpszStr, WCHAR ch)
345 TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch);
352 if (toupperW(*lpszStr) == ch)
353 return (LPWSTR)lpszStr;
354 lpszStr = CharNextW(lpszStr);
358 return (LPWSTR)lpszStr;
361 /*************************************************************************
362 * StrCmpIW [SHLWAPI.@]
364 * Compare two strings, ignoring case.
367 * lpszStr [I] First string to compare
368 * lpszComp [I] Second string to compare
371 * An integer less than, equal to or greater than 0, indicating that
372 * lpszStr is less than, the same, or greater than lpszComp.
374 int WINAPI StrCmpIW(LPCWSTR lpszStr, LPCWSTR lpszComp)
378 TRACE("(%s,%s)\n", debugstr_w(lpszStr),debugstr_w(lpszComp));
380 iRet = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, lpszStr, -1, lpszComp, -1);
381 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
384 /*************************************************************************
385 * StrCmpNA [SHLWAPI.@]
387 * Compare two strings, up to a maximum length.
390 * lpszStr [I] First string to compare
391 * lpszComp [I] Second string to compare
392 * iLen [I] Maximum number of chars to compare.
395 * An integer less than, equal to or greater than 0, indicating that
396 * lpszStr is less than, the same, or greater than lpszComp.
398 INT WINAPI StrCmpNA(LPCSTR lpszStr, LPCSTR lpszComp, INT iLen)
402 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
404 iRet = CompareStringA(GetThreadLocale(), 0, lpszStr, iLen, lpszComp, iLen);
405 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
408 /*************************************************************************
409 * StrCmpNW [SHLWAPI.@]
413 INT WINAPI StrCmpNW(LPCWSTR lpszStr, LPCWSTR lpszComp, INT iLen)
417 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen);
419 iRet = CompareStringW(GetThreadLocale(), 0, lpszStr, iLen, lpszComp, iLen);
420 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
423 /*************************************************************************
424 * StrCmpNIA [SHLWAPI.@]
426 * Compare two strings, up to a maximum length, ignoring case.
429 * lpszStr [I] First string to compare
430 * lpszComp [I] Second string to compare
431 * iLen [I] Maximum number of chars to compare.
434 * An integer less than, equal to or greater than 0, indicating that
435 * lpszStr is less than, the same, or greater than lpszComp.
437 int WINAPI StrCmpNIA(LPCSTR lpszStr, LPCSTR lpszComp, int iLen)
441 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
443 iRet = CompareStringA(GetThreadLocale(), NORM_IGNORECASE, lpszStr, iLen, lpszComp, iLen);
444 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
447 /*************************************************************************
448 * StrCmpNIW [SHLWAPI.@]
452 INT WINAPI StrCmpNIW(LPCWSTR lpszStr, LPCWSTR lpszComp, int iLen)
456 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen);
458 iRet = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, lpszStr, iLen, lpszComp, iLen);
459 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
462 /*************************************************************************
463 * StrCmpW [SHLWAPI.@]
465 * Compare two strings.
468 * lpszStr [I] First string to compare
469 * lpszComp [I] Second string to compare
472 * An integer less than, equal to or greater than 0, indicating that
473 * lpszStr is less than, the same, or greater than lpszComp.
475 int WINAPI StrCmpW(LPCWSTR lpszStr, LPCWSTR lpszComp)
479 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszComp));
481 iRet = CompareStringW(GetThreadLocale(), 0, lpszStr, -1, lpszComp, -1);
482 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
485 /*************************************************************************
486 * StrCatW [SHLWAPI.@]
488 * Concatanate two strings.
491 * lpszStr [O] Initial string
492 * lpszSrc [I] String to concatanate
497 LPWSTR WINAPI StrCatW(LPWSTR lpszStr, LPCWSTR lpszSrc)
499 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSrc));
501 strcatW(lpszStr, lpszSrc);
505 /*************************************************************************
506 * StrCpyW [SHLWAPI.@]
508 * Copy a string to another string.
511 * lpszStr [O] Destination string
512 * lpszSrc [I] Source string
517 LPWSTR WINAPI StrCpyW(LPWSTR lpszStr, LPCWSTR lpszSrc)
519 TRACE("(%p,%s)\n", lpszStr, debugstr_w(lpszSrc));
521 strcpyW(lpszStr, lpszSrc);
525 /*************************************************************************
526 * StrCpyNW [SHLWAPI.@]
528 * Copy a string to another string, up to a maximum number of characters.
531 * lpszStr [O] Destination string
532 * lpszSrc [I] Source string
533 * iLen [I] Maximum number of chars to copy
538 LPWSTR WINAPI StrCpyNW(LPWSTR lpszStr, LPCWSTR lpszSrc, int iLen)
540 TRACE("(%p,%s,%i)\n", lpszStr, debugstr_w(lpszSrc), iLen);
542 lstrcpynW(lpszStr, lpszSrc, iLen);
548 /*************************************************************************
549 * SHLWAPI_StrStrHelperA
551 * Internal implementation of StrStrA/StrStrIA
553 static LPSTR WINAPI SHLWAPI_StrStrHelperA(LPCSTR lpszStr, LPCSTR lpszSearch,
554 int (*pStrCmpFn)(LPCSTR,LPCSTR,size_t))
558 if (!lpszStr || !lpszSearch || !*lpszSearch)
561 iLen = strlen(lpszSearch);
565 if (!pStrCmpFn(lpszStr, lpszSearch, iLen))
566 return (LPSTR)lpszStr;
567 lpszStr = CharNextA(lpszStr);
572 /*************************************************************************
573 * SHLWAPI_StrStrHelperW
575 * Internal implementation of StrStrW/StrStrIW
577 static LPWSTR WINAPI SHLWAPI_StrStrHelperW(LPCWSTR lpszStr, LPCWSTR lpszSearch,
578 int (*pStrCmpFn)(LPCWSTR,LPCWSTR,int))
582 if (!lpszStr || !lpszSearch || !*lpszSearch)
585 iLen = strlenW(lpszSearch);
589 if (!pStrCmpFn(lpszStr, lpszSearch, iLen))
590 return (LPWSTR)lpszStr;
591 lpszStr = CharNextW(lpszStr);
596 /*************************************************************************
597 * StrStrA [SHLWAPI.@]
599 * Find a substring within a string.
602 * lpszStr [I] String to search in
603 * lpszSearch [I] String to look for
606 * The start of lpszSearch within lpszStr, or NULL if not found.
608 LPSTR WINAPI StrStrA(LPCSTR lpszStr, LPCSTR lpszSearch)
610 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
612 return SHLWAPI_StrStrHelperA(lpszStr, lpszSearch, strncmp);
615 /*************************************************************************
616 * StrStrW [SHLWAPI.@]
620 LPWSTR WINAPI StrStrW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
622 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
624 return SHLWAPI_StrStrHelperW(lpszStr, lpszSearch, strncmpW);
627 /*************************************************************************
628 * StrRStrIA [SHLWAPI.@]
630 * Find the last occurrence of a substring within a string.
633 * lpszStr [I] String to search in
634 * lpszEnd [I] End of lpszStr
635 * lpszSearch [I] String to look for
638 * The last occurrence lpszSearch within lpszStr, or NULL if not found.
640 LPSTR WINAPI StrRStrIA(LPCSTR lpszStr, LPCSTR lpszEnd, LPCSTR lpszSearch)
642 LPSTR lpszRet = NULL;
646 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
648 if (!lpszStr || !lpszSearch || !*lpszSearch)
652 lpszEnd = lpszStr + lstrlenA(lpszStr);
654 if (IsDBCSLeadByte(*lpszSearch))
655 ch1 = *lpszSearch << 8 | lpszSearch[1];
658 iLen = lstrlenA(lpszSearch);
660 while (lpszStr <= lpszEnd && *lpszStr)
662 ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr;
663 if (!ChrCmpIA(ch1, ch2))
665 if (!StrCmpNIA(lpszStr, lpszSearch, iLen))
666 lpszRet = (LPSTR)lpszStr;
668 lpszStr = CharNextA(lpszStr);
673 /*************************************************************************
674 * StrRStrIW [SHLWAPI.@]
678 LPWSTR WINAPI StrRStrIW(LPCWSTR lpszStr, LPCWSTR lpszEnd, LPCWSTR lpszSearch)
680 LPWSTR lpszRet = NULL;
683 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
685 if (!lpszStr || !lpszSearch || !*lpszSearch)
689 lpszEnd = lpszStr + strlenW(lpszStr);
691 iLen = strlenW(lpszSearch);
693 while (lpszStr <= lpszEnd && *lpszStr)
695 if (!ChrCmpIW(*lpszSearch, *lpszStr))
697 if (!StrCmpNIW(lpszStr, lpszSearch, iLen))
698 lpszRet = (LPWSTR)lpszStr;
700 lpszStr = CharNextW(lpszStr);
705 /*************************************************************************
706 * StrStrIA [SHLWAPI.@]
708 * Find a substring within a string, ignoring case.
711 * lpszStr [I] String to search in
712 * lpszSearch [I] String to look for
715 * The start of lpszSearch within lpszStr, or NULL if not found.
717 LPSTR WINAPI StrStrIA(LPCSTR lpszStr, LPCSTR lpszSearch)
719 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
721 return SHLWAPI_StrStrHelperA(lpszStr, lpszSearch, strncasecmp);
724 /*************************************************************************
725 * StrStrIW [SHLWAPI.@]
729 LPWSTR WINAPI StrStrIW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
731 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
733 return SHLWAPI_StrStrHelperW(lpszStr, lpszSearch, strncmpiW);
736 /*************************************************************************
737 * StrToIntA [SHLWAPI.@]
739 * Read a signed integer from a string.
742 * lpszStr [I] String to read integer from
745 * The signed integer value represented by the string, or 0 if no integer is
749 * No leading space is allowed before the number, although a leading '-' is.
751 int WINAPI StrToIntA(LPCSTR lpszStr)
755 TRACE("(%s)\n", debugstr_a(lpszStr));
759 WARN("Invalid lpszStr would crash under Win32!\n");
763 if (*lpszStr == '-' || isdigit(*lpszStr))
764 StrToIntExA(lpszStr, 0, &iRet);
768 /*************************************************************************
769 * StrToIntW [SHLWAPI.@]
773 int WINAPI StrToIntW(LPCWSTR lpszStr)
777 TRACE("(%s)\n", debugstr_w(lpszStr));
781 WARN("Invalid lpszStr would crash under Win32!\n");
785 if (*lpszStr == '-' || isdigitW(*lpszStr))
786 StrToIntExW(lpszStr, 0, &iRet);
790 /*************************************************************************
791 * StrToIntExA [SHLWAPI.@]
793 * Read an integer from a string.
796 * lpszStr [I] String to read integer from
797 * dwFlags [I] Flags controlling the conversion
798 * lpiRet [O] Destination for read integer.
801 * Success: TRUE. lpiRet contains the integer value represented by the string.
802 * Failure: FALSE, if the string is invalid, or no number is present.
805 * Leading whitespace, '-' and '+' are allowed before the number. If
806 * dwFlags includes STIF_SUPPORT_HEX, hexadecimal numbers are allowed, if
807 * preceded by '0x'. If this flag is not set, or there is no '0x' prefix,
808 * the string is treated as a decimal string. A leading '-' is ignored for
809 * hexadecimal numbers.
811 BOOL WINAPI StrToIntExA(LPCSTR lpszStr, DWORD dwFlags, LPINT lpiRet)
813 BOOL bNegative = FALSE;
816 TRACE("(%s,%08X,%p)\n", debugstr_a(lpszStr), dwFlags, lpiRet);
818 if (!lpszStr || !lpiRet)
820 WARN("Invalid parameter would crash under Win32!\n");
823 if (dwFlags > STIF_SUPPORT_HEX)
825 WARN("Unknown flags (%08lX)!\n", dwFlags & ~STIF_SUPPORT_HEX);
828 /* Skip leading space, '+', '-' */
829 while (isspace(*lpszStr))
830 lpszStr = CharNextA(lpszStr);
837 else if (*lpszStr == '+')
840 if (dwFlags & STIF_SUPPORT_HEX &&
841 *lpszStr == '0' && tolower(lpszStr[1]) == 'x')
843 /* Read hex number */
846 if (!isxdigit(*lpszStr))
849 while (isxdigit(*lpszStr))
852 if (isdigit(*lpszStr))
853 iRet += (*lpszStr - '0');
855 iRet += 10 + (tolower(*lpszStr) - 'a');
862 /* Read decimal number */
863 if (!isdigit(*lpszStr))
866 while (isdigit(*lpszStr))
869 iRet += (*lpszStr - '0');
872 *lpiRet = bNegative ? -iRet : iRet;
876 /*************************************************************************
877 * StrToIntExW [SHLWAPI.@]
881 BOOL WINAPI StrToIntExW(LPCWSTR lpszStr, DWORD dwFlags, LPINT lpiRet)
883 BOOL bNegative = FALSE;
886 TRACE("(%s,%08X,%p)\n", debugstr_w(lpszStr), dwFlags, lpiRet);
888 if (!lpszStr || !lpiRet)
890 WARN("Invalid parameter would crash under Win32!\n");
893 if (dwFlags > STIF_SUPPORT_HEX)
895 WARN("Unknown flags (%08lX)!\n", dwFlags & ~STIF_SUPPORT_HEX);
898 /* Skip leading space, '+', '-' */
899 while (isspaceW(*lpszStr))
900 lpszStr = CharNextW(lpszStr);
907 else if (*lpszStr == '+')
910 if (dwFlags & STIF_SUPPORT_HEX &&
911 *lpszStr == '0' && tolowerW(lpszStr[1]) == 'x')
913 /* Read hex number */
916 if (!isxdigitW(*lpszStr))
919 while (isxdigitW(*lpszStr))
922 if (isdigitW(*lpszStr))
923 iRet += (*lpszStr - '0');
925 iRet += 10 + (tolowerW(*lpszStr) - 'a');
932 /* Read decimal number */
933 if (!isdigitW(*lpszStr))
936 while (isdigitW(*lpszStr))
939 iRet += (*lpszStr - '0');
942 *lpiRet = bNegative ? -iRet : iRet;
946 /*************************************************************************
947 * StrDupA [SHLWAPI.@]
949 * Duplicate a string.
952 * lpszStr [I] String to duplicate.
955 * Success: A pointer to a new string containing the contents of lpszStr
956 * Failure: NULL, if memory cannot be allocated
959 * The string memory is allocated with LocalAlloc(), and so should be released
960 * by calling LocalFree().
962 LPSTR WINAPI StrDupA(LPCSTR lpszStr)
967 TRACE("(%s)\n",debugstr_a(lpszStr));
969 iLen = lpszStr ? strlen(lpszStr) + 1 : 1;
970 lpszRet = (LPSTR)LocalAlloc(LMEM_FIXED, iLen);
975 memcpy(lpszRet, lpszStr, iLen);
982 /*************************************************************************
983 * StrDupW [SHLWAPI.@]
987 LPWSTR WINAPI StrDupW(LPCWSTR lpszStr)
992 TRACE("(%s)\n",debugstr_w(lpszStr));
994 iLen = (lpszStr ? strlenW(lpszStr) + 1 : 1) * sizeof(WCHAR);
995 lpszRet = (LPWSTR)LocalAlloc(LMEM_FIXED, iLen);
1000 memcpy(lpszRet, lpszStr, iLen);
1007 /*************************************************************************
1008 * SHLWAPI_StrSpnHelperA
1010 * Internal implementation of StrSpnA/StrCSpnA/StrCSpnIA
1012 static int WINAPI SHLWAPI_StrSpnHelperA(LPCSTR lpszStr, LPCSTR lpszMatch,
1013 LPSTR (WINAPI *pStrChrFn)(LPCSTR,WORD),
1016 LPCSTR lpszRead = lpszStr;
1017 if (lpszStr && *lpszStr && lpszMatch)
1021 LPCSTR lpszTest = pStrChrFn(lpszMatch, *lpszRead);
1023 if (!bInvert && !lpszTest)
1025 if (bInvert && lpszTest)
1027 lpszRead = CharNextA(lpszRead);
1030 return lpszRead - lpszStr;
1033 /*************************************************************************
1034 * SHLWAPI_StrSpnHelperW
1036 * Internal implementation of StrSpnW/StrCSpnW/StrCSpnIW
1038 static int WINAPI SHLWAPI_StrSpnHelperW(LPCWSTR lpszStr, LPCWSTR lpszMatch,
1039 LPWSTR (WINAPI *pStrChrFn)(LPCWSTR,WCHAR),
1042 LPCWSTR lpszRead = lpszStr;
1043 if (lpszStr && *lpszStr && lpszMatch)
1047 LPCWSTR lpszTest = pStrChrFn(lpszMatch, *lpszRead);
1049 if (!bInvert && !lpszTest)
1051 if (bInvert && lpszTest)
1053 lpszRead = CharNextW(lpszRead);
1056 return lpszRead - lpszStr;
1059 /*************************************************************************
1060 * StrSpnA [SHLWAPI.@]
1062 * Find the length of the start of a string that contains only certain
1066 * lpszStr [I] String to search
1067 * lpszMatch [I] Characters that can be in the substring
1070 * The length of the part of lpszStr containing only chars from lpszMatch,
1071 * or 0 if any parameter is invalid.
1073 int WINAPI StrSpnA(LPCSTR lpszStr, LPCSTR lpszMatch)
1075 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1077 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, FALSE);
1080 /*************************************************************************
1081 * StrSpnW [SHLWAPI.@]
1085 int WINAPI StrSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1087 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1089 return SHLWAPI_StrSpnHelperW(lpszStr, lpszMatch, StrChrW, FALSE);
1092 /*************************************************************************
1093 * StrCSpnA [SHLWAPI.@]
1095 * Find the length of the start of a string that does not contain certain
1099 * lpszStr [I] String to search
1100 * lpszMatch [I] Characters that cannot be in the substring
1103 * The length of the part of lpszStr containing only chars not in lpszMatch,
1104 * or 0 if any parameter is invalid.
1106 int WINAPI StrCSpnA(LPCSTR lpszStr, LPCSTR lpszMatch)
1108 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1110 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, TRUE);
1113 /*************************************************************************
1114 * StrCSpnW [SHLWAPI.@]
1118 int WINAPI StrCSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1120 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1122 return SHLWAPI_StrSpnHelperW(lpszStr, lpszMatch, StrChrW, TRUE);
1125 /*************************************************************************
1126 * StrCSpnIA [SHLWAPI.@]
1128 * Find the length of the start of a string that does not contain certain
1129 * characters, ignoring case.
1132 * lpszStr [I] String to search
1133 * lpszMatch [I] Characters that cannot be in the substring
1136 * The length of the part of lpszStr containing only chars not in lpszMatch,
1137 * or 0 if any parameter is invalid.
1139 int WINAPI StrCSpnIA(LPCSTR lpszStr, LPCSTR lpszMatch)
1141 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1143 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrIA, TRUE);
1146 /*************************************************************************
1147 * StrCSpnIW [SHLWAPI.@]
1151 int WINAPI StrCSpnIW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1153 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1155 return SHLWAPI_StrSpnHelperW(lpszStr, lpszMatch, StrChrIW, TRUE);
1158 /*************************************************************************
1159 * StrPBrkA [SHLWAPI.@]
1161 * Search a string for any of a group of characters.
1164 * lpszStr [I] String to search
1165 * lpszMatch [I] Characters to match
1168 * A pointer to the first matching character in lpszStr, or NULL if no
1171 LPSTR WINAPI StrPBrkA(LPCSTR lpszStr, LPCSTR lpszMatch)
1173 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1175 if (lpszStr && lpszMatch && *lpszMatch)
1179 if (StrChrA(lpszMatch, *lpszStr))
1180 return (LPSTR)lpszStr;
1181 lpszStr = CharNextA(lpszStr);
1187 /*************************************************************************
1188 * StrPBrkW [SHLWAPI.@]
1192 LPWSTR WINAPI StrPBrkW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1194 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1196 if (lpszStr && lpszMatch && *lpszMatch)
1200 if (StrChrW(lpszMatch, *lpszStr))
1201 return (LPWSTR)lpszStr;
1202 lpszStr = CharNextW(lpszStr);
1208 /*************************************************************************
1209 * SHLWAPI_StrRChrHelperA
1211 * Internal implementation of StrRChrA/StrRChrIA.
1213 static LPSTR WINAPI SHLWAPI_StrRChrHelperA(LPCSTR lpszStr,
1214 LPCSTR lpszEnd, WORD ch,
1215 BOOL (WINAPI *pChrCmpFn)(WORD,WORD))
1217 LPCSTR lpszRet = NULL;
1224 lpszEnd = lpszStr + lstrlenA(lpszStr);
1226 while (*lpszStr && lpszStr <= lpszEnd)
1228 ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr;
1230 if (!pChrCmpFn(ch, ch2))
1232 lpszStr = CharNextA(lpszStr);
1235 return (LPSTR)lpszRet;
1238 /*************************************************************************
1239 * SHLWAPI_StrRChrHelperW
1241 * Internal implementation of StrRChrW/StrRChrIW.
1243 static LPWSTR WINAPI SHLWAPI_StrRChrHelperW(LPCWSTR lpszStr,
1244 LPCWSTR lpszEnd, WCHAR ch,
1245 BOOL (WINAPI *pChrCmpFn)(WCHAR,WCHAR))
1247 LPCWSTR lpszRet = NULL;
1252 lpszEnd = lpszStr + strlenW(lpszStr);
1254 while (*lpszStr && lpszStr <= lpszEnd)
1256 if (!pChrCmpFn(ch, *lpszStr))
1258 lpszStr = CharNextW(lpszStr);
1261 return (LPWSTR)lpszRet;
1264 /**************************************************************************
1265 * StrRChrA [SHLWAPI.@]
1267 * Find the last occurrence of a character in string.
1270 * lpszStr [I] String to search in
1271 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1272 * ch [I] Character to search for.
1275 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1276 * or NULL if not found.
1277 * Failure: NULL, if any arguments are invalid.
1279 LPSTR WINAPI StrRChrA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch)
1281 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch);
1283 return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, SHLWAPI_ChrCmpA);
1286 /**************************************************************************
1287 * StrRChrW [SHLWAPI.@]
1291 LPWSTR WINAPI StrRChrW(LPCWSTR lpszStr, LPCWSTR lpszEnd, WORD ch)
1293 TRACE("(%s,%s,%x)\n", debugstr_w(lpszStr), debugstr_w(lpszEnd), ch);
1295 return SHLWAPI_StrRChrHelperW(lpszStr, lpszEnd, ch, SHLWAPI_ChrCmpW);
1298 /**************************************************************************
1299 * StrRChrIA [SHLWAPI.@]
1301 * Find the last occurrence of a character in string, ignoring case.
1304 * lpszStr [I] String to search in
1305 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1306 * ch [I] Character to search for.
1309 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1310 * or NULL if not found.
1311 * Failure: NULL, if any arguments are invalid.
1313 LPSTR WINAPI StrRChrIA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch)
1315 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch);
1317 return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, ChrCmpIA);
1320 /**************************************************************************
1321 * StrRChrIW [SHLWAPI.@]
1325 LPWSTR WINAPI StrRChrIW(LPCWSTR lpszStr, LPCWSTR lpszEnd, WORD ch)
1327 TRACE("(%s,%s,%x)\n", debugstr_w(lpszStr), debugstr_w(lpszEnd), ch);
1329 return SHLWAPI_StrRChrHelperW(lpszStr, lpszEnd, ch, ChrCmpIW);
1332 /*************************************************************************
1333 * StrCatBuffA [SHLWAPI.@]
1335 * Concatenate two strings together.
1338 * lpszStr [O] String to concatenate to
1339 * lpszCat [I] String to add to lpszCat
1340 * cchMax [I] Maximum number of characters for the whole string
1346 * cchMax determines the number of characters in the final length of the
1347 * string, not the number appended to lpszStr from lpszCat.
1349 LPSTR WINAPI StrCatBuffA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax)
1353 TRACE("(%p,%s,%d)\n", lpszStr, debugstr_a(lpszCat), cchMax);
1357 WARN("Invalid lpszStr would crash under Win32!\n");
1361 iLen = strlen(lpszStr);
1365 StrCpyNA(lpszStr + iLen, lpszCat, cchMax);
1369 /*************************************************************************
1370 * StrCatBuffW [SHLWAPI.@]
1374 LPWSTR WINAPI StrCatBuffW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax)
1378 TRACE("(%p,%s,%d)\n", lpszStr, debugstr_w(lpszCat), cchMax);
1382 WARN("Invalid lpszStr would crash under Win32!\n");
1386 iLen = strlenW(lpszStr);
1390 StrCpyNW(lpszStr + iLen, lpszCat, cchMax);
1394 /*************************************************************************
1395 * StrRetToBufA [SHLWAPI.@]
1397 * Convert a STRRET to a normal string.
1400 * lpStrRet [O] STRRET to convert
1401 * pIdl [I] ITEMIDLIST for lpStrRet->uType == STRRET_OFFSET
1402 * lpszDest [O] Destination for normal string
1403 * dwLen [I] Length of lpszDest
1406 * Success: S_OK. lpszDest contains up to dwLen characters of the string.
1407 * If lpStrRet is of type STRRET_WSTR, its memory is freed with
1408 * CoTaskMemFree() and its type set to STRRET_CSTRA.
1409 * Failure: E_FAIL, if any parameters are invalid.
1411 HRESULT WINAPI StrRetToBufA (LPSTRRET src, const ITEMIDLIST *pidl, LPSTR dest, UINT len)
1414 * This routine is identical to that in dlls/shell32/shellstring.c.
1415 * It was duplicated because not every version of Shlwapi.dll exports
1416 * StrRetToBufA. If you change one routine, change them both.
1418 TRACE("dest=%p len=0x%x strret=%p pidl=%p stub\n",dest,len,src,pidl);
1422 WARN("Invalid lpStrRet would crash under Win32!\n");
1436 WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, dest, len, NULL, NULL);
1437 CoTaskMemFree(src->u.pOleStr);
1441 lstrcpynA((LPSTR)dest, src->u.cStr, len);
1445 lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len);
1449 FIXME("unknown type!\n");
1455 /*************************************************************************
1456 * StrRetToBufW [SHLWAPI.@]
1460 HRESULT WINAPI StrRetToBufW (LPSTRRET src, const ITEMIDLIST *pidl, LPWSTR dest, UINT len)
1462 TRACE("dest=%p len=0x%x strret=%p pidl=%p stub\n",dest,len,src,pidl);
1466 WARN("Invalid lpStrRet would crash under Win32!\n");
1480 lstrcpynW((LPWSTR)dest, src->u.pOleStr, len);
1481 CoTaskMemFree(src->u.pOleStr);
1485 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
1492 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1,
1499 FIXME("unknown type!\n");
1505 /*************************************************************************
1506 * StrRetToStrA [SHLWAPI.@]
1508 * Converts a STRRET to a normal string.
1511 * lpStrRet [O] STRRET to convert
1512 * pidl [I] ITEMIDLIST for lpStrRet->uType == STRRET_OFFSET
1513 * ppszName [O] Destination for converted string
1516 * Success: S_OK. ppszName contains the new string, allocated with CoTaskMemAlloc().
1517 * Failure: E_FAIL, if any parameters are invalid.
1519 HRESULT WINAPI StrRetToStrA(LPSTRRET lpStrRet, const ITEMIDLIST *pidl, LPSTR *ppszName)
1521 HRESULT hRet = E_FAIL;
1523 switch (lpStrRet->uType)
1526 hRet = _SHStrDupAW(lpStrRet->u.pOleStr, ppszName);
1527 CoTaskMemFree(lpStrRet->u.pOleStr);
1531 hRet = _SHStrDupAA(lpStrRet->u.cStr, ppszName);
1535 hRet = _SHStrDupAA(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, ppszName);
1545 /*************************************************************************
1546 * StrRetToStrW [SHLWAPI.@]
1550 HRESULT WINAPI StrRetToStrW(LPSTRRET lpStrRet, const ITEMIDLIST *pidl, LPWSTR *ppszName)
1552 HRESULT hRet = E_FAIL;
1554 switch (lpStrRet->uType)
1557 hRet = SHStrDupW(lpStrRet->u.pOleStr, ppszName);
1558 CoTaskMemFree(lpStrRet->u.pOleStr);
1562 hRet = SHStrDupA(lpStrRet->u.cStr, ppszName);
1566 hRet = SHStrDupA(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, ppszName);
1576 /* Create an ASCII string copy using SysAllocString() */
1577 static HRESULT _SHStrDupAToBSTR(LPCSTR src, BSTR *pBstrOut)
1583 INT len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0);
1584 WCHAR* szTemp = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1588 MultiByteToWideChar(CP_ACP, 0, src, -1, szTemp, len);
1589 *pBstrOut = SysAllocString(szTemp);
1590 HeapFree(GetProcessHeap(), 0, szTemp);
1596 return E_OUTOFMEMORY;
1599 /*************************************************************************
1600 * StrRetToBSTR [SHLWAPI.@]
1602 * Converts a STRRET to a BSTR.
1605 * lpStrRet [O] STRRET to convert
1606 * pidl [I] ITEMIDLIST for lpStrRet->uType = STRRET_OFFSET
1607 * pBstrOut [O] Destination for converted BSTR
1610 * Success: S_OK. pBstrOut contains the new string.
1611 * Failure: E_FAIL, if any parameters are invalid.
1613 HRESULT WINAPI StrRetToBSTR(STRRET *lpStrRet, LPCITEMIDLIST pidl, BSTR* pBstrOut)
1615 HRESULT hRet = E_FAIL;
1617 switch (lpStrRet->uType)
1620 *pBstrOut = SysAllocString(lpStrRet->u.pOleStr);
1623 CoTaskMemFree(lpStrRet->u.pOleStr);
1627 hRet = _SHStrDupAToBSTR(lpStrRet->u.cStr, pBstrOut);
1631 hRet = _SHStrDupAToBSTR(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, pBstrOut);
1641 /*************************************************************************
1642 * StrFormatKBSizeA [SHLWAPI.@]
1644 * Create a formatted string containing a byte count in Kilobytes.
1647 * llBytes [I] Byte size to format
1648 * lpszDest [I] Destination for formatted string
1649 * cchMax [I] Size of lpszDest
1654 LPSTR WINAPI StrFormatKBSizeA(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax)
1658 if (!StrFormatKBSizeW(llBytes, wszBuf, 256))
1660 if (!WideCharToMultiByte(CP_ACP, 0, wszBuf, -1, lpszDest, cchMax, NULL, NULL))
1665 /*************************************************************************
1666 * StrFormatKBSizeW [SHLWAPI.@]
1668 * See StrFormatKBSizeA.
1670 LPWSTR WINAPI StrFormatKBSizeW(LONGLONG llBytes, LPWSTR lpszDest, UINT cchMax)
1672 static const WCHAR kb[] = {' ','K','B',0};
1673 LONGLONG llKB = (llBytes + 1023) >> 10;
1676 TRACE("(0x%s,%p,%d)\n", wine_dbgstr_longlong(llBytes), lpszDest, cchMax);
1678 if (!FormatInt(llKB, lpszDest, cchMax))
1681 len = lstrlenW(lpszDest);
1682 if (cchMax - len < 4)
1684 lstrcatW(lpszDest, kb);
1688 /*************************************************************************
1689 * StrNCatA [SHLWAPI.@]
1691 * Concatenate two strings together.
1694 * lpszStr [O] String to concatenate to
1695 * lpszCat [I] String to add to lpszCat
1696 * cchMax [I] Maximum number of characters to concatenate
1702 * cchMax determines the number of characters that are appended to lpszStr,
1703 * not the total length of the string.
1705 LPSTR WINAPI StrNCatA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax)
1707 LPSTR lpszRet = lpszStr;
1709 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszCat), cchMax);
1713 WARN("Invalid lpszStr would crash under Win32!\n");
1717 StrCpyNA(lpszStr + strlen(lpszStr), lpszCat, cchMax);
1721 /*************************************************************************
1722 * StrNCatW [SHLWAPI.@]
1726 LPWSTR WINAPI StrNCatW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax)
1728 LPWSTR lpszRet = lpszStr;
1730 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszCat), cchMax);
1734 WARN("Invalid lpszStr would crash under Win32\n");
1738 StrCpyNW(lpszStr + strlenW(lpszStr), lpszCat, cchMax);
1742 /*************************************************************************
1743 * StrTrimA [SHLWAPI.@]
1745 * Remove characters from the start and end of a string.
1748 * lpszStr [O] String to remove characters from
1749 * lpszTrim [I] Characters to remove from lpszStr
1752 * TRUE If lpszStr was valid and modified
1755 BOOL WINAPI StrTrimA(LPSTR lpszStr, LPCSTR lpszTrim)
1758 LPSTR lpszRead = lpszStr;
1761 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszTrim));
1763 if (lpszRead && *lpszRead)
1765 while (*lpszRead && StrChrA(lpszTrim, *lpszRead))
1766 lpszRead = CharNextA(lpszRead); /* Skip leading matches */
1768 dwLen = strlen(lpszRead);
1770 if (lpszRead != lpszStr)
1772 memmove(lpszStr, lpszRead, dwLen + 1);
1777 lpszRead = lpszStr + dwLen;
1778 while (StrChrA(lpszTrim, lpszRead[-1]))
1779 lpszRead = CharPrevA(lpszStr, lpszRead); /* Skip trailing matches */
1781 if (lpszRead != lpszStr + dwLen)
1791 /*************************************************************************
1792 * StrTrimW [SHLWAPI.@]
1796 BOOL WINAPI StrTrimW(LPWSTR lpszStr, LPCWSTR lpszTrim)
1799 LPWSTR lpszRead = lpszStr;
1802 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszTrim));
1804 if (lpszRead && *lpszRead)
1806 while (*lpszRead && StrChrW(lpszTrim, *lpszRead))
1807 lpszRead = CharNextW(lpszRead); /* Skip leading matches */
1809 dwLen = strlenW(lpszRead);
1811 if (lpszRead != lpszStr)
1813 memmove(lpszStr, lpszRead, (dwLen + 1) * sizeof(WCHAR));
1818 lpszRead = lpszStr + dwLen;
1819 while (StrChrW(lpszTrim, lpszRead[-1]))
1820 lpszRead = CharPrevW(lpszStr, lpszRead); /* Skip trailing matches */
1822 if (lpszRead != lpszStr + dwLen)
1832 /*************************************************************************
1833 * _SHStrDupAA [INTERNAL]
1835 * Duplicates a ASCII string to ASCII. The destination buffer is allocated.
1837 static HRESULT WINAPI _SHStrDupAA(LPCSTR src, LPSTR * dest)
1843 len = lstrlenA(src) + 1;
1844 *dest = CoTaskMemAlloc(len);
1850 lstrcpynA(*dest,src, len);
1856 TRACE("%s->(%p)\n", debugstr_a(src), *dest);
1860 /*************************************************************************
1861 * SHStrDupA [SHLWAPI.@]
1863 * Return a Unicode copy of a string, in memory allocated by CoTaskMemAlloc().
1866 * lpszStr [I] String to copy
1867 * lppszDest [O] Destination for the new string copy
1870 * Success: S_OK. lppszDest contains the new string in Unicode format.
1871 * Failure: E_OUTOFMEMORY, If any arguments are invalid or memory allocation
1874 HRESULT WINAPI SHStrDupA(LPCSTR lpszStr, LPWSTR * lppszDest)
1881 len = MultiByteToWideChar(0, 0, lpszStr, -1, 0, 0) * sizeof(WCHAR);
1882 *lppszDest = CoTaskMemAlloc(len);
1889 MultiByteToWideChar(0, 0, lpszStr, -1, *lppszDest, len/sizeof(WCHAR));
1893 hRet = E_OUTOFMEMORY;
1895 TRACE("%s->(%p)\n", debugstr_a(lpszStr), *lppszDest);
1899 /*************************************************************************
1900 * _SHStrDupAW [INTERNAL]
1902 * Duplicates a UNICODE to a ASCII string. The destination buffer is allocated.
1904 static HRESULT WINAPI _SHStrDupAW(LPCWSTR src, LPSTR * dest)
1910 len = WideCharToMultiByte(CP_ACP, 0, src, -1, NULL, 0, NULL, NULL);
1911 *dest = CoTaskMemAlloc(len);
1917 WideCharToMultiByte(CP_ACP, 0, src, -1, *dest, len, NULL, NULL);
1923 TRACE("%s->(%p)\n", debugstr_w(src), *dest);
1927 /*************************************************************************
1928 * SHStrDupW [SHLWAPI.@]
1932 HRESULT WINAPI SHStrDupW(LPCWSTR src, LPWSTR * dest)
1938 len = (lstrlenW(src) + 1) * sizeof(WCHAR);
1939 *dest = CoTaskMemAlloc(len);
1945 memcpy(*dest, src, len);
1951 TRACE("%s->(%p)\n", debugstr_w(src), *dest);
1955 /*************************************************************************
1956 * SHLWAPI_WriteReverseNum
1958 * Internal helper for SHLWAPI_WriteTimeClass.
1960 inline static LPWSTR SHLWAPI_WriteReverseNum(LPWSTR lpszOut, DWORD dwNum)
1964 /* Write a decimal number to a string, backwards */
1967 DWORD dwNextDigit = dwNum % 10;
1968 *lpszOut-- = '0' + dwNextDigit;
1969 dwNum = (dwNum - dwNextDigit) / 10;
1970 } while (dwNum > 0);
1975 /*************************************************************************
1976 * SHLWAPI_FormatSignificant
1978 * Internal helper for SHLWAPI_WriteTimeClass.
1980 inline static int SHLWAPI_FormatSignificant(LPWSTR lpszNum, int dwDigits)
1982 /* Zero non significant digits, return remaining significant digits */
1986 if (--dwDigits == 0)
1996 /*************************************************************************
1997 * SHLWAPI_WriteTimeClass
1999 * Internal helper for StrFromTimeIntervalW.
2001 static int WINAPI SHLWAPI_WriteTimeClass(LPWSTR lpszOut, DWORD dwValue,
2002 UINT uClassStringId, int iDigits)
2004 WCHAR szBuff[64], *szOut = szBuff + 32;
2006 szOut = SHLWAPI_WriteReverseNum(szOut, dwValue);
2007 iDigits = SHLWAPI_FormatSignificant(szOut + 1, iDigits);
2009 LoadStringW(shlwapi_hInstance, uClassStringId, szBuff + 32, 32);
2010 strcatW(lpszOut, szOut);
2014 /*************************************************************************
2015 * StrFromTimeIntervalA [SHLWAPI.@]
2017 * Format a millisecond time interval into a string
2020 * lpszStr [O] Output buffer for formatted time interval
2021 * cchMax [I] Size of lpszStr
2022 * dwMS [I] Number of milliseconds
2023 * iDigits [I] Number of digits to print
2026 * The length of the formatted string, or 0 if any parameter is invalid.
2029 * This implementation mimics the Win32 behaviour of always writing a leading
2030 * space before the time interval begins.
2032 * iDigits is used to provide approximate times if accuracy is not important.
2033 * This number of digits will be written of the first non-zero time class
2034 * (hours/minutes/seconds). If this does not complete the time classification,
2035 * the remaining digits are changed to zeros (i.e. The time is _not_ rounded).
2036 * If there are digits remaining following the writing of a time class, the
2037 * next time class will be written.
2039 * For example, given dwMS represents 138 hours,43 minutes and 15 seconds, the
2040 * following will result from the given values of iDigits:
2042 *| iDigits 1 2 3 4 5 ...
2043 *| lpszStr "100 hr" "130 hr" "138 hr" "138 hr 40 min" "138 hr 43 min" ...
2045 INT WINAPI StrFromTimeIntervalA(LPSTR lpszStr, UINT cchMax, DWORD dwMS,
2050 TRACE("(%p,%d,%d,%d)\n", lpszStr, cchMax, dwMS, iDigits);
2052 if (lpszStr && cchMax)
2055 StrFromTimeIntervalW(szBuff, sizeof(szBuff)/sizeof(WCHAR), dwMS, iDigits);
2056 WideCharToMultiByte(CP_ACP,0,szBuff,-1,lpszStr,cchMax,0,0);
2062 /*************************************************************************
2063 * StrFromTimeIntervalW [SHLWAPI.@]
2065 * See StrFromTimeIntervalA.
2067 INT WINAPI StrFromTimeIntervalW(LPWSTR lpszStr, UINT cchMax, DWORD dwMS,
2072 TRACE("(%p,%d,%d,%d)\n", lpszStr, cchMax, dwMS, iDigits);
2074 if (lpszStr && cchMax)
2077 DWORD dwHours, dwMinutes;
2079 if (!iDigits || cchMax == 1)
2085 /* Calculate the time classes */
2086 dwMS = (dwMS + 500) / 1000;
2087 dwHours = dwMS / 3600;
2088 dwMS -= dwHours * 3600;
2089 dwMinutes = dwMS / 60;
2090 dwMS -= dwMinutes * 60;
2095 iDigits = SHLWAPI_WriteTimeClass(szCopy, dwHours, IDS_TIME_INTERVAL_HOURS, iDigits);
2097 if (dwMinutes && iDigits)
2098 iDigits = SHLWAPI_WriteTimeClass(szCopy, dwMinutes, IDS_TIME_INTERVAL_MINUTES, iDigits);
2100 if (iDigits) /* Always write seconds if we have significant digits */
2101 SHLWAPI_WriteTimeClass(szCopy, dwMS, IDS_TIME_INTERVAL_SECONDS, iDigits);
2103 lstrcpynW(lpszStr, szCopy, cchMax);
2104 iRet = strlenW(lpszStr);
2109 /*************************************************************************
2110 * StrIsIntlEqualA [SHLWAPI.@]
2112 * Compare two strings.
2115 * bCase [I] Whether to compare case sensitively
2116 * lpszStr [I] First string to compare
2117 * lpszComp [I] Second string to compare
2118 * iLen [I] Length to compare
2121 * TRUE If the strings are equal.
2124 BOOL WINAPI StrIsIntlEqualA(BOOL bCase, LPCSTR lpszStr, LPCSTR lpszComp,
2129 TRACE("(%d,%s,%s,%d)\n", bCase,
2130 debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
2132 /* FIXME: This flag is undocumented and unknown by our CompareString.
2133 * We need a define for it.
2135 dwFlags = 0x10000000;
2136 if (!bCase) dwFlags |= NORM_IGNORECASE;
2138 return (CompareStringA(GetThreadLocale(), dwFlags, lpszStr, iLen, lpszComp, iLen) == CSTR_EQUAL);
2141 /*************************************************************************
2142 * StrIsIntlEqualW [SHLWAPI.@]
2144 * See StrIsIntlEqualA.
2146 BOOL WINAPI StrIsIntlEqualW(BOOL bCase, LPCWSTR lpszStr, LPCWSTR lpszComp,
2151 TRACE("(%d,%s,%s,%d)\n", bCase,
2152 debugstr_w(lpszStr),debugstr_w(lpszComp), iLen);
2154 /* FIXME: This flag is undocumented and unknown by our CompareString.
2155 * We need a define for it.
2157 dwFlags = 0x10000000;
2158 if (!bCase) dwFlags |= NORM_IGNORECASE;
2160 return (CompareStringW(GetThreadLocale(), dwFlags, lpszStr, iLen, lpszComp, iLen) == CSTR_EQUAL);
2163 /*************************************************************************
2166 * Copy a string to another string, up to a maximum number of characters.
2169 * lpszDest [O] Destination string
2170 * lpszSrc [I] Source string
2171 * iLen [I] Maximum number of chars to copy
2174 * Success: A pointer to the last character written to lpszDest..
2175 * Failure: lpszDest, if any arguments are invalid.
2177 LPSTR WINAPI StrCpyNXA(LPSTR lpszDest, LPCSTR lpszSrc, int iLen)
2179 TRACE("(%p,%s,%i)\n", lpszDest, debugstr_a(lpszSrc), iLen);
2181 if (lpszDest && lpszSrc && iLen > 0)
2183 while ((iLen-- > 1) && *lpszSrc)
2184 *lpszDest++ = *lpszSrc++;
2191 /*************************************************************************
2194 * Unicode version of StrCpyNXA.
2196 LPWSTR WINAPI StrCpyNXW(LPWSTR lpszDest, LPCWSTR lpszSrc, int iLen)
2198 TRACE("(%p,%s,%i)\n", lpszDest, debugstr_w(lpszSrc), iLen);
2200 if (lpszDest && lpszSrc && iLen > 0)
2202 while ((iLen-- > 1) && *lpszSrc)
2203 *lpszDest++ = *lpszSrc++;
2210 /*************************************************************************
2211 * StrCmpLogicalW [SHLWAPI.@]
2213 * Compare two strings, ignoring case and comparing digits as numbers.
2216 * lpszStr [I] First string to compare
2217 * lpszComp [I] Second string to compare
2218 * iLen [I] Length to compare
2221 * TRUE If the strings are equal.
2224 INT WINAPI StrCmpLogicalW(LPCWSTR lpszStr, LPCWSTR lpszComp)
2228 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszComp));
2230 if (lpszStr && lpszComp)
2236 else if (isdigitW(*lpszStr))
2240 if (!isdigitW(*lpszComp))
2243 /* Compare the numbers */
2244 StrToIntExW(lpszStr, 0, &iStr);
2245 StrToIntExW(lpszComp, 0, &iComp);
2249 else if (iStr > iComp)
2253 while (isdigitW(*lpszStr))
2255 while (isdigitW(*lpszComp))
2258 else if (isdigitW(*lpszComp))
2262 iDiff = SHLWAPI_ChrCmpHelperW(*lpszStr,*lpszComp,NORM_IGNORECASE);
2278 /* Structure for formatting byte strings */
2279 typedef struct tagSHLWAPI_BYTEFORMATS
2286 } SHLWAPI_BYTEFORMATS;
2288 /*************************************************************************
2289 * StrFormatByteSizeW [SHLWAPI.@]
2291 * Create a string containing an abbreviated byte count of up to 2^63-1.
2294 * llBytes [I] Byte size to format
2295 * lpszDest [I] Destination for formatted string
2296 * cchMax [I] Size of lpszDest
2302 * There is no StrFormatByteSize64W function, it is called StrFormatByteSizeW().
2304 LPWSTR WINAPI StrFormatByteSizeW(LONGLONG llBytes, LPWSTR lpszDest, UINT cchMax)
2306 #define KB ((ULONGLONG)1024)
2308 #define GB (KB*KB*KB)
2309 #define TB (KB*KB*KB*KB)
2310 #define PB (KB*KB*KB*KB*KB)
2312 static const SHLWAPI_BYTEFORMATS bfFormats[] =
2314 { 10*KB, 10.24, 100.0, 2, 'K' }, /* 10 KB */
2315 { 100*KB, 102.4, 10.0, 1, 'K' }, /* 100 KB */
2316 { 1000*KB, 1024.0, 1.0, 0, 'K' }, /* 1000 KB */
2317 { 10*MB, 10485.76, 100.0, 2, 'M' }, /* 10 MB */
2318 { 100*MB, 104857.6, 10.0, 1, 'M' }, /* 100 MB */
2319 { 1000*MB, 1048576.0, 1.0, 0, 'M' }, /* 1000 MB */
2320 { 10*GB, 10737418.24, 100.0, 2, 'G' }, /* 10 GB */
2321 { 100*GB, 107374182.4, 10.0, 1, 'G' }, /* 100 GB */
2322 { 1000*GB, 1073741824.0, 1.0, 0, 'G' }, /* 1000 GB */
2323 { 10*TB, 10485.76, 100.0, 2, 'T' }, /* 10 TB */
2324 { 100*TB, 104857.6, 10.0, 1, 'T' }, /* 100 TB */
2325 { 1000*TB, 1048576.0, 1.0, 0, 'T' }, /* 1000 TB */
2326 { 10*PB, 10737418.24, 100.00, 2, 'P' }, /* 10 PB */
2327 { 100*PB, 107374182.4, 10.00, 1, 'P' }, /* 100 PB */
2328 { 1000*PB, 1073741824.0, 1.00, 0, 'P' }, /* 1000 PB */
2329 { 0, 10995116277.76, 100.00, 2, 'E' } /* EB's, catch all */
2331 WCHAR wszAdd[] = {' ','?','B',0};
2335 TRACE("(0x%s,%p,%d)\n", wine_dbgstr_longlong(llBytes), lpszDest, cchMax);
2337 if (!lpszDest || !cchMax)
2340 if (llBytes < 1024) /* 1K */
2342 WCHAR wszBytesFormat[64];
2343 LoadStringW(shlwapi_hInstance, IDS_BYTES_FORMAT, wszBytesFormat, 64);
2344 snprintfW(lpszDest, cchMax, wszBytesFormat, (long)llBytes);
2348 /* Note that if this loop completes without finding a match, i will be
2349 * pointing at the last entry, which is a catch all for > 1000 PB
2351 while (i < sizeof(bfFormats) / sizeof(SHLWAPI_BYTEFORMATS) - 1)
2353 if (llBytes < bfFormats[i].dLimit)
2357 /* Above 1 TB we encounter problems with FP accuracy. So for amounts above
2358 * this number we integer shift down by 1 MB first. The table above has
2359 * the divisors scaled down from the '< 10 TB' entry onwards, to account
2360 * for this. We also add a small fudge factor to get the correct result for
2361 * counts that lie exactly on a 1024 byte boundary.
2364 dBytes = (double)(llBytes >> 20) + 0.001; /* Scale down by I MB */
2366 dBytes = (double)llBytes + 0.00001;
2368 dBytes = floor(dBytes / bfFormats[i].dDivisor) / bfFormats[i].dNormaliser;
2370 if (!FormatDouble(dBytes, bfFormats[i].nDecimals, lpszDest, cchMax))
2372 wszAdd[1] = bfFormats[i].wPrefix;
2373 StrCatBuffW(lpszDest, wszAdd, cchMax);
2377 /*************************************************************************
2378 * StrFormatByteSize64A [SHLWAPI.@]
2380 * See StrFormatByteSizeW.
2382 LPSTR WINAPI StrFormatByteSize64A(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax)
2386 StrFormatByteSizeW(llBytes, wszBuff, sizeof(wszBuff)/sizeof(WCHAR));
2389 WideCharToMultiByte(CP_ACP, 0, wszBuff, -1, lpszDest, cchMax, 0, 0);
2393 /*************************************************************************
2394 * StrFormatByteSizeA [SHLWAPI.@]
2396 * Create a string containing an abbreviated byte count of up to 2^31-1.
2399 * dwBytes [I] Byte size to format
2400 * lpszDest [I] Destination for formatted string
2401 * cchMax [I] Size of lpszDest
2407 * The Ascii and Unicode versions of this function accept a different
2408 * integer type for dwBytes. See StrFormatByteSize64A().
2410 LPSTR WINAPI StrFormatByteSizeA(DWORD dwBytes, LPSTR lpszDest, UINT cchMax)
2412 TRACE("(%d,%p,%d)\n", dwBytes, lpszDest, cchMax);
2414 return StrFormatByteSize64A(dwBytes, lpszDest, cchMax);
2417 /*************************************************************************
2420 * Remove a hanging lead byte from the end of a string, if present.
2423 * lpStr [I] String to check for a hanging lead byte
2424 * size [I] Length of lpStr
2427 * Success: The new length of the string. Any hanging lead bytes are removed.
2428 * Failure: 0, if any parameters are invalid.
2430 DWORD WINAPI SHTruncateString(LPSTR lpStr, DWORD size)
2434 LPSTR lastByte = lpStr + size - 1;
2436 while(lpStr < lastByte)
2437 lpStr += IsDBCSLeadByte(*lpStr) ? 2 : 1;
2439 if(lpStr == lastByte && IsDBCSLeadByte(*lpStr))
2449 /*************************************************************************
2452 * Remove a single non-trailing ampersand ('&') from a string.
2455 * lpszStr [I/O] String to remove ampersand from.
2458 * The character after the first ampersand in lpszStr, or the first character
2459 * in lpszStr if there is no ampersand in the string.
2461 char WINAPI SHStripMneumonicA(LPCSTR lpszStr)
2463 LPSTR lpszIter, lpszTmp;
2466 TRACE("(%s)\n", debugstr_a(lpszStr));
2470 if ((lpszIter = StrChrA(lpszStr, '&')))
2472 lpszTmp = CharNextA(lpszIter);
2473 if (lpszTmp && *lpszTmp)
2475 if (*lpszTmp != '&')
2478 while (lpszIter && *lpszIter)
2480 lpszTmp = CharNextA(lpszIter);
2481 *lpszIter = *lpszTmp;
2490 /*************************************************************************
2493 * Unicode version of SHStripMneumonicA.
2495 WCHAR WINAPI SHStripMneumonicW(LPCWSTR lpszStr)
2497 LPWSTR lpszIter, lpszTmp;
2500 TRACE("(%s)\n", debugstr_w(lpszStr));
2504 if ((lpszIter = StrChrW(lpszStr, '&')))
2506 lpszTmp = CharNextW(lpszIter);
2507 if (lpszTmp && *lpszTmp)
2509 if (*lpszTmp != '&')
2512 while (lpszIter && *lpszIter)
2514 lpszTmp = CharNextW(lpszIter);
2515 *lpszIter = *lpszTmp;
2524 /*************************************************************************
2527 * Convert an Ascii string to Unicode.
2530 * dwCp [I] Code page for the conversion
2531 * lpSrcStr [I] Source Ascii string to convert
2532 * lpDstStr [O] Destination for converted Unicode string
2533 * iLen [I] Length of lpDstStr
2536 * The return value of the MultiByteToWideChar() function called on lpSrcStr.
2538 DWORD WINAPI SHAnsiToUnicodeCP(DWORD dwCp, LPCSTR lpSrcStr, LPWSTR lpDstStr, int iLen)
2542 dwRet = MultiByteToWideChar(dwCp, 0, lpSrcStr, -1, lpDstStr, iLen);
2543 TRACE("%s->%s,ret=%d\n", debugstr_a(lpSrcStr), debugstr_w(lpDstStr), dwRet);
2547 /*************************************************************************
2550 * Convert an Ascii string to Unicode.
2553 * lpSrcStr [I] Source Ascii string to convert
2554 * lpDstStr [O] Destination for converted Unicode string
2555 * iLen [I] Length of lpDstStr
2558 * The return value of the MultiByteToWideChar() function called on lpSrcStr.
2561 * This function simply calls SHAnsiToUnicodeCP with code page CP_ACP.
2563 DWORD WINAPI SHAnsiToUnicode(LPCSTR lpSrcStr, LPWSTR lpDstStr, int iLen)
2565 return SHAnsiToUnicodeCP(CP_ACP, lpSrcStr, lpDstStr, iLen);
2568 /*************************************************************************
2571 * Convert a Unicode string to Ascii.
2574 * CodePage [I] Code page to use for the conversion
2575 * lpSrcStr [I] Source Unicode string to convert
2576 * lpDstStr [O] Destination for converted Ascii string
2577 * lpiLen [I/O] Input length of lpDstStr/destination for length of lpDstStr
2580 * Success: The number of characters that result from the conversion.
2583 INT WINAPI SHUnicodeToAnsiCP(UINT CodePage, LPCWSTR lpSrcStr, LPSTR lpDstStr,
2586 static const WCHAR emptyW[] = { '\0' };
2590 if (!lpDstStr || !lpiLen)
2598 len = strlenW(lpSrcStr) + 1;
2603 CodePage = CP_UTF8; /* Fall through... */
2604 case 0x0000C350: /* FIXME: CP_ #define */
2609 INT nWideCharCount = len - 1;
2611 GET_FUNC(pConvertINetUnicodeToMultiByte, mlang, "ConvertINetUnicodeToMultiByte", 0);
2612 if (!pConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &nWideCharCount, lpDstStr,
2616 if (nWideCharCount < len - 1)
2618 mem = HeapAlloc(GetProcessHeap(), 0, *lpiLen);
2624 if (pConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &len, mem, lpiLen))
2626 SHTruncateString(mem, *lpiLen);
2627 lstrcpynA(lpDstStr, mem, *lpiLen + 1);
2628 HeapFree(GetProcessHeap(), 0, mem);
2631 HeapFree(GetProcessHeap(), 0, mem);
2634 lpDstStr[*lpiLen] = '\0';
2641 reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, lpDstStr,
2642 *lpiLen, NULL, NULL);
2644 if (!reqLen && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
2646 reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, NULL, 0, NULL, NULL);
2649 mem = HeapAlloc(GetProcessHeap(), 0, reqLen);
2652 reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, mem,
2653 reqLen, NULL, NULL);
2655 reqLen = SHTruncateString(mem, *lpiLen);
2658 lstrcpynA(lpDstStr, mem, *lpiLen);
2660 HeapFree(GetProcessHeap(), 0, mem);
2667 /*************************************************************************
2670 * Convert a Unicode string to Ascii.
2673 * lpSrcStr [I] Source Unicode string to convert
2674 * lpDstStr [O] Destination for converted Ascii string
2675 * iLen [O] Length of lpDstStr in characters
2678 * See SHUnicodeToAnsiCP
2681 * This function simply calls SHUnicodeToAnsiCP() with CodePage = CP_ACP.
2683 INT WINAPI SHUnicodeToAnsi(LPCWSTR lpSrcStr, LPSTR lpDstStr, INT iLen)
2687 return SHUnicodeToAnsiCP(CP_ACP, lpSrcStr, lpDstStr, &myint);
2690 /*************************************************************************
2693 * Copy one string to another.
2696 * lpszSrc [I] Source string to copy
2697 * lpszDst [O] Destination for copy
2698 * iLen [I] Length of lpszDst in characters
2701 * The length of the copied string, including the terminating NUL. lpszDst
2702 * contains iLen characters of lpszSrc.
2704 DWORD WINAPI SHAnsiToAnsi(LPCSTR lpszSrc, LPSTR lpszDst, int iLen)
2708 TRACE("(%s,%p,0x%08x)\n", debugstr_a(lpszSrc), lpszDst, iLen);
2710 lpszRet = StrCpyNXA(lpszDst, lpszSrc, iLen);
2711 return lpszRet - lpszDst + 1;
2714 /*************************************************************************
2717 * Unicode version of SSHAnsiToAnsi.
2719 DWORD WINAPI SHUnicodeToUnicode(LPCWSTR lpszSrc, LPWSTR lpszDst, int iLen)
2723 TRACE("(%s,%p,0x%08x)\n", debugstr_w(lpszSrc), lpszDst, iLen);
2725 lpszRet = StrCpyNXW(lpszDst, lpszSrc, iLen);
2726 return lpszRet - lpszDst + 1;
2729 /*************************************************************************
2732 * Determine if an Ascii string converts to Unicode and back identically.
2735 * lpSrcStr [I] Source Unicode string to convert
2736 * lpDst [O] Destination for resulting Ascii string
2737 * iLen [I] Length of lpDst in characters
2740 * TRUE, since Ascii strings always convert identically.
2742 BOOL WINAPI DoesStringRoundTripA(LPCSTR lpSrcStr, LPSTR lpDst, INT iLen)
2744 lstrcpynA(lpDst, lpSrcStr, iLen);
2748 /*************************************************************************
2751 * Determine if a Unicode string converts to Ascii and back identically.
2754 * lpSrcStr [I] Source Unicode string to convert
2755 * lpDst [O] Destination for resulting Ascii string
2756 * iLen [I] Length of lpDst in characters
2759 * TRUE, if lpSrcStr converts to Ascii and back identically,
2762 BOOL WINAPI DoesStringRoundTripW(LPCWSTR lpSrcStr, LPSTR lpDst, INT iLen)
2764 WCHAR szBuff[MAX_PATH];
2766 SHUnicodeToAnsi(lpSrcStr, lpDst, iLen);
2767 SHAnsiToUnicode(lpDst, szBuff, MAX_PATH);
2768 return !strcmpW(lpSrcStr, szBuff);
2771 /*************************************************************************
2772 * SHLoadIndirectString [SHLWAPI.@]
2774 * If passed a string that begins with a '@' extract the string from the
2775 * appropriate resource, otherwise do a straight copy.
2778 HRESULT WINAPI SHLoadIndirectString(LPCWSTR src, LPWSTR dst, UINT dst_len, void **reserved)
2780 WCHAR *dllname = NULL;
2781 HMODULE hmod = NULL;
2782 HRESULT hr = E_FAIL;
2784 TRACE("(%s %p %08x %p)\n", debugstr_w(src), dst, dst_len, reserved);
2792 dllname = StrDupW(src + 1);
2793 index_str = strchrW(dllname, ',');
2795 if(!index_str) goto end;
2799 index = atoiW(index_str);
2801 hmod = LoadLibraryW(dllname);
2806 if(LoadStringW(hmod, -index, dst, dst_len))
2810 FIXME("can't handle non-negative indicies (%d)\n", index);
2815 lstrcpynW(dst, src, dst_len);
2819 TRACE("returing %s\n", debugstr_w(dst));
2821 if(hmod) FreeLibrary(hmod);
2822 HeapFree(GetProcessHeap(), 0, dllname);