ntdll: Reuse signal to trap translation for FreeBSD on ARM.
[wine.git] / dlls / shlwapi / string.c
blob7b8473a379c3476db74cd6a6851ecb9227577524
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 *dest = '\0';
1531 return E_FAIL;
1534 *dest = '\0';
1536 switch (src->uType) {
1537 case STRRET_WSTR: {
1538 size_t dst_len;
1539 if (!src->u.pOleStr)
1540 return E_FAIL;
1541 dst_len = strlenW(src->u.pOleStr);
1542 memcpy(dest, src->u.pOleStr, min(dst_len, len-1) * sizeof(WCHAR));
1543 dest[min(dst_len, len-1)] = 0;
1544 CoTaskMemFree(src->u.pOleStr);
1545 if (len <= dst_len)
1547 dest[0] = 0;
1548 return E_NOT_SUFFICIENT_BUFFER;
1550 break;
1553 case STRRET_CSTR:
1554 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ))
1555 dest[len-1] = 0;
1556 break;
1558 case STRRET_OFFSET:
1559 if (pidl)
1561 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1,
1562 dest, len ))
1563 dest[len-1] = 0;
1565 break;
1567 default:
1568 FIXME("unknown type!\n");
1569 return E_NOTIMPL;
1572 return S_OK;
1575 /*************************************************************************
1576 * StrRetToStrA [SHLWAPI.@]
1578 * Converts a STRRET to a normal string.
1580 * PARAMS
1581 * lpStrRet [O] STRRET to convert
1582 * pidl [I] ITEMIDLIST for lpStrRet->uType == STRRET_OFFSET
1583 * ppszName [O] Destination for converted string
1585 * RETURNS
1586 * Success: S_OK. ppszName contains the new string, allocated with CoTaskMemAlloc().
1587 * Failure: E_FAIL, if any parameters are invalid.
1589 HRESULT WINAPI StrRetToStrA(LPSTRRET lpStrRet, const ITEMIDLIST *pidl, LPSTR *ppszName)
1591 HRESULT hRet = E_FAIL;
1593 switch (lpStrRet->uType)
1595 case STRRET_WSTR:
1596 hRet = _SHStrDupAW(lpStrRet->u.pOleStr, ppszName);
1597 CoTaskMemFree(lpStrRet->u.pOleStr);
1598 break;
1600 case STRRET_CSTR:
1601 hRet = _SHStrDupAA(lpStrRet->u.cStr, ppszName);
1602 break;
1604 case STRRET_OFFSET:
1605 hRet = _SHStrDupAA(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, ppszName);
1606 break;
1608 default:
1609 *ppszName = NULL;
1612 return hRet;
1615 /*************************************************************************
1616 * StrRetToStrW [SHLWAPI.@]
1618 * See StrRetToStrA.
1620 HRESULT WINAPI StrRetToStrW(LPSTRRET lpStrRet, const ITEMIDLIST *pidl, LPWSTR *ppszName)
1622 HRESULT hRet = E_FAIL;
1624 switch (lpStrRet->uType)
1626 case STRRET_WSTR:
1627 hRet = SHStrDupW(lpStrRet->u.pOleStr, ppszName);
1628 CoTaskMemFree(lpStrRet->u.pOleStr);
1629 break;
1631 case STRRET_CSTR:
1632 hRet = SHStrDupA(lpStrRet->u.cStr, ppszName);
1633 break;
1635 case STRRET_OFFSET:
1636 hRet = SHStrDupA(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, ppszName);
1637 break;
1639 default:
1640 *ppszName = NULL;
1643 return hRet;
1646 /* Create an ASCII string copy using SysAllocString() */
1647 static HRESULT _SHStrDupAToBSTR(LPCSTR src, BSTR *pBstrOut)
1649 *pBstrOut = NULL;
1651 if (src)
1653 INT len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0);
1654 WCHAR* szTemp = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1656 if (szTemp)
1658 MultiByteToWideChar(CP_ACP, 0, src, -1, szTemp, len);
1659 *pBstrOut = SysAllocString(szTemp);
1660 HeapFree(GetProcessHeap(), 0, szTemp);
1662 if (*pBstrOut)
1663 return S_OK;
1666 return E_OUTOFMEMORY;
1669 /*************************************************************************
1670 * StrRetToBSTR [SHLWAPI.@]
1672 * Converts a STRRET to a BSTR.
1674 * PARAMS
1675 * lpStrRet [O] STRRET to convert
1676 * pidl [I] ITEMIDLIST for lpStrRet->uType = STRRET_OFFSET
1677 * pBstrOut [O] Destination for converted BSTR
1679 * RETURNS
1680 * Success: S_OK. pBstrOut contains the new string.
1681 * Failure: E_FAIL, if any parameters are invalid.
1683 HRESULT WINAPI StrRetToBSTR(STRRET *lpStrRet, LPCITEMIDLIST pidl, BSTR* pBstrOut)
1685 HRESULT hRet = E_FAIL;
1687 switch (lpStrRet->uType)
1689 case STRRET_WSTR:
1690 *pBstrOut = SysAllocString(lpStrRet->u.pOleStr);
1691 if (*pBstrOut)
1692 hRet = S_OK;
1693 CoTaskMemFree(lpStrRet->u.pOleStr);
1694 break;
1696 case STRRET_CSTR:
1697 hRet = _SHStrDupAToBSTR(lpStrRet->u.cStr, pBstrOut);
1698 break;
1700 case STRRET_OFFSET:
1701 hRet = _SHStrDupAToBSTR(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, pBstrOut);
1702 break;
1704 default:
1705 *pBstrOut = NULL;
1708 return hRet;
1711 /*************************************************************************
1712 * StrFormatKBSizeA [SHLWAPI.@]
1714 * Create a formatted string containing a byte count in Kilobytes.
1716 * PARAMS
1717 * llBytes [I] Byte size to format
1718 * lpszDest [I] Destination for formatted string
1719 * cchMax [I] Size of lpszDest
1721 * RETURNS
1722 * lpszDest.
1724 LPSTR WINAPI StrFormatKBSizeA(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax)
1726 WCHAR wszBuf[256];
1728 if (!StrFormatKBSizeW(llBytes, wszBuf, 256))
1729 return NULL;
1730 if (!WideCharToMultiByte(CP_ACP, 0, wszBuf, -1, lpszDest, cchMax, NULL, NULL))
1731 return NULL;
1732 return lpszDest;
1735 /*************************************************************************
1736 * StrFormatKBSizeW [SHLWAPI.@]
1738 * See StrFormatKBSizeA.
1740 LPWSTR WINAPI StrFormatKBSizeW(LONGLONG llBytes, LPWSTR lpszDest, UINT cchMax)
1742 static const WCHAR kb[] = {' ','K','B',0};
1743 LONGLONG llKB = (llBytes + 1023) >> 10;
1744 int len;
1746 TRACE("(0x%s,%p,%d)\n", wine_dbgstr_longlong(llBytes), lpszDest, cchMax);
1748 if (!FormatInt(llKB, lpszDest, cchMax))
1749 return NULL;
1751 len = lstrlenW(lpszDest);
1752 if (cchMax - len < 4)
1753 return NULL;
1754 lstrcatW(lpszDest, kb);
1755 return lpszDest;
1758 /*************************************************************************
1759 * StrNCatA [SHLWAPI.@]
1761 * Concatenate two strings together.
1763 * PARAMS
1764 * lpszStr [O] String to concatenate to
1765 * lpszCat [I] String to add to lpszCat
1766 * cchMax [I] Maximum number of characters to concatenate
1768 * RETURNS
1769 * lpszStr.
1771 * NOTES
1772 * cchMax determines the number of characters that are appended to lpszStr,
1773 * not the total length of the string.
1775 LPSTR WINAPI StrNCatA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax)
1777 LPSTR lpszRet = lpszStr;
1779 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszCat), cchMax);
1781 if (!lpszStr)
1783 WARN("Invalid lpszStr would crash under Win32!\n");
1784 return NULL;
1787 StrCpyNA(lpszStr + strlen(lpszStr), lpszCat, cchMax);
1788 return lpszRet;
1791 /*************************************************************************
1792 * StrNCatW [SHLWAPI.@]
1794 * See StrNCatA.
1796 LPWSTR WINAPI StrNCatW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax)
1798 LPWSTR lpszRet = lpszStr;
1800 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszCat), cchMax);
1802 if (!lpszStr)
1804 WARN("Invalid lpszStr would crash under Win32\n");
1805 return NULL;
1808 StrCpyNW(lpszStr + strlenW(lpszStr), lpszCat, cchMax);
1809 return lpszRet;
1812 /*************************************************************************
1813 * StrTrimA [SHLWAPI.@]
1815 * Remove characters from the start and end of a string.
1817 * PARAMS
1818 * lpszStr [O] String to remove characters from
1819 * lpszTrim [I] Characters to remove from lpszStr
1821 * RETURNS
1822 * TRUE If lpszStr was valid and modified
1823 * FALSE Otherwise
1825 BOOL WINAPI StrTrimA(LPSTR lpszStr, LPCSTR lpszTrim)
1827 DWORD dwLen;
1828 LPSTR lpszRead = lpszStr;
1829 BOOL bRet = FALSE;
1831 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszTrim));
1833 if (lpszRead && *lpszRead)
1835 while (*lpszRead && StrChrA(lpszTrim, *lpszRead))
1836 lpszRead = CharNextA(lpszRead); /* Skip leading matches */
1838 dwLen = strlen(lpszRead);
1840 if (lpszRead != lpszStr)
1842 memmove(lpszStr, lpszRead, dwLen + 1);
1843 bRet = TRUE;
1845 if (dwLen > 0)
1847 lpszRead = lpszStr + dwLen;
1848 while (StrChrA(lpszTrim, lpszRead[-1]))
1849 lpszRead = CharPrevA(lpszStr, lpszRead); /* Skip trailing matches */
1851 if (lpszRead != lpszStr + dwLen)
1853 *lpszRead = '\0';
1854 bRet = TRUE;
1858 return bRet;
1861 /*************************************************************************
1862 * StrTrimW [SHLWAPI.@]
1864 * See StrTrimA.
1866 BOOL WINAPI StrTrimW(LPWSTR lpszStr, LPCWSTR lpszTrim)
1868 DWORD dwLen;
1869 LPWSTR lpszRead = lpszStr;
1870 BOOL bRet = FALSE;
1872 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszTrim));
1874 if (lpszRead && *lpszRead)
1876 while (*lpszRead && StrChrW(lpszTrim, *lpszRead)) lpszRead++;
1878 dwLen = strlenW(lpszRead);
1880 if (lpszRead != lpszStr)
1882 memmove(lpszStr, lpszRead, (dwLen + 1) * sizeof(WCHAR));
1883 bRet = TRUE;
1885 if (dwLen > 0)
1887 lpszRead = lpszStr + dwLen;
1888 while (StrChrW(lpszTrim, lpszRead[-1]))
1889 lpszRead--; /* Skip trailing matches */
1891 if (lpszRead != lpszStr + dwLen)
1893 *lpszRead = '\0';
1894 bRet = TRUE;
1898 return bRet;
1901 /*************************************************************************
1902 * _SHStrDupAA [INTERNAL]
1904 * Duplicates a ASCII string to ASCII. The destination buffer is allocated.
1906 static HRESULT _SHStrDupAA(LPCSTR src, LPSTR * dest)
1908 HRESULT hr;
1909 int len = 0;
1911 if (src) {
1912 len = lstrlenA(src) + 1;
1913 *dest = CoTaskMemAlloc(len);
1914 } else {
1915 *dest = NULL;
1918 if (*dest) {
1919 lstrcpynA(*dest,src, len);
1920 hr = S_OK;
1921 } else {
1922 hr = E_OUTOFMEMORY;
1925 TRACE("%s->(%p)\n", debugstr_a(src), *dest);
1926 return hr;
1929 /*************************************************************************
1930 * SHStrDupA [SHLWAPI.@]
1932 * Return a Unicode copy of a string, in memory allocated by CoTaskMemAlloc().
1934 * PARAMS
1935 * lpszStr [I] String to copy
1936 * lppszDest [O] Destination for the new string copy
1938 * RETURNS
1939 * Success: S_OK. lppszDest contains the new string in Unicode format.
1940 * Failure: E_OUTOFMEMORY, If any arguments are invalid or memory allocation
1941 * fails.
1943 HRESULT WINAPI SHStrDupA(LPCSTR lpszStr, LPWSTR * lppszDest)
1945 HRESULT hRet;
1946 int len = 0;
1948 if (lpszStr)
1950 len = MultiByteToWideChar(CP_ACP, 0, lpszStr, -1, NULL, 0) * sizeof(WCHAR);
1951 *lppszDest = CoTaskMemAlloc(len);
1953 else
1954 *lppszDest = NULL;
1956 if (*lppszDest)
1958 MultiByteToWideChar(CP_ACP, 0, lpszStr, -1, *lppszDest, len/sizeof(WCHAR));
1959 hRet = S_OK;
1961 else
1962 hRet = E_OUTOFMEMORY;
1964 TRACE("%s->(%p)\n", debugstr_a(lpszStr), *lppszDest);
1965 return hRet;
1968 /*************************************************************************
1969 * _SHStrDupAW [INTERNAL]
1971 * Duplicates a UNICODE to a ASCII string. The destination buffer is allocated.
1973 static HRESULT _SHStrDupAW(LPCWSTR src, LPSTR * dest)
1975 HRESULT hr;
1976 int len = 0;
1978 if (src) {
1979 len = WideCharToMultiByte(CP_ACP, 0, src, -1, NULL, 0, NULL, NULL);
1980 *dest = CoTaskMemAlloc(len);
1981 } else {
1982 *dest = NULL;
1985 if (*dest) {
1986 WideCharToMultiByte(CP_ACP, 0, src, -1, *dest, len, NULL, NULL);
1987 hr = S_OK;
1988 } else {
1989 hr = E_OUTOFMEMORY;
1992 TRACE("%s->(%p)\n", debugstr_w(src), *dest);
1993 return hr;
1996 /*************************************************************************
1997 * SHStrDupW [SHLWAPI.@]
1999 * See SHStrDupA.
2001 HRESULT WINAPI SHStrDupW(LPCWSTR src, LPWSTR * dest)
2003 HRESULT hr;
2004 int len = 0;
2006 if (src) {
2007 len = (lstrlenW(src) + 1) * sizeof(WCHAR);
2008 *dest = CoTaskMemAlloc(len);
2009 } else {
2010 *dest = NULL;
2013 if (*dest) {
2014 memcpy(*dest, src, len);
2015 hr = S_OK;
2016 } else {
2017 hr = E_OUTOFMEMORY;
2020 TRACE("%s->(%p)\n", debugstr_w(src), *dest);
2021 return hr;
2024 /*************************************************************************
2025 * SHLWAPI_WriteReverseNum
2027 * Internal helper for SHLWAPI_WriteTimeClass.
2029 static inline LPWSTR SHLWAPI_WriteReverseNum(LPWSTR lpszOut, DWORD dwNum)
2031 *lpszOut-- = '\0';
2033 /* Write a decimal number to a string, backwards */
2036 DWORD dwNextDigit = dwNum % 10;
2037 *lpszOut-- = '0' + dwNextDigit;
2038 dwNum = (dwNum - dwNextDigit) / 10;
2039 } while (dwNum > 0);
2041 return lpszOut;
2044 /*************************************************************************
2045 * SHLWAPI_FormatSignificant
2047 * Internal helper for SHLWAPI_WriteTimeClass.
2049 static inline int SHLWAPI_FormatSignificant(LPWSTR lpszNum, int dwDigits)
2051 /* Zero non significant digits, return remaining significant digits */
2052 while (*lpszNum)
2054 lpszNum++;
2055 if (--dwDigits == 0)
2057 while (*lpszNum)
2058 *lpszNum++ = '0';
2059 return 0;
2062 return dwDigits;
2065 /*************************************************************************
2066 * SHLWAPI_WriteTimeClass
2068 * Internal helper for StrFromTimeIntervalW.
2070 static int SHLWAPI_WriteTimeClass(LPWSTR lpszOut, DWORD dwValue,
2071 UINT uClassStringId, int iDigits)
2073 WCHAR szBuff[64], *szOut = szBuff + 32;
2075 szOut = SHLWAPI_WriteReverseNum(szOut, dwValue);
2076 iDigits = SHLWAPI_FormatSignificant(szOut + 1, iDigits);
2077 *szOut = ' ';
2078 LoadStringW(shlwapi_hInstance, uClassStringId, szBuff + 32, 32);
2079 strcatW(lpszOut, szOut);
2080 return iDigits;
2083 /*************************************************************************
2084 * StrFromTimeIntervalA [SHLWAPI.@]
2086 * Format a millisecond time interval into a string
2088 * PARAMS
2089 * lpszStr [O] Output buffer for formatted time interval
2090 * cchMax [I] Size of lpszStr
2091 * dwMS [I] Number of milliseconds
2092 * iDigits [I] Number of digits to print
2094 * RETURNS
2095 * The length of the formatted string, or 0 if any parameter is invalid.
2097 * NOTES
2098 * This implementation mimics the Win32 behaviour of always writing a leading
2099 * space before the time interval begins.
2101 * iDigits is used to provide approximate times if accuracy is not important.
2102 * This number of digits will be written of the first non-zero time class
2103 * (hours/minutes/seconds). If this does not complete the time classification,
2104 * the remaining digits are changed to zeros (i.e. The time is _not_ rounded).
2105 * If there are digits remaining following the writing of a time class, the
2106 * next time class will be written.
2108 * For example, given dwMS represents 138 hours,43 minutes and 15 seconds, the
2109 * following will result from the given values of iDigits:
2111 *| iDigits 1 2 3 4 5 ...
2112 *| lpszStr "100 hr" "130 hr" "138 hr" "138 hr 40 min" "138 hr 43 min" ...
2114 INT WINAPI StrFromTimeIntervalA(LPSTR lpszStr, UINT cchMax, DWORD dwMS,
2115 int iDigits)
2117 INT iRet = 0;
2119 TRACE("(%p,%d,%d,%d)\n", lpszStr, cchMax, dwMS, iDigits);
2121 if (lpszStr && cchMax)
2123 WCHAR szBuff[128];
2124 StrFromTimeIntervalW(szBuff, ARRAY_SIZE(szBuff), dwMS, iDigits);
2125 WideCharToMultiByte(CP_ACP,0,szBuff,-1,lpszStr,cchMax,0,0);
2127 return iRet;
2131 /*************************************************************************
2132 * StrFromTimeIntervalW [SHLWAPI.@]
2134 * See StrFromTimeIntervalA.
2136 INT WINAPI StrFromTimeIntervalW(LPWSTR lpszStr, UINT cchMax, DWORD dwMS,
2137 int iDigits)
2139 INT iRet = 0;
2141 TRACE("(%p,%d,%d,%d)\n", lpszStr, cchMax, dwMS, iDigits);
2143 if (lpszStr && cchMax)
2145 WCHAR szCopy[128];
2146 DWORD dwHours, dwMinutes;
2148 if (!iDigits || cchMax == 1)
2150 *lpszStr = '\0';
2151 return 0;
2154 /* Calculate the time classes */
2155 dwMS = (dwMS + 500) / 1000;
2156 dwHours = dwMS / 3600;
2157 dwMS -= dwHours * 3600;
2158 dwMinutes = dwMS / 60;
2159 dwMS -= dwMinutes * 60;
2161 szCopy[0] = '\0';
2163 if (dwHours)
2164 iDigits = SHLWAPI_WriteTimeClass(szCopy, dwHours, IDS_TIME_INTERVAL_HOURS, iDigits);
2166 if (dwMinutes && iDigits)
2167 iDigits = SHLWAPI_WriteTimeClass(szCopy, dwMinutes, IDS_TIME_INTERVAL_MINUTES, iDigits);
2169 if (iDigits) /* Always write seconds if we have significant digits */
2170 SHLWAPI_WriteTimeClass(szCopy, dwMS, IDS_TIME_INTERVAL_SECONDS, iDigits);
2172 lstrcpynW(lpszStr, szCopy, cchMax);
2173 iRet = strlenW(lpszStr);
2175 return iRet;
2178 /*************************************************************************
2179 * StrIsIntlEqualA [SHLWAPI.@]
2181 * Compare two strings.
2183 * PARAMS
2184 * bCase [I] Whether to compare case sensitively
2185 * lpszStr [I] First string to compare
2186 * lpszComp [I] Second string to compare
2187 * iLen [I] Length to compare
2189 * RETURNS
2190 * TRUE If the strings are equal.
2191 * FALSE Otherwise.
2193 BOOL WINAPI StrIsIntlEqualA(BOOL bCase, LPCSTR lpszStr, LPCSTR lpszComp,
2194 int iLen)
2196 DWORD dwFlags;
2198 TRACE("(%d,%s,%s,%d)\n", bCase,
2199 debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
2201 /* FIXME: This flag is undocumented and unknown by our CompareString.
2202 * We need a define for it.
2204 dwFlags = 0x10000000;
2205 if (!bCase) dwFlags |= NORM_IGNORECASE;
2207 return (CompareStringA(GetThreadLocale(), dwFlags, lpszStr, iLen, lpszComp, iLen) == CSTR_EQUAL);
2210 /*************************************************************************
2211 * StrIsIntlEqualW [SHLWAPI.@]
2213 * See StrIsIntlEqualA.
2215 BOOL WINAPI StrIsIntlEqualW(BOOL bCase, LPCWSTR lpszStr, LPCWSTR lpszComp,
2216 int iLen)
2218 DWORD dwFlags;
2220 TRACE("(%d,%s,%s,%d)\n", bCase,
2221 debugstr_w(lpszStr),debugstr_w(lpszComp), iLen);
2223 /* FIXME: This flag is undocumented and unknown by our CompareString.
2224 * We need a define for it.
2226 dwFlags = 0x10000000;
2227 if (!bCase) dwFlags |= NORM_IGNORECASE;
2229 return (CompareStringW(GetThreadLocale(), dwFlags, lpszStr, iLen, lpszComp, iLen) == CSTR_EQUAL);
2232 /*************************************************************************
2233 * @ [SHLWAPI.399]
2235 * Copy a string to another string, up to a maximum number of characters.
2237 * PARAMS
2238 * lpszDest [O] Destination string
2239 * lpszSrc [I] Source string
2240 * iLen [I] Maximum number of chars to copy
2242 * RETURNS
2243 * Success: A pointer to the last character written to lpszDest.
2244 * Failure: lpszDest, if any arguments are invalid.
2246 LPSTR WINAPI StrCpyNXA(LPSTR lpszDest, LPCSTR lpszSrc, int iLen)
2248 TRACE("(%p,%s,%i)\n", lpszDest, debugstr_a(lpszSrc), iLen);
2250 if (lpszDest && lpszSrc && iLen > 0)
2252 while ((iLen-- > 1) && *lpszSrc)
2253 *lpszDest++ = *lpszSrc++;
2254 if (iLen >= 0)
2255 *lpszDest = '\0';
2257 return lpszDest;
2260 /*************************************************************************
2261 * @ [SHLWAPI.400]
2263 * Unicode version of StrCpyNXA.
2265 LPWSTR WINAPI StrCpyNXW(LPWSTR lpszDest, LPCWSTR lpszSrc, int iLen)
2267 TRACE("(%p,%s,%i)\n", lpszDest, debugstr_w(lpszSrc), iLen);
2269 if (lpszDest && lpszSrc && iLen > 0)
2271 while ((iLen-- > 1) && *lpszSrc)
2272 *lpszDest++ = *lpszSrc++;
2273 if (iLen >= 0)
2274 *lpszDest = '\0';
2276 return lpszDest;
2279 /*************************************************************************
2280 * StrCmpLogicalW [SHLWAPI.@]
2282 * Compare two strings, ignoring case and comparing digits as numbers.
2284 * PARAMS
2285 * lpszStr [I] First string to compare
2286 * lpszComp [I] Second string to compare
2287 * iLen [I] Length to compare
2289 * RETURNS
2290 * TRUE If the strings are equal.
2291 * FALSE Otherwise.
2293 INT WINAPI StrCmpLogicalW(LPCWSTR lpszStr, LPCWSTR lpszComp)
2295 INT iDiff;
2297 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszComp));
2299 if (lpszStr && lpszComp)
2301 while (*lpszStr)
2303 if (!*lpszComp)
2304 return 1;
2305 else if (isdigitW(*lpszStr))
2307 int iStr, iComp;
2309 if (!isdigitW(*lpszComp))
2310 return -1;
2312 /* Compare the numbers */
2313 StrToIntExW(lpszStr, 0, &iStr);
2314 StrToIntExW(lpszComp, 0, &iComp);
2316 if (iStr < iComp)
2317 return -1;
2318 else if (iStr > iComp)
2319 return 1;
2321 /* Skip */
2322 while (isdigitW(*lpszStr))
2323 lpszStr++;
2324 while (isdigitW(*lpszComp))
2325 lpszComp++;
2327 else if (isdigitW(*lpszComp))
2328 return 1;
2329 else
2331 iDiff = ChrCmpIW(*lpszStr,*lpszComp);
2332 if (iDiff > 0)
2333 return 1;
2334 else if (iDiff < 0)
2335 return -1;
2337 lpszStr++;
2338 lpszComp++;
2341 if (*lpszComp)
2342 return -1;
2344 return 0;
2347 /* Structure for formatting byte strings */
2348 typedef struct tagSHLWAPI_BYTEFORMATS
2350 LONGLONG dLimit;
2351 double dDivisor;
2352 double dNormaliser;
2353 int nDecimals;
2354 WCHAR wPrefix;
2355 } SHLWAPI_BYTEFORMATS;
2357 /*************************************************************************
2358 * StrFormatByteSizeW [SHLWAPI.@]
2360 * Create a string containing an abbreviated byte count of up to 2^63-1.
2362 * PARAMS
2363 * llBytes [I] Byte size to format
2364 * lpszDest [I] Destination for formatted string
2365 * cchMax [I] Size of lpszDest
2367 * RETURNS
2368 * lpszDest.
2370 * NOTES
2371 * There is no StrFormatByteSize64W function, it is called StrFormatByteSizeW().
2373 LPWSTR WINAPI StrFormatByteSizeW(LONGLONG llBytes, LPWSTR lpszDest, UINT cchMax)
2375 #define KB ((ULONGLONG)1024)
2376 #define MB (KB*KB)
2377 #define GB (KB*KB*KB)
2378 #define TB (KB*KB*KB*KB)
2379 #define PB (KB*KB*KB*KB*KB)
2381 static const SHLWAPI_BYTEFORMATS bfFormats[] =
2383 { 10*KB, 10.24, 100.0, 2, 'K' }, /* 10 KB */
2384 { 100*KB, 102.4, 10.0, 1, 'K' }, /* 100 KB */
2385 { 1000*KB, 1024.0, 1.0, 0, 'K' }, /* 1000 KB */
2386 { 10*MB, 10485.76, 100.0, 2, 'M' }, /* 10 MB */
2387 { 100*MB, 104857.6, 10.0, 1, 'M' }, /* 100 MB */
2388 { 1000*MB, 1048576.0, 1.0, 0, 'M' }, /* 1000 MB */
2389 { 10*GB, 10737418.24, 100.0, 2, 'G' }, /* 10 GB */
2390 { 100*GB, 107374182.4, 10.0, 1, 'G' }, /* 100 GB */
2391 { 1000*GB, 1073741824.0, 1.0, 0, 'G' }, /* 1000 GB */
2392 { 10*TB, 10485.76, 100.0, 2, 'T' }, /* 10 TB */
2393 { 100*TB, 104857.6, 10.0, 1, 'T' }, /* 100 TB */
2394 { 1000*TB, 1048576.0, 1.0, 0, 'T' }, /* 1000 TB */
2395 { 10*PB, 10737418.24, 100.00, 2, 'P' }, /* 10 PB */
2396 { 100*PB, 107374182.4, 10.00, 1, 'P' }, /* 100 PB */
2397 { 1000*PB, 1073741824.0, 1.00, 0, 'P' }, /* 1000 PB */
2398 { 0, 10995116277.76, 100.00, 2, 'E' } /* EB's, catch all */
2400 WCHAR wszAdd[] = {' ','?','B',0};
2401 double dBytes;
2402 UINT i = 0;
2404 TRACE("(0x%s,%p,%d)\n", wine_dbgstr_longlong(llBytes), lpszDest, cchMax);
2406 if (!lpszDest || !cchMax)
2407 return lpszDest;
2409 if (llBytes < 1024) /* 1K */
2411 WCHAR wszBytesFormat[64];
2412 LoadStringW(shlwapi_hInstance, IDS_BYTES_FORMAT, wszBytesFormat, 64);
2413 snprintfW(lpszDest, cchMax, wszBytesFormat, (int)llBytes);
2414 return lpszDest;
2417 /* Note that if this loop completes without finding a match, i will be
2418 * pointing at the last entry, which is a catch all for > 1000 PB
2420 while (i < ARRAY_SIZE(bfFormats) - 1)
2422 if (llBytes < bfFormats[i].dLimit)
2423 break;
2424 i++;
2426 /* Above 1 TB we encounter problems with FP accuracy. So for amounts above
2427 * this number we integer shift down by 1 MB first. The table above has
2428 * the divisors scaled down from the '< 10 TB' entry onwards, to account
2429 * for this. We also add a small fudge factor to get the correct result for
2430 * counts that lie exactly on a 1024 byte boundary.
2432 if (i > 8)
2433 dBytes = (double)(llBytes >> 20) + 0.001; /* Scale down by 1 MB */
2434 else
2435 dBytes = (double)llBytes + 0.00001;
2437 dBytes = floor(dBytes / bfFormats[i].dDivisor) / bfFormats[i].dNormaliser;
2439 if (!FormatDouble(dBytes, bfFormats[i].nDecimals, lpszDest, cchMax))
2440 return NULL;
2441 wszAdd[1] = bfFormats[i].wPrefix;
2442 StrCatBuffW(lpszDest, wszAdd, cchMax);
2443 return lpszDest;
2446 /*************************************************************************
2447 * StrFormatByteSize64A [SHLWAPI.@]
2449 * See StrFormatByteSizeW.
2451 LPSTR WINAPI StrFormatByteSize64A(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax)
2453 WCHAR wszBuff[32];
2455 StrFormatByteSizeW(llBytes, wszBuff, ARRAY_SIZE(wszBuff));
2457 if (lpszDest)
2458 WideCharToMultiByte(CP_ACP, 0, wszBuff, -1, lpszDest, cchMax, 0, 0);
2459 return lpszDest;
2462 /*************************************************************************
2463 * StrFormatByteSizeA [SHLWAPI.@]
2465 * Create a string containing an abbreviated byte count of up to 2^31-1.
2467 * PARAMS
2468 * dwBytes [I] Byte size to format
2469 * lpszDest [I] Destination for formatted string
2470 * cchMax [I] Size of lpszDest
2472 * RETURNS
2473 * lpszDest.
2475 * NOTES
2476 * The Ascii and Unicode versions of this function accept a different
2477 * integer type for dwBytes. See StrFormatByteSize64A().
2479 LPSTR WINAPI StrFormatByteSizeA(DWORD dwBytes, LPSTR lpszDest, UINT cchMax)
2481 TRACE("(%d,%p,%d)\n", dwBytes, lpszDest, cchMax);
2483 return StrFormatByteSize64A(dwBytes, lpszDest, cchMax);
2486 /*************************************************************************
2487 * @ [SHLWAPI.162]
2489 * Remove a hanging lead byte from the end of a string, if present.
2491 * PARAMS
2492 * lpStr [I] String to check for a hanging lead byte
2493 * size [I] Length of lpStr
2495 * RETURNS
2496 * Success: The new length of the string. Any hanging lead bytes are removed.
2497 * Failure: 0, if any parameters are invalid.
2499 DWORD WINAPI SHTruncateString(LPSTR lpStr, DWORD size)
2501 if (lpStr && size)
2503 LPSTR lastByte = lpStr + size - 1;
2505 while(lpStr < lastByte)
2506 lpStr += IsDBCSLeadByte(*lpStr) ? 2 : 1;
2508 if(lpStr == lastByte && IsDBCSLeadByte(*lpStr))
2510 *lpStr = '\0';
2511 size--;
2513 return size;
2515 return 0;
2518 /*************************************************************************
2519 * @ [SHLWAPI.203]
2521 * Remove a single non-trailing ampersand ('&') from a string.
2523 * PARAMS
2524 * lpszStr [I/O] String to remove ampersand from.
2526 * RETURNS
2527 * The character after the first ampersand in lpszStr, or the first character
2528 * in lpszStr if there is no ampersand in the string.
2530 char WINAPI SHStripMneumonicA(LPCSTR lpszStr)
2532 LPSTR lpszIter, lpszTmp;
2533 char ch;
2535 TRACE("(%s)\n", debugstr_a(lpszStr));
2537 ch = *lpszStr;
2539 if ((lpszIter = StrChrA(lpszStr, '&')))
2541 lpszTmp = CharNextA(lpszIter);
2542 if (*lpszTmp)
2544 if (*lpszTmp != '&')
2545 ch = *lpszTmp;
2547 memmove( lpszIter, lpszTmp, strlen(lpszTmp) + 1 );
2551 return ch;
2554 /*************************************************************************
2555 * @ [SHLWAPI.225]
2557 * Unicode version of SHStripMneumonicA.
2559 WCHAR WINAPI SHStripMneumonicW(LPCWSTR lpszStr)
2561 LPWSTR lpszIter, lpszTmp;
2562 WCHAR ch;
2564 TRACE("(%s)\n", debugstr_w(lpszStr));
2566 ch = *lpszStr;
2568 if ((lpszIter = StrChrW(lpszStr, '&')))
2570 lpszTmp = lpszIter + 1;
2571 if (*lpszTmp)
2573 if (*lpszTmp != '&')
2574 ch = *lpszTmp;
2576 memmove( lpszIter, lpszTmp, (strlenW(lpszTmp) + 1) * sizeof(WCHAR) );
2580 return ch;
2583 /*************************************************************************
2584 * @ [SHLWAPI.216]
2586 * Convert an Ascii string to Unicode.
2588 * PARAMS
2589 * dwCp [I] Code page for the conversion
2590 * lpSrcStr [I] Source Ascii string to convert
2591 * lpDstStr [O] Destination for converted Unicode string
2592 * iLen [I] Length of lpDstStr
2594 * RETURNS
2595 * The return value of the MultiByteToWideChar() function called on lpSrcStr.
2597 DWORD WINAPI SHAnsiToUnicodeCP(DWORD dwCp, LPCSTR lpSrcStr, LPWSTR lpDstStr, int iLen)
2599 DWORD dwRet;
2601 dwRet = MultiByteToWideChar(dwCp, 0, lpSrcStr, -1, lpDstStr, iLen);
2602 TRACE("%s->%s,ret=%d\n", debugstr_a(lpSrcStr), debugstr_w(lpDstStr), dwRet);
2603 return dwRet;
2606 /*************************************************************************
2607 * @ [SHLWAPI.215]
2609 * Convert an Ascii string to Unicode.
2611 * PARAMS
2612 * lpSrcStr [I] Source Ascii string to convert
2613 * lpDstStr [O] Destination for converted Unicode string
2614 * iLen [I] Length of lpDstStr
2616 * RETURNS
2617 * The return value of the MultiByteToWideChar() function called on lpSrcStr.
2619 * NOTES
2620 * This function simply calls SHAnsiToUnicodeCP with code page CP_ACP.
2622 DWORD WINAPI SHAnsiToUnicode(LPCSTR lpSrcStr, LPWSTR lpDstStr, int iLen)
2624 return SHAnsiToUnicodeCP(CP_ACP, lpSrcStr, lpDstStr, iLen);
2627 /*************************************************************************
2628 * @ [SHLWAPI.218]
2630 * Convert a Unicode string to Ascii.
2632 * PARAMS
2633 * CodePage [I] Code page to use for the conversion
2634 * lpSrcStr [I] Source Unicode string to convert
2635 * lpDstStr [O] Destination for converted Ascii string
2636 * dstlen [I] Length of buffer at lpDstStr
2638 * RETURNS
2639 * Success: The length in bytes of the result at lpDstStr (including the terminator)
2640 * Failure: When using CP_UTF8, CP_UTF7 or 0xc350 as codePage, 0 is returned and
2641 * the result is not nul-terminated.
2642 * When using a different codepage, the length in bytes of the truncated
2643 * result at lpDstStr (including the terminator) is returned and
2644 * lpDstStr is always nul-terminated.
2647 DWORD WINAPI SHUnicodeToAnsiCP(UINT CodePage, LPCWSTR lpSrcStr, LPSTR lpDstStr, int dstlen)
2649 static const WCHAR emptyW[] = { '\0' };
2650 int len , reqLen;
2651 LPSTR mem;
2653 if (!lpDstStr || !dstlen)
2654 return 0;
2656 if (!lpSrcStr)
2657 lpSrcStr = emptyW;
2659 *lpDstStr = '\0';
2661 len = strlenW(lpSrcStr) + 1;
2663 switch (CodePage)
2665 case CP_WINUNICODE:
2666 CodePage = CP_UTF8; /* Fall through... */
2667 case 0x0000C350: /* FIXME: CP_ #define */
2668 case CP_UTF7:
2669 case CP_UTF8:
2671 DWORD dwMode = 0;
2672 INT lenW = len - 1;
2673 INT needed = dstlen - 1;
2674 HRESULT hr;
2676 /* try the user supplied buffer first */
2677 hr = ConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &lenW, lpDstStr, &needed);
2678 if (hr == S_OK)
2680 lpDstStr[needed] = '\0';
2681 return needed + 1;
2684 /* user buffer too small. exclude termination and copy as much as possible */
2685 lenW = len;
2686 hr = ConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &lenW, NULL, &needed);
2687 needed++;
2688 mem = HeapAlloc(GetProcessHeap(), 0, needed);
2689 if (!mem)
2690 return 0;
2692 hr = ConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &len, mem, &needed);
2693 if (hr == S_OK)
2695 reqLen = SHTruncateString(mem, dstlen);
2696 if (reqLen > 0) memcpy(lpDstStr, mem, reqLen-1);
2698 HeapFree(GetProcessHeap(), 0, mem);
2699 return 0;
2701 default:
2702 break;
2705 /* try the user supplied buffer first */
2706 reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, lpDstStr, dstlen, NULL, NULL);
2708 if (!reqLen && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
2710 reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, NULL, 0, NULL, NULL);
2711 if (reqLen)
2713 mem = HeapAlloc(GetProcessHeap(), 0, reqLen);
2714 if (mem)
2716 WideCharToMultiByte(CodePage, 0, lpSrcStr, len, mem, reqLen, NULL, NULL);
2718 reqLen = SHTruncateString(mem, dstlen -1);
2719 reqLen++;
2721 lstrcpynA(lpDstStr, mem, reqLen);
2722 HeapFree(GetProcessHeap(), 0, mem);
2723 lpDstStr[reqLen-1] = '\0';
2727 return reqLen;
2730 /*************************************************************************
2731 * @ [SHLWAPI.217]
2733 * Convert a Unicode string to Ascii.
2735 * PARAMS
2736 * lpSrcStr [I] Source Unicode string to convert
2737 * lpDstStr [O] Destination for converted Ascii string
2738 * iLen [O] Length of lpDstStr in characters
2740 * RETURNS
2741 * See SHUnicodeToAnsiCP
2743 * NOTES
2744 * This function simply calls SHUnicodeToAnsiCP() with CodePage = CP_ACP.
2746 INT WINAPI SHUnicodeToAnsi(LPCWSTR lpSrcStr, LPSTR lpDstStr, INT iLen)
2748 return SHUnicodeToAnsiCP(CP_ACP, lpSrcStr, lpDstStr, iLen);
2751 /*************************************************************************
2752 * @ [SHLWAPI.364]
2754 * Determine if an Ascii string converts to Unicode and back identically.
2756 * PARAMS
2757 * lpSrcStr [I] Source Unicode string to convert
2758 * lpDst [O] Destination for resulting Ascii string
2759 * iLen [I] Length of lpDst in characters
2761 * RETURNS
2762 * TRUE, since Ascii strings always convert identically.
2764 BOOL WINAPI DoesStringRoundTripA(LPCSTR lpSrcStr, LPSTR lpDst, INT iLen)
2766 lstrcpynA(lpDst, lpSrcStr, iLen);
2767 return TRUE;
2770 /*************************************************************************
2771 * @ [SHLWAPI.365]
2773 * Determine if a Unicode string converts to Ascii and back identically.
2775 * PARAMS
2776 * lpSrcStr [I] Source Unicode string to convert
2777 * lpDst [O] Destination for resulting Ascii string
2778 * iLen [I] Length of lpDst in characters
2780 * RETURNS
2781 * TRUE, if lpSrcStr converts to Ascii and back identically,
2782 * FALSE otherwise.
2784 BOOL WINAPI DoesStringRoundTripW(LPCWSTR lpSrcStr, LPSTR lpDst, INT iLen)
2786 WCHAR szBuff[MAX_PATH];
2788 SHUnicodeToAnsi(lpSrcStr, lpDst, iLen);
2789 SHAnsiToUnicode(lpDst, szBuff, MAX_PATH);
2790 return !strcmpW(lpSrcStr, szBuff);
2793 /*************************************************************************
2794 * SHLoadIndirectString [SHLWAPI.@]
2796 * If passed a string that begins with '@', extract the string from the
2797 * appropriate resource, otherwise do a straight copy.
2800 HRESULT WINAPI SHLoadIndirectString(LPCWSTR src, LPWSTR dst, UINT dst_len, void **reserved)
2802 WCHAR *dllname = NULL;
2803 HMODULE hmod = NULL;
2804 HRESULT hr = E_FAIL;
2806 TRACE("(%s %p %08x %p)\n", debugstr_w(src), dst, dst_len, reserved);
2808 if(src[0] == '@')
2810 WCHAR *index_str;
2811 int index;
2813 dst[0] = 0;
2814 dllname = StrDupW(src + 1);
2815 index_str = strchrW(dllname, ',');
2817 if(!index_str) goto end;
2819 *index_str = 0;
2820 index_str++;
2821 index = atoiW(index_str);
2823 hmod = LoadLibraryW(dllname);
2824 if(!hmod) goto end;
2826 if(index < 0)
2828 if(LoadStringW(hmod, -index, dst, dst_len))
2829 hr = S_OK;
2831 else
2832 FIXME("can't handle non-negative indices (%d)\n", index);
2834 else
2836 if(dst != src)
2837 lstrcpynW(dst, src, dst_len);
2838 hr = S_OK;
2841 TRACE("returning %s\n", debugstr_w(dst));
2842 end:
2843 if(hmod) FreeLibrary(hmod);
2844 LocalFree(dllname);
2845 return hr;
2848 BOOL WINAPI IsCharSpaceA(CHAR c)
2850 WORD CharType;
2851 return GetStringTypeA(GetSystemDefaultLCID(), CT_CTYPE1, &c, 1, &CharType) && (CharType & C1_SPACE);
2854 /*************************************************************************
2855 * @ [SHLWAPI.29]
2857 * Determine if a Unicode character is a space.
2859 * PARAMS
2860 * wc [I] Character to check.
2862 * RETURNS
2863 * TRUE, if wc is a space,
2864 * FALSE otherwise.
2866 BOOL WINAPI IsCharSpaceW(WCHAR wc)
2868 WORD CharType;
2870 return GetStringTypeW(CT_CTYPE1, &wc, 1, &CharType) && (CharType & C1_SPACE);