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