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
28 extern HINSTANCE shlwapi_hInstance
;
30 static HRESULT
_SHStrDupAA(LPCSTR
,LPSTR
*);
31 static HRESULT
_SHStrDupAW(LPCWSTR
,LPSTR
*);
34 static void FillNumberFmt(NUMBERFMTW
*fmt
, LPWSTR decimal_buffer
, int decimal_bufwlen
,
35 LPWSTR thousand_buffer
, int thousand_bufwlen
)
40 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_ILZERO
|LOCALE_RETURN_NUMBER
, (LPWSTR
)&fmt
->LeadingZero
, sizeof(fmt
->LeadingZero
)/sizeof(WCHAR
));
41 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_INEGNUMBER
|LOCALE_RETURN_NUMBER
, (LPWSTR
)&fmt
->LeadingZero
, sizeof(fmt
->NegativeOrder
)/sizeof(WCHAR
));
43 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_SDECIMAL
, decimal_buffer
, decimal_bufwlen
);
44 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_STHOUSAND
, thousand_buffer
, thousand_bufwlen
);
45 fmt
->lpThousandSep
= thousand_buffer
;
46 fmt
->lpDecimalSep
= decimal_buffer
;
49 * Converting grouping string to number as described on
50 * http://blogs.msdn.com/oldnewthing/archive/2006/04/18/578251.aspx
53 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_SGROUPING
, grouping
, sizeof(grouping
)/sizeof(WCHAR
));
54 for (c
= grouping
; *c
; c
++)
55 if (*c
>= '0' && *c
< '9')
58 fmt
->Grouping
+= *c
- '0';
61 if (fmt
->Grouping
% 10 == 0)
67 /*************************************************************************
68 * FormatInt [internal]
70 * Format an integer according to the current locale
73 * The number of characters written on success or 0 on failure
75 static int FormatInt(LONGLONG qdwValue
, LPWSTR pszBuf
, int cchBuf
)
78 WCHAR decimal
[8], thousand
[8];
81 BOOL neg
= (qdwValue
< 0);
83 FillNumberFmt(&fmt
, decimal
, sizeof decimal
/ sizeof (WCHAR
),
84 thousand
, sizeof thousand
/ sizeof (WCHAR
));
90 *(--c
) = '0' + (qdwValue
%10);
92 } while (qdwValue
> 0);
96 return GetNumberFormatW(LOCALE_USER_DEFAULT
, 0, c
, &fmt
, pszBuf
, cchBuf
);
99 /*************************************************************************
100 * FormatDouble [internal]
102 * Format an integer according to the current locale. Prints the specified number of digits
103 * after the decimal point
106 * The number of characters written on success or 0 on failure
108 static int FormatDouble(double value
, int decimals
, LPWSTR pszBuf
, int cchBuf
)
110 static const WCHAR flfmt
[] = {'%','f',0};
113 WCHAR decimal
[8], thousand
[8];
115 snprintfW(buf
, 64, flfmt
, value
);
117 FillNumberFmt(&fmt
, decimal
, sizeof decimal
/ sizeof (WCHAR
),
118 thousand
, sizeof thousand
/ sizeof (WCHAR
));
119 fmt
.NumDigits
= decimals
;
120 return GetNumberFormatW(LOCALE_USER_DEFAULT
, 0, buf
, &fmt
, pszBuf
, cchBuf
);
123 /*************************************************************************
124 * SHLWAPI_ChrCmpHelperA
126 * Internal helper for SHLWAPI_ChrCmpA/ChrCMPIA.
129 * Both this function and its Unicode counterpart are very inefficient. To
130 * fix this, CompareString must be completely implemented and optimised
131 * first. Then the core character test can be taken out of that function and
132 * placed here, so that it need never be called at all. Until then, do not
133 * attempt to optimise this code unless you are willing to test that it
134 * still performs correctly.
136 static BOOL
SHLWAPI_ChrCmpHelperA(WORD ch1
, WORD ch2
, DWORD dwFlags
)
138 char str1
[3], str2
[3];
140 str1
[0] = LOBYTE(ch1
);
141 if (IsDBCSLeadByte(str1
[0]))
143 str1
[1] = HIBYTE(ch1
);
149 str2
[0] = LOBYTE(ch2
);
150 if (IsDBCSLeadByte(str2
[0]))
152 str2
[1] = HIBYTE(ch2
);
158 return CompareStringA(GetThreadLocale(), dwFlags
, str1
, -1, str2
, -1) - CSTR_EQUAL
;
161 /*************************************************************************
164 * Internal helper function.
166 static BOOL WINAPI
SHLWAPI_ChrCmpA(WORD ch1
, WORD ch2
)
168 return SHLWAPI_ChrCmpHelperA(ch1
, ch2
, 0);
171 /*************************************************************************
172 * ChrCmpIA (SHLWAPI.385)
174 * Compare two characters, ignoring case.
177 * ch1 [I] First character to compare
178 * ch2 [I] Second character to compare
181 * FALSE, if the characters are equal.
182 * Non-zero otherwise.
184 BOOL WINAPI
ChrCmpIA(WORD ch1
, WORD ch2
)
186 TRACE("(%d,%d)\n", ch1
, ch2
);
188 return SHLWAPI_ChrCmpHelperA(ch1
, ch2
, NORM_IGNORECASE
);
191 /*************************************************************************
192 * ChrCmpIW [SHLWAPI.386]
196 BOOL WINAPI
ChrCmpIW(WCHAR ch1
, WCHAR ch2
)
198 return CompareStringW(GetThreadLocale(), NORM_IGNORECASE
, &ch1
, 1, &ch2
, 1) - CSTR_EQUAL
;
201 /*************************************************************************
202 * StrChrA [SHLWAPI.@]
204 * Find a given character in a string.
207 * lpszStr [I] String to search in.
208 * ch [I] Character to search for.
211 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
213 * Failure: NULL, if any arguments are invalid.
215 LPSTR WINAPI
StrChrA(LPCSTR lpszStr
, WORD ch
)
217 TRACE("(%s,%i)\n", debugstr_a(lpszStr
), ch
);
223 if (!SHLWAPI_ChrCmpA(*lpszStr
, ch
))
224 return (LPSTR
)lpszStr
;
225 lpszStr
= CharNextA(lpszStr
);
231 /*************************************************************************
232 * StrChrW [SHLWAPI.@]
236 LPWSTR WINAPI
StrChrW(LPCWSTR lpszStr
, WCHAR ch
)
238 LPWSTR lpszRet
= NULL
;
240 TRACE("(%s,%i)\n", debugstr_w(lpszStr
), ch
);
243 lpszRet
= strchrW(lpszStr
, ch
);
247 /*************************************************************************
248 * StrChrIA [SHLWAPI.@]
250 * Find a given character in a string, ignoring case.
253 * lpszStr [I] String to search in.
254 * ch [I] Character to search for.
257 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
259 * Failure: NULL, if any arguments are invalid.
261 LPSTR WINAPI
StrChrIA(LPCSTR lpszStr
, WORD ch
)
263 TRACE("(%s,%i)\n", debugstr_a(lpszStr
), ch
);
269 if (!ChrCmpIA(*lpszStr
, ch
))
270 return (LPSTR
)lpszStr
;
271 lpszStr
= CharNextA(lpszStr
);
277 /*************************************************************************
278 * StrChrIW [SHLWAPI.@]
282 LPWSTR WINAPI
StrChrIW(LPCWSTR lpszStr
, WCHAR ch
)
284 TRACE("(%s,%i)\n", debugstr_w(lpszStr
), ch
);
291 if (toupperW(*lpszStr
) == ch
)
292 return (LPWSTR
)lpszStr
;
297 return (LPWSTR
)lpszStr
;
300 /*************************************************************************
301 * StrChrNW [SHLWAPI.@]
303 LPWSTR WINAPI
StrChrNW(LPCWSTR lpszStr
, WCHAR ch
, UINT cchMax
)
305 TRACE("(%s(%i),%i)\n", debugstr_wn(lpszStr
,cchMax
), cchMax
, ch
);
309 while (*lpszStr
&& cchMax
-- > 0)
312 return (LPWSTR
)lpszStr
;
319 /*************************************************************************
320 * StrCmpIW [SHLWAPI.@]
322 * Compare two strings, ignoring case.
325 * lpszStr [I] First string to compare
326 * lpszComp [I] Second string to compare
329 * An integer less than, equal to or greater than 0, indicating that
330 * lpszStr is less than, the same, or greater than lpszComp.
332 int WINAPI
StrCmpIW(LPCWSTR lpszStr
, LPCWSTR lpszComp
)
334 TRACE("(%s,%s)\n", debugstr_w(lpszStr
),debugstr_w(lpszComp
));
335 return CompareStringW(GetThreadLocale(), NORM_IGNORECASE
, lpszStr
, -1, lpszComp
, -1) - CSTR_EQUAL
;
338 /*************************************************************************
339 * StrCmpNA [SHLWAPI.@]
341 * Compare two strings, up to a maximum length.
344 * lpszStr [I] First string to compare
345 * lpszComp [I] Second string to compare
346 * iLen [I] Number of chars to compare
349 * An integer less than, equal to or greater than 0, indicating that
350 * lpszStr is less than, the same, or greater than lpszComp.
352 INT WINAPI
StrCmpNA(LPCSTR lpszStr
, LPCSTR lpszComp
, INT iLen
)
354 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr
), debugstr_a(lpszComp
), iLen
);
355 return CompareStringA(GetThreadLocale(), 0, lpszStr
, iLen
, lpszComp
, iLen
) - CSTR_EQUAL
;
358 /*************************************************************************
359 * StrCmpNW [SHLWAPI.@]
363 INT WINAPI
StrCmpNW(LPCWSTR lpszStr
, LPCWSTR lpszComp
, INT iLen
)
365 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr
), debugstr_w(lpszComp
), iLen
);
366 return CompareStringW(GetThreadLocale(), 0, lpszStr
, iLen
, lpszComp
, iLen
) - CSTR_EQUAL
;
369 /*************************************************************************
370 * StrCmpNIA [SHLWAPI.@]
372 * Compare two strings, up to a maximum length, ignoring case.
375 * lpszStr [I] First string to compare
376 * lpszComp [I] Second string to compare
377 * iLen [I] Number of chars 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
StrCmpNIA(LPCSTR lpszStr
, LPCSTR lpszComp
, int iLen
)
385 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr
), debugstr_a(lpszComp
), iLen
);
386 return CompareStringA(GetThreadLocale(), NORM_IGNORECASE
, lpszStr
, iLen
, lpszComp
, iLen
) - CSTR_EQUAL
;
389 /*************************************************************************
390 * StrCmpNIW [SHLWAPI.@]
394 INT WINAPI
StrCmpNIW(LPCWSTR lpszStr
, LPCWSTR lpszComp
, int iLen
)
396 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr
), debugstr_w(lpszComp
), iLen
);
397 return CompareStringW(GetThreadLocale(), NORM_IGNORECASE
, lpszStr
, iLen
, lpszComp
, iLen
) - CSTR_EQUAL
;
400 /*************************************************************************
401 * StrCmpW [SHLWAPI.@]
403 * Compare two strings.
406 * lpszStr [I] First string to compare
407 * lpszComp [I] Second string to compare
410 * An integer less than, equal to or greater than 0, indicating that
411 * lpszStr is less than, the same, or greater than lpszComp.
413 int WINAPI
StrCmpW(LPCWSTR lpszStr
, LPCWSTR lpszComp
)
415 TRACE("(%s,%s)\n", debugstr_w(lpszStr
), debugstr_w(lpszComp
));
416 return CompareStringW(GetThreadLocale(), 0, lpszStr
, -1, lpszComp
, -1) - CSTR_EQUAL
;
419 /*************************************************************************
420 * StrCatW [SHLWAPI.@]
422 * Concatenate two strings.
425 * lpszStr [O] Initial string
426 * lpszSrc [I] String to concatenate
431 LPWSTR WINAPI
StrCatW(LPWSTR lpszStr
, LPCWSTR lpszSrc
)
433 TRACE("(%s,%s)\n", debugstr_w(lpszStr
), debugstr_w(lpszSrc
));
435 if (lpszStr
&& lpszSrc
)
436 strcatW(lpszStr
, lpszSrc
);
440 /*************************************************************************
441 * StrCatChainW [SHLWAPI.@]
443 * Concatenates two unicode strings.
446 * lpszStr [O] Initial string
447 * cchMax [I] Length of destination buffer
448 * ichAt [I] Offset from the destination buffer to begin concatenation
449 * lpszCat [I] String to concatenate
452 * The offset from the beginning of pszDst to the terminating NULL.
454 DWORD WINAPI
StrCatChainW(LPWSTR lpszStr
, DWORD cchMax
, DWORD ichAt
, LPCWSTR lpszCat
)
456 TRACE("(%s,%u,%d,%s)\n", debugstr_w(lpszStr
), cchMax
, ichAt
, debugstr_w(lpszCat
));
459 ichAt
= strlenW(lpszStr
);
467 if (lpszCat
&& ichAt
< cchMax
)
470 while (ichAt
< cchMax
- 1 && *lpszCat
)
472 *lpszStr
++ = *lpszCat
++;
481 /*************************************************************************
482 * StrCpyW [SHLWAPI.@]
484 * Copy a string to another string.
487 * lpszStr [O] Destination string
488 * lpszSrc [I] Source string
493 LPWSTR WINAPI
StrCpyW(LPWSTR lpszStr
, LPCWSTR lpszSrc
)
495 TRACE("(%p,%s)\n", lpszStr
, debugstr_w(lpszSrc
));
497 if (lpszStr
&& lpszSrc
)
498 strcpyW(lpszStr
, lpszSrc
);
502 /*************************************************************************
503 * StrCpyNW [SHLWAPI.@]
505 * Copy a string to another string, up to a maximum number of characters.
508 * dst [O] Destination string
509 * src [I] Source string
510 * count [I] Maximum number of chars to copy
515 LPWSTR WINAPI
StrCpyNW(LPWSTR dst
, LPCWSTR src
, int count
)
520 TRACE("(%p,%s,%i)\n", dst
, debugstr_w(src
), count
);
524 while ((count
> 1) && *s
)
535 /*************************************************************************
536 * SHLWAPI_StrStrHelperA
538 * Internal implementation of StrStrA/StrStrIA
540 static LPSTR
SHLWAPI_StrStrHelperA(LPCSTR lpszStr
, LPCSTR lpszSearch
,
541 INT (WINAPI
*pStrCmpFn
)(LPCSTR
,LPCSTR
,INT
))
546 if (!lpszStr
|| !lpszSearch
|| !*lpszSearch
)
549 iLen
= strlen(lpszSearch
);
550 end
= lpszStr
+ strlen(lpszStr
);
552 while (lpszStr
+ iLen
<= end
)
554 if (!pStrCmpFn(lpszStr
, lpszSearch
, iLen
))
555 return (LPSTR
)lpszStr
;
556 lpszStr
= CharNextA(lpszStr
);
561 /*************************************************************************
562 * StrStrA [SHLWAPI.@]
564 * Find a substring within a string.
567 * lpszStr [I] String to search in
568 * lpszSearch [I] String to look for
571 * The start of lpszSearch within lpszStr, or NULL if not found.
573 LPSTR WINAPI
StrStrA(LPCSTR lpszStr
, LPCSTR lpszSearch
)
575 TRACE("(%s,%s)\n", debugstr_a(lpszStr
), debugstr_a(lpszSearch
));
577 return SHLWAPI_StrStrHelperA(lpszStr
, lpszSearch
, StrCmpNA
);
580 /*************************************************************************
581 * StrStrW [SHLWAPI.@]
585 LPWSTR WINAPI
StrStrW(LPCWSTR lpszStr
, LPCWSTR lpszSearch
)
587 TRACE("(%s, %s)\n", debugstr_w(lpszStr
), debugstr_w(lpszSearch
));
589 if (!lpszStr
|| !lpszSearch
|| !*lpszSearch
) return NULL
;
590 return strstrW( lpszStr
, lpszSearch
);
593 /*************************************************************************
594 * StrRStrIA [SHLWAPI.@]
596 * Find the last occurrence of a substring within a string.
599 * lpszStr [I] String to search in
600 * lpszEnd [I] End of lpszStr
601 * lpszSearch [I] String to look for
604 * The last occurrence lpszSearch within lpszStr, or NULL if not found.
606 LPSTR WINAPI
StrRStrIA(LPCSTR lpszStr
, LPCSTR lpszEnd
, LPCSTR lpszSearch
)
608 LPSTR lpszRet
= NULL
;
612 TRACE("(%s,%s)\n", debugstr_a(lpszStr
), debugstr_a(lpszSearch
));
614 if (!lpszStr
|| !lpszSearch
|| !*lpszSearch
)
617 if (IsDBCSLeadByte(*lpszSearch
))
618 ch1
= *lpszSearch
<< 8 | (UCHAR
)lpszSearch
[1];
621 iLen
= lstrlenA(lpszSearch
);
624 lpszEnd
= lpszStr
+ lstrlenA(lpszStr
);
625 else /* reproduce the broken behaviour on Windows */
626 lpszEnd
+= min(iLen
- 1, lstrlenA(lpszEnd
));
628 while (lpszStr
+ iLen
<= lpszEnd
&& *lpszStr
)
630 ch2
= IsDBCSLeadByte(*lpszStr
)? *lpszStr
<< 8 | (UCHAR
)lpszStr
[1] : *lpszStr
;
631 if (!ChrCmpIA(ch1
, ch2
))
633 if (!StrCmpNIA(lpszStr
, lpszSearch
, iLen
))
634 lpszRet
= (LPSTR
)lpszStr
;
636 lpszStr
= CharNextA(lpszStr
);
641 /*************************************************************************
642 * StrRStrIW [SHLWAPI.@]
646 LPWSTR WINAPI
StrRStrIW(LPCWSTR lpszStr
, LPCWSTR lpszEnd
, LPCWSTR lpszSearch
)
648 LPWSTR lpszRet
= NULL
;
651 TRACE("(%s,%s)\n", debugstr_w(lpszStr
), debugstr_w(lpszSearch
));
653 if (!lpszStr
|| !lpszSearch
|| !*lpszSearch
)
656 iLen
= strlenW(lpszSearch
);
659 lpszEnd
= lpszStr
+ strlenW(lpszStr
);
660 else /* reproduce the broken behaviour on Windows */
661 lpszEnd
+= min(iLen
- 1, lstrlenW(lpszEnd
));
663 while (lpszStr
+ iLen
<= lpszEnd
&& *lpszStr
)
665 if (!ChrCmpIW(*lpszSearch
, *lpszStr
))
667 if (!StrCmpNIW(lpszStr
, lpszSearch
, iLen
))
668 lpszRet
= (LPWSTR
)lpszStr
;
675 /*************************************************************************
676 * StrStrIA [SHLWAPI.@]
678 * Find a substring within a string, ignoring case.
681 * lpszStr [I] String to search in
682 * lpszSearch [I] String to look for
685 * The start of lpszSearch within lpszStr, or NULL if not found.
687 LPSTR WINAPI
StrStrIA(LPCSTR lpszStr
, LPCSTR lpszSearch
)
689 TRACE("(%s,%s)\n", debugstr_a(lpszStr
), debugstr_a(lpszSearch
));
691 return SHLWAPI_StrStrHelperA(lpszStr
, lpszSearch
, StrCmpNIA
);
694 /*************************************************************************
695 * StrStrIW [SHLWAPI.@]
699 LPWSTR WINAPI
StrStrIW(LPCWSTR lpszStr
, LPCWSTR lpszSearch
)
704 TRACE("(%s,%s)\n", debugstr_w(lpszStr
), debugstr_w(lpszSearch
));
706 if (!lpszStr
|| !lpszSearch
|| !*lpszSearch
)
709 iLen
= strlenW(lpszSearch
);
710 end
= lpszStr
+ strlenW(lpszStr
);
712 while (lpszStr
+ iLen
<= end
)
714 if (!StrCmpNIW(lpszStr
, lpszSearch
, iLen
))
715 return (LPWSTR
)lpszStr
;
721 /*************************************************************************
722 * StrStrNW [SHLWAPI.@]
724 * Find a substring within a string up to a given number of initial characters.
727 * lpFirst [I] String to search in
728 * lpSrch [I] String to look for
729 * cchMax [I] Maximum number of initial search characters
732 * The start of lpFirst within lpSrch, or NULL if not found.
734 LPWSTR WINAPI
StrStrNW(LPCWSTR lpFirst
, LPCWSTR lpSrch
, UINT cchMax
)
739 TRACE("(%s, %s, %u)\n", debugstr_w(lpFirst
), debugstr_w(lpSrch
), cchMax
);
741 if (!lpFirst
|| !lpSrch
|| !*lpSrch
|| !cchMax
)
744 len
= strlenW(lpSrch
);
746 for (i
= cchMax
; *lpFirst
&& (i
> 0); i
--, lpFirst
++)
748 if (!strncmpW(lpFirst
, lpSrch
, len
))
749 return (LPWSTR
)lpFirst
;
755 /*************************************************************************
756 * StrStrNIW [SHLWAPI.@]
758 * Find a substring within a string up to a given number of initial characters,
762 * lpFirst [I] String to search in
763 * lpSrch [I] String to look for
764 * cchMax [I] Maximum number of initial search characters
767 * The start of lpFirst within lpSrch, or NULL if not found.
769 LPWSTR WINAPI
StrStrNIW(LPCWSTR lpFirst
, LPCWSTR lpSrch
, UINT cchMax
)
774 TRACE("(%s, %s, %u)\n", debugstr_w(lpFirst
), debugstr_w(lpSrch
), cchMax
);
776 if (!lpFirst
|| !lpSrch
|| !*lpSrch
|| !cchMax
)
779 len
= strlenW(lpSrch
);
781 for (i
= cchMax
; *lpFirst
&& (i
> 0); i
--, lpFirst
++)
783 if (!strncmpiW(lpFirst
, lpSrch
, len
))
784 return (LPWSTR
)lpFirst
;
790 /*************************************************************************
791 * StrToIntA [SHLWAPI.@]
793 * Read a signed integer from a string.
796 * lpszStr [I] String to read integer from
799 * The signed integer value represented by the string, or 0 if no integer is
803 * No leading space is allowed before the number, although a leading '-' is.
805 int WINAPI
StrToIntA(LPCSTR lpszStr
)
809 TRACE("(%s)\n", debugstr_a(lpszStr
));
813 WARN("Invalid lpszStr would crash under Win32!\n");
817 if (*lpszStr
== '-' || isdigit(*lpszStr
))
818 StrToIntExA(lpszStr
, 0, &iRet
);
822 /*************************************************************************
823 * StrToIntW [SHLWAPI.@]
827 int WINAPI
StrToIntW(LPCWSTR lpszStr
)
831 TRACE("(%s)\n", debugstr_w(lpszStr
));
835 WARN("Invalid lpszStr would crash under Win32!\n");
839 if (*lpszStr
== '-' || isdigitW(*lpszStr
))
840 StrToIntExW(lpszStr
, 0, &iRet
);
844 /*************************************************************************
845 * StrToIntExA [SHLWAPI.@]
847 * Read an integer from a string.
850 * lpszStr [I] String to read integer from
851 * dwFlags [I] Flags controlling the conversion
852 * lpiRet [O] Destination for read integer.
855 * Success: TRUE. lpiRet contains the integer value represented by the string.
856 * Failure: FALSE, if the string is invalid, or no number is present.
859 * Leading whitespace, '-' and '+' are allowed before the number. If
860 * dwFlags includes STIF_SUPPORT_HEX, hexadecimal numbers are allowed, if
861 * preceded by '0x'. If this flag is not set, or there is no '0x' prefix,
862 * the string is treated as a decimal string. A leading '-' is ignored for
863 * hexadecimal numbers.
865 BOOL WINAPI
StrToIntExA(LPCSTR lpszStr
, DWORD dwFlags
, LPINT lpiRet
)
870 TRACE("(%s,%08X,%p)\n", debugstr_a(lpszStr
), dwFlags
, lpiRet
);
872 bRes
= StrToInt64ExA(lpszStr
, dwFlags
, &li
);
873 if (bRes
) *lpiRet
= li
;
877 /*************************************************************************
878 * StrToInt64ExA [SHLWAPI.@]
882 BOOL WINAPI
StrToInt64ExA(LPCSTR lpszStr
, DWORD dwFlags
, LONGLONG
*lpiRet
)
884 BOOL bNegative
= FALSE
;
887 TRACE("(%s,%08X,%p)\n", debugstr_a(lpszStr
), dwFlags
, lpiRet
);
889 if (!lpszStr
|| !lpiRet
)
891 WARN("Invalid parameter would crash under Win32!\n");
894 if (dwFlags
> STIF_SUPPORT_HEX
) WARN("Unknown flags %08x\n", dwFlags
);
896 /* Skip leading space, '+', '-' */
897 while (isspace(*lpszStr
))
898 lpszStr
= CharNextA(lpszStr
);
905 else if (*lpszStr
== '+')
908 if (dwFlags
& STIF_SUPPORT_HEX
&&
909 *lpszStr
== '0' && tolower(lpszStr
[1]) == 'x')
911 /* Read hex number */
914 if (!isxdigit(*lpszStr
))
917 while (isxdigit(*lpszStr
))
920 if (isdigit(*lpszStr
))
921 iRet
+= (*lpszStr
- '0');
923 iRet
+= 10 + (tolower(*lpszStr
) - 'a');
930 /* Read decimal number */
931 if (!isdigit(*lpszStr
))
934 while (isdigit(*lpszStr
))
937 iRet
+= (*lpszStr
- '0');
940 *lpiRet
= bNegative
? -iRet
: iRet
;
944 /*************************************************************************
945 * StrToIntExW [SHLWAPI.@]
949 BOOL WINAPI
StrToIntExW(LPCWSTR lpszStr
, DWORD dwFlags
, LPINT lpiRet
)
954 TRACE("(%s,%08X,%p)\n", debugstr_w(lpszStr
), dwFlags
, lpiRet
);
956 bRes
= StrToInt64ExW(lpszStr
, dwFlags
, &li
);
957 if (bRes
) *lpiRet
= li
;
961 /*************************************************************************
962 * StrToInt64ExW [SHLWAPI.@]
966 BOOL WINAPI
StrToInt64ExW(LPCWSTR lpszStr
, DWORD dwFlags
, LONGLONG
*lpiRet
)
968 BOOL bNegative
= FALSE
;
971 TRACE("(%s,%08X,%p)\n", debugstr_w(lpszStr
), dwFlags
, lpiRet
);
973 if (!lpszStr
|| !lpiRet
)
975 WARN("Invalid parameter would crash under Win32!\n");
978 if (dwFlags
> STIF_SUPPORT_HEX
) WARN("Unknown flags %08x\n", dwFlags
);
980 /* Skip leading space, '+', '-' */
981 while (isspaceW(*lpszStr
)) lpszStr
++;
988 else if (*lpszStr
== '+')
991 if (dwFlags
& STIF_SUPPORT_HEX
&&
992 *lpszStr
== '0' && tolowerW(lpszStr
[1]) == 'x')
994 /* Read hex number */
997 if (!isxdigitW(*lpszStr
))
1000 while (isxdigitW(*lpszStr
))
1003 if (isdigitW(*lpszStr
))
1004 iRet
+= (*lpszStr
- '0');
1006 iRet
+= 10 + (tolowerW(*lpszStr
) - 'a');
1013 /* Read decimal number */
1014 if (!isdigitW(*lpszStr
))
1017 while (isdigitW(*lpszStr
))
1020 iRet
+= (*lpszStr
- '0');
1023 *lpiRet
= bNegative
? -iRet
: iRet
;
1027 /*************************************************************************
1028 * StrDupA [SHLWAPI.@]
1030 * Duplicate a string.
1033 * lpszStr [I] String to duplicate.
1036 * Success: A pointer to a new string containing the contents of lpszStr
1037 * Failure: NULL, if memory cannot be allocated
1040 * The string memory is allocated with LocalAlloc(), and so should be released
1041 * by calling LocalFree().
1043 LPSTR WINAPI
StrDupA(LPCSTR lpszStr
)
1048 TRACE("(%s)\n",debugstr_a(lpszStr
));
1050 iLen
= lpszStr
? strlen(lpszStr
) + 1 : 1;
1051 lpszRet
= LocalAlloc(LMEM_FIXED
, iLen
);
1056 memcpy(lpszRet
, lpszStr
, iLen
);
1063 /*************************************************************************
1064 * StrDupW [SHLWAPI.@]
1068 LPWSTR WINAPI
StrDupW(LPCWSTR lpszStr
)
1073 TRACE("(%s)\n",debugstr_w(lpszStr
));
1075 iLen
= (lpszStr
? strlenW(lpszStr
) + 1 : 1) * sizeof(WCHAR
);
1076 lpszRet
= LocalAlloc(LMEM_FIXED
, iLen
);
1081 memcpy(lpszRet
, lpszStr
, iLen
);
1088 /*************************************************************************
1089 * SHLWAPI_StrSpnHelperA
1091 * Internal implementation of StrSpnA/StrCSpnA/StrCSpnIA
1093 static int SHLWAPI_StrSpnHelperA(LPCSTR lpszStr
, LPCSTR lpszMatch
,
1094 LPSTR (WINAPI
*pStrChrFn
)(LPCSTR
,WORD
),
1097 LPCSTR lpszRead
= lpszStr
;
1098 if (lpszStr
&& *lpszStr
&& lpszMatch
)
1102 LPCSTR lpszTest
= pStrChrFn(lpszMatch
, *lpszRead
);
1104 if (!bInvert
&& !lpszTest
)
1106 if (bInvert
&& lpszTest
)
1108 lpszRead
= CharNextA(lpszRead
);
1111 return lpszRead
- lpszStr
;
1114 /*************************************************************************
1115 * StrSpnA [SHLWAPI.@]
1117 * Find the length of the start of a string that contains only certain
1121 * lpszStr [I] String to search
1122 * lpszMatch [I] Characters that can be in the substring
1125 * The length of the part of lpszStr containing only chars from lpszMatch,
1126 * or 0 if any parameter is invalid.
1128 int WINAPI
StrSpnA(LPCSTR lpszStr
, LPCSTR lpszMatch
)
1130 TRACE("(%s,%s)\n",debugstr_a(lpszStr
), debugstr_a(lpszMatch
));
1132 return SHLWAPI_StrSpnHelperA(lpszStr
, lpszMatch
, StrChrA
, FALSE
);
1135 /*************************************************************************
1136 * StrSpnW [SHLWAPI.@]
1140 int WINAPI
StrSpnW(LPCWSTR lpszStr
, LPCWSTR lpszMatch
)
1142 if (!lpszStr
|| !lpszMatch
) return 0;
1143 return strspnW( lpszStr
, lpszMatch
);
1146 /*************************************************************************
1147 * StrCSpnA [SHLWAPI.@]
1149 * Find the length of the start of a string that does not contain certain
1153 * lpszStr [I] String to search
1154 * lpszMatch [I] Characters that cannot be in the substring
1157 * The length of the part of lpszStr containing only chars not in lpszMatch,
1158 * or 0 if any parameter is invalid.
1160 int WINAPI
StrCSpnA(LPCSTR lpszStr
, LPCSTR lpszMatch
)
1162 TRACE("(%s,%s)\n",debugstr_a(lpszStr
), debugstr_a(lpszMatch
));
1164 return SHLWAPI_StrSpnHelperA(lpszStr
, lpszMatch
, StrChrA
, TRUE
);
1167 /*************************************************************************
1168 * StrCSpnW [SHLWAPI.@]
1172 int WINAPI
StrCSpnW(LPCWSTR lpszStr
, LPCWSTR lpszMatch
)
1174 if (!lpszStr
|| !lpszMatch
) return 0;
1175 return strcspnW( lpszStr
, lpszMatch
);
1178 /*************************************************************************
1179 * StrCSpnIA [SHLWAPI.@]
1181 * Find the length of the start of a string that does not contain certain
1182 * characters, ignoring case.
1185 * lpszStr [I] String to search
1186 * lpszMatch [I] Characters that cannot be in the substring
1189 * The length of the part of lpszStr containing only chars not in lpszMatch,
1190 * or 0 if any parameter is invalid.
1192 int WINAPI
StrCSpnIA(LPCSTR lpszStr
, LPCSTR lpszMatch
)
1194 TRACE("(%s,%s)\n",debugstr_a(lpszStr
), debugstr_a(lpszMatch
));
1196 return SHLWAPI_StrSpnHelperA(lpszStr
, lpszMatch
, StrChrIA
, TRUE
);
1199 /*************************************************************************
1200 * StrCSpnIW [SHLWAPI.@]
1204 int WINAPI
StrCSpnIW(LPCWSTR lpszStr
, LPCWSTR lpszMatch
)
1206 LPCWSTR lpszRead
= lpszStr
;
1208 TRACE("(%s,%s)\n",debugstr_w(lpszStr
), debugstr_w(lpszMatch
));
1210 if (lpszStr
&& *lpszStr
&& lpszMatch
)
1214 if (StrChrIW(lpszMatch
, *lpszRead
)) break;
1218 return lpszRead
- lpszStr
;
1221 /*************************************************************************
1222 * StrPBrkA [SHLWAPI.@]
1224 * Search a string for any of a group of characters.
1227 * lpszStr [I] String to search
1228 * lpszMatch [I] Characters to match
1231 * A pointer to the first matching character in lpszStr, or NULL if no
1234 LPSTR WINAPI
StrPBrkA(LPCSTR lpszStr
, LPCSTR lpszMatch
)
1236 TRACE("(%s,%s)\n",debugstr_a(lpszStr
), debugstr_a(lpszMatch
));
1238 if (lpszStr
&& lpszMatch
&& *lpszMatch
)
1242 if (StrChrA(lpszMatch
, *lpszStr
))
1243 return (LPSTR
)lpszStr
;
1244 lpszStr
= CharNextA(lpszStr
);
1250 /*************************************************************************
1251 * StrPBrkW [SHLWAPI.@]
1255 LPWSTR WINAPI
StrPBrkW(LPCWSTR lpszStr
, LPCWSTR lpszMatch
)
1257 if (!lpszStr
|| !lpszMatch
) return NULL
;
1258 return strpbrkW( lpszStr
, lpszMatch
);
1261 /*************************************************************************
1262 * SHLWAPI_StrRChrHelperA
1264 * Internal implementation of StrRChrA/StrRChrIA.
1266 static LPSTR
SHLWAPI_StrRChrHelperA(LPCSTR lpszStr
,
1267 LPCSTR lpszEnd
, WORD ch
,
1268 BOOL (WINAPI
*pChrCmpFn
)(WORD
,WORD
))
1270 LPCSTR lpszRet
= NULL
;
1277 lpszEnd
= lpszStr
+ lstrlenA(lpszStr
);
1279 while (*lpszStr
&& lpszStr
<= lpszEnd
)
1281 ch2
= IsDBCSLeadByte(*lpszStr
)? *lpszStr
<< 8 | lpszStr
[1] : *lpszStr
;
1283 if (!pChrCmpFn(ch
, ch2
))
1285 lpszStr
= CharNextA(lpszStr
);
1288 return (LPSTR
)lpszRet
;
1291 /**************************************************************************
1292 * StrRChrA [SHLWAPI.@]
1294 * Find the last occurrence of a character in string.
1297 * lpszStr [I] String to search in
1298 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1299 * ch [I] Character to search for.
1302 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1303 * or NULL if not found.
1304 * Failure: NULL, if any arguments are invalid.
1306 LPSTR WINAPI
StrRChrA(LPCSTR lpszStr
, LPCSTR lpszEnd
, WORD ch
)
1308 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr
), debugstr_a(lpszEnd
), ch
);
1310 return SHLWAPI_StrRChrHelperA(lpszStr
, lpszEnd
, ch
, SHLWAPI_ChrCmpA
);
1313 /**************************************************************************
1314 * StrRChrW [SHLWAPI.@]
1318 LPWSTR WINAPI
StrRChrW(LPCWSTR str
, LPCWSTR end
, WORD ch
)
1322 if (!str
) return NULL
;
1323 if (!end
) end
= str
+ strlenW(str
);
1326 if (*str
== ch
) ret
= (WCHAR
*)str
;
1332 /**************************************************************************
1333 * StrRChrIA [SHLWAPI.@]
1335 * Find the last occurrence of a character in string, ignoring case.
1338 * lpszStr [I] String to search in
1339 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1340 * ch [I] Character to search for.
1343 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1344 * or NULL if not found.
1345 * Failure: NULL, if any arguments are invalid.
1347 LPSTR WINAPI
StrRChrIA(LPCSTR lpszStr
, LPCSTR lpszEnd
, WORD ch
)
1349 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr
), debugstr_a(lpszEnd
), ch
);
1351 return SHLWAPI_StrRChrHelperA(lpszStr
, lpszEnd
, ch
, ChrCmpIA
);
1354 /**************************************************************************
1355 * StrRChrIW [SHLWAPI.@]
1359 LPWSTR WINAPI
StrRChrIW(LPCWSTR str
, LPCWSTR end
, WORD ch
)
1363 if (!str
) return NULL
;
1364 if (!end
) end
= str
+ strlenW(str
);
1367 if (!ChrCmpIW(*str
, ch
)) ret
= (WCHAR
*)str
;
1373 /*************************************************************************
1374 * StrCatBuffA [SHLWAPI.@]
1376 * Concatenate two strings together.
1379 * lpszStr [O] String to concatenate to
1380 * lpszCat [I] String to add to lpszCat
1381 * cchMax [I] Maximum number of characters for the whole string
1387 * cchMax determines the number of characters in the final length of the
1388 * string, not the number appended to lpszStr from lpszCat.
1390 LPSTR WINAPI
StrCatBuffA(LPSTR lpszStr
, LPCSTR lpszCat
, INT cchMax
)
1394 TRACE("(%p,%s,%d)\n", lpszStr
, debugstr_a(lpszCat
), cchMax
);
1398 WARN("Invalid lpszStr would crash under Win32!\n");
1402 iLen
= strlen(lpszStr
);
1406 StrCpyNA(lpszStr
+ iLen
, lpszCat
, cchMax
);
1410 /*************************************************************************
1411 * StrCatBuffW [SHLWAPI.@]
1415 LPWSTR WINAPI
StrCatBuffW(LPWSTR lpszStr
, LPCWSTR lpszCat
, INT cchMax
)
1419 TRACE("(%p,%s,%d)\n", lpszStr
, debugstr_w(lpszCat
), cchMax
);
1423 WARN("Invalid lpszStr would crash under Win32!\n");
1427 iLen
= strlenW(lpszStr
);
1431 StrCpyNW(lpszStr
+ iLen
, lpszCat
, cchMax
);
1435 /*************************************************************************
1436 * StrRetToBufA [SHLWAPI.@]
1438 * Convert a STRRET to a normal string.
1441 * lpStrRet [O] STRRET to convert
1442 * pIdl [I] ITEMIDLIST for lpStrRet->uType == STRRET_OFFSET
1443 * lpszDest [O] Destination for normal string
1444 * dwLen [I] Length of lpszDest
1447 * Success: S_OK. lpszDest contains up to dwLen characters of the string.
1448 * If lpStrRet is of type STRRET_WSTR, its memory is freed with
1449 * CoTaskMemFree() and its type set to STRRET_CSTRA.
1450 * Failure: E_FAIL, if any parameters are invalid.
1452 HRESULT WINAPI
StrRetToBufA (LPSTRRET src
, const ITEMIDLIST
*pidl
, LPSTR dest
, UINT len
)
1455 * This routine is identical to that in dlls/shell32/shellstring.c.
1456 * It was duplicated because not every version of Shlwapi.dll exports
1457 * StrRetToBufA. If you change one routine, change them both.
1459 TRACE("dest=%p len=0x%x strret=%p pidl=%p\n", dest
, len
, src
, pidl
);
1463 WARN("Invalid lpStrRet would crash under Win32!\n");
1477 WideCharToMultiByte(CP_ACP
, 0, src
->u
.pOleStr
, -1, dest
, len
, NULL
, NULL
);
1478 CoTaskMemFree(src
->u
.pOleStr
);
1482 lstrcpynA(dest
, src
->u
.cStr
, len
);
1486 lstrcpynA((LPSTR
)dest
, ((LPCSTR
)&pidl
->mkid
)+src
->u
.uOffset
, len
);
1490 FIXME("unknown type!\n");
1496 /*************************************************************************
1497 * StrRetToBufW [SHLWAPI.@]
1501 HRESULT WINAPI
StrRetToBufW (LPSTRRET src
, const ITEMIDLIST
*pidl
, LPWSTR dest
, UINT len
)
1503 TRACE("dest=%p len=0x%x strret=%p pidl=%p\n", dest
, len
, src
, pidl
);
1510 WARN("Invalid lpStrRet would crash under Win32!\n");
1518 switch (src
->uType
) {
1521 if (!src
->u
.pOleStr
)
1523 dst_len
= strlenW(src
->u
.pOleStr
);
1524 memcpy(dest
, src
->u
.pOleStr
, min(dst_len
, len
-1) * sizeof(WCHAR
));
1525 dest
[min(dst_len
, len
-1)] = 0;
1526 CoTaskMemFree(src
->u
.pOleStr
);
1530 return E_NOT_SUFFICIENT_BUFFER
;
1536 if (!MultiByteToWideChar( CP_ACP
, 0, src
->u
.cStr
, -1, dest
, len
))
1543 if (!MultiByteToWideChar( CP_ACP
, 0, ((LPCSTR
)&pidl
->mkid
)+src
->u
.uOffset
, -1,
1550 FIXME("unknown type!\n");
1557 /*************************************************************************
1558 * StrRetToStrA [SHLWAPI.@]
1560 * Converts a STRRET to a normal string.
1563 * lpStrRet [O] STRRET to convert
1564 * pidl [I] ITEMIDLIST for lpStrRet->uType == STRRET_OFFSET
1565 * ppszName [O] Destination for converted string
1568 * Success: S_OK. ppszName contains the new string, allocated with CoTaskMemAlloc().
1569 * Failure: E_FAIL, if any parameters are invalid.
1571 HRESULT WINAPI
StrRetToStrA(LPSTRRET lpStrRet
, const ITEMIDLIST
*pidl
, LPSTR
*ppszName
)
1573 HRESULT hRet
= E_FAIL
;
1575 switch (lpStrRet
->uType
)
1578 hRet
= _SHStrDupAW(lpStrRet
->u
.pOleStr
, ppszName
);
1579 CoTaskMemFree(lpStrRet
->u
.pOleStr
);
1583 hRet
= _SHStrDupAA(lpStrRet
->u
.cStr
, ppszName
);
1587 hRet
= _SHStrDupAA(((LPCSTR
)&pidl
->mkid
) + lpStrRet
->u
.uOffset
, ppszName
);
1597 /*************************************************************************
1598 * StrRetToStrW [SHLWAPI.@]
1602 HRESULT WINAPI
StrRetToStrW(LPSTRRET lpStrRet
, const ITEMIDLIST
*pidl
, LPWSTR
*ppszName
)
1604 HRESULT hRet
= E_FAIL
;
1606 switch (lpStrRet
->uType
)
1609 hRet
= SHStrDupW(lpStrRet
->u
.pOleStr
, ppszName
);
1610 CoTaskMemFree(lpStrRet
->u
.pOleStr
);
1614 hRet
= SHStrDupA(lpStrRet
->u
.cStr
, ppszName
);
1618 hRet
= SHStrDupA(((LPCSTR
)&pidl
->mkid
) + lpStrRet
->u
.uOffset
, ppszName
);
1628 /* Create an ASCII string copy using SysAllocString() */
1629 static HRESULT
_SHStrDupAToBSTR(LPCSTR src
, BSTR
*pBstrOut
)
1635 INT len
= MultiByteToWideChar(CP_ACP
, 0, src
, -1, NULL
, 0);
1636 WCHAR
* szTemp
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1640 MultiByteToWideChar(CP_ACP
, 0, src
, -1, szTemp
, len
);
1641 *pBstrOut
= SysAllocString(szTemp
);
1642 HeapFree(GetProcessHeap(), 0, szTemp
);
1648 return E_OUTOFMEMORY
;
1651 /*************************************************************************
1652 * StrRetToBSTR [SHLWAPI.@]
1654 * Converts a STRRET to a BSTR.
1657 * lpStrRet [O] STRRET to convert
1658 * pidl [I] ITEMIDLIST for lpStrRet->uType = STRRET_OFFSET
1659 * pBstrOut [O] Destination for converted BSTR
1662 * Success: S_OK. pBstrOut contains the new string.
1663 * Failure: E_FAIL, if any parameters are invalid.
1665 HRESULT WINAPI
StrRetToBSTR(STRRET
*lpStrRet
, LPCITEMIDLIST pidl
, BSTR
* pBstrOut
)
1667 HRESULT hRet
= E_FAIL
;
1669 switch (lpStrRet
->uType
)
1672 *pBstrOut
= SysAllocString(lpStrRet
->u
.pOleStr
);
1675 CoTaskMemFree(lpStrRet
->u
.pOleStr
);
1679 hRet
= _SHStrDupAToBSTR(lpStrRet
->u
.cStr
, pBstrOut
);
1683 hRet
= _SHStrDupAToBSTR(((LPCSTR
)&pidl
->mkid
) + lpStrRet
->u
.uOffset
, pBstrOut
);
1693 /*************************************************************************
1694 * StrFormatKBSizeA [SHLWAPI.@]
1696 * Create a formatted string containing a byte count in Kilobytes.
1699 * llBytes [I] Byte size to format
1700 * lpszDest [I] Destination for formatted string
1701 * cchMax [I] Size of lpszDest
1706 LPSTR WINAPI
StrFormatKBSizeA(LONGLONG llBytes
, LPSTR lpszDest
, UINT cchMax
)
1710 if (!StrFormatKBSizeW(llBytes
, wszBuf
, 256))
1712 if (!WideCharToMultiByte(CP_ACP
, 0, wszBuf
, -1, lpszDest
, cchMax
, NULL
, NULL
))
1717 /*************************************************************************
1718 * StrFormatKBSizeW [SHLWAPI.@]
1720 * See StrFormatKBSizeA.
1722 LPWSTR WINAPI
StrFormatKBSizeW(LONGLONG llBytes
, LPWSTR lpszDest
, UINT cchMax
)
1724 static const WCHAR kb
[] = {' ','K','B',0};
1725 LONGLONG llKB
= (llBytes
+ 1023) >> 10;
1728 TRACE("(0x%s,%p,%d)\n", wine_dbgstr_longlong(llBytes
), lpszDest
, cchMax
);
1730 if (!FormatInt(llKB
, lpszDest
, cchMax
))
1733 len
= lstrlenW(lpszDest
);
1734 if (cchMax
- len
< 4)
1736 lstrcatW(lpszDest
, kb
);
1740 /*************************************************************************
1741 * StrNCatA [SHLWAPI.@]
1743 * Concatenate two strings together.
1746 * lpszStr [O] String to concatenate to
1747 * lpszCat [I] String to add to lpszCat
1748 * cchMax [I] Maximum number of characters to concatenate
1754 * cchMax determines the number of characters that are appended to lpszStr,
1755 * not the total length of the string.
1757 LPSTR WINAPI
StrNCatA(LPSTR lpszStr
, LPCSTR lpszCat
, INT cchMax
)
1759 LPSTR lpszRet
= lpszStr
;
1761 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr
), debugstr_a(lpszCat
), cchMax
);
1765 WARN("Invalid lpszStr would crash under Win32!\n");
1769 StrCpyNA(lpszStr
+ strlen(lpszStr
), lpszCat
, cchMax
);
1773 /*************************************************************************
1774 * StrNCatW [SHLWAPI.@]
1778 LPWSTR WINAPI
StrNCatW(LPWSTR lpszStr
, LPCWSTR lpszCat
, INT cchMax
)
1780 LPWSTR lpszRet
= lpszStr
;
1782 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr
), debugstr_w(lpszCat
), cchMax
);
1786 WARN("Invalid lpszStr would crash under Win32\n");
1790 StrCpyNW(lpszStr
+ strlenW(lpszStr
), lpszCat
, cchMax
);
1794 /*************************************************************************
1795 * StrTrimA [SHLWAPI.@]
1797 * Remove characters from the start and end of a string.
1800 * lpszStr [O] String to remove characters from
1801 * lpszTrim [I] Characters to remove from lpszStr
1804 * TRUE If lpszStr was valid and modified
1807 BOOL WINAPI
StrTrimA(LPSTR lpszStr
, LPCSTR lpszTrim
)
1810 LPSTR lpszRead
= lpszStr
;
1813 TRACE("(%s,%s)\n", debugstr_a(lpszStr
), debugstr_a(lpszTrim
));
1815 if (lpszRead
&& *lpszRead
)
1817 while (*lpszRead
&& StrChrA(lpszTrim
, *lpszRead
))
1818 lpszRead
= CharNextA(lpszRead
); /* Skip leading matches */
1820 dwLen
= strlen(lpszRead
);
1822 if (lpszRead
!= lpszStr
)
1824 memmove(lpszStr
, lpszRead
, dwLen
+ 1);
1829 lpszRead
= lpszStr
+ dwLen
;
1830 while (StrChrA(lpszTrim
, lpszRead
[-1]))
1831 lpszRead
= CharPrevA(lpszStr
, lpszRead
); /* Skip trailing matches */
1833 if (lpszRead
!= lpszStr
+ dwLen
)
1843 /*************************************************************************
1844 * StrTrimW [SHLWAPI.@]
1848 BOOL WINAPI
StrTrimW(LPWSTR lpszStr
, LPCWSTR lpszTrim
)
1851 LPWSTR lpszRead
= lpszStr
;
1854 TRACE("(%s,%s)\n", debugstr_w(lpszStr
), debugstr_w(lpszTrim
));
1856 if (lpszRead
&& *lpszRead
)
1858 while (*lpszRead
&& StrChrW(lpszTrim
, *lpszRead
)) lpszRead
++;
1860 dwLen
= strlenW(lpszRead
);
1862 if (lpszRead
!= lpszStr
)
1864 memmove(lpszStr
, lpszRead
, (dwLen
+ 1) * sizeof(WCHAR
));
1869 lpszRead
= lpszStr
+ dwLen
;
1870 while (StrChrW(lpszTrim
, lpszRead
[-1]))
1871 lpszRead
--; /* Skip trailing matches */
1873 if (lpszRead
!= lpszStr
+ dwLen
)
1883 /*************************************************************************
1884 * _SHStrDupAA [INTERNAL]
1886 * Duplicates a ASCII string to ASCII. The destination buffer is allocated.
1888 static HRESULT
_SHStrDupAA(LPCSTR src
, LPSTR
* dest
)
1894 len
= lstrlenA(src
) + 1;
1895 *dest
= CoTaskMemAlloc(len
);
1901 lstrcpynA(*dest
,src
, len
);
1907 TRACE("%s->(%p)\n", debugstr_a(src
), *dest
);
1911 /*************************************************************************
1912 * SHStrDupA [SHLWAPI.@]
1914 * Return a Unicode copy of a string, in memory allocated by CoTaskMemAlloc().
1917 * lpszStr [I] String to copy
1918 * lppszDest [O] Destination for the new string copy
1921 * Success: S_OK. lppszDest contains the new string in Unicode format.
1922 * Failure: E_OUTOFMEMORY, If any arguments are invalid or memory allocation
1925 HRESULT WINAPI
SHStrDupA(LPCSTR lpszStr
, LPWSTR
* lppszDest
)
1932 len
= MultiByteToWideChar(CP_ACP
, 0, lpszStr
, -1, NULL
, 0) * sizeof(WCHAR
);
1933 *lppszDest
= CoTaskMemAlloc(len
);
1940 MultiByteToWideChar(CP_ACP
, 0, lpszStr
, -1, *lppszDest
, len
/sizeof(WCHAR
));
1944 hRet
= E_OUTOFMEMORY
;
1946 TRACE("%s->(%p)\n", debugstr_a(lpszStr
), *lppszDest
);
1950 /*************************************************************************
1951 * _SHStrDupAW [INTERNAL]
1953 * Duplicates a UNICODE to a ASCII string. The destination buffer is allocated.
1955 static HRESULT
_SHStrDupAW(LPCWSTR src
, LPSTR
* dest
)
1961 len
= WideCharToMultiByte(CP_ACP
, 0, src
, -1, NULL
, 0, NULL
, NULL
);
1962 *dest
= CoTaskMemAlloc(len
);
1968 WideCharToMultiByte(CP_ACP
, 0, src
, -1, *dest
, len
, NULL
, NULL
);
1974 TRACE("%s->(%p)\n", debugstr_w(src
), *dest
);
1978 /*************************************************************************
1979 * SHStrDupW [SHLWAPI.@]
1983 HRESULT WINAPI
SHStrDupW(LPCWSTR src
, LPWSTR
* dest
)
1989 len
= (lstrlenW(src
) + 1) * sizeof(WCHAR
);
1990 *dest
= CoTaskMemAlloc(len
);
1996 memcpy(*dest
, src
, len
);
2002 TRACE("%s->(%p)\n", debugstr_w(src
), *dest
);
2006 /*************************************************************************
2007 * SHLWAPI_WriteReverseNum
2009 * Internal helper for SHLWAPI_WriteTimeClass.
2011 static inline LPWSTR
SHLWAPI_WriteReverseNum(LPWSTR lpszOut
, DWORD dwNum
)
2015 /* Write a decimal number to a string, backwards */
2018 DWORD dwNextDigit
= dwNum
% 10;
2019 *lpszOut
-- = '0' + dwNextDigit
;
2020 dwNum
= (dwNum
- dwNextDigit
) / 10;
2021 } while (dwNum
> 0);
2026 /*************************************************************************
2027 * SHLWAPI_FormatSignificant
2029 * Internal helper for SHLWAPI_WriteTimeClass.
2031 static inline int SHLWAPI_FormatSignificant(LPWSTR lpszNum
, int dwDigits
)
2033 /* Zero non significant digits, return remaining significant digits */
2037 if (--dwDigits
== 0)
2047 /*************************************************************************
2048 * SHLWAPI_WriteTimeClass
2050 * Internal helper for StrFromTimeIntervalW.
2052 static int SHLWAPI_WriteTimeClass(LPWSTR lpszOut
, DWORD dwValue
,
2053 UINT uClassStringId
, int iDigits
)
2055 WCHAR szBuff
[64], *szOut
= szBuff
+ 32;
2057 szOut
= SHLWAPI_WriteReverseNum(szOut
, dwValue
);
2058 iDigits
= SHLWAPI_FormatSignificant(szOut
+ 1, iDigits
);
2060 LoadStringW(shlwapi_hInstance
, uClassStringId
, szBuff
+ 32, 32);
2061 strcatW(lpszOut
, szOut
);
2065 /*************************************************************************
2066 * StrFromTimeIntervalA [SHLWAPI.@]
2068 * Format a millisecond time interval into a string
2071 * lpszStr [O] Output buffer for formatted time interval
2072 * cchMax [I] Size of lpszStr
2073 * dwMS [I] Number of milliseconds
2074 * iDigits [I] Number of digits to print
2077 * The length of the formatted string, or 0 if any parameter is invalid.
2080 * This implementation mimics the Win32 behaviour of always writing a leading
2081 * space before the time interval begins.
2083 * iDigits is used to provide approximate times if accuracy is not important.
2084 * This number of digits will be written of the first non-zero time class
2085 * (hours/minutes/seconds). If this does not complete the time classification,
2086 * the remaining digits are changed to zeros (i.e. The time is _not_ rounded).
2087 * If there are digits remaining following the writing of a time class, the
2088 * next time class will be written.
2090 * For example, given dwMS represents 138 hours,43 minutes and 15 seconds, the
2091 * following will result from the given values of iDigits:
2093 *| iDigits 1 2 3 4 5 ...
2094 *| lpszStr "100 hr" "130 hr" "138 hr" "138 hr 40 min" "138 hr 43 min" ...
2096 INT WINAPI
StrFromTimeIntervalA(LPSTR lpszStr
, UINT cchMax
, DWORD dwMS
,
2101 TRACE("(%p,%d,%d,%d)\n", lpszStr
, cchMax
, dwMS
, iDigits
);
2103 if (lpszStr
&& cchMax
)
2106 StrFromTimeIntervalW(szBuff
, sizeof(szBuff
)/sizeof(WCHAR
), dwMS
, iDigits
);
2107 WideCharToMultiByte(CP_ACP
,0,szBuff
,-1,lpszStr
,cchMax
,0,0);
2113 /*************************************************************************
2114 * StrFromTimeIntervalW [SHLWAPI.@]
2116 * See StrFromTimeIntervalA.
2118 INT WINAPI
StrFromTimeIntervalW(LPWSTR lpszStr
, UINT cchMax
, DWORD dwMS
,
2123 TRACE("(%p,%d,%d,%d)\n", lpszStr
, cchMax
, dwMS
, iDigits
);
2125 if (lpszStr
&& cchMax
)
2128 DWORD dwHours
, dwMinutes
;
2130 if (!iDigits
|| cchMax
== 1)
2136 /* Calculate the time classes */
2137 dwMS
= (dwMS
+ 500) / 1000;
2138 dwHours
= dwMS
/ 3600;
2139 dwMS
-= dwHours
* 3600;
2140 dwMinutes
= dwMS
/ 60;
2141 dwMS
-= dwMinutes
* 60;
2146 iDigits
= SHLWAPI_WriteTimeClass(szCopy
, dwHours
, IDS_TIME_INTERVAL_HOURS
, iDigits
);
2148 if (dwMinutes
&& iDigits
)
2149 iDigits
= SHLWAPI_WriteTimeClass(szCopy
, dwMinutes
, IDS_TIME_INTERVAL_MINUTES
, iDigits
);
2151 if (iDigits
) /* Always write seconds if we have significant digits */
2152 SHLWAPI_WriteTimeClass(szCopy
, dwMS
, IDS_TIME_INTERVAL_SECONDS
, iDigits
);
2154 lstrcpynW(lpszStr
, szCopy
, cchMax
);
2155 iRet
= strlenW(lpszStr
);
2160 /*************************************************************************
2161 * StrIsIntlEqualA [SHLWAPI.@]
2163 * Compare two strings.
2166 * bCase [I] Whether to compare case sensitively
2167 * lpszStr [I] First string to compare
2168 * lpszComp [I] Second string to compare
2169 * iLen [I] Length to compare
2172 * TRUE If the strings are equal.
2175 BOOL WINAPI
StrIsIntlEqualA(BOOL bCase
, LPCSTR lpszStr
, LPCSTR lpszComp
,
2180 TRACE("(%d,%s,%s,%d)\n", bCase
,
2181 debugstr_a(lpszStr
), debugstr_a(lpszComp
), iLen
);
2183 /* FIXME: This flag is undocumented and unknown by our CompareString.
2184 * We need a define for it.
2186 dwFlags
= 0x10000000;
2187 if (!bCase
) dwFlags
|= NORM_IGNORECASE
;
2189 return (CompareStringA(GetThreadLocale(), dwFlags
, lpszStr
, iLen
, lpszComp
, iLen
) == CSTR_EQUAL
);
2192 /*************************************************************************
2193 * StrIsIntlEqualW [SHLWAPI.@]
2195 * See StrIsIntlEqualA.
2197 BOOL WINAPI
StrIsIntlEqualW(BOOL bCase
, LPCWSTR lpszStr
, LPCWSTR lpszComp
,
2202 TRACE("(%d,%s,%s,%d)\n", bCase
,
2203 debugstr_w(lpszStr
),debugstr_w(lpszComp
), iLen
);
2205 /* FIXME: This flag is undocumented and unknown by our CompareString.
2206 * We need a define for it.
2208 dwFlags
= 0x10000000;
2209 if (!bCase
) dwFlags
|= NORM_IGNORECASE
;
2211 return (CompareStringW(GetThreadLocale(), dwFlags
, lpszStr
, iLen
, lpszComp
, iLen
) == CSTR_EQUAL
);
2214 /*************************************************************************
2217 * Copy a string to another string, up to a maximum number of characters.
2220 * lpszDest [O] Destination string
2221 * lpszSrc [I] Source string
2222 * iLen [I] Maximum number of chars to copy
2225 * Success: A pointer to the last character written to lpszDest.
2226 * Failure: lpszDest, if any arguments are invalid.
2228 LPSTR WINAPI
StrCpyNXA(LPSTR lpszDest
, LPCSTR lpszSrc
, int iLen
)
2230 TRACE("(%p,%s,%i)\n", lpszDest
, debugstr_a(lpszSrc
), iLen
);
2232 if (lpszDest
&& lpszSrc
&& iLen
> 0)
2234 while ((iLen
-- > 1) && *lpszSrc
)
2235 *lpszDest
++ = *lpszSrc
++;
2242 /*************************************************************************
2245 * Unicode version of StrCpyNXA.
2247 LPWSTR WINAPI
StrCpyNXW(LPWSTR lpszDest
, LPCWSTR lpszSrc
, int iLen
)
2249 TRACE("(%p,%s,%i)\n", lpszDest
, debugstr_w(lpszSrc
), iLen
);
2251 if (lpszDest
&& lpszSrc
&& iLen
> 0)
2253 while ((iLen
-- > 1) && *lpszSrc
)
2254 *lpszDest
++ = *lpszSrc
++;
2261 /*************************************************************************
2262 * StrCmpLogicalW [SHLWAPI.@]
2264 * Compare two strings, ignoring case and comparing digits as numbers.
2267 * lpszStr [I] First string to compare
2268 * lpszComp [I] Second string to compare
2269 * iLen [I] Length to compare
2272 * TRUE If the strings are equal.
2275 INT WINAPI
StrCmpLogicalW(LPCWSTR lpszStr
, LPCWSTR lpszComp
)
2279 TRACE("(%s,%s)\n", debugstr_w(lpszStr
), debugstr_w(lpszComp
));
2281 if (lpszStr
&& lpszComp
)
2287 else if (isdigitW(*lpszStr
))
2291 if (!isdigitW(*lpszComp
))
2294 /* Compare the numbers */
2295 StrToIntExW(lpszStr
, 0, &iStr
);
2296 StrToIntExW(lpszComp
, 0, &iComp
);
2300 else if (iStr
> iComp
)
2304 while (isdigitW(*lpszStr
))
2306 while (isdigitW(*lpszComp
))
2309 else if (isdigitW(*lpszComp
))
2313 iDiff
= ChrCmpIW(*lpszStr
,*lpszComp
);
2329 /* Structure for formatting byte strings */
2330 typedef struct tagSHLWAPI_BYTEFORMATS
2337 } SHLWAPI_BYTEFORMATS
;
2339 /*************************************************************************
2340 * StrFormatByteSizeW [SHLWAPI.@]
2342 * Create a string containing an abbreviated byte count of up to 2^63-1.
2345 * llBytes [I] Byte size to format
2346 * lpszDest [I] Destination for formatted string
2347 * cchMax [I] Size of lpszDest
2353 * There is no StrFormatByteSize64W function, it is called StrFormatByteSizeW().
2355 LPWSTR WINAPI
StrFormatByteSizeW(LONGLONG llBytes
, LPWSTR lpszDest
, UINT cchMax
)
2357 #define KB ((ULONGLONG)1024)
2359 #define GB (KB*KB*KB)
2360 #define TB (KB*KB*KB*KB)
2361 #define PB (KB*KB*KB*KB*KB)
2363 static const SHLWAPI_BYTEFORMATS bfFormats
[] =
2365 { 10*KB
, 10.24, 100.0, 2, 'K' }, /* 10 KB */
2366 { 100*KB
, 102.4, 10.0, 1, 'K' }, /* 100 KB */
2367 { 1000*KB
, 1024.0, 1.0, 0, 'K' }, /* 1000 KB */
2368 { 10*MB
, 10485.76, 100.0, 2, 'M' }, /* 10 MB */
2369 { 100*MB
, 104857.6, 10.0, 1, 'M' }, /* 100 MB */
2370 { 1000*MB
, 1048576.0, 1.0, 0, 'M' }, /* 1000 MB */
2371 { 10*GB
, 10737418.24, 100.0, 2, 'G' }, /* 10 GB */
2372 { 100*GB
, 107374182.4, 10.0, 1, 'G' }, /* 100 GB */
2373 { 1000*GB
, 1073741824.0, 1.0, 0, 'G' }, /* 1000 GB */
2374 { 10*TB
, 10485.76, 100.0, 2, 'T' }, /* 10 TB */
2375 { 100*TB
, 104857.6, 10.0, 1, 'T' }, /* 100 TB */
2376 { 1000*TB
, 1048576.0, 1.0, 0, 'T' }, /* 1000 TB */
2377 { 10*PB
, 10737418.24, 100.00, 2, 'P' }, /* 10 PB */
2378 { 100*PB
, 107374182.4, 10.00, 1, 'P' }, /* 100 PB */
2379 { 1000*PB
, 1073741824.0, 1.00, 0, 'P' }, /* 1000 PB */
2380 { 0, 10995116277.76, 100.00, 2, 'E' } /* EB's, catch all */
2382 WCHAR wszAdd
[] = {' ','?','B',0};
2386 TRACE("(0x%s,%p,%d)\n", wine_dbgstr_longlong(llBytes
), lpszDest
, cchMax
);
2388 if (!lpszDest
|| !cchMax
)
2391 if (llBytes
< 1024) /* 1K */
2393 WCHAR wszBytesFormat
[64];
2394 LoadStringW(shlwapi_hInstance
, IDS_BYTES_FORMAT
, wszBytesFormat
, 64);
2395 snprintfW(lpszDest
, cchMax
, wszBytesFormat
, (int)llBytes
);
2399 /* Note that if this loop completes without finding a match, i will be
2400 * pointing at the last entry, which is a catch all for > 1000 PB
2402 while (i
< sizeof(bfFormats
) / sizeof(SHLWAPI_BYTEFORMATS
) - 1)
2404 if (llBytes
< bfFormats
[i
].dLimit
)
2408 /* Above 1 TB we encounter problems with FP accuracy. So for amounts above
2409 * this number we integer shift down by 1 MB first. The table above has
2410 * the divisors scaled down from the '< 10 TB' entry onwards, to account
2411 * for this. We also add a small fudge factor to get the correct result for
2412 * counts that lie exactly on a 1024 byte boundary.
2415 dBytes
= (double)(llBytes
>> 20) + 0.001; /* Scale down by 1 MB */
2417 dBytes
= (double)llBytes
+ 0.00001;
2419 dBytes
= floor(dBytes
/ bfFormats
[i
].dDivisor
) / bfFormats
[i
].dNormaliser
;
2421 if (!FormatDouble(dBytes
, bfFormats
[i
].nDecimals
, lpszDest
, cchMax
))
2423 wszAdd
[1] = bfFormats
[i
].wPrefix
;
2424 StrCatBuffW(lpszDest
, wszAdd
, cchMax
);
2428 /*************************************************************************
2429 * StrFormatByteSize64A [SHLWAPI.@]
2431 * See StrFormatByteSizeW.
2433 LPSTR WINAPI
StrFormatByteSize64A(LONGLONG llBytes
, LPSTR lpszDest
, UINT cchMax
)
2437 StrFormatByteSizeW(llBytes
, wszBuff
, sizeof(wszBuff
)/sizeof(WCHAR
));
2440 WideCharToMultiByte(CP_ACP
, 0, wszBuff
, -1, lpszDest
, cchMax
, 0, 0);
2444 /*************************************************************************
2445 * StrFormatByteSizeA [SHLWAPI.@]
2447 * Create a string containing an abbreviated byte count of up to 2^31-1.
2450 * dwBytes [I] Byte size to format
2451 * lpszDest [I] Destination for formatted string
2452 * cchMax [I] Size of lpszDest
2458 * The Ascii and Unicode versions of this function accept a different
2459 * integer type for dwBytes. See StrFormatByteSize64A().
2461 LPSTR WINAPI
StrFormatByteSizeA(DWORD dwBytes
, LPSTR lpszDest
, UINT cchMax
)
2463 TRACE("(%d,%p,%d)\n", dwBytes
, lpszDest
, cchMax
);
2465 return StrFormatByteSize64A(dwBytes
, lpszDest
, cchMax
);
2468 /*************************************************************************
2471 * Remove a hanging lead byte from the end of a string, if present.
2474 * lpStr [I] String to check for a hanging lead byte
2475 * size [I] Length of lpStr
2478 * Success: The new length of the string. Any hanging lead bytes are removed.
2479 * Failure: 0, if any parameters are invalid.
2481 DWORD WINAPI
SHTruncateString(LPSTR lpStr
, DWORD size
)
2485 LPSTR lastByte
= lpStr
+ size
- 1;
2487 while(lpStr
< lastByte
)
2488 lpStr
+= IsDBCSLeadByte(*lpStr
) ? 2 : 1;
2490 if(lpStr
== lastByte
&& IsDBCSLeadByte(*lpStr
))
2500 /*************************************************************************
2503 * Remove a single non-trailing ampersand ('&') from a string.
2506 * lpszStr [I/O] String to remove ampersand from.
2509 * The character after the first ampersand in lpszStr, or the first character
2510 * in lpszStr if there is no ampersand in the string.
2512 char WINAPI
SHStripMneumonicA(LPCSTR lpszStr
)
2514 LPSTR lpszIter
, lpszTmp
;
2517 TRACE("(%s)\n", debugstr_a(lpszStr
));
2521 if ((lpszIter
= StrChrA(lpszStr
, '&')))
2523 lpszTmp
= CharNextA(lpszIter
);
2526 if (*lpszTmp
!= '&')
2529 memmove( lpszIter
, lpszTmp
, strlen(lpszTmp
) + 1 );
2536 /*************************************************************************
2539 * Unicode version of SHStripMneumonicA.
2541 WCHAR WINAPI
SHStripMneumonicW(LPCWSTR lpszStr
)
2543 LPWSTR lpszIter
, lpszTmp
;
2546 TRACE("(%s)\n", debugstr_w(lpszStr
));
2550 if ((lpszIter
= StrChrW(lpszStr
, '&')))
2552 lpszTmp
= lpszIter
+ 1;
2555 if (*lpszTmp
!= '&')
2558 memmove( lpszIter
, lpszTmp
, (strlenW(lpszTmp
) + 1) * sizeof(WCHAR
) );
2565 /*************************************************************************
2568 * Convert an Ascii string to Unicode.
2571 * dwCp [I] Code page for the conversion
2572 * lpSrcStr [I] Source Ascii string to convert
2573 * lpDstStr [O] Destination for converted Unicode string
2574 * iLen [I] Length of lpDstStr
2577 * The return value of the MultiByteToWideChar() function called on lpSrcStr.
2579 DWORD WINAPI
SHAnsiToUnicodeCP(DWORD dwCp
, LPCSTR lpSrcStr
, LPWSTR lpDstStr
, int iLen
)
2583 dwRet
= MultiByteToWideChar(dwCp
, 0, lpSrcStr
, -1, lpDstStr
, iLen
);
2584 TRACE("%s->%s,ret=%d\n", debugstr_a(lpSrcStr
), debugstr_w(lpDstStr
), dwRet
);
2588 /*************************************************************************
2591 * Convert an Ascii string to Unicode.
2594 * lpSrcStr [I] Source Ascii string to convert
2595 * lpDstStr [O] Destination for converted Unicode string
2596 * iLen [I] Length of lpDstStr
2599 * The return value of the MultiByteToWideChar() function called on lpSrcStr.
2602 * This function simply calls SHAnsiToUnicodeCP with code page CP_ACP.
2604 DWORD WINAPI
SHAnsiToUnicode(LPCSTR lpSrcStr
, LPWSTR lpDstStr
, int iLen
)
2606 return SHAnsiToUnicodeCP(CP_ACP
, lpSrcStr
, lpDstStr
, iLen
);
2609 /*************************************************************************
2612 * Convert a Unicode string to Ascii.
2615 * CodePage [I] Code page to use for the conversion
2616 * lpSrcStr [I] Source Unicode string to convert
2617 * lpDstStr [O] Destination for converted Ascii string
2618 * dstlen [I] Length of buffer at lpDstStr
2621 * Success: The length in bytes of the result at lpDstStr (including the terminator)
2622 * Failure: When using CP_UTF8, CP_UTF7 or 0xc350 as codePage, 0 is returned and
2623 * the result is not nul-terminated.
2624 * When using a different codepage, the length in bytes of the truncated
2625 * result at lpDstStr (including the terminator) is returned and
2626 * lpDstStr is always nul-terminated.
2629 DWORD WINAPI
SHUnicodeToAnsiCP(UINT CodePage
, LPCWSTR lpSrcStr
, LPSTR lpDstStr
, int dstlen
)
2631 static const WCHAR emptyW
[] = { '\0' };
2635 if (!lpDstStr
|| !dstlen
)
2643 len
= strlenW(lpSrcStr
) + 1;
2648 CodePage
= CP_UTF8
; /* Fall through... */
2649 case 0x0000C350: /* FIXME: CP_ #define */
2655 INT needed
= dstlen
- 1;
2658 /* try the user supplied buffer first */
2659 hr
= ConvertINetUnicodeToMultiByte(&dwMode
, CodePage
, lpSrcStr
, &lenW
, lpDstStr
, &needed
);
2662 lpDstStr
[needed
] = '\0';
2666 /* user buffer too small. exclude termination and copy as much as possible */
2668 hr
= ConvertINetUnicodeToMultiByte(&dwMode
, CodePage
, lpSrcStr
, &lenW
, NULL
, &needed
);
2670 mem
= HeapAlloc(GetProcessHeap(), 0, needed
);
2674 hr
= ConvertINetUnicodeToMultiByte(&dwMode
, CodePage
, lpSrcStr
, &len
, mem
, &needed
);
2677 reqLen
= SHTruncateString(mem
, dstlen
);
2678 if (reqLen
> 0) memcpy(lpDstStr
, mem
, reqLen
-1);
2680 HeapFree(GetProcessHeap(), 0, mem
);
2687 /* try the user supplied buffer first */
2688 reqLen
= WideCharToMultiByte(CodePage
, 0, lpSrcStr
, len
, lpDstStr
, dstlen
, NULL
, NULL
);
2690 if (!reqLen
&& GetLastError() == ERROR_INSUFFICIENT_BUFFER
)
2692 reqLen
= WideCharToMultiByte(CodePage
, 0, lpSrcStr
, len
, NULL
, 0, NULL
, NULL
);
2695 mem
= HeapAlloc(GetProcessHeap(), 0, reqLen
);
2698 WideCharToMultiByte(CodePage
, 0, lpSrcStr
, len
, mem
, reqLen
, NULL
, NULL
);
2700 reqLen
= SHTruncateString(mem
, dstlen
-1);
2703 lstrcpynA(lpDstStr
, mem
, reqLen
);
2704 HeapFree(GetProcessHeap(), 0, mem
);
2705 lpDstStr
[reqLen
-1] = '\0';
2712 /*************************************************************************
2715 * Convert a Unicode string to Ascii.
2718 * lpSrcStr [I] Source Unicode string to convert
2719 * lpDstStr [O] Destination for converted Ascii string
2720 * iLen [O] Length of lpDstStr in characters
2723 * See SHUnicodeToAnsiCP
2726 * This function simply calls SHUnicodeToAnsiCP() with CodePage = CP_ACP.
2728 INT WINAPI
SHUnicodeToAnsi(LPCWSTR lpSrcStr
, LPSTR lpDstStr
, INT iLen
)
2730 return SHUnicodeToAnsiCP(CP_ACP
, lpSrcStr
, lpDstStr
, iLen
);
2733 /*************************************************************************
2736 * Copy one string to another.
2739 * lpszSrc [I] Source string to copy
2740 * lpszDst [O] Destination for copy
2741 * iLen [I] Length of lpszDst in characters
2744 * The length of the copied string, including the terminating NUL. lpszDst
2745 * contains iLen characters of lpszSrc.
2747 DWORD WINAPI
SHAnsiToAnsi(LPCSTR lpszSrc
, LPSTR lpszDst
, int iLen
)
2751 TRACE("(%s,%p,0x%08x)\n", debugstr_a(lpszSrc
), lpszDst
, iLen
);
2753 lpszRet
= StrCpyNXA(lpszDst
, lpszSrc
, iLen
);
2754 return lpszRet
- lpszDst
+ 1;
2757 /*************************************************************************
2760 * Unicode version of SSHAnsiToAnsi.
2762 DWORD WINAPI
SHUnicodeToUnicode(LPCWSTR lpszSrc
, LPWSTR lpszDst
, int iLen
)
2766 TRACE("(%s,%p,0x%08x)\n", debugstr_w(lpszSrc
), lpszDst
, iLen
);
2768 lpszRet
= StrCpyNXW(lpszDst
, lpszSrc
, iLen
);
2769 return lpszRet
- lpszDst
+ 1;
2772 /*************************************************************************
2775 * Determine if an Ascii string converts to Unicode and back identically.
2778 * lpSrcStr [I] Source Unicode string to convert
2779 * lpDst [O] Destination for resulting Ascii string
2780 * iLen [I] Length of lpDst in characters
2783 * TRUE, since Ascii strings always convert identically.
2785 BOOL WINAPI
DoesStringRoundTripA(LPCSTR lpSrcStr
, LPSTR lpDst
, INT iLen
)
2787 lstrcpynA(lpDst
, lpSrcStr
, iLen
);
2791 /*************************************************************************
2794 * Determine if a Unicode string converts to Ascii and back identically.
2797 * lpSrcStr [I] Source Unicode string to convert
2798 * lpDst [O] Destination for resulting Ascii string
2799 * iLen [I] Length of lpDst in characters
2802 * TRUE, if lpSrcStr converts to Ascii and back identically,
2805 BOOL WINAPI
DoesStringRoundTripW(LPCWSTR lpSrcStr
, LPSTR lpDst
, INT iLen
)
2807 WCHAR szBuff
[MAX_PATH
];
2809 SHUnicodeToAnsi(lpSrcStr
, lpDst
, iLen
);
2810 SHAnsiToUnicode(lpDst
, szBuff
, MAX_PATH
);
2811 return !strcmpW(lpSrcStr
, szBuff
);
2814 /*************************************************************************
2815 * SHLoadIndirectString [SHLWAPI.@]
2817 * If passed a string that begins with '@', extract the string from the
2818 * appropriate resource, otherwise do a straight copy.
2821 HRESULT WINAPI
SHLoadIndirectString(LPCWSTR src
, LPWSTR dst
, UINT dst_len
, void **reserved
)
2823 WCHAR
*dllname
= NULL
;
2824 HMODULE hmod
= NULL
;
2825 HRESULT hr
= E_FAIL
;
2827 TRACE("(%s %p %08x %p)\n", debugstr_w(src
), dst
, dst_len
, reserved
);
2835 dllname
= StrDupW(src
+ 1);
2836 index_str
= strchrW(dllname
, ',');
2838 if(!index_str
) goto end
;
2842 index
= atoiW(index_str
);
2844 hmod
= LoadLibraryW(dllname
);
2849 if(LoadStringW(hmod
, -index
, dst
, dst_len
))
2853 FIXME("can't handle non-negative indices (%d)\n", index
);
2858 lstrcpynW(dst
, src
, dst_len
);
2862 TRACE("returning %s\n", debugstr_w(dst
));
2864 if(hmod
) FreeLibrary(hmod
);
2869 BOOL WINAPI
IsCharSpaceA(CHAR c
)
2872 return GetStringTypeA(GetSystemDefaultLCID(), CT_CTYPE1
, &c
, 1, &CharType
) && (CharType
& C1_SPACE
);
2875 /*************************************************************************
2878 * Determine if a Unicode character is a space.
2881 * wc [I] Character to check.
2884 * TRUE, if wc is a space,
2887 BOOL WINAPI
IsCharSpaceW(WCHAR wc
)
2891 return GetStringTypeW(CT_CTYPE1
, &wc
, 1, &CharType
) && (CharType
& C1_SPACE
);