kernel32/tests: Add a test to check some fields in fake dlls.
[wine.git] / dlls / shlwapi / string.c
blobd400f8befe4120821bf7192607ffc65c8557714b
1 /*
2 * Shlwapi string functions
4 * Copyright 1998 Juergen Schmied
5 * Copyright 2002 Jon Griffiths
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "config.h"
23 #include "wine/port.h"
25 #include <math.h>
26 #include <stdarg.h>
27 #include <stdio.h>
28 #include <string.h>
30 #define NONAMELESSUNION
32 #include "windef.h"
33 #include "winbase.h"
34 #define NO_SHLWAPI_REG
35 #define NO_SHLWAPI_STREAM
36 #include "shlwapi.h"
37 #include "wingdi.h"
38 #include "winuser.h"
39 #include "shlobj.h"
40 #include "mlang.h"
41 #include "ddeml.h"
42 #include "wine/unicode.h"
43 #include "wine/debug.h"
45 #include "resource.h"
47 WINE_DEFAULT_DEBUG_CHANNEL(shell);
49 extern HINSTANCE shlwapi_hInstance;
51 static HRESULT _SHStrDupAA(LPCSTR,LPSTR*);
52 static HRESULT _SHStrDupAW(LPCWSTR,LPSTR*);
55 static void FillNumberFmt(NUMBERFMTW *fmt, LPWSTR decimal_buffer, int decimal_bufwlen,
56 LPWSTR thousand_buffer, int thousand_bufwlen)
58 WCHAR grouping[64];
59 WCHAR *c;
61 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_ILZERO|LOCALE_RETURN_NUMBER, (LPWSTR)&fmt->LeadingZero, sizeof(fmt->LeadingZero)/sizeof(WCHAR));
62 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_INEGNUMBER|LOCALE_RETURN_NUMBER, (LPWSTR)&fmt->LeadingZero, sizeof(fmt->NegativeOrder)/sizeof(WCHAR));
63 fmt->NumDigits = 0;
64 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, decimal_buffer, decimal_bufwlen);
65 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, thousand_buffer, thousand_bufwlen);
66 fmt->lpThousandSep = thousand_buffer;
67 fmt->lpDecimalSep = decimal_buffer;
69 /*
70 * Converting grouping string to number as described on
71 * http://blogs.msdn.com/oldnewthing/archive/2006/04/18/578251.aspx
73 fmt->Grouping = 0;
74 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SGROUPING, grouping, ARRAY_SIZE(grouping));
75 for (c = grouping; *c; c++)
76 if (*c >= '0' && *c < '9')
78 fmt->Grouping *= 10;
79 fmt->Grouping += *c - '0';
82 if (fmt->Grouping % 10 == 0)
83 fmt->Grouping /= 10;
84 else
85 fmt->Grouping *= 10;
88 /*************************************************************************
89 * FormatInt [internal]
91 * Format an integer according to the current locale
93 * RETURNS
94 * The number of characters written on success or 0 on failure
96 static int FormatInt(LONGLONG qdwValue, LPWSTR pszBuf, int cchBuf)
98 NUMBERFMTW fmt;
99 WCHAR decimal[8], thousand[8];
100 WCHAR buf[24];
101 WCHAR *c;
102 BOOL neg = (qdwValue < 0);
104 FillNumberFmt(&fmt, decimal, ARRAY_SIZE(decimal), thousand, ARRAY_SIZE(thousand));
106 c = &buf[24];
107 *(--c) = 0;
110 *(--c) = '0' + (qdwValue%10);
111 qdwValue /= 10;
112 } while (qdwValue > 0);
113 if (neg)
114 *(--c) = '-';
116 return GetNumberFormatW(LOCALE_USER_DEFAULT, 0, c, &fmt, pszBuf, cchBuf);
119 /*************************************************************************
120 * FormatDouble [internal]
122 * Format an integer according to the current locale. Prints the specified number of digits
123 * after the decimal point
125 * RETURNS
126 * The number of characters written on success or 0 on failure
128 static int FormatDouble(double value, int decimals, LPWSTR pszBuf, int cchBuf)
130 static const WCHAR flfmt[] = {'%','f',0};
131 WCHAR buf[64];
132 NUMBERFMTW fmt;
133 WCHAR decimal[8], thousand[8];
135 snprintfW(buf, 64, flfmt, value);
137 FillNumberFmt(&fmt, decimal, ARRAY_SIZE(decimal), thousand, ARRAY_SIZE(thousand));
138 fmt.NumDigits = decimals;
139 return GetNumberFormatW(LOCALE_USER_DEFAULT, 0, buf, &fmt, pszBuf, cchBuf);
142 /*************************************************************************
143 * SHLWAPI_ChrCmpHelperA
145 * Internal helper for SHLWAPI_ChrCmpA/ChrCMPIA.
147 * NOTES
148 * Both this function and its Unicode counterpart are very inefficient. To
149 * fix this, CompareString must be completely implemented and optimised
150 * first. Then the core character test can be taken out of that function and
151 * placed here, so that it need never be called at all. Until then, do not
152 * attempt to optimise this code unless you are willing to test that it
153 * still performs correctly.
155 static BOOL SHLWAPI_ChrCmpHelperA(WORD ch1, WORD ch2, DWORD dwFlags)
157 char str1[3], str2[3];
159 str1[0] = LOBYTE(ch1);
160 if (IsDBCSLeadByte(str1[0]))
162 str1[1] = HIBYTE(ch1);
163 str1[2] = '\0';
165 else
166 str1[1] = '\0';
168 str2[0] = LOBYTE(ch2);
169 if (IsDBCSLeadByte(str2[0]))
171 str2[1] = HIBYTE(ch2);
172 str2[2] = '\0';
174 else
175 str2[1] = '\0';
177 return CompareStringA(GetThreadLocale(), dwFlags, str1, -1, str2, -1) - CSTR_EQUAL;
180 /*************************************************************************
181 * SHLWAPI_ChrCmpA
183 * Internal helper function.
185 static BOOL WINAPI SHLWAPI_ChrCmpA(WORD ch1, WORD ch2)
187 return SHLWAPI_ChrCmpHelperA(ch1, ch2, 0);
190 /*************************************************************************
191 * ChrCmpIA (SHLWAPI.385)
193 * Compare two characters, ignoring case.
195 * PARAMS
196 * ch1 [I] First character to compare
197 * ch2 [I] Second character to compare
199 * RETURNS
200 * FALSE, if the characters are equal.
201 * Non-zero otherwise.
203 BOOL WINAPI ChrCmpIA(WORD ch1, WORD ch2)
205 TRACE("(%d,%d)\n", ch1, ch2);
207 return SHLWAPI_ChrCmpHelperA(ch1, ch2, NORM_IGNORECASE);
210 /*************************************************************************
211 * ChrCmpIW [SHLWAPI.386]
213 * See ChrCmpIA.
215 BOOL WINAPI ChrCmpIW(WCHAR ch1, WCHAR ch2)
217 return CompareStringW(GetThreadLocale(), NORM_IGNORECASE, &ch1, 1, &ch2, 1) - CSTR_EQUAL;
220 /*************************************************************************
221 * StrChrA [SHLWAPI.@]
223 * Find a given character in a string.
225 * PARAMS
226 * lpszStr [I] String to search in.
227 * ch [I] Character to search for.
229 * RETURNS
230 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
231 * not found.
232 * Failure: NULL, if any arguments are invalid.
234 LPSTR WINAPI StrChrA(LPCSTR lpszStr, WORD ch)
236 TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch);
238 if (lpszStr)
240 while (*lpszStr)
242 if (!SHLWAPI_ChrCmpA(*lpszStr, ch))
243 return (LPSTR)lpszStr;
244 lpszStr = CharNextA(lpszStr);
247 return NULL;
250 /*************************************************************************
251 * StrChrW [SHLWAPI.@]
253 * See StrChrA.
255 LPWSTR WINAPI StrChrW(LPCWSTR lpszStr, WCHAR ch)
257 LPWSTR lpszRet = NULL;
259 TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch);
261 if (lpszStr)
262 lpszRet = strchrW(lpszStr, ch);
263 return lpszRet;
266 /*************************************************************************
267 * StrChrIA [SHLWAPI.@]
269 * Find a given character in a string, ignoring case.
271 * PARAMS
272 * lpszStr [I] String to search in.
273 * ch [I] Character to search for.
275 * RETURNS
276 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
277 * not found.
278 * Failure: NULL, if any arguments are invalid.
280 LPSTR WINAPI StrChrIA(LPCSTR lpszStr, WORD ch)
282 TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch);
284 if (lpszStr)
286 while (*lpszStr)
288 if (!ChrCmpIA(*lpszStr, ch))
289 return (LPSTR)lpszStr;
290 lpszStr = CharNextA(lpszStr);
293 return NULL;
296 /*************************************************************************
297 * StrChrIW [SHLWAPI.@]
299 * See StrChrA.
301 LPWSTR WINAPI StrChrIW(LPCWSTR lpszStr, WCHAR ch)
303 TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch);
305 if (lpszStr)
307 ch = toupperW(ch);
308 while (*lpszStr)
310 if (toupperW(*lpszStr) == ch)
311 return (LPWSTR)lpszStr;
312 lpszStr++;
314 lpszStr = NULL;
316 return (LPWSTR)lpszStr;
319 /*************************************************************************
320 * StrChrNW [SHLWAPI.@]
322 LPWSTR WINAPI StrChrNW(LPCWSTR lpszStr, WCHAR ch, UINT cchMax)
324 TRACE("(%s(%i),%i)\n", debugstr_wn(lpszStr,cchMax), cchMax, ch);
326 if (lpszStr)
328 while (*lpszStr && cchMax-- > 0)
330 if (*lpszStr == ch)
331 return (LPWSTR)lpszStr;
332 lpszStr++;
335 return NULL;
338 /*************************************************************************
339 * StrCmpIW [SHLWAPI.@]
341 * Compare two strings, ignoring case.
343 * PARAMS
344 * lpszStr [I] First string to compare
345 * lpszComp [I] Second string to compare
347 * RETURNS
348 * An integer less than, equal to or greater than 0, indicating that
349 * lpszStr is less than, the same, or greater than lpszComp.
351 int WINAPI StrCmpIW(LPCWSTR lpszStr, LPCWSTR lpszComp)
353 TRACE("(%s,%s)\n", debugstr_w(lpszStr),debugstr_w(lpszComp));
354 return CompareStringW(GetThreadLocale(), NORM_IGNORECASE, lpszStr, -1, lpszComp, -1) - CSTR_EQUAL;
357 /*************************************************************************
358 * StrCmpNA [SHLWAPI.@]
360 * Compare two strings, up to a maximum length.
362 * PARAMS
363 * lpszStr [I] First string to compare
364 * lpszComp [I] Second string to compare
365 * iLen [I] Number of chars to compare
367 * RETURNS
368 * An integer less than, equal to or greater than 0, indicating that
369 * lpszStr is less than, the same, or greater than lpszComp.
371 INT WINAPI StrCmpNA(LPCSTR lpszStr, LPCSTR lpszComp, INT iLen)
373 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
374 return CompareStringA(GetThreadLocale(), 0, lpszStr, iLen, lpszComp, iLen) - CSTR_EQUAL;
377 /*************************************************************************
378 * StrCmpNW [SHLWAPI.@]
380 * See StrCmpNA.
382 INT WINAPI StrCmpNW(LPCWSTR lpszStr, LPCWSTR lpszComp, INT iLen)
384 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen);
385 return CompareStringW(GetThreadLocale(), 0, lpszStr, iLen, lpszComp, iLen) - CSTR_EQUAL;
388 /*************************************************************************
389 * StrCmpNIA [SHLWAPI.@]
391 * Compare two strings, up to a maximum length, ignoring case.
393 * PARAMS
394 * lpszStr [I] First string to compare
395 * lpszComp [I] Second string to compare
396 * iLen [I] Number of chars to compare
398 * RETURNS
399 * An integer less than, equal to or greater than 0, indicating that
400 * lpszStr is less than, the same, or greater than lpszComp.
402 int WINAPI StrCmpNIA(LPCSTR lpszStr, LPCSTR lpszComp, int iLen)
404 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
405 return CompareStringA(GetThreadLocale(), NORM_IGNORECASE, lpszStr, iLen, lpszComp, iLen) - CSTR_EQUAL;
408 /*************************************************************************
409 * StrCmpNIW [SHLWAPI.@]
411 * See StrCmpNIA.
413 INT WINAPI StrCmpNIW(LPCWSTR lpszStr, LPCWSTR lpszComp, int iLen)
415 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen);
416 return CompareStringW(GetThreadLocale(), NORM_IGNORECASE, lpszStr, iLen, lpszComp, iLen) - CSTR_EQUAL;
419 /*************************************************************************
420 * StrCmpW [SHLWAPI.@]
422 * Compare two strings.
424 * PARAMS
425 * lpszStr [I] First string to compare
426 * lpszComp [I] Second string to compare
428 * RETURNS
429 * An integer less than, equal to or greater than 0, indicating that
430 * lpszStr is less than, the same, or greater than lpszComp.
432 int WINAPI StrCmpW(LPCWSTR lpszStr, LPCWSTR lpszComp)
434 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszComp));
435 return CompareStringW(GetThreadLocale(), 0, lpszStr, -1, lpszComp, -1) - CSTR_EQUAL;
438 /*************************************************************************
439 * StrCatW [SHLWAPI.@]
441 * Concatenate two strings.
443 * PARAMS
444 * lpszStr [O] Initial string
445 * lpszSrc [I] String to concatenate
447 * RETURNS
448 * lpszStr.
450 LPWSTR WINAPI StrCatW(LPWSTR lpszStr, LPCWSTR lpszSrc)
452 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSrc));
454 if (lpszStr && lpszSrc)
455 strcatW(lpszStr, lpszSrc);
456 return lpszStr;
459 /*************************************************************************
460 * StrCatChainW [SHLWAPI.@]
462 * Concatenates two unicode strings.
464 * PARAMS
465 * lpszStr [O] Initial string
466 * cchMax [I] Length of destination buffer
467 * ichAt [I] Offset from the destination buffer to begin concatenation
468 * lpszCat [I] String to concatenate
470 * RETURNS
471 * The offset from the beginning of pszDst to the terminating NULL.
473 DWORD WINAPI StrCatChainW(LPWSTR lpszStr, DWORD cchMax, DWORD ichAt, LPCWSTR lpszCat)
475 TRACE("(%s,%u,%d,%s)\n", debugstr_w(lpszStr), cchMax, ichAt, debugstr_w(lpszCat));
477 if (ichAt == -1)
478 ichAt = strlenW(lpszStr);
480 if (!cchMax)
481 return ichAt;
483 if (ichAt == cchMax)
484 ichAt--;
486 if (lpszCat && ichAt < cchMax)
488 lpszStr += ichAt;
489 while (ichAt < cchMax - 1 && *lpszCat)
491 *lpszStr++ = *lpszCat++;
492 ichAt++;
494 *lpszStr = 0;
497 return ichAt;
500 /*************************************************************************
501 * StrCpyW [SHLWAPI.@]
503 * Copy a string to another string.
505 * PARAMS
506 * lpszStr [O] Destination string
507 * lpszSrc [I] Source string
509 * RETURNS
510 * lpszStr.
512 LPWSTR WINAPI StrCpyW(LPWSTR lpszStr, LPCWSTR lpszSrc)
514 TRACE("(%p,%s)\n", lpszStr, debugstr_w(lpszSrc));
516 if (lpszStr && lpszSrc)
517 strcpyW(lpszStr, lpszSrc);
518 return lpszStr;
521 /*************************************************************************
522 * StrCpyNW [SHLWAPI.@]
524 * Copy a string to another string, up to a maximum number of characters.
526 * PARAMS
527 * dst [O] Destination string
528 * src [I] Source string
529 * count [I] Maximum number of chars to copy
531 * RETURNS
532 * dst.
534 LPWSTR WINAPI StrCpyNW(LPWSTR dst, LPCWSTR src, int count)
536 LPWSTR d = dst;
537 LPCWSTR s = src;
539 TRACE("(%p,%s,%i)\n", dst, debugstr_w(src), count);
541 if (s)
543 while ((count > 1) && *s)
545 count--;
546 *d++ = *s++;
549 if (count) *d = 0;
551 return dst;
554 /*************************************************************************
555 * SHLWAPI_StrStrHelperA
557 * Internal implementation of StrStrA/StrStrIA
559 static LPSTR SHLWAPI_StrStrHelperA(LPCSTR lpszStr, LPCSTR lpszSearch,
560 INT (WINAPI *pStrCmpFn)(LPCSTR,LPCSTR,INT))
562 size_t iLen;
563 LPCSTR end;
565 if (!lpszStr || !lpszSearch || !*lpszSearch)
566 return NULL;
568 iLen = strlen(lpszSearch);
569 end = lpszStr + strlen(lpszStr);
571 while (lpszStr + iLen <= end)
573 if (!pStrCmpFn(lpszStr, lpszSearch, iLen))
574 return (LPSTR)lpszStr;
575 lpszStr = CharNextA(lpszStr);
577 return NULL;
580 /*************************************************************************
581 * StrStrA [SHLWAPI.@]
583 * Find a substring within a string.
585 * PARAMS
586 * lpszStr [I] String to search in
587 * lpszSearch [I] String to look for
589 * RETURNS
590 * The start of lpszSearch within lpszStr, or NULL if not found.
592 LPSTR WINAPI StrStrA(LPCSTR lpszStr, LPCSTR lpszSearch)
594 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
596 return SHLWAPI_StrStrHelperA(lpszStr, lpszSearch, StrCmpNA);
599 /*************************************************************************
600 * StrStrW [SHLWAPI.@]
602 * See StrStrA.
604 LPWSTR WINAPI StrStrW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
606 TRACE("(%s, %s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
608 if (!lpszStr || !lpszSearch || !*lpszSearch) return NULL;
609 return strstrW( lpszStr, lpszSearch );
612 /*************************************************************************
613 * StrRStrIA [SHLWAPI.@]
615 * Find the last occurrence of a substring within a string.
617 * PARAMS
618 * lpszStr [I] String to search in
619 * lpszEnd [I] End of lpszStr
620 * lpszSearch [I] String to look for
622 * RETURNS
623 * The last occurrence lpszSearch within lpszStr, or NULL if not found.
625 LPSTR WINAPI StrRStrIA(LPCSTR lpszStr, LPCSTR lpszEnd, LPCSTR lpszSearch)
627 LPSTR lpszRet = NULL;
628 WORD ch1, ch2;
629 INT iLen;
631 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
633 if (!lpszStr || !lpszSearch || !*lpszSearch)
634 return NULL;
636 if (IsDBCSLeadByte(*lpszSearch))
637 ch1 = *lpszSearch << 8 | (UCHAR)lpszSearch[1];
638 else
639 ch1 = *lpszSearch;
640 iLen = lstrlenA(lpszSearch);
642 if (!lpszEnd)
643 lpszEnd = lpszStr + lstrlenA(lpszStr);
644 else /* reproduce the broken behaviour on Windows */
645 lpszEnd += min(iLen - 1, lstrlenA(lpszEnd));
647 while (lpszStr + iLen <= lpszEnd && *lpszStr)
649 ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | (UCHAR)lpszStr[1] : *lpszStr;
650 if (!ChrCmpIA(ch1, ch2))
652 if (!StrCmpNIA(lpszStr, lpszSearch, iLen))
653 lpszRet = (LPSTR)lpszStr;
655 lpszStr = CharNextA(lpszStr);
657 return lpszRet;
660 /*************************************************************************
661 * StrRStrIW [SHLWAPI.@]
663 * See StrRStrIA.
665 LPWSTR WINAPI StrRStrIW(LPCWSTR lpszStr, LPCWSTR lpszEnd, LPCWSTR lpszSearch)
667 LPWSTR lpszRet = NULL;
668 INT iLen;
670 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
672 if (!lpszStr || !lpszSearch || !*lpszSearch)
673 return NULL;
675 iLen = strlenW(lpszSearch);
677 if (!lpszEnd)
678 lpszEnd = lpszStr + strlenW(lpszStr);
679 else /* reproduce the broken behaviour on Windows */
680 lpszEnd += min(iLen - 1, lstrlenW(lpszEnd));
682 while (lpszStr + iLen <= lpszEnd && *lpszStr)
684 if (!ChrCmpIW(*lpszSearch, *lpszStr))
686 if (!StrCmpNIW(lpszStr, lpszSearch, iLen))
687 lpszRet = (LPWSTR)lpszStr;
689 lpszStr++;
691 return lpszRet;
694 /*************************************************************************
695 * StrStrIA [SHLWAPI.@]
697 * Find a substring within a string, ignoring case.
699 * PARAMS
700 * lpszStr [I] String to search in
701 * lpszSearch [I] String to look for
703 * RETURNS
704 * The start of lpszSearch within lpszStr, or NULL if not found.
706 LPSTR WINAPI StrStrIA(LPCSTR lpszStr, LPCSTR lpszSearch)
708 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
710 return SHLWAPI_StrStrHelperA(lpszStr, lpszSearch, StrCmpNIA);
713 /*************************************************************************
714 * StrStrIW [SHLWAPI.@]
716 * See StrStrIA.
718 LPWSTR WINAPI StrStrIW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
720 int iLen;
721 LPCWSTR end;
723 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
725 if (!lpszStr || !lpszSearch || !*lpszSearch)
726 return NULL;
728 iLen = strlenW(lpszSearch);
729 end = lpszStr + strlenW(lpszStr);
731 while (lpszStr + iLen <= end)
733 if (!StrCmpNIW(lpszStr, lpszSearch, iLen))
734 return (LPWSTR)lpszStr;
735 lpszStr++;
737 return NULL;
740 /*************************************************************************
741 * StrStrNW [SHLWAPI.@]
743 * Find a substring within a string up to a given number of initial characters.
745 * PARAMS
746 * lpFirst [I] String to search in
747 * lpSrch [I] String to look for
748 * cchMax [I] Maximum number of initial search characters
750 * RETURNS
751 * The start of lpFirst within lpSrch, or NULL if not found.
753 LPWSTR WINAPI StrStrNW(LPCWSTR lpFirst, LPCWSTR lpSrch, UINT cchMax)
755 UINT i;
756 int len;
758 TRACE("(%s, %s, %u)\n", debugstr_w(lpFirst), debugstr_w(lpSrch), cchMax);
760 if (!lpFirst || !lpSrch || !*lpSrch || !cchMax)
761 return NULL;
763 len = strlenW(lpSrch);
765 for (i = cchMax; *lpFirst && (i > 0); i--, lpFirst++)
767 if (!strncmpW(lpFirst, lpSrch, len))
768 return (LPWSTR)lpFirst;
771 return NULL;
774 /*************************************************************************
775 * StrStrNIW [SHLWAPI.@]
777 * Find a substring within a string up to a given number of initial characters,
778 * ignoring case.
780 * PARAMS
781 * lpFirst [I] String to search in
782 * lpSrch [I] String to look for
783 * cchMax [I] Maximum number of initial search characters
785 * RETURNS
786 * The start of lpFirst within lpSrch, or NULL if not found.
788 LPWSTR WINAPI StrStrNIW(LPCWSTR lpFirst, LPCWSTR lpSrch, UINT cchMax)
790 UINT i;
791 int len;
793 TRACE("(%s, %s, %u)\n", debugstr_w(lpFirst), debugstr_w(lpSrch), cchMax);
795 if (!lpFirst || !lpSrch || !*lpSrch || !cchMax)
796 return NULL;
798 len = strlenW(lpSrch);
800 for (i = cchMax; *lpFirst && (i > 0); i--, lpFirst++)
802 if (!strncmpiW(lpFirst, lpSrch, len))
803 return (LPWSTR)lpFirst;
806 return NULL;
809 /*************************************************************************
810 * StrToIntA [SHLWAPI.@]
812 * Read a signed integer from a string.
814 * PARAMS
815 * lpszStr [I] String to read integer from
817 * RETURNS
818 * The signed integer value represented by the string, or 0 if no integer is
819 * present.
821 * NOTES
822 * No leading space is allowed before the number, although a leading '-' is.
824 int WINAPI StrToIntA(LPCSTR lpszStr)
826 int iRet = 0;
828 TRACE("(%s)\n", debugstr_a(lpszStr));
830 if (!lpszStr)
832 WARN("Invalid lpszStr would crash under Win32!\n");
833 return 0;
836 if (*lpszStr == '-' || isdigit(*lpszStr))
837 StrToIntExA(lpszStr, 0, &iRet);
838 return iRet;
841 /*************************************************************************
842 * StrToIntW [SHLWAPI.@]
844 * See StrToIntA.
846 int WINAPI StrToIntW(LPCWSTR lpszStr)
848 int iRet = 0;
850 TRACE("(%s)\n", debugstr_w(lpszStr));
852 if (!lpszStr)
854 WARN("Invalid lpszStr would crash under Win32!\n");
855 return 0;
858 if (*lpszStr == '-' || isdigitW(*lpszStr))
859 StrToIntExW(lpszStr, 0, &iRet);
860 return iRet;
863 /*************************************************************************
864 * StrToIntExA [SHLWAPI.@]
866 * Read an integer from a string.
868 * PARAMS
869 * lpszStr [I] String to read integer from
870 * dwFlags [I] Flags controlling the conversion
871 * lpiRet [O] Destination for read integer.
873 * RETURNS
874 * Success: TRUE. lpiRet contains the integer value represented by the string.
875 * Failure: FALSE, if the string is invalid, or no number is present.
877 * NOTES
878 * Leading whitespace, '-' and '+' are allowed before the number. If
879 * dwFlags includes STIF_SUPPORT_HEX, hexadecimal numbers are allowed, if
880 * preceded by '0x'. If this flag is not set, or there is no '0x' prefix,
881 * the string is treated as a decimal string. A leading '-' is ignored for
882 * hexadecimal numbers.
884 BOOL WINAPI StrToIntExA(LPCSTR lpszStr, DWORD dwFlags, LPINT lpiRet)
886 LONGLONG li;
887 BOOL bRes;
889 TRACE("(%s,%08X,%p)\n", debugstr_a(lpszStr), dwFlags, lpiRet);
891 bRes = StrToInt64ExA(lpszStr, dwFlags, &li);
892 if (bRes) *lpiRet = li;
893 return bRes;
896 /*************************************************************************
897 * StrToInt64ExA [SHLWAPI.@]
899 * See StrToIntExA.
901 BOOL WINAPI StrToInt64ExA(LPCSTR lpszStr, DWORD dwFlags, LONGLONG *lpiRet)
903 BOOL bNegative = FALSE;
904 LONGLONG iRet = 0;
906 TRACE("(%s,%08X,%p)\n", debugstr_a(lpszStr), dwFlags, lpiRet);
908 if (!lpszStr || !lpiRet)
910 WARN("Invalid parameter would crash under Win32!\n");
911 return FALSE;
913 if (dwFlags > STIF_SUPPORT_HEX) WARN("Unknown flags %08x\n", dwFlags);
915 /* Skip leading space, '+', '-' */
916 while (isspace(*lpszStr))
917 lpszStr = CharNextA(lpszStr);
919 if (*lpszStr == '-')
921 bNegative = TRUE;
922 lpszStr++;
924 else if (*lpszStr == '+')
925 lpszStr++;
927 if (dwFlags & STIF_SUPPORT_HEX &&
928 *lpszStr == '0' && tolower(lpszStr[1]) == 'x')
930 /* Read hex number */
931 lpszStr += 2;
933 if (!isxdigit(*lpszStr))
934 return FALSE;
936 while (isxdigit(*lpszStr))
938 iRet = iRet * 16;
939 if (isdigit(*lpszStr))
940 iRet += (*lpszStr - '0');
941 else
942 iRet += 10 + (tolower(*lpszStr) - 'a');
943 lpszStr++;
945 *lpiRet = iRet;
946 return TRUE;
949 /* Read decimal number */
950 if (!isdigit(*lpszStr))
951 return FALSE;
953 while (isdigit(*lpszStr))
955 iRet = iRet * 10;
956 iRet += (*lpszStr - '0');
957 lpszStr++;
959 *lpiRet = bNegative ? -iRet : iRet;
960 return TRUE;
963 /*************************************************************************
964 * StrToIntExW [SHLWAPI.@]
966 * See StrToIntExA.
968 BOOL WINAPI StrToIntExW(LPCWSTR lpszStr, DWORD dwFlags, LPINT lpiRet)
970 LONGLONG li;
971 BOOL bRes;
973 TRACE("(%s,%08X,%p)\n", debugstr_w(lpszStr), dwFlags, lpiRet);
975 bRes = StrToInt64ExW(lpszStr, dwFlags, &li);
976 if (bRes) *lpiRet = li;
977 return bRes;
980 /*************************************************************************
981 * StrToInt64ExW [SHLWAPI.@]
983 * See StrToIntExA.
985 BOOL WINAPI StrToInt64ExW(LPCWSTR lpszStr, DWORD dwFlags, LONGLONG *lpiRet)
987 BOOL bNegative = FALSE;
988 LONGLONG iRet = 0;
990 TRACE("(%s,%08X,%p)\n", debugstr_w(lpszStr), dwFlags, lpiRet);
992 if (!lpszStr || !lpiRet)
994 WARN("Invalid parameter would crash under Win32!\n");
995 return FALSE;
997 if (dwFlags > STIF_SUPPORT_HEX) WARN("Unknown flags %08x\n", dwFlags);
999 /* Skip leading space, '+', '-' */
1000 while (isspaceW(*lpszStr)) lpszStr++;
1002 if (*lpszStr == '-')
1004 bNegative = TRUE;
1005 lpszStr++;
1007 else if (*lpszStr == '+')
1008 lpszStr++;
1010 if (dwFlags & STIF_SUPPORT_HEX &&
1011 *lpszStr == '0' && tolowerW(lpszStr[1]) == 'x')
1013 /* Read hex number */
1014 lpszStr += 2;
1016 if (!isxdigitW(*lpszStr))
1017 return FALSE;
1019 while (isxdigitW(*lpszStr))
1021 iRet = iRet * 16;
1022 if (isdigitW(*lpszStr))
1023 iRet += (*lpszStr - '0');
1024 else
1025 iRet += 10 + (tolowerW(*lpszStr) - 'a');
1026 lpszStr++;
1028 *lpiRet = iRet;
1029 return TRUE;
1032 /* Read decimal number */
1033 if (!isdigitW(*lpszStr))
1034 return FALSE;
1036 while (isdigitW(*lpszStr))
1038 iRet = iRet * 10;
1039 iRet += (*lpszStr - '0');
1040 lpszStr++;
1042 *lpiRet = bNegative ? -iRet : iRet;
1043 return TRUE;
1046 /*************************************************************************
1047 * StrDupA [SHLWAPI.@]
1049 * Duplicate a string.
1051 * PARAMS
1052 * lpszStr [I] String to duplicate.
1054 * RETURNS
1055 * Success: A pointer to a new string containing the contents of lpszStr
1056 * Failure: NULL, if memory cannot be allocated
1058 * NOTES
1059 * The string memory is allocated with LocalAlloc(), and so should be released
1060 * by calling LocalFree().
1062 LPSTR WINAPI StrDupA(LPCSTR lpszStr)
1064 int iLen;
1065 LPSTR lpszRet;
1067 TRACE("(%s)\n",debugstr_a(lpszStr));
1069 iLen = lpszStr ? strlen(lpszStr) + 1 : 1;
1070 lpszRet = LocalAlloc(LMEM_FIXED, iLen);
1072 if (lpszRet)
1074 if (lpszStr)
1075 memcpy(lpszRet, lpszStr, iLen);
1076 else
1077 *lpszRet = '\0';
1079 return lpszRet;
1082 /*************************************************************************
1083 * StrDupW [SHLWAPI.@]
1085 * See StrDupA.
1087 LPWSTR WINAPI StrDupW(LPCWSTR lpszStr)
1089 int iLen;
1090 LPWSTR lpszRet;
1092 TRACE("(%s)\n",debugstr_w(lpszStr));
1094 iLen = (lpszStr ? strlenW(lpszStr) + 1 : 1) * sizeof(WCHAR);
1095 lpszRet = LocalAlloc(LMEM_FIXED, iLen);
1097 if (lpszRet)
1099 if (lpszStr)
1100 memcpy(lpszRet, lpszStr, iLen);
1101 else
1102 *lpszRet = '\0';
1104 return lpszRet;
1107 /*************************************************************************
1108 * SHLWAPI_StrSpnHelperA
1110 * Internal implementation of StrSpnA/StrCSpnA/StrCSpnIA
1112 static int SHLWAPI_StrSpnHelperA(LPCSTR lpszStr, LPCSTR lpszMatch,
1113 LPSTR (WINAPI *pStrChrFn)(LPCSTR,WORD),
1114 BOOL bInvert)
1116 LPCSTR lpszRead = lpszStr;
1117 if (lpszStr && *lpszStr && lpszMatch)
1119 while (*lpszRead)
1121 LPCSTR lpszTest = pStrChrFn(lpszMatch, *lpszRead);
1123 if (!bInvert && !lpszTest)
1124 break;
1125 if (bInvert && lpszTest)
1126 break;
1127 lpszRead = CharNextA(lpszRead);
1130 return lpszRead - lpszStr;
1133 /*************************************************************************
1134 * StrSpnA [SHLWAPI.@]
1136 * Find the length of the start of a string that contains only certain
1137 * characters.
1139 * PARAMS
1140 * lpszStr [I] String to search
1141 * lpszMatch [I] Characters that can be in the substring
1143 * RETURNS
1144 * The length of the part of lpszStr containing only chars from lpszMatch,
1145 * or 0 if any parameter is invalid.
1147 int WINAPI StrSpnA(LPCSTR lpszStr, LPCSTR lpszMatch)
1149 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1151 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, FALSE);
1154 /*************************************************************************
1155 * StrSpnW [SHLWAPI.@]
1157 * See StrSpnA.
1159 int WINAPI StrSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1161 if (!lpszStr || !lpszMatch) return 0;
1162 return strspnW( lpszStr, lpszMatch );
1165 /*************************************************************************
1166 * StrCSpnA [SHLWAPI.@]
1168 * Find the length of the start of a string that does not contain certain
1169 * characters.
1171 * PARAMS
1172 * lpszStr [I] String to search
1173 * lpszMatch [I] Characters that cannot be in the substring
1175 * RETURNS
1176 * The length of the part of lpszStr containing only chars not in lpszMatch,
1177 * or 0 if any parameter is invalid.
1179 int WINAPI StrCSpnA(LPCSTR lpszStr, LPCSTR lpszMatch)
1181 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1183 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, TRUE);
1186 /*************************************************************************
1187 * StrCSpnW [SHLWAPI.@]
1189 * See StrCSpnA.
1191 int WINAPI StrCSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1193 if (!lpszStr || !lpszMatch) return 0;
1194 return strcspnW( lpszStr, lpszMatch );
1197 /*************************************************************************
1198 * StrCSpnIA [SHLWAPI.@]
1200 * Find the length of the start of a string that does not contain certain
1201 * characters, ignoring case.
1203 * PARAMS
1204 * lpszStr [I] String to search
1205 * lpszMatch [I] Characters that cannot be in the substring
1207 * RETURNS
1208 * The length of the part of lpszStr containing only chars not in lpszMatch,
1209 * or 0 if any parameter is invalid.
1211 int WINAPI StrCSpnIA(LPCSTR lpszStr, LPCSTR lpszMatch)
1213 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1215 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrIA, TRUE);
1218 /*************************************************************************
1219 * StrCSpnIW [SHLWAPI.@]
1221 * See StrCSpnIA.
1223 int WINAPI StrCSpnIW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1225 LPCWSTR lpszRead = lpszStr;
1227 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1229 if (lpszStr && *lpszStr && lpszMatch)
1231 while (*lpszRead)
1233 if (StrChrIW(lpszMatch, *lpszRead)) break;
1234 lpszRead++;
1237 return lpszRead - lpszStr;
1240 /*************************************************************************
1241 * StrPBrkA [SHLWAPI.@]
1243 * Search a string for any of a group of characters.
1245 * PARAMS
1246 * lpszStr [I] String to search
1247 * lpszMatch [I] Characters to match
1249 * RETURNS
1250 * A pointer to the first matching character in lpszStr, or NULL if no
1251 * match was found.
1253 LPSTR WINAPI StrPBrkA(LPCSTR lpszStr, LPCSTR lpszMatch)
1255 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1257 if (lpszStr && lpszMatch && *lpszMatch)
1259 while (*lpszStr)
1261 if (StrChrA(lpszMatch, *lpszStr))
1262 return (LPSTR)lpszStr;
1263 lpszStr = CharNextA(lpszStr);
1266 return NULL;
1269 /*************************************************************************
1270 * StrPBrkW [SHLWAPI.@]
1272 * See StrPBrkA.
1274 LPWSTR WINAPI StrPBrkW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1276 if (!lpszStr || !lpszMatch) return NULL;
1277 return strpbrkW( lpszStr, lpszMatch );
1280 /*************************************************************************
1281 * SHLWAPI_StrRChrHelperA
1283 * Internal implementation of StrRChrA/StrRChrIA.
1285 static LPSTR SHLWAPI_StrRChrHelperA(LPCSTR lpszStr,
1286 LPCSTR lpszEnd, WORD ch,
1287 BOOL (WINAPI *pChrCmpFn)(WORD,WORD))
1289 LPCSTR lpszRet = NULL;
1291 if (lpszStr)
1293 WORD ch2;
1295 if (!lpszEnd)
1296 lpszEnd = lpszStr + lstrlenA(lpszStr);
1298 while (*lpszStr && lpszStr <= lpszEnd)
1300 ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr;
1302 if (!pChrCmpFn(ch, ch2))
1303 lpszRet = lpszStr;
1304 lpszStr = CharNextA(lpszStr);
1307 return (LPSTR)lpszRet;
1310 /**************************************************************************
1311 * StrRChrA [SHLWAPI.@]
1313 * Find the last occurrence of a character in string.
1315 * PARAMS
1316 * lpszStr [I] String to search in
1317 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1318 * ch [I] Character to search for.
1320 * RETURNS
1321 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1322 * or NULL if not found.
1323 * Failure: NULL, if any arguments are invalid.
1325 LPSTR WINAPI StrRChrA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch)
1327 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch);
1329 return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, SHLWAPI_ChrCmpA);
1332 /**************************************************************************
1333 * StrRChrW [SHLWAPI.@]
1335 * See StrRChrA.
1337 LPWSTR WINAPI StrRChrW(LPCWSTR str, LPCWSTR end, WORD ch)
1339 WCHAR *ret = NULL;
1341 if (!str) return NULL;
1342 if (!end) end = str + strlenW(str);
1343 while (str < end)
1345 if (*str == ch) ret = (WCHAR *)str;
1346 str++;
1348 return ret;
1351 /**************************************************************************
1352 * StrRChrIA [SHLWAPI.@]
1354 * Find the last occurrence of a character in string, ignoring case.
1356 * PARAMS
1357 * lpszStr [I] String to search in
1358 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1359 * ch [I] Character to search for.
1361 * RETURNS
1362 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1363 * or NULL if not found.
1364 * Failure: NULL, if any arguments are invalid.
1366 LPSTR WINAPI StrRChrIA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch)
1368 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch);
1370 return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, ChrCmpIA);
1373 /**************************************************************************
1374 * StrRChrIW [SHLWAPI.@]
1376 * See StrRChrIA.
1378 LPWSTR WINAPI StrRChrIW(LPCWSTR str, LPCWSTR end, WORD ch)
1380 WCHAR *ret = NULL;
1382 if (!str) return NULL;
1383 if (!end) end = str + strlenW(str);
1384 while (str < end)
1386 if (!ChrCmpIW(*str, ch)) ret = (WCHAR *)str;
1387 str++;
1389 return ret;
1392 /*************************************************************************
1393 * StrCatBuffA [SHLWAPI.@]
1395 * Concatenate two strings together.
1397 * PARAMS
1398 * lpszStr [O] String to concatenate to
1399 * lpszCat [I] String to add to lpszCat
1400 * cchMax [I] Maximum number of characters for the whole string
1402 * RETURNS
1403 * lpszStr.
1405 * NOTES
1406 * cchMax determines the number of characters in the final length of the
1407 * string, not the number appended to lpszStr from lpszCat.
1409 LPSTR WINAPI StrCatBuffA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax)
1411 INT iLen;
1413 TRACE("(%p,%s,%d)\n", lpszStr, debugstr_a(lpszCat), cchMax);
1415 if (!lpszStr)
1417 WARN("Invalid lpszStr would crash under Win32!\n");
1418 return NULL;
1421 iLen = strlen(lpszStr);
1422 cchMax -= iLen;
1424 if (cchMax > 0)
1425 StrCpyNA(lpszStr + iLen, lpszCat, cchMax);
1426 return lpszStr;
1429 /*************************************************************************
1430 * StrCatBuffW [SHLWAPI.@]
1432 * See StrCatBuffA.
1434 LPWSTR WINAPI StrCatBuffW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax)
1436 INT iLen;
1438 TRACE("(%p,%s,%d)\n", lpszStr, debugstr_w(lpszCat), cchMax);
1440 if (!lpszStr)
1442 WARN("Invalid lpszStr would crash under Win32!\n");
1443 return NULL;
1446 iLen = strlenW(lpszStr);
1447 cchMax -= iLen;
1449 if (cchMax > 0)
1450 StrCpyNW(lpszStr + iLen, lpszCat, cchMax);
1451 return lpszStr;
1454 /*************************************************************************
1455 * StrRetToBufA [SHLWAPI.@]
1457 * Convert a STRRET to a normal string.
1459 * PARAMS
1460 * lpStrRet [O] STRRET to convert
1461 * pIdl [I] ITEMIDLIST for lpStrRet->uType == STRRET_OFFSET
1462 * lpszDest [O] Destination for normal string
1463 * dwLen [I] Length of lpszDest
1465 * RETURNS
1466 * Success: S_OK. lpszDest contains up to dwLen characters of the string.
1467 * If lpStrRet is of type STRRET_WSTR, its memory is freed with
1468 * CoTaskMemFree() and its type set to STRRET_CSTRA.
1469 * Failure: E_FAIL, if any parameters are invalid.
1471 HRESULT WINAPI StrRetToBufA (LPSTRRET src, const ITEMIDLIST *pidl, LPSTR dest, UINT len)
1473 /* NOTE:
1474 * This routine is identical to that in dlls/shell32/shellstring.c.
1475 * It was duplicated because not every version of Shlwapi.dll exports
1476 * StrRetToBufA. If you change one routine, change them both.
1478 TRACE("dest=%p len=0x%x strret=%p pidl=%p\n", dest, len, src, pidl);
1480 if (!src)
1482 WARN("Invalid lpStrRet would crash under Win32!\n");
1483 if (dest)
1484 *dest = '\0';
1485 return E_FAIL;
1488 if (!dest || !len)
1489 return E_FAIL;
1491 *dest = '\0';
1493 switch (src->uType)
1495 case STRRET_WSTR:
1496 WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, dest, len, NULL, NULL);
1497 CoTaskMemFree(src->u.pOleStr);
1498 break;
1500 case STRRET_CSTR:
1501 lstrcpynA(dest, src->u.cStr, len);
1502 break;
1504 case STRRET_OFFSET:
1505 lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len);
1506 break;
1508 default:
1509 FIXME("unknown type!\n");
1510 return E_NOTIMPL;
1512 return S_OK;
1515 /*************************************************************************
1516 * StrRetToBufW [SHLWAPI.@]
1518 * See StrRetToBufA.
1520 HRESULT WINAPI StrRetToBufW (LPSTRRET src, const ITEMIDLIST *pidl, LPWSTR dest, UINT len)
1522 TRACE("dest=%p len=0x%x strret=%p pidl=%p\n", dest, len, src, pidl);
1524 if (!dest || !len)
1525 return E_FAIL;
1527 if (!src)
1529 WARN("Invalid lpStrRet would crash under Win32!\n");
1530 if (dest)
1531 *dest = '\0';
1532 return E_FAIL;
1535 *dest = '\0';
1537 switch (src->uType) {
1538 case STRRET_WSTR: {
1539 size_t dst_len;
1540 if (!src->u.pOleStr)
1541 return E_FAIL;
1542 dst_len = strlenW(src->u.pOleStr);
1543 memcpy(dest, src->u.pOleStr, min(dst_len, len-1) * sizeof(WCHAR));
1544 dest[min(dst_len, len-1)] = 0;
1545 CoTaskMemFree(src->u.pOleStr);
1546 if (len <= dst_len)
1548 dest[0] = 0;
1549 return E_NOT_SUFFICIENT_BUFFER;
1551 break;
1554 case STRRET_CSTR:
1555 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ))
1556 dest[len-1] = 0;
1557 break;
1559 case STRRET_OFFSET:
1560 if (pidl)
1562 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1,
1563 dest, len ))
1564 dest[len-1] = 0;
1566 break;
1568 default:
1569 FIXME("unknown type!\n");
1570 return E_NOTIMPL;
1573 return S_OK;
1576 /*************************************************************************
1577 * StrRetToStrA [SHLWAPI.@]
1579 * Converts a STRRET to a normal string.
1581 * PARAMS
1582 * lpStrRet [O] STRRET to convert
1583 * pidl [I] ITEMIDLIST for lpStrRet->uType == STRRET_OFFSET
1584 * ppszName [O] Destination for converted string
1586 * RETURNS
1587 * Success: S_OK. ppszName contains the new string, allocated with CoTaskMemAlloc().
1588 * Failure: E_FAIL, if any parameters are invalid.
1590 HRESULT WINAPI StrRetToStrA(LPSTRRET lpStrRet, const ITEMIDLIST *pidl, LPSTR *ppszName)
1592 HRESULT hRet = E_FAIL;
1594 switch (lpStrRet->uType)
1596 case STRRET_WSTR:
1597 hRet = _SHStrDupAW(lpStrRet->u.pOleStr, ppszName);
1598 CoTaskMemFree(lpStrRet->u.pOleStr);
1599 break;
1601 case STRRET_CSTR:
1602 hRet = _SHStrDupAA(lpStrRet->u.cStr, ppszName);
1603 break;
1605 case STRRET_OFFSET:
1606 hRet = _SHStrDupAA(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, ppszName);
1607 break;
1609 default:
1610 *ppszName = NULL;
1613 return hRet;
1616 /*************************************************************************
1617 * StrRetToStrW [SHLWAPI.@]
1619 * See StrRetToStrA.
1621 HRESULT WINAPI StrRetToStrW(LPSTRRET lpStrRet, const ITEMIDLIST *pidl, LPWSTR *ppszName)
1623 HRESULT hRet = E_FAIL;
1625 switch (lpStrRet->uType)
1627 case STRRET_WSTR:
1628 hRet = SHStrDupW(lpStrRet->u.pOleStr, ppszName);
1629 CoTaskMemFree(lpStrRet->u.pOleStr);
1630 break;
1632 case STRRET_CSTR:
1633 hRet = SHStrDupA(lpStrRet->u.cStr, ppszName);
1634 break;
1636 case STRRET_OFFSET:
1637 hRet = SHStrDupA(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, ppszName);
1638 break;
1640 default:
1641 *ppszName = NULL;
1644 return hRet;
1647 /* Create an ASCII string copy using SysAllocString() */
1648 static HRESULT _SHStrDupAToBSTR(LPCSTR src, BSTR *pBstrOut)
1650 *pBstrOut = NULL;
1652 if (src)
1654 INT len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0);
1655 WCHAR* szTemp = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1657 if (szTemp)
1659 MultiByteToWideChar(CP_ACP, 0, src, -1, szTemp, len);
1660 *pBstrOut = SysAllocString(szTemp);
1661 HeapFree(GetProcessHeap(), 0, szTemp);
1663 if (*pBstrOut)
1664 return S_OK;
1667 return E_OUTOFMEMORY;
1670 /*************************************************************************
1671 * StrRetToBSTR [SHLWAPI.@]
1673 * Converts a STRRET to a BSTR.
1675 * PARAMS
1676 * lpStrRet [O] STRRET to convert
1677 * pidl [I] ITEMIDLIST for lpStrRet->uType = STRRET_OFFSET
1678 * pBstrOut [O] Destination for converted BSTR
1680 * RETURNS
1681 * Success: S_OK. pBstrOut contains the new string.
1682 * Failure: E_FAIL, if any parameters are invalid.
1684 HRESULT WINAPI StrRetToBSTR(STRRET *lpStrRet, LPCITEMIDLIST pidl, BSTR* pBstrOut)
1686 HRESULT hRet = E_FAIL;
1688 switch (lpStrRet->uType)
1690 case STRRET_WSTR:
1691 *pBstrOut = SysAllocString(lpStrRet->u.pOleStr);
1692 if (*pBstrOut)
1693 hRet = S_OK;
1694 CoTaskMemFree(lpStrRet->u.pOleStr);
1695 break;
1697 case STRRET_CSTR:
1698 hRet = _SHStrDupAToBSTR(lpStrRet->u.cStr, pBstrOut);
1699 break;
1701 case STRRET_OFFSET:
1702 hRet = _SHStrDupAToBSTR(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, pBstrOut);
1703 break;
1705 default:
1706 *pBstrOut = NULL;
1709 return hRet;
1712 /*************************************************************************
1713 * StrFormatKBSizeA [SHLWAPI.@]
1715 * Create a formatted string containing a byte count in Kilobytes.
1717 * PARAMS
1718 * llBytes [I] Byte size to format
1719 * lpszDest [I] Destination for formatted string
1720 * cchMax [I] Size of lpszDest
1722 * RETURNS
1723 * lpszDest.
1725 LPSTR WINAPI StrFormatKBSizeA(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax)
1727 WCHAR wszBuf[256];
1729 if (!StrFormatKBSizeW(llBytes, wszBuf, 256))
1730 return NULL;
1731 if (!WideCharToMultiByte(CP_ACP, 0, wszBuf, -1, lpszDest, cchMax, NULL, NULL))
1732 return NULL;
1733 return lpszDest;
1736 /*************************************************************************
1737 * StrFormatKBSizeW [SHLWAPI.@]
1739 * See StrFormatKBSizeA.
1741 LPWSTR WINAPI StrFormatKBSizeW(LONGLONG llBytes, LPWSTR lpszDest, UINT cchMax)
1743 static const WCHAR kb[] = {' ','K','B',0};
1744 LONGLONG llKB = (llBytes + 1023) >> 10;
1745 int len;
1747 TRACE("(0x%s,%p,%d)\n", wine_dbgstr_longlong(llBytes), lpszDest, cchMax);
1749 if (!FormatInt(llKB, lpszDest, cchMax))
1750 return NULL;
1752 len = lstrlenW(lpszDest);
1753 if (cchMax - len < 4)
1754 return NULL;
1755 lstrcatW(lpszDest, kb);
1756 return lpszDest;
1759 /*************************************************************************
1760 * StrNCatA [SHLWAPI.@]
1762 * Concatenate two strings together.
1764 * PARAMS
1765 * lpszStr [O] String to concatenate to
1766 * lpszCat [I] String to add to lpszCat
1767 * cchMax [I] Maximum number of characters to concatenate
1769 * RETURNS
1770 * lpszStr.
1772 * NOTES
1773 * cchMax determines the number of characters that are appended to lpszStr,
1774 * not the total length of the string.
1776 LPSTR WINAPI StrNCatA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax)
1778 LPSTR lpszRet = lpszStr;
1780 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszCat), cchMax);
1782 if (!lpszStr)
1784 WARN("Invalid lpszStr would crash under Win32!\n");
1785 return NULL;
1788 StrCpyNA(lpszStr + strlen(lpszStr), lpszCat, cchMax);
1789 return lpszRet;
1792 /*************************************************************************
1793 * StrNCatW [SHLWAPI.@]
1795 * See StrNCatA.
1797 LPWSTR WINAPI StrNCatW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax)
1799 LPWSTR lpszRet = lpszStr;
1801 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszCat), cchMax);
1803 if (!lpszStr)
1805 WARN("Invalid lpszStr would crash under Win32\n");
1806 return NULL;
1809 StrCpyNW(lpszStr + strlenW(lpszStr), lpszCat, cchMax);
1810 return lpszRet;
1813 /*************************************************************************
1814 * StrTrimA [SHLWAPI.@]
1816 * Remove characters from the start and end of a string.
1818 * PARAMS
1819 * lpszStr [O] String to remove characters from
1820 * lpszTrim [I] Characters to remove from lpszStr
1822 * RETURNS
1823 * TRUE If lpszStr was valid and modified
1824 * FALSE Otherwise
1826 BOOL WINAPI StrTrimA(LPSTR lpszStr, LPCSTR lpszTrim)
1828 DWORD dwLen;
1829 LPSTR lpszRead = lpszStr;
1830 BOOL bRet = FALSE;
1832 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszTrim));
1834 if (lpszRead && *lpszRead)
1836 while (*lpszRead && StrChrA(lpszTrim, *lpszRead))
1837 lpszRead = CharNextA(lpszRead); /* Skip leading matches */
1839 dwLen = strlen(lpszRead);
1841 if (lpszRead != lpszStr)
1843 memmove(lpszStr, lpszRead, dwLen + 1);
1844 bRet = TRUE;
1846 if (dwLen > 0)
1848 lpszRead = lpszStr + dwLen;
1849 while (StrChrA(lpszTrim, lpszRead[-1]))
1850 lpszRead = CharPrevA(lpszStr, lpszRead); /* Skip trailing matches */
1852 if (lpszRead != lpszStr + dwLen)
1854 *lpszRead = '\0';
1855 bRet = TRUE;
1859 return bRet;
1862 /*************************************************************************
1863 * StrTrimW [SHLWAPI.@]
1865 * See StrTrimA.
1867 BOOL WINAPI StrTrimW(LPWSTR lpszStr, LPCWSTR lpszTrim)
1869 DWORD dwLen;
1870 LPWSTR lpszRead = lpszStr;
1871 BOOL bRet = FALSE;
1873 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszTrim));
1875 if (lpszRead && *lpszRead)
1877 while (*lpszRead && StrChrW(lpszTrim, *lpszRead)) lpszRead++;
1879 dwLen = strlenW(lpszRead);
1881 if (lpszRead != lpszStr)
1883 memmove(lpszStr, lpszRead, (dwLen + 1) * sizeof(WCHAR));
1884 bRet = TRUE;
1886 if (dwLen > 0)
1888 lpszRead = lpszStr + dwLen;
1889 while (StrChrW(lpszTrim, lpszRead[-1]))
1890 lpszRead--; /* Skip trailing matches */
1892 if (lpszRead != lpszStr + dwLen)
1894 *lpszRead = '\0';
1895 bRet = TRUE;
1899 return bRet;
1902 /*************************************************************************
1903 * _SHStrDupAA [INTERNAL]
1905 * Duplicates a ASCII string to ASCII. The destination buffer is allocated.
1907 static HRESULT _SHStrDupAA(LPCSTR src, LPSTR * dest)
1909 HRESULT hr;
1910 int len = 0;
1912 if (src) {
1913 len = lstrlenA(src) + 1;
1914 *dest = CoTaskMemAlloc(len);
1915 } else {
1916 *dest = NULL;
1919 if (*dest) {
1920 lstrcpynA(*dest,src, len);
1921 hr = S_OK;
1922 } else {
1923 hr = E_OUTOFMEMORY;
1926 TRACE("%s->(%p)\n", debugstr_a(src), *dest);
1927 return hr;
1930 /*************************************************************************
1931 * SHStrDupA [SHLWAPI.@]
1933 * Return a Unicode copy of a string, in memory allocated by CoTaskMemAlloc().
1935 * PARAMS
1936 * lpszStr [I] String to copy
1937 * lppszDest [O] Destination for the new string copy
1939 * RETURNS
1940 * Success: S_OK. lppszDest contains the new string in Unicode format.
1941 * Failure: E_OUTOFMEMORY, If any arguments are invalid or memory allocation
1942 * fails.
1944 HRESULT WINAPI SHStrDupA(LPCSTR lpszStr, LPWSTR * lppszDest)
1946 HRESULT hRet;
1947 int len = 0;
1949 if (lpszStr)
1951 len = MultiByteToWideChar(CP_ACP, 0, lpszStr, -1, NULL, 0) * sizeof(WCHAR);
1952 *lppszDest = CoTaskMemAlloc(len);
1954 else
1955 *lppszDest = NULL;
1957 if (*lppszDest)
1959 MultiByteToWideChar(CP_ACP, 0, lpszStr, -1, *lppszDest, len/sizeof(WCHAR));
1960 hRet = S_OK;
1962 else
1963 hRet = E_OUTOFMEMORY;
1965 TRACE("%s->(%p)\n", debugstr_a(lpszStr), *lppszDest);
1966 return hRet;
1969 /*************************************************************************
1970 * _SHStrDupAW [INTERNAL]
1972 * Duplicates a UNICODE to a ASCII string. The destination buffer is allocated.
1974 static HRESULT _SHStrDupAW(LPCWSTR src, LPSTR * dest)
1976 HRESULT hr;
1977 int len = 0;
1979 if (src) {
1980 len = WideCharToMultiByte(CP_ACP, 0, src, -1, NULL, 0, NULL, NULL);
1981 *dest = CoTaskMemAlloc(len);
1982 } else {
1983 *dest = NULL;
1986 if (*dest) {
1987 WideCharToMultiByte(CP_ACP, 0, src, -1, *dest, len, NULL, NULL);
1988 hr = S_OK;
1989 } else {
1990 hr = E_OUTOFMEMORY;
1993 TRACE("%s->(%p)\n", debugstr_w(src), *dest);
1994 return hr;
1997 /*************************************************************************
1998 * SHStrDupW [SHLWAPI.@]
2000 * See SHStrDupA.
2002 HRESULT WINAPI SHStrDupW(LPCWSTR src, LPWSTR * dest)
2004 HRESULT hr;
2005 int len = 0;
2007 if (src) {
2008 len = (lstrlenW(src) + 1) * sizeof(WCHAR);
2009 *dest = CoTaskMemAlloc(len);
2010 } else {
2011 *dest = NULL;
2014 if (*dest) {
2015 memcpy(*dest, src, len);
2016 hr = S_OK;
2017 } else {
2018 hr = E_OUTOFMEMORY;
2021 TRACE("%s->(%p)\n", debugstr_w(src), *dest);
2022 return hr;
2025 /*************************************************************************
2026 * SHLWAPI_WriteReverseNum
2028 * Internal helper for SHLWAPI_WriteTimeClass.
2030 static inline LPWSTR SHLWAPI_WriteReverseNum(LPWSTR lpszOut, DWORD dwNum)
2032 *lpszOut-- = '\0';
2034 /* Write a decimal number to a string, backwards */
2037 DWORD dwNextDigit = dwNum % 10;
2038 *lpszOut-- = '0' + dwNextDigit;
2039 dwNum = (dwNum - dwNextDigit) / 10;
2040 } while (dwNum > 0);
2042 return lpszOut;
2045 /*************************************************************************
2046 * SHLWAPI_FormatSignificant
2048 * Internal helper for SHLWAPI_WriteTimeClass.
2050 static inline int SHLWAPI_FormatSignificant(LPWSTR lpszNum, int dwDigits)
2052 /* Zero non significant digits, return remaining significant digits */
2053 while (*lpszNum)
2055 lpszNum++;
2056 if (--dwDigits == 0)
2058 while (*lpszNum)
2059 *lpszNum++ = '0';
2060 return 0;
2063 return dwDigits;
2066 /*************************************************************************
2067 * SHLWAPI_WriteTimeClass
2069 * Internal helper for StrFromTimeIntervalW.
2071 static int SHLWAPI_WriteTimeClass(LPWSTR lpszOut, DWORD dwValue,
2072 UINT uClassStringId, int iDigits)
2074 WCHAR szBuff[64], *szOut = szBuff + 32;
2076 szOut = SHLWAPI_WriteReverseNum(szOut, dwValue);
2077 iDigits = SHLWAPI_FormatSignificant(szOut + 1, iDigits);
2078 *szOut = ' ';
2079 LoadStringW(shlwapi_hInstance, uClassStringId, szBuff + 32, 32);
2080 strcatW(lpszOut, szOut);
2081 return iDigits;
2084 /*************************************************************************
2085 * StrFromTimeIntervalA [SHLWAPI.@]
2087 * Format a millisecond time interval into a string
2089 * PARAMS
2090 * lpszStr [O] Output buffer for formatted time interval
2091 * cchMax [I] Size of lpszStr
2092 * dwMS [I] Number of milliseconds
2093 * iDigits [I] Number of digits to print
2095 * RETURNS
2096 * The length of the formatted string, or 0 if any parameter is invalid.
2098 * NOTES
2099 * This implementation mimics the Win32 behaviour of always writing a leading
2100 * space before the time interval begins.
2102 * iDigits is used to provide approximate times if accuracy is not important.
2103 * This number of digits will be written of the first non-zero time class
2104 * (hours/minutes/seconds). If this does not complete the time classification,
2105 * the remaining digits are changed to zeros (i.e. The time is _not_ rounded).
2106 * If there are digits remaining following the writing of a time class, the
2107 * next time class will be written.
2109 * For example, given dwMS represents 138 hours,43 minutes and 15 seconds, the
2110 * following will result from the given values of iDigits:
2112 *| iDigits 1 2 3 4 5 ...
2113 *| lpszStr "100 hr" "130 hr" "138 hr" "138 hr 40 min" "138 hr 43 min" ...
2115 INT WINAPI StrFromTimeIntervalA(LPSTR lpszStr, UINT cchMax, DWORD dwMS,
2116 int iDigits)
2118 INT iRet = 0;
2120 TRACE("(%p,%d,%d,%d)\n", lpszStr, cchMax, dwMS, iDigits);
2122 if (lpszStr && cchMax)
2124 WCHAR szBuff[128];
2125 StrFromTimeIntervalW(szBuff, ARRAY_SIZE(szBuff), dwMS, iDigits);
2126 WideCharToMultiByte(CP_ACP,0,szBuff,-1,lpszStr,cchMax,0,0);
2128 return iRet;
2132 /*************************************************************************
2133 * StrFromTimeIntervalW [SHLWAPI.@]
2135 * See StrFromTimeIntervalA.
2137 INT WINAPI StrFromTimeIntervalW(LPWSTR lpszStr, UINT cchMax, DWORD dwMS,
2138 int iDigits)
2140 INT iRet = 0;
2142 TRACE("(%p,%d,%d,%d)\n", lpszStr, cchMax, dwMS, iDigits);
2144 if (lpszStr && cchMax)
2146 WCHAR szCopy[128];
2147 DWORD dwHours, dwMinutes;
2149 if (!iDigits || cchMax == 1)
2151 *lpszStr = '\0';
2152 return 0;
2155 /* Calculate the time classes */
2156 dwMS = (dwMS + 500) / 1000;
2157 dwHours = dwMS / 3600;
2158 dwMS -= dwHours * 3600;
2159 dwMinutes = dwMS / 60;
2160 dwMS -= dwMinutes * 60;
2162 szCopy[0] = '\0';
2164 if (dwHours)
2165 iDigits = SHLWAPI_WriteTimeClass(szCopy, dwHours, IDS_TIME_INTERVAL_HOURS, iDigits);
2167 if (dwMinutes && iDigits)
2168 iDigits = SHLWAPI_WriteTimeClass(szCopy, dwMinutes, IDS_TIME_INTERVAL_MINUTES, iDigits);
2170 if (iDigits) /* Always write seconds if we have significant digits */
2171 SHLWAPI_WriteTimeClass(szCopy, dwMS, IDS_TIME_INTERVAL_SECONDS, iDigits);
2173 lstrcpynW(lpszStr, szCopy, cchMax);
2174 iRet = strlenW(lpszStr);
2176 return iRet;
2179 /*************************************************************************
2180 * StrIsIntlEqualA [SHLWAPI.@]
2182 * Compare two strings.
2184 * PARAMS
2185 * bCase [I] Whether to compare case sensitively
2186 * lpszStr [I] First string to compare
2187 * lpszComp [I] Second string to compare
2188 * iLen [I] Length to compare
2190 * RETURNS
2191 * TRUE If the strings are equal.
2192 * FALSE Otherwise.
2194 BOOL WINAPI StrIsIntlEqualA(BOOL bCase, LPCSTR lpszStr, LPCSTR lpszComp,
2195 int iLen)
2197 DWORD dwFlags;
2199 TRACE("(%d,%s,%s,%d)\n", bCase,
2200 debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
2202 /* FIXME: This flag is undocumented and unknown by our CompareString.
2203 * We need a define for it.
2205 dwFlags = 0x10000000;
2206 if (!bCase) dwFlags |= NORM_IGNORECASE;
2208 return (CompareStringA(GetThreadLocale(), dwFlags, lpszStr, iLen, lpszComp, iLen) == CSTR_EQUAL);
2211 /*************************************************************************
2212 * StrIsIntlEqualW [SHLWAPI.@]
2214 * See StrIsIntlEqualA.
2216 BOOL WINAPI StrIsIntlEqualW(BOOL bCase, LPCWSTR lpszStr, LPCWSTR lpszComp,
2217 int iLen)
2219 DWORD dwFlags;
2221 TRACE("(%d,%s,%s,%d)\n", bCase,
2222 debugstr_w(lpszStr),debugstr_w(lpszComp), iLen);
2224 /* FIXME: This flag is undocumented and unknown by our CompareString.
2225 * We need a define for it.
2227 dwFlags = 0x10000000;
2228 if (!bCase) dwFlags |= NORM_IGNORECASE;
2230 return (CompareStringW(GetThreadLocale(), dwFlags, lpszStr, iLen, lpszComp, iLen) == CSTR_EQUAL);
2233 /*************************************************************************
2234 * @ [SHLWAPI.399]
2236 * Copy a string to another string, up to a maximum number of characters.
2238 * PARAMS
2239 * lpszDest [O] Destination string
2240 * lpszSrc [I] Source string
2241 * iLen [I] Maximum number of chars to copy
2243 * RETURNS
2244 * Success: A pointer to the last character written to lpszDest.
2245 * Failure: lpszDest, if any arguments are invalid.
2247 LPSTR WINAPI StrCpyNXA(LPSTR lpszDest, LPCSTR lpszSrc, int iLen)
2249 TRACE("(%p,%s,%i)\n", lpszDest, debugstr_a(lpszSrc), iLen);
2251 if (lpszDest && lpszSrc && iLen > 0)
2253 while ((iLen-- > 1) && *lpszSrc)
2254 *lpszDest++ = *lpszSrc++;
2255 if (iLen >= 0)
2256 *lpszDest = '\0';
2258 return lpszDest;
2261 /*************************************************************************
2262 * @ [SHLWAPI.400]
2264 * Unicode version of StrCpyNXA.
2266 LPWSTR WINAPI StrCpyNXW(LPWSTR lpszDest, LPCWSTR lpszSrc, int iLen)
2268 TRACE("(%p,%s,%i)\n", lpszDest, debugstr_w(lpszSrc), iLen);
2270 if (lpszDest && lpszSrc && iLen > 0)
2272 while ((iLen-- > 1) && *lpszSrc)
2273 *lpszDest++ = *lpszSrc++;
2274 if (iLen >= 0)
2275 *lpszDest = '\0';
2277 return lpszDest;
2280 /*************************************************************************
2281 * StrCmpLogicalW [SHLWAPI.@]
2283 * Compare two strings, ignoring case and comparing digits as numbers.
2285 * PARAMS
2286 * lpszStr [I] First string to compare
2287 * lpszComp [I] Second string to compare
2288 * iLen [I] Length to compare
2290 * RETURNS
2291 * TRUE If the strings are equal.
2292 * FALSE Otherwise.
2294 INT WINAPI StrCmpLogicalW(LPCWSTR lpszStr, LPCWSTR lpszComp)
2296 INT iDiff;
2298 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszComp));
2300 if (lpszStr && lpszComp)
2302 while (*lpszStr)
2304 if (!*lpszComp)
2305 return 1;
2306 else if (isdigitW(*lpszStr))
2308 int iStr, iComp;
2310 if (!isdigitW(*lpszComp))
2311 return -1;
2313 /* Compare the numbers */
2314 StrToIntExW(lpszStr, 0, &iStr);
2315 StrToIntExW(lpszComp, 0, &iComp);
2317 if (iStr < iComp)
2318 return -1;
2319 else if (iStr > iComp)
2320 return 1;
2322 /* Skip */
2323 while (isdigitW(*lpszStr))
2324 lpszStr++;
2325 while (isdigitW(*lpszComp))
2326 lpszComp++;
2328 else if (isdigitW(*lpszComp))
2329 return 1;
2330 else
2332 iDiff = ChrCmpIW(*lpszStr,*lpszComp);
2333 if (iDiff > 0)
2334 return 1;
2335 else if (iDiff < 0)
2336 return -1;
2338 lpszStr++;
2339 lpszComp++;
2342 if (*lpszComp)
2343 return -1;
2345 return 0;
2348 /* Structure for formatting byte strings */
2349 typedef struct tagSHLWAPI_BYTEFORMATS
2351 LONGLONG dLimit;
2352 double dDivisor;
2353 double dNormaliser;
2354 int nDecimals;
2355 WCHAR wPrefix;
2356 } SHLWAPI_BYTEFORMATS;
2358 /*************************************************************************
2359 * StrFormatByteSizeW [SHLWAPI.@]
2361 * Create a string containing an abbreviated byte count of up to 2^63-1.
2363 * PARAMS
2364 * llBytes [I] Byte size to format
2365 * lpszDest [I] Destination for formatted string
2366 * cchMax [I] Size of lpszDest
2368 * RETURNS
2369 * lpszDest.
2371 * NOTES
2372 * There is no StrFormatByteSize64W function, it is called StrFormatByteSizeW().
2374 LPWSTR WINAPI StrFormatByteSizeW(LONGLONG llBytes, LPWSTR lpszDest, UINT cchMax)
2376 #define KB ((ULONGLONG)1024)
2377 #define MB (KB*KB)
2378 #define GB (KB*KB*KB)
2379 #define TB (KB*KB*KB*KB)
2380 #define PB (KB*KB*KB*KB*KB)
2382 static const SHLWAPI_BYTEFORMATS bfFormats[] =
2384 { 10*KB, 10.24, 100.0, 2, 'K' }, /* 10 KB */
2385 { 100*KB, 102.4, 10.0, 1, 'K' }, /* 100 KB */
2386 { 1000*KB, 1024.0, 1.0, 0, 'K' }, /* 1000 KB */
2387 { 10*MB, 10485.76, 100.0, 2, 'M' }, /* 10 MB */
2388 { 100*MB, 104857.6, 10.0, 1, 'M' }, /* 100 MB */
2389 { 1000*MB, 1048576.0, 1.0, 0, 'M' }, /* 1000 MB */
2390 { 10*GB, 10737418.24, 100.0, 2, 'G' }, /* 10 GB */
2391 { 100*GB, 107374182.4, 10.0, 1, 'G' }, /* 100 GB */
2392 { 1000*GB, 1073741824.0, 1.0, 0, 'G' }, /* 1000 GB */
2393 { 10*TB, 10485.76, 100.0, 2, 'T' }, /* 10 TB */
2394 { 100*TB, 104857.6, 10.0, 1, 'T' }, /* 100 TB */
2395 { 1000*TB, 1048576.0, 1.0, 0, 'T' }, /* 1000 TB */
2396 { 10*PB, 10737418.24, 100.00, 2, 'P' }, /* 10 PB */
2397 { 100*PB, 107374182.4, 10.00, 1, 'P' }, /* 100 PB */
2398 { 1000*PB, 1073741824.0, 1.00, 0, 'P' }, /* 1000 PB */
2399 { 0, 10995116277.76, 100.00, 2, 'E' } /* EB's, catch all */
2401 WCHAR wszAdd[] = {' ','?','B',0};
2402 double dBytes;
2403 UINT i = 0;
2405 TRACE("(0x%s,%p,%d)\n", wine_dbgstr_longlong(llBytes), lpszDest, cchMax);
2407 if (!lpszDest || !cchMax)
2408 return lpszDest;
2410 if (llBytes < 1024) /* 1K */
2412 WCHAR wszBytesFormat[64];
2413 LoadStringW(shlwapi_hInstance, IDS_BYTES_FORMAT, wszBytesFormat, 64);
2414 snprintfW(lpszDest, cchMax, wszBytesFormat, (int)llBytes);
2415 return lpszDest;
2418 /* Note that if this loop completes without finding a match, i will be
2419 * pointing at the last entry, which is a catch all for > 1000 PB
2421 while (i < ARRAY_SIZE(bfFormats) - 1)
2423 if (llBytes < bfFormats[i].dLimit)
2424 break;
2425 i++;
2427 /* Above 1 TB we encounter problems with FP accuracy. So for amounts above
2428 * this number we integer shift down by 1 MB first. The table above has
2429 * the divisors scaled down from the '< 10 TB' entry onwards, to account
2430 * for this. We also add a small fudge factor to get the correct result for
2431 * counts that lie exactly on a 1024 byte boundary.
2433 if (i > 8)
2434 dBytes = (double)(llBytes >> 20) + 0.001; /* Scale down by 1 MB */
2435 else
2436 dBytes = (double)llBytes + 0.00001;
2438 dBytes = floor(dBytes / bfFormats[i].dDivisor) / bfFormats[i].dNormaliser;
2440 if (!FormatDouble(dBytes, bfFormats[i].nDecimals, lpszDest, cchMax))
2441 return NULL;
2442 wszAdd[1] = bfFormats[i].wPrefix;
2443 StrCatBuffW(lpszDest, wszAdd, cchMax);
2444 return lpszDest;
2447 /*************************************************************************
2448 * StrFormatByteSize64A [SHLWAPI.@]
2450 * See StrFormatByteSizeW.
2452 LPSTR WINAPI StrFormatByteSize64A(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax)
2454 WCHAR wszBuff[32];
2456 StrFormatByteSizeW(llBytes, wszBuff, ARRAY_SIZE(wszBuff));
2458 if (lpszDest)
2459 WideCharToMultiByte(CP_ACP, 0, wszBuff, -1, lpszDest, cchMax, 0, 0);
2460 return lpszDest;
2463 /*************************************************************************
2464 * StrFormatByteSizeA [SHLWAPI.@]
2466 * Create a string containing an abbreviated byte count of up to 2^31-1.
2468 * PARAMS
2469 * dwBytes [I] Byte size to format
2470 * lpszDest [I] Destination for formatted string
2471 * cchMax [I] Size of lpszDest
2473 * RETURNS
2474 * lpszDest.
2476 * NOTES
2477 * The Ascii and Unicode versions of this function accept a different
2478 * integer type for dwBytes. See StrFormatByteSize64A().
2480 LPSTR WINAPI StrFormatByteSizeA(DWORD dwBytes, LPSTR lpszDest, UINT cchMax)
2482 TRACE("(%d,%p,%d)\n", dwBytes, lpszDest, cchMax);
2484 return StrFormatByteSize64A(dwBytes, lpszDest, cchMax);
2487 /*************************************************************************
2488 * @ [SHLWAPI.162]
2490 * Remove a hanging lead byte from the end of a string, if present.
2492 * PARAMS
2493 * lpStr [I] String to check for a hanging lead byte
2494 * size [I] Length of lpStr
2496 * RETURNS
2497 * Success: The new length of the string. Any hanging lead bytes are removed.
2498 * Failure: 0, if any parameters are invalid.
2500 DWORD WINAPI SHTruncateString(LPSTR lpStr, DWORD size)
2502 if (lpStr && size)
2504 LPSTR lastByte = lpStr + size - 1;
2506 while(lpStr < lastByte)
2507 lpStr += IsDBCSLeadByte(*lpStr) ? 2 : 1;
2509 if(lpStr == lastByte && IsDBCSLeadByte(*lpStr))
2511 *lpStr = '\0';
2512 size--;
2514 return size;
2516 return 0;
2519 /*************************************************************************
2520 * @ [SHLWAPI.203]
2522 * Remove a single non-trailing ampersand ('&') from a string.
2524 * PARAMS
2525 * lpszStr [I/O] String to remove ampersand from.
2527 * RETURNS
2528 * The character after the first ampersand in lpszStr, or the first character
2529 * in lpszStr if there is no ampersand in the string.
2531 char WINAPI SHStripMneumonicA(LPCSTR lpszStr)
2533 LPSTR lpszIter, lpszTmp;
2534 char ch;
2536 TRACE("(%s)\n", debugstr_a(lpszStr));
2538 ch = *lpszStr;
2540 if ((lpszIter = StrChrA(lpszStr, '&')))
2542 lpszTmp = CharNextA(lpszIter);
2543 if (*lpszTmp)
2545 if (*lpszTmp != '&')
2546 ch = *lpszTmp;
2548 memmove( lpszIter, lpszTmp, strlen(lpszTmp) + 1 );
2552 return ch;
2555 /*************************************************************************
2556 * @ [SHLWAPI.225]
2558 * Unicode version of SHStripMneumonicA.
2560 WCHAR WINAPI SHStripMneumonicW(LPCWSTR lpszStr)
2562 LPWSTR lpszIter, lpszTmp;
2563 WCHAR ch;
2565 TRACE("(%s)\n", debugstr_w(lpszStr));
2567 ch = *lpszStr;
2569 if ((lpszIter = StrChrW(lpszStr, '&')))
2571 lpszTmp = lpszIter + 1;
2572 if (*lpszTmp)
2574 if (*lpszTmp != '&')
2575 ch = *lpszTmp;
2577 memmove( lpszIter, lpszTmp, (strlenW(lpszTmp) + 1) * sizeof(WCHAR) );
2581 return ch;
2584 /*************************************************************************
2585 * @ [SHLWAPI.216]
2587 * Convert an Ascii string to Unicode.
2589 * PARAMS
2590 * dwCp [I] Code page for the conversion
2591 * lpSrcStr [I] Source Ascii string to convert
2592 * lpDstStr [O] Destination for converted Unicode string
2593 * iLen [I] Length of lpDstStr
2595 * RETURNS
2596 * The return value of the MultiByteToWideChar() function called on lpSrcStr.
2598 DWORD WINAPI SHAnsiToUnicodeCP(DWORD dwCp, LPCSTR lpSrcStr, LPWSTR lpDstStr, int iLen)
2600 DWORD dwRet;
2602 dwRet = MultiByteToWideChar(dwCp, 0, lpSrcStr, -1, lpDstStr, iLen);
2603 TRACE("%s->%s,ret=%d\n", debugstr_a(lpSrcStr), debugstr_w(lpDstStr), dwRet);
2604 return dwRet;
2607 /*************************************************************************
2608 * @ [SHLWAPI.215]
2610 * Convert an Ascii string to Unicode.
2612 * PARAMS
2613 * lpSrcStr [I] Source Ascii string to convert
2614 * lpDstStr [O] Destination for converted Unicode string
2615 * iLen [I] Length of lpDstStr
2617 * RETURNS
2618 * The return value of the MultiByteToWideChar() function called on lpSrcStr.
2620 * NOTES
2621 * This function simply calls SHAnsiToUnicodeCP with code page CP_ACP.
2623 DWORD WINAPI SHAnsiToUnicode(LPCSTR lpSrcStr, LPWSTR lpDstStr, int iLen)
2625 return SHAnsiToUnicodeCP(CP_ACP, lpSrcStr, lpDstStr, iLen);
2628 /*************************************************************************
2629 * @ [SHLWAPI.218]
2631 * Convert a Unicode string to Ascii.
2633 * PARAMS
2634 * CodePage [I] Code page to use for the conversion
2635 * lpSrcStr [I] Source Unicode string to convert
2636 * lpDstStr [O] Destination for converted Ascii string
2637 * dstlen [I] Length of buffer at lpDstStr
2639 * RETURNS
2640 * Success: The length in bytes of the result at lpDstStr (including the terminator)
2641 * Failure: When using CP_UTF8, CP_UTF7 or 0xc350 as codePage, 0 is returned and
2642 * the result is not nul-terminated.
2643 * When using a different codepage, the length in bytes of the truncated
2644 * result at lpDstStr (including the terminator) is returned and
2645 * lpDstStr is always nul-terminated.
2648 DWORD WINAPI SHUnicodeToAnsiCP(UINT CodePage, LPCWSTR lpSrcStr, LPSTR lpDstStr, int dstlen)
2650 static const WCHAR emptyW[] = { '\0' };
2651 int len , reqLen;
2652 LPSTR mem;
2654 if (!lpDstStr || !dstlen)
2655 return 0;
2657 if (!lpSrcStr)
2658 lpSrcStr = emptyW;
2660 *lpDstStr = '\0';
2662 len = strlenW(lpSrcStr) + 1;
2664 switch (CodePage)
2666 case CP_WINUNICODE:
2667 CodePage = CP_UTF8; /* Fall through... */
2668 case 0x0000C350: /* FIXME: CP_ #define */
2669 case CP_UTF7:
2670 case CP_UTF8:
2672 DWORD dwMode = 0;
2673 INT lenW = len - 1;
2674 INT needed = dstlen - 1;
2675 HRESULT hr;
2677 /* try the user supplied buffer first */
2678 hr = ConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &lenW, lpDstStr, &needed);
2679 if (hr == S_OK)
2681 lpDstStr[needed] = '\0';
2682 return needed + 1;
2685 /* user buffer too small. exclude termination and copy as much as possible */
2686 lenW = len;
2687 hr = ConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &lenW, NULL, &needed);
2688 needed++;
2689 mem = HeapAlloc(GetProcessHeap(), 0, needed);
2690 if (!mem)
2691 return 0;
2693 hr = ConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &len, mem, &needed);
2694 if (hr == S_OK)
2696 reqLen = SHTruncateString(mem, dstlen);
2697 if (reqLen > 0) memcpy(lpDstStr, mem, reqLen-1);
2699 HeapFree(GetProcessHeap(), 0, mem);
2700 return 0;
2702 default:
2703 break;
2706 /* try the user supplied buffer first */
2707 reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, lpDstStr, dstlen, NULL, NULL);
2709 if (!reqLen && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
2711 reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, NULL, 0, NULL, NULL);
2712 if (reqLen)
2714 mem = HeapAlloc(GetProcessHeap(), 0, reqLen);
2715 if (mem)
2717 WideCharToMultiByte(CodePage, 0, lpSrcStr, len, mem, reqLen, NULL, NULL);
2719 reqLen = SHTruncateString(mem, dstlen -1);
2720 reqLen++;
2722 lstrcpynA(lpDstStr, mem, reqLen);
2723 HeapFree(GetProcessHeap(), 0, mem);
2724 lpDstStr[reqLen-1] = '\0';
2728 return reqLen;
2731 /*************************************************************************
2732 * @ [SHLWAPI.217]
2734 * Convert a Unicode string to Ascii.
2736 * PARAMS
2737 * lpSrcStr [I] Source Unicode string to convert
2738 * lpDstStr [O] Destination for converted Ascii string
2739 * iLen [O] Length of lpDstStr in characters
2741 * RETURNS
2742 * See SHUnicodeToAnsiCP
2744 * NOTES
2745 * This function simply calls SHUnicodeToAnsiCP() with CodePage = CP_ACP.
2747 INT WINAPI SHUnicodeToAnsi(LPCWSTR lpSrcStr, LPSTR lpDstStr, INT iLen)
2749 return SHUnicodeToAnsiCP(CP_ACP, lpSrcStr, lpDstStr, iLen);
2752 /*************************************************************************
2753 * @ [SHLWAPI.364]
2755 * Determine if an Ascii string converts to Unicode and back identically.
2757 * PARAMS
2758 * lpSrcStr [I] Source Unicode string to convert
2759 * lpDst [O] Destination for resulting Ascii string
2760 * iLen [I] Length of lpDst in characters
2762 * RETURNS
2763 * TRUE, since Ascii strings always convert identically.
2765 BOOL WINAPI DoesStringRoundTripA(LPCSTR lpSrcStr, LPSTR lpDst, INT iLen)
2767 lstrcpynA(lpDst, lpSrcStr, iLen);
2768 return TRUE;
2771 /*************************************************************************
2772 * @ [SHLWAPI.365]
2774 * Determine if a Unicode string converts to Ascii and back identically.
2776 * PARAMS
2777 * lpSrcStr [I] Source Unicode string to convert
2778 * lpDst [O] Destination for resulting Ascii string
2779 * iLen [I] Length of lpDst in characters
2781 * RETURNS
2782 * TRUE, if lpSrcStr converts to Ascii and back identically,
2783 * FALSE otherwise.
2785 BOOL WINAPI DoesStringRoundTripW(LPCWSTR lpSrcStr, LPSTR lpDst, INT iLen)
2787 WCHAR szBuff[MAX_PATH];
2789 SHUnicodeToAnsi(lpSrcStr, lpDst, iLen);
2790 SHAnsiToUnicode(lpDst, szBuff, MAX_PATH);
2791 return !strcmpW(lpSrcStr, szBuff);
2794 /*************************************************************************
2795 * SHLoadIndirectString [SHLWAPI.@]
2797 * If passed a string that begins with '@', extract the string from the
2798 * appropriate resource, otherwise do a straight copy.
2801 HRESULT WINAPI SHLoadIndirectString(LPCWSTR src, LPWSTR dst, UINT dst_len, void **reserved)
2803 WCHAR *dllname = NULL;
2804 HMODULE hmod = NULL;
2805 HRESULT hr = E_FAIL;
2807 TRACE("(%s %p %08x %p)\n", debugstr_w(src), dst, dst_len, reserved);
2809 if(src[0] == '@')
2811 WCHAR *index_str;
2812 int index;
2814 dst[0] = 0;
2815 dllname = StrDupW(src + 1);
2816 index_str = strchrW(dllname, ',');
2818 if(!index_str) goto end;
2820 *index_str = 0;
2821 index_str++;
2822 index = atoiW(index_str);
2824 hmod = LoadLibraryW(dllname);
2825 if(!hmod) goto end;
2827 if(index < 0)
2829 if(LoadStringW(hmod, -index, dst, dst_len))
2830 hr = S_OK;
2832 else
2833 FIXME("can't handle non-negative indices (%d)\n", index);
2835 else
2837 if(dst != src)
2838 lstrcpynW(dst, src, dst_len);
2839 hr = S_OK;
2842 TRACE("returning %s\n", debugstr_w(dst));
2843 end:
2844 if(hmod) FreeLibrary(hmod);
2845 LocalFree(dllname);
2846 return hr;
2849 BOOL WINAPI IsCharSpaceA(CHAR c)
2851 WORD CharType;
2852 return GetStringTypeA(GetSystemDefaultLCID(), CT_CTYPE1, &c, 1, &CharType) && (CharType & C1_SPACE);
2855 /*************************************************************************
2856 * @ [SHLWAPI.29]
2858 * Determine if a Unicode character is a space.
2860 * PARAMS
2861 * wc [I] Character to check.
2863 * RETURNS
2864 * TRUE, if wc is a space,
2865 * FALSE otherwise.
2867 BOOL WINAPI IsCharSpaceW(WCHAR wc)
2869 WORD CharType;
2871 return GetStringTypeW(CT_CTYPE1, &wc, 1, &CharType) && (CharType & C1_SPACE);