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 WIN32_NO_STATUS
24 #define COM_NO_WINDOWS_H
27 //#include "wine/port.h"
34 #define NONAMELESSUNION
35 #define NONAMELESSSTRUCT
38 #define NO_SHLWAPI_REG
39 #define NO_SHLWAPI_STREAM
42 //#include "winuser.h"
46 #include <wine/unicode.h>
47 #include <wine/debug.h>
51 WINE_DEFAULT_DEBUG_CHANNEL(shell
);
53 extern HINSTANCE shlwapi_hInstance
;
55 static HRESULT
_SHStrDupAA(LPCSTR
,LPSTR
*);
56 static HRESULT
_SHStrDupAW(LPCWSTR
,LPSTR
*);
59 static void FillNumberFmt(NUMBERFMTW
*fmt
, LPWSTR decimal_buffer
, int decimal_bufwlen
,
60 LPWSTR thousand_buffer
, int thousand_bufwlen
)
65 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_ILZERO
|LOCALE_RETURN_NUMBER
, (LPWSTR
)&fmt
->LeadingZero
, sizeof(fmt
->LeadingZero
)/sizeof(WCHAR
));
66 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_INEGNUMBER
|LOCALE_RETURN_NUMBER
, (LPWSTR
)&fmt
->LeadingZero
, sizeof(fmt
->NegativeOrder
)/sizeof(WCHAR
));
68 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_SDECIMAL
, decimal_buffer
, decimal_bufwlen
);
69 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_STHOUSAND
, thousand_buffer
, thousand_bufwlen
);
70 fmt
->lpThousandSep
= thousand_buffer
;
71 fmt
->lpDecimalSep
= decimal_buffer
;
74 * Converting grouping string to number as described on
75 * http://blogs.msdn.com/oldnewthing/archive/2006/04/18/578251.aspx
78 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_SGROUPING
, grouping
, sizeof(grouping
)/sizeof(WCHAR
));
79 for (c
= grouping
; *c
; c
++)
80 if (*c
>= '0' && *c
< '9')
83 fmt
->Grouping
+= *c
- '0';
86 if (fmt
->Grouping
% 10 == 0)
92 /*************************************************************************
93 * FormatInt [internal]
95 * Format an integer according to the current locale
98 * The number of characters written on success or 0 on failure
100 static int FormatInt(LONGLONG qdwValue
, LPWSTR pszBuf
, int cchBuf
)
103 WCHAR decimal
[8], thousand
[8];
106 BOOL neg
= (qdwValue
< 0);
108 FillNumberFmt(&fmt
, decimal
, sizeof decimal
/ sizeof (WCHAR
),
109 thousand
, sizeof thousand
/ sizeof (WCHAR
));
115 *(--c
) = '0' + (qdwValue
%10);
117 } while (qdwValue
> 0);
121 return GetNumberFormatW(LOCALE_USER_DEFAULT
, 0, c
, &fmt
, pszBuf
, cchBuf
);
124 /*************************************************************************
125 * FormatDouble [internal]
127 * Format an integer according to the current locale. Prints the specified number of digits
128 * after the decimal point
131 * The number of characters written on success or 0 on failure
133 static int FormatDouble(double value
, int decimals
, LPWSTR pszBuf
, int cchBuf
)
135 static const WCHAR flfmt
[] = {'%','f',0};
138 WCHAR decimal
[8], thousand
[8];
140 snprintfW(buf
, 64, flfmt
, value
);
142 FillNumberFmt(&fmt
, decimal
, sizeof decimal
/ sizeof (WCHAR
),
143 thousand
, sizeof thousand
/ sizeof (WCHAR
));
144 fmt
.NumDigits
= decimals
;
145 return GetNumberFormatW(LOCALE_USER_DEFAULT
, 0, buf
, &fmt
, pszBuf
, cchBuf
);
148 /*************************************************************************
149 * SHLWAPI_ChrCmpHelperA
151 * Internal helper for SHLWAPI_ChrCmpA/ChrCMPIA.
154 * Both this function and its Unicode counterpart are very inefficient. To
155 * fix this, CompareString must be completely implemented and optimised
156 * first. Then the core character test can be taken out of that function and
157 * placed here, so that it need never be called at all. Until then, do not
158 * attempt to optimise this code unless you are willing to test that it
159 * still performs correctly.
161 static BOOL
SHLWAPI_ChrCmpHelperA(WORD ch1
, WORD ch2
, DWORD dwFlags
)
163 char str1
[3], str2
[3];
165 str1
[0] = LOBYTE(ch1
);
166 if (IsDBCSLeadByte(str1
[0]))
168 str1
[1] = HIBYTE(ch1
);
174 str2
[0] = LOBYTE(ch2
);
175 if (IsDBCSLeadByte(str2
[0]))
177 str2
[1] = HIBYTE(ch2
);
183 return CompareStringA(GetThreadLocale(), dwFlags
, str1
, -1, str2
, -1) - CSTR_EQUAL
;
186 /*************************************************************************
189 * Internal helper function.
191 static BOOL WINAPI
SHLWAPI_ChrCmpA(WORD ch1
, WORD ch2
)
193 return SHLWAPI_ChrCmpHelperA(ch1
, ch2
, 0);
196 /*************************************************************************
197 * ChrCmpIA (SHLWAPI.385)
199 * Compare two characters, ignoring case.
202 * ch1 [I] First character to compare
203 * ch2 [I] Second character to compare
206 * FALSE, if the characters are equal.
207 * Non-zero otherwise.
209 BOOL WINAPI
ChrCmpIA(WORD ch1
, WORD ch2
)
211 TRACE("(%d,%d)\n", ch1
, ch2
);
213 return SHLWAPI_ChrCmpHelperA(ch1
, ch2
, NORM_IGNORECASE
);
216 /*************************************************************************
217 * ChrCmpIW [SHLWAPI.386]
221 BOOL WINAPI
ChrCmpIW(WCHAR ch1
, WCHAR ch2
)
223 return CompareStringW(GetThreadLocale(), NORM_IGNORECASE
, &ch1
, 1, &ch2
, 1) - CSTR_EQUAL
;
226 /*************************************************************************
227 * StrChrA [SHLWAPI.@]
229 * Find a given character in a string.
232 * lpszStr [I] String to search in.
233 * ch [I] Character to search for.
236 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
238 * Failure: NULL, if any arguments are invalid.
240 LPSTR WINAPI
StrChrA(LPCSTR lpszStr
, WORD ch
)
242 TRACE("(%s,%i)\n", debugstr_a(lpszStr
), ch
);
248 if (!SHLWAPI_ChrCmpA(*lpszStr
, ch
))
249 return (LPSTR
)lpszStr
;
250 lpszStr
= CharNextA(lpszStr
);
256 /*************************************************************************
257 * StrChrW [SHLWAPI.@]
261 LPWSTR WINAPI
StrChrW(LPCWSTR lpszStr
, WCHAR ch
)
263 LPWSTR lpszRet
= NULL
;
265 TRACE("(%s,%i)\n", debugstr_w(lpszStr
), ch
);
268 lpszRet
= strchrW(lpszStr
, ch
);
272 /*************************************************************************
273 * StrChrIA [SHLWAPI.@]
275 * Find a given character in a string, ignoring case.
278 * lpszStr [I] String to search in.
279 * ch [I] Character to search for.
282 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
284 * Failure: NULL, if any arguments are invalid.
286 LPSTR WINAPI
StrChrIA(LPCSTR lpszStr
, WORD ch
)
288 TRACE("(%s,%i)\n", debugstr_a(lpszStr
), ch
);
294 if (!ChrCmpIA(*lpszStr
, ch
))
295 return (LPSTR
)lpszStr
;
296 lpszStr
= CharNextA(lpszStr
);
302 /*************************************************************************
303 * StrChrIW [SHLWAPI.@]
307 LPWSTR WINAPI
StrChrIW(LPCWSTR lpszStr
, WCHAR ch
)
309 TRACE("(%s,%i)\n", debugstr_w(lpszStr
), ch
);
316 if (toupperW(*lpszStr
) == ch
)
317 return (LPWSTR
)lpszStr
;
322 return (LPWSTR
)lpszStr
;
325 /*************************************************************************
326 * StrChrNW [SHLWAPI.@]
328 LPWSTR WINAPI
StrChrNW(LPCWSTR lpszStr
, WCHAR ch
, UINT cchMax
)
330 TRACE("(%s(%i),%i)\n", debugstr_wn(lpszStr
,cchMax
), cchMax
, ch
);
334 while (*lpszStr
&& cchMax
-- > 0)
337 return (LPWSTR
)lpszStr
;
344 /*************************************************************************
345 * StrCmpIW [SHLWAPI.@]
347 * Compare two strings, ignoring case.
350 * lpszStr [I] First string to compare
351 * lpszComp [I] Second string to compare
354 * An integer less than, equal to or greater than 0, indicating that
355 * lpszStr is less than, the same, or greater than lpszComp.
357 int WINAPI
StrCmpIW(LPCWSTR lpszStr
, LPCWSTR lpszComp
)
359 TRACE("(%s,%s)\n", debugstr_w(lpszStr
),debugstr_w(lpszComp
));
360 return CompareStringW(GetThreadLocale(), NORM_IGNORECASE
, lpszStr
, -1, lpszComp
, -1) - CSTR_EQUAL
;
363 /*************************************************************************
364 * StrCmpNA [SHLWAPI.@]
366 * Compare two strings, up to a maximum length.
369 * lpszStr [I] First string to compare
370 * lpszComp [I] Second string to compare
371 * iLen [I] Maximum number of chars to compare.
374 * An integer less than, equal to or greater than 0, indicating that
375 * lpszStr is less than, the same, or greater than lpszComp.
377 INT WINAPI
StrCmpNA(LPCSTR lpszStr
, LPCSTR lpszComp
, INT iLen
)
379 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr
), debugstr_a(lpszComp
), iLen
);
380 return CompareStringA(GetThreadLocale(), 0, lpszStr
, iLen
, lpszComp
, iLen
) - CSTR_EQUAL
;
383 /*************************************************************************
384 * StrCmpNW [SHLWAPI.@]
388 INT WINAPI
StrCmpNW(LPCWSTR lpszStr
, LPCWSTR lpszComp
, INT iLen
)
390 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr
), debugstr_w(lpszComp
), iLen
);
391 return CompareStringW(GetThreadLocale(), 0, lpszStr
, iLen
, lpszComp
, iLen
) - CSTR_EQUAL
;
394 /*************************************************************************
395 * StrCmpNIA [SHLWAPI.@]
397 * Compare two strings, up to a maximum length, ignoring case.
400 * lpszStr [I] First string to compare
401 * lpszComp [I] Second string to compare
402 * iLen [I] Maximum number of chars to compare.
405 * An integer less than, equal to or greater than 0, indicating that
406 * lpszStr is less than, the same, or greater than lpszComp.
408 int WINAPI
StrCmpNIA(LPCSTR lpszStr
, LPCSTR lpszComp
, int iLen
)
410 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr
), debugstr_a(lpszComp
), iLen
);
411 return CompareStringA(GetThreadLocale(), NORM_IGNORECASE
, lpszStr
, iLen
, lpszComp
, iLen
) - CSTR_EQUAL
;
414 /*************************************************************************
415 * StrCmpNIW [SHLWAPI.@]
419 INT WINAPI
StrCmpNIW(LPCWSTR lpszStr
, LPCWSTR lpszComp
, int iLen
)
421 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr
), debugstr_w(lpszComp
), iLen
);
422 return CompareStringW(GetThreadLocale(), NORM_IGNORECASE
, lpszStr
, iLen
, lpszComp
, iLen
) - CSTR_EQUAL
;
425 /*************************************************************************
426 * StrCmpW [SHLWAPI.@]
428 * Compare two strings.
431 * lpszStr [I] First string to compare
432 * lpszComp [I] Second string to compare
435 * An integer less than, equal to or greater than 0, indicating that
436 * lpszStr is less than, the same, or greater than lpszComp.
438 int WINAPI
StrCmpW(LPCWSTR lpszStr
, LPCWSTR lpszComp
)
440 TRACE("(%s,%s)\n", debugstr_w(lpszStr
), debugstr_w(lpszComp
));
441 return CompareStringW(GetThreadLocale(), 0, lpszStr
, -1, lpszComp
, -1) - CSTR_EQUAL
;
444 /*************************************************************************
445 * StrCatW [SHLWAPI.@]
447 * Concatenate two strings.
450 * lpszStr [O] Initial string
451 * lpszSrc [I] String to concatenate
456 LPWSTR WINAPI
StrCatW(LPWSTR lpszStr
, LPCWSTR lpszSrc
)
458 TRACE("(%s,%s)\n", debugstr_w(lpszStr
), debugstr_w(lpszSrc
));
460 if (lpszStr
&& lpszSrc
)
461 strcatW(lpszStr
, lpszSrc
);
465 /*************************************************************************
466 * StrCpyW [SHLWAPI.@]
468 * Copy a string to another string.
471 * lpszStr [O] Destination string
472 * lpszSrc [I] Source string
477 LPWSTR WINAPI
StrCpyW(LPWSTR lpszStr
, LPCWSTR lpszSrc
)
479 TRACE("(%p,%s)\n", lpszStr
, debugstr_w(lpszSrc
));
481 if (lpszStr
&& lpszSrc
)
482 strcpyW(lpszStr
, lpszSrc
);
486 /*************************************************************************
487 * StrCpyNW [SHLWAPI.@]
489 * Copy a string to another string, up to a maximum number of characters.
492 * dst [O] Destination string
493 * src [I] Source string
494 * count [I] Maximum number of chars to copy
499 LPWSTR WINAPI
StrCpyNW(LPWSTR dst
, LPCWSTR src
, int count
)
504 TRACE("(%p,%s,%i)\n", dst
, debugstr_w(src
), count
);
508 while ((count
> 1) && *s
)
519 /*************************************************************************
520 * SHLWAPI_StrStrHelperA
522 * Internal implementation of StrStrA/StrStrIA
524 static LPSTR
SHLWAPI_StrStrHelperA(LPCSTR lpszStr
, LPCSTR lpszSearch
,
525 INT (WINAPI
*pStrCmpFn
)(LPCSTR
,LPCSTR
,INT
))
529 if (!lpszStr
|| !lpszSearch
|| !*lpszSearch
)
532 iLen
= strlen(lpszSearch
);
536 if (!pStrCmpFn(lpszStr
, lpszSearch
, iLen
))
537 return (LPSTR
)lpszStr
;
538 lpszStr
= CharNextA(lpszStr
);
543 /*************************************************************************
544 * StrStrA [SHLWAPI.@]
546 * Find a substring within a string.
549 * lpszStr [I] String to search in
550 * lpszSearch [I] String to look for
553 * The start of lpszSearch within lpszStr, or NULL if not found.
555 LPSTR WINAPI
StrStrA(LPCSTR lpszStr
, LPCSTR lpszSearch
)
557 TRACE("(%s,%s)\n", debugstr_a(lpszStr
), debugstr_a(lpszSearch
));
559 return SHLWAPI_StrStrHelperA(lpszStr
, lpszSearch
, StrCmpNA
);
562 /*************************************************************************
563 * StrStrW [SHLWAPI.@]
567 LPWSTR WINAPI
StrStrW(LPCWSTR lpszStr
, LPCWSTR lpszSearch
)
569 TRACE("(%s, %s)\n", debugstr_w(lpszStr
), debugstr_w(lpszSearch
));
571 if (!lpszStr
|| !lpszSearch
|| !*lpszSearch
) return NULL
;
572 return strstrW( lpszStr
, lpszSearch
);
575 /*************************************************************************
576 * StrRStrIA [SHLWAPI.@]
578 * Find the last occurrence of a substring within a string.
581 * lpszStr [I] String to search in
582 * lpszEnd [I] End of lpszStr
583 * lpszSearch [I] String to look for
586 * The last occurrence lpszSearch within lpszStr, or NULL if not found.
588 LPSTR WINAPI
StrRStrIA(LPCSTR lpszStr
, LPCSTR lpszEnd
, LPCSTR lpszSearch
)
593 TRACE("(%s,%s)\n", debugstr_a(lpszStr
), debugstr_a(lpszSearch
));
595 if (!lpszStr
|| !lpszSearch
|| !*lpszSearch
)
599 lpszEnd
= lpszStr
+ lstrlenA(lpszStr
);
600 if (lpszEnd
== lpszStr
)
603 if (IsDBCSLeadByte(*lpszSearch
))
604 ch1
= *lpszSearch
<< 8 | (UCHAR
)lpszSearch
[1];
607 iLen
= lstrlenA(lpszSearch
);
611 lpszEnd
= CharPrevA(lpszStr
, lpszEnd
);
612 ch2
= IsDBCSLeadByte(*lpszEnd
)? *lpszEnd
<< 8 | (UCHAR
)lpszEnd
[1] : *lpszEnd
;
613 if (!ChrCmpIA(ch1
, ch2
))
615 if (!StrCmpNIA(lpszEnd
, lpszSearch
, iLen
))
616 return (LPSTR
)lpszEnd
;
618 } while (lpszEnd
> lpszStr
);
622 /*************************************************************************
623 * StrRStrIW [SHLWAPI.@]
627 LPWSTR WINAPI
StrRStrIW(LPCWSTR lpszStr
, LPCWSTR lpszEnd
, LPCWSTR lpszSearch
)
631 TRACE("(%s,%s)\n", debugstr_w(lpszStr
), debugstr_w(lpszSearch
));
633 if (!lpszStr
|| !lpszSearch
|| !*lpszSearch
)
637 lpszEnd
= lpszStr
+ strlenW(lpszStr
);
639 iLen
= strlenW(lpszSearch
);
641 while (lpszEnd
> lpszStr
)
644 if (!StrCmpNIW(lpszEnd
, lpszSearch
, iLen
))
645 return (LPWSTR
)lpszEnd
;
650 /*************************************************************************
651 * StrStrIA [SHLWAPI.@]
653 * Find a substring within a string, ignoring case.
656 * lpszStr [I] String to search in
657 * lpszSearch [I] String to look for
660 * The start of lpszSearch within lpszStr, or NULL if not found.
662 LPSTR WINAPI
StrStrIA(LPCSTR lpszStr
, LPCSTR lpszSearch
)
664 TRACE("(%s,%s)\n", debugstr_a(lpszStr
), debugstr_a(lpszSearch
));
666 return SHLWAPI_StrStrHelperA(lpszStr
, lpszSearch
, StrCmpNIA
);
669 /*************************************************************************
670 * StrStrIW [SHLWAPI.@]
674 LPWSTR WINAPI
StrStrIW(LPCWSTR lpszStr
, LPCWSTR lpszSearch
)
678 TRACE("(%s,%s)\n", debugstr_w(lpszStr
), debugstr_w(lpszSearch
));
680 if (!lpszStr
|| !lpszSearch
|| !*lpszSearch
)
683 iLen
= strlenW(lpszSearch
);
687 if (!StrCmpNIW(lpszStr
, lpszSearch
, iLen
))
688 return (LPWSTR
)lpszStr
;
694 /*************************************************************************
695 * StrStrNW [SHLWAPI.@]
697 * Find a substring within a string up to a given number of initial characters.
700 * lpFirst [I] String to search in
701 * lpSrch [I] String to look for
702 * cchMax [I] Maximum number of initial search characters
705 * The start of lpFirst within lpSrch, or NULL if not found.
707 LPWSTR WINAPI
StrStrNW(LPCWSTR lpFirst
, LPCWSTR lpSrch
, UINT cchMax
)
712 TRACE("(%s, %s, %u)\n", debugstr_w(lpFirst
), debugstr_w(lpSrch
), cchMax
);
714 if (!lpFirst
|| !lpSrch
|| !*lpSrch
|| !cchMax
)
717 len
= strlenW(lpSrch
);
719 for (i
= cchMax
; *lpFirst
&& (i
> 0); i
--, lpFirst
++)
721 if (!strncmpW(lpFirst
, lpSrch
, len
))
722 return (LPWSTR
)lpFirst
;
728 /*************************************************************************
729 * StrStrNIW [SHLWAPI.@]
731 * Find a substring within a string up to a given number of initial characters,
735 * lpFirst [I] String to search in
736 * lpSrch [I] String to look for
737 * cchMax [I] Maximum number of initial search characters
740 * The start of lpFirst within lpSrch, or NULL if not found.
742 LPWSTR WINAPI
StrStrNIW(LPCWSTR lpFirst
, LPCWSTR lpSrch
, UINT cchMax
)
747 TRACE("(%s, %s, %u)\n", debugstr_w(lpFirst
), debugstr_w(lpSrch
), cchMax
);
749 if (!lpFirst
|| !lpSrch
|| !*lpSrch
|| !cchMax
)
752 len
= strlenW(lpSrch
);
754 for (i
= cchMax
; *lpFirst
&& (i
> 0); i
--, lpFirst
++)
756 if (!strncmpiW(lpFirst
, lpSrch
, len
))
757 return (LPWSTR
)lpFirst
;
763 /*************************************************************************
764 * StrToIntA [SHLWAPI.@]
766 * Read a signed integer from a string.
769 * lpszStr [I] String to read integer from
772 * The signed integer value represented by the string, or 0 if no integer is
776 * No leading space is allowed before the number, although a leading '-' is.
778 int WINAPI
StrToIntA(LPCSTR lpszStr
)
782 TRACE("(%s)\n", debugstr_a(lpszStr
));
786 WARN("Invalid lpszStr would crash under Win32!\n");
790 if (*lpszStr
== '-' || isdigit(*lpszStr
))
791 StrToIntExA(lpszStr
, 0, &iRet
);
795 /*************************************************************************
796 * StrToIntW [SHLWAPI.@]
800 int WINAPI
StrToIntW(LPCWSTR lpszStr
)
804 TRACE("(%s)\n", debugstr_w(lpszStr
));
808 WARN("Invalid lpszStr would crash under Win32!\n");
812 if (*lpszStr
== '-' || isdigitW(*lpszStr
))
813 StrToIntExW(lpszStr
, 0, &iRet
);
817 /*************************************************************************
818 * StrToIntExA [SHLWAPI.@]
820 * Read an integer from a string.
823 * lpszStr [I] String to read integer from
824 * dwFlags [I] Flags controlling the conversion
825 * lpiRet [O] Destination for read integer.
828 * Success: TRUE. lpiRet contains the integer value represented by the string.
829 * Failure: FALSE, if the string is invalid, or no number is present.
832 * Leading whitespace, '-' and '+' are allowed before the number. If
833 * dwFlags includes STIF_SUPPORT_HEX, hexadecimal numbers are allowed, if
834 * preceded by '0x'. If this flag is not set, or there is no '0x' prefix,
835 * the string is treated as a decimal string. A leading '-' is ignored for
836 * hexadecimal numbers.
838 BOOL WINAPI
StrToIntExA(LPCSTR lpszStr
, DWORD dwFlags
, LPINT lpiRet
)
843 TRACE("(%s,%08X,%p)\n", debugstr_a(lpszStr
), dwFlags
, lpiRet
);
845 bRes
= StrToInt64ExA(lpszStr
, dwFlags
, &li
);
846 if (bRes
) *lpiRet
= li
;
850 /*************************************************************************
851 * StrToInt64ExA [SHLWAPI.@]
855 BOOL WINAPI
StrToInt64ExA(LPCSTR lpszStr
, DWORD dwFlags
, LONGLONG
*lpiRet
)
857 BOOL bNegative
= FALSE
;
860 TRACE("(%s,%08X,%p)\n", debugstr_a(lpszStr
), dwFlags
, lpiRet
);
862 if (!lpszStr
|| !lpiRet
)
864 WARN("Invalid parameter would crash under Win32!\n");
867 if (dwFlags
> STIF_SUPPORT_HEX
) WARN("Unknown flags %08x\n", dwFlags
);
869 /* Skip leading space, '+', '-' */
870 while (isspace(*lpszStr
))
871 lpszStr
= CharNextA(lpszStr
);
878 else if (*lpszStr
== '+')
881 if (dwFlags
& STIF_SUPPORT_HEX
&&
882 *lpszStr
== '0' && tolower(lpszStr
[1]) == 'x')
884 /* Read hex number */
887 if (!isxdigit(*lpszStr
))
890 while (isxdigit(*lpszStr
))
893 if (isdigit(*lpszStr
))
894 iRet
+= (*lpszStr
- '0');
896 iRet
+= 10 + (tolower(*lpszStr
) - 'a');
903 /* Read decimal number */
904 if (!isdigit(*lpszStr
))
907 while (isdigit(*lpszStr
))
910 iRet
+= (*lpszStr
- '0');
913 *lpiRet
= bNegative
? -iRet
: iRet
;
917 /*************************************************************************
918 * StrToIntExW [SHLWAPI.@]
922 BOOL WINAPI
StrToIntExW(LPCWSTR lpszStr
, DWORD dwFlags
, LPINT lpiRet
)
927 TRACE("(%s,%08X,%p)\n", debugstr_w(lpszStr
), dwFlags
, lpiRet
);
929 bRes
= StrToInt64ExW(lpszStr
, dwFlags
, &li
);
930 if (bRes
) *lpiRet
= li
;
934 /*************************************************************************
935 * StrToInt64ExW [SHLWAPI.@]
939 BOOL WINAPI
StrToInt64ExW(LPCWSTR lpszStr
, DWORD dwFlags
, LONGLONG
*lpiRet
)
941 BOOL bNegative
= FALSE
;
944 TRACE("(%s,%08X,%p)\n", debugstr_w(lpszStr
), dwFlags
, lpiRet
);
946 if (!lpszStr
|| !lpiRet
)
948 WARN("Invalid parameter would crash under Win32!\n");
951 if (dwFlags
> STIF_SUPPORT_HEX
) WARN("Unknown flags %08x\n", dwFlags
);
953 /* Skip leading space, '+', '-' */
954 while (isspaceW(*lpszStr
)) lpszStr
++;
961 else if (*lpszStr
== '+')
964 if (dwFlags
& STIF_SUPPORT_HEX
&&
965 *lpszStr
== '0' && tolowerW(lpszStr
[1]) == 'x')
967 /* Read hex number */
970 if (!isxdigitW(*lpszStr
))
973 while (isxdigitW(*lpszStr
))
976 if (isdigitW(*lpszStr
))
977 iRet
+= (*lpszStr
- '0');
979 iRet
+= 10 + (tolowerW(*lpszStr
) - 'a');
986 /* Read decimal number */
987 if (!isdigitW(*lpszStr
))
990 while (isdigitW(*lpszStr
))
993 iRet
+= (*lpszStr
- '0');
996 *lpiRet
= bNegative
? -iRet
: iRet
;
1000 /*************************************************************************
1001 * StrDupA [SHLWAPI.@]
1003 * Duplicate a string.
1006 * lpszStr [I] String to duplicate.
1009 * Success: A pointer to a new string containing the contents of lpszStr
1010 * Failure: NULL, if memory cannot be allocated
1013 * The string memory is allocated with LocalAlloc(), and so should be released
1014 * by calling LocalFree().
1016 LPSTR WINAPI
StrDupA(LPCSTR lpszStr
)
1021 TRACE("(%s)\n",debugstr_a(lpszStr
));
1023 iLen
= lpszStr
? strlen(lpszStr
) + 1 : 1;
1024 lpszRet
= LocalAlloc(LMEM_FIXED
, iLen
);
1029 memcpy(lpszRet
, lpszStr
, iLen
);
1036 /*************************************************************************
1037 * StrDupW [SHLWAPI.@]
1041 LPWSTR WINAPI
StrDupW(LPCWSTR lpszStr
)
1046 TRACE("(%s)\n",debugstr_w(lpszStr
));
1048 iLen
= (lpszStr
? strlenW(lpszStr
) + 1 : 1) * sizeof(WCHAR
);
1049 lpszRet
= LocalAlloc(LMEM_FIXED
, iLen
);
1054 memcpy(lpszRet
, lpszStr
, iLen
);
1061 /*************************************************************************
1062 * SHLWAPI_StrSpnHelperA
1064 * Internal implementation of StrSpnA/StrCSpnA/StrCSpnIA
1066 static int SHLWAPI_StrSpnHelperA(LPCSTR lpszStr
, LPCSTR lpszMatch
,
1067 LPSTR (WINAPI
*pStrChrFn
)(LPCSTR
,WORD
),
1070 LPCSTR lpszRead
= lpszStr
;
1071 if (lpszStr
&& *lpszStr
&& lpszMatch
)
1075 LPCSTR lpszTest
= pStrChrFn(lpszMatch
, *lpszRead
);
1077 if (!bInvert
&& !lpszTest
)
1079 if (bInvert
&& lpszTest
)
1081 lpszRead
= CharNextA(lpszRead
);
1084 return lpszRead
- lpszStr
;
1087 /*************************************************************************
1088 * StrSpnA [SHLWAPI.@]
1090 * Find the length of the start of a string that contains only certain
1094 * lpszStr [I] String to search
1095 * lpszMatch [I] Characters that can be in the substring
1098 * The length of the part of lpszStr containing only chars from lpszMatch,
1099 * or 0 if any parameter is invalid.
1101 int WINAPI
StrSpnA(LPCSTR lpszStr
, LPCSTR lpszMatch
)
1103 TRACE("(%s,%s)\n",debugstr_a(lpszStr
), debugstr_a(lpszMatch
));
1105 return SHLWAPI_StrSpnHelperA(lpszStr
, lpszMatch
, StrChrA
, FALSE
);
1108 /*************************************************************************
1109 * StrSpnW [SHLWAPI.@]
1113 int WINAPI
StrSpnW(LPCWSTR lpszStr
, LPCWSTR lpszMatch
)
1115 if (!lpszStr
|| !lpszMatch
) return 0;
1116 return strspnW( lpszStr
, lpszMatch
);
1119 /*************************************************************************
1120 * StrCSpnA [SHLWAPI.@]
1122 * Find the length of the start of a string that does not contain certain
1126 * lpszStr [I] String to search
1127 * lpszMatch [I] Characters that cannot be in the substring
1130 * The length of the part of lpszStr containing only chars not in lpszMatch,
1131 * or 0 if any parameter is invalid.
1133 int WINAPI
StrCSpnA(LPCSTR lpszStr
, LPCSTR lpszMatch
)
1135 TRACE("(%s,%s)\n",debugstr_a(lpszStr
), debugstr_a(lpszMatch
));
1137 return SHLWAPI_StrSpnHelperA(lpszStr
, lpszMatch
, StrChrA
, TRUE
);
1140 /*************************************************************************
1141 * StrCSpnW [SHLWAPI.@]
1145 int WINAPI
StrCSpnW(LPCWSTR lpszStr
, LPCWSTR lpszMatch
)
1147 if (!lpszStr
|| !lpszMatch
) return 0;
1148 return strcspnW( lpszStr
, lpszMatch
);
1151 /*************************************************************************
1152 * StrCSpnIA [SHLWAPI.@]
1154 * Find the length of the start of a string that does not contain certain
1155 * characters, ignoring case.
1158 * lpszStr [I] String to search
1159 * lpszMatch [I] Characters that cannot be in the substring
1162 * The length of the part of lpszStr containing only chars not in lpszMatch,
1163 * or 0 if any parameter is invalid.
1165 int WINAPI
StrCSpnIA(LPCSTR lpszStr
, LPCSTR lpszMatch
)
1167 TRACE("(%s,%s)\n",debugstr_a(lpszStr
), debugstr_a(lpszMatch
));
1169 return SHLWAPI_StrSpnHelperA(lpszStr
, lpszMatch
, StrChrIA
, TRUE
);
1172 /*************************************************************************
1173 * StrCSpnIW [SHLWAPI.@]
1177 int WINAPI
StrCSpnIW(LPCWSTR lpszStr
, LPCWSTR lpszMatch
)
1179 LPCWSTR lpszRead
= lpszStr
;
1181 TRACE("(%s,%s)\n",debugstr_w(lpszStr
), debugstr_w(lpszMatch
));
1183 if (lpszStr
&& *lpszStr
&& lpszMatch
)
1187 if (StrChrIW(lpszMatch
, *lpszRead
)) break;
1191 return lpszRead
- lpszStr
;
1194 /*************************************************************************
1195 * StrPBrkA [SHLWAPI.@]
1197 * Search a string for any of a group of characters.
1200 * lpszStr [I] String to search
1201 * lpszMatch [I] Characters to match
1204 * A pointer to the first matching character in lpszStr, or NULL if no
1207 LPSTR WINAPI
StrPBrkA(LPCSTR lpszStr
, LPCSTR lpszMatch
)
1209 TRACE("(%s,%s)\n",debugstr_a(lpszStr
), debugstr_a(lpszMatch
));
1211 if (lpszStr
&& lpszMatch
&& *lpszMatch
)
1215 if (StrChrA(lpszMatch
, *lpszStr
))
1216 return (LPSTR
)lpszStr
;
1217 lpszStr
= CharNextA(lpszStr
);
1223 /*************************************************************************
1224 * StrPBrkW [SHLWAPI.@]
1228 LPWSTR WINAPI
StrPBrkW(LPCWSTR lpszStr
, LPCWSTR lpszMatch
)
1230 if (!lpszStr
|| !lpszMatch
) return NULL
;
1231 return strpbrkW( lpszStr
, lpszMatch
);
1234 /*************************************************************************
1235 * SHLWAPI_StrRChrHelperA
1237 * Internal implementation of StrRChrA/StrRChrIA.
1239 static LPSTR
SHLWAPI_StrRChrHelperA(LPCSTR lpszStr
,
1240 LPCSTR lpszEnd
, WORD ch
,
1241 BOOL (WINAPI
*pChrCmpFn
)(WORD
,WORD
))
1243 LPCSTR lpszRet
= NULL
;
1250 lpszEnd
= lpszStr
+ lstrlenA(lpszStr
);
1252 while (*lpszStr
&& lpszStr
<= lpszEnd
)
1254 ch2
= IsDBCSLeadByte(*lpszStr
)? *lpszStr
<< 8 | lpszStr
[1] : *lpszStr
;
1256 if (!pChrCmpFn(ch
, ch2
))
1258 lpszStr
= CharNextA(lpszStr
);
1261 return (LPSTR
)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 str
, LPCWSTR end
, WORD ch
)
1295 if (!str
) return NULL
;
1296 if (!end
) end
= str
+ strlenW(str
);
1299 if (*str
== ch
) ret
= (WCHAR
*)str
;
1305 /**************************************************************************
1306 * StrRChrIA [SHLWAPI.@]
1308 * Find the last occurrence of a character in string, ignoring case.
1311 * lpszStr [I] String to search in
1312 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1313 * ch [I] Character to search for.
1316 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1317 * or NULL if not found.
1318 * Failure: NULL, if any arguments are invalid.
1320 LPSTR WINAPI
StrRChrIA(LPCSTR lpszStr
, LPCSTR lpszEnd
, WORD ch
)
1322 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr
), debugstr_a(lpszEnd
), ch
);
1324 return SHLWAPI_StrRChrHelperA(lpszStr
, lpszEnd
, ch
, ChrCmpIA
);
1327 /**************************************************************************
1328 * StrRChrIW [SHLWAPI.@]
1332 LPWSTR WINAPI
StrRChrIW(LPCWSTR str
, LPCWSTR end
, WORD ch
)
1336 if (!str
) return NULL
;
1337 if (!end
) end
= str
+ strlenW(str
);
1340 if (!ChrCmpIW(*str
, ch
)) ret
= (WCHAR
*)str
;
1346 /*************************************************************************
1347 * StrCatBuffA [SHLWAPI.@]
1349 * Concatenate two strings together.
1352 * lpszStr [O] String to concatenate to
1353 * lpszCat [I] String to add to lpszCat
1354 * cchMax [I] Maximum number of characters for the whole string
1360 * cchMax determines the number of characters in the final length of the
1361 * string, not the number appended to lpszStr from lpszCat.
1363 LPSTR WINAPI
StrCatBuffA(LPSTR lpszStr
, LPCSTR lpszCat
, INT cchMax
)
1367 TRACE("(%p,%s,%d)\n", lpszStr
, debugstr_a(lpszCat
), cchMax
);
1371 WARN("Invalid lpszStr would crash under Win32!\n");
1375 iLen
= strlen(lpszStr
);
1379 StrCpyNA(lpszStr
+ iLen
, lpszCat
, cchMax
);
1383 /*************************************************************************
1384 * StrCatBuffW [SHLWAPI.@]
1388 LPWSTR WINAPI
StrCatBuffW(LPWSTR lpszStr
, LPCWSTR lpszCat
, INT cchMax
)
1392 TRACE("(%p,%s,%d)\n", lpszStr
, debugstr_w(lpszCat
), cchMax
);
1396 WARN("Invalid lpszStr would crash under Win32!\n");
1400 iLen
= strlenW(lpszStr
);
1404 StrCpyNW(lpszStr
+ iLen
, lpszCat
, cchMax
);
1408 /*************************************************************************
1409 * StrRetToBufA [SHLWAPI.@]
1411 * Convert a STRRET to a normal string.
1414 * lpStrRet [O] STRRET to convert
1415 * pIdl [I] ITEMIDLIST for lpStrRet->uType == STRRET_OFFSET
1416 * lpszDest [O] Destination for normal string
1417 * dwLen [I] Length of lpszDest
1420 * Success: S_OK. lpszDest contains up to dwLen characters of the string.
1421 * If lpStrRet is of type STRRET_WSTR, its memory is freed with
1422 * CoTaskMemFree() and its type set to STRRET_CSTRA.
1423 * Failure: E_FAIL, if any parameters are invalid.
1425 HRESULT WINAPI
StrRetToBufA (LPSTRRET src
, const ITEMIDLIST
*pidl
, LPSTR dest
, UINT len
)
1428 * This routine is identical to that in dlls/shell32/shellstring.c.
1429 * It was duplicated because not every version of Shlwapi.dll exports
1430 * StrRetToBufA. If you change one routine, change them both.
1432 TRACE("dest=%p len=0x%x strret=%p pidl=%p\n", dest
, len
, src
, pidl
);
1436 WARN("Invalid lpStrRet would crash under Win32!\n");
1450 WideCharToMultiByte(CP_ACP
, 0, src
->u
.pOleStr
, -1, dest
, len
, NULL
, NULL
);
1451 CoTaskMemFree(src
->u
.pOleStr
);
1455 lstrcpynA(dest
, src
->u
.cStr
, len
);
1459 lstrcpynA((LPSTR
)dest
, ((LPCSTR
)&pidl
->mkid
)+src
->u
.uOffset
, len
);
1463 FIXME("unknown type!\n");
1469 /*************************************************************************
1470 * StrRetToBufW [SHLWAPI.@]
1474 HRESULT WINAPI
StrRetToBufW (LPSTRRET src
, const ITEMIDLIST
*pidl
, LPWSTR dest
, UINT len
)
1476 TRACE("dest=%p len=0x%x strret=%p pidl=%p\n", dest
, len
, src
, pidl
);
1480 WARN("Invalid lpStrRet would crash under Win32!\n");
1494 lstrcpynW(dest
, src
->u
.pOleStr
, len
);
1495 CoTaskMemFree(src
->u
.pOleStr
);
1499 if (!MultiByteToWideChar( CP_ACP
, 0, src
->u
.cStr
, -1, dest
, len
))
1506 if (!MultiByteToWideChar( CP_ACP
, 0, ((LPCSTR
)&pidl
->mkid
)+src
->u
.uOffset
, -1,
1513 FIXME("unknown type!\n");
1519 /*************************************************************************
1520 * StrRetToStrA [SHLWAPI.@]
1522 * Converts a STRRET to a normal string.
1525 * lpStrRet [O] STRRET to convert
1526 * pidl [I] ITEMIDLIST for lpStrRet->uType == STRRET_OFFSET
1527 * ppszName [O] Destination for converted string
1530 * Success: S_OK. ppszName contains the new string, allocated with CoTaskMemAlloc().
1531 * Failure: E_FAIL, if any parameters are invalid.
1533 HRESULT WINAPI
StrRetToStrA(LPSTRRET lpStrRet
, const ITEMIDLIST
*pidl
, LPSTR
*ppszName
)
1535 HRESULT hRet
= E_FAIL
;
1537 switch (lpStrRet
->uType
)
1540 hRet
= _SHStrDupAW(lpStrRet
->u
.pOleStr
, ppszName
);
1541 CoTaskMemFree(lpStrRet
->u
.pOleStr
);
1545 hRet
= _SHStrDupAA(lpStrRet
->u
.cStr
, ppszName
);
1549 hRet
= _SHStrDupAA(((LPCSTR
)&pidl
->mkid
) + lpStrRet
->u
.uOffset
, ppszName
);
1559 /*************************************************************************
1560 * StrRetToStrW [SHLWAPI.@]
1564 HRESULT WINAPI
StrRetToStrW(LPSTRRET lpStrRet
, const ITEMIDLIST
*pidl
, LPWSTR
*ppszName
)
1566 HRESULT hRet
= E_FAIL
;
1568 switch (lpStrRet
->uType
)
1571 hRet
= SHStrDupW(lpStrRet
->u
.pOleStr
, ppszName
);
1572 CoTaskMemFree(lpStrRet
->u
.pOleStr
);
1576 hRet
= SHStrDupA(lpStrRet
->u
.cStr
, ppszName
);
1580 hRet
= SHStrDupA(((LPCSTR
)&pidl
->mkid
) + lpStrRet
->u
.uOffset
, ppszName
);
1590 /* Create an ASCII string copy using SysAllocString() */
1591 static HRESULT
_SHStrDupAToBSTR(LPCSTR src
, BSTR
*pBstrOut
)
1597 INT len
= MultiByteToWideChar(CP_ACP
, 0, src
, -1, NULL
, 0);
1598 WCHAR
* szTemp
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1602 MultiByteToWideChar(CP_ACP
, 0, src
, -1, szTemp
, len
);
1603 *pBstrOut
= SysAllocString(szTemp
);
1604 HeapFree(GetProcessHeap(), 0, szTemp
);
1610 return E_OUTOFMEMORY
;
1613 /*************************************************************************
1614 * StrRetToBSTR [SHLWAPI.@]
1616 * Converts a STRRET to a BSTR.
1619 * lpStrRet [O] STRRET to convert
1620 * pidl [I] ITEMIDLIST for lpStrRet->uType = STRRET_OFFSET
1621 * pBstrOut [O] Destination for converted BSTR
1624 * Success: S_OK. pBstrOut contains the new string.
1625 * Failure: E_FAIL, if any parameters are invalid.
1627 HRESULT WINAPI
StrRetToBSTR(STRRET
*lpStrRet
, LPCITEMIDLIST pidl
, BSTR
* pBstrOut
)
1629 HRESULT hRet
= E_FAIL
;
1631 switch (lpStrRet
->uType
)
1634 *pBstrOut
= SysAllocString(lpStrRet
->u
.pOleStr
);
1637 CoTaskMemFree(lpStrRet
->u
.pOleStr
);
1641 hRet
= _SHStrDupAToBSTR(lpStrRet
->u
.cStr
, pBstrOut
);
1645 hRet
= _SHStrDupAToBSTR(((LPCSTR
)&pidl
->mkid
) + lpStrRet
->u
.uOffset
, pBstrOut
);
1655 /*************************************************************************
1656 * StrFormatKBSizeA [SHLWAPI.@]
1658 * Create a formatted string containing a byte count in Kilobytes.
1661 * llBytes [I] Byte size to format
1662 * lpszDest [I] Destination for formatted string
1663 * cchMax [I] Size of lpszDest
1668 LPSTR WINAPI
StrFormatKBSizeA(LONGLONG llBytes
, LPSTR lpszDest
, UINT cchMax
)
1672 if (!StrFormatKBSizeW(llBytes
, wszBuf
, 256))
1674 if (!WideCharToMultiByte(CP_ACP
, 0, wszBuf
, -1, lpszDest
, cchMax
, NULL
, NULL
))
1679 /*************************************************************************
1680 * StrFormatKBSizeW [SHLWAPI.@]
1682 * See StrFormatKBSizeA.
1684 LPWSTR WINAPI
StrFormatKBSizeW(LONGLONG llBytes
, LPWSTR lpszDest
, UINT cchMax
)
1686 static const WCHAR kb
[] = {' ','K','B',0};
1687 LONGLONG llKB
= (llBytes
+ 1023) >> 10;
1690 TRACE("(0x%s,%p,%d)\n", wine_dbgstr_longlong(llBytes
), lpszDest
, cchMax
);
1692 if (!FormatInt(llKB
, lpszDest
, cchMax
))
1695 len
= lstrlenW(lpszDest
);
1696 if (cchMax
- len
< 4)
1698 lstrcatW(lpszDest
, kb
);
1702 /*************************************************************************
1703 * StrNCatA [SHLWAPI.@]
1705 * Concatenate two strings together.
1708 * lpszStr [O] String to concatenate to
1709 * lpszCat [I] String to add to lpszCat
1710 * cchMax [I] Maximum number of characters to concatenate
1716 * cchMax determines the number of characters that are appended to lpszStr,
1717 * not the total length of the string.
1719 LPSTR WINAPI
StrNCatA(LPSTR lpszStr
, LPCSTR lpszCat
, INT cchMax
)
1721 LPSTR lpszRet
= lpszStr
;
1723 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr
), debugstr_a(lpszCat
), cchMax
);
1727 WARN("Invalid lpszStr would crash under Win32!\n");
1731 StrCpyNA(lpszStr
+ strlen(lpszStr
), lpszCat
, cchMax
);
1735 /*************************************************************************
1736 * StrNCatW [SHLWAPI.@]
1740 LPWSTR WINAPI
StrNCatW(LPWSTR lpszStr
, LPCWSTR lpszCat
, INT cchMax
)
1742 LPWSTR lpszRet
= lpszStr
;
1744 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr
), debugstr_w(lpszCat
), cchMax
);
1748 WARN("Invalid lpszStr would crash under Win32\n");
1752 StrCpyNW(lpszStr
+ strlenW(lpszStr
), lpszCat
, cchMax
);
1756 /*************************************************************************
1757 * StrTrimA [SHLWAPI.@]
1759 * Remove characters from the start and end of a string.
1762 * lpszStr [O] String to remove characters from
1763 * lpszTrim [I] Characters to remove from lpszStr
1766 * TRUE If lpszStr was valid and modified
1769 BOOL WINAPI
StrTrimA(LPSTR lpszStr
, LPCSTR lpszTrim
)
1772 LPSTR lpszRead
= lpszStr
;
1775 TRACE("(%s,%s)\n", debugstr_a(lpszStr
), debugstr_a(lpszTrim
));
1777 if (lpszRead
&& *lpszRead
)
1779 while (*lpszRead
&& StrChrA(lpszTrim
, *lpszRead
))
1780 lpszRead
= CharNextA(lpszRead
); /* Skip leading matches */
1782 dwLen
= strlen(lpszRead
);
1784 if (lpszRead
!= lpszStr
)
1786 memmove(lpszStr
, lpszRead
, dwLen
+ 1);
1791 lpszRead
= lpszStr
+ dwLen
;
1792 while (StrChrA(lpszTrim
, lpszRead
[-1]))
1793 lpszRead
= CharPrevA(lpszStr
, lpszRead
); /* Skip trailing matches */
1795 if (lpszRead
!= lpszStr
+ dwLen
)
1805 /*************************************************************************
1806 * StrTrimW [SHLWAPI.@]
1810 BOOL WINAPI
StrTrimW(LPWSTR lpszStr
, LPCWSTR lpszTrim
)
1813 LPWSTR lpszRead
= lpszStr
;
1816 TRACE("(%s,%s)\n", debugstr_w(lpszStr
), debugstr_w(lpszTrim
));
1818 if (lpszRead
&& *lpszRead
)
1820 while (*lpszRead
&& StrChrW(lpszTrim
, *lpszRead
)) lpszRead
++;
1822 dwLen
= strlenW(lpszRead
);
1824 if (lpszRead
!= lpszStr
)
1826 memmove(lpszStr
, lpszRead
, (dwLen
+ 1) * sizeof(WCHAR
));
1831 lpszRead
= lpszStr
+ dwLen
;
1832 while (StrChrW(lpszTrim
, lpszRead
[-1]))
1833 lpszRead
--; /* Skip trailing matches */
1835 if (lpszRead
!= lpszStr
+ dwLen
)
1845 /*************************************************************************
1846 * _SHStrDupAA [INTERNAL]
1848 * Duplicates a ASCII string to ASCII. The destination buffer is allocated.
1850 static HRESULT
_SHStrDupAA(LPCSTR src
, LPSTR
* dest
)
1856 len
= lstrlenA(src
) + 1;
1857 *dest
= CoTaskMemAlloc(len
);
1863 lstrcpynA(*dest
,src
, len
);
1869 TRACE("%s->(%p)\n", debugstr_a(src
), *dest
);
1873 /*************************************************************************
1874 * SHStrDupA [SHLWAPI.@]
1876 * Return a Unicode copy of a string, in memory allocated by CoTaskMemAlloc().
1879 * lpszStr [I] String to copy
1880 * lppszDest [O] Destination for the new string copy
1883 * Success: S_OK. lppszDest contains the new string in Unicode format.
1884 * Failure: E_OUTOFMEMORY, If any arguments are invalid or memory allocation
1887 HRESULT WINAPI
SHStrDupA(LPCSTR lpszStr
, LPWSTR
* lppszDest
)
1894 len
= MultiByteToWideChar(CP_ACP
, 0, lpszStr
, -1, NULL
, 0) * sizeof(WCHAR
);
1895 *lppszDest
= CoTaskMemAlloc(len
);
1902 MultiByteToWideChar(CP_ACP
, 0, lpszStr
, -1, *lppszDest
, len
/sizeof(WCHAR
));
1906 hRet
= E_OUTOFMEMORY
;
1908 TRACE("%s->(%p)\n", debugstr_a(lpszStr
), *lppszDest
);
1912 /*************************************************************************
1913 * _SHStrDupAW [INTERNAL]
1915 * Duplicates a UNICODE to a ASCII string. The destination buffer is allocated.
1917 static HRESULT
_SHStrDupAW(LPCWSTR src
, LPSTR
* dest
)
1923 len
= WideCharToMultiByte(CP_ACP
, 0, src
, -1, NULL
, 0, NULL
, NULL
);
1924 *dest
= CoTaskMemAlloc(len
);
1930 WideCharToMultiByte(CP_ACP
, 0, src
, -1, *dest
, len
, NULL
, NULL
);
1936 TRACE("%s->(%p)\n", debugstr_w(src
), *dest
);
1940 /*************************************************************************
1941 * SHStrDupW [SHLWAPI.@]
1945 HRESULT WINAPI
SHStrDupW(LPCWSTR src
, LPWSTR
* dest
)
1951 len
= (lstrlenW(src
) + 1) * sizeof(WCHAR
);
1952 *dest
= CoTaskMemAlloc(len
);
1958 memcpy(*dest
, src
, len
);
1964 TRACE("%s->(%p)\n", debugstr_w(src
), *dest
);
1968 /*************************************************************************
1969 * SHLWAPI_WriteReverseNum
1971 * Internal helper for SHLWAPI_WriteTimeClass.
1973 static inline LPWSTR
SHLWAPI_WriteReverseNum(LPWSTR lpszOut
, DWORD dwNum
)
1977 /* Write a decimal number to a string, backwards */
1980 DWORD dwNextDigit
= dwNum
% 10;
1981 *lpszOut
-- = '0' + dwNextDigit
;
1982 dwNum
= (dwNum
- dwNextDigit
) / 10;
1983 } while (dwNum
> 0);
1988 /*************************************************************************
1989 * SHLWAPI_FormatSignificant
1991 * Internal helper for SHLWAPI_WriteTimeClass.
1993 static inline int SHLWAPI_FormatSignificant(LPWSTR lpszNum
, int dwDigits
)
1995 /* Zero non significant digits, return remaining significant digits */
1999 if (--dwDigits
== 0)
2009 /*************************************************************************
2010 * SHLWAPI_WriteTimeClass
2012 * Internal helper for StrFromTimeIntervalW.
2014 static int SHLWAPI_WriteTimeClass(LPWSTR lpszOut
, DWORD dwValue
,
2015 UINT uClassStringId
, int iDigits
)
2017 WCHAR szBuff
[64], *szOut
= szBuff
+ 32;
2019 szOut
= SHLWAPI_WriteReverseNum(szOut
, dwValue
);
2020 iDigits
= SHLWAPI_FormatSignificant(szOut
+ 1, iDigits
);
2022 LoadStringW(shlwapi_hInstance
, uClassStringId
, szBuff
+ 32, 32);
2023 strcatW(lpszOut
, szOut
);
2027 /*************************************************************************
2028 * StrFromTimeIntervalA [SHLWAPI.@]
2030 * Format a millisecond time interval into a string
2033 * lpszStr [O] Output buffer for formatted time interval
2034 * cchMax [I] Size of lpszStr
2035 * dwMS [I] Number of milliseconds
2036 * iDigits [I] Number of digits to print
2039 * The length of the formatted string, or 0 if any parameter is invalid.
2042 * This implementation mimics the Win32 behaviour of always writing a leading
2043 * space before the time interval begins.
2045 * iDigits is used to provide approximate times if accuracy is not important.
2046 * This number of digits will be written of the first non-zero time class
2047 * (hours/minutes/seconds). If this does not complete the time classification,
2048 * the remaining digits are changed to zeros (i.e. The time is _not_ rounded).
2049 * If there are digits remaining following the writing of a time class, the
2050 * next time class will be written.
2052 * For example, given dwMS represents 138 hours,43 minutes and 15 seconds, the
2053 * following will result from the given values of iDigits:
2055 *| iDigits 1 2 3 4 5 ...
2056 *| lpszStr "100 hr" "130 hr" "138 hr" "138 hr 40 min" "138 hr 43 min" ...
2058 INT WINAPI
StrFromTimeIntervalA(LPSTR lpszStr
, UINT cchMax
, DWORD dwMS
,
2063 TRACE("(%p,%d,%d,%d)\n", lpszStr
, cchMax
, dwMS
, iDigits
);
2065 if (lpszStr
&& cchMax
)
2068 StrFromTimeIntervalW(szBuff
, sizeof(szBuff
)/sizeof(WCHAR
), dwMS
, iDigits
);
2069 WideCharToMultiByte(CP_ACP
,0,szBuff
,-1,lpszStr
,cchMax
,0,0);
2075 /*************************************************************************
2076 * StrFromTimeIntervalW [SHLWAPI.@]
2078 * See StrFromTimeIntervalA.
2080 INT WINAPI
StrFromTimeIntervalW(LPWSTR lpszStr
, UINT cchMax
, DWORD dwMS
,
2085 TRACE("(%p,%d,%d,%d)\n", lpszStr
, cchMax
, dwMS
, iDigits
);
2087 if (lpszStr
&& cchMax
)
2090 DWORD dwHours
, dwMinutes
;
2092 if (!iDigits
|| cchMax
== 1)
2098 /* Calculate the time classes */
2099 dwMS
= (dwMS
+ 500) / 1000;
2100 dwHours
= dwMS
/ 3600;
2101 dwMS
-= dwHours
* 3600;
2102 dwMinutes
= dwMS
/ 60;
2103 dwMS
-= dwMinutes
* 60;
2108 iDigits
= SHLWAPI_WriteTimeClass(szCopy
, dwHours
, IDS_TIME_INTERVAL_HOURS
, iDigits
);
2110 if (dwMinutes
&& iDigits
)
2111 iDigits
= SHLWAPI_WriteTimeClass(szCopy
, dwMinutes
, IDS_TIME_INTERVAL_MINUTES
, iDigits
);
2113 if (iDigits
) /* Always write seconds if we have significant digits */
2114 SHLWAPI_WriteTimeClass(szCopy
, dwMS
, IDS_TIME_INTERVAL_SECONDS
, iDigits
);
2116 lstrcpynW(lpszStr
, szCopy
, cchMax
);
2117 iRet
= strlenW(lpszStr
);
2122 /*************************************************************************
2123 * StrIsIntlEqualA [SHLWAPI.@]
2125 * Compare two strings.
2128 * bCase [I] Whether to compare case sensitively
2129 * lpszStr [I] First string to compare
2130 * lpszComp [I] Second string to compare
2131 * iLen [I] Length to compare
2134 * TRUE If the strings are equal.
2137 BOOL WINAPI
StrIsIntlEqualA(BOOL bCase
, LPCSTR lpszStr
, LPCSTR lpszComp
,
2142 TRACE("(%d,%s,%s,%d)\n", bCase
,
2143 debugstr_a(lpszStr
), debugstr_a(lpszComp
), iLen
);
2145 /* FIXME: This flag is undocumented and unknown by our CompareString.
2146 * We need a define for it.
2148 dwFlags
= 0x10000000;
2149 if (!bCase
) dwFlags
|= NORM_IGNORECASE
;
2151 return (CompareStringA(GetThreadLocale(), dwFlags
, lpszStr
, iLen
, lpszComp
, iLen
) == CSTR_EQUAL
);
2154 /*************************************************************************
2155 * StrIsIntlEqualW [SHLWAPI.@]
2157 * See StrIsIntlEqualA.
2159 BOOL WINAPI
StrIsIntlEqualW(BOOL bCase
, LPCWSTR lpszStr
, LPCWSTR lpszComp
,
2164 TRACE("(%d,%s,%s,%d)\n", bCase
,
2165 debugstr_w(lpszStr
),debugstr_w(lpszComp
), iLen
);
2167 /* FIXME: This flag is undocumented and unknown by our CompareString.
2168 * We need a define for it.
2170 dwFlags
= 0x10000000;
2171 if (!bCase
) dwFlags
|= NORM_IGNORECASE
;
2173 return (CompareStringW(GetThreadLocale(), dwFlags
, lpszStr
, iLen
, lpszComp
, iLen
) == CSTR_EQUAL
);
2176 /*************************************************************************
2179 * Copy a string to another string, up to a maximum number of characters.
2182 * lpszDest [O] Destination string
2183 * lpszSrc [I] Source string
2184 * iLen [I] Maximum number of chars to copy
2187 * Success: A pointer to the last character written to lpszDest.
2188 * Failure: lpszDest, if any arguments are invalid.
2190 LPSTR WINAPI
StrCpyNXA(LPSTR lpszDest
, LPCSTR lpszSrc
, int iLen
)
2192 TRACE("(%p,%s,%i)\n", lpszDest
, debugstr_a(lpszSrc
), iLen
);
2194 if (lpszDest
&& lpszSrc
&& iLen
> 0)
2196 while ((iLen
-- > 1) && *lpszSrc
)
2197 *lpszDest
++ = *lpszSrc
++;
2204 /*************************************************************************
2207 * Unicode version of StrCpyNXA.
2209 LPWSTR WINAPI
StrCpyNXW(LPWSTR lpszDest
, LPCWSTR lpszSrc
, int iLen
)
2211 TRACE("(%p,%s,%i)\n", lpszDest
, debugstr_w(lpszSrc
), iLen
);
2213 if (lpszDest
&& lpszSrc
&& iLen
> 0)
2215 while ((iLen
-- > 1) && *lpszSrc
)
2216 *lpszDest
++ = *lpszSrc
++;
2223 /*************************************************************************
2224 * StrCmpLogicalW [SHLWAPI.@]
2226 * Compare two strings, ignoring case and comparing digits as numbers.
2229 * lpszStr [I] First string to compare
2230 * lpszComp [I] Second string to compare
2231 * iLen [I] Length to compare
2234 * TRUE If the strings are equal.
2237 INT WINAPI
StrCmpLogicalW(LPCWSTR lpszStr
, LPCWSTR lpszComp
)
2241 TRACE("(%s,%s)\n", debugstr_w(lpszStr
), debugstr_w(lpszComp
));
2243 if (lpszStr
&& lpszComp
)
2249 else if (isdigitW(*lpszStr
))
2253 if (!isdigitW(*lpszComp
))
2256 /* Compare the numbers */
2257 StrToIntExW(lpszStr
, 0, &iStr
);
2258 StrToIntExW(lpszComp
, 0, &iComp
);
2262 else if (iStr
> iComp
)
2266 while (isdigitW(*lpszStr
))
2268 while (isdigitW(*lpszComp
))
2271 else if (isdigitW(*lpszComp
))
2275 iDiff
= ChrCmpIW(*lpszStr
,*lpszComp
);
2291 /* Structure for formatting byte strings */
2292 typedef struct tagSHLWAPI_BYTEFORMATS
2299 } SHLWAPI_BYTEFORMATS
;
2301 /*************************************************************************
2302 * StrFormatByteSizeW [SHLWAPI.@]
2304 * Create a string containing an abbreviated byte count of up to 2^63-1.
2307 * llBytes [I] Byte size to format
2308 * lpszDest [I] Destination for formatted string
2309 * cchMax [I] Size of lpszDest
2315 * There is no StrFormatByteSize64W function, it is called StrFormatByteSizeW().
2317 LPWSTR WINAPI
StrFormatByteSizeW(LONGLONG llBytes
, LPWSTR lpszDest
, UINT cchMax
)
2319 #define KB ((ULONGLONG)1024)
2321 #define GB (KB*KB*KB)
2322 #define TB (KB*KB*KB*KB)
2323 #define PB (KB*KB*KB*KB*KB)
2325 static const SHLWAPI_BYTEFORMATS bfFormats
[] =
2327 { 10*KB
, 10.24, 100.0, 2, 'K' }, /* 10 KB */
2328 { 100*KB
, 102.4, 10.0, 1, 'K' }, /* 100 KB */
2329 { 1000*KB
, 1024.0, 1.0, 0, 'K' }, /* 1000 KB */
2330 { 10*MB
, 10485.76, 100.0, 2, 'M' }, /* 10 MB */
2331 { 100*MB
, 104857.6, 10.0, 1, 'M' }, /* 100 MB */
2332 { 1000*MB
, 1048576.0, 1.0, 0, 'M' }, /* 1000 MB */
2333 { 10*GB
, 10737418.24, 100.0, 2, 'G' }, /* 10 GB */
2334 { 100*GB
, 107374182.4, 10.0, 1, 'G' }, /* 100 GB */
2335 { 1000*GB
, 1073741824.0, 1.0, 0, 'G' }, /* 1000 GB */
2336 { 10*TB
, 10485.76, 100.0, 2, 'T' }, /* 10 TB */
2337 { 100*TB
, 104857.6, 10.0, 1, 'T' }, /* 100 TB */
2338 { 1000*TB
, 1048576.0, 1.0, 0, 'T' }, /* 1000 TB */
2339 { 10*PB
, 10737418.24, 100.00, 2, 'P' }, /* 10 PB */
2340 { 100*PB
, 107374182.4, 10.00, 1, 'P' }, /* 100 PB */
2341 { 1000*PB
, 1073741824.0, 1.00, 0, 'P' }, /* 1000 PB */
2342 { 0, 10995116277.76, 100.00, 2, 'E' } /* EB's, catch all */
2344 WCHAR wszAdd
[] = {' ','?','B',0};
2348 TRACE("(0x%s,%p,%d)\n", wine_dbgstr_longlong(llBytes
), lpszDest
, cchMax
);
2350 if (!lpszDest
|| !cchMax
)
2353 if (llBytes
< 1024) /* 1K */
2355 WCHAR wszBytesFormat
[64];
2356 LoadStringW(shlwapi_hInstance
, IDS_BYTES_FORMAT
, wszBytesFormat
, 64);
2357 snprintfW(lpszDest
, cchMax
, wszBytesFormat
, (int)llBytes
);
2361 /* Note that if this loop completes without finding a match, i will be
2362 * pointing at the last entry, which is a catch all for > 1000 PB
2364 while (i
< sizeof(bfFormats
) / sizeof(SHLWAPI_BYTEFORMATS
) - 1)
2366 if (llBytes
< bfFormats
[i
].dLimit
)
2370 /* Above 1 TB we encounter problems with FP accuracy. So for amounts above
2371 * this number we integer shift down by 1 MB first. The table above has
2372 * the divisors scaled down from the '< 10 TB' entry onwards, to account
2373 * for this. We also add a small fudge factor to get the correct result for
2374 * counts that lie exactly on a 1024 byte boundary.
2377 dBytes
= (double)(llBytes
>> 20) + 0.001; /* Scale down by 1 MB */
2379 dBytes
= (double)llBytes
+ 0.00001;
2381 dBytes
= floor(dBytes
/ bfFormats
[i
].dDivisor
) / bfFormats
[i
].dNormaliser
;
2383 if (!FormatDouble(dBytes
, bfFormats
[i
].nDecimals
, lpszDest
, cchMax
))
2385 wszAdd
[1] = bfFormats
[i
].wPrefix
;
2386 StrCatBuffW(lpszDest
, wszAdd
, cchMax
);
2390 /*************************************************************************
2391 * StrFormatByteSize64A [SHLWAPI.@]
2393 * See StrFormatByteSizeW.
2395 LPSTR WINAPI
StrFormatByteSize64A(LONGLONG llBytes
, LPSTR lpszDest
, UINT cchMax
)
2399 StrFormatByteSizeW(llBytes
, wszBuff
, sizeof(wszBuff
)/sizeof(WCHAR
));
2402 WideCharToMultiByte(CP_ACP
, 0, wszBuff
, -1, lpszDest
, cchMax
, 0, 0);
2406 /*************************************************************************
2407 * StrFormatByteSizeA [SHLWAPI.@]
2409 * Create a string containing an abbreviated byte count of up to 2^31-1.
2412 * dwBytes [I] Byte size to format
2413 * lpszDest [I] Destination for formatted string
2414 * cchMax [I] Size of lpszDest
2420 * The Ascii and Unicode versions of this function accept a different
2421 * integer type for dwBytes. See StrFormatByteSize64A().
2423 LPSTR WINAPI
StrFormatByteSizeA(DWORD dwBytes
, LPSTR lpszDest
, UINT cchMax
)
2425 TRACE("(%d,%p,%d)\n", dwBytes
, lpszDest
, cchMax
);
2427 return StrFormatByteSize64A(dwBytes
, lpszDest
, cchMax
);
2430 /*************************************************************************
2433 * Remove a hanging lead byte from the end of a string, if present.
2436 * lpStr [I] String to check for a hanging lead byte
2437 * size [I] Length of lpStr
2440 * Success: The new length of the string. Any hanging lead bytes are removed.
2441 * Failure: 0, if any parameters are invalid.
2443 DWORD WINAPI
SHTruncateString(LPSTR lpStr
, DWORD size
)
2447 LPSTR lastByte
= lpStr
+ size
- 1;
2449 while(lpStr
< lastByte
)
2450 lpStr
+= IsDBCSLeadByte(*lpStr
) ? 2 : 1;
2452 if(lpStr
== lastByte
&& IsDBCSLeadByte(*lpStr
))
2462 /*************************************************************************
2465 * Remove a single non-trailing ampersand ('&') from a string.
2468 * lpszStr [I/O] String to remove ampersand from.
2471 * The character after the first ampersand in lpszStr, or the first character
2472 * in lpszStr if there is no ampersand in the string.
2474 char WINAPI
SHStripMneumonicA(LPCSTR lpszStr
)
2476 LPSTR lpszIter
, lpszTmp
;
2479 TRACE("(%s)\n", debugstr_a(lpszStr
));
2483 if ((lpszIter
= StrChrA(lpszStr
, '&')))
2485 lpszTmp
= CharNextA(lpszIter
);
2488 if (*lpszTmp
!= '&')
2491 memmove( lpszIter
, lpszTmp
, strlen(lpszTmp
) + 1 );
2498 /*************************************************************************
2501 * Unicode version of SHStripMneumonicA.
2503 WCHAR WINAPI
SHStripMneumonicW(LPCWSTR lpszStr
)
2505 LPWSTR lpszIter
, lpszTmp
;
2508 TRACE("(%s)\n", debugstr_w(lpszStr
));
2512 if ((lpszIter
= StrChrW(lpszStr
, '&')))
2514 lpszTmp
= lpszIter
+ 1;
2517 if (*lpszTmp
!= '&')
2520 memmove( lpszIter
, lpszTmp
, (strlenW(lpszTmp
) + 1) * sizeof(WCHAR
) );
2527 /*************************************************************************
2530 * Convert an Ascii string to Unicode.
2533 * dwCp [I] Code page for the conversion
2534 * lpSrcStr [I] Source Ascii string to convert
2535 * lpDstStr [O] Destination for converted Unicode string
2536 * iLen [I] Length of lpDstStr
2539 * The return value of the MultiByteToWideChar() function called on lpSrcStr.
2541 DWORD WINAPI
SHAnsiToUnicodeCP(DWORD dwCp
, LPCSTR lpSrcStr
, LPWSTR lpDstStr
, int iLen
)
2545 dwRet
= MultiByteToWideChar(dwCp
, 0, lpSrcStr
, -1, lpDstStr
, iLen
);
2546 TRACE("%s->%s,ret=%d\n", debugstr_a(lpSrcStr
), debugstr_w(lpDstStr
), dwRet
);
2550 /*************************************************************************
2553 * Convert an Ascii string to Unicode.
2556 * lpSrcStr [I] Source Ascii string to convert
2557 * lpDstStr [O] Destination for converted Unicode string
2558 * iLen [I] Length of lpDstStr
2561 * The return value of the MultiByteToWideChar() function called on lpSrcStr.
2564 * This function simply calls SHAnsiToUnicodeCP with code page CP_ACP.
2566 DWORD WINAPI
SHAnsiToUnicode(LPCSTR lpSrcStr
, LPWSTR lpDstStr
, int iLen
)
2568 return SHAnsiToUnicodeCP(CP_ACP
, lpSrcStr
, lpDstStr
, iLen
);
2571 /*************************************************************************
2574 * Convert a Unicode string to Ascii.
2577 * CodePage [I] Code page to use for the conversion
2578 * lpSrcStr [I] Source Unicode string to convert
2579 * lpDstStr [O] Destination for converted Ascii string
2580 * dstlen [I] Length of buffer at lpDstStr
2583 * Success: The length in bytes of the result at lpDstStr (including the terminator)
2584 * Failure: When using CP_UTF8, CP_UTF7 or 0xc350 as codePage, 0 is returned and
2585 * the result is not nul-terminated.
2586 * When using a different codepage, the length in bytes of the truncated
2587 * result at lpDstStr (including the terminator) is returned and
2588 * lpDstStr is always nul-terminated.
2591 DWORD WINAPI
SHUnicodeToAnsiCP(UINT CodePage
, LPCWSTR lpSrcStr
, LPSTR lpDstStr
, int dstlen
)
2593 static const WCHAR emptyW
[] = { '\0' };
2597 if (!lpDstStr
|| !dstlen
)
2605 len
= strlenW(lpSrcStr
) + 1;
2610 CodePage
= CP_UTF8
; /* Fall through... */
2611 case 0x0000C350: /* FIXME: CP_ #define */
2617 INT needed
= dstlen
- 1;
2620 /* try the user supplied buffer first */
2621 hr
= ConvertINetUnicodeToMultiByte(&dwMode
, CodePage
, lpSrcStr
, &lenW
, lpDstStr
, &needed
);
2624 lpDstStr
[needed
] = '\0';
2628 /* user buffer too small. exclude termination and copy as much as possible */
2630 hr
= ConvertINetUnicodeToMultiByte(&dwMode
, CodePage
, lpSrcStr
, &lenW
, NULL
, &needed
);
2632 mem
= HeapAlloc(GetProcessHeap(), 0, needed
);
2636 hr
= ConvertINetUnicodeToMultiByte(&dwMode
, CodePage
, lpSrcStr
, &len
, mem
, &needed
);
2639 reqLen
= SHTruncateString(mem
, dstlen
);
2640 if (reqLen
> 0) memcpy(lpDstStr
, mem
, reqLen
-1);
2642 HeapFree(GetProcessHeap(), 0, mem
);
2649 /* try the user supplied buffer first */
2650 reqLen
= WideCharToMultiByte(CodePage
, 0, lpSrcStr
, len
, lpDstStr
, dstlen
, NULL
, NULL
);
2652 if (!reqLen
&& GetLastError() == ERROR_INSUFFICIENT_BUFFER
)
2654 reqLen
= WideCharToMultiByte(CodePage
, 0, lpSrcStr
, len
, NULL
, 0, NULL
, NULL
);
2657 mem
= HeapAlloc(GetProcessHeap(), 0, reqLen
);
2660 reqLen
= WideCharToMultiByte(CodePage
, 0, lpSrcStr
, len
, mem
,
2661 reqLen
, NULL
, NULL
);
2663 reqLen
= SHTruncateString(mem
, dstlen
-1);
2666 lstrcpynA(lpDstStr
, mem
, reqLen
);
2667 HeapFree(GetProcessHeap(), 0, mem
);
2668 lpDstStr
[reqLen
-1] = '\0';
2675 /*************************************************************************
2678 * Convert a Unicode string to Ascii.
2681 * lpSrcStr [I] Source Unicode string to convert
2682 * lpDstStr [O] Destination for converted Ascii string
2683 * iLen [O] Length of lpDstStr in characters
2686 * See SHUnicodeToAnsiCP
2689 * This function simply calls SHUnicodeToAnsiCP() with CodePage = CP_ACP.
2691 INT WINAPI
SHUnicodeToAnsi(LPCWSTR lpSrcStr
, LPSTR lpDstStr
, INT iLen
)
2693 return SHUnicodeToAnsiCP(CP_ACP
, lpSrcStr
, lpDstStr
, iLen
);
2696 /*************************************************************************
2699 * Copy one string to another.
2702 * lpszSrc [I] Source string to copy
2703 * lpszDst [O] Destination for copy
2704 * iLen [I] Length of lpszDst in characters
2707 * The length of the copied string, including the terminating NUL. lpszDst
2708 * contains iLen characters of lpszSrc.
2710 DWORD WINAPI
SHAnsiToAnsi(LPCSTR lpszSrc
, LPSTR lpszDst
, int iLen
)
2714 TRACE("(%s,%p,0x%08x)\n", debugstr_a(lpszSrc
), lpszDst
, iLen
);
2716 lpszRet
= StrCpyNXA(lpszDst
, lpszSrc
, iLen
);
2717 return lpszRet
- lpszDst
+ 1;
2720 /*************************************************************************
2723 * Unicode version of SSHAnsiToAnsi.
2725 DWORD WINAPI
SHUnicodeToUnicode(LPCWSTR lpszSrc
, LPWSTR lpszDst
, int iLen
)
2729 TRACE("(%s,%p,0x%08x)\n", debugstr_w(lpszSrc
), lpszDst
, iLen
);
2731 lpszRet
= StrCpyNXW(lpszDst
, lpszSrc
, iLen
);
2732 return lpszRet
- lpszDst
+ 1;
2735 /*************************************************************************
2738 * Determine if an Ascii string converts to Unicode and back identically.
2741 * lpSrcStr [I] Source Unicode string to convert
2742 * lpDst [O] Destination for resulting Ascii string
2743 * iLen [I] Length of lpDst in characters
2746 * TRUE, since Ascii strings always convert identically.
2748 BOOL WINAPI
DoesStringRoundTripA(LPCSTR lpSrcStr
, LPSTR lpDst
, INT iLen
)
2750 lstrcpynA(lpDst
, lpSrcStr
, iLen
);
2754 /*************************************************************************
2757 * Determine if a Unicode string converts to Ascii and back identically.
2760 * lpSrcStr [I] Source Unicode string to convert
2761 * lpDst [O] Destination for resulting Ascii string
2762 * iLen [I] Length of lpDst in characters
2765 * TRUE, if lpSrcStr converts to Ascii and back identically,
2768 BOOL WINAPI
DoesStringRoundTripW(LPCWSTR lpSrcStr
, LPSTR lpDst
, INT iLen
)
2770 WCHAR szBuff
[MAX_PATH
];
2772 SHUnicodeToAnsi(lpSrcStr
, lpDst
, iLen
);
2773 SHAnsiToUnicode(lpDst
, szBuff
, MAX_PATH
);
2774 return !strcmpW(lpSrcStr
, szBuff
);
2777 /*************************************************************************
2778 * SHLoadIndirectString [SHLWAPI.@]
2780 * If passed a string that begins with '@', extract the string from the
2781 * appropriate resource, otherwise do a straight copy.
2784 HRESULT WINAPI
SHLoadIndirectString(LPCWSTR src
, LPWSTR dst
, UINT dst_len
, void **reserved
)
2786 WCHAR
*dllname
= NULL
;
2787 HMODULE hmod
= NULL
;
2788 HRESULT hr
= E_FAIL
;
2790 TRACE("(%s %p %08x %p)\n", debugstr_w(src
), dst
, dst_len
, reserved
);
2798 dllname
= StrDupW(src
+ 1);
2799 index_str
= strchrW(dllname
, ',');
2801 if(!index_str
) goto end
;
2805 index
= atoiW(index_str
);
2807 hmod
= LoadLibraryW(dllname
);
2812 if(LoadStringW(hmod
, -index
, dst
, dst_len
))
2816 FIXME("can't handle non-negative indices (%d)\n", index
);
2821 lstrcpynW(dst
, src
, dst_len
);
2825 TRACE("returning %s\n", debugstr_w(dst
));
2827 if(hmod
) FreeLibrary(hmod
);
2828 HeapFree(GetProcessHeap(), 0, dllname
);
2832 BOOL WINAPI
IsCharSpaceA(CHAR c
)
2835 return GetStringTypeA(GetSystemDefaultLCID(), CT_CTYPE1
, &c
, 1, &CharType
) && (CharType
& C1_SPACE
);
2838 /*************************************************************************
2841 * Determine if a Unicode character is a space.
2844 * wc [I] Character to check.
2847 * TRUE, if wc is a space,
2850 BOOL WINAPI
IsCharSpaceW(WCHAR wc
)
2854 return GetStringTypeW(CT_CTYPE1
, &wc
, 1, &CharType
) && (CharType
& C1_SPACE
);