2 * Shlwapi string functions
4 * Copyright 1998 Juergen Schmied
5 * Copyright 2002 Jon Griffiths
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include "wine/port.h"
30 #define NONAMELESSUNION
31 #define NONAMELESSSTRUCT
34 #define NO_SHLWAPI_REG
35 #define NO_SHLWAPI_STREAM
42 #include "wine/unicode.h"
43 #include "wine/debug.h"
47 WINE_DEFAULT_DEBUG_CHANNEL(shell
);
49 extern HINSTANCE shlwapi_hInstance
;
51 static HRESULT
_SHStrDupAA(LPCSTR
,LPSTR
*);
52 static HRESULT
_SHStrDupAW(LPCWSTR
,LPSTR
*);
55 static void FillNumberFmt(NUMBERFMTW
*fmt
, LPWSTR decimal_buffer
, int decimal_bufwlen
,
56 LPWSTR thousand_buffer
, int thousand_bufwlen
)
61 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_ILZERO
|LOCALE_RETURN_NUMBER
, (LPWSTR
)&fmt
->LeadingZero
, sizeof(fmt
->LeadingZero
)/sizeof(WCHAR
));
62 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_INEGNUMBER
|LOCALE_RETURN_NUMBER
, (LPWSTR
)&fmt
->LeadingZero
, sizeof(fmt
->NegativeOrder
)/sizeof(WCHAR
));
64 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_SDECIMAL
, decimal_buffer
, decimal_bufwlen
);
65 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_STHOUSAND
, thousand_buffer
, thousand_bufwlen
);
66 fmt
->lpThousandSep
= thousand_buffer
;
67 fmt
->lpDecimalSep
= decimal_buffer
;
70 * Converting grouping string to number as described on
71 * http://blogs.msdn.com/oldnewthing/archive/2006/04/18/578251.aspx
74 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_SGROUPING
, grouping
, sizeof(grouping
)/sizeof(WCHAR
));
75 for (c
= grouping
; *c
; c
++)
76 if (*c
>= '0' && *c
< '9')
79 fmt
->Grouping
+= *c
- '0';
82 if (fmt
->Grouping
% 10 == 0)
88 /*************************************************************************
89 * FormatInt [internal]
91 * Format an integer according to the current locale
94 * The number of bytes written on success or 0 on failure
96 static int FormatInt(LONGLONG qdwValue
, LPWSTR pszBuf
, int cchBuf
)
99 WCHAR decimal
[8], thousand
[8];
102 BOOL neg
= (qdwValue
< 0);
104 FillNumberFmt(&fmt
, decimal
, sizeof decimal
/ sizeof (WCHAR
),
105 thousand
, sizeof thousand
/ sizeof (WCHAR
));
111 *(--c
) = '0' + (qdwValue
%10);
113 } while (qdwValue
> 0);
117 return GetNumberFormatW(LOCALE_USER_DEFAULT
, 0, c
, &fmt
, pszBuf
, cchBuf
);
120 /*************************************************************************
121 * FormatDouble [internal]
123 * Format an integer according to the current locale. Prints the specified number of digits
124 * after the decimal point
127 * The number of bytes written on success or 0 on failure
129 static int FormatDouble(double value
, int decimals
, LPWSTR pszBuf
, int cchBuf
)
131 static const WCHAR flfmt
[] = {'%','f',0};
134 WCHAR decimal
[8], thousand
[8];
136 snprintfW(buf
, 64, flfmt
, value
);
138 FillNumberFmt(&fmt
, decimal
, sizeof decimal
/ sizeof (WCHAR
),
139 thousand
, sizeof thousand
/ sizeof (WCHAR
));
140 fmt
.NumDigits
= decimals
;
141 return GetNumberFormatW(LOCALE_USER_DEFAULT
, 0, buf
, &fmt
, pszBuf
, cchBuf
);
144 /*************************************************************************
145 * SHLWAPI_ChrCmpHelperA
147 * Internal helper for SHLWAPI_ChrCmpA/ChrCMPIA.
150 * Both this function and its Unicode counterpart are very inefficient. To
151 * fix this, CompareString must be completely implemented and optimised
152 * first. Then the core character test can be taken out of that function and
153 * placed here, so that it need never be called at all. Until then, do not
154 * attempt to optimise this code unless you are willing to test that it
155 * still performs correctly.
157 static BOOL
SHLWAPI_ChrCmpHelperA(WORD ch1
, WORD ch2
, DWORD dwFlags
)
159 char str1
[3], str2
[3];
161 str1
[0] = LOBYTE(ch1
);
162 if (IsDBCSLeadByte(str1
[0]))
164 str1
[1] = HIBYTE(ch1
);
170 str2
[0] = LOBYTE(ch2
);
171 if (IsDBCSLeadByte(str2
[0]))
173 str2
[1] = HIBYTE(ch2
);
179 return CompareStringA(GetThreadLocale(), dwFlags
, str1
, -1, str2
, -1) - 2;
182 /*************************************************************************
185 * Internal helper function.
187 static BOOL WINAPI
SHLWAPI_ChrCmpA(WORD ch1
, WORD ch2
)
189 return SHLWAPI_ChrCmpHelperA(ch1
, ch2
, 0);
192 /*************************************************************************
193 * ChrCmpIA (SHLWAPI.385)
195 * Compare two characters, ignoring case.
198 * ch1 [I] First character to compare
199 * ch2 [I] Second character to compare
202 * FALSE, if the characters are equal.
203 * Non-zero otherwise.
205 BOOL WINAPI
ChrCmpIA(WORD ch1
, WORD ch2
)
207 TRACE("(%d,%d)\n", ch1
, ch2
);
209 return SHLWAPI_ChrCmpHelperA(ch1
, ch2
, NORM_IGNORECASE
);
212 /*************************************************************************
213 * ChrCmpIW [SHLWAPI.386]
217 BOOL WINAPI
ChrCmpIW(WCHAR ch1
, WCHAR ch2
)
219 return CompareStringW(GetThreadLocale(), NORM_IGNORECASE
, &ch1
, 1, &ch2
, 1) - 2;
222 /*************************************************************************
223 * StrChrA [SHLWAPI.@]
225 * Find a given character in a string.
228 * lpszStr [I] String to search in.
229 * ch [I] Character to search for.
232 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
234 * Failure: NULL, if any arguments are invalid.
236 LPSTR WINAPI
StrChrA(LPCSTR lpszStr
, WORD ch
)
238 TRACE("(%s,%i)\n", debugstr_a(lpszStr
), ch
);
244 if (!SHLWAPI_ChrCmpA(*lpszStr
, ch
))
245 return (LPSTR
)lpszStr
;
246 lpszStr
= CharNextA(lpszStr
);
252 /*************************************************************************
253 * StrChrW [SHLWAPI.@]
257 LPWSTR WINAPI
StrChrW(LPCWSTR lpszStr
, WCHAR ch
)
259 LPWSTR lpszRet
= NULL
;
261 TRACE("(%s,%i)\n", debugstr_w(lpszStr
), ch
);
264 lpszRet
= strchrW(lpszStr
, ch
);
268 /*************************************************************************
269 * StrChrIA [SHLWAPI.@]
271 * Find a given character in a string, ignoring case.
274 * lpszStr [I] String to search in.
275 * ch [I] Character to search for.
278 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
280 * Failure: NULL, if any arguments are invalid.
282 LPSTR WINAPI
StrChrIA(LPCSTR lpszStr
, WORD ch
)
284 TRACE("(%s,%i)\n", debugstr_a(lpszStr
), ch
);
290 if (!ChrCmpIA(*lpszStr
, ch
))
291 return (LPSTR
)lpszStr
;
292 lpszStr
= CharNextA(lpszStr
);
298 /*************************************************************************
299 * StrChrIW [SHLWAPI.@]
303 LPWSTR WINAPI
StrChrIW(LPCWSTR lpszStr
, WCHAR ch
)
305 TRACE("(%s,%i)\n", debugstr_w(lpszStr
), ch
);
312 if (toupperW(*lpszStr
) == ch
)
313 return (LPWSTR
)lpszStr
;
318 return (LPWSTR
)lpszStr
;
321 /*************************************************************************
322 * StrChrNW [SHLWAPI.@]
324 LPWSTR WINAPI
StrChrNW(LPCWSTR lpszStr
, WCHAR ch
, UINT cchMax
)
326 TRACE("(%s(%i),%i)\n", debugstr_wn(lpszStr
,cchMax
), cchMax
, ch
);
330 while (*lpszStr
&& cchMax
-- > 0)
333 return (LPWSTR
)lpszStr
;
340 /*************************************************************************
341 * StrCmpIW [SHLWAPI.@]
343 * Compare two strings, ignoring case.
346 * lpszStr [I] First string to compare
347 * lpszComp [I] Second string to compare
350 * An integer less than, equal to or greater than 0, indicating that
351 * lpszStr is less than, the same, or greater than lpszComp.
353 int WINAPI
StrCmpIW(LPCWSTR lpszStr
, LPCWSTR lpszComp
)
357 TRACE("(%s,%s)\n", debugstr_w(lpszStr
),debugstr_w(lpszComp
));
359 iRet
= CompareStringW(GetThreadLocale(), NORM_IGNORECASE
, lpszStr
, -1, lpszComp
, -1);
360 return iRet
== CSTR_LESS_THAN
? -1 : iRet
== CSTR_GREATER_THAN
? 1 : 0;
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
)
381 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr
), debugstr_a(lpszComp
), iLen
);
383 iRet
= CompareStringA(GetThreadLocale(), 0, lpszStr
, iLen
, lpszComp
, iLen
);
384 return iRet
== CSTR_LESS_THAN
? -1 : iRet
== CSTR_GREATER_THAN
? 1 : 0;
387 /*************************************************************************
388 * StrCmpNW [SHLWAPI.@]
392 INT WINAPI
StrCmpNW(LPCWSTR lpszStr
, LPCWSTR lpszComp
, INT iLen
)
396 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr
), debugstr_w(lpszComp
), iLen
);
398 iRet
= CompareStringW(GetThreadLocale(), 0, lpszStr
, iLen
, lpszComp
, iLen
);
399 return iRet
== CSTR_LESS_THAN
? -1 : iRet
== CSTR_GREATER_THAN
? 1 : 0;
402 /*************************************************************************
403 * StrCmpNIA [SHLWAPI.@]
405 * Compare two strings, up to a maximum length, ignoring case.
408 * lpszStr [I] First string to compare
409 * lpszComp [I] Second string to compare
410 * iLen [I] Maximum number of chars to compare.
413 * An integer less than, equal to or greater than 0, indicating that
414 * lpszStr is less than, the same, or greater than lpszComp.
416 int WINAPI
StrCmpNIA(LPCSTR lpszStr
, LPCSTR lpszComp
, int iLen
)
420 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr
), debugstr_a(lpszComp
), iLen
);
422 iRet
= CompareStringA(GetThreadLocale(), NORM_IGNORECASE
, lpszStr
, iLen
, lpszComp
, iLen
);
423 return iRet
== CSTR_LESS_THAN
? -1 : iRet
== CSTR_GREATER_THAN
? 1 : 0;
426 /*************************************************************************
427 * StrCmpNIW [SHLWAPI.@]
431 INT WINAPI
StrCmpNIW(LPCWSTR lpszStr
, LPCWSTR lpszComp
, int iLen
)
435 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr
), debugstr_w(lpszComp
), iLen
);
437 iRet
= CompareStringW(GetThreadLocale(), NORM_IGNORECASE
, lpszStr
, iLen
, lpszComp
, iLen
);
438 return iRet
== CSTR_LESS_THAN
? -1 : iRet
== CSTR_GREATER_THAN
? 1 : 0;
441 /*************************************************************************
442 * StrCmpW [SHLWAPI.@]
444 * Compare two strings.
447 * lpszStr [I] First string to compare
448 * lpszComp [I] Second string to compare
451 * An integer less than, equal to or greater than 0, indicating that
452 * lpszStr is less than, the same, or greater than lpszComp.
454 int WINAPI
StrCmpW(LPCWSTR lpszStr
, LPCWSTR lpszComp
)
458 TRACE("(%s,%s)\n", debugstr_w(lpszStr
), debugstr_w(lpszComp
));
460 iRet
= CompareStringW(GetThreadLocale(), 0, lpszStr
, -1, lpszComp
, -1);
461 return iRet
== CSTR_LESS_THAN
? -1 : iRet
== CSTR_GREATER_THAN
? 1 : 0;
464 /*************************************************************************
465 * StrCatW [SHLWAPI.@]
467 * Concatenate two strings.
470 * lpszStr [O] Initial string
471 * lpszSrc [I] String to concatenate
476 LPWSTR WINAPI
StrCatW(LPWSTR lpszStr
, LPCWSTR lpszSrc
)
478 TRACE("(%s,%s)\n", debugstr_w(lpszStr
), debugstr_w(lpszSrc
));
480 strcatW(lpszStr
, lpszSrc
);
484 /*************************************************************************
485 * StrCpyW [SHLWAPI.@]
487 * Copy a string to another string.
490 * lpszStr [O] Destination string
491 * lpszSrc [I] Source string
496 LPWSTR WINAPI
StrCpyW(LPWSTR lpszStr
, LPCWSTR lpszSrc
)
498 TRACE("(%p,%s)\n", lpszStr
, debugstr_w(lpszSrc
));
500 strcpyW(lpszStr
, lpszSrc
);
504 /*************************************************************************
505 * StrCpyNW [SHLWAPI.@]
507 * Copy a string to another string, up to a maximum number of characters.
510 * dst [O] Destination string
511 * src [I] Source string
512 * count [I] Maximum number of chars to copy
517 LPWSTR WINAPI
StrCpyNW(LPWSTR dst
, LPCWSTR src
, int count
)
522 TRACE("(%p,%s,%i)\n", dst
, debugstr_w(src
), count
);
526 while ((count
> 1) && *s
)
537 /*************************************************************************
538 * SHLWAPI_StrStrHelperA
540 * Internal implementation of StrStrA/StrStrIA
542 static LPSTR
SHLWAPI_StrStrHelperA(LPCSTR lpszStr
, LPCSTR lpszSearch
,
543 INT (WINAPI
*pStrCmpFn
)(LPCSTR
,LPCSTR
,INT
))
547 if (!lpszStr
|| !lpszSearch
|| !*lpszSearch
)
550 iLen
= strlen(lpszSearch
);
554 if (!pStrCmpFn(lpszStr
, lpszSearch
, iLen
))
555 return (LPSTR
)lpszStr
;
556 lpszStr
= CharNextA(lpszStr
);
561 /*************************************************************************
562 * StrStrA [SHLWAPI.@]
564 * Find a substring within a string.
567 * lpszStr [I] String to search in
568 * lpszSearch [I] String to look for
571 * The start of lpszSearch within lpszStr, or NULL if not found.
573 LPSTR WINAPI
StrStrA(LPCSTR lpszStr
, LPCSTR lpszSearch
)
575 TRACE("(%s,%s)\n", debugstr_a(lpszStr
), debugstr_a(lpszSearch
));
577 return SHLWAPI_StrStrHelperA(lpszStr
, lpszSearch
, StrCmpNA
);
580 /*************************************************************************
581 * StrStrW [SHLWAPI.@]
585 LPWSTR WINAPI
StrStrW(LPCWSTR lpszStr
, LPCWSTR lpszSearch
)
587 TRACE("(%s, %s)\n", debugstr_w(lpszStr
), debugstr_w(lpszSearch
));
589 if (!lpszStr
|| !lpszSearch
|| !*lpszSearch
) return NULL
;
590 return strstrW( lpszStr
, lpszSearch
);
593 /*************************************************************************
594 * StrRStrIA [SHLWAPI.@]
596 * Find the last occurrence of a substring within a string.
599 * lpszStr [I] String to search in
600 * lpszEnd [I] End of lpszStr
601 * lpszSearch [I] String to look for
604 * The last occurrence lpszSearch within lpszStr, or NULL if not found.
606 LPSTR WINAPI
StrRStrIA(LPCSTR lpszStr
, LPCSTR lpszEnd
, LPCSTR lpszSearch
)
611 TRACE("(%s,%s)\n", debugstr_a(lpszStr
), debugstr_a(lpszSearch
));
613 if (!lpszStr
|| !lpszSearch
|| !*lpszSearch
)
617 lpszEnd
= lpszStr
+ lstrlenA(lpszStr
);
618 if (lpszEnd
== lpszStr
)
621 if (IsDBCSLeadByte(*lpszSearch
))
622 ch1
= *lpszSearch
<< 8 | (UCHAR
)lpszSearch
[1];
625 iLen
= lstrlenA(lpszSearch
);
629 lpszEnd
= CharPrevA(lpszStr
, lpszEnd
);
630 ch2
= IsDBCSLeadByte(*lpszEnd
)? *lpszEnd
<< 8 | (UCHAR
)lpszEnd
[1] : *lpszEnd
;
631 if (!ChrCmpIA(ch1
, ch2
))
633 if (!StrCmpNIA(lpszEnd
, lpszSearch
, iLen
))
634 return (LPSTR
)lpszEnd
;
636 } while (lpszEnd
> lpszStr
);
640 /*************************************************************************
641 * StrRStrIW [SHLWAPI.@]
645 LPWSTR WINAPI
StrRStrIW(LPCWSTR lpszStr
, LPCWSTR lpszEnd
, LPCWSTR lpszSearch
)
649 TRACE("(%s,%s)\n", debugstr_w(lpszStr
), debugstr_w(lpszSearch
));
651 if (!lpszStr
|| !lpszSearch
|| !*lpszSearch
)
655 lpszEnd
= lpszStr
+ strlenW(lpszStr
);
657 iLen
= strlenW(lpszSearch
);
659 while (lpszEnd
> lpszStr
)
662 if (!StrCmpNIW(lpszEnd
, lpszSearch
, iLen
))
663 return (LPWSTR
)lpszEnd
;
668 /*************************************************************************
669 * StrStrIA [SHLWAPI.@]
671 * Find a substring within a string, ignoring case.
674 * lpszStr [I] String to search in
675 * lpszSearch [I] String to look for
678 * The start of lpszSearch within lpszStr, or NULL if not found.
680 LPSTR WINAPI
StrStrIA(LPCSTR lpszStr
, LPCSTR lpszSearch
)
682 TRACE("(%s,%s)\n", debugstr_a(lpszStr
), debugstr_a(lpszSearch
));
684 return SHLWAPI_StrStrHelperA(lpszStr
, lpszSearch
, StrCmpNIA
);
687 /*************************************************************************
688 * StrStrIW [SHLWAPI.@]
692 LPWSTR WINAPI
StrStrIW(LPCWSTR lpszStr
, LPCWSTR lpszSearch
)
696 TRACE("(%s,%s)\n", debugstr_w(lpszStr
), debugstr_w(lpszSearch
));
698 if (!lpszStr
|| !lpszSearch
|| !*lpszSearch
)
701 iLen
= strlenW(lpszSearch
);
705 if (!StrCmpNIW(lpszStr
, lpszSearch
, iLen
))
706 return (LPWSTR
)lpszStr
;
712 /*************************************************************************
713 * StrStrNW [SHLWAPI.@]
715 * Find a substring within a string up to a given number of initial characters.
718 * lpFirst [I] String to search in
719 * lpSrch [I] String to look for
720 * cchMax [I] Maximum number of initial search characters
723 * The start of lpFirst within lpSrch, or NULL if not found.
725 LPWSTR WINAPI
StrStrNW(LPCWSTR lpFirst
, LPCWSTR lpSrch
, UINT cchMax
)
730 TRACE("(%s, %s, %u)\n", debugstr_w(lpFirst
), debugstr_w(lpSrch
), cchMax
);
732 if (!lpFirst
|| !lpSrch
|| !*lpSrch
|| !cchMax
)
735 len
= strlenW(lpSrch
);
737 for (i
= cchMax
; *lpFirst
&& (i
> 0); i
--, lpFirst
++)
739 if (!strncmpW(lpFirst
, lpSrch
, len
))
740 return (LPWSTR
)lpFirst
;
746 /*************************************************************************
747 * StrStrNIW [SHLWAPI.@]
749 * Find a substring within a string up to a given number of initial characters,
753 * lpFirst [I] String to search in
754 * lpSrch [I] String to look for
755 * cchMax [I] Maximum number of initial search characters
758 * The start of lpFirst within lpSrch, or NULL if not found.
760 LPWSTR WINAPI
StrStrNIW(LPCWSTR lpFirst
, LPCWSTR lpSrch
, UINT cchMax
)
765 TRACE("(%s, %s, %u)\n", debugstr_w(lpFirst
), debugstr_w(lpSrch
), cchMax
);
767 if (!lpFirst
|| !lpSrch
|| !*lpSrch
|| !cchMax
)
770 len
= strlenW(lpSrch
);
772 for (i
= cchMax
; *lpFirst
&& (i
> 0); i
--, lpFirst
++)
774 if (!strncmpiW(lpFirst
, lpSrch
, len
))
775 return (LPWSTR
)lpFirst
;
781 /*************************************************************************
782 * StrToIntA [SHLWAPI.@]
784 * Read a signed integer from a string.
787 * lpszStr [I] String to read integer from
790 * The signed integer value represented by the string, or 0 if no integer is
794 * No leading space is allowed before the number, although a leading '-' is.
796 int WINAPI
StrToIntA(LPCSTR lpszStr
)
800 TRACE("(%s)\n", debugstr_a(lpszStr
));
804 WARN("Invalid lpszStr would crash under Win32!\n");
808 if (*lpszStr
== '-' || isdigit(*lpszStr
))
809 StrToIntExA(lpszStr
, 0, &iRet
);
813 /*************************************************************************
814 * StrToIntW [SHLWAPI.@]
818 int WINAPI
StrToIntW(LPCWSTR lpszStr
)
822 TRACE("(%s)\n", debugstr_w(lpszStr
));
826 WARN("Invalid lpszStr would crash under Win32!\n");
830 if (*lpszStr
== '-' || isdigitW(*lpszStr
))
831 StrToIntExW(lpszStr
, 0, &iRet
);
835 /*************************************************************************
836 * StrToIntExA [SHLWAPI.@]
838 * Read an integer from a string.
841 * lpszStr [I] String to read integer from
842 * dwFlags [I] Flags controlling the conversion
843 * lpiRet [O] Destination for read integer.
846 * Success: TRUE. lpiRet contains the integer value represented by the string.
847 * Failure: FALSE, if the string is invalid, or no number is present.
850 * Leading whitespace, '-' and '+' are allowed before the number. If
851 * dwFlags includes STIF_SUPPORT_HEX, hexadecimal numbers are allowed, if
852 * preceded by '0x'. If this flag is not set, or there is no '0x' prefix,
853 * the string is treated as a decimal string. A leading '-' is ignored for
854 * hexadecimal numbers.
856 BOOL WINAPI
StrToIntExA(LPCSTR lpszStr
, DWORD dwFlags
, LPINT lpiRet
)
858 BOOL bNegative
= FALSE
;
861 TRACE("(%s,%08X,%p)\n", debugstr_a(lpszStr
), dwFlags
, lpiRet
);
863 if (!lpszStr
|| !lpiRet
)
865 WARN("Invalid parameter would crash under Win32!\n");
868 if (dwFlags
> STIF_SUPPORT_HEX
) WARN("Unknown flags %08x\n", dwFlags
);
870 /* Skip leading space, '+', '-' */
871 while (isspace(*lpszStr
))
872 lpszStr
= CharNextA(lpszStr
);
879 else if (*lpszStr
== '+')
882 if (dwFlags
& STIF_SUPPORT_HEX
&&
883 *lpszStr
== '0' && tolower(lpszStr
[1]) == 'x')
885 /* Read hex number */
888 if (!isxdigit(*lpszStr
))
891 while (isxdigit(*lpszStr
))
894 if (isdigit(*lpszStr
))
895 iRet
+= (*lpszStr
- '0');
897 iRet
+= 10 + (tolower(*lpszStr
) - 'a');
904 /* Read decimal number */
905 if (!isdigit(*lpszStr
))
908 while (isdigit(*lpszStr
))
911 iRet
+= (*lpszStr
- '0');
914 *lpiRet
= bNegative
? -iRet
: iRet
;
918 /*************************************************************************
919 * StrToIntExW [SHLWAPI.@]
923 BOOL WINAPI
StrToIntExW(LPCWSTR lpszStr
, DWORD dwFlags
, LPINT lpiRet
)
925 BOOL bNegative
= FALSE
;
928 TRACE("(%s,%08X,%p)\n", debugstr_w(lpszStr
), dwFlags
, lpiRet
);
930 if (!lpszStr
|| !lpiRet
)
932 WARN("Invalid parameter would crash under Win32!\n");
935 if (dwFlags
> STIF_SUPPORT_HEX
) WARN("Unknown flags %08x\n", dwFlags
);
937 /* Skip leading space, '+', '-' */
938 while (isspaceW(*lpszStr
)) lpszStr
++;
945 else if (*lpszStr
== '+')
948 if (dwFlags
& STIF_SUPPORT_HEX
&&
949 *lpszStr
== '0' && tolowerW(lpszStr
[1]) == 'x')
951 /* Read hex number */
954 if (!isxdigitW(*lpszStr
))
957 while (isxdigitW(*lpszStr
))
960 if (isdigitW(*lpszStr
))
961 iRet
+= (*lpszStr
- '0');
963 iRet
+= 10 + (tolowerW(*lpszStr
) - 'a');
970 /* Read decimal number */
971 if (!isdigitW(*lpszStr
))
974 while (isdigitW(*lpszStr
))
977 iRet
+= (*lpszStr
- '0');
980 *lpiRet
= bNegative
? -iRet
: iRet
;
984 /*************************************************************************
985 * StrDupA [SHLWAPI.@]
987 * Duplicate a string.
990 * lpszStr [I] String to duplicate.
993 * Success: A pointer to a new string containing the contents of lpszStr
994 * Failure: NULL, if memory cannot be allocated
997 * The string memory is allocated with LocalAlloc(), and so should be released
998 * by calling LocalFree().
1000 LPSTR WINAPI
StrDupA(LPCSTR lpszStr
)
1005 TRACE("(%s)\n",debugstr_a(lpszStr
));
1007 iLen
= lpszStr
? strlen(lpszStr
) + 1 : 1;
1008 lpszRet
= LocalAlloc(LMEM_FIXED
, iLen
);
1013 memcpy(lpszRet
, lpszStr
, iLen
);
1020 /*************************************************************************
1021 * StrDupW [SHLWAPI.@]
1025 LPWSTR WINAPI
StrDupW(LPCWSTR lpszStr
)
1030 TRACE("(%s)\n",debugstr_w(lpszStr
));
1032 iLen
= (lpszStr
? strlenW(lpszStr
) + 1 : 1) * sizeof(WCHAR
);
1033 lpszRet
= LocalAlloc(LMEM_FIXED
, iLen
);
1038 memcpy(lpszRet
, lpszStr
, iLen
);
1045 /*************************************************************************
1046 * SHLWAPI_StrSpnHelperA
1048 * Internal implementation of StrSpnA/StrCSpnA/StrCSpnIA
1050 static int SHLWAPI_StrSpnHelperA(LPCSTR lpszStr
, LPCSTR lpszMatch
,
1051 LPSTR (WINAPI
*pStrChrFn
)(LPCSTR
,WORD
),
1054 LPCSTR lpszRead
= lpszStr
;
1055 if (lpszStr
&& *lpszStr
&& lpszMatch
)
1059 LPCSTR lpszTest
= pStrChrFn(lpszMatch
, *lpszRead
);
1061 if (!bInvert
&& !lpszTest
)
1063 if (bInvert
&& lpszTest
)
1065 lpszRead
= CharNextA(lpszRead
);
1068 return lpszRead
- lpszStr
;
1071 /*************************************************************************
1072 * StrSpnA [SHLWAPI.@]
1074 * Find the length of the start of a string that contains only certain
1078 * lpszStr [I] String to search
1079 * lpszMatch [I] Characters that can be in the substring
1082 * The length of the part of lpszStr containing only chars from lpszMatch,
1083 * or 0 if any parameter is invalid.
1085 int WINAPI
StrSpnA(LPCSTR lpszStr
, LPCSTR lpszMatch
)
1087 TRACE("(%s,%s)\n",debugstr_a(lpszStr
), debugstr_a(lpszMatch
));
1089 return SHLWAPI_StrSpnHelperA(lpszStr
, lpszMatch
, StrChrA
, FALSE
);
1092 /*************************************************************************
1093 * StrSpnW [SHLWAPI.@]
1097 int WINAPI
StrSpnW(LPCWSTR lpszStr
, LPCWSTR lpszMatch
)
1099 if (!lpszStr
|| !lpszMatch
) return 0;
1100 return strspnW( lpszStr
, lpszMatch
);
1103 /*************************************************************************
1104 * StrCSpnA [SHLWAPI.@]
1106 * Find the length of the start of a string that does not contain certain
1110 * lpszStr [I] String to search
1111 * lpszMatch [I] Characters that cannot be in the substring
1114 * The length of the part of lpszStr containing only chars not in lpszMatch,
1115 * or 0 if any parameter is invalid.
1117 int WINAPI
StrCSpnA(LPCSTR lpszStr
, LPCSTR lpszMatch
)
1119 TRACE("(%s,%s)\n",debugstr_a(lpszStr
), debugstr_a(lpszMatch
));
1121 return SHLWAPI_StrSpnHelperA(lpszStr
, lpszMatch
, StrChrA
, TRUE
);
1124 /*************************************************************************
1125 * StrCSpnW [SHLWAPI.@]
1129 int WINAPI
StrCSpnW(LPCWSTR lpszStr
, LPCWSTR lpszMatch
)
1131 if (!lpszStr
|| !lpszMatch
) return 0;
1132 return strcspnW( lpszStr
, lpszMatch
);
1135 /*************************************************************************
1136 * StrCSpnIA [SHLWAPI.@]
1138 * Find the length of the start of a string that does not contain certain
1139 * characters, ignoring case.
1142 * lpszStr [I] String to search
1143 * lpszMatch [I] Characters that cannot be in the substring
1146 * The length of the part of lpszStr containing only chars not in lpszMatch,
1147 * or 0 if any parameter is invalid.
1149 int WINAPI
StrCSpnIA(LPCSTR lpszStr
, LPCSTR lpszMatch
)
1151 TRACE("(%s,%s)\n",debugstr_a(lpszStr
), debugstr_a(lpszMatch
));
1153 return SHLWAPI_StrSpnHelperA(lpszStr
, lpszMatch
, StrChrIA
, TRUE
);
1156 /*************************************************************************
1157 * StrCSpnIW [SHLWAPI.@]
1161 int WINAPI
StrCSpnIW(LPCWSTR lpszStr
, LPCWSTR lpszMatch
)
1163 LPCWSTR lpszRead
= lpszStr
;
1165 TRACE("(%s,%s)\n",debugstr_w(lpszStr
), debugstr_w(lpszMatch
));
1167 if (lpszStr
&& *lpszStr
&& lpszMatch
)
1171 if (StrChrIW(lpszMatch
, *lpszRead
)) break;
1175 return lpszRead
- lpszStr
;
1178 /*************************************************************************
1179 * StrPBrkA [SHLWAPI.@]
1181 * Search a string for any of a group of characters.
1184 * lpszStr [I] String to search
1185 * lpszMatch [I] Characters to match
1188 * A pointer to the first matching character in lpszStr, or NULL if no
1191 LPSTR WINAPI
StrPBrkA(LPCSTR lpszStr
, LPCSTR lpszMatch
)
1193 TRACE("(%s,%s)\n",debugstr_a(lpszStr
), debugstr_a(lpszMatch
));
1195 if (lpszStr
&& lpszMatch
&& *lpszMatch
)
1199 if (StrChrA(lpszMatch
, *lpszStr
))
1200 return (LPSTR
)lpszStr
;
1201 lpszStr
= CharNextA(lpszStr
);
1207 /*************************************************************************
1208 * StrPBrkW [SHLWAPI.@]
1212 LPWSTR WINAPI
StrPBrkW(LPCWSTR lpszStr
, LPCWSTR lpszMatch
)
1214 if (!lpszStr
|| !lpszMatch
) return NULL
;
1215 return strpbrkW( lpszStr
, lpszMatch
);
1218 /*************************************************************************
1219 * SHLWAPI_StrRChrHelperA
1221 * Internal implementation of StrRChrA/StrRChrIA.
1223 static LPSTR
SHLWAPI_StrRChrHelperA(LPCSTR lpszStr
,
1224 LPCSTR lpszEnd
, WORD ch
,
1225 BOOL (WINAPI
*pChrCmpFn
)(WORD
,WORD
))
1227 LPCSTR lpszRet
= NULL
;
1234 lpszEnd
= lpszStr
+ lstrlenA(lpszStr
);
1236 while (*lpszStr
&& lpszStr
<= lpszEnd
)
1238 ch2
= IsDBCSLeadByte(*lpszStr
)? *lpszStr
<< 8 | lpszStr
[1] : *lpszStr
;
1240 if (!pChrCmpFn(ch
, ch2
))
1242 lpszStr
= CharNextA(lpszStr
);
1245 return (LPSTR
)lpszRet
;
1248 /**************************************************************************
1249 * StrRChrA [SHLWAPI.@]
1251 * Find the last occurrence of a character in string.
1254 * lpszStr [I] String to search in
1255 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1256 * ch [I] Character to search for.
1259 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1260 * or NULL if not found.
1261 * Failure: NULL, if any arguments are invalid.
1263 LPSTR WINAPI
StrRChrA(LPCSTR lpszStr
, LPCSTR lpszEnd
, WORD ch
)
1265 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr
), debugstr_a(lpszEnd
), ch
);
1267 return SHLWAPI_StrRChrHelperA(lpszStr
, lpszEnd
, ch
, SHLWAPI_ChrCmpA
);
1270 /**************************************************************************
1271 * StrRChrW [SHLWAPI.@]
1275 LPWSTR WINAPI
StrRChrW(LPCWSTR str
, LPCWSTR end
, WORD ch
)
1279 if (!str
) return NULL
;
1280 if (!end
) end
= str
+ strlenW(str
);
1283 if (*str
== ch
) ret
= (WCHAR
*)str
;
1289 /**************************************************************************
1290 * StrRChrIA [SHLWAPI.@]
1292 * Find the last occurrence of a character in string, ignoring case.
1295 * lpszStr [I] String to search in
1296 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1297 * ch [I] Character to search for.
1300 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1301 * or NULL if not found.
1302 * Failure: NULL, if any arguments are invalid.
1304 LPSTR WINAPI
StrRChrIA(LPCSTR lpszStr
, LPCSTR lpszEnd
, WORD ch
)
1306 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr
), debugstr_a(lpszEnd
), ch
);
1308 return SHLWAPI_StrRChrHelperA(lpszStr
, lpszEnd
, ch
, ChrCmpIA
);
1311 /**************************************************************************
1312 * StrRChrIW [SHLWAPI.@]
1316 LPWSTR WINAPI
StrRChrIW(LPCWSTR str
, LPCWSTR end
, WORD ch
)
1320 if (!str
) return NULL
;
1321 if (!end
) end
= str
+ strlenW(str
);
1324 if (!ChrCmpIW(*str
, ch
)) ret
= (WCHAR
*)str
;
1330 /*************************************************************************
1331 * StrCatBuffA [SHLWAPI.@]
1333 * Concatenate two strings together.
1336 * lpszStr [O] String to concatenate to
1337 * lpszCat [I] String to add to lpszCat
1338 * cchMax [I] Maximum number of characters for the whole string
1344 * cchMax determines the number of characters in the final length of the
1345 * string, not the number appended to lpszStr from lpszCat.
1347 LPSTR WINAPI
StrCatBuffA(LPSTR lpszStr
, LPCSTR lpszCat
, INT cchMax
)
1351 TRACE("(%p,%s,%d)\n", lpszStr
, debugstr_a(lpszCat
), cchMax
);
1355 WARN("Invalid lpszStr would crash under Win32!\n");
1359 iLen
= strlen(lpszStr
);
1363 StrCpyNA(lpszStr
+ iLen
, lpszCat
, cchMax
);
1367 /*************************************************************************
1368 * StrCatBuffW [SHLWAPI.@]
1372 LPWSTR WINAPI
StrCatBuffW(LPWSTR lpszStr
, LPCWSTR lpszCat
, INT cchMax
)
1376 TRACE("(%p,%s,%d)\n", lpszStr
, debugstr_w(lpszCat
), cchMax
);
1380 WARN("Invalid lpszStr would crash under Win32!\n");
1384 iLen
= strlenW(lpszStr
);
1388 StrCpyNW(lpszStr
+ iLen
, lpszCat
, cchMax
);
1392 /*************************************************************************
1393 * StrRetToBufA [SHLWAPI.@]
1395 * Convert a STRRET to a normal string.
1398 * lpStrRet [O] STRRET to convert
1399 * pIdl [I] ITEMIDLIST for lpStrRet->uType == STRRET_OFFSET
1400 * lpszDest [O] Destination for normal string
1401 * dwLen [I] Length of lpszDest
1404 * Success: S_OK. lpszDest contains up to dwLen characters of the string.
1405 * If lpStrRet is of type STRRET_WSTR, its memory is freed with
1406 * CoTaskMemFree() and its type set to STRRET_CSTRA.
1407 * Failure: E_FAIL, if any parameters are invalid.
1409 HRESULT WINAPI
StrRetToBufA (LPSTRRET src
, const ITEMIDLIST
*pidl
, LPSTR dest
, UINT len
)
1412 * This routine is identical to that in dlls/shell32/shellstring.c.
1413 * It was duplicated because not every version of Shlwapi.dll exports
1414 * StrRetToBufA. If you change one routine, change them both.
1416 TRACE("dest=%p len=0x%x strret=%p pidl=%p stub\n",dest
,len
,src
,pidl
);
1420 WARN("Invalid lpStrRet would crash under Win32!\n");
1434 WideCharToMultiByte(CP_ACP
, 0, src
->u
.pOleStr
, -1, dest
, len
, NULL
, NULL
);
1435 CoTaskMemFree(src
->u
.pOleStr
);
1439 lstrcpynA(dest
, src
->u
.cStr
, len
);
1443 lstrcpynA((LPSTR
)dest
, ((LPCSTR
)&pidl
->mkid
)+src
->u
.uOffset
, len
);
1447 FIXME("unknown type!\n");
1453 /*************************************************************************
1454 * StrRetToBufW [SHLWAPI.@]
1458 HRESULT WINAPI
StrRetToBufW (LPSTRRET src
, const ITEMIDLIST
*pidl
, LPWSTR dest
, UINT len
)
1460 TRACE("dest=%p len=0x%x strret=%p pidl=%p stub\n",dest
,len
,src
,pidl
);
1464 WARN("Invalid lpStrRet would crash under Win32!\n");
1478 lstrcpynW(dest
, src
->u
.pOleStr
, len
);
1479 CoTaskMemFree(src
->u
.pOleStr
);
1483 if (!MultiByteToWideChar( CP_ACP
, 0, src
->u
.cStr
, -1, dest
, len
))
1490 if (!MultiByteToWideChar( CP_ACP
, 0, ((LPCSTR
)&pidl
->mkid
)+src
->u
.uOffset
, -1,
1497 FIXME("unknown type!\n");
1503 /*************************************************************************
1504 * StrRetToStrA [SHLWAPI.@]
1506 * Converts a STRRET to a normal string.
1509 * lpStrRet [O] STRRET to convert
1510 * pidl [I] ITEMIDLIST for lpStrRet->uType == STRRET_OFFSET
1511 * ppszName [O] Destination for converted string
1514 * Success: S_OK. ppszName contains the new string, allocated with CoTaskMemAlloc().
1515 * Failure: E_FAIL, if any parameters are invalid.
1517 HRESULT WINAPI
StrRetToStrA(LPSTRRET lpStrRet
, const ITEMIDLIST
*pidl
, LPSTR
*ppszName
)
1519 HRESULT hRet
= E_FAIL
;
1521 switch (lpStrRet
->uType
)
1524 hRet
= _SHStrDupAW(lpStrRet
->u
.pOleStr
, ppszName
);
1525 CoTaskMemFree(lpStrRet
->u
.pOleStr
);
1529 hRet
= _SHStrDupAA(lpStrRet
->u
.cStr
, ppszName
);
1533 hRet
= _SHStrDupAA(((LPCSTR
)&pidl
->mkid
) + lpStrRet
->u
.uOffset
, ppszName
);
1543 /*************************************************************************
1544 * StrRetToStrW [SHLWAPI.@]
1548 HRESULT WINAPI
StrRetToStrW(LPSTRRET lpStrRet
, const ITEMIDLIST
*pidl
, LPWSTR
*ppszName
)
1550 HRESULT hRet
= E_FAIL
;
1552 switch (lpStrRet
->uType
)
1555 hRet
= SHStrDupW(lpStrRet
->u
.pOleStr
, ppszName
);
1556 CoTaskMemFree(lpStrRet
->u
.pOleStr
);
1560 hRet
= SHStrDupA(lpStrRet
->u
.cStr
, ppszName
);
1564 hRet
= SHStrDupA(((LPCSTR
)&pidl
->mkid
) + lpStrRet
->u
.uOffset
, ppszName
);
1574 /* Create an ASCII string copy using SysAllocString() */
1575 static HRESULT
_SHStrDupAToBSTR(LPCSTR src
, BSTR
*pBstrOut
)
1581 INT len
= MultiByteToWideChar(CP_ACP
, 0, src
, -1, NULL
, 0);
1582 WCHAR
* szTemp
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1586 MultiByteToWideChar(CP_ACP
, 0, src
, -1, szTemp
, len
);
1587 *pBstrOut
= SysAllocString(szTemp
);
1588 HeapFree(GetProcessHeap(), 0, szTemp
);
1594 return E_OUTOFMEMORY
;
1597 /*************************************************************************
1598 * StrRetToBSTR [SHLWAPI.@]
1600 * Converts a STRRET to a BSTR.
1603 * lpStrRet [O] STRRET to convert
1604 * pidl [I] ITEMIDLIST for lpStrRet->uType = STRRET_OFFSET
1605 * pBstrOut [O] Destination for converted BSTR
1608 * Success: S_OK. pBstrOut contains the new string.
1609 * Failure: E_FAIL, if any parameters are invalid.
1611 HRESULT WINAPI
StrRetToBSTR(STRRET
*lpStrRet
, LPCITEMIDLIST pidl
, BSTR
* pBstrOut
)
1613 HRESULT hRet
= E_FAIL
;
1615 switch (lpStrRet
->uType
)
1618 *pBstrOut
= SysAllocString(lpStrRet
->u
.pOleStr
);
1621 CoTaskMemFree(lpStrRet
->u
.pOleStr
);
1625 hRet
= _SHStrDupAToBSTR(lpStrRet
->u
.cStr
, pBstrOut
);
1629 hRet
= _SHStrDupAToBSTR(((LPCSTR
)&pidl
->mkid
) + lpStrRet
->u
.uOffset
, pBstrOut
);
1639 /*************************************************************************
1640 * StrFormatKBSizeA [SHLWAPI.@]
1642 * Create a formatted string containing a byte count in Kilobytes.
1645 * llBytes [I] Byte size to format
1646 * lpszDest [I] Destination for formatted string
1647 * cchMax [I] Size of lpszDest
1652 LPSTR WINAPI
StrFormatKBSizeA(LONGLONG llBytes
, LPSTR lpszDest
, UINT cchMax
)
1656 if (!StrFormatKBSizeW(llBytes
, wszBuf
, 256))
1658 if (!WideCharToMultiByte(CP_ACP
, 0, wszBuf
, -1, lpszDest
, cchMax
, NULL
, NULL
))
1663 /*************************************************************************
1664 * StrFormatKBSizeW [SHLWAPI.@]
1666 * See StrFormatKBSizeA.
1668 LPWSTR WINAPI
StrFormatKBSizeW(LONGLONG llBytes
, LPWSTR lpszDest
, UINT cchMax
)
1670 static const WCHAR kb
[] = {' ','K','B',0};
1671 LONGLONG llKB
= (llBytes
+ 1023) >> 10;
1674 TRACE("(0x%s,%p,%d)\n", wine_dbgstr_longlong(llBytes
), lpszDest
, cchMax
);
1676 if (!FormatInt(llKB
, lpszDest
, cchMax
))
1679 len
= lstrlenW(lpszDest
);
1680 if (cchMax
- len
< 4)
1682 lstrcatW(lpszDest
, kb
);
1686 /*************************************************************************
1687 * StrNCatA [SHLWAPI.@]
1689 * Concatenate two strings together.
1692 * lpszStr [O] String to concatenate to
1693 * lpszCat [I] String to add to lpszCat
1694 * cchMax [I] Maximum number of characters to concatenate
1700 * cchMax determines the number of characters that are appended to lpszStr,
1701 * not the total length of the string.
1703 LPSTR WINAPI
StrNCatA(LPSTR lpszStr
, LPCSTR lpszCat
, INT cchMax
)
1705 LPSTR lpszRet
= lpszStr
;
1707 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr
), debugstr_a(lpszCat
), cchMax
);
1711 WARN("Invalid lpszStr would crash under Win32!\n");
1715 StrCpyNA(lpszStr
+ strlen(lpszStr
), lpszCat
, cchMax
);
1719 /*************************************************************************
1720 * StrNCatW [SHLWAPI.@]
1724 LPWSTR WINAPI
StrNCatW(LPWSTR lpszStr
, LPCWSTR lpszCat
, INT cchMax
)
1726 LPWSTR lpszRet
= lpszStr
;
1728 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr
), debugstr_w(lpszCat
), cchMax
);
1732 WARN("Invalid lpszStr would crash under Win32\n");
1736 StrCpyNW(lpszStr
+ strlenW(lpszStr
), lpszCat
, cchMax
);
1740 /*************************************************************************
1741 * StrTrimA [SHLWAPI.@]
1743 * Remove characters from the start and end of a string.
1746 * lpszStr [O] String to remove characters from
1747 * lpszTrim [I] Characters to remove from lpszStr
1750 * TRUE If lpszStr was valid and modified
1753 BOOL WINAPI
StrTrimA(LPSTR lpszStr
, LPCSTR lpszTrim
)
1756 LPSTR lpszRead
= lpszStr
;
1759 TRACE("(%s,%s)\n", debugstr_a(lpszStr
), debugstr_a(lpszTrim
));
1761 if (lpszRead
&& *lpszRead
)
1763 while (*lpszRead
&& StrChrA(lpszTrim
, *lpszRead
))
1764 lpszRead
= CharNextA(lpszRead
); /* Skip leading matches */
1766 dwLen
= strlen(lpszRead
);
1768 if (lpszRead
!= lpszStr
)
1770 memmove(lpszStr
, lpszRead
, dwLen
+ 1);
1775 lpszRead
= lpszStr
+ dwLen
;
1776 while (StrChrA(lpszTrim
, lpszRead
[-1]))
1777 lpszRead
= CharPrevA(lpszStr
, lpszRead
); /* Skip trailing matches */
1779 if (lpszRead
!= lpszStr
+ dwLen
)
1789 /*************************************************************************
1790 * StrTrimW [SHLWAPI.@]
1794 BOOL WINAPI
StrTrimW(LPWSTR lpszStr
, LPCWSTR lpszTrim
)
1797 LPWSTR lpszRead
= lpszStr
;
1800 TRACE("(%s,%s)\n", debugstr_w(lpszStr
), debugstr_w(lpszTrim
));
1802 if (lpszRead
&& *lpszRead
)
1804 while (*lpszRead
&& StrChrW(lpszTrim
, *lpszRead
)) lpszRead
++;
1806 dwLen
= strlenW(lpszRead
);
1808 if (lpszRead
!= lpszStr
)
1810 memmove(lpszStr
, lpszRead
, (dwLen
+ 1) * sizeof(WCHAR
));
1815 lpszRead
= lpszStr
+ dwLen
;
1816 while (StrChrW(lpszTrim
, lpszRead
[-1]))
1817 lpszRead
--; /* Skip trailing matches */
1819 if (lpszRead
!= lpszStr
+ dwLen
)
1829 /*************************************************************************
1830 * _SHStrDupAA [INTERNAL]
1832 * Duplicates a ASCII string to ASCII. The destination buffer is allocated.
1834 static HRESULT
_SHStrDupAA(LPCSTR src
, LPSTR
* dest
)
1840 len
= lstrlenA(src
) + 1;
1841 *dest
= CoTaskMemAlloc(len
);
1847 lstrcpynA(*dest
,src
, len
);
1853 TRACE("%s->(%p)\n", debugstr_a(src
), *dest
);
1857 /*************************************************************************
1858 * SHStrDupA [SHLWAPI.@]
1860 * Return a Unicode copy of a string, in memory allocated by CoTaskMemAlloc().
1863 * lpszStr [I] String to copy
1864 * lppszDest [O] Destination for the new string copy
1867 * Success: S_OK. lppszDest contains the new string in Unicode format.
1868 * Failure: E_OUTOFMEMORY, If any arguments are invalid or memory allocation
1871 HRESULT WINAPI
SHStrDupA(LPCSTR lpszStr
, LPWSTR
* lppszDest
)
1878 len
= MultiByteToWideChar(0, 0, lpszStr
, -1, 0, 0) * sizeof(WCHAR
);
1879 *lppszDest
= CoTaskMemAlloc(len
);
1886 MultiByteToWideChar(0, 0, lpszStr
, -1, *lppszDest
, len
/sizeof(WCHAR
));
1890 hRet
= E_OUTOFMEMORY
;
1892 TRACE("%s->(%p)\n", debugstr_a(lpszStr
), *lppszDest
);
1896 /*************************************************************************
1897 * _SHStrDupAW [INTERNAL]
1899 * Duplicates a UNICODE to a ASCII string. The destination buffer is allocated.
1901 static HRESULT
_SHStrDupAW(LPCWSTR src
, LPSTR
* dest
)
1907 len
= WideCharToMultiByte(CP_ACP
, 0, src
, -1, NULL
, 0, NULL
, NULL
);
1908 *dest
= CoTaskMemAlloc(len
);
1914 WideCharToMultiByte(CP_ACP
, 0, src
, -1, *dest
, len
, NULL
, NULL
);
1920 TRACE("%s->(%p)\n", debugstr_w(src
), *dest
);
1924 /*************************************************************************
1925 * SHStrDupW [SHLWAPI.@]
1929 HRESULT WINAPI
SHStrDupW(LPCWSTR src
, LPWSTR
* dest
)
1935 len
= (lstrlenW(src
) + 1) * sizeof(WCHAR
);
1936 *dest
= CoTaskMemAlloc(len
);
1942 memcpy(*dest
, src
, len
);
1948 TRACE("%s->(%p)\n", debugstr_w(src
), *dest
);
1952 /*************************************************************************
1953 * SHLWAPI_WriteReverseNum
1955 * Internal helper for SHLWAPI_WriteTimeClass.
1957 static inline LPWSTR
SHLWAPI_WriteReverseNum(LPWSTR lpszOut
, DWORD dwNum
)
1961 /* Write a decimal number to a string, backwards */
1964 DWORD dwNextDigit
= dwNum
% 10;
1965 *lpszOut
-- = '0' + dwNextDigit
;
1966 dwNum
= (dwNum
- dwNextDigit
) / 10;
1967 } while (dwNum
> 0);
1972 /*************************************************************************
1973 * SHLWAPI_FormatSignificant
1975 * Internal helper for SHLWAPI_WriteTimeClass.
1977 static inline int SHLWAPI_FormatSignificant(LPWSTR lpszNum
, int dwDigits
)
1979 /* Zero non significant digits, return remaining significant digits */
1983 if (--dwDigits
== 0)
1993 /*************************************************************************
1994 * SHLWAPI_WriteTimeClass
1996 * Internal helper for StrFromTimeIntervalW.
1998 static int SHLWAPI_WriteTimeClass(LPWSTR lpszOut
, DWORD dwValue
,
1999 UINT uClassStringId
, int iDigits
)
2001 WCHAR szBuff
[64], *szOut
= szBuff
+ 32;
2003 szOut
= SHLWAPI_WriteReverseNum(szOut
, dwValue
);
2004 iDigits
= SHLWAPI_FormatSignificant(szOut
+ 1, iDigits
);
2006 LoadStringW(shlwapi_hInstance
, uClassStringId
, szBuff
+ 32, 32);
2007 strcatW(lpszOut
, szOut
);
2011 /*************************************************************************
2012 * StrFromTimeIntervalA [SHLWAPI.@]
2014 * Format a millisecond time interval into a string
2017 * lpszStr [O] Output buffer for formatted time interval
2018 * cchMax [I] Size of lpszStr
2019 * dwMS [I] Number of milliseconds
2020 * iDigits [I] Number of digits to print
2023 * The length of the formatted string, or 0 if any parameter is invalid.
2026 * This implementation mimics the Win32 behaviour of always writing a leading
2027 * space before the time interval begins.
2029 * iDigits is used to provide approximate times if accuracy is not important.
2030 * This number of digits will be written of the first non-zero time class
2031 * (hours/minutes/seconds). If this does not complete the time classification,
2032 * the remaining digits are changed to zeros (i.e. The time is _not_ rounded).
2033 * If there are digits remaining following the writing of a time class, the
2034 * next time class will be written.
2036 * For example, given dwMS represents 138 hours,43 minutes and 15 seconds, the
2037 * following will result from the given values of iDigits:
2039 *| iDigits 1 2 3 4 5 ...
2040 *| lpszStr "100 hr" "130 hr" "138 hr" "138 hr 40 min" "138 hr 43 min" ...
2042 INT WINAPI
StrFromTimeIntervalA(LPSTR lpszStr
, UINT cchMax
, DWORD dwMS
,
2047 TRACE("(%p,%d,%d,%d)\n", lpszStr
, cchMax
, dwMS
, iDigits
);
2049 if (lpszStr
&& cchMax
)
2052 StrFromTimeIntervalW(szBuff
, sizeof(szBuff
)/sizeof(WCHAR
), dwMS
, iDigits
);
2053 WideCharToMultiByte(CP_ACP
,0,szBuff
,-1,lpszStr
,cchMax
,0,0);
2059 /*************************************************************************
2060 * StrFromTimeIntervalW [SHLWAPI.@]
2062 * See StrFromTimeIntervalA.
2064 INT WINAPI
StrFromTimeIntervalW(LPWSTR lpszStr
, UINT cchMax
, DWORD dwMS
,
2069 TRACE("(%p,%d,%d,%d)\n", lpszStr
, cchMax
, dwMS
, iDigits
);
2071 if (lpszStr
&& cchMax
)
2074 DWORD dwHours
, dwMinutes
;
2076 if (!iDigits
|| cchMax
== 1)
2082 /* Calculate the time classes */
2083 dwMS
= (dwMS
+ 500) / 1000;
2084 dwHours
= dwMS
/ 3600;
2085 dwMS
-= dwHours
* 3600;
2086 dwMinutes
= dwMS
/ 60;
2087 dwMS
-= dwMinutes
* 60;
2092 iDigits
= SHLWAPI_WriteTimeClass(szCopy
, dwHours
, IDS_TIME_INTERVAL_HOURS
, iDigits
);
2094 if (dwMinutes
&& iDigits
)
2095 iDigits
= SHLWAPI_WriteTimeClass(szCopy
, dwMinutes
, IDS_TIME_INTERVAL_MINUTES
, iDigits
);
2097 if (iDigits
) /* Always write seconds if we have significant digits */
2098 SHLWAPI_WriteTimeClass(szCopy
, dwMS
, IDS_TIME_INTERVAL_SECONDS
, iDigits
);
2100 lstrcpynW(lpszStr
, szCopy
, cchMax
);
2101 iRet
= strlenW(lpszStr
);
2106 /*************************************************************************
2107 * StrIsIntlEqualA [SHLWAPI.@]
2109 * Compare two strings.
2112 * bCase [I] Whether to compare case sensitively
2113 * lpszStr [I] First string to compare
2114 * lpszComp [I] Second string to compare
2115 * iLen [I] Length to compare
2118 * TRUE If the strings are equal.
2121 BOOL WINAPI
StrIsIntlEqualA(BOOL bCase
, LPCSTR lpszStr
, LPCSTR lpszComp
,
2126 TRACE("(%d,%s,%s,%d)\n", bCase
,
2127 debugstr_a(lpszStr
), debugstr_a(lpszComp
), iLen
);
2129 /* FIXME: This flag is undocumented and unknown by our CompareString.
2130 * We need a define for it.
2132 dwFlags
= 0x10000000;
2133 if (!bCase
) dwFlags
|= NORM_IGNORECASE
;
2135 return (CompareStringA(GetThreadLocale(), dwFlags
, lpszStr
, iLen
, lpszComp
, iLen
) == CSTR_EQUAL
);
2138 /*************************************************************************
2139 * StrIsIntlEqualW [SHLWAPI.@]
2141 * See StrIsIntlEqualA.
2143 BOOL WINAPI
StrIsIntlEqualW(BOOL bCase
, LPCWSTR lpszStr
, LPCWSTR lpszComp
,
2148 TRACE("(%d,%s,%s,%d)\n", bCase
,
2149 debugstr_w(lpszStr
),debugstr_w(lpszComp
), iLen
);
2151 /* FIXME: This flag is undocumented and unknown by our CompareString.
2152 * We need a define for it.
2154 dwFlags
= 0x10000000;
2155 if (!bCase
) dwFlags
|= NORM_IGNORECASE
;
2157 return (CompareStringW(GetThreadLocale(), dwFlags
, lpszStr
, iLen
, lpszComp
, iLen
) == CSTR_EQUAL
);
2160 /*************************************************************************
2163 * Copy a string to another string, up to a maximum number of characters.
2166 * lpszDest [O] Destination string
2167 * lpszSrc [I] Source string
2168 * iLen [I] Maximum number of chars to copy
2171 * Success: A pointer to the last character written to lpszDest.
2172 * Failure: lpszDest, if any arguments are invalid.
2174 LPSTR WINAPI
StrCpyNXA(LPSTR lpszDest
, LPCSTR lpszSrc
, int iLen
)
2176 TRACE("(%p,%s,%i)\n", lpszDest
, debugstr_a(lpszSrc
), iLen
);
2178 if (lpszDest
&& lpszSrc
&& iLen
> 0)
2180 while ((iLen
-- > 1) && *lpszSrc
)
2181 *lpszDest
++ = *lpszSrc
++;
2188 /*************************************************************************
2191 * Unicode version of StrCpyNXA.
2193 LPWSTR WINAPI
StrCpyNXW(LPWSTR lpszDest
, LPCWSTR lpszSrc
, int iLen
)
2195 TRACE("(%p,%s,%i)\n", lpszDest
, debugstr_w(lpszSrc
), iLen
);
2197 if (lpszDest
&& lpszSrc
&& iLen
> 0)
2199 while ((iLen
-- > 1) && *lpszSrc
)
2200 *lpszDest
++ = *lpszSrc
++;
2207 /*************************************************************************
2208 * StrCmpLogicalW [SHLWAPI.@]
2210 * Compare two strings, ignoring case and comparing digits as numbers.
2213 * lpszStr [I] First string to compare
2214 * lpszComp [I] Second string to compare
2215 * iLen [I] Length to compare
2218 * TRUE If the strings are equal.
2221 INT WINAPI
StrCmpLogicalW(LPCWSTR lpszStr
, LPCWSTR lpszComp
)
2225 TRACE("(%s,%s)\n", debugstr_w(lpszStr
), debugstr_w(lpszComp
));
2227 if (lpszStr
&& lpszComp
)
2233 else if (isdigitW(*lpszStr
))
2237 if (!isdigitW(*lpszComp
))
2240 /* Compare the numbers */
2241 StrToIntExW(lpszStr
, 0, &iStr
);
2242 StrToIntExW(lpszComp
, 0, &iComp
);
2246 else if (iStr
> iComp
)
2250 while (isdigitW(*lpszStr
))
2252 while (isdigitW(*lpszComp
))
2255 else if (isdigitW(*lpszComp
))
2259 iDiff
= ChrCmpIW(*lpszStr
,*lpszComp
);
2275 /* Structure for formatting byte strings */
2276 typedef struct tagSHLWAPI_BYTEFORMATS
2283 } SHLWAPI_BYTEFORMATS
;
2285 /*************************************************************************
2286 * StrFormatByteSizeW [SHLWAPI.@]
2288 * Create a string containing an abbreviated byte count of up to 2^63-1.
2291 * llBytes [I] Byte size to format
2292 * lpszDest [I] Destination for formatted string
2293 * cchMax [I] Size of lpszDest
2299 * There is no StrFormatByteSize64W function, it is called StrFormatByteSizeW().
2301 LPWSTR WINAPI
StrFormatByteSizeW(LONGLONG llBytes
, LPWSTR lpszDest
, UINT cchMax
)
2303 #define KB ((ULONGLONG)1024)
2305 #define GB (KB*KB*KB)
2306 #define TB (KB*KB*KB*KB)
2307 #define PB (KB*KB*KB*KB*KB)
2309 static const SHLWAPI_BYTEFORMATS bfFormats
[] =
2311 { 10*KB
, 10.24, 100.0, 2, 'K' }, /* 10 KB */
2312 { 100*KB
, 102.4, 10.0, 1, 'K' }, /* 100 KB */
2313 { 1000*KB
, 1024.0, 1.0, 0, 'K' }, /* 1000 KB */
2314 { 10*MB
, 10485.76, 100.0, 2, 'M' }, /* 10 MB */
2315 { 100*MB
, 104857.6, 10.0, 1, 'M' }, /* 100 MB */
2316 { 1000*MB
, 1048576.0, 1.0, 0, 'M' }, /* 1000 MB */
2317 { 10*GB
, 10737418.24, 100.0, 2, 'G' }, /* 10 GB */
2318 { 100*GB
, 107374182.4, 10.0, 1, 'G' }, /* 100 GB */
2319 { 1000*GB
, 1073741824.0, 1.0, 0, 'G' }, /* 1000 GB */
2320 { 10*TB
, 10485.76, 100.0, 2, 'T' }, /* 10 TB */
2321 { 100*TB
, 104857.6, 10.0, 1, 'T' }, /* 100 TB */
2322 { 1000*TB
, 1048576.0, 1.0, 0, 'T' }, /* 1000 TB */
2323 { 10*PB
, 10737418.24, 100.00, 2, 'P' }, /* 10 PB */
2324 { 100*PB
, 107374182.4, 10.00, 1, 'P' }, /* 100 PB */
2325 { 1000*PB
, 1073741824.0, 1.00, 0, 'P' }, /* 1000 PB */
2326 { 0, 10995116277.76, 100.00, 2, 'E' } /* EB's, catch all */
2328 WCHAR wszAdd
[] = {' ','?','B',0};
2332 TRACE("(0x%s,%p,%d)\n", wine_dbgstr_longlong(llBytes
), lpszDest
, cchMax
);
2334 if (!lpszDest
|| !cchMax
)
2337 if (llBytes
< 1024) /* 1K */
2339 WCHAR wszBytesFormat
[64];
2340 LoadStringW(shlwapi_hInstance
, IDS_BYTES_FORMAT
, wszBytesFormat
, 64);
2341 snprintfW(lpszDest
, cchMax
, wszBytesFormat
, (int)llBytes
);
2345 /* Note that if this loop completes without finding a match, i will be
2346 * pointing at the last entry, which is a catch all for > 1000 PB
2348 while (i
< sizeof(bfFormats
) / sizeof(SHLWAPI_BYTEFORMATS
) - 1)
2350 if (llBytes
< bfFormats
[i
].dLimit
)
2354 /* Above 1 TB we encounter problems with FP accuracy. So for amounts above
2355 * this number we integer shift down by 1 MB first. The table above has
2356 * the divisors scaled down from the '< 10 TB' entry onwards, to account
2357 * for this. We also add a small fudge factor to get the correct result for
2358 * counts that lie exactly on a 1024 byte boundary.
2361 dBytes
= (double)(llBytes
>> 20) + 0.001; /* Scale down by 1 MB */
2363 dBytes
= (double)llBytes
+ 0.00001;
2365 dBytes
= floor(dBytes
/ bfFormats
[i
].dDivisor
) / bfFormats
[i
].dNormaliser
;
2367 if (!FormatDouble(dBytes
, bfFormats
[i
].nDecimals
, lpszDest
, cchMax
))
2369 wszAdd
[1] = bfFormats
[i
].wPrefix
;
2370 StrCatBuffW(lpszDest
, wszAdd
, cchMax
);
2374 /*************************************************************************
2375 * StrFormatByteSize64A [SHLWAPI.@]
2377 * See StrFormatByteSizeW.
2379 LPSTR WINAPI
StrFormatByteSize64A(LONGLONG llBytes
, LPSTR lpszDest
, UINT cchMax
)
2383 StrFormatByteSizeW(llBytes
, wszBuff
, sizeof(wszBuff
)/sizeof(WCHAR
));
2386 WideCharToMultiByte(CP_ACP
, 0, wszBuff
, -1, lpszDest
, cchMax
, 0, 0);
2390 /*************************************************************************
2391 * StrFormatByteSizeA [SHLWAPI.@]
2393 * Create a string containing an abbreviated byte count of up to 2^31-1.
2396 * dwBytes [I] Byte size to format
2397 * lpszDest [I] Destination for formatted string
2398 * cchMax [I] Size of lpszDest
2404 * The Ascii and Unicode versions of this function accept a different
2405 * integer type for dwBytes. See StrFormatByteSize64A().
2407 LPSTR WINAPI
StrFormatByteSizeA(DWORD dwBytes
, LPSTR lpszDest
, UINT cchMax
)
2409 TRACE("(%d,%p,%d)\n", dwBytes
, lpszDest
, cchMax
);
2411 return StrFormatByteSize64A(dwBytes
, lpszDest
, cchMax
);
2414 /*************************************************************************
2417 * Remove a hanging lead byte from the end of a string, if present.
2420 * lpStr [I] String to check for a hanging lead byte
2421 * size [I] Length of lpStr
2424 * Success: The new length of the string. Any hanging lead bytes are removed.
2425 * Failure: 0, if any parameters are invalid.
2427 DWORD WINAPI
SHTruncateString(LPSTR lpStr
, DWORD size
)
2431 LPSTR lastByte
= lpStr
+ size
- 1;
2433 while(lpStr
< lastByte
)
2434 lpStr
+= IsDBCSLeadByte(*lpStr
) ? 2 : 1;
2436 if(lpStr
== lastByte
&& IsDBCSLeadByte(*lpStr
))
2446 /*************************************************************************
2449 * Remove a single non-trailing ampersand ('&') from a string.
2452 * lpszStr [I/O] String to remove ampersand from.
2455 * The character after the first ampersand in lpszStr, or the first character
2456 * in lpszStr if there is no ampersand in the string.
2458 char WINAPI
SHStripMneumonicA(LPCSTR lpszStr
)
2460 LPSTR lpszIter
, lpszTmp
;
2463 TRACE("(%s)\n", debugstr_a(lpszStr
));
2467 if ((lpszIter
= StrChrA(lpszStr
, '&')))
2469 lpszTmp
= CharNextA(lpszIter
);
2472 if (*lpszTmp
!= '&')
2475 memmove( lpszIter
, lpszTmp
, strlen(lpszTmp
) + 1 );
2482 /*************************************************************************
2485 * Unicode version of SHStripMneumonicA.
2487 WCHAR WINAPI
SHStripMneumonicW(LPCWSTR lpszStr
)
2489 LPWSTR lpszIter
, lpszTmp
;
2492 TRACE("(%s)\n", debugstr_w(lpszStr
));
2496 if ((lpszIter
= StrChrW(lpszStr
, '&')))
2498 lpszTmp
= lpszIter
+ 1;
2501 if (*lpszTmp
!= '&')
2504 memmove( lpszIter
, lpszTmp
, (strlenW(lpszTmp
) + 1) * sizeof(WCHAR
) );
2511 /*************************************************************************
2514 * Convert an Ascii string to Unicode.
2517 * dwCp [I] Code page for the conversion
2518 * lpSrcStr [I] Source Ascii string to convert
2519 * lpDstStr [O] Destination for converted Unicode string
2520 * iLen [I] Length of lpDstStr
2523 * The return value of the MultiByteToWideChar() function called on lpSrcStr.
2525 DWORD WINAPI
SHAnsiToUnicodeCP(DWORD dwCp
, LPCSTR lpSrcStr
, LPWSTR lpDstStr
, int iLen
)
2529 dwRet
= MultiByteToWideChar(dwCp
, 0, lpSrcStr
, -1, lpDstStr
, iLen
);
2530 TRACE("%s->%s,ret=%d\n", debugstr_a(lpSrcStr
), debugstr_w(lpDstStr
), dwRet
);
2534 /*************************************************************************
2537 * Convert an Ascii string to Unicode.
2540 * lpSrcStr [I] Source Ascii string to convert
2541 * lpDstStr [O] Destination for converted Unicode string
2542 * iLen [I] Length of lpDstStr
2545 * The return value of the MultiByteToWideChar() function called on lpSrcStr.
2548 * This function simply calls SHAnsiToUnicodeCP with code page CP_ACP.
2550 DWORD WINAPI
SHAnsiToUnicode(LPCSTR lpSrcStr
, LPWSTR lpDstStr
, int iLen
)
2552 return SHAnsiToUnicodeCP(CP_ACP
, lpSrcStr
, lpDstStr
, iLen
);
2555 /*************************************************************************
2558 * Convert a Unicode string to Ascii.
2561 * CodePage [I] Code page to use for the conversion
2562 * lpSrcStr [I] Source Unicode string to convert
2563 * lpDstStr [O] Destination for converted Ascii string
2564 * dstlen [I] Length of buffer at lpDstStr
2567 * Success: The length in bytes of the result at lpDstStr (including the terminator)
2568 * Failure: When using CP_UTF8, CP_UTF7 or 0xc350 as codePage, 0 is returned and
2569 * the result is not nul-terminated.
2570 * When using a different codepage, the length in bytes of the truncated
2571 * result at lpDstStr (including the terminator) is returned and
2572 * lpDstStr is always nul-terminated.
2575 DWORD WINAPI
SHUnicodeToAnsiCP(UINT CodePage
, LPCWSTR lpSrcStr
, LPSTR lpDstStr
, int dstlen
)
2577 static const WCHAR emptyW
[] = { '\0' };
2581 if (!lpDstStr
|| !dstlen
)
2589 len
= strlenW(lpSrcStr
) + 1;
2594 CodePage
= CP_UTF8
; /* Fall through... */
2595 case 0x0000C350: /* FIXME: CP_ #define */
2601 INT needed
= dstlen
- 1;
2604 /* try the user supplied buffer first */
2605 hr
= ConvertINetUnicodeToMultiByte(&dwMode
, CodePage
, lpSrcStr
, &lenW
, lpDstStr
, &needed
);
2608 lpDstStr
[needed
] = '\0';
2612 /* user buffer too small. exclude termination and copy as much as possible */
2614 hr
= ConvertINetUnicodeToMultiByte(&dwMode
, CodePage
, lpSrcStr
, &lenW
, NULL
, &needed
);
2616 mem
= HeapAlloc(GetProcessHeap(), 0, needed
);
2620 hr
= ConvertINetUnicodeToMultiByte(&dwMode
, CodePage
, lpSrcStr
, &len
, mem
, &needed
);
2623 reqLen
= SHTruncateString(mem
, dstlen
);
2624 if (reqLen
> 0) memcpy(lpDstStr
, mem
, reqLen
-1);
2626 HeapFree(GetProcessHeap(), 0, mem
);
2633 /* try the user supplied buffer first */
2634 reqLen
= WideCharToMultiByte(CodePage
, 0, lpSrcStr
, len
, lpDstStr
, dstlen
, NULL
, NULL
);
2636 if (!reqLen
&& GetLastError() == ERROR_INSUFFICIENT_BUFFER
)
2638 reqLen
= WideCharToMultiByte(CodePage
, 0, lpSrcStr
, len
, NULL
, 0, NULL
, NULL
);
2641 mem
= HeapAlloc(GetProcessHeap(), 0, reqLen
);
2644 reqLen
= WideCharToMultiByte(CodePage
, 0, lpSrcStr
, len
, mem
,
2645 reqLen
, NULL
, NULL
);
2647 reqLen
= SHTruncateString(mem
, dstlen
-1);
2650 lstrcpynA(lpDstStr
, mem
, reqLen
);
2651 HeapFree(GetProcessHeap(), 0, mem
);
2652 lpDstStr
[reqLen
-1] = '\0';
2659 /*************************************************************************
2662 * Convert a Unicode string to Ascii.
2665 * lpSrcStr [I] Source Unicode string to convert
2666 * lpDstStr [O] Destination for converted Ascii string
2667 * iLen [O] Length of lpDstStr in characters
2670 * See SHUnicodeToAnsiCP
2673 * This function simply calls SHUnicodeToAnsiCP() with CodePage = CP_ACP.
2675 INT WINAPI
SHUnicodeToAnsi(LPCWSTR lpSrcStr
, LPSTR lpDstStr
, INT iLen
)
2677 return SHUnicodeToAnsiCP(CP_ACP
, lpSrcStr
, lpDstStr
, iLen
);
2680 /*************************************************************************
2683 * Copy one string to another.
2686 * lpszSrc [I] Source string to copy
2687 * lpszDst [O] Destination for copy
2688 * iLen [I] Length of lpszDst in characters
2691 * The length of the copied string, including the terminating NUL. lpszDst
2692 * contains iLen characters of lpszSrc.
2694 DWORD WINAPI
SHAnsiToAnsi(LPCSTR lpszSrc
, LPSTR lpszDst
, int iLen
)
2698 TRACE("(%s,%p,0x%08x)\n", debugstr_a(lpszSrc
), lpszDst
, iLen
);
2700 lpszRet
= StrCpyNXA(lpszDst
, lpszSrc
, iLen
);
2701 return lpszRet
- lpszDst
+ 1;
2704 /*************************************************************************
2707 * Unicode version of SSHAnsiToAnsi.
2709 DWORD WINAPI
SHUnicodeToUnicode(LPCWSTR lpszSrc
, LPWSTR lpszDst
, int iLen
)
2713 TRACE("(%s,%p,0x%08x)\n", debugstr_w(lpszSrc
), lpszDst
, iLen
);
2715 lpszRet
= StrCpyNXW(lpszDst
, lpszSrc
, iLen
);
2716 return lpszRet
- lpszDst
+ 1;
2719 /*************************************************************************
2722 * Determine if an Ascii string converts to Unicode and back identically.
2725 * lpSrcStr [I] Source Unicode string to convert
2726 * lpDst [O] Destination for resulting Ascii string
2727 * iLen [I] Length of lpDst in characters
2730 * TRUE, since Ascii strings always convert identically.
2732 BOOL WINAPI
DoesStringRoundTripA(LPCSTR lpSrcStr
, LPSTR lpDst
, INT iLen
)
2734 lstrcpynA(lpDst
, lpSrcStr
, iLen
);
2738 /*************************************************************************
2741 * Determine if a Unicode string converts to Ascii and back identically.
2744 * lpSrcStr [I] Source Unicode string to convert
2745 * lpDst [O] Destination for resulting Ascii string
2746 * iLen [I] Length of lpDst in characters
2749 * TRUE, if lpSrcStr converts to Ascii and back identically,
2752 BOOL WINAPI
DoesStringRoundTripW(LPCWSTR lpSrcStr
, LPSTR lpDst
, INT iLen
)
2754 WCHAR szBuff
[MAX_PATH
];
2756 SHUnicodeToAnsi(lpSrcStr
, lpDst
, iLen
);
2757 SHAnsiToUnicode(lpDst
, szBuff
, MAX_PATH
);
2758 return !strcmpW(lpSrcStr
, szBuff
);
2761 /*************************************************************************
2762 * SHLoadIndirectString [SHLWAPI.@]
2764 * If passed a string that begins with '@', extract the string from the
2765 * appropriate resource, otherwise do a straight copy.
2768 HRESULT WINAPI
SHLoadIndirectString(LPCWSTR src
, LPWSTR dst
, UINT dst_len
, void **reserved
)
2770 WCHAR
*dllname
= NULL
;
2771 HMODULE hmod
= NULL
;
2772 HRESULT hr
= E_FAIL
;
2774 TRACE("(%s %p %08x %p)\n", debugstr_w(src
), dst
, dst_len
, reserved
);
2782 dllname
= StrDupW(src
+ 1);
2783 index_str
= strchrW(dllname
, ',');
2785 if(!index_str
) goto end
;
2789 index
= atoiW(index_str
);
2791 hmod
= LoadLibraryW(dllname
);
2796 if(LoadStringW(hmod
, -index
, dst
, dst_len
))
2800 FIXME("can't handle non-negative indices (%d)\n", index
);
2805 lstrcpynW(dst
, src
, dst_len
);
2809 TRACE("returning %s\n", debugstr_w(dst
));
2811 if(hmod
) FreeLibrary(hmod
);
2812 HeapFree(GetProcessHeap(), 0, dllname
);