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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #define COM_NO_WINDOWS_H
24 #include "wine/port.h"
32 #define NONAMELESSUNION
33 #define NONAMELESSSTRUCT
36 #define NO_SHLWAPI_REG
37 #define NO_SHLWAPI_STREAM
43 #include "wine/unicode.h"
44 #include "wine/debug.h"
46 WINE_DEFAULT_DEBUG_CHANNEL(shell
);
48 /* Get a function pointer from a DLL handle */
49 #define GET_FUNC(func, module, name, fail) \
52 if (!SHLWAPI_h##module && !(SHLWAPI_h##module = LoadLibraryA(#module ".dll"))) return fail; \
53 func = (fn##func)GetProcAddress(SHLWAPI_h##module, name); \
54 if (!func) return fail; \
58 extern HMODULE SHLWAPI_hmlang
;
60 typedef HRESULT (WINAPI
*fnpConvertINetUnicodeToMultiByte
)(LPDWORD
,DWORD
,LPCWSTR
,LPINT
,LPSTR
,LPINT
);
61 static fnpConvertINetUnicodeToMultiByte pConvertINetUnicodeToMultiByte
;
63 static HRESULT WINAPI
_SHStrDupAA(LPCSTR
,LPSTR
*);
64 static HRESULT WINAPI
_SHStrDupAW(LPCWSTR
,LPSTR
*);
66 /*************************************************************************
67 * SHLWAPI_ChrCmpHelperA
69 * Internal helper for SHLWAPI_ChrCmpA/ChrCMPIA.
72 * Both this function and its Unicode counterpart are very inneficient. To
73 * fix this, CompareString must be completely implemented and optimised
74 * first. Then the core character test can be taken out of that function and
75 * placed here, so that it need never be called at all. Until then, do not
76 * attempt to optimise this code unless you are willing to test that it
77 * still performs correctly.
79 static BOOL WINAPI
SHLWAPI_ChrCmpHelperA(WORD ch1
, WORD ch2
, DWORD dwFlags
)
81 char str1
[3], str2
[3];
83 str1
[0] = LOBYTE(ch1
);
84 if (IsDBCSLeadByte(str1
[0]))
86 str1
[1] = HIBYTE(ch1
);
92 str2
[0] = LOBYTE(ch2
);
93 if (IsDBCSLeadByte(str2
[0]))
95 str2
[1] = HIBYTE(ch2
);
101 return CompareStringA(GetThreadLocale(), dwFlags
, str1
, -1, str2
, -1) - 2;
104 /*************************************************************************
105 * SHLWAPI_ChrCmpHelperW
107 * Internal helper for SHLWAPI_ChrCmpW/ChrCmpIW.
109 static BOOL WINAPI
SHLWAPI_ChrCmpHelperW(WCHAR ch1
, WCHAR ch2
, DWORD dwFlags
)
111 WCHAR str1
[2], str2
[2];
117 return CompareStringW(GetThreadLocale(), dwFlags
, str1
, 2, str2
, 2) - 2;
120 /*************************************************************************
123 * Internal helper function.
125 static BOOL WINAPI
SHLWAPI_ChrCmpA(WORD ch1
, WORD ch2
)
127 return SHLWAPI_ChrCmpHelperA(ch1
, ch2
, 0);
130 /*************************************************************************
131 * ChrCmpIA (SHLWAPI.385)
133 * Compare two characters, ignoring case.
136 * ch1 [I] First character to compare
137 * ch2 [I] Second character to compare
140 * FALSE, if the characters are equal.
141 * Non-zero otherwise.
143 BOOL WINAPI
ChrCmpIA(WORD ch1
, WORD ch2
)
145 TRACE("(%d,%d)\n", ch1
, ch2
);
147 return SHLWAPI_ChrCmpHelperA(ch1
, ch2
, NORM_IGNORECASE
);
150 /*************************************************************************
153 * Internal helper function.
155 static BOOL WINAPI
SHLWAPI_ChrCmpW(WCHAR ch1
, WCHAR ch2
)
157 return SHLWAPI_ChrCmpHelperW(ch1
, ch2
, 0);
160 /*************************************************************************
161 * ChrCmpIW [SHLWAPI.386]
165 BOOL WINAPI
ChrCmpIW(WCHAR ch1
, WCHAR ch2
)
167 return SHLWAPI_ChrCmpHelperW(ch1
, ch2
, NORM_IGNORECASE
);
170 /*************************************************************************
171 * StrChrA [SHLWAPI.@]
173 * Find a given character in a string.
176 * lpszStr [I] String to search in.
177 * ch [I] Character to search for.
180 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
182 * Failure: NULL, if any arguments are invalid.
184 LPSTR WINAPI
StrChrA(LPCSTR lpszStr
, WORD ch
)
186 TRACE("(%s,%i)\n", debugstr_a(lpszStr
), ch
);
192 if (!SHLWAPI_ChrCmpA(*lpszStr
, ch
))
193 return (LPSTR
)lpszStr
;
194 lpszStr
= CharNextA(lpszStr
);
200 /*************************************************************************
201 * StrChrW [SHLWAPI.@]
205 LPWSTR WINAPI
StrChrW(LPCWSTR lpszStr
, WCHAR ch
)
207 LPWSTR lpszRet
= NULL
;
209 TRACE("(%s,%i)\n", debugstr_w(lpszStr
), ch
);
212 lpszRet
= strchrW(lpszStr
, ch
);
216 /*************************************************************************
217 * StrChrIA [SHLWAPI.@]
219 * Find a given character in a string, ignoring case.
222 * lpszStr [I] String to search in.
223 * ch [I] Character to search for.
226 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
228 * Failure: NULL, if any arguments are invalid.
230 LPSTR WINAPI
StrChrIA(LPCSTR lpszStr
, WORD ch
)
232 TRACE("(%s,%i)\n", debugstr_a(lpszStr
), ch
);
238 if (!ChrCmpIA(*lpszStr
, ch
))
239 return (LPSTR
)lpszStr
;
240 lpszStr
= CharNextA(lpszStr
);
246 /*************************************************************************
247 * StrChrIW [SHLWAPI.@]
251 LPWSTR WINAPI
StrChrIW(LPCWSTR lpszStr
, WCHAR ch
)
253 TRACE("(%s,%i)\n", debugstr_w(lpszStr
), ch
);
260 if (toupperW(*lpszStr
) == ch
)
261 return (LPWSTR
)lpszStr
;
262 lpszStr
= CharNextW(lpszStr
);
266 return (LPWSTR
)lpszStr
;
269 /*************************************************************************
270 * StrCmpIW [SHLWAPI.@]
272 * Compare two strings, ignoring case.
275 * lpszStr [I] First string to compare
276 * lpszComp [I] Second string to compare
279 * An integer less than, equal to or greater than 0, indicating that
280 * lpszStr is less than, the same, or greater than lpszComp.
282 int WINAPI
StrCmpIW(LPCWSTR lpszStr
, LPCWSTR lpszComp
)
286 TRACE("(%s,%s)\n", debugstr_w(lpszStr
),debugstr_w(lpszComp
));
288 iRet
= CompareStringW(GetThreadLocale(), NORM_IGNORECASE
, lpszStr
, -1, lpszComp
, -1);
289 return iRet
== CSTR_LESS_THAN
? -1 : iRet
== CSTR_GREATER_THAN
? 1 : 0;
292 /*************************************************************************
293 * StrCmpNA [SHLWAPI.@]
295 * Compare two strings, up to a maximum length.
298 * lpszStr [I] First string to compare
299 * lpszComp [I] Second string to compare
300 * iLen [I] Maximum number of chars to compare.
303 * An integer less than, equal to or greater than 0, indicating that
304 * lpszStr is less than, the same, or greater than lpszComp.
306 INT WINAPI
StrCmpNA(LPCSTR lpszStr
, LPCSTR lpszComp
, INT iLen
)
310 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr
), debugstr_a(lpszComp
), iLen
);
312 iRet
= CompareStringA(GetThreadLocale(), 0, lpszStr
, iLen
, lpszComp
, iLen
);
313 return iRet
== CSTR_LESS_THAN
? -1 : iRet
== CSTR_GREATER_THAN
? 1 : 0;
316 /*************************************************************************
317 * StrCmpNW [SHLWAPI.@]
321 INT WINAPI
StrCmpNW(LPCWSTR lpszStr
, LPCWSTR lpszComp
, INT iLen
)
325 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr
), debugstr_w(lpszComp
), iLen
);
327 iRet
= CompareStringW(GetThreadLocale(), 0, lpszStr
, iLen
, lpszComp
, iLen
);
328 return iRet
== CSTR_LESS_THAN
? -1 : iRet
== CSTR_GREATER_THAN
? 1 : 0;
331 /*************************************************************************
332 * StrCmpNIA [SHLWAPI.@]
334 * Compare two strings, up to a maximum length, ignoring case.
337 * lpszStr [I] First string to compare
338 * lpszComp [I] Second string to compare
339 * iLen [I] Maximum number of chars to compare.
342 * An integer less than, equal to or greater than 0, indicating that
343 * lpszStr is less than, the same, or greater than lpszComp.
345 int WINAPI
StrCmpNIA(LPCSTR lpszStr
, LPCSTR lpszComp
, int iLen
)
349 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr
), debugstr_a(lpszComp
), iLen
);
351 iRet
= CompareStringA(GetThreadLocale(), NORM_IGNORECASE
, lpszStr
, iLen
, lpszComp
, iLen
);
352 return iRet
== CSTR_LESS_THAN
? -1 : iRet
== CSTR_GREATER_THAN
? 1 : 0;
355 /*************************************************************************
356 * StrCmpNIW [SHLWAPI.@]
360 INT WINAPI
StrCmpNIW(LPCWSTR lpszStr
, LPCWSTR lpszComp
, int iLen
)
364 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr
), debugstr_w(lpszComp
), iLen
);
366 iRet
= CompareStringW(GetThreadLocale(), NORM_IGNORECASE
, lpszStr
, iLen
, lpszComp
, iLen
);
367 return iRet
== CSTR_LESS_THAN
? -1 : iRet
== CSTR_GREATER_THAN
? 1 : 0;
370 /*************************************************************************
371 * StrCmpW [SHLWAPI.@]
373 * Compare two strings.
376 * lpszStr [I] First string to compare
377 * lpszComp [I] Second string to compare
380 * An integer less than, equal to or greater than 0, indicating that
381 * lpszStr is less than, the same, or greater than lpszComp.
383 int WINAPI
StrCmpW(LPCWSTR lpszStr
, LPCWSTR lpszComp
)
387 TRACE("(%s,%s)\n", debugstr_w(lpszStr
), debugstr_w(lpszComp
));
389 iRet
= CompareStringW(GetThreadLocale(), 0, lpszStr
, -1, lpszComp
, -1);
390 return iRet
== CSTR_LESS_THAN
? -1 : iRet
== CSTR_GREATER_THAN
? 1 : 0;
393 /*************************************************************************
394 * StrCatW [SHLWAPI.@]
396 * Concatanate two strings.
399 * lpszStr [O] Initial string
400 * lpszSrc [I] String to concatanate
405 LPWSTR WINAPI
StrCatW(LPWSTR lpszStr
, LPCWSTR lpszSrc
)
407 TRACE("(%s,%s)\n", debugstr_w(lpszStr
), debugstr_w(lpszSrc
));
409 strcatW(lpszStr
, lpszSrc
);
413 /*************************************************************************
414 * StrCpyW [SHLWAPI.@]
416 * Copy a string to another string.
419 * lpszStr [O] Destination string
420 * lpszSrc [I] Source string
425 LPWSTR WINAPI
StrCpyW(LPWSTR lpszStr
, LPCWSTR lpszSrc
)
427 TRACE("(%p,%s)\n", lpszStr
, debugstr_w(lpszSrc
));
429 strcpyW(lpszStr
, lpszSrc
);
433 /*************************************************************************
434 * StrCpyNW [SHLWAPI.@]
436 * Copy a string to another string, up to a maximum number of characters.
439 * lpszStr [O] Destination string
440 * lpszSrc [I] Source string
441 * iLen [I] Maximum number of chars to copy
446 LPWSTR WINAPI
StrCpyNW(LPWSTR lpszStr
, LPCWSTR lpszSrc
, int iLen
)
448 TRACE("(%p,%s,%i)\n", lpszStr
, debugstr_w(lpszSrc
), iLen
);
450 lstrcpynW(lpszStr
, lpszSrc
, iLen
);
456 /*************************************************************************
457 * SHLWAPI_StrStrHelperA
459 * Internal implementation of StrStrA/StrStrIA
461 static LPSTR WINAPI
SHLWAPI_StrStrHelperA(LPCSTR lpszStr
, LPCSTR lpszSearch
,
462 int (*pStrCmpFn
)(LPCSTR
,LPCSTR
,size_t))
466 if (!lpszStr
|| !lpszSearch
|| !*lpszSearch
)
469 iLen
= strlen(lpszSearch
);
473 if (!pStrCmpFn(lpszStr
, lpszSearch
, iLen
))
474 return (LPSTR
)lpszStr
;
475 lpszStr
= CharNextA(lpszStr
);
480 /*************************************************************************
481 * SHLWAPI_StrStrHelperW
483 * Internal implementation of StrStrW/StrStrIW
485 static LPWSTR WINAPI
SHLWAPI_StrStrHelperW(LPCWSTR lpszStr
, LPCWSTR lpszSearch
,
486 int (*pStrCmpFn
)(LPCWSTR
,LPCWSTR
,int))
490 if (!lpszStr
|| !lpszSearch
|| !*lpszSearch
)
493 iLen
= strlenW(lpszSearch
);
497 if (!pStrCmpFn(lpszStr
, lpszSearch
, iLen
))
498 return (LPWSTR
)lpszStr
;
499 lpszStr
= CharNextW(lpszStr
);
504 /*************************************************************************
505 * StrStrA [SHLWAPI.@]
507 * Find a substring within a string.
510 * lpszStr [I] String to search in
511 * lpszSearch [I] String to look for
514 * The start of lpszSearch within lpszStr, or NULL if not found.
516 LPSTR WINAPI
StrStrA(LPCSTR lpszStr
, LPCSTR lpszSearch
)
518 TRACE("(%s,%s)\n", debugstr_a(lpszStr
), debugstr_a(lpszSearch
));
520 return SHLWAPI_StrStrHelperA(lpszStr
, lpszSearch
, strncmp
);
523 /*************************************************************************
524 * StrStrW [SHLWAPI.@]
528 LPWSTR WINAPI
StrStrW(LPCWSTR lpszStr
, LPCWSTR lpszSearch
)
530 TRACE("(%s,%s)\n", debugstr_w(lpszStr
), debugstr_w(lpszSearch
));
532 return SHLWAPI_StrStrHelperW(lpszStr
, lpszSearch
, (int (*)(LPCWSTR
,LPCWSTR
,int))wcsncmp
);
535 /*************************************************************************
536 * StrRStrIA [SHLWAPI.@]
538 * Find the last occurrence of a substring within a string.
541 * lpszStr [I] String to search in
542 * lpszEnd [I] End of lpszStr
543 * lpszSearch [I] String to look for
546 * The last occurrence lpszSearch within lpszStr, or NULL if not found.
548 LPSTR WINAPI
StrRStrIA(LPCSTR lpszStr
, LPCSTR lpszEnd
, LPCSTR lpszSearch
)
550 LPSTR lpszRet
= NULL
;
554 TRACE("(%s,%s)\n", debugstr_a(lpszStr
), debugstr_a(lpszSearch
));
556 if (!lpszStr
|| !lpszSearch
|| !*lpszSearch
)
560 lpszEnd
= lpszStr
+ lstrlenA(lpszStr
);
562 if (IsDBCSLeadByte(*lpszSearch
))
563 ch1
= *lpszSearch
<< 8 | lpszSearch
[1];
566 iLen
= lstrlenA(lpszSearch
);
568 while (lpszStr
<= lpszEnd
&& *lpszStr
)
570 ch2
= IsDBCSLeadByte(*lpszStr
)? *lpszStr
<< 8 | lpszStr
[1] : *lpszStr
;
571 if (!ChrCmpIA(ch1
, ch2
))
573 if (!StrCmpNIA(lpszStr
, lpszSearch
, iLen
))
574 lpszRet
= (LPSTR
)lpszStr
;
576 lpszStr
= CharNextA(lpszStr
);
581 /*************************************************************************
582 * StrRStrIW [SHLWAPI.@]
586 LPWSTR WINAPI
StrRStrIW(LPCWSTR lpszStr
, LPCWSTR lpszEnd
, LPCWSTR lpszSearch
)
588 LPWSTR lpszRet
= NULL
;
591 TRACE("(%s,%s)\n", debugstr_w(lpszStr
), debugstr_w(lpszSearch
));
593 if (!lpszStr
|| !lpszSearch
|| !*lpszSearch
)
597 lpszEnd
= lpszStr
+ strlenW(lpszStr
);
599 iLen
= strlenW(lpszSearch
);
601 while (lpszStr
<= lpszEnd
&& *lpszStr
)
603 if (!ChrCmpIW(*lpszSearch
, *lpszStr
))
605 if (!StrCmpNIW(lpszStr
, lpszSearch
, iLen
))
606 lpszRet
= (LPWSTR
)lpszStr
;
608 lpszStr
= CharNextW(lpszStr
);
613 /*************************************************************************
614 * StrStrIA [SHLWAPI.@]
616 * Find a substring within a string, ignoring case.
619 * lpszStr [I] String to search in
620 * lpszSearch [I] String to look for
623 * The start of lpszSearch within lpszStr, or NULL if not found.
625 LPSTR WINAPI
StrStrIA(LPCSTR lpszStr
, LPCSTR lpszSearch
)
627 TRACE("(%s,%s)\n", debugstr_a(lpszStr
), debugstr_a(lpszSearch
));
629 return SHLWAPI_StrStrHelperA(lpszStr
, lpszSearch
, strncasecmp
);
632 /*************************************************************************
633 * StrStrIW [SHLWAPI.@]
637 LPWSTR WINAPI
StrStrIW(LPCWSTR lpszStr
, LPCWSTR lpszSearch
)
639 TRACE("(%s,%s)\n", debugstr_w(lpszStr
), debugstr_w(lpszSearch
));
641 return SHLWAPI_StrStrHelperW(lpszStr
, lpszSearch
, (int (*)(LPCWSTR
,LPCWSTR
,int))_wcsnicmp
);
644 /*************************************************************************
645 * StrToIntA [SHLWAPI.@]
647 * Read a signed integer from a string.
650 * lpszStr [I] String to read integer from
653 * The signed integer value represented by the string, or 0 if no integer is
657 * No leading space is allowed before the number, although a leading '-' is.
659 int WINAPI
StrToIntA(LPCSTR lpszStr
)
663 TRACE("(%s)\n", debugstr_a(lpszStr
));
667 WARN("Invalid lpszStr would crash under Win32!\n");
671 if (*lpszStr
== '-' || isdigit(*lpszStr
))
672 StrToIntExA(lpszStr
, 0, &iRet
);
676 /*************************************************************************
677 * StrToIntW [SHLWAPI.@]
681 int WINAPI
StrToIntW(LPCWSTR lpszStr
)
685 TRACE("(%s)\n", debugstr_w(lpszStr
));
689 WARN("Invalid lpszStr would crash under Win32!\n");
693 if (*lpszStr
== '-' || isdigitW(*lpszStr
))
694 StrToIntExW(lpszStr
, 0, &iRet
);
698 /*************************************************************************
699 * StrToIntExA [SHLWAPI.@]
701 * Read an integer from a string.
704 * lpszStr [I] String to read integer from
705 * dwFlags [I] Flags controlling the conversion
706 * lpiRet [O] Destination for read integer.
709 * Success: TRUE. lpiRet contains the integer value represented by the string.
710 * Failure: FALSE, if the string is invalid, or no number is present.
713 * Leading whitespace, '-' and '+' are allowed before the number. If
714 * dwFlags includes STIF_SUPPORT_HEX, hexadecimal numbers are allowed, if
715 * preceded by '0x'. If this flag is not set, or there is no '0x' prefix,
716 * the string is treated as a decimal string. A leading '-' is ignored for
717 * hexadecimal numbers.
719 BOOL WINAPI
StrToIntExA(LPCSTR lpszStr
, DWORD dwFlags
, LPINT lpiRet
)
721 BOOL bNegative
= FALSE
;
724 TRACE("(%s,%08lX,%p)\n", debugstr_a(lpszStr
), dwFlags
, lpiRet
);
726 if (!lpszStr
|| !lpiRet
)
728 WARN("Invalid parameter would crash under Win32!\n");
731 if (dwFlags
> STIF_SUPPORT_HEX
)
733 WARN("Unknown flags (%08lX)!\n", dwFlags
& ~STIF_SUPPORT_HEX
);
736 /* Skip leading space, '+', '-' */
737 while (isspace(*lpszStr
))
738 lpszStr
= CharNextA(lpszStr
);
745 else if (*lpszStr
== '+')
748 if (dwFlags
& STIF_SUPPORT_HEX
&&
749 *lpszStr
== '0' && tolower(lpszStr
[1]) == 'x')
751 /* Read hex number */
754 if (!isxdigit(*lpszStr
))
757 while (isxdigit(*lpszStr
))
760 if (isdigit(*lpszStr
))
761 iRet
+= (*lpszStr
- '0');
763 iRet
+= 10 + (tolower(*lpszStr
) - 'a');
770 /* Read decimal number */
771 if (!isdigit(*lpszStr
))
774 while (isdigit(*lpszStr
))
777 iRet
+= (*lpszStr
- '0');
780 *lpiRet
= bNegative
? -iRet
: iRet
;
784 /*************************************************************************
785 * StrToIntExW [SHLWAPI.@]
789 BOOL WINAPI
StrToIntExW(LPCWSTR lpszStr
, DWORD dwFlags
, LPINT lpiRet
)
791 BOOL bNegative
= FALSE
;
794 TRACE("(%s,%08lX,%p)\n", debugstr_w(lpszStr
), dwFlags
, lpiRet
);
796 if (!lpszStr
|| !lpiRet
)
798 WARN("Invalid parameter would crash under Win32!\n");
801 if (dwFlags
> STIF_SUPPORT_HEX
)
803 WARN("Unknown flags (%08lX)!\n", dwFlags
& ~STIF_SUPPORT_HEX
);
806 /* Skip leading space, '+', '-' */
807 while (isspaceW(*lpszStr
))
808 lpszStr
= CharNextW(lpszStr
);
815 else if (*lpszStr
== '+')
818 if (dwFlags
& STIF_SUPPORT_HEX
&&
819 *lpszStr
== '0' && tolowerW(lpszStr
[1]) == 'x')
821 /* Read hex number */
824 if (!isxdigitW(*lpszStr
))
827 while (isxdigitW(*lpszStr
))
830 if (isdigitW(*lpszStr
))
831 iRet
+= (*lpszStr
- '0');
833 iRet
+= 10 + (tolowerW(*lpszStr
) - 'a');
840 /* Read decimal number */
841 if (!isdigitW(*lpszStr
))
844 while (isdigitW(*lpszStr
))
847 iRet
+= (*lpszStr
- '0');
850 *lpiRet
= bNegative
? -iRet
: iRet
;
854 /*************************************************************************
855 * StrDupA [SHLWAPI.@]
857 * Duplicate a string.
860 * lpszStr [I] String to duplicate.
863 * Success: A pointer to a new string containing the contents of lpszStr
864 * Failure: NULL, if memory cannot be allocated
867 * The string memory is allocated with LocalAlloc(), and so should be released
868 * by calling LocalFree().
870 LPSTR WINAPI
StrDupA(LPCSTR lpszStr
)
875 TRACE("(%s)\n",debugstr_a(lpszStr
));
877 iLen
= lpszStr
? strlen(lpszStr
) + 1 : 1;
878 lpszRet
= (LPSTR
)LocalAlloc(LMEM_FIXED
, iLen
);
883 memcpy(lpszRet
, lpszStr
, iLen
);
890 /*************************************************************************
891 * StrDupW [SHLWAPI.@]
895 LPWSTR WINAPI
StrDupW(LPCWSTR lpszStr
)
900 TRACE("(%s)\n",debugstr_w(lpszStr
));
902 iLen
= (lpszStr
? strlenW(lpszStr
) + 1 : 1) * sizeof(WCHAR
);
903 lpszRet
= (LPWSTR
)LocalAlloc(LMEM_FIXED
, iLen
);
908 memcpy(lpszRet
, lpszStr
, iLen
);
915 /*************************************************************************
916 * SHLWAPI_StrSpnHelperA
918 * Internal implementation of StrSpnA/StrCSpnA/StrCSpnIA
920 static int WINAPI
SHLWAPI_StrSpnHelperA(LPCSTR lpszStr
, LPCSTR lpszMatch
,
921 LPSTR (WINAPI
*pStrChrFn
)(LPCSTR
,WORD
),
924 LPCSTR lpszRead
= lpszStr
;
925 if (lpszStr
&& *lpszStr
&& lpszMatch
)
929 LPCSTR lpszTest
= pStrChrFn(lpszMatch
, *lpszRead
);
931 if (!bInvert
&& !lpszTest
)
933 if (bInvert
&& lpszTest
)
935 lpszRead
= CharNextA(lpszRead
);
938 return lpszRead
- lpszStr
;
941 /*************************************************************************
942 * SHLWAPI_StrSpnHelperW
944 * Internal implementation of StrSpnW/StrCSpnW/StrCSpnIW
946 static int WINAPI
SHLWAPI_StrSpnHelperW(LPCWSTR lpszStr
, LPCWSTR lpszMatch
,
947 LPWSTR (WINAPI
*pStrChrFn
)(LPCWSTR
,WCHAR
),
950 LPCWSTR lpszRead
= lpszStr
;
951 if (lpszStr
&& *lpszStr
&& lpszMatch
)
955 LPCWSTR lpszTest
= pStrChrFn(lpszMatch
, *lpszRead
);
957 if (!bInvert
&& !lpszTest
)
959 if (bInvert
&& lpszTest
)
961 lpszRead
= CharNextW(lpszRead
);
964 return lpszRead
- lpszStr
;
967 /*************************************************************************
968 * StrSpnA [SHLWAPI.@]
970 * Find the length of the start of a string that contains only certain
974 * lpszStr [I] String to search
975 * lpszMatch [I] Characters that can be in the substring
978 * The length of the part of lpszStr containing only chars from lpszMatch,
979 * or 0 if any parameter is invalid.
981 int WINAPI
StrSpnA(LPCSTR lpszStr
, LPCSTR lpszMatch
)
983 TRACE("(%s,%s)\n",debugstr_a(lpszStr
), debugstr_a(lpszMatch
));
985 return SHLWAPI_StrSpnHelperA(lpszStr
, lpszMatch
, StrChrA
, FALSE
);
988 /*************************************************************************
989 * StrSpnW [SHLWAPI.@]
993 int WINAPI
StrSpnW(LPCWSTR lpszStr
, LPCWSTR lpszMatch
)
995 TRACE("(%s,%s)\n",debugstr_w(lpszStr
), debugstr_w(lpszMatch
));
997 return SHLWAPI_StrSpnHelperW(lpszStr
, lpszMatch
, StrChrW
, FALSE
);
1000 /*************************************************************************
1001 * StrCSpnA [SHLWAPI.@]
1003 * Find the length of the start of a string that does not contain certain
1007 * lpszStr [I] String to search
1008 * lpszMatch [I] Characters that cannot be in the substring
1011 * The length of the part of lpszStr containing only chars not in lpszMatch,
1012 * or 0 if any parameter is invalid.
1014 int WINAPI
StrCSpnA(LPCSTR lpszStr
, LPCSTR lpszMatch
)
1016 TRACE("(%s,%s)\n",debugstr_a(lpszStr
), debugstr_a(lpszMatch
));
1018 return SHLWAPI_StrSpnHelperA(lpszStr
, lpszMatch
, StrChrA
, TRUE
);
1021 /*************************************************************************
1022 * StrCSpnW [SHLWAPI.@]
1026 int WINAPI
StrCSpnW(LPCWSTR lpszStr
, LPCWSTR lpszMatch
)
1028 TRACE("(%s,%s)\n",debugstr_w(lpszStr
), debugstr_w(lpszMatch
));
1030 return SHLWAPI_StrSpnHelperW(lpszStr
, lpszMatch
, StrChrW
, TRUE
);
1033 /*************************************************************************
1034 * StrCSpnIA [SHLWAPI.@]
1036 * Find the length of the start of a string that does not contain certain
1037 * characters, ignoring case.
1040 * lpszStr [I] String to search
1041 * lpszMatch [I] Characters that cannot be in the substring
1044 * The length of the part of lpszStr containing only chars not in lpszMatch,
1045 * or 0 if any parameter is invalid.
1047 int WINAPI
StrCSpnIA(LPCSTR lpszStr
, LPCSTR lpszMatch
)
1049 TRACE("(%s,%s)\n",debugstr_a(lpszStr
), debugstr_a(lpszMatch
));
1051 return SHLWAPI_StrSpnHelperA(lpszStr
, lpszMatch
, StrChrIA
, TRUE
);
1054 /*************************************************************************
1055 * StrCSpnIW [SHLWAPI.@]
1059 int WINAPI
StrCSpnIW(LPCWSTR lpszStr
, LPCWSTR lpszMatch
)
1061 TRACE("(%s,%s)\n",debugstr_w(lpszStr
), debugstr_w(lpszMatch
));
1063 return SHLWAPI_StrSpnHelperW(lpszStr
, lpszMatch
, StrChrIW
, TRUE
);
1066 /*************************************************************************
1067 * StrPBrkA [SHLWAPI.@]
1069 * Search a string for any of a group of characters.
1072 * lpszStr [I] String to search
1073 * lpszMatch [I] Characters to match
1076 * A pointer to the first matching character in lpszStr, or NULL if no
1079 LPSTR WINAPI
StrPBrkA(LPCSTR lpszStr
, LPCSTR lpszMatch
)
1081 TRACE("(%s,%s)\n",debugstr_a(lpszStr
), debugstr_a(lpszMatch
));
1083 if (lpszStr
&& lpszMatch
&& *lpszMatch
)
1087 if (StrChrA(lpszMatch
, *lpszStr
))
1088 return (LPSTR
)lpszStr
;
1089 lpszStr
= CharNextA(lpszStr
);
1095 /*************************************************************************
1096 * StrPBrkW [SHLWAPI.@]
1100 LPWSTR WINAPI
StrPBrkW(LPCWSTR lpszStr
, LPCWSTR lpszMatch
)
1102 TRACE("(%s,%s)\n",debugstr_w(lpszStr
), debugstr_w(lpszMatch
));
1104 if (lpszStr
&& lpszMatch
&& *lpszMatch
)
1108 if (StrChrW(lpszMatch
, *lpszStr
))
1109 return (LPWSTR
)lpszStr
;
1110 lpszStr
= CharNextW(lpszStr
);
1116 /*************************************************************************
1117 * SHLWAPI_StrRChrHelperA
1119 * Internal implementation of StrRChrA/StrRChrIA.
1121 static LPSTR WINAPI
SHLWAPI_StrRChrHelperA(LPCSTR lpszStr
,
1122 LPCSTR lpszEnd
, WORD ch
,
1123 BOOL (WINAPI
*pChrCmpFn
)(WORD
,WORD
))
1125 LPCSTR lpszRet
= NULL
;
1132 lpszEnd
= lpszStr
+ lstrlenA(lpszStr
);
1134 while (*lpszStr
&& lpszStr
<= lpszEnd
)
1136 ch2
= IsDBCSLeadByte(*lpszStr
)? *lpszStr
<< 8 | lpszStr
[1] : *lpszStr
;
1138 if (!pChrCmpFn(ch
, ch2
))
1140 lpszStr
= CharNextA(lpszStr
);
1143 return (LPSTR
)lpszRet
;
1146 /*************************************************************************
1147 * SHLWAPI_StrRChrHelperW
1149 * Internal implementation of StrRChrW/StrRChrIW.
1151 static LPWSTR WINAPI
SHLWAPI_StrRChrHelperW(LPCWSTR lpszStr
,
1152 LPCWSTR lpszEnd
, WCHAR ch
,
1153 BOOL (WINAPI
*pChrCmpFn
)(WCHAR
,WCHAR
))
1155 LPCWSTR lpszRet
= NULL
;
1160 lpszEnd
= lpszStr
+ strlenW(lpszStr
);
1162 while (*lpszStr
&& lpszStr
<= lpszEnd
)
1164 if (!pChrCmpFn(ch
, *lpszStr
))
1166 lpszStr
= CharNextW(lpszStr
);
1169 return (LPWSTR
)lpszRet
;
1172 /**************************************************************************
1173 * StrRChrA [SHLWAPI.@]
1175 * Find the last occurrence of a character in string.
1178 * lpszStr [I] String to search in
1179 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1180 * ch [I] Character to search for.
1183 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1184 * or NULL if not found.
1185 * Failure: NULL, if any arguments are invalid.
1187 LPSTR WINAPI
StrRChrA(LPCSTR lpszStr
, LPCSTR lpszEnd
, WORD ch
)
1189 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr
), debugstr_a(lpszEnd
), ch
);
1191 return SHLWAPI_StrRChrHelperA(lpszStr
, lpszEnd
, ch
, SHLWAPI_ChrCmpA
);
1194 /**************************************************************************
1195 * StrRChrW [SHLWAPI.@]
1199 LPWSTR WINAPI
StrRChrW(LPCWSTR lpszStr
, LPCWSTR lpszEnd
, WORD ch
)
1201 TRACE("(%s,%s,%x)\n", debugstr_w(lpszStr
), debugstr_w(lpszEnd
), ch
);
1203 return SHLWAPI_StrRChrHelperW(lpszStr
, lpszEnd
, ch
, SHLWAPI_ChrCmpW
);
1206 /**************************************************************************
1207 * StrRChrIA [SHLWAPI.@]
1209 * Find the last occurrence of a character in string, ignoring case.
1212 * lpszStr [I] String to search in
1213 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1214 * ch [I] Character to search for.
1217 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1218 * or NULL if not found.
1219 * Failure: NULL, if any arguments are invalid.
1221 LPSTR WINAPI
StrRChrIA(LPCSTR lpszStr
, LPCSTR lpszEnd
, WORD ch
)
1223 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr
), debugstr_a(lpszEnd
), ch
);
1225 return SHLWAPI_StrRChrHelperA(lpszStr
, lpszEnd
, ch
, ChrCmpIA
);
1228 /**************************************************************************
1229 * StrRChrIW [SHLWAPI.@]
1233 LPWSTR WINAPI
StrRChrIW(LPCWSTR lpszStr
, LPCWSTR lpszEnd
, WORD ch
)
1235 TRACE("(%s,%s,%x)\n", debugstr_w(lpszStr
), debugstr_w(lpszEnd
), ch
);
1237 return SHLWAPI_StrRChrHelperW(lpszStr
, lpszEnd
, ch
, ChrCmpIW
);
1240 /*************************************************************************
1241 * StrCatBuffA [SHLWAPI.@]
1243 * Concatenate two strings together.
1246 * lpszStr [O] String to concatenate to
1247 * lpszCat [I] String to add to lpszCat
1248 * cchMax [I] Maximum number of characters for the whole string
1254 * cchMax determines the number of characters in the final length of the
1255 * string, not the number appended to lpszStr from lpszCat.
1257 LPSTR WINAPI
StrCatBuffA(LPSTR lpszStr
, LPCSTR lpszCat
, INT cchMax
)
1261 TRACE("(%p,%s,%d)\n", lpszStr
, debugstr_a(lpszCat
), cchMax
);
1265 WARN("Invalid lpszStr would crash under Win32!\n");
1269 iLen
= strlen(lpszStr
);
1273 StrCpyNA(lpszStr
+ iLen
, lpszCat
, cchMax
);
1277 /*************************************************************************
1278 * StrCatBuffW [SHLWAPI.@]
1282 LPWSTR WINAPI
StrCatBuffW(LPWSTR lpszStr
, LPCWSTR lpszCat
, INT cchMax
)
1286 TRACE("(%p,%s,%d)\n", lpszStr
, debugstr_w(lpszCat
), cchMax
);
1290 WARN("Invalid lpszStr would crash under Win32!\n");
1294 iLen
= strlenW(lpszStr
);
1298 StrCpyNW(lpszStr
+ iLen
, lpszCat
, cchMax
);
1302 /*************************************************************************
1303 * StrRetToBufA [SHLWAPI.@]
1305 * Convert a STRRET to a normal string.
1308 * lpStrRet [O] STRRET to convert
1309 * pIdl [I] ITEMIDLIST for lpStrRet->uType == STRRET_OFFSET
1310 * lpszDest [O] Destination for normal string
1311 * dwLen [I] Length of lpszDest
1314 * Success: S_OK. lpszDest contains up to dwLen characters of the string.
1315 * If lpStrRet is of type STRRET_WSTR, its memory is freed with
1316 * CoTaskMemFree() and its type set to STRRET_CSTRA.
1317 * Failure: E_FAIL, if any parameters are invalid.
1319 HRESULT WINAPI
StrRetToBufA (LPSTRRET src
, const ITEMIDLIST
*pidl
, LPSTR dest
, UINT len
)
1322 * This routine is identical to that in dlls/shell32/shellstring.c.
1323 * It was duplicated because not every version of Shlwapi.dll exports
1324 * StrRetToBufA. If you change one routine, change them both.
1326 TRACE("dest=%p len=0x%x strret=%p pidl=%p stub\n",dest
,len
,src
,pidl
);
1330 WARN("Invalid lpStrRet would crash under Win32!\n");
1344 WideCharToMultiByte(CP_ACP
, 0, src
->u
.pOleStr
, -1, dest
, len
, NULL
, NULL
);
1345 CoTaskMemFree(src
->u
.pOleStr
);
1349 lstrcpynA((LPSTR
)dest
, src
->u
.cStr
, len
);
1353 lstrcpynA((LPSTR
)dest
, ((LPCSTR
)&pidl
->mkid
)+src
->u
.uOffset
, len
);
1357 FIXME("unknown type!\n");
1363 /*************************************************************************
1364 * StrRetToBufW [SHLWAPI.@]
1368 HRESULT WINAPI
StrRetToBufW (LPSTRRET src
, const ITEMIDLIST
*pidl
, LPWSTR dest
, UINT len
)
1370 TRACE("dest=%p len=0x%x strret=%p pidl=%p stub\n",dest
,len
,src
,pidl
);
1374 WARN("Invalid lpStrRet would crash under Win32!\n");
1388 lstrcpynW((LPWSTR
)dest
, src
->u
.pOleStr
, len
);
1389 CoTaskMemFree(src
->u
.pOleStr
);
1393 if (!MultiByteToWideChar( CP_ACP
, 0, src
->u
.cStr
, -1, dest
, len
) && len
)
1400 if (!MultiByteToWideChar( CP_ACP
, 0, ((LPCSTR
)&pidl
->mkid
)+src
->u
.uOffset
, -1,
1407 FIXME("unknown type!\n");
1413 /*************************************************************************
1414 * StrRetToStrA [SHLWAPI.@]
1416 * Converts a STRRET to a normal string.
1419 * lpStrRet [O] STRRET to convert
1420 * pidl [I] ITEMIDLIST for lpStrRet->uType == STRRET_OFFSET
1421 * ppszName [O] Destination for converted string
1424 * Success: S_OK. ppszName contains the new string, allocated with CoTaskMemAlloc().
1425 * Failure: E_FAIL, if any parameters are invalid.
1427 HRESULT WINAPI
StrRetToStrA(LPSTRRET lpStrRet
, const ITEMIDLIST
*pidl
, LPSTR
*ppszName
)
1429 HRESULT hRet
= E_FAIL
;
1431 switch (lpStrRet
->uType
)
1434 hRet
= _SHStrDupAW(lpStrRet
->u
.pOleStr
, ppszName
);
1435 CoTaskMemFree(lpStrRet
->u
.pOleStr
);
1439 hRet
= _SHStrDupAA(lpStrRet
->u
.cStr
, ppszName
);
1443 hRet
= _SHStrDupAA(((LPCSTR
)&pidl
->mkid
) + lpStrRet
->u
.uOffset
, ppszName
);
1453 /*************************************************************************
1454 * StrRetToStrW [SHLWAPI.@]
1458 HRESULT WINAPI
StrRetToStrW(LPSTRRET lpStrRet
, const ITEMIDLIST
*pidl
, LPWSTR
*ppszName
)
1460 HRESULT hRet
= E_FAIL
;
1462 switch (lpStrRet
->uType
)
1465 hRet
= SHStrDupW(lpStrRet
->u
.pOleStr
, ppszName
);
1466 CoTaskMemFree(lpStrRet
->u
.pOleStr
);
1470 hRet
= SHStrDupA(lpStrRet
->u
.cStr
, ppszName
);
1474 hRet
= SHStrDupA(((LPCSTR
)&pidl
->mkid
) + lpStrRet
->u
.uOffset
, ppszName
);
1484 /* Create an ASCII string copy using SysAllocString() */
1485 static HRESULT
_SHStrDupAToBSTR(LPCSTR src
, BSTR
*pBstrOut
)
1491 INT len
= MultiByteToWideChar(CP_ACP
, 0, src
, -1, NULL
, 0);
1492 WCHAR
* szTemp
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1496 MultiByteToWideChar(CP_ACP
, 0, src
, -1, szTemp
, len
);
1497 *pBstrOut
= SysAllocString(szTemp
);
1498 HeapFree(GetProcessHeap(), 0, szTemp
);
1504 return E_OUTOFMEMORY
;
1507 /*************************************************************************
1508 * StrRetToBSTR [SHLWAPI.@]
1510 * Converts a STRRET to a BSTR.
1513 * lpStrRet [O] STRRET to convert
1514 * pidl [I] ITEMIDLIST for lpStrRet->uType = STRRET_OFFSET
1515 * pBstrOut [O] Destination for converted BSTR
1518 * Success: S_OK. pBstrOut contains the new string.
1519 * Failure: E_FAIL, if any parameters are invalid.
1521 HRESULT WINAPI
StrRetToBSTR(STRRET
*lpStrRet
, LPCITEMIDLIST pidl
, BSTR
* pBstrOut
)
1523 HRESULT hRet
= E_FAIL
;
1525 switch (lpStrRet
->uType
)
1528 *pBstrOut
= SysAllocString(lpStrRet
->u
.pOleStr
);
1531 CoTaskMemFree(lpStrRet
->u
.pOleStr
);
1535 hRet
= _SHStrDupAToBSTR(lpStrRet
->u
.cStr
, pBstrOut
);
1539 hRet
= _SHStrDupAToBSTR(((LPCSTR
)&pidl
->mkid
) + lpStrRet
->u
.uOffset
, pBstrOut
);
1549 /*************************************************************************
1550 * StrFormatKBSizeA [SHLWAPI.@]
1552 * Create a formatted string containing a byte count in Kilobytes.
1555 * llBytes [I] Byte size to format
1556 * lpszDest [I] Destination for formatted string
1557 * cchMax [I] Size of lpszDest
1562 LPSTR WINAPI
StrFormatKBSizeA(LONGLONG llBytes
, LPSTR lpszDest
, UINT cchMax
)
1564 char szBuff
[256], *szOut
= szBuff
+ sizeof(szBuff
) - 1;
1565 LONGLONG ulKB
= (llBytes
+ 1023) >> 10;
1567 TRACE("(%lld,%p,%d)\n", llBytes
, lpszDest
, cchMax
);
1576 LONGLONG ulNextDigit
= ulKB
% 10;
1577 *szOut
-- = '0' + ulNextDigit
;
1578 ulKB
= (ulKB
- ulNextDigit
) / 10;
1581 lstrcpynA(lpszDest
, szOut
+ 1, cchMax
);
1585 /*************************************************************************
1586 * StrFormatKBSizeW [SHLWAPI.@]
1588 * See StrFormatKBSizeA.
1590 LPWSTR WINAPI
StrFormatKBSizeW(LONGLONG llBytes
, LPWSTR lpszDest
, UINT cchMax
)
1592 WCHAR szBuff
[256], *szOut
= szBuff
+ sizeof(szBuff
)/sizeof(WCHAR
) - 1;
1593 LONGLONG ulKB
= (llBytes
+ 1023) >> 10;
1595 TRACE("(%lld,%p,%d)\n", llBytes
, lpszDest
, cchMax
);
1604 LONGLONG ulNextDigit
= ulKB
% 10;
1605 *szOut
-- = '0' + ulNextDigit
;
1606 ulKB
= (ulKB
- ulNextDigit
) / 10;
1609 lstrcpynW(lpszDest
, szOut
+ 1, cchMax
);
1613 /*************************************************************************
1614 * StrNCatA [SHLWAPI.@]
1616 * Concatenate two strings together.
1619 * lpszStr [O] String to concatenate to
1620 * lpszCat [I] String to add to lpszCat
1621 * cchMax [I] Maximum number of characters to concatenate
1627 * cchMax determines the number of characters that are appended to lpszStr,
1628 * not the total length of the string.
1630 LPSTR WINAPI
StrNCatA(LPSTR lpszStr
, LPCSTR lpszCat
, INT cchMax
)
1632 LPSTR lpszRet
= lpszStr
;
1634 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr
), debugstr_a(lpszCat
), cchMax
);
1638 WARN("Invalid lpszStr would crash under Win32!\n");
1642 StrCpyNA(lpszStr
+ strlen(lpszStr
), lpszCat
, cchMax
);
1646 /*************************************************************************
1647 * StrNCatW [SHLWAPI.@]
1651 LPWSTR WINAPI
StrNCatW(LPWSTR lpszStr
, LPCWSTR lpszCat
, INT cchMax
)
1653 LPWSTR lpszRet
= lpszStr
;
1655 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr
), debugstr_w(lpszCat
), cchMax
);
1659 WARN("Invalid lpszStr would crash under Win32\n");
1663 StrCpyNW(lpszStr
+ strlenW(lpszStr
), lpszCat
, cchMax
);
1667 /*************************************************************************
1668 * StrTrimA [SHLWAPI.@]
1670 * Remove characters from the start and end of a string.
1673 * lpszStr [O] String to remove characters from
1674 * lpszTrim [I] Characters to remove from lpszStr
1677 * TRUE If lpszStr was valid and modified
1680 BOOL WINAPI
StrTrimA(LPSTR lpszStr
, LPCSTR lpszTrim
)
1683 LPSTR lpszRead
= lpszStr
;
1686 TRACE("(%s,%s)\n", debugstr_a(lpszStr
), debugstr_a(lpszTrim
));
1688 if (lpszRead
&& *lpszRead
)
1690 while (*lpszRead
&& StrChrA(lpszTrim
, *lpszRead
))
1691 lpszRead
= CharNextA(lpszRead
); /* Skip leading matches */
1693 dwLen
= strlen(lpszRead
);
1695 if (lpszRead
!= lpszStr
)
1697 memmove(lpszStr
, lpszRead
, dwLen
+ 1);
1702 lpszRead
= lpszStr
+ dwLen
;
1703 while (StrChrA(lpszTrim
, lpszRead
[-1]))
1704 lpszRead
= CharPrevA(lpszStr
, lpszRead
); /* Skip trailing matches */
1706 if (lpszRead
!= lpszStr
+ dwLen
)
1716 /*************************************************************************
1717 * StrTrimW [SHLWAPI.@]
1721 BOOL WINAPI
StrTrimW(LPWSTR lpszStr
, LPCWSTR lpszTrim
)
1724 LPWSTR lpszRead
= lpszStr
;
1727 TRACE("(%s,%s)\n", debugstr_w(lpszStr
), debugstr_w(lpszTrim
));
1729 if (lpszRead
&& *lpszRead
)
1731 while (*lpszRead
&& StrChrW(lpszTrim
, *lpszRead
))
1732 lpszRead
= CharNextW(lpszRead
); /* Skip leading matches */
1734 dwLen
= strlenW(lpszRead
);
1736 if (lpszRead
!= lpszStr
)
1738 memmove(lpszStr
, lpszRead
, (dwLen
+ 1) * sizeof(WCHAR
));
1743 lpszRead
= lpszStr
+ dwLen
;
1744 while (StrChrW(lpszTrim
, lpszRead
[-1]))
1745 lpszRead
= CharPrevW(lpszStr
, lpszRead
); /* Skip trailing matches */
1747 if (lpszRead
!= lpszStr
+ dwLen
)
1757 /*************************************************************************
1758 * _SHStrDupAA [INTERNAL]
1760 * Duplicates a ASCII string to ASCII. The destination buffer is allocated.
1762 static HRESULT WINAPI
_SHStrDupAA(LPCSTR src
, LPSTR
* dest
)
1768 len
= lstrlenA(src
) + 1;
1769 *dest
= CoTaskMemAlloc(len
);
1775 lstrcpynA(*dest
,src
, len
);
1781 TRACE("%s->(%p)\n", debugstr_a(src
), *dest
);
1785 /*************************************************************************
1786 * SHStrDupA [SHLWAPI.@]
1788 * Return a Unicode copy of a string, in memory allocated by CoTaskMemAlloc().
1791 * lpszStr [I] String to copy
1792 * lppszDest [O] Destination for the new string copy
1795 * Success: S_OK. lppszDest contains the new string in Unicode format.
1796 * Failure: E_OUTOFMEMORY, If any arguments are invalid or memory allocation
1799 HRESULT WINAPI
SHStrDupA(LPCSTR lpszStr
, LPWSTR
* lppszDest
)
1806 len
= MultiByteToWideChar(0, 0, lpszStr
, -1, 0, 0) * sizeof(WCHAR
);
1807 *lppszDest
= CoTaskMemAlloc(len
);
1814 MultiByteToWideChar(0, 0, lpszStr
, -1, *lppszDest
, len
/sizeof(WCHAR
));
1818 hRet
= E_OUTOFMEMORY
;
1820 TRACE("%s->(%p)\n", debugstr_a(lpszStr
), *lppszDest
);
1824 /*************************************************************************
1825 * _SHStrDupAW [INTERNAL]
1827 * Duplicates a UNICODE to a ASCII string. The destination buffer is allocated.
1829 static HRESULT WINAPI
_SHStrDupAW(LPCWSTR src
, LPSTR
* dest
)
1835 len
= WideCharToMultiByte(CP_ACP
, 0, src
, -1, NULL
, 0, NULL
, NULL
);
1836 *dest
= CoTaskMemAlloc(len
);
1842 WideCharToMultiByte(CP_ACP
, 0, src
, -1, *dest
, len
, NULL
, NULL
);
1848 TRACE("%s->(%p)\n", debugstr_w(src
), *dest
);
1852 /*************************************************************************
1853 * SHStrDupW [SHLWAPI.@]
1857 HRESULT WINAPI
SHStrDupW(LPCWSTR src
, LPWSTR
* dest
)
1863 len
= (lstrlenW(src
) + 1) * sizeof(WCHAR
);
1864 *dest
= CoTaskMemAlloc(len
);
1870 memcpy(*dest
, src
, len
);
1876 TRACE("%s->(%p)\n", debugstr_w(src
), *dest
);
1880 /*************************************************************************
1881 * SHLWAPI_WriteReverseNum
1883 * Internal helper for SHLWAPI_WriteTimeClass.
1885 inline static LPWSTR
SHLWAPI_WriteReverseNum(LPWSTR lpszOut
, DWORD dwNum
)
1889 /* Write a decimal number to a string, backwards */
1892 DWORD dwNextDigit
= dwNum
% 10;
1893 *lpszOut
-- = '0' + dwNextDigit
;
1894 dwNum
= (dwNum
- dwNextDigit
) / 10;
1895 } while (dwNum
> 0);
1900 /*************************************************************************
1901 * SHLWAPI_FormatSignificant
1903 * Internal helper for SHLWAPI_WriteTimeClass.
1905 inline static int SHLWAPI_FormatSignificant(LPWSTR lpszNum
, int dwDigits
)
1907 /* Zero non significant digits, return remaining significant digits */
1911 if (--dwDigits
== 0)
1921 /*************************************************************************
1922 * SHLWAPI_WriteTimeClass
1924 * Internal helper for StrFromTimeIntervalW.
1926 static int WINAPI
SHLWAPI_WriteTimeClass(LPWSTR lpszOut
, DWORD dwValue
,
1927 LPCWSTR lpszClass
, int iDigits
)
1929 WCHAR szBuff
[64], *szOut
= szBuff
+ 32;
1931 szOut
= SHLWAPI_WriteReverseNum(szOut
, dwValue
);
1932 iDigits
= SHLWAPI_FormatSignificant(szOut
+ 1, iDigits
);
1934 strcpyW(szBuff
+ 32, lpszClass
);
1935 strcatW(lpszOut
, szOut
);
1939 /*************************************************************************
1940 * StrFromTimeIntervalA [SHLWAPI.@]
1942 * Format a millisecond time interval into a string
1945 * lpszStr [O] Output buffer for formatted time interval
1946 * cchMax [I] Size of lpszStr
1947 * dwMS [I] Number of milliseconds
1948 * iDigits [I] Number of digits to print
1951 * The length of the formatted string, or 0 if any parameter is invalid.
1954 * This implementation mimics the Win32 behaviour of always writing a leading
1955 * space before the time interval begins.
1957 * iDigits is used to provide approximate times if accuracy is not important.
1958 * This number of digits will be written of the first non-zero time class
1959 * (hours/minutes/seconds). If this does not complete the time classification,
1960 * the remaining digits are changed to zeros (i.e. The time is _not_ rounded).
1961 * If there are digits remaining following the writing of a time class, the
1962 * next time class will be written.
1964 * For example, given dwMS represents 138 hours,43 minutes and 15 seconds, the
1965 * following will result from the given values of iDigits:
1967 *| iDigits 1 2 3 4 5 ...
1968 *| lpszStr "100 hr" "130 hr" "138 hr" "138 hr 40 min" "138 hr 43 min" ...
1970 INT WINAPI
StrFromTimeIntervalA(LPSTR lpszStr
, UINT cchMax
, DWORD dwMS
,
1975 TRACE("(%p,%d,%ld,%d)\n", lpszStr
, cchMax
, dwMS
, iDigits
);
1977 if (lpszStr
&& cchMax
)
1980 StrFromTimeIntervalW(szBuff
, sizeof(szBuff
)/sizeof(WCHAR
), dwMS
, iDigits
);
1981 WideCharToMultiByte(CP_ACP
,0,szBuff
,-1,lpszStr
,cchMax
,0,0);
1987 /*************************************************************************
1988 * StrFromTimeIntervalW [SHLWAPI.@]
1990 * See StrFromTimeIntervalA.
1992 INT WINAPI
StrFromTimeIntervalW(LPWSTR lpszStr
, UINT cchMax
, DWORD dwMS
,
1995 static const WCHAR szHr
[] = {' ','h','r','\0'};
1996 static const WCHAR szMin
[] = {' ','m','i','n','\0'};
1997 static const WCHAR szSec
[] = {' ','s','e','c','\0'};
2000 TRACE("(%p,%d,%ld,%d)\n", lpszStr
, cchMax
, dwMS
, iDigits
);
2002 if (lpszStr
&& cchMax
)
2005 DWORD dwHours
, dwMinutes
;
2007 if (!iDigits
|| cchMax
== 1)
2013 /* Calculate the time classes */
2014 dwMS
= (dwMS
+ 500) / 1000;
2015 dwHours
= dwMS
/ 3600;
2016 dwMS
-= dwHours
* 3600;
2017 dwMinutes
= dwMS
/ 60;
2018 dwMS
-= dwMinutes
* 60;
2023 iDigits
= SHLWAPI_WriteTimeClass(szCopy
, dwHours
, szHr
, iDigits
);
2025 if (dwMinutes
&& iDigits
)
2026 iDigits
= SHLWAPI_WriteTimeClass(szCopy
, dwMinutes
, szMin
, iDigits
);
2028 if (iDigits
) /* Always write seconds if we have significant digits */
2029 SHLWAPI_WriteTimeClass(szCopy
, dwMS
, szSec
, iDigits
);
2031 lstrcpynW(lpszStr
, szCopy
, cchMax
);
2032 iRet
= strlenW(lpszStr
);
2037 /*************************************************************************
2038 * StrIsIntlEqualA [SHLWAPI.@]
2040 * Compare two strings.
2043 * bCase [I] Whether to compare case sensitively
2044 * lpszStr [I] First string to compare
2045 * lpszComp [I] Second string to compare
2046 * iLen [I] Length to compare
2049 * TRUE If the strings are equal.
2052 BOOL WINAPI
StrIsIntlEqualA(BOOL bCase
, LPCSTR lpszStr
, LPCSTR lpszComp
,
2057 TRACE("(%d,%s,%s,%d)\n", bCase
,
2058 debugstr_a(lpszStr
), debugstr_a(lpszComp
), iLen
);
2060 /* FIXME: This flag is undocumented and unknown by our CompareString.
2061 * We need a define for it.
2063 dwFlags
= 0x10000000;
2064 if (!bCase
) dwFlags
|= NORM_IGNORECASE
;
2066 return (CompareStringA(GetThreadLocale(), dwFlags
, lpszStr
, iLen
, lpszComp
, iLen
) == CSTR_EQUAL
);
2069 /*************************************************************************
2070 * StrIsIntlEqualW [SHLWAPI.@]
2072 * See StrIsIntlEqualA.
2074 BOOL WINAPI
StrIsIntlEqualW(BOOL bCase
, LPCWSTR lpszStr
, LPCWSTR lpszComp
,
2079 TRACE("(%d,%s,%s,%d)\n", bCase
,
2080 debugstr_w(lpszStr
),debugstr_w(lpszComp
), iLen
);
2082 /* FIXME: This flag is undocumented and unknown by our CompareString.
2083 * We need a define for it.
2085 dwFlags
= 0x10000000;
2086 if (!bCase
) dwFlags
|= NORM_IGNORECASE
;
2088 return (CompareStringW(GetThreadLocale(), dwFlags
, lpszStr
, iLen
, lpszComp
, iLen
) == CSTR_EQUAL
);
2091 /*************************************************************************
2094 * Copy a string to another string, up to a maximum number of characters.
2097 * lpszDest [O] Destination string
2098 * lpszSrc [I] Source string
2099 * iLen [I] Maximum number of chars to copy
2102 * Success: A pointer to the last character written to lpszDest..
2103 * Failure: lpszDest, if any arguments are invalid.
2105 LPSTR WINAPI
StrCpyNXA(LPSTR lpszDest
, LPCSTR lpszSrc
, int iLen
)
2107 TRACE("(%p,%s,%i)\n", lpszDest
, debugstr_a(lpszSrc
), iLen
);
2109 if (lpszDest
&& lpszSrc
&& iLen
> 0)
2111 while ((iLen
-- > 1) && *lpszSrc
)
2112 *lpszDest
++ = *lpszSrc
++;
2119 /*************************************************************************
2122 * Unicode version of StrCpyNXA.
2124 LPWSTR WINAPI
StrCpyNXW(LPWSTR lpszDest
, LPCWSTR lpszSrc
, int iLen
)
2126 TRACE("(%p,%s,%i)\n", lpszDest
, debugstr_w(lpszSrc
), iLen
);
2128 if (lpszDest
&& lpszSrc
&& iLen
> 0)
2130 while ((iLen
-- > 1) && *lpszSrc
)
2131 *lpszDest
++ = *lpszSrc
++;
2138 /*************************************************************************
2139 * StrCmpLogicalW [SHLWAPI.@]
2141 * Compare two strings, ignoring case and comparing digits as numbers.
2144 * lpszStr [I] First string to compare
2145 * lpszComp [I] Second string to compare
2146 * iLen [I] Length to compare
2149 * TRUE If the strings are equal.
2152 INT WINAPI
StrCmpLogicalW(LPCWSTR lpszStr
, LPCWSTR lpszComp
)
2156 TRACE("(%s,%s)\n", debugstr_w(lpszStr
), debugstr_w(lpszComp
));
2158 if (lpszStr
&& lpszComp
)
2164 else if (isdigitW(*lpszStr
))
2168 if (!isdigitW(*lpszComp
))
2171 /* Compare the numbers */
2172 StrToIntExW(lpszStr
, 0, &iStr
);
2173 StrToIntExW(lpszComp
, 0, &iComp
);
2177 else if (iStr
> iComp
)
2181 while (isdigitW(*lpszStr
))
2183 while (isdigitW(*lpszComp
))
2186 else if (isdigitW(*lpszComp
))
2190 iDiff
= SHLWAPI_ChrCmpHelperW(*lpszStr
,*lpszComp
,NORM_IGNORECASE
);
2206 /* Structure for formatting byte strings */
2207 typedef struct tagSHLWAPI_BYTEFORMATS
2212 LPCWSTR lpwszFormat
;
2214 } SHLWAPI_BYTEFORMATS
;
2216 /*************************************************************************
2217 * StrFormatByteSizeW [SHLWAPI.@]
2219 * Create a string containing an abbreviated byte count of up to 2^63-1.
2222 * llBytes [I] Byte size to format
2223 * lpszDest [I] Destination for formatted string
2224 * cchMax [I] Size of lpszDest
2230 * There is no StrFormatByteSize64W function, it is called StrFormatByteSizeW().
2232 LPWSTR WINAPI
StrFormatByteSizeW(LONGLONG llBytes
, LPWSTR lpszDest
, UINT cchMax
)
2234 static const WCHAR wszBytes
[] = {'%','l','d',' ','b','y','t','e','s',0};
2235 static const WCHAR wsz3_0
[] = {'%','3','.','0','f',0};
2236 static const WCHAR wsz3_1
[] = {'%','3','.','1','f',0};
2237 static const WCHAR wsz3_2
[] = {'%','3','.','2','f',0};
2239 #define KB ((ULONGLONG)1024)
2241 #define GB (KB*KB*KB)
2242 #define TB (KB*KB*KB*KB)
2243 #define PB (KB*KB*KB*KB*KB)
2245 static const SHLWAPI_BYTEFORMATS bfFormats
[] =
2247 { 10*KB
, 10.24, 100.0, wsz3_2
, 'K' }, /* 10 KB */
2248 { 100*KB
, 102.4, 10.0, wsz3_1
, 'K' }, /* 100 KB */
2249 { 1000*KB
, 1024.0, 1.0, wsz3_0
, 'K' }, /* 1000 KB */
2250 { 10*MB
, 10485.76, 100.0, wsz3_2
, 'M' }, /* 10 MB */
2251 { 100*MB
, 104857.6, 10.0, wsz3_1
, 'M' }, /* 100 MB */
2252 { 1000*MB
, 1048576.0, 1.0, wsz3_0
, 'M' }, /* 1000 MB */
2253 { 10*GB
, 10737418.24, 100.0, wsz3_2
, 'G' }, /* 10 GB */
2254 { 100*GB
, 107374182.4, 10.0, wsz3_1
, 'G' }, /* 100 GB */
2255 { 1000*GB
, 1073741824.0, 1.0, wsz3_0
, 'G' }, /* 1000 GB */
2256 { 10*TB
, 10485.76, 100.0, wsz3_2
, 'T' }, /* 10 TB */
2257 { 100*TB
, 104857.6, 10.0, wsz3_1
, 'T' }, /* 100 TB */
2258 { 1000*TB
, 1048576.0, 1.0, wsz3_0
, 'T' }, /* 1000 TB */
2259 { 10*PB
, 10737418.24, 100.00, wsz3_2
, 'P' }, /* 10 PB */
2260 { 100*PB
, 107374182.4, 10.00, wsz3_1
, 'P' }, /* 100 PB */
2261 { 1000*PB
, 1073741824.0, 1.00, wsz3_0
, 'P' }, /* 1000 PB */
2262 { 0, 10995116277.76, 100.00, wsz3_2
, 'E' } /* EB's, catch all */
2265 WCHAR wszAdd
[] = {' ','?','B',0};
2269 TRACE("(%lld,%p,%d)\n", llBytes
, lpszDest
, cchMax
);
2271 if (!lpszDest
|| !cchMax
)
2274 if (llBytes
< 1024) /* 1K */
2276 snprintfW(lpszDest
, cchMax
, wszBytes
, (long)llBytes
);
2280 /* Note that if this loop completes without finding a match, i will be
2281 * pointing at the last entry, which is a catch all for > 1000 PB
2283 while (i
< sizeof(bfFormats
) / sizeof(SHLWAPI_BYTEFORMATS
) - 1)
2285 if (llBytes
< bfFormats
[i
].dLimit
)
2289 /* Above 1 TB we encounter problems with FP accuracy. So for amounts above
2290 * this number we integer shift down by 1 MB first. The table above has
2291 * the divisors scaled down from the '< 10 TB' entry onwards, to account
2292 * for this. We also add a small fudge factor to get the correct result for
2293 * counts that lie exactly on a 1024 byte boundary.
2296 dBytes
= (double)(llBytes
>> 20) + 0.001; /* Scale down by I MB */
2298 dBytes
= (double)llBytes
+ 0.00001;
2300 dBytes
= floor(dBytes
/ bfFormats
[i
].dDivisor
) / bfFormats
[i
].dNormaliser
;
2302 sprintfW(wszBuff
, bfFormats
[i
].lpwszFormat
, dBytes
);
2303 wszAdd
[1] = bfFormats
[i
].wPrefix
;
2304 strcatW(wszBuff
, wszAdd
);
2305 lstrcpynW(lpszDest
, wszBuff
, cchMax
);
2309 /*************************************************************************
2310 * StrFormatByteSize64A [SHLWAPI.@]
2312 * See StrFormatByteSizeW.
2314 LPSTR WINAPI
StrFormatByteSize64A(LONGLONG llBytes
, LPSTR lpszDest
, UINT cchMax
)
2318 StrFormatByteSizeW(llBytes
, wszBuff
, sizeof(wszBuff
)/sizeof(WCHAR
));
2321 WideCharToMultiByte(CP_ACP
, 0, wszBuff
, -1, lpszDest
, cchMax
, 0, 0);
2325 /*************************************************************************
2326 * StrFormatByteSizeA [SHLWAPI.@]
2328 * Create a string containing an abbreviated byte count of up to 2^31-1.
2331 * dwBytes [I] Byte size to format
2332 * lpszDest [I] Destination for formatted string
2333 * cchMax [I] Size of lpszDest
2339 * The Ascii and Unicode versions of this function accept a different
2340 * integer type for dwBytes. See StrFormatByteSize64A().
2342 LPSTR WINAPI
StrFormatByteSizeA(DWORD dwBytes
, LPSTR lpszDest
, UINT cchMax
)
2344 TRACE("(%ld,%p,%d)\n", dwBytes
, lpszDest
, cchMax
);
2346 return StrFormatByteSize64A(dwBytes
, lpszDest
, cchMax
);
2349 /*************************************************************************
2352 * Remove a hanging lead byte from the end of a string, if present.
2355 * lpStr [I] String to check for a hanging lead byte
2356 * size [I] Length of lpStr
2359 * Success: The new length of the string. Any hanging lead bytes are removed.
2360 * Failure: 0, if any parameters are invalid.
2362 DWORD WINAPI
SHTruncateString(LPSTR lpStr
, DWORD size
)
2366 LPSTR lastByte
= lpStr
+ size
- 1;
2368 while(lpStr
< lastByte
)
2369 lpStr
+= IsDBCSLeadByte(*lpStr
) ? 2 : 1;
2371 if(lpStr
== lastByte
&& IsDBCSLeadByte(*lpStr
))
2381 /*************************************************************************
2384 * Remove a single non-trailing ampersand ('&') from a string.
2387 * lpszStr [I/O] String to remove ampersand from.
2390 * The character after the first ampersand in lpszStr, or the first character
2391 * in lpszStr if there is no ampersand in the string.
2393 char WINAPI
SHStripMneumonicA(LPCSTR lpszStr
)
2395 LPSTR lpszIter
, lpszTmp
;
2398 TRACE("(%s)\n", debugstr_a(lpszStr
));
2402 if ((lpszIter
= StrChrA(lpszStr
, '&')))
2404 lpszTmp
= CharNextA(lpszIter
);
2405 if (lpszTmp
&& *lpszTmp
)
2407 if (*lpszTmp
!= '&')
2410 while (lpszIter
&& *lpszIter
)
2412 lpszTmp
= CharNextA(lpszIter
);
2413 *lpszIter
= *lpszTmp
;
2422 /*************************************************************************
2425 * Unicode version of SHStripMneumonicA.
2427 WCHAR WINAPI
SHStripMneumonicW(LPCWSTR lpszStr
)
2429 LPWSTR lpszIter
, lpszTmp
;
2432 TRACE("(%s)\n", debugstr_w(lpszStr
));
2436 if ((lpszIter
= StrChrW(lpszStr
, '&')))
2438 lpszTmp
= CharNextW(lpszIter
);
2439 if (lpszTmp
&& *lpszTmp
)
2441 if (*lpszTmp
!= '&')
2444 while (lpszIter
&& *lpszIter
)
2446 lpszTmp
= CharNextW(lpszIter
);
2447 *lpszIter
= *lpszTmp
;
2456 /*************************************************************************
2459 * Convert an Ascii string to Unicode.
2462 * dwCp [I] Code page for the conversion
2463 * lpSrcStr [I] Source Ascii string to convert
2464 * lpDstStr [O] Destination for converted Unicode string
2465 * iLen [I] Length of lpDstStr
2468 * The return value of the MultiByteToWideChar() function called on lpSrcStr.
2470 DWORD WINAPI
SHAnsiToUnicodeCP(DWORD dwCp
, LPCSTR lpSrcStr
, LPWSTR lpDstStr
, int iLen
)
2474 dwRet
= MultiByteToWideChar(dwCp
, 0, lpSrcStr
, -1, lpDstStr
, iLen
);
2475 TRACE("%s->%s,ret=%ld\n", debugstr_a(lpSrcStr
), debugstr_w(lpDstStr
), dwRet
);
2479 /*************************************************************************
2482 * Convert an Ascii string to Unicode.
2485 * lpSrcStr [I] Source Ascii string to convert
2486 * lpDstStr [O] Destination for converted Unicode string
2487 * iLen [I] Length of lpDstStr
2490 * The return value of the MultiByteToWideChar() function called on lpSrcStr.
2493 * This function simply calls SHAnsiToUnicodeCP with code page CP_ACP.
2495 DWORD WINAPI
SHAnsiToUnicode(LPCSTR lpSrcStr
, LPWSTR lpDstStr
, int iLen
)
2497 return SHAnsiToUnicodeCP(CP_ACP
, lpSrcStr
, lpDstStr
, iLen
);
2500 /*************************************************************************
2503 * Convert a Unicode string to Ascii.
2506 * CodePage [I] Code page to use for the conversion
2507 * lpSrcStr [I] Source Unicode string to convert
2508 * lpDstStr [O] Destination for converted Ascii string
2509 * lpiLen [I/O] Input length of lpDstStr/destination for length of lpDstStr
2512 * Success: The number of characters that result from the conversion.
2515 INT WINAPI
SHUnicodeToAnsiCP(UINT CodePage
, LPCWSTR lpSrcStr
, LPSTR lpDstStr
,
2518 static const WCHAR emptyW
[] = { '\0' };
2522 if (!lpDstStr
|| !lpiLen
)
2530 len
= strlenW(lpSrcStr
) + 1;
2535 CodePage
= CP_UTF8
; /* Fall through... */
2536 case 0x0000C350: /* FIXME: CP_ #define */
2541 INT nWideCharCount
= len
- 1;
2543 GET_FUNC(pConvertINetUnicodeToMultiByte
, mlang
, "ConvertINetUnicodeToMultiByte", 0);
2544 if (!pConvertINetUnicodeToMultiByte(&dwMode
, CodePage
, lpSrcStr
, &nWideCharCount
, lpDstStr
,
2548 if (nWideCharCount
< len
- 1)
2550 mem
= HeapAlloc(GetProcessHeap(), 0, *lpiLen
);
2556 if (pConvertINetUnicodeToMultiByte(&dwMode
, CodePage
, lpSrcStr
, &len
, mem
, lpiLen
))
2558 SHTruncateString(mem
, *lpiLen
);
2559 lstrcpynA(lpDstStr
, mem
, *lpiLen
+ 1);
2560 HeapFree(GetProcessHeap(), 0, mem
);
2563 HeapFree(GetProcessHeap(), 0, mem
);
2566 lpDstStr
[*lpiLen
] = '\0';
2573 reqLen
= WideCharToMultiByte(CodePage
, 0, lpSrcStr
, len
, lpDstStr
,
2574 *lpiLen
, NULL
, NULL
);
2576 if (!reqLen
&& GetLastError() == ERROR_INSUFFICIENT_BUFFER
)
2578 reqLen
= WideCharToMultiByte(CodePage
, 0, lpSrcStr
, len
, NULL
, 0, NULL
, NULL
);
2581 mem
= HeapAlloc(GetProcessHeap(), 0, reqLen
);
2584 reqLen
= WideCharToMultiByte(CodePage
, 0, lpSrcStr
, len
, mem
,
2585 reqLen
, NULL
, NULL
);
2587 reqLen
= SHTruncateString(mem
, *lpiLen
);
2590 lstrcpynA(lpDstStr
, mem
, *lpiLen
);
2592 HeapFree(GetProcessHeap(), 0, mem
);
2599 /*************************************************************************
2602 * Convert a Unicode string to Ascii.
2605 * lpSrcStr [I] Source Unicode string to convert
2606 * lpDstStr [O] Destination for converted Ascii string
2607 * iLen [O] Length of lpDstStr in characters
2610 * See SHUnicodeToAnsiCP
2613 * This function simply calls SHUnicodeToAnsiCP() with CodePage = CP_ACP.
2615 INT WINAPI
SHUnicodeToAnsi(LPCWSTR lpSrcStr
, LPSTR lpDstStr
, INT iLen
)
2619 return SHUnicodeToAnsiCP(CP_ACP
, lpSrcStr
, lpDstStr
, &myint
);
2622 /*************************************************************************
2625 * Copy one string to another.
2628 * lpszSrc [I] Source string to copy
2629 * lpszDst [O] Destination for copy
2630 * iLen [I] Length of lpszDst in characters
2633 * The length of the copied string, including the terminating NUL. lpszDst
2634 * contains iLen characters of lpszSrc.
2636 DWORD WINAPI
SHAnsiToAnsi(LPCSTR lpszSrc
, LPSTR lpszDst
, int iLen
)
2640 TRACE("(%s,%p,0x%08x)\n", debugstr_a(lpszSrc
), lpszDst
, iLen
);
2642 lpszRet
= StrCpyNXA(lpszDst
, lpszSrc
, iLen
);
2643 return lpszRet
- lpszDst
+ 1;
2646 /*************************************************************************
2649 * Unicode version of SSHAnsiToAnsi.
2651 DWORD WINAPI
SHUnicodeToUnicode(LPCWSTR lpszSrc
, LPWSTR lpszDst
, int iLen
)
2655 TRACE("(%s,%p,0x%08x)\n", debugstr_w(lpszSrc
), lpszDst
, iLen
);
2657 lpszRet
= StrCpyNXW(lpszDst
, lpszSrc
, iLen
);
2658 return lpszRet
- lpszDst
+ 1;
2661 /*************************************************************************
2664 * Determine if an Ascii string converts to Unicode and back identically.
2667 * lpSrcStr [I] Source Unicode string to convert
2668 * lpDst [O] Destination for resulting Ascii string
2669 * iLen [I] Length of lpDst in characters
2672 * TRUE, since Ascii strings always convert identically.
2674 BOOL WINAPI
DoesStringRoundTripA(LPCSTR lpSrcStr
, LPSTR lpDst
, INT iLen
)
2676 lstrcpynA(lpDst
, lpSrcStr
, iLen
);
2680 /*************************************************************************
2683 * Determine if a Unicode string converts to Ascii and back identically.
2686 * lpSrcStr [I] Source Unicode string to convert
2687 * lpDst [O] Destination for resulting Ascii string
2688 * iLen [I] Length of lpDst in characters
2691 * TRUE, if lpSrcStr converts to Ascii and back identically,
2694 BOOL WINAPI
DoesStringRoundTripW(LPCWSTR lpSrcStr
, LPSTR lpDst
, INT iLen
)
2696 WCHAR szBuff
[MAX_PATH
];
2698 SHUnicodeToAnsi(lpSrcStr
, lpDst
, iLen
);
2699 SHAnsiToUnicode(lpDst
, szBuff
, MAX_PATH
);
2700 return !strcmpW(lpSrcStr
, szBuff
);
2703 /*************************************************************************
2704 * SHLoadIndirectString [SHLWAPI.@]
2706 * If passed a string that begins with a '@' extract the string from the
2707 * appropriate resource, otherwise do a straight copy.
2710 HRESULT WINAPI
SHLoadIndirectString(LPCWSTR src
, LPWSTR dst
, UINT dst_len
, void **reserved
)
2712 WCHAR
*dllname
= NULL
;
2713 HMODULE hmod
= NULL
;
2714 HRESULT hr
= E_FAIL
;
2716 TRACE("(%s %p %08x %p)\n", debugstr_w(src
), dst
, dst_len
, reserved
);
2724 dllname
= StrDupW(src
+ 1);
2725 index_str
= strchrW(dllname
, ',');
2727 if(!index_str
) goto end
;
2731 index
= atoiW(index_str
);
2733 hmod
= LoadLibraryW(dllname
);
2738 if(LoadStringW(hmod
, -index
, dst
, dst_len
))
2742 FIXME("can't handle non-negative indicies (%d)\n", index
);
2747 lstrcpynW(dst
, src
, dst_len
);
2751 TRACE("returing %s\n", debugstr_w(dst
));
2753 if(hmod
) FreeLibrary(hmod
);
2754 HeapFree(GetProcessHeap(), 0, dllname
);