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
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
, ARRAY_SIZE(grouping
));
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 characters 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
, ARRAY_SIZE(decimal
), thousand
, ARRAY_SIZE(thousand
));
110 *(--c
) = '0' + (qdwValue
%10);
112 } while (qdwValue
> 0);
116 return GetNumberFormatW(LOCALE_USER_DEFAULT
, 0, c
, &fmt
, pszBuf
, cchBuf
);
119 /*************************************************************************
120 * FormatDouble [internal]
122 * Format an integer according to the current locale. Prints the specified number of digits
123 * after the decimal point
126 * The number of characters written on success or 0 on failure
128 static int FormatDouble(double value
, int decimals
, LPWSTR pszBuf
, int cchBuf
)
130 static const WCHAR flfmt
[] = {'%','f',0};
133 WCHAR decimal
[8], thousand
[8];
135 snprintfW(buf
, 64, flfmt
, value
);
137 FillNumberFmt(&fmt
, decimal
, ARRAY_SIZE(decimal
), thousand
, ARRAY_SIZE(thousand
));
138 fmt
.NumDigits
= decimals
;
139 return GetNumberFormatW(LOCALE_USER_DEFAULT
, 0, buf
, &fmt
, pszBuf
, cchBuf
);
142 /*************************************************************************
143 * SHLWAPI_ChrCmpHelperA
145 * Internal helper for SHLWAPI_ChrCmpA/ChrCMPIA.
148 * Both this function and its Unicode counterpart are very inefficient. To
149 * fix this, CompareString must be completely implemented and optimised
150 * first. Then the core character test can be taken out of that function and
151 * placed here, so that it need never be called at all. Until then, do not
152 * attempt to optimise this code unless you are willing to test that it
153 * still performs correctly.
155 static BOOL
SHLWAPI_ChrCmpHelperA(WORD ch1
, WORD ch2
, DWORD dwFlags
)
157 char str1
[3], str2
[3];
159 str1
[0] = LOBYTE(ch1
);
160 if (IsDBCSLeadByte(str1
[0]))
162 str1
[1] = HIBYTE(ch1
);
168 str2
[0] = LOBYTE(ch2
);
169 if (IsDBCSLeadByte(str2
[0]))
171 str2
[1] = HIBYTE(ch2
);
177 return CompareStringA(GetThreadLocale(), dwFlags
, str1
, -1, str2
, -1) - CSTR_EQUAL
;
180 /*************************************************************************
183 * Internal helper function.
185 static BOOL WINAPI
SHLWAPI_ChrCmpA(WORD ch1
, WORD ch2
)
187 return SHLWAPI_ChrCmpHelperA(ch1
, ch2
, 0);
190 /*************************************************************************
191 * ChrCmpIA (SHLWAPI.385)
193 * Compare two characters, ignoring case.
196 * ch1 [I] First character to compare
197 * ch2 [I] Second character to compare
200 * FALSE, if the characters are equal.
201 * Non-zero otherwise.
203 BOOL WINAPI
ChrCmpIA(WORD ch1
, WORD ch2
)
205 TRACE("(%d,%d)\n", ch1
, ch2
);
207 return SHLWAPI_ChrCmpHelperA(ch1
, ch2
, NORM_IGNORECASE
);
210 /*************************************************************************
211 * ChrCmpIW [SHLWAPI.386]
215 BOOL WINAPI
ChrCmpIW(WCHAR ch1
, WCHAR ch2
)
217 return CompareStringW(GetThreadLocale(), NORM_IGNORECASE
, &ch1
, 1, &ch2
, 1) - CSTR_EQUAL
;
220 /*************************************************************************
221 * StrChrA [SHLWAPI.@]
223 * Find a given character in a string.
226 * lpszStr [I] String to search in.
227 * ch [I] Character to search for.
230 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
232 * Failure: NULL, if any arguments are invalid.
234 LPSTR WINAPI
StrChrA(LPCSTR lpszStr
, WORD ch
)
236 TRACE("(%s,%i)\n", debugstr_a(lpszStr
), ch
);
242 if (!SHLWAPI_ChrCmpA(*lpszStr
, ch
))
243 return (LPSTR
)lpszStr
;
244 lpszStr
= CharNextA(lpszStr
);
250 /*************************************************************************
251 * StrChrW [SHLWAPI.@]
255 LPWSTR WINAPI
StrChrW(LPCWSTR lpszStr
, WCHAR ch
)
257 LPWSTR lpszRet
= NULL
;
259 TRACE("(%s,%i)\n", debugstr_w(lpszStr
), ch
);
262 lpszRet
= strchrW(lpszStr
, ch
);
266 /*************************************************************************
267 * StrChrIA [SHLWAPI.@]
269 * Find a given character in a string, ignoring case.
272 * lpszStr [I] String to search in.
273 * ch [I] Character to search for.
276 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
278 * Failure: NULL, if any arguments are invalid.
280 LPSTR WINAPI
StrChrIA(LPCSTR lpszStr
, WORD ch
)
282 TRACE("(%s,%i)\n", debugstr_a(lpszStr
), ch
);
288 if (!ChrCmpIA(*lpszStr
, ch
))
289 return (LPSTR
)lpszStr
;
290 lpszStr
= CharNextA(lpszStr
);
296 /*************************************************************************
297 * StrChrIW [SHLWAPI.@]
301 LPWSTR WINAPI
StrChrIW(LPCWSTR lpszStr
, WCHAR ch
)
303 TRACE("(%s,%i)\n", debugstr_w(lpszStr
), ch
);
310 if (toupperW(*lpszStr
) == ch
)
311 return (LPWSTR
)lpszStr
;
316 return (LPWSTR
)lpszStr
;
319 /*************************************************************************
320 * StrChrNW [SHLWAPI.@]
322 LPWSTR WINAPI
StrChrNW(LPCWSTR lpszStr
, WCHAR ch
, UINT cchMax
)
324 TRACE("(%s(%i),%i)\n", debugstr_wn(lpszStr
,cchMax
), cchMax
, ch
);
328 while (*lpszStr
&& cchMax
-- > 0)
331 return (LPWSTR
)lpszStr
;
338 /*************************************************************************
339 * StrCmpIW [SHLWAPI.@]
341 * Compare two strings, ignoring case.
344 * lpszStr [I] First string to compare
345 * lpszComp [I] Second string to compare
348 * An integer less than, equal to or greater than 0, indicating that
349 * lpszStr is less than, the same, or greater than lpszComp.
351 int WINAPI
StrCmpIW(LPCWSTR lpszStr
, LPCWSTR lpszComp
)
353 TRACE("(%s,%s)\n", debugstr_w(lpszStr
),debugstr_w(lpszComp
));
354 return CompareStringW(GetThreadLocale(), NORM_IGNORECASE
, lpszStr
, -1, lpszComp
, -1) - CSTR_EQUAL
;
357 /*************************************************************************
358 * StrCmpNA [SHLWAPI.@]
360 * Compare two strings, up to a maximum length.
363 * lpszStr [I] First string to compare
364 * lpszComp [I] Second string to compare
365 * iLen [I] Number of chars to compare
368 * An integer less than, equal to or greater than 0, indicating that
369 * lpszStr is less than, the same, or greater than lpszComp.
371 INT WINAPI
StrCmpNA(LPCSTR lpszStr
, LPCSTR lpszComp
, INT iLen
)
373 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr
), debugstr_a(lpszComp
), iLen
);
374 return CompareStringA(GetThreadLocale(), 0, lpszStr
, iLen
, lpszComp
, iLen
) - CSTR_EQUAL
;
377 /*************************************************************************
378 * StrCmpNW [SHLWAPI.@]
382 INT WINAPI
StrCmpNW(LPCWSTR lpszStr
, LPCWSTR lpszComp
, INT iLen
)
384 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr
), debugstr_w(lpszComp
), iLen
);
385 return CompareStringW(GetThreadLocale(), 0, lpszStr
, iLen
, lpszComp
, iLen
) - CSTR_EQUAL
;
388 /*************************************************************************
389 * StrCmpNIA [SHLWAPI.@]
391 * Compare two strings, up to a maximum length, ignoring case.
394 * lpszStr [I] First string to compare
395 * lpszComp [I] Second string to compare
396 * iLen [I] Number of chars to compare
399 * An integer less than, equal to or greater than 0, indicating that
400 * lpszStr is less than, the same, or greater than lpszComp.
402 int WINAPI
StrCmpNIA(LPCSTR lpszStr
, LPCSTR lpszComp
, int iLen
)
404 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr
), debugstr_a(lpszComp
), iLen
);
405 return CompareStringA(GetThreadLocale(), NORM_IGNORECASE
, lpszStr
, iLen
, lpszComp
, iLen
) - CSTR_EQUAL
;
408 /*************************************************************************
409 * StrCmpNIW [SHLWAPI.@]
413 INT WINAPI
StrCmpNIW(LPCWSTR lpszStr
, LPCWSTR lpszComp
, int iLen
)
415 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr
), debugstr_w(lpszComp
), iLen
);
416 return CompareStringW(GetThreadLocale(), NORM_IGNORECASE
, lpszStr
, iLen
, lpszComp
, iLen
) - CSTR_EQUAL
;
419 /*************************************************************************
420 * StrCmpW [SHLWAPI.@]
422 * Compare two strings.
425 * lpszStr [I] First string to compare
426 * lpszComp [I] Second string to compare
429 * An integer less than, equal to or greater than 0, indicating that
430 * lpszStr is less than, the same, or greater than lpszComp.
432 int WINAPI
StrCmpW(LPCWSTR lpszStr
, LPCWSTR lpszComp
)
434 TRACE("(%s,%s)\n", debugstr_w(lpszStr
), debugstr_w(lpszComp
));
435 return CompareStringW(GetThreadLocale(), 0, lpszStr
, -1, lpszComp
, -1) - CSTR_EQUAL
;
438 /*************************************************************************
439 * StrCatW [SHLWAPI.@]
441 * Concatenate two strings.
444 * lpszStr [O] Initial string
445 * lpszSrc [I] String to concatenate
450 LPWSTR WINAPI
StrCatW(LPWSTR lpszStr
, LPCWSTR lpszSrc
)
452 TRACE("(%s,%s)\n", debugstr_w(lpszStr
), debugstr_w(lpszSrc
));
454 if (lpszStr
&& lpszSrc
)
455 strcatW(lpszStr
, lpszSrc
);
459 /*************************************************************************
460 * StrCatChainW [SHLWAPI.@]
462 * Concatenates two unicode strings.
465 * lpszStr [O] Initial string
466 * cchMax [I] Length of destination buffer
467 * ichAt [I] Offset from the destination buffer to begin concatenation
468 * lpszCat [I] String to concatenate
471 * The offset from the beginning of pszDst to the terminating NULL.
473 DWORD WINAPI
StrCatChainW(LPWSTR lpszStr
, DWORD cchMax
, DWORD ichAt
, LPCWSTR lpszCat
)
475 TRACE("(%s,%u,%d,%s)\n", debugstr_w(lpszStr
), cchMax
, ichAt
, debugstr_w(lpszCat
));
478 ichAt
= strlenW(lpszStr
);
486 if (lpszCat
&& ichAt
< cchMax
)
489 while (ichAt
< cchMax
- 1 && *lpszCat
)
491 *lpszStr
++ = *lpszCat
++;
500 /*************************************************************************
501 * StrCpyW [SHLWAPI.@]
503 * Copy a string to another string.
506 * lpszStr [O] Destination string
507 * lpszSrc [I] Source string
512 LPWSTR WINAPI
StrCpyW(LPWSTR lpszStr
, LPCWSTR lpszSrc
)
514 TRACE("(%p,%s)\n", lpszStr
, debugstr_w(lpszSrc
));
516 if (lpszStr
&& lpszSrc
)
517 strcpyW(lpszStr
, lpszSrc
);
521 /*************************************************************************
522 * StrCpyNW [SHLWAPI.@]
524 * Copy a string to another string, up to a maximum number of characters.
527 * dst [O] Destination string
528 * src [I] Source string
529 * count [I] Maximum number of chars to copy
534 LPWSTR WINAPI
StrCpyNW(LPWSTR dst
, LPCWSTR src
, int count
)
539 TRACE("(%p,%s,%i)\n", dst
, debugstr_w(src
), count
);
543 while ((count
> 1) && *s
)
554 /*************************************************************************
555 * SHLWAPI_StrStrHelperA
557 * Internal implementation of StrStrA/StrStrIA
559 static LPSTR
SHLWAPI_StrStrHelperA(LPCSTR lpszStr
, LPCSTR lpszSearch
,
560 INT (WINAPI
*pStrCmpFn
)(LPCSTR
,LPCSTR
,INT
))
565 if (!lpszStr
|| !lpszSearch
|| !*lpszSearch
)
568 iLen
= strlen(lpszSearch
);
569 end
= lpszStr
+ strlen(lpszStr
);
571 while (lpszStr
+ iLen
<= end
)
573 if (!pStrCmpFn(lpszStr
, lpszSearch
, iLen
))
574 return (LPSTR
)lpszStr
;
575 lpszStr
= CharNextA(lpszStr
);
580 /*************************************************************************
581 * StrStrA [SHLWAPI.@]
583 * Find a substring within a string.
586 * lpszStr [I] String to search in
587 * lpszSearch [I] String to look for
590 * The start of lpszSearch within lpszStr, or NULL if not found.
592 LPSTR WINAPI
StrStrA(LPCSTR lpszStr
, LPCSTR lpszSearch
)
594 TRACE("(%s,%s)\n", debugstr_a(lpszStr
), debugstr_a(lpszSearch
));
596 return SHLWAPI_StrStrHelperA(lpszStr
, lpszSearch
, StrCmpNA
);
599 /*************************************************************************
600 * StrStrW [SHLWAPI.@]
604 LPWSTR WINAPI
StrStrW(LPCWSTR lpszStr
, LPCWSTR lpszSearch
)
606 TRACE("(%s, %s)\n", debugstr_w(lpszStr
), debugstr_w(lpszSearch
));
608 if (!lpszStr
|| !lpszSearch
|| !*lpszSearch
) return NULL
;
609 return strstrW( lpszStr
, lpszSearch
);
612 /*************************************************************************
613 * StrRStrIA [SHLWAPI.@]
615 * Find the last occurrence of a substring within a string.
618 * lpszStr [I] String to search in
619 * lpszEnd [I] End of lpszStr
620 * lpszSearch [I] String to look for
623 * The last occurrence lpszSearch within lpszStr, or NULL if not found.
625 LPSTR WINAPI
StrRStrIA(LPCSTR lpszStr
, LPCSTR lpszEnd
, LPCSTR lpszSearch
)
627 LPSTR lpszRet
= NULL
;
631 TRACE("(%s,%s)\n", debugstr_a(lpszStr
), debugstr_a(lpszSearch
));
633 if (!lpszStr
|| !lpszSearch
|| !*lpszSearch
)
636 if (IsDBCSLeadByte(*lpszSearch
))
637 ch1
= *lpszSearch
<< 8 | (UCHAR
)lpszSearch
[1];
640 iLen
= lstrlenA(lpszSearch
);
643 lpszEnd
= lpszStr
+ lstrlenA(lpszStr
);
644 else /* reproduce the broken behaviour on Windows */
645 lpszEnd
+= min(iLen
- 1, lstrlenA(lpszEnd
));
647 while (lpszStr
+ iLen
<= lpszEnd
&& *lpszStr
)
649 ch2
= IsDBCSLeadByte(*lpszStr
)? *lpszStr
<< 8 | (UCHAR
)lpszStr
[1] : *lpszStr
;
650 if (!ChrCmpIA(ch1
, ch2
))
652 if (!StrCmpNIA(lpszStr
, lpszSearch
, iLen
))
653 lpszRet
= (LPSTR
)lpszStr
;
655 lpszStr
= CharNextA(lpszStr
);
660 /*************************************************************************
661 * StrRStrIW [SHLWAPI.@]
665 LPWSTR WINAPI
StrRStrIW(LPCWSTR lpszStr
, LPCWSTR lpszEnd
, LPCWSTR lpszSearch
)
667 LPWSTR lpszRet
= NULL
;
670 TRACE("(%s,%s)\n", debugstr_w(lpszStr
), debugstr_w(lpszSearch
));
672 if (!lpszStr
|| !lpszSearch
|| !*lpszSearch
)
675 iLen
= strlenW(lpszSearch
);
678 lpszEnd
= lpszStr
+ strlenW(lpszStr
);
679 else /* reproduce the broken behaviour on Windows */
680 lpszEnd
+= min(iLen
- 1, lstrlenW(lpszEnd
));
682 while (lpszStr
+ iLen
<= lpszEnd
&& *lpszStr
)
684 if (!ChrCmpIW(*lpszSearch
, *lpszStr
))
686 if (!StrCmpNIW(lpszStr
, lpszSearch
, iLen
))
687 lpszRet
= (LPWSTR
)lpszStr
;
694 /*************************************************************************
695 * StrStrIA [SHLWAPI.@]
697 * Find a substring within a string, ignoring case.
700 * lpszStr [I] String to search in
701 * lpszSearch [I] String to look for
704 * The start of lpszSearch within lpszStr, or NULL if not found.
706 LPSTR WINAPI
StrStrIA(LPCSTR lpszStr
, LPCSTR lpszSearch
)
708 TRACE("(%s,%s)\n", debugstr_a(lpszStr
), debugstr_a(lpszSearch
));
710 return SHLWAPI_StrStrHelperA(lpszStr
, lpszSearch
, StrCmpNIA
);
713 /*************************************************************************
714 * StrStrIW [SHLWAPI.@]
718 LPWSTR WINAPI
StrStrIW(LPCWSTR lpszStr
, LPCWSTR lpszSearch
)
723 TRACE("(%s,%s)\n", debugstr_w(lpszStr
), debugstr_w(lpszSearch
));
725 if (!lpszStr
|| !lpszSearch
|| !*lpszSearch
)
728 iLen
= strlenW(lpszSearch
);
729 end
= lpszStr
+ strlenW(lpszStr
);
731 while (lpszStr
+ iLen
<= end
)
733 if (!StrCmpNIW(lpszStr
, lpszSearch
, iLen
))
734 return (LPWSTR
)lpszStr
;
740 /*************************************************************************
741 * StrStrNW [SHLWAPI.@]
743 * Find a substring within a string up to a given number of initial characters.
746 * lpFirst [I] String to search in
747 * lpSrch [I] String to look for
748 * cchMax [I] Maximum number of initial search characters
751 * The start of lpFirst within lpSrch, or NULL if not found.
753 LPWSTR WINAPI
StrStrNW(LPCWSTR lpFirst
, LPCWSTR lpSrch
, UINT cchMax
)
758 TRACE("(%s, %s, %u)\n", debugstr_w(lpFirst
), debugstr_w(lpSrch
), cchMax
);
760 if (!lpFirst
|| !lpSrch
|| !*lpSrch
|| !cchMax
)
763 len
= strlenW(lpSrch
);
765 for (i
= cchMax
; *lpFirst
&& (i
> 0); i
--, lpFirst
++)
767 if (!strncmpW(lpFirst
, lpSrch
, len
))
768 return (LPWSTR
)lpFirst
;
774 /*************************************************************************
775 * StrStrNIW [SHLWAPI.@]
777 * Find a substring within a string up to a given number of initial characters,
781 * lpFirst [I] String to search in
782 * lpSrch [I] String to look for
783 * cchMax [I] Maximum number of initial search characters
786 * The start of lpFirst within lpSrch, or NULL if not found.
788 LPWSTR WINAPI
StrStrNIW(LPCWSTR lpFirst
, LPCWSTR lpSrch
, UINT cchMax
)
793 TRACE("(%s, %s, %u)\n", debugstr_w(lpFirst
), debugstr_w(lpSrch
), cchMax
);
795 if (!lpFirst
|| !lpSrch
|| !*lpSrch
|| !cchMax
)
798 len
= strlenW(lpSrch
);
800 for (i
= cchMax
; *lpFirst
&& (i
> 0); i
--, lpFirst
++)
802 if (!strncmpiW(lpFirst
, lpSrch
, len
))
803 return (LPWSTR
)lpFirst
;
809 /*************************************************************************
810 * StrToIntA [SHLWAPI.@]
812 * Read a signed integer from a string.
815 * lpszStr [I] String to read integer from
818 * The signed integer value represented by the string, or 0 if no integer is
822 * No leading space is allowed before the number, although a leading '-' is.
824 int WINAPI
StrToIntA(LPCSTR lpszStr
)
828 TRACE("(%s)\n", debugstr_a(lpszStr
));
832 WARN("Invalid lpszStr would crash under Win32!\n");
836 if (*lpszStr
== '-' || isdigit(*lpszStr
))
837 StrToIntExA(lpszStr
, 0, &iRet
);
841 /*************************************************************************
842 * StrToIntW [SHLWAPI.@]
846 int WINAPI
StrToIntW(LPCWSTR lpszStr
)
850 TRACE("(%s)\n", debugstr_w(lpszStr
));
854 WARN("Invalid lpszStr would crash under Win32!\n");
858 if (*lpszStr
== '-' || isdigitW(*lpszStr
))
859 StrToIntExW(lpszStr
, 0, &iRet
);
863 /*************************************************************************
864 * StrToIntExA [SHLWAPI.@]
866 * Read an integer from a string.
869 * lpszStr [I] String to read integer from
870 * dwFlags [I] Flags controlling the conversion
871 * lpiRet [O] Destination for read integer.
874 * Success: TRUE. lpiRet contains the integer value represented by the string.
875 * Failure: FALSE, if the string is invalid, or no number is present.
878 * Leading whitespace, '-' and '+' are allowed before the number. If
879 * dwFlags includes STIF_SUPPORT_HEX, hexadecimal numbers are allowed, if
880 * preceded by '0x'. If this flag is not set, or there is no '0x' prefix,
881 * the string is treated as a decimal string. A leading '-' is ignored for
882 * hexadecimal numbers.
884 BOOL WINAPI
StrToIntExA(LPCSTR lpszStr
, DWORD dwFlags
, LPINT lpiRet
)
889 TRACE("(%s,%08X,%p)\n", debugstr_a(lpszStr
), dwFlags
, lpiRet
);
891 bRes
= StrToInt64ExA(lpszStr
, dwFlags
, &li
);
892 if (bRes
) *lpiRet
= li
;
896 /*************************************************************************
897 * StrToInt64ExA [SHLWAPI.@]
901 BOOL WINAPI
StrToInt64ExA(LPCSTR lpszStr
, DWORD dwFlags
, LONGLONG
*lpiRet
)
903 BOOL bNegative
= FALSE
;
906 TRACE("(%s,%08X,%p)\n", debugstr_a(lpszStr
), dwFlags
, lpiRet
);
908 if (!lpszStr
|| !lpiRet
)
910 WARN("Invalid parameter would crash under Win32!\n");
913 if (dwFlags
> STIF_SUPPORT_HEX
) WARN("Unknown flags %08x\n", dwFlags
);
915 /* Skip leading space, '+', '-' */
916 while (isspace(*lpszStr
))
917 lpszStr
= CharNextA(lpszStr
);
924 else if (*lpszStr
== '+')
927 if (dwFlags
& STIF_SUPPORT_HEX
&&
928 *lpszStr
== '0' && tolower(lpszStr
[1]) == 'x')
930 /* Read hex number */
933 if (!isxdigit(*lpszStr
))
936 while (isxdigit(*lpszStr
))
939 if (isdigit(*lpszStr
))
940 iRet
+= (*lpszStr
- '0');
942 iRet
+= 10 + (tolower(*lpszStr
) - 'a');
949 /* Read decimal number */
950 if (!isdigit(*lpszStr
))
953 while (isdigit(*lpszStr
))
956 iRet
+= (*lpszStr
- '0');
959 *lpiRet
= bNegative
? -iRet
: iRet
;
963 /*************************************************************************
964 * StrToIntExW [SHLWAPI.@]
968 BOOL WINAPI
StrToIntExW(LPCWSTR lpszStr
, DWORD dwFlags
, LPINT lpiRet
)
973 TRACE("(%s,%08X,%p)\n", debugstr_w(lpszStr
), dwFlags
, lpiRet
);
975 bRes
= StrToInt64ExW(lpszStr
, dwFlags
, &li
);
976 if (bRes
) *lpiRet
= li
;
980 /*************************************************************************
981 * StrToInt64ExW [SHLWAPI.@]
985 BOOL WINAPI
StrToInt64ExW(LPCWSTR lpszStr
, DWORD dwFlags
, LONGLONG
*lpiRet
)
987 BOOL bNegative
= FALSE
;
990 TRACE("(%s,%08X,%p)\n", debugstr_w(lpszStr
), dwFlags
, lpiRet
);
992 if (!lpszStr
|| !lpiRet
)
994 WARN("Invalid parameter would crash under Win32!\n");
997 if (dwFlags
> STIF_SUPPORT_HEX
) WARN("Unknown flags %08x\n", dwFlags
);
999 /* Skip leading space, '+', '-' */
1000 while (isspaceW(*lpszStr
)) lpszStr
++;
1002 if (*lpszStr
== '-')
1007 else if (*lpszStr
== '+')
1010 if (dwFlags
& STIF_SUPPORT_HEX
&&
1011 *lpszStr
== '0' && tolowerW(lpszStr
[1]) == 'x')
1013 /* Read hex number */
1016 if (!isxdigitW(*lpszStr
))
1019 while (isxdigitW(*lpszStr
))
1022 if (isdigitW(*lpszStr
))
1023 iRet
+= (*lpszStr
- '0');
1025 iRet
+= 10 + (tolowerW(*lpszStr
) - 'a');
1032 /* Read decimal number */
1033 if (!isdigitW(*lpszStr
))
1036 while (isdigitW(*lpszStr
))
1039 iRet
+= (*lpszStr
- '0');
1042 *lpiRet
= bNegative
? -iRet
: iRet
;
1046 /*************************************************************************
1047 * StrDupA [SHLWAPI.@]
1049 * Duplicate a string.
1052 * lpszStr [I] String to duplicate.
1055 * Success: A pointer to a new string containing the contents of lpszStr
1056 * Failure: NULL, if memory cannot be allocated
1059 * The string memory is allocated with LocalAlloc(), and so should be released
1060 * by calling LocalFree().
1062 LPSTR WINAPI
StrDupA(LPCSTR lpszStr
)
1067 TRACE("(%s)\n",debugstr_a(lpszStr
));
1069 iLen
= lpszStr
? strlen(lpszStr
) + 1 : 1;
1070 lpszRet
= LocalAlloc(LMEM_FIXED
, iLen
);
1075 memcpy(lpszRet
, lpszStr
, iLen
);
1082 /*************************************************************************
1083 * StrDupW [SHLWAPI.@]
1087 LPWSTR WINAPI
StrDupW(LPCWSTR lpszStr
)
1092 TRACE("(%s)\n",debugstr_w(lpszStr
));
1094 iLen
= (lpszStr
? strlenW(lpszStr
) + 1 : 1) * sizeof(WCHAR
);
1095 lpszRet
= LocalAlloc(LMEM_FIXED
, iLen
);
1100 memcpy(lpszRet
, lpszStr
, iLen
);
1107 /*************************************************************************
1108 * SHLWAPI_StrSpnHelperA
1110 * Internal implementation of StrSpnA/StrCSpnA/StrCSpnIA
1112 static int SHLWAPI_StrSpnHelperA(LPCSTR lpszStr
, LPCSTR lpszMatch
,
1113 LPSTR (WINAPI
*pStrChrFn
)(LPCSTR
,WORD
),
1116 LPCSTR lpszRead
= lpszStr
;
1117 if (lpszStr
&& *lpszStr
&& lpszMatch
)
1121 LPCSTR lpszTest
= pStrChrFn(lpszMatch
, *lpszRead
);
1123 if (!bInvert
&& !lpszTest
)
1125 if (bInvert
&& lpszTest
)
1127 lpszRead
= CharNextA(lpszRead
);
1130 return lpszRead
- lpszStr
;
1133 /*************************************************************************
1134 * StrSpnA [SHLWAPI.@]
1136 * Find the length of the start of a string that contains only certain
1140 * lpszStr [I] String to search
1141 * lpszMatch [I] Characters that can be in the substring
1144 * The length of the part of lpszStr containing only chars from lpszMatch,
1145 * or 0 if any parameter is invalid.
1147 int WINAPI
StrSpnA(LPCSTR lpszStr
, LPCSTR lpszMatch
)
1149 TRACE("(%s,%s)\n",debugstr_a(lpszStr
), debugstr_a(lpszMatch
));
1151 return SHLWAPI_StrSpnHelperA(lpszStr
, lpszMatch
, StrChrA
, FALSE
);
1154 /*************************************************************************
1155 * StrSpnW [SHLWAPI.@]
1159 int WINAPI
StrSpnW(LPCWSTR lpszStr
, LPCWSTR lpszMatch
)
1161 if (!lpszStr
|| !lpszMatch
) return 0;
1162 return strspnW( lpszStr
, lpszMatch
);
1165 /*************************************************************************
1166 * StrCSpnA [SHLWAPI.@]
1168 * Find the length of the start of a string that does not contain certain
1172 * lpszStr [I] String to search
1173 * lpszMatch [I] Characters that cannot be in the substring
1176 * The length of the part of lpszStr containing only chars not in lpszMatch,
1177 * or 0 if any parameter is invalid.
1179 int WINAPI
StrCSpnA(LPCSTR lpszStr
, LPCSTR lpszMatch
)
1181 TRACE("(%s,%s)\n",debugstr_a(lpszStr
), debugstr_a(lpszMatch
));
1183 return SHLWAPI_StrSpnHelperA(lpszStr
, lpszMatch
, StrChrA
, TRUE
);
1186 /*************************************************************************
1187 * StrCSpnW [SHLWAPI.@]
1191 int WINAPI
StrCSpnW(LPCWSTR lpszStr
, LPCWSTR lpszMatch
)
1193 if (!lpszStr
|| !lpszMatch
) return 0;
1194 return strcspnW( lpszStr
, lpszMatch
);
1197 /*************************************************************************
1198 * StrCSpnIA [SHLWAPI.@]
1200 * Find the length of the start of a string that does not contain certain
1201 * characters, ignoring case.
1204 * lpszStr [I] String to search
1205 * lpszMatch [I] Characters that cannot be in the substring
1208 * The length of the part of lpszStr containing only chars not in lpszMatch,
1209 * or 0 if any parameter is invalid.
1211 int WINAPI
StrCSpnIA(LPCSTR lpszStr
, LPCSTR lpszMatch
)
1213 TRACE("(%s,%s)\n",debugstr_a(lpszStr
), debugstr_a(lpszMatch
));
1215 return SHLWAPI_StrSpnHelperA(lpszStr
, lpszMatch
, StrChrIA
, TRUE
);
1218 /*************************************************************************
1219 * StrCSpnIW [SHLWAPI.@]
1223 int WINAPI
StrCSpnIW(LPCWSTR lpszStr
, LPCWSTR lpszMatch
)
1225 LPCWSTR lpszRead
= lpszStr
;
1227 TRACE("(%s,%s)\n",debugstr_w(lpszStr
), debugstr_w(lpszMatch
));
1229 if (lpszStr
&& *lpszStr
&& lpszMatch
)
1233 if (StrChrIW(lpszMatch
, *lpszRead
)) break;
1237 return lpszRead
- lpszStr
;
1240 /*************************************************************************
1241 * StrPBrkA [SHLWAPI.@]
1243 * Search a string for any of a group of characters.
1246 * lpszStr [I] String to search
1247 * lpszMatch [I] Characters to match
1250 * A pointer to the first matching character in lpszStr, or NULL if no
1253 LPSTR WINAPI
StrPBrkA(LPCSTR lpszStr
, LPCSTR lpszMatch
)
1255 TRACE("(%s,%s)\n",debugstr_a(lpszStr
), debugstr_a(lpszMatch
));
1257 if (lpszStr
&& lpszMatch
&& *lpszMatch
)
1261 if (StrChrA(lpszMatch
, *lpszStr
))
1262 return (LPSTR
)lpszStr
;
1263 lpszStr
= CharNextA(lpszStr
);
1269 /*************************************************************************
1270 * StrPBrkW [SHLWAPI.@]
1274 LPWSTR WINAPI
StrPBrkW(LPCWSTR lpszStr
, LPCWSTR lpszMatch
)
1276 if (!lpszStr
|| !lpszMatch
) return NULL
;
1277 return strpbrkW( lpszStr
, lpszMatch
);
1280 /*************************************************************************
1281 * SHLWAPI_StrRChrHelperA
1283 * Internal implementation of StrRChrA/StrRChrIA.
1285 static LPSTR
SHLWAPI_StrRChrHelperA(LPCSTR lpszStr
,
1286 LPCSTR lpszEnd
, WORD ch
,
1287 BOOL (WINAPI
*pChrCmpFn
)(WORD
,WORD
))
1289 LPCSTR lpszRet
= NULL
;
1296 lpszEnd
= lpszStr
+ lstrlenA(lpszStr
);
1298 while (*lpszStr
&& lpszStr
<= lpszEnd
)
1300 ch2
= IsDBCSLeadByte(*lpszStr
)? *lpszStr
<< 8 | lpszStr
[1] : *lpszStr
;
1302 if (!pChrCmpFn(ch
, ch2
))
1304 lpszStr
= CharNextA(lpszStr
);
1307 return (LPSTR
)lpszRet
;
1310 /**************************************************************************
1311 * StrRChrA [SHLWAPI.@]
1313 * Find the last occurrence of a character in string.
1316 * lpszStr [I] String to search in
1317 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1318 * ch [I] Character to search for.
1321 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1322 * or NULL if not found.
1323 * Failure: NULL, if any arguments are invalid.
1325 LPSTR WINAPI
StrRChrA(LPCSTR lpszStr
, LPCSTR lpszEnd
, WORD ch
)
1327 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr
), debugstr_a(lpszEnd
), ch
);
1329 return SHLWAPI_StrRChrHelperA(lpszStr
, lpszEnd
, ch
, SHLWAPI_ChrCmpA
);
1332 /**************************************************************************
1333 * StrRChrW [SHLWAPI.@]
1337 LPWSTR WINAPI
StrRChrW(LPCWSTR str
, LPCWSTR end
, WORD ch
)
1341 if (!str
) return NULL
;
1342 if (!end
) end
= str
+ strlenW(str
);
1345 if (*str
== ch
) ret
= (WCHAR
*)str
;
1351 /**************************************************************************
1352 * StrRChrIA [SHLWAPI.@]
1354 * Find the last occurrence of a character in string, ignoring case.
1357 * lpszStr [I] String to search in
1358 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1359 * ch [I] Character to search for.
1362 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1363 * or NULL if not found.
1364 * Failure: NULL, if any arguments are invalid.
1366 LPSTR WINAPI
StrRChrIA(LPCSTR lpszStr
, LPCSTR lpszEnd
, WORD ch
)
1368 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr
), debugstr_a(lpszEnd
), ch
);
1370 return SHLWAPI_StrRChrHelperA(lpszStr
, lpszEnd
, ch
, ChrCmpIA
);
1373 /**************************************************************************
1374 * StrRChrIW [SHLWAPI.@]
1378 LPWSTR WINAPI
StrRChrIW(LPCWSTR str
, LPCWSTR end
, WORD ch
)
1382 if (!str
) return NULL
;
1383 if (!end
) end
= str
+ strlenW(str
);
1386 if (!ChrCmpIW(*str
, ch
)) ret
= (WCHAR
*)str
;
1392 /*************************************************************************
1393 * StrCatBuffA [SHLWAPI.@]
1395 * Concatenate two strings together.
1398 * lpszStr [O] String to concatenate to
1399 * lpszCat [I] String to add to lpszCat
1400 * cchMax [I] Maximum number of characters for the whole string
1406 * cchMax determines the number of characters in the final length of the
1407 * string, not the number appended to lpszStr from lpszCat.
1409 LPSTR WINAPI
StrCatBuffA(LPSTR lpszStr
, LPCSTR lpszCat
, INT cchMax
)
1413 TRACE("(%p,%s,%d)\n", lpszStr
, debugstr_a(lpszCat
), cchMax
);
1417 WARN("Invalid lpszStr would crash under Win32!\n");
1421 iLen
= strlen(lpszStr
);
1425 StrCpyNA(lpszStr
+ iLen
, lpszCat
, cchMax
);
1429 /*************************************************************************
1430 * StrCatBuffW [SHLWAPI.@]
1434 LPWSTR WINAPI
StrCatBuffW(LPWSTR lpszStr
, LPCWSTR lpszCat
, INT cchMax
)
1438 TRACE("(%p,%s,%d)\n", lpszStr
, debugstr_w(lpszCat
), cchMax
);
1442 WARN("Invalid lpszStr would crash under Win32!\n");
1446 iLen
= strlenW(lpszStr
);
1450 StrCpyNW(lpszStr
+ iLen
, lpszCat
, cchMax
);
1454 /*************************************************************************
1455 * StrRetToBufA [SHLWAPI.@]
1457 * Convert a STRRET to a normal string.
1460 * lpStrRet [O] STRRET to convert
1461 * pIdl [I] ITEMIDLIST for lpStrRet->uType == STRRET_OFFSET
1462 * lpszDest [O] Destination for normal string
1463 * dwLen [I] Length of lpszDest
1466 * Success: S_OK. lpszDest contains up to dwLen characters of the string.
1467 * If lpStrRet is of type STRRET_WSTR, its memory is freed with
1468 * CoTaskMemFree() and its type set to STRRET_CSTRA.
1469 * Failure: E_FAIL, if any parameters are invalid.
1471 HRESULT WINAPI
StrRetToBufA (LPSTRRET src
, const ITEMIDLIST
*pidl
, LPSTR dest
, UINT len
)
1474 * This routine is identical to that in dlls/shell32/shellstring.c.
1475 * It was duplicated because not every version of Shlwapi.dll exports
1476 * StrRetToBufA. If you change one routine, change them both.
1478 TRACE("dest=%p len=0x%x strret=%p pidl=%p\n", dest
, len
, src
, pidl
);
1482 WARN("Invalid lpStrRet would crash under Win32!\n");
1496 WideCharToMultiByte(CP_ACP
, 0, src
->u
.pOleStr
, -1, dest
, len
, NULL
, NULL
);
1497 CoTaskMemFree(src
->u
.pOleStr
);
1501 lstrcpynA(dest
, src
->u
.cStr
, len
);
1505 lstrcpynA((LPSTR
)dest
, ((LPCSTR
)&pidl
->mkid
)+src
->u
.uOffset
, len
);
1509 FIXME("unknown type!\n");
1515 /*************************************************************************
1516 * StrRetToBufW [SHLWAPI.@]
1520 HRESULT WINAPI
StrRetToBufW (LPSTRRET src
, const ITEMIDLIST
*pidl
, LPWSTR dest
, UINT len
)
1522 TRACE("dest=%p len=0x%x strret=%p pidl=%p\n", dest
, len
, src
, pidl
);
1529 WARN("Invalid lpStrRet would crash under Win32!\n");
1536 switch (src
->uType
) {
1539 if (!src
->u
.pOleStr
)
1541 dst_len
= strlenW(src
->u
.pOleStr
);
1542 memcpy(dest
, src
->u
.pOleStr
, min(dst_len
, len
-1) * sizeof(WCHAR
));
1543 dest
[min(dst_len
, len
-1)] = 0;
1544 CoTaskMemFree(src
->u
.pOleStr
);
1548 return E_NOT_SUFFICIENT_BUFFER
;
1554 if (!MultiByteToWideChar( CP_ACP
, 0, src
->u
.cStr
, -1, dest
, len
))
1561 if (!MultiByteToWideChar( CP_ACP
, 0, ((LPCSTR
)&pidl
->mkid
)+src
->u
.uOffset
, -1,
1568 FIXME("unknown type!\n");
1575 /*************************************************************************
1576 * StrRetToStrA [SHLWAPI.@]
1578 * Converts a STRRET to a normal string.
1581 * lpStrRet [O] STRRET to convert
1582 * pidl [I] ITEMIDLIST for lpStrRet->uType == STRRET_OFFSET
1583 * ppszName [O] Destination for converted string
1586 * Success: S_OK. ppszName contains the new string, allocated with CoTaskMemAlloc().
1587 * Failure: E_FAIL, if any parameters are invalid.
1589 HRESULT WINAPI
StrRetToStrA(LPSTRRET lpStrRet
, const ITEMIDLIST
*pidl
, LPSTR
*ppszName
)
1591 HRESULT hRet
= E_FAIL
;
1593 switch (lpStrRet
->uType
)
1596 hRet
= _SHStrDupAW(lpStrRet
->u
.pOleStr
, ppszName
);
1597 CoTaskMemFree(lpStrRet
->u
.pOleStr
);
1601 hRet
= _SHStrDupAA(lpStrRet
->u
.cStr
, ppszName
);
1605 hRet
= _SHStrDupAA(((LPCSTR
)&pidl
->mkid
) + lpStrRet
->u
.uOffset
, ppszName
);
1615 /*************************************************************************
1616 * StrRetToStrW [SHLWAPI.@]
1620 HRESULT WINAPI
StrRetToStrW(LPSTRRET lpStrRet
, const ITEMIDLIST
*pidl
, LPWSTR
*ppszName
)
1622 HRESULT hRet
= E_FAIL
;
1624 switch (lpStrRet
->uType
)
1627 hRet
= SHStrDupW(lpStrRet
->u
.pOleStr
, ppszName
);
1628 CoTaskMemFree(lpStrRet
->u
.pOleStr
);
1632 hRet
= SHStrDupA(lpStrRet
->u
.cStr
, ppszName
);
1636 hRet
= SHStrDupA(((LPCSTR
)&pidl
->mkid
) + lpStrRet
->u
.uOffset
, ppszName
);
1646 /* Create an ASCII string copy using SysAllocString() */
1647 static HRESULT
_SHStrDupAToBSTR(LPCSTR src
, BSTR
*pBstrOut
)
1653 INT len
= MultiByteToWideChar(CP_ACP
, 0, src
, -1, NULL
, 0);
1654 WCHAR
* szTemp
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1658 MultiByteToWideChar(CP_ACP
, 0, src
, -1, szTemp
, len
);
1659 *pBstrOut
= SysAllocString(szTemp
);
1660 HeapFree(GetProcessHeap(), 0, szTemp
);
1666 return E_OUTOFMEMORY
;
1669 /*************************************************************************
1670 * StrRetToBSTR [SHLWAPI.@]
1672 * Converts a STRRET to a BSTR.
1675 * lpStrRet [O] STRRET to convert
1676 * pidl [I] ITEMIDLIST for lpStrRet->uType = STRRET_OFFSET
1677 * pBstrOut [O] Destination for converted BSTR
1680 * Success: S_OK. pBstrOut contains the new string.
1681 * Failure: E_FAIL, if any parameters are invalid.
1683 HRESULT WINAPI
StrRetToBSTR(STRRET
*lpStrRet
, LPCITEMIDLIST pidl
, BSTR
* pBstrOut
)
1685 HRESULT hRet
= E_FAIL
;
1687 switch (lpStrRet
->uType
)
1690 *pBstrOut
= SysAllocString(lpStrRet
->u
.pOleStr
);
1693 CoTaskMemFree(lpStrRet
->u
.pOleStr
);
1697 hRet
= _SHStrDupAToBSTR(lpStrRet
->u
.cStr
, pBstrOut
);
1701 hRet
= _SHStrDupAToBSTR(((LPCSTR
)&pidl
->mkid
) + lpStrRet
->u
.uOffset
, pBstrOut
);
1711 /*************************************************************************
1712 * StrFormatKBSizeA [SHLWAPI.@]
1714 * Create a formatted string containing a byte count in Kilobytes.
1717 * llBytes [I] Byte size to format
1718 * lpszDest [I] Destination for formatted string
1719 * cchMax [I] Size of lpszDest
1724 LPSTR WINAPI
StrFormatKBSizeA(LONGLONG llBytes
, LPSTR lpszDest
, UINT cchMax
)
1728 if (!StrFormatKBSizeW(llBytes
, wszBuf
, 256))
1730 if (!WideCharToMultiByte(CP_ACP
, 0, wszBuf
, -1, lpszDest
, cchMax
, NULL
, NULL
))
1735 /*************************************************************************
1736 * StrFormatKBSizeW [SHLWAPI.@]
1738 * See StrFormatKBSizeA.
1740 LPWSTR WINAPI
StrFormatKBSizeW(LONGLONG llBytes
, LPWSTR lpszDest
, UINT cchMax
)
1742 static const WCHAR kb
[] = {' ','K','B',0};
1743 LONGLONG llKB
= (llBytes
+ 1023) >> 10;
1746 TRACE("(0x%s,%p,%d)\n", wine_dbgstr_longlong(llBytes
), lpszDest
, cchMax
);
1748 if (!FormatInt(llKB
, lpszDest
, cchMax
))
1751 len
= lstrlenW(lpszDest
);
1752 if (cchMax
- len
< 4)
1754 lstrcatW(lpszDest
, kb
);
1758 /*************************************************************************
1759 * StrNCatA [SHLWAPI.@]
1761 * Concatenate two strings together.
1764 * lpszStr [O] String to concatenate to
1765 * lpszCat [I] String to add to lpszCat
1766 * cchMax [I] Maximum number of characters to concatenate
1772 * cchMax determines the number of characters that are appended to lpszStr,
1773 * not the total length of the string.
1775 LPSTR WINAPI
StrNCatA(LPSTR lpszStr
, LPCSTR lpszCat
, INT cchMax
)
1777 LPSTR lpszRet
= lpszStr
;
1779 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr
), debugstr_a(lpszCat
), cchMax
);
1783 WARN("Invalid lpszStr would crash under Win32!\n");
1787 StrCpyNA(lpszStr
+ strlen(lpszStr
), lpszCat
, cchMax
);
1791 /*************************************************************************
1792 * StrNCatW [SHLWAPI.@]
1796 LPWSTR WINAPI
StrNCatW(LPWSTR lpszStr
, LPCWSTR lpszCat
, INT cchMax
)
1798 LPWSTR lpszRet
= lpszStr
;
1800 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr
), debugstr_w(lpszCat
), cchMax
);
1804 WARN("Invalid lpszStr would crash under Win32\n");
1808 StrCpyNW(lpszStr
+ strlenW(lpszStr
), lpszCat
, cchMax
);
1812 /*************************************************************************
1813 * StrTrimA [SHLWAPI.@]
1815 * Remove characters from the start and end of a string.
1818 * lpszStr [O] String to remove characters from
1819 * lpszTrim [I] Characters to remove from lpszStr
1822 * TRUE If lpszStr was valid and modified
1825 BOOL WINAPI
StrTrimA(LPSTR lpszStr
, LPCSTR lpszTrim
)
1828 LPSTR lpszRead
= lpszStr
;
1831 TRACE("(%s,%s)\n", debugstr_a(lpszStr
), debugstr_a(lpszTrim
));
1833 if (lpszRead
&& *lpszRead
)
1835 while (*lpszRead
&& StrChrA(lpszTrim
, *lpszRead
))
1836 lpszRead
= CharNextA(lpszRead
); /* Skip leading matches */
1838 dwLen
= strlen(lpszRead
);
1840 if (lpszRead
!= lpszStr
)
1842 memmove(lpszStr
, lpszRead
, dwLen
+ 1);
1847 lpszRead
= lpszStr
+ dwLen
;
1848 while (StrChrA(lpszTrim
, lpszRead
[-1]))
1849 lpszRead
= CharPrevA(lpszStr
, lpszRead
); /* Skip trailing matches */
1851 if (lpszRead
!= lpszStr
+ dwLen
)
1861 /*************************************************************************
1862 * StrTrimW [SHLWAPI.@]
1866 BOOL WINAPI
StrTrimW(LPWSTR lpszStr
, LPCWSTR lpszTrim
)
1869 LPWSTR lpszRead
= lpszStr
;
1872 TRACE("(%s,%s)\n", debugstr_w(lpszStr
), debugstr_w(lpszTrim
));
1874 if (lpszRead
&& *lpszRead
)
1876 while (*lpszRead
&& StrChrW(lpszTrim
, *lpszRead
)) lpszRead
++;
1878 dwLen
= strlenW(lpszRead
);
1880 if (lpszRead
!= lpszStr
)
1882 memmove(lpszStr
, lpszRead
, (dwLen
+ 1) * sizeof(WCHAR
));
1887 lpszRead
= lpszStr
+ dwLen
;
1888 while (StrChrW(lpszTrim
, lpszRead
[-1]))
1889 lpszRead
--; /* Skip trailing matches */
1891 if (lpszRead
!= lpszStr
+ dwLen
)
1901 /*************************************************************************
1902 * _SHStrDupAA [INTERNAL]
1904 * Duplicates a ASCII string to ASCII. The destination buffer is allocated.
1906 static HRESULT
_SHStrDupAA(LPCSTR src
, LPSTR
* dest
)
1912 len
= lstrlenA(src
) + 1;
1913 *dest
= CoTaskMemAlloc(len
);
1919 lstrcpynA(*dest
,src
, len
);
1925 TRACE("%s->(%p)\n", debugstr_a(src
), *dest
);
1929 /*************************************************************************
1930 * SHStrDupA [SHLWAPI.@]
1932 * Return a Unicode copy of a string, in memory allocated by CoTaskMemAlloc().
1935 * lpszStr [I] String to copy
1936 * lppszDest [O] Destination for the new string copy
1939 * Success: S_OK. lppszDest contains the new string in Unicode format.
1940 * Failure: E_OUTOFMEMORY, If any arguments are invalid or memory allocation
1943 HRESULT WINAPI
SHStrDupA(LPCSTR lpszStr
, LPWSTR
* lppszDest
)
1950 len
= MultiByteToWideChar(CP_ACP
, 0, lpszStr
, -1, NULL
, 0) * sizeof(WCHAR
);
1951 *lppszDest
= CoTaskMemAlloc(len
);
1958 MultiByteToWideChar(CP_ACP
, 0, lpszStr
, -1, *lppszDest
, len
/sizeof(WCHAR
));
1962 hRet
= E_OUTOFMEMORY
;
1964 TRACE("%s->(%p)\n", debugstr_a(lpszStr
), *lppszDest
);
1968 /*************************************************************************
1969 * _SHStrDupAW [INTERNAL]
1971 * Duplicates a UNICODE to a ASCII string. The destination buffer is allocated.
1973 static HRESULT
_SHStrDupAW(LPCWSTR src
, LPSTR
* dest
)
1979 len
= WideCharToMultiByte(CP_ACP
, 0, src
, -1, NULL
, 0, NULL
, NULL
);
1980 *dest
= CoTaskMemAlloc(len
);
1986 WideCharToMultiByte(CP_ACP
, 0, src
, -1, *dest
, len
, NULL
, NULL
);
1992 TRACE("%s->(%p)\n", debugstr_w(src
), *dest
);
1996 /*************************************************************************
1997 * SHStrDupW [SHLWAPI.@]
2001 HRESULT WINAPI
SHStrDupW(LPCWSTR src
, LPWSTR
* dest
)
2007 len
= (lstrlenW(src
) + 1) * sizeof(WCHAR
);
2008 *dest
= CoTaskMemAlloc(len
);
2014 memcpy(*dest
, src
, len
);
2020 TRACE("%s->(%p)\n", debugstr_w(src
), *dest
);
2024 /*************************************************************************
2025 * SHLWAPI_WriteReverseNum
2027 * Internal helper for SHLWAPI_WriteTimeClass.
2029 static inline LPWSTR
SHLWAPI_WriteReverseNum(LPWSTR lpszOut
, DWORD dwNum
)
2033 /* Write a decimal number to a string, backwards */
2036 DWORD dwNextDigit
= dwNum
% 10;
2037 *lpszOut
-- = '0' + dwNextDigit
;
2038 dwNum
= (dwNum
- dwNextDigit
) / 10;
2039 } while (dwNum
> 0);
2044 /*************************************************************************
2045 * SHLWAPI_FormatSignificant
2047 * Internal helper for SHLWAPI_WriteTimeClass.
2049 static inline int SHLWAPI_FormatSignificant(LPWSTR lpszNum
, int dwDigits
)
2051 /* Zero non significant digits, return remaining significant digits */
2055 if (--dwDigits
== 0)
2065 /*************************************************************************
2066 * SHLWAPI_WriteTimeClass
2068 * Internal helper for StrFromTimeIntervalW.
2070 static int SHLWAPI_WriteTimeClass(LPWSTR lpszOut
, DWORD dwValue
,
2071 UINT uClassStringId
, int iDigits
)
2073 WCHAR szBuff
[64], *szOut
= szBuff
+ 32;
2075 szOut
= SHLWAPI_WriteReverseNum(szOut
, dwValue
);
2076 iDigits
= SHLWAPI_FormatSignificant(szOut
+ 1, iDigits
);
2078 LoadStringW(shlwapi_hInstance
, uClassStringId
, szBuff
+ 32, 32);
2079 strcatW(lpszOut
, szOut
);
2083 /*************************************************************************
2084 * StrFromTimeIntervalA [SHLWAPI.@]
2086 * Format a millisecond time interval into a string
2089 * lpszStr [O] Output buffer for formatted time interval
2090 * cchMax [I] Size of lpszStr
2091 * dwMS [I] Number of milliseconds
2092 * iDigits [I] Number of digits to print
2095 * The length of the formatted string, or 0 if any parameter is invalid.
2098 * This implementation mimics the Win32 behaviour of always writing a leading
2099 * space before the time interval begins.
2101 * iDigits is used to provide approximate times if accuracy is not important.
2102 * This number of digits will be written of the first non-zero time class
2103 * (hours/minutes/seconds). If this does not complete the time classification,
2104 * the remaining digits are changed to zeros (i.e. The time is _not_ rounded).
2105 * If there are digits remaining following the writing of a time class, the
2106 * next time class will be written.
2108 * For example, given dwMS represents 138 hours,43 minutes and 15 seconds, the
2109 * following will result from the given values of iDigits:
2111 *| iDigits 1 2 3 4 5 ...
2112 *| lpszStr "100 hr" "130 hr" "138 hr" "138 hr 40 min" "138 hr 43 min" ...
2114 INT WINAPI
StrFromTimeIntervalA(LPSTR lpszStr
, UINT cchMax
, DWORD dwMS
,
2119 TRACE("(%p,%d,%d,%d)\n", lpszStr
, cchMax
, dwMS
, iDigits
);
2121 if (lpszStr
&& cchMax
)
2124 StrFromTimeIntervalW(szBuff
, ARRAY_SIZE(szBuff
), dwMS
, iDigits
);
2125 WideCharToMultiByte(CP_ACP
,0,szBuff
,-1,lpszStr
,cchMax
,0,0);
2131 /*************************************************************************
2132 * StrFromTimeIntervalW [SHLWAPI.@]
2134 * See StrFromTimeIntervalA.
2136 INT WINAPI
StrFromTimeIntervalW(LPWSTR lpszStr
, UINT cchMax
, DWORD dwMS
,
2141 TRACE("(%p,%d,%d,%d)\n", lpszStr
, cchMax
, dwMS
, iDigits
);
2143 if (lpszStr
&& cchMax
)
2146 DWORD dwHours
, dwMinutes
;
2148 if (!iDigits
|| cchMax
== 1)
2154 /* Calculate the time classes */
2155 dwMS
= (dwMS
+ 500) / 1000;
2156 dwHours
= dwMS
/ 3600;
2157 dwMS
-= dwHours
* 3600;
2158 dwMinutes
= dwMS
/ 60;
2159 dwMS
-= dwMinutes
* 60;
2164 iDigits
= SHLWAPI_WriteTimeClass(szCopy
, dwHours
, IDS_TIME_INTERVAL_HOURS
, iDigits
);
2166 if (dwMinutes
&& iDigits
)
2167 iDigits
= SHLWAPI_WriteTimeClass(szCopy
, dwMinutes
, IDS_TIME_INTERVAL_MINUTES
, iDigits
);
2169 if (iDigits
) /* Always write seconds if we have significant digits */
2170 SHLWAPI_WriteTimeClass(szCopy
, dwMS
, IDS_TIME_INTERVAL_SECONDS
, iDigits
);
2172 lstrcpynW(lpszStr
, szCopy
, cchMax
);
2173 iRet
= strlenW(lpszStr
);
2178 /*************************************************************************
2179 * StrIsIntlEqualA [SHLWAPI.@]
2181 * Compare two strings.
2184 * bCase [I] Whether to compare case sensitively
2185 * lpszStr [I] First string to compare
2186 * lpszComp [I] Second string to compare
2187 * iLen [I] Length to compare
2190 * TRUE If the strings are equal.
2193 BOOL WINAPI
StrIsIntlEqualA(BOOL bCase
, LPCSTR lpszStr
, LPCSTR lpszComp
,
2198 TRACE("(%d,%s,%s,%d)\n", bCase
,
2199 debugstr_a(lpszStr
), debugstr_a(lpszComp
), iLen
);
2201 /* FIXME: This flag is undocumented and unknown by our CompareString.
2202 * We need a define for it.
2204 dwFlags
= 0x10000000;
2205 if (!bCase
) dwFlags
|= NORM_IGNORECASE
;
2207 return (CompareStringA(GetThreadLocale(), dwFlags
, lpszStr
, iLen
, lpszComp
, iLen
) == CSTR_EQUAL
);
2210 /*************************************************************************
2211 * StrIsIntlEqualW [SHLWAPI.@]
2213 * See StrIsIntlEqualA.
2215 BOOL WINAPI
StrIsIntlEqualW(BOOL bCase
, LPCWSTR lpszStr
, LPCWSTR lpszComp
,
2220 TRACE("(%d,%s,%s,%d)\n", bCase
,
2221 debugstr_w(lpszStr
),debugstr_w(lpszComp
), iLen
);
2223 /* FIXME: This flag is undocumented and unknown by our CompareString.
2224 * We need a define for it.
2226 dwFlags
= 0x10000000;
2227 if (!bCase
) dwFlags
|= NORM_IGNORECASE
;
2229 return (CompareStringW(GetThreadLocale(), dwFlags
, lpszStr
, iLen
, lpszComp
, iLen
) == CSTR_EQUAL
);
2232 /*************************************************************************
2235 * Copy a string to another string, up to a maximum number of characters.
2238 * lpszDest [O] Destination string
2239 * lpszSrc [I] Source string
2240 * iLen [I] Maximum number of chars to copy
2243 * Success: A pointer to the last character written to lpszDest.
2244 * Failure: lpszDest, if any arguments are invalid.
2246 LPSTR WINAPI
StrCpyNXA(LPSTR lpszDest
, LPCSTR lpszSrc
, int iLen
)
2248 TRACE("(%p,%s,%i)\n", lpszDest
, debugstr_a(lpszSrc
), iLen
);
2250 if (lpszDest
&& lpszSrc
&& iLen
> 0)
2252 while ((iLen
-- > 1) && *lpszSrc
)
2253 *lpszDest
++ = *lpszSrc
++;
2260 /*************************************************************************
2263 * Unicode version of StrCpyNXA.
2265 LPWSTR WINAPI
StrCpyNXW(LPWSTR lpszDest
, LPCWSTR lpszSrc
, int iLen
)
2267 TRACE("(%p,%s,%i)\n", lpszDest
, debugstr_w(lpszSrc
), iLen
);
2269 if (lpszDest
&& lpszSrc
&& iLen
> 0)
2271 while ((iLen
-- > 1) && *lpszSrc
)
2272 *lpszDest
++ = *lpszSrc
++;
2279 /*************************************************************************
2280 * StrCmpLogicalW [SHLWAPI.@]
2282 * Compare two strings, ignoring case and comparing digits as numbers.
2285 * lpszStr [I] First string to compare
2286 * lpszComp [I] Second string to compare
2287 * iLen [I] Length to compare
2290 * TRUE If the strings are equal.
2293 INT WINAPI
StrCmpLogicalW(LPCWSTR lpszStr
, LPCWSTR lpszComp
)
2297 TRACE("(%s,%s)\n", debugstr_w(lpszStr
), debugstr_w(lpszComp
));
2299 if (lpszStr
&& lpszComp
)
2305 else if (isdigitW(*lpszStr
))
2309 if (!isdigitW(*lpszComp
))
2312 /* Compare the numbers */
2313 StrToIntExW(lpszStr
, 0, &iStr
);
2314 StrToIntExW(lpszComp
, 0, &iComp
);
2318 else if (iStr
> iComp
)
2322 while (isdigitW(*lpszStr
))
2324 while (isdigitW(*lpszComp
))
2327 else if (isdigitW(*lpszComp
))
2331 iDiff
= ChrCmpIW(*lpszStr
,*lpszComp
);
2347 /* Structure for formatting byte strings */
2348 typedef struct tagSHLWAPI_BYTEFORMATS
2355 } SHLWAPI_BYTEFORMATS
;
2357 /*************************************************************************
2358 * StrFormatByteSizeW [SHLWAPI.@]
2360 * Create a string containing an abbreviated byte count of up to 2^63-1.
2363 * llBytes [I] Byte size to format
2364 * lpszDest [I] Destination for formatted string
2365 * cchMax [I] Size of lpszDest
2371 * There is no StrFormatByteSize64W function, it is called StrFormatByteSizeW().
2373 LPWSTR WINAPI
StrFormatByteSizeW(LONGLONG llBytes
, LPWSTR lpszDest
, UINT cchMax
)
2375 #define KB ((ULONGLONG)1024)
2377 #define GB (KB*KB*KB)
2378 #define TB (KB*KB*KB*KB)
2379 #define PB (KB*KB*KB*KB*KB)
2381 static const SHLWAPI_BYTEFORMATS bfFormats
[] =
2383 { 10*KB
, 10.24, 100.0, 2, 'K' }, /* 10 KB */
2384 { 100*KB
, 102.4, 10.0, 1, 'K' }, /* 100 KB */
2385 { 1000*KB
, 1024.0, 1.0, 0, 'K' }, /* 1000 KB */
2386 { 10*MB
, 10485.76, 100.0, 2, 'M' }, /* 10 MB */
2387 { 100*MB
, 104857.6, 10.0, 1, 'M' }, /* 100 MB */
2388 { 1000*MB
, 1048576.0, 1.0, 0, 'M' }, /* 1000 MB */
2389 { 10*GB
, 10737418.24, 100.0, 2, 'G' }, /* 10 GB */
2390 { 100*GB
, 107374182.4, 10.0, 1, 'G' }, /* 100 GB */
2391 { 1000*GB
, 1073741824.0, 1.0, 0, 'G' }, /* 1000 GB */
2392 { 10*TB
, 10485.76, 100.0, 2, 'T' }, /* 10 TB */
2393 { 100*TB
, 104857.6, 10.0, 1, 'T' }, /* 100 TB */
2394 { 1000*TB
, 1048576.0, 1.0, 0, 'T' }, /* 1000 TB */
2395 { 10*PB
, 10737418.24, 100.00, 2, 'P' }, /* 10 PB */
2396 { 100*PB
, 107374182.4, 10.00, 1, 'P' }, /* 100 PB */
2397 { 1000*PB
, 1073741824.0, 1.00, 0, 'P' }, /* 1000 PB */
2398 { 0, 10995116277.76, 100.00, 2, 'E' } /* EB's, catch all */
2400 WCHAR wszAdd
[] = {' ','?','B',0};
2404 TRACE("(0x%s,%p,%d)\n", wine_dbgstr_longlong(llBytes
), lpszDest
, cchMax
);
2406 if (!lpszDest
|| !cchMax
)
2409 if (llBytes
< 1024) /* 1K */
2411 WCHAR wszBytesFormat
[64];
2412 LoadStringW(shlwapi_hInstance
, IDS_BYTES_FORMAT
, wszBytesFormat
, 64);
2413 snprintfW(lpszDest
, cchMax
, wszBytesFormat
, (int)llBytes
);
2417 /* Note that if this loop completes without finding a match, i will be
2418 * pointing at the last entry, which is a catch all for > 1000 PB
2420 while (i
< ARRAY_SIZE(bfFormats
) - 1)
2422 if (llBytes
< bfFormats
[i
].dLimit
)
2426 /* Above 1 TB we encounter problems with FP accuracy. So for amounts above
2427 * this number we integer shift down by 1 MB first. The table above has
2428 * the divisors scaled down from the '< 10 TB' entry onwards, to account
2429 * for this. We also add a small fudge factor to get the correct result for
2430 * counts that lie exactly on a 1024 byte boundary.
2433 dBytes
= (double)(llBytes
>> 20) + 0.001; /* Scale down by 1 MB */
2435 dBytes
= (double)llBytes
+ 0.00001;
2437 dBytes
= floor(dBytes
/ bfFormats
[i
].dDivisor
) / bfFormats
[i
].dNormaliser
;
2439 if (!FormatDouble(dBytes
, bfFormats
[i
].nDecimals
, lpszDest
, cchMax
))
2441 wszAdd
[1] = bfFormats
[i
].wPrefix
;
2442 StrCatBuffW(lpszDest
, wszAdd
, cchMax
);
2446 /*************************************************************************
2447 * StrFormatByteSize64A [SHLWAPI.@]
2449 * See StrFormatByteSizeW.
2451 LPSTR WINAPI
StrFormatByteSize64A(LONGLONG llBytes
, LPSTR lpszDest
, UINT cchMax
)
2455 StrFormatByteSizeW(llBytes
, wszBuff
, ARRAY_SIZE(wszBuff
));
2458 WideCharToMultiByte(CP_ACP
, 0, wszBuff
, -1, lpszDest
, cchMax
, 0, 0);
2462 /*************************************************************************
2463 * StrFormatByteSizeA [SHLWAPI.@]
2465 * Create a string containing an abbreviated byte count of up to 2^31-1.
2468 * dwBytes [I] Byte size to format
2469 * lpszDest [I] Destination for formatted string
2470 * cchMax [I] Size of lpszDest
2476 * The Ascii and Unicode versions of this function accept a different
2477 * integer type for dwBytes. See StrFormatByteSize64A().
2479 LPSTR WINAPI
StrFormatByteSizeA(DWORD dwBytes
, LPSTR lpszDest
, UINT cchMax
)
2481 TRACE("(%d,%p,%d)\n", dwBytes
, lpszDest
, cchMax
);
2483 return StrFormatByteSize64A(dwBytes
, lpszDest
, cchMax
);
2486 /*************************************************************************
2489 * Remove a hanging lead byte from the end of a string, if present.
2492 * lpStr [I] String to check for a hanging lead byte
2493 * size [I] Length of lpStr
2496 * Success: The new length of the string. Any hanging lead bytes are removed.
2497 * Failure: 0, if any parameters are invalid.
2499 DWORD WINAPI
SHTruncateString(LPSTR lpStr
, DWORD size
)
2503 LPSTR lastByte
= lpStr
+ size
- 1;
2505 while(lpStr
< lastByte
)
2506 lpStr
+= IsDBCSLeadByte(*lpStr
) ? 2 : 1;
2508 if(lpStr
== lastByte
&& IsDBCSLeadByte(*lpStr
))
2518 /*************************************************************************
2521 * Remove a single non-trailing ampersand ('&') from a string.
2524 * lpszStr [I/O] String to remove ampersand from.
2527 * The character after the first ampersand in lpszStr, or the first character
2528 * in lpszStr if there is no ampersand in the string.
2530 char WINAPI
SHStripMneumonicA(LPCSTR lpszStr
)
2532 LPSTR lpszIter
, lpszTmp
;
2535 TRACE("(%s)\n", debugstr_a(lpszStr
));
2539 if ((lpszIter
= StrChrA(lpszStr
, '&')))
2541 lpszTmp
= CharNextA(lpszIter
);
2544 if (*lpszTmp
!= '&')
2547 memmove( lpszIter
, lpszTmp
, strlen(lpszTmp
) + 1 );
2554 /*************************************************************************
2557 * Unicode version of SHStripMneumonicA.
2559 WCHAR WINAPI
SHStripMneumonicW(LPCWSTR lpszStr
)
2561 LPWSTR lpszIter
, lpszTmp
;
2564 TRACE("(%s)\n", debugstr_w(lpszStr
));
2568 if ((lpszIter
= StrChrW(lpszStr
, '&')))
2570 lpszTmp
= lpszIter
+ 1;
2573 if (*lpszTmp
!= '&')
2576 memmove( lpszIter
, lpszTmp
, (strlenW(lpszTmp
) + 1) * sizeof(WCHAR
) );
2583 /*************************************************************************
2586 * Convert an Ascii string to Unicode.
2589 * dwCp [I] Code page for the conversion
2590 * lpSrcStr [I] Source Ascii string to convert
2591 * lpDstStr [O] Destination for converted Unicode string
2592 * iLen [I] Length of lpDstStr
2595 * The return value of the MultiByteToWideChar() function called on lpSrcStr.
2597 DWORD WINAPI
SHAnsiToUnicodeCP(DWORD dwCp
, LPCSTR lpSrcStr
, LPWSTR lpDstStr
, int iLen
)
2601 dwRet
= MultiByteToWideChar(dwCp
, 0, lpSrcStr
, -1, lpDstStr
, iLen
);
2602 TRACE("%s->%s,ret=%d\n", debugstr_a(lpSrcStr
), debugstr_w(lpDstStr
), dwRet
);
2606 /*************************************************************************
2609 * Convert an Ascii string to Unicode.
2612 * lpSrcStr [I] Source Ascii string to convert
2613 * lpDstStr [O] Destination for converted Unicode string
2614 * iLen [I] Length of lpDstStr
2617 * The return value of the MultiByteToWideChar() function called on lpSrcStr.
2620 * This function simply calls SHAnsiToUnicodeCP with code page CP_ACP.
2622 DWORD WINAPI
SHAnsiToUnicode(LPCSTR lpSrcStr
, LPWSTR lpDstStr
, int iLen
)
2624 return SHAnsiToUnicodeCP(CP_ACP
, lpSrcStr
, lpDstStr
, iLen
);
2627 /*************************************************************************
2630 * Convert a Unicode string to Ascii.
2633 * CodePage [I] Code page to use for the conversion
2634 * lpSrcStr [I] Source Unicode string to convert
2635 * lpDstStr [O] Destination for converted Ascii string
2636 * dstlen [I] Length of buffer at lpDstStr
2639 * Success: The length in bytes of the result at lpDstStr (including the terminator)
2640 * Failure: When using CP_UTF8, CP_UTF7 or 0xc350 as codePage, 0 is returned and
2641 * the result is not nul-terminated.
2642 * When using a different codepage, the length in bytes of the truncated
2643 * result at lpDstStr (including the terminator) is returned and
2644 * lpDstStr is always nul-terminated.
2647 DWORD WINAPI
SHUnicodeToAnsiCP(UINT CodePage
, LPCWSTR lpSrcStr
, LPSTR lpDstStr
, int dstlen
)
2649 static const WCHAR emptyW
[] = { '\0' };
2653 if (!lpDstStr
|| !dstlen
)
2661 len
= strlenW(lpSrcStr
) + 1;
2666 CodePage
= CP_UTF8
; /* Fall through... */
2667 case 0x0000C350: /* FIXME: CP_ #define */
2673 INT needed
= dstlen
- 1;
2676 /* try the user supplied buffer first */
2677 hr
= ConvertINetUnicodeToMultiByte(&dwMode
, CodePage
, lpSrcStr
, &lenW
, lpDstStr
, &needed
);
2680 lpDstStr
[needed
] = '\0';
2684 /* user buffer too small. exclude termination and copy as much as possible */
2686 hr
= ConvertINetUnicodeToMultiByte(&dwMode
, CodePage
, lpSrcStr
, &lenW
, NULL
, &needed
);
2688 mem
= HeapAlloc(GetProcessHeap(), 0, needed
);
2692 hr
= ConvertINetUnicodeToMultiByte(&dwMode
, CodePage
, lpSrcStr
, &len
, mem
, &needed
);
2695 reqLen
= SHTruncateString(mem
, dstlen
);
2696 if (reqLen
> 0) memcpy(lpDstStr
, mem
, reqLen
-1);
2698 HeapFree(GetProcessHeap(), 0, mem
);
2705 /* try the user supplied buffer first */
2706 reqLen
= WideCharToMultiByte(CodePage
, 0, lpSrcStr
, len
, lpDstStr
, dstlen
, NULL
, NULL
);
2708 if (!reqLen
&& GetLastError() == ERROR_INSUFFICIENT_BUFFER
)
2710 reqLen
= WideCharToMultiByte(CodePage
, 0, lpSrcStr
, len
, NULL
, 0, NULL
, NULL
);
2713 mem
= HeapAlloc(GetProcessHeap(), 0, reqLen
);
2716 WideCharToMultiByte(CodePage
, 0, lpSrcStr
, len
, mem
, reqLen
, NULL
, NULL
);
2718 reqLen
= SHTruncateString(mem
, dstlen
-1);
2721 lstrcpynA(lpDstStr
, mem
, reqLen
);
2722 HeapFree(GetProcessHeap(), 0, mem
);
2723 lpDstStr
[reqLen
-1] = '\0';
2730 /*************************************************************************
2733 * Convert a Unicode string to Ascii.
2736 * lpSrcStr [I] Source Unicode string to convert
2737 * lpDstStr [O] Destination for converted Ascii string
2738 * iLen [O] Length of lpDstStr in characters
2741 * See SHUnicodeToAnsiCP
2744 * This function simply calls SHUnicodeToAnsiCP() with CodePage = CP_ACP.
2746 INT WINAPI
SHUnicodeToAnsi(LPCWSTR lpSrcStr
, LPSTR lpDstStr
, INT iLen
)
2748 return SHUnicodeToAnsiCP(CP_ACP
, lpSrcStr
, lpDstStr
, iLen
);
2751 /*************************************************************************
2754 * Determine if an Ascii string converts to Unicode and back identically.
2757 * lpSrcStr [I] Source Unicode string to convert
2758 * lpDst [O] Destination for resulting Ascii string
2759 * iLen [I] Length of lpDst in characters
2762 * TRUE, since Ascii strings always convert identically.
2764 BOOL WINAPI
DoesStringRoundTripA(LPCSTR lpSrcStr
, LPSTR lpDst
, INT iLen
)
2766 lstrcpynA(lpDst
, lpSrcStr
, iLen
);
2770 /*************************************************************************
2773 * Determine if a Unicode string converts to Ascii and back identically.
2776 * lpSrcStr [I] Source Unicode string to convert
2777 * lpDst [O] Destination for resulting Ascii string
2778 * iLen [I] Length of lpDst in characters
2781 * TRUE, if lpSrcStr converts to Ascii and back identically,
2784 BOOL WINAPI
DoesStringRoundTripW(LPCWSTR lpSrcStr
, LPSTR lpDst
, INT iLen
)
2786 WCHAR szBuff
[MAX_PATH
];
2788 SHUnicodeToAnsi(lpSrcStr
, lpDst
, iLen
);
2789 SHAnsiToUnicode(lpDst
, szBuff
, MAX_PATH
);
2790 return !strcmpW(lpSrcStr
, szBuff
);
2793 /*************************************************************************
2794 * SHLoadIndirectString [SHLWAPI.@]
2796 * If passed a string that begins with '@', extract the string from the
2797 * appropriate resource, otherwise do a straight copy.
2800 HRESULT WINAPI
SHLoadIndirectString(LPCWSTR src
, LPWSTR dst
, UINT dst_len
, void **reserved
)
2802 WCHAR
*dllname
= NULL
;
2803 HMODULE hmod
= NULL
;
2804 HRESULT hr
= E_FAIL
;
2806 TRACE("(%s %p %08x %p)\n", debugstr_w(src
), dst
, dst_len
, reserved
);
2814 dllname
= StrDupW(src
+ 1);
2815 index_str
= strchrW(dllname
, ',');
2817 if(!index_str
) goto end
;
2821 index
= atoiW(index_str
);
2823 hmod
= LoadLibraryW(dllname
);
2828 if(LoadStringW(hmod
, -index
, dst
, dst_len
))
2832 FIXME("can't handle non-negative indices (%d)\n", index
);
2837 lstrcpynW(dst
, src
, dst_len
);
2841 TRACE("returning %s\n", debugstr_w(dst
));
2843 if(hmod
) FreeLibrary(hmod
);
2848 BOOL WINAPI
IsCharSpaceA(CHAR c
)
2851 return GetStringTypeA(GetSystemDefaultLCID(), CT_CTYPE1
, &c
, 1, &CharType
) && (CharType
& C1_SPACE
);
2854 /*************************************************************************
2857 * Determine if a Unicode character is a space.
2860 * wc [I] Character to check.
2863 * TRUE, if wc is a space,
2866 BOOL WINAPI
IsCharSpaceW(WCHAR wc
)
2870 return GetStringTypeW(CT_CTYPE1
, &wc
, 1, &CharType
) && (CharType
& C1_SPACE
);