riched20: Don't apply paragraph formatting until the end of paragraph.
[wine.git] / dlls / shlwapi / string.c
blob4d77c3f2e992265a3e97c19196cf87fbcf03b0e5
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, sizeof(grouping)/sizeof(WCHAR));
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, sizeof decimal / sizeof (WCHAR),
105 thousand, sizeof thousand / sizeof (WCHAR));
107 c = &buf[24];
108 *(--c) = 0;
111 *(--c) = '0' + (qdwValue%10);
112 qdwValue /= 10;
113 } while (qdwValue > 0);
114 if (neg)
115 *(--c) = '-';
117 return GetNumberFormatW(LOCALE_USER_DEFAULT, 0, c, &fmt, pszBuf, cchBuf);
120 /*************************************************************************
121 * FormatDouble [internal]
123 * Format an integer according to the current locale. Prints the specified number of digits
124 * after the decimal point
126 * RETURNS
127 * The number of characters written on success or 0 on failure
129 static int FormatDouble(double value, int decimals, LPWSTR pszBuf, int cchBuf)
131 static const WCHAR flfmt[] = {'%','f',0};
132 WCHAR buf[64];
133 NUMBERFMTW fmt;
134 WCHAR decimal[8], thousand[8];
136 snprintfW(buf, 64, flfmt, value);
138 FillNumberFmt(&fmt, decimal, sizeof decimal / sizeof (WCHAR),
139 thousand, sizeof thousand / sizeof (WCHAR));
140 fmt.NumDigits = decimals;
141 return GetNumberFormatW(LOCALE_USER_DEFAULT, 0, buf, &fmt, pszBuf, cchBuf);
144 /*************************************************************************
145 * SHLWAPI_ChrCmpHelperA
147 * Internal helper for SHLWAPI_ChrCmpA/ChrCMPIA.
149 * NOTES
150 * Both this function and its Unicode counterpart are very inefficient. To
151 * fix this, CompareString must be completely implemented and optimised
152 * first. Then the core character test can be taken out of that function and
153 * placed here, so that it need never be called at all. Until then, do not
154 * attempt to optimise this code unless you are willing to test that it
155 * still performs correctly.
157 static BOOL SHLWAPI_ChrCmpHelperA(WORD ch1, WORD ch2, DWORD dwFlags)
159 char str1[3], str2[3];
161 str1[0] = LOBYTE(ch1);
162 if (IsDBCSLeadByte(str1[0]))
164 str1[1] = HIBYTE(ch1);
165 str1[2] = '\0';
167 else
168 str1[1] = '\0';
170 str2[0] = LOBYTE(ch2);
171 if (IsDBCSLeadByte(str2[0]))
173 str2[1] = HIBYTE(ch2);
174 str2[2] = '\0';
176 else
177 str2[1] = '\0';
179 return CompareStringA(GetThreadLocale(), dwFlags, str1, -1, str2, -1) - CSTR_EQUAL;
182 /*************************************************************************
183 * SHLWAPI_ChrCmpA
185 * Internal helper function.
187 static BOOL WINAPI SHLWAPI_ChrCmpA(WORD ch1, WORD ch2)
189 return SHLWAPI_ChrCmpHelperA(ch1, ch2, 0);
192 /*************************************************************************
193 * ChrCmpIA (SHLWAPI.385)
195 * Compare two characters, ignoring case.
197 * PARAMS
198 * ch1 [I] First character to compare
199 * ch2 [I] Second character to compare
201 * RETURNS
202 * FALSE, if the characters are equal.
203 * Non-zero otherwise.
205 BOOL WINAPI ChrCmpIA(WORD ch1, WORD ch2)
207 TRACE("(%d,%d)\n", ch1, ch2);
209 return SHLWAPI_ChrCmpHelperA(ch1, ch2, NORM_IGNORECASE);
212 /*************************************************************************
213 * ChrCmpIW [SHLWAPI.386]
215 * See ChrCmpIA.
217 BOOL WINAPI ChrCmpIW(WCHAR ch1, WCHAR ch2)
219 return CompareStringW(GetThreadLocale(), NORM_IGNORECASE, &ch1, 1, &ch2, 1) - CSTR_EQUAL;
222 /*************************************************************************
223 * StrChrA [SHLWAPI.@]
225 * Find a given character in a string.
227 * PARAMS
228 * lpszStr [I] String to search in.
229 * ch [I] Character to search for.
231 * RETURNS
232 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
233 * not found.
234 * Failure: NULL, if any arguments are invalid.
236 LPSTR WINAPI StrChrA(LPCSTR lpszStr, WORD ch)
238 TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch);
240 if (lpszStr)
242 while (*lpszStr)
244 if (!SHLWAPI_ChrCmpA(*lpszStr, ch))
245 return (LPSTR)lpszStr;
246 lpszStr = CharNextA(lpszStr);
249 return NULL;
252 /*************************************************************************
253 * StrChrW [SHLWAPI.@]
255 * See StrChrA.
257 LPWSTR WINAPI StrChrW(LPCWSTR lpszStr, WCHAR ch)
259 LPWSTR lpszRet = NULL;
261 TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch);
263 if (lpszStr)
264 lpszRet = strchrW(lpszStr, ch);
265 return lpszRet;
268 /*************************************************************************
269 * StrChrIA [SHLWAPI.@]
271 * Find a given character in a string, ignoring case.
273 * PARAMS
274 * lpszStr [I] String to search in.
275 * ch [I] Character to search for.
277 * RETURNS
278 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
279 * not found.
280 * Failure: NULL, if any arguments are invalid.
282 LPSTR WINAPI StrChrIA(LPCSTR lpszStr, WORD ch)
284 TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch);
286 if (lpszStr)
288 while (*lpszStr)
290 if (!ChrCmpIA(*lpszStr, ch))
291 return (LPSTR)lpszStr;
292 lpszStr = CharNextA(lpszStr);
295 return NULL;
298 /*************************************************************************
299 * StrChrIW [SHLWAPI.@]
301 * See StrChrA.
303 LPWSTR WINAPI StrChrIW(LPCWSTR lpszStr, WCHAR ch)
305 TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch);
307 if (lpszStr)
309 ch = toupperW(ch);
310 while (*lpszStr)
312 if (toupperW(*lpszStr) == ch)
313 return (LPWSTR)lpszStr;
314 lpszStr++;
316 lpszStr = NULL;
318 return (LPWSTR)lpszStr;
321 /*************************************************************************
322 * StrChrNW [SHLWAPI.@]
324 LPWSTR WINAPI StrChrNW(LPCWSTR lpszStr, WCHAR ch, UINT cchMax)
326 TRACE("(%s(%i),%i)\n", debugstr_wn(lpszStr,cchMax), cchMax, ch);
328 if (lpszStr)
330 while (*lpszStr && cchMax-- > 0)
332 if (*lpszStr == ch)
333 return (LPWSTR)lpszStr;
334 lpszStr++;
337 return NULL;
340 /*************************************************************************
341 * StrCmpIW [SHLWAPI.@]
343 * Compare two strings, ignoring case.
345 * PARAMS
346 * lpszStr [I] First string to compare
347 * lpszComp [I] Second string to compare
349 * RETURNS
350 * An integer less than, equal to or greater than 0, indicating that
351 * lpszStr is less than, the same, or greater than lpszComp.
353 int WINAPI StrCmpIW(LPCWSTR lpszStr, LPCWSTR lpszComp)
355 TRACE("(%s,%s)\n", debugstr_w(lpszStr),debugstr_w(lpszComp));
356 return CompareStringW(GetThreadLocale(), NORM_IGNORECASE, lpszStr, -1, lpszComp, -1) - CSTR_EQUAL;
359 /*************************************************************************
360 * StrCmpNA [SHLWAPI.@]
362 * Compare two strings, up to a maximum length.
364 * PARAMS
365 * lpszStr [I] First string to compare
366 * lpszComp [I] Second string to compare
367 * iLen [I] Number of chars to compare
369 * RETURNS
370 * An integer less than, equal to or greater than 0, indicating that
371 * lpszStr is less than, the same, or greater than lpszComp.
373 INT WINAPI StrCmpNA(LPCSTR lpszStr, LPCSTR lpszComp, INT iLen)
375 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
376 return CompareStringA(GetThreadLocale(), 0, lpszStr, iLen, lpszComp, iLen) - CSTR_EQUAL;
379 /*************************************************************************
380 * StrCmpNW [SHLWAPI.@]
382 * See StrCmpNA.
384 INT WINAPI StrCmpNW(LPCWSTR lpszStr, LPCWSTR lpszComp, INT iLen)
386 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen);
387 return CompareStringW(GetThreadLocale(), 0, lpszStr, iLen, lpszComp, iLen) - CSTR_EQUAL;
390 /*************************************************************************
391 * StrCmpNIA [SHLWAPI.@]
393 * Compare two strings, up to a maximum length, ignoring case.
395 * PARAMS
396 * lpszStr [I] First string to compare
397 * lpszComp [I] Second string to compare
398 * iLen [I] Number of chars to compare
400 * RETURNS
401 * An integer less than, equal to or greater than 0, indicating that
402 * lpszStr is less than, the same, or greater than lpszComp.
404 int WINAPI StrCmpNIA(LPCSTR lpszStr, LPCSTR lpszComp, int iLen)
406 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
407 return CompareStringA(GetThreadLocale(), NORM_IGNORECASE, lpszStr, iLen, lpszComp, iLen) - CSTR_EQUAL;
410 /*************************************************************************
411 * StrCmpNIW [SHLWAPI.@]
413 * See StrCmpNIA.
415 INT WINAPI StrCmpNIW(LPCWSTR lpszStr, LPCWSTR lpszComp, int iLen)
417 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen);
418 return CompareStringW(GetThreadLocale(), NORM_IGNORECASE, lpszStr, iLen, lpszComp, iLen) - CSTR_EQUAL;
421 /*************************************************************************
422 * StrCmpW [SHLWAPI.@]
424 * Compare two strings.
426 * PARAMS
427 * lpszStr [I] First string to compare
428 * lpszComp [I] Second string to compare
430 * RETURNS
431 * An integer less than, equal to or greater than 0, indicating that
432 * lpszStr is less than, the same, or greater than lpszComp.
434 int WINAPI StrCmpW(LPCWSTR lpszStr, LPCWSTR lpszComp)
436 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszComp));
437 return CompareStringW(GetThreadLocale(), 0, lpszStr, -1, lpszComp, -1) - CSTR_EQUAL;
440 /*************************************************************************
441 * StrCatW [SHLWAPI.@]
443 * Concatenate two strings.
445 * PARAMS
446 * lpszStr [O] Initial string
447 * lpszSrc [I] String to concatenate
449 * RETURNS
450 * lpszStr.
452 LPWSTR WINAPI StrCatW(LPWSTR lpszStr, LPCWSTR lpszSrc)
454 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSrc));
456 if (lpszStr && lpszSrc)
457 strcatW(lpszStr, lpszSrc);
458 return lpszStr;
461 /*************************************************************************
462 * StrCatChainW [SHLWAPI.@]
464 * Concatenates two unicode strings.
466 * PARAMS
467 * lpszStr [O] Initial string
468 * cchMax [I] Length of destination buffer
469 * ichAt [I] Offset from the destination buffer to begin concatenation
470 * lpszCat [I] String to concatenate
472 * RETURNS
473 * The offset from the beginning of pszDst to the terminating NULL.
475 DWORD WINAPI StrCatChainW(LPWSTR lpszStr, DWORD cchMax, DWORD ichAt, LPCWSTR lpszCat)
477 TRACE("(%s,%u,%d,%s)\n", debugstr_w(lpszStr), cchMax, ichAt, debugstr_w(lpszCat));
479 if (ichAt == -1)
480 ichAt = strlenW(lpszStr);
482 if (!cchMax)
483 return ichAt;
485 if (ichAt == cchMax)
486 ichAt--;
488 if (lpszCat && ichAt < cchMax)
490 lpszStr += ichAt;
491 while (ichAt < cchMax - 1 && *lpszCat)
493 *lpszStr++ = *lpszCat++;
494 ichAt++;
496 *lpszStr = 0;
499 return ichAt;
502 /*************************************************************************
503 * StrCpyW [SHLWAPI.@]
505 * Copy a string to another string.
507 * PARAMS
508 * lpszStr [O] Destination string
509 * lpszSrc [I] Source string
511 * RETURNS
512 * lpszStr.
514 LPWSTR WINAPI StrCpyW(LPWSTR lpszStr, LPCWSTR lpszSrc)
516 TRACE("(%p,%s)\n", lpszStr, debugstr_w(lpszSrc));
518 if (lpszStr && lpszSrc)
519 strcpyW(lpszStr, lpszSrc);
520 return lpszStr;
523 /*************************************************************************
524 * StrCpyNW [SHLWAPI.@]
526 * Copy a string to another string, up to a maximum number of characters.
528 * PARAMS
529 * dst [O] Destination string
530 * src [I] Source string
531 * count [I] Maximum number of chars to copy
533 * RETURNS
534 * dst.
536 LPWSTR WINAPI StrCpyNW(LPWSTR dst, LPCWSTR src, int count)
538 LPWSTR d = dst;
539 LPCWSTR s = src;
541 TRACE("(%p,%s,%i)\n", dst, debugstr_w(src), count);
543 if (s)
545 while ((count > 1) && *s)
547 count--;
548 *d++ = *s++;
551 if (count) *d = 0;
553 return dst;
556 /*************************************************************************
557 * SHLWAPI_StrStrHelperA
559 * Internal implementation of StrStrA/StrStrIA
561 static LPSTR SHLWAPI_StrStrHelperA(LPCSTR lpszStr, LPCSTR lpszSearch,
562 INT (WINAPI *pStrCmpFn)(LPCSTR,LPCSTR,INT))
564 size_t iLen;
565 LPCSTR end;
567 if (!lpszStr || !lpszSearch || !*lpszSearch)
568 return NULL;
570 iLen = strlen(lpszSearch);
571 end = lpszStr + strlen(lpszStr);
573 while (lpszStr + iLen <= end)
575 if (!pStrCmpFn(lpszStr, lpszSearch, iLen))
576 return (LPSTR)lpszStr;
577 lpszStr = CharNextA(lpszStr);
579 return NULL;
582 /*************************************************************************
583 * StrStrA [SHLWAPI.@]
585 * Find a substring within a string.
587 * PARAMS
588 * lpszStr [I] String to search in
589 * lpszSearch [I] String to look for
591 * RETURNS
592 * The start of lpszSearch within lpszStr, or NULL if not found.
594 LPSTR WINAPI StrStrA(LPCSTR lpszStr, LPCSTR lpszSearch)
596 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
598 return SHLWAPI_StrStrHelperA(lpszStr, lpszSearch, StrCmpNA);
601 /*************************************************************************
602 * StrStrW [SHLWAPI.@]
604 * See StrStrA.
606 LPWSTR WINAPI StrStrW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
608 TRACE("(%s, %s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
610 if (!lpszStr || !lpszSearch || !*lpszSearch) return NULL;
611 return strstrW( lpszStr, lpszSearch );
614 /*************************************************************************
615 * StrRStrIA [SHLWAPI.@]
617 * Find the last occurrence of a substring within a string.
619 * PARAMS
620 * lpszStr [I] String to search in
621 * lpszEnd [I] End of lpszStr
622 * lpszSearch [I] String to look for
624 * RETURNS
625 * The last occurrence lpszSearch within lpszStr, or NULL if not found.
627 LPSTR WINAPI StrRStrIA(LPCSTR lpszStr, LPCSTR lpszEnd, LPCSTR lpszSearch)
629 LPSTR lpszRet = NULL;
630 WORD ch1, ch2;
631 INT iLen;
633 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
635 if (!lpszStr || !lpszSearch || !*lpszSearch)
636 return NULL;
638 if (IsDBCSLeadByte(*lpszSearch))
639 ch1 = *lpszSearch << 8 | (UCHAR)lpszSearch[1];
640 else
641 ch1 = *lpszSearch;
642 iLen = lstrlenA(lpszSearch);
644 if (!lpszEnd)
645 lpszEnd = lpszStr + lstrlenA(lpszStr);
646 else /* reproduce the broken behaviour on Windows */
647 lpszEnd += min(iLen - 1, lstrlenA(lpszEnd));
649 while (lpszStr + iLen <= lpszEnd && *lpszStr)
651 ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | (UCHAR)lpszStr[1] : *lpszStr;
652 if (!ChrCmpIA(ch1, ch2))
654 if (!StrCmpNIA(lpszStr, lpszSearch, iLen))
655 lpszRet = (LPSTR)lpszStr;
657 lpszStr = CharNextA(lpszStr);
659 return lpszRet;
662 /*************************************************************************
663 * StrRStrIW [SHLWAPI.@]
665 * See StrRStrIA.
667 LPWSTR WINAPI StrRStrIW(LPCWSTR lpszStr, LPCWSTR lpszEnd, LPCWSTR lpszSearch)
669 LPWSTR lpszRet = NULL;
670 INT iLen;
672 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
674 if (!lpszStr || !lpszSearch || !*lpszSearch)
675 return NULL;
677 iLen = strlenW(lpszSearch);
679 if (!lpszEnd)
680 lpszEnd = lpszStr + strlenW(lpszStr);
681 else /* reproduce the broken behaviour on Windows */
682 lpszEnd += min(iLen - 1, lstrlenW(lpszEnd));
684 while (lpszStr + iLen <= lpszEnd && *lpszStr)
686 if (!ChrCmpIW(*lpszSearch, *lpszStr))
688 if (!StrCmpNIW(lpszStr, lpszSearch, iLen))
689 lpszRet = (LPWSTR)lpszStr;
691 lpszStr++;
693 return lpszRet;
696 /*************************************************************************
697 * StrStrIA [SHLWAPI.@]
699 * Find a substring within a string, ignoring case.
701 * PARAMS
702 * lpszStr [I] String to search in
703 * lpszSearch [I] String to look for
705 * RETURNS
706 * The start of lpszSearch within lpszStr, or NULL if not found.
708 LPSTR WINAPI StrStrIA(LPCSTR lpszStr, LPCSTR lpszSearch)
710 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
712 return SHLWAPI_StrStrHelperA(lpszStr, lpszSearch, StrCmpNIA);
715 /*************************************************************************
716 * StrStrIW [SHLWAPI.@]
718 * See StrStrIA.
720 LPWSTR WINAPI StrStrIW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
722 int iLen;
723 LPCWSTR end;
725 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
727 if (!lpszStr || !lpszSearch || !*lpszSearch)
728 return NULL;
730 iLen = strlenW(lpszSearch);
731 end = lpszStr + strlenW(lpszStr);
733 while (lpszStr + iLen <= end)
735 if (!StrCmpNIW(lpszStr, lpszSearch, iLen))
736 return (LPWSTR)lpszStr;
737 lpszStr++;
739 return NULL;
742 /*************************************************************************
743 * StrStrNW [SHLWAPI.@]
745 * Find a substring within a string up to a given number of initial characters.
747 * PARAMS
748 * lpFirst [I] String to search in
749 * lpSrch [I] String to look for
750 * cchMax [I] Maximum number of initial search characters
752 * RETURNS
753 * The start of lpFirst within lpSrch, or NULL if not found.
755 LPWSTR WINAPI StrStrNW(LPCWSTR lpFirst, LPCWSTR lpSrch, UINT cchMax)
757 UINT i;
758 int len;
760 TRACE("(%s, %s, %u)\n", debugstr_w(lpFirst), debugstr_w(lpSrch), cchMax);
762 if (!lpFirst || !lpSrch || !*lpSrch || !cchMax)
763 return NULL;
765 len = strlenW(lpSrch);
767 for (i = cchMax; *lpFirst && (i > 0); i--, lpFirst++)
769 if (!strncmpW(lpFirst, lpSrch, len))
770 return (LPWSTR)lpFirst;
773 return NULL;
776 /*************************************************************************
777 * StrStrNIW [SHLWAPI.@]
779 * Find a substring within a string up to a given number of initial characters,
780 * ignoring case.
782 * PARAMS
783 * lpFirst [I] String to search in
784 * lpSrch [I] String to look for
785 * cchMax [I] Maximum number of initial search characters
787 * RETURNS
788 * The start of lpFirst within lpSrch, or NULL if not found.
790 LPWSTR WINAPI StrStrNIW(LPCWSTR lpFirst, LPCWSTR lpSrch, UINT cchMax)
792 UINT i;
793 int len;
795 TRACE("(%s, %s, %u)\n", debugstr_w(lpFirst), debugstr_w(lpSrch), cchMax);
797 if (!lpFirst || !lpSrch || !*lpSrch || !cchMax)
798 return NULL;
800 len = strlenW(lpSrch);
802 for (i = cchMax; *lpFirst && (i > 0); i--, lpFirst++)
804 if (!strncmpiW(lpFirst, lpSrch, len))
805 return (LPWSTR)lpFirst;
808 return NULL;
811 /*************************************************************************
812 * StrToIntA [SHLWAPI.@]
814 * Read a signed integer from a string.
816 * PARAMS
817 * lpszStr [I] String to read integer from
819 * RETURNS
820 * The signed integer value represented by the string, or 0 if no integer is
821 * present.
823 * NOTES
824 * No leading space is allowed before the number, although a leading '-' is.
826 int WINAPI StrToIntA(LPCSTR lpszStr)
828 int iRet = 0;
830 TRACE("(%s)\n", debugstr_a(lpszStr));
832 if (!lpszStr)
834 WARN("Invalid lpszStr would crash under Win32!\n");
835 return 0;
838 if (*lpszStr == '-' || isdigit(*lpszStr))
839 StrToIntExA(lpszStr, 0, &iRet);
840 return iRet;
843 /*************************************************************************
844 * StrToIntW [SHLWAPI.@]
846 * See StrToIntA.
848 int WINAPI StrToIntW(LPCWSTR lpszStr)
850 int iRet = 0;
852 TRACE("(%s)\n", debugstr_w(lpszStr));
854 if (!lpszStr)
856 WARN("Invalid lpszStr would crash under Win32!\n");
857 return 0;
860 if (*lpszStr == '-' || isdigitW(*lpszStr))
861 StrToIntExW(lpszStr, 0, &iRet);
862 return iRet;
865 /*************************************************************************
866 * StrToIntExA [SHLWAPI.@]
868 * Read an integer from a string.
870 * PARAMS
871 * lpszStr [I] String to read integer from
872 * dwFlags [I] Flags controlling the conversion
873 * lpiRet [O] Destination for read integer.
875 * RETURNS
876 * Success: TRUE. lpiRet contains the integer value represented by the string.
877 * Failure: FALSE, if the string is invalid, or no number is present.
879 * NOTES
880 * Leading whitespace, '-' and '+' are allowed before the number. If
881 * dwFlags includes STIF_SUPPORT_HEX, hexadecimal numbers are allowed, if
882 * preceded by '0x'. If this flag is not set, or there is no '0x' prefix,
883 * the string is treated as a decimal string. A leading '-' is ignored for
884 * hexadecimal numbers.
886 BOOL WINAPI StrToIntExA(LPCSTR lpszStr, DWORD dwFlags, LPINT lpiRet)
888 LONGLONG li;
889 BOOL bRes;
891 TRACE("(%s,%08X,%p)\n", debugstr_a(lpszStr), dwFlags, lpiRet);
893 bRes = StrToInt64ExA(lpszStr, dwFlags, &li);
894 if (bRes) *lpiRet = li;
895 return bRes;
898 /*************************************************************************
899 * StrToInt64ExA [SHLWAPI.@]
901 * See StrToIntExA.
903 BOOL WINAPI StrToInt64ExA(LPCSTR lpszStr, DWORD dwFlags, LONGLONG *lpiRet)
905 BOOL bNegative = FALSE;
906 LONGLONG iRet = 0;
908 TRACE("(%s,%08X,%p)\n", debugstr_a(lpszStr), dwFlags, lpiRet);
910 if (!lpszStr || !lpiRet)
912 WARN("Invalid parameter would crash under Win32!\n");
913 return FALSE;
915 if (dwFlags > STIF_SUPPORT_HEX) WARN("Unknown flags %08x\n", dwFlags);
917 /* Skip leading space, '+', '-' */
918 while (isspace(*lpszStr))
919 lpszStr = CharNextA(lpszStr);
921 if (*lpszStr == '-')
923 bNegative = TRUE;
924 lpszStr++;
926 else if (*lpszStr == '+')
927 lpszStr++;
929 if (dwFlags & STIF_SUPPORT_HEX &&
930 *lpszStr == '0' && tolower(lpszStr[1]) == 'x')
932 /* Read hex number */
933 lpszStr += 2;
935 if (!isxdigit(*lpszStr))
936 return FALSE;
938 while (isxdigit(*lpszStr))
940 iRet = iRet * 16;
941 if (isdigit(*lpszStr))
942 iRet += (*lpszStr - '0');
943 else
944 iRet += 10 + (tolower(*lpszStr) - 'a');
945 lpszStr++;
947 *lpiRet = iRet;
948 return TRUE;
951 /* Read decimal number */
952 if (!isdigit(*lpszStr))
953 return FALSE;
955 while (isdigit(*lpszStr))
957 iRet = iRet * 10;
958 iRet += (*lpszStr - '0');
959 lpszStr++;
961 *lpiRet = bNegative ? -iRet : iRet;
962 return TRUE;
965 /*************************************************************************
966 * StrToIntExW [SHLWAPI.@]
968 * See StrToIntExA.
970 BOOL WINAPI StrToIntExW(LPCWSTR lpszStr, DWORD dwFlags, LPINT lpiRet)
972 LONGLONG li;
973 BOOL bRes;
975 TRACE("(%s,%08X,%p)\n", debugstr_w(lpszStr), dwFlags, lpiRet);
977 bRes = StrToInt64ExW(lpszStr, dwFlags, &li);
978 if (bRes) *lpiRet = li;
979 return bRes;
982 /*************************************************************************
983 * StrToInt64ExW [SHLWAPI.@]
985 * See StrToIntExA.
987 BOOL WINAPI StrToInt64ExW(LPCWSTR lpszStr, DWORD dwFlags, LONGLONG *lpiRet)
989 BOOL bNegative = FALSE;
990 LONGLONG iRet = 0;
992 TRACE("(%s,%08X,%p)\n", debugstr_w(lpszStr), dwFlags, lpiRet);
994 if (!lpszStr || !lpiRet)
996 WARN("Invalid parameter would crash under Win32!\n");
997 return FALSE;
999 if (dwFlags > STIF_SUPPORT_HEX) WARN("Unknown flags %08x\n", dwFlags);
1001 /* Skip leading space, '+', '-' */
1002 while (isspaceW(*lpszStr)) lpszStr++;
1004 if (*lpszStr == '-')
1006 bNegative = TRUE;
1007 lpszStr++;
1009 else if (*lpszStr == '+')
1010 lpszStr++;
1012 if (dwFlags & STIF_SUPPORT_HEX &&
1013 *lpszStr == '0' && tolowerW(lpszStr[1]) == 'x')
1015 /* Read hex number */
1016 lpszStr += 2;
1018 if (!isxdigitW(*lpszStr))
1019 return FALSE;
1021 while (isxdigitW(*lpszStr))
1023 iRet = iRet * 16;
1024 if (isdigitW(*lpszStr))
1025 iRet += (*lpszStr - '0');
1026 else
1027 iRet += 10 + (tolowerW(*lpszStr) - 'a');
1028 lpszStr++;
1030 *lpiRet = iRet;
1031 return TRUE;
1034 /* Read decimal number */
1035 if (!isdigitW(*lpszStr))
1036 return FALSE;
1038 while (isdigitW(*lpszStr))
1040 iRet = iRet * 10;
1041 iRet += (*lpszStr - '0');
1042 lpszStr++;
1044 *lpiRet = bNegative ? -iRet : iRet;
1045 return TRUE;
1048 /*************************************************************************
1049 * StrDupA [SHLWAPI.@]
1051 * Duplicate a string.
1053 * PARAMS
1054 * lpszStr [I] String to duplicate.
1056 * RETURNS
1057 * Success: A pointer to a new string containing the contents of lpszStr
1058 * Failure: NULL, if memory cannot be allocated
1060 * NOTES
1061 * The string memory is allocated with LocalAlloc(), and so should be released
1062 * by calling LocalFree().
1064 LPSTR WINAPI StrDupA(LPCSTR lpszStr)
1066 int iLen;
1067 LPSTR lpszRet;
1069 TRACE("(%s)\n",debugstr_a(lpszStr));
1071 iLen = lpszStr ? strlen(lpszStr) + 1 : 1;
1072 lpszRet = LocalAlloc(LMEM_FIXED, iLen);
1074 if (lpszRet)
1076 if (lpszStr)
1077 memcpy(lpszRet, lpszStr, iLen);
1078 else
1079 *lpszRet = '\0';
1081 return lpszRet;
1084 /*************************************************************************
1085 * StrDupW [SHLWAPI.@]
1087 * See StrDupA.
1089 LPWSTR WINAPI StrDupW(LPCWSTR lpszStr)
1091 int iLen;
1092 LPWSTR lpszRet;
1094 TRACE("(%s)\n",debugstr_w(lpszStr));
1096 iLen = (lpszStr ? strlenW(lpszStr) + 1 : 1) * sizeof(WCHAR);
1097 lpszRet = LocalAlloc(LMEM_FIXED, iLen);
1099 if (lpszRet)
1101 if (lpszStr)
1102 memcpy(lpszRet, lpszStr, iLen);
1103 else
1104 *lpszRet = '\0';
1106 return lpszRet;
1109 /*************************************************************************
1110 * SHLWAPI_StrSpnHelperA
1112 * Internal implementation of StrSpnA/StrCSpnA/StrCSpnIA
1114 static int SHLWAPI_StrSpnHelperA(LPCSTR lpszStr, LPCSTR lpszMatch,
1115 LPSTR (WINAPI *pStrChrFn)(LPCSTR,WORD),
1116 BOOL bInvert)
1118 LPCSTR lpszRead = lpszStr;
1119 if (lpszStr && *lpszStr && lpszMatch)
1121 while (*lpszRead)
1123 LPCSTR lpszTest = pStrChrFn(lpszMatch, *lpszRead);
1125 if (!bInvert && !lpszTest)
1126 break;
1127 if (bInvert && lpszTest)
1128 break;
1129 lpszRead = CharNextA(lpszRead);
1132 return lpszRead - lpszStr;
1135 /*************************************************************************
1136 * StrSpnA [SHLWAPI.@]
1138 * Find the length of the start of a string that contains only certain
1139 * characters.
1141 * PARAMS
1142 * lpszStr [I] String to search
1143 * lpszMatch [I] Characters that can be in the substring
1145 * RETURNS
1146 * The length of the part of lpszStr containing only chars from lpszMatch,
1147 * or 0 if any parameter is invalid.
1149 int WINAPI StrSpnA(LPCSTR lpszStr, LPCSTR lpszMatch)
1151 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1153 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, FALSE);
1156 /*************************************************************************
1157 * StrSpnW [SHLWAPI.@]
1159 * See StrSpnA.
1161 int WINAPI StrSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1163 if (!lpszStr || !lpszMatch) return 0;
1164 return strspnW( lpszStr, lpszMatch );
1167 /*************************************************************************
1168 * StrCSpnA [SHLWAPI.@]
1170 * Find the length of the start of a string that does not contain certain
1171 * characters.
1173 * PARAMS
1174 * lpszStr [I] String to search
1175 * lpszMatch [I] Characters that cannot be in the substring
1177 * RETURNS
1178 * The length of the part of lpszStr containing only chars not in lpszMatch,
1179 * or 0 if any parameter is invalid.
1181 int WINAPI StrCSpnA(LPCSTR lpszStr, LPCSTR lpszMatch)
1183 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1185 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, TRUE);
1188 /*************************************************************************
1189 * StrCSpnW [SHLWAPI.@]
1191 * See StrCSpnA.
1193 int WINAPI StrCSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1195 if (!lpszStr || !lpszMatch) return 0;
1196 return strcspnW( lpszStr, lpszMatch );
1199 /*************************************************************************
1200 * StrCSpnIA [SHLWAPI.@]
1202 * Find the length of the start of a string that does not contain certain
1203 * characters, ignoring case.
1205 * PARAMS
1206 * lpszStr [I] String to search
1207 * lpszMatch [I] Characters that cannot be in the substring
1209 * RETURNS
1210 * The length of the part of lpszStr containing only chars not in lpszMatch,
1211 * or 0 if any parameter is invalid.
1213 int WINAPI StrCSpnIA(LPCSTR lpszStr, LPCSTR lpszMatch)
1215 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1217 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrIA, TRUE);
1220 /*************************************************************************
1221 * StrCSpnIW [SHLWAPI.@]
1223 * See StrCSpnIA.
1225 int WINAPI StrCSpnIW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1227 LPCWSTR lpszRead = lpszStr;
1229 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1231 if (lpszStr && *lpszStr && lpszMatch)
1233 while (*lpszRead)
1235 if (StrChrIW(lpszMatch, *lpszRead)) break;
1236 lpszRead++;
1239 return lpszRead - lpszStr;
1242 /*************************************************************************
1243 * StrPBrkA [SHLWAPI.@]
1245 * Search a string for any of a group of characters.
1247 * PARAMS
1248 * lpszStr [I] String to search
1249 * lpszMatch [I] Characters to match
1251 * RETURNS
1252 * A pointer to the first matching character in lpszStr, or NULL if no
1253 * match was found.
1255 LPSTR WINAPI StrPBrkA(LPCSTR lpszStr, LPCSTR lpszMatch)
1257 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1259 if (lpszStr && lpszMatch && *lpszMatch)
1261 while (*lpszStr)
1263 if (StrChrA(lpszMatch, *lpszStr))
1264 return (LPSTR)lpszStr;
1265 lpszStr = CharNextA(lpszStr);
1268 return NULL;
1271 /*************************************************************************
1272 * StrPBrkW [SHLWAPI.@]
1274 * See StrPBrkA.
1276 LPWSTR WINAPI StrPBrkW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1278 if (!lpszStr || !lpszMatch) return NULL;
1279 return strpbrkW( lpszStr, lpszMatch );
1282 /*************************************************************************
1283 * SHLWAPI_StrRChrHelperA
1285 * Internal implementation of StrRChrA/StrRChrIA.
1287 static LPSTR SHLWAPI_StrRChrHelperA(LPCSTR lpszStr,
1288 LPCSTR lpszEnd, WORD ch,
1289 BOOL (WINAPI *pChrCmpFn)(WORD,WORD))
1291 LPCSTR lpszRet = NULL;
1293 if (lpszStr)
1295 WORD ch2;
1297 if (!lpszEnd)
1298 lpszEnd = lpszStr + lstrlenA(lpszStr);
1300 while (*lpszStr && lpszStr <= lpszEnd)
1302 ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr;
1304 if (!pChrCmpFn(ch, ch2))
1305 lpszRet = lpszStr;
1306 lpszStr = CharNextA(lpszStr);
1309 return (LPSTR)lpszRet;
1312 /**************************************************************************
1313 * StrRChrA [SHLWAPI.@]
1315 * Find the last occurrence of a character in string.
1317 * PARAMS
1318 * lpszStr [I] String to search in
1319 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1320 * ch [I] Character to search for.
1322 * RETURNS
1323 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1324 * or NULL if not found.
1325 * Failure: NULL, if any arguments are invalid.
1327 LPSTR WINAPI StrRChrA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch)
1329 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch);
1331 return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, SHLWAPI_ChrCmpA);
1334 /**************************************************************************
1335 * StrRChrW [SHLWAPI.@]
1337 * See StrRChrA.
1339 LPWSTR WINAPI StrRChrW(LPCWSTR str, LPCWSTR end, WORD ch)
1341 WCHAR *ret = NULL;
1343 if (!str) return NULL;
1344 if (!end) end = str + strlenW(str);
1345 while (str < end)
1347 if (*str == ch) ret = (WCHAR *)str;
1348 str++;
1350 return ret;
1353 /**************************************************************************
1354 * StrRChrIA [SHLWAPI.@]
1356 * Find the last occurrence of a character in string, ignoring case.
1358 * PARAMS
1359 * lpszStr [I] String to search in
1360 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1361 * ch [I] Character to search for.
1363 * RETURNS
1364 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1365 * or NULL if not found.
1366 * Failure: NULL, if any arguments are invalid.
1368 LPSTR WINAPI StrRChrIA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch)
1370 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch);
1372 return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, ChrCmpIA);
1375 /**************************************************************************
1376 * StrRChrIW [SHLWAPI.@]
1378 * See StrRChrIA.
1380 LPWSTR WINAPI StrRChrIW(LPCWSTR str, LPCWSTR end, WORD ch)
1382 WCHAR *ret = NULL;
1384 if (!str) return NULL;
1385 if (!end) end = str + strlenW(str);
1386 while (str < end)
1388 if (!ChrCmpIW(*str, ch)) ret = (WCHAR *)str;
1389 str++;
1391 return ret;
1394 /*************************************************************************
1395 * StrCatBuffA [SHLWAPI.@]
1397 * Concatenate two strings together.
1399 * PARAMS
1400 * lpszStr [O] String to concatenate to
1401 * lpszCat [I] String to add to lpszCat
1402 * cchMax [I] Maximum number of characters for the whole string
1404 * RETURNS
1405 * lpszStr.
1407 * NOTES
1408 * cchMax determines the number of characters in the final length of the
1409 * string, not the number appended to lpszStr from lpszCat.
1411 LPSTR WINAPI StrCatBuffA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax)
1413 INT iLen;
1415 TRACE("(%p,%s,%d)\n", lpszStr, debugstr_a(lpszCat), cchMax);
1417 if (!lpszStr)
1419 WARN("Invalid lpszStr would crash under Win32!\n");
1420 return NULL;
1423 iLen = strlen(lpszStr);
1424 cchMax -= iLen;
1426 if (cchMax > 0)
1427 StrCpyNA(lpszStr + iLen, lpszCat, cchMax);
1428 return lpszStr;
1431 /*************************************************************************
1432 * StrCatBuffW [SHLWAPI.@]
1434 * See StrCatBuffA.
1436 LPWSTR WINAPI StrCatBuffW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax)
1438 INT iLen;
1440 TRACE("(%p,%s,%d)\n", lpszStr, debugstr_w(lpszCat), cchMax);
1442 if (!lpszStr)
1444 WARN("Invalid lpszStr would crash under Win32!\n");
1445 return NULL;
1448 iLen = strlenW(lpszStr);
1449 cchMax -= iLen;
1451 if (cchMax > 0)
1452 StrCpyNW(lpszStr + iLen, lpszCat, cchMax);
1453 return lpszStr;
1456 /*************************************************************************
1457 * StrRetToBufA [SHLWAPI.@]
1459 * Convert a STRRET to a normal string.
1461 * PARAMS
1462 * lpStrRet [O] STRRET to convert
1463 * pIdl [I] ITEMIDLIST for lpStrRet->uType == STRRET_OFFSET
1464 * lpszDest [O] Destination for normal string
1465 * dwLen [I] Length of lpszDest
1467 * RETURNS
1468 * Success: S_OK. lpszDest contains up to dwLen characters of the string.
1469 * If lpStrRet is of type STRRET_WSTR, its memory is freed with
1470 * CoTaskMemFree() and its type set to STRRET_CSTRA.
1471 * Failure: E_FAIL, if any parameters are invalid.
1473 HRESULT WINAPI StrRetToBufA (LPSTRRET src, const ITEMIDLIST *pidl, LPSTR dest, UINT len)
1475 /* NOTE:
1476 * This routine is identical to that in dlls/shell32/shellstring.c.
1477 * It was duplicated because not every version of Shlwapi.dll exports
1478 * StrRetToBufA. If you change one routine, change them both.
1480 TRACE("dest=%p len=0x%x strret=%p pidl=%p\n", dest, len, src, pidl);
1482 if (!src)
1484 WARN("Invalid lpStrRet would crash under Win32!\n");
1485 if (dest)
1486 *dest = '\0';
1487 return E_FAIL;
1490 if (!dest || !len)
1491 return E_FAIL;
1493 *dest = '\0';
1495 switch (src->uType)
1497 case STRRET_WSTR:
1498 WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, dest, len, NULL, NULL);
1499 CoTaskMemFree(src->u.pOleStr);
1500 break;
1502 case STRRET_CSTR:
1503 lstrcpynA(dest, src->u.cStr, len);
1504 break;
1506 case STRRET_OFFSET:
1507 lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len);
1508 break;
1510 default:
1511 FIXME("unknown type!\n");
1512 return FALSE;
1514 return S_OK;
1517 /*************************************************************************
1518 * StrRetToBufW [SHLWAPI.@]
1520 * See StrRetToBufA.
1522 HRESULT WINAPI StrRetToBufW (LPSTRRET src, const ITEMIDLIST *pidl, LPWSTR dest, UINT len)
1524 TRACE("dest=%p len=0x%x strret=%p pidl=%p\n", dest, len, src, pidl);
1526 if (!src)
1528 WARN("Invalid lpStrRet would crash under Win32!\n");
1529 if (dest)
1530 *dest = '\0';
1531 return E_FAIL;
1534 if (!dest || !len)
1535 return E_FAIL;
1537 *dest = '\0';
1539 switch (src->uType)
1541 case STRRET_WSTR:
1542 lstrcpynW(dest, src->u.pOleStr, len);
1543 CoTaskMemFree(src->u.pOleStr);
1544 break;
1546 case STRRET_CSTR:
1547 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ))
1548 dest[len-1] = 0;
1549 break;
1551 case STRRET_OFFSET:
1552 if (pidl)
1554 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1,
1555 dest, len ))
1556 dest[len-1] = 0;
1558 break;
1560 default:
1561 FIXME("unknown type!\n");
1562 return FALSE;
1564 return S_OK;
1567 /*************************************************************************
1568 * StrRetToStrA [SHLWAPI.@]
1570 * Converts a STRRET to a normal string.
1572 * PARAMS
1573 * lpStrRet [O] STRRET to convert
1574 * pidl [I] ITEMIDLIST for lpStrRet->uType == STRRET_OFFSET
1575 * ppszName [O] Destination for converted string
1577 * RETURNS
1578 * Success: S_OK. ppszName contains the new string, allocated with CoTaskMemAlloc().
1579 * Failure: E_FAIL, if any parameters are invalid.
1581 HRESULT WINAPI StrRetToStrA(LPSTRRET lpStrRet, const ITEMIDLIST *pidl, LPSTR *ppszName)
1583 HRESULT hRet = E_FAIL;
1585 switch (lpStrRet->uType)
1587 case STRRET_WSTR:
1588 hRet = _SHStrDupAW(lpStrRet->u.pOleStr, ppszName);
1589 CoTaskMemFree(lpStrRet->u.pOleStr);
1590 break;
1592 case STRRET_CSTR:
1593 hRet = _SHStrDupAA(lpStrRet->u.cStr, ppszName);
1594 break;
1596 case STRRET_OFFSET:
1597 hRet = _SHStrDupAA(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, ppszName);
1598 break;
1600 default:
1601 *ppszName = NULL;
1604 return hRet;
1607 /*************************************************************************
1608 * StrRetToStrW [SHLWAPI.@]
1610 * See StrRetToStrA.
1612 HRESULT WINAPI StrRetToStrW(LPSTRRET lpStrRet, const ITEMIDLIST *pidl, LPWSTR *ppszName)
1614 HRESULT hRet = E_FAIL;
1616 switch (lpStrRet->uType)
1618 case STRRET_WSTR:
1619 hRet = SHStrDupW(lpStrRet->u.pOleStr, ppszName);
1620 CoTaskMemFree(lpStrRet->u.pOleStr);
1621 break;
1623 case STRRET_CSTR:
1624 hRet = SHStrDupA(lpStrRet->u.cStr, ppszName);
1625 break;
1627 case STRRET_OFFSET:
1628 hRet = SHStrDupA(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, ppszName);
1629 break;
1631 default:
1632 *ppszName = NULL;
1635 return hRet;
1638 /* Create an ASCII string copy using SysAllocString() */
1639 static HRESULT _SHStrDupAToBSTR(LPCSTR src, BSTR *pBstrOut)
1641 *pBstrOut = NULL;
1643 if (src)
1645 INT len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0);
1646 WCHAR* szTemp = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1648 if (szTemp)
1650 MultiByteToWideChar(CP_ACP, 0, src, -1, szTemp, len);
1651 *pBstrOut = SysAllocString(szTemp);
1652 HeapFree(GetProcessHeap(), 0, szTemp);
1654 if (*pBstrOut)
1655 return S_OK;
1658 return E_OUTOFMEMORY;
1661 /*************************************************************************
1662 * StrRetToBSTR [SHLWAPI.@]
1664 * Converts a STRRET to a BSTR.
1666 * PARAMS
1667 * lpStrRet [O] STRRET to convert
1668 * pidl [I] ITEMIDLIST for lpStrRet->uType = STRRET_OFFSET
1669 * pBstrOut [O] Destination for converted BSTR
1671 * RETURNS
1672 * Success: S_OK. pBstrOut contains the new string.
1673 * Failure: E_FAIL, if any parameters are invalid.
1675 HRESULT WINAPI StrRetToBSTR(STRRET *lpStrRet, LPCITEMIDLIST pidl, BSTR* pBstrOut)
1677 HRESULT hRet = E_FAIL;
1679 switch (lpStrRet->uType)
1681 case STRRET_WSTR:
1682 *pBstrOut = SysAllocString(lpStrRet->u.pOleStr);
1683 if (*pBstrOut)
1684 hRet = S_OK;
1685 CoTaskMemFree(lpStrRet->u.pOleStr);
1686 break;
1688 case STRRET_CSTR:
1689 hRet = _SHStrDupAToBSTR(lpStrRet->u.cStr, pBstrOut);
1690 break;
1692 case STRRET_OFFSET:
1693 hRet = _SHStrDupAToBSTR(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, pBstrOut);
1694 break;
1696 default:
1697 *pBstrOut = NULL;
1700 return hRet;
1703 /*************************************************************************
1704 * StrFormatKBSizeA [SHLWAPI.@]
1706 * Create a formatted string containing a byte count in Kilobytes.
1708 * PARAMS
1709 * llBytes [I] Byte size to format
1710 * lpszDest [I] Destination for formatted string
1711 * cchMax [I] Size of lpszDest
1713 * RETURNS
1714 * lpszDest.
1716 LPSTR WINAPI StrFormatKBSizeA(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax)
1718 WCHAR wszBuf[256];
1720 if (!StrFormatKBSizeW(llBytes, wszBuf, 256))
1721 return NULL;
1722 if (!WideCharToMultiByte(CP_ACP, 0, wszBuf, -1, lpszDest, cchMax, NULL, NULL))
1723 return NULL;
1724 return lpszDest;
1727 /*************************************************************************
1728 * StrFormatKBSizeW [SHLWAPI.@]
1730 * See StrFormatKBSizeA.
1732 LPWSTR WINAPI StrFormatKBSizeW(LONGLONG llBytes, LPWSTR lpszDest, UINT cchMax)
1734 static const WCHAR kb[] = {' ','K','B',0};
1735 LONGLONG llKB = (llBytes + 1023) >> 10;
1736 int len;
1738 TRACE("(0x%s,%p,%d)\n", wine_dbgstr_longlong(llBytes), lpszDest, cchMax);
1740 if (!FormatInt(llKB, lpszDest, cchMax))
1741 return NULL;
1743 len = lstrlenW(lpszDest);
1744 if (cchMax - len < 4)
1745 return NULL;
1746 lstrcatW(lpszDest, kb);
1747 return lpszDest;
1750 /*************************************************************************
1751 * StrNCatA [SHLWAPI.@]
1753 * Concatenate two strings together.
1755 * PARAMS
1756 * lpszStr [O] String to concatenate to
1757 * lpszCat [I] String to add to lpszCat
1758 * cchMax [I] Maximum number of characters to concatenate
1760 * RETURNS
1761 * lpszStr.
1763 * NOTES
1764 * cchMax determines the number of characters that are appended to lpszStr,
1765 * not the total length of the string.
1767 LPSTR WINAPI StrNCatA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax)
1769 LPSTR lpszRet = lpszStr;
1771 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszCat), cchMax);
1773 if (!lpszStr)
1775 WARN("Invalid lpszStr would crash under Win32!\n");
1776 return NULL;
1779 StrCpyNA(lpszStr + strlen(lpszStr), lpszCat, cchMax);
1780 return lpszRet;
1783 /*************************************************************************
1784 * StrNCatW [SHLWAPI.@]
1786 * See StrNCatA.
1788 LPWSTR WINAPI StrNCatW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax)
1790 LPWSTR lpszRet = lpszStr;
1792 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszCat), cchMax);
1794 if (!lpszStr)
1796 WARN("Invalid lpszStr would crash under Win32\n");
1797 return NULL;
1800 StrCpyNW(lpszStr + strlenW(lpszStr), lpszCat, cchMax);
1801 return lpszRet;
1804 /*************************************************************************
1805 * StrTrimA [SHLWAPI.@]
1807 * Remove characters from the start and end of a string.
1809 * PARAMS
1810 * lpszStr [O] String to remove characters from
1811 * lpszTrim [I] Characters to remove from lpszStr
1813 * RETURNS
1814 * TRUE If lpszStr was valid and modified
1815 * FALSE Otherwise
1817 BOOL WINAPI StrTrimA(LPSTR lpszStr, LPCSTR lpszTrim)
1819 DWORD dwLen;
1820 LPSTR lpszRead = lpszStr;
1821 BOOL bRet = FALSE;
1823 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszTrim));
1825 if (lpszRead && *lpszRead)
1827 while (*lpszRead && StrChrA(lpszTrim, *lpszRead))
1828 lpszRead = CharNextA(lpszRead); /* Skip leading matches */
1830 dwLen = strlen(lpszRead);
1832 if (lpszRead != lpszStr)
1834 memmove(lpszStr, lpszRead, dwLen + 1);
1835 bRet = TRUE;
1837 if (dwLen > 0)
1839 lpszRead = lpszStr + dwLen;
1840 while (StrChrA(lpszTrim, lpszRead[-1]))
1841 lpszRead = CharPrevA(lpszStr, lpszRead); /* Skip trailing matches */
1843 if (lpszRead != lpszStr + dwLen)
1845 *lpszRead = '\0';
1846 bRet = TRUE;
1850 return bRet;
1853 /*************************************************************************
1854 * StrTrimW [SHLWAPI.@]
1856 * See StrTrimA.
1858 BOOL WINAPI StrTrimW(LPWSTR lpszStr, LPCWSTR lpszTrim)
1860 DWORD dwLen;
1861 LPWSTR lpszRead = lpszStr;
1862 BOOL bRet = FALSE;
1864 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszTrim));
1866 if (lpszRead && *lpszRead)
1868 while (*lpszRead && StrChrW(lpszTrim, *lpszRead)) lpszRead++;
1870 dwLen = strlenW(lpszRead);
1872 if (lpszRead != lpszStr)
1874 memmove(lpszStr, lpszRead, (dwLen + 1) * sizeof(WCHAR));
1875 bRet = TRUE;
1877 if (dwLen > 0)
1879 lpszRead = lpszStr + dwLen;
1880 while (StrChrW(lpszTrim, lpszRead[-1]))
1881 lpszRead--; /* Skip trailing matches */
1883 if (lpszRead != lpszStr + dwLen)
1885 *lpszRead = '\0';
1886 bRet = TRUE;
1890 return bRet;
1893 /*************************************************************************
1894 * _SHStrDupAA [INTERNAL]
1896 * Duplicates a ASCII string to ASCII. The destination buffer is allocated.
1898 static HRESULT _SHStrDupAA(LPCSTR src, LPSTR * dest)
1900 HRESULT hr;
1901 int len = 0;
1903 if (src) {
1904 len = lstrlenA(src) + 1;
1905 *dest = CoTaskMemAlloc(len);
1906 } else {
1907 *dest = NULL;
1910 if (*dest) {
1911 lstrcpynA(*dest,src, len);
1912 hr = S_OK;
1913 } else {
1914 hr = E_OUTOFMEMORY;
1917 TRACE("%s->(%p)\n", debugstr_a(src), *dest);
1918 return hr;
1921 /*************************************************************************
1922 * SHStrDupA [SHLWAPI.@]
1924 * Return a Unicode copy of a string, in memory allocated by CoTaskMemAlloc().
1926 * PARAMS
1927 * lpszStr [I] String to copy
1928 * lppszDest [O] Destination for the new string copy
1930 * RETURNS
1931 * Success: S_OK. lppszDest contains the new string in Unicode format.
1932 * Failure: E_OUTOFMEMORY, If any arguments are invalid or memory allocation
1933 * fails.
1935 HRESULT WINAPI SHStrDupA(LPCSTR lpszStr, LPWSTR * lppszDest)
1937 HRESULT hRet;
1938 int len = 0;
1940 if (lpszStr)
1942 len = MultiByteToWideChar(CP_ACP, 0, lpszStr, -1, NULL, 0) * sizeof(WCHAR);
1943 *lppszDest = CoTaskMemAlloc(len);
1945 else
1946 *lppszDest = NULL;
1948 if (*lppszDest)
1950 MultiByteToWideChar(CP_ACP, 0, lpszStr, -1, *lppszDest, len/sizeof(WCHAR));
1951 hRet = S_OK;
1953 else
1954 hRet = E_OUTOFMEMORY;
1956 TRACE("%s->(%p)\n", debugstr_a(lpszStr), *lppszDest);
1957 return hRet;
1960 /*************************************************************************
1961 * _SHStrDupAW [INTERNAL]
1963 * Duplicates a UNICODE to a ASCII string. The destination buffer is allocated.
1965 static HRESULT _SHStrDupAW(LPCWSTR src, LPSTR * dest)
1967 HRESULT hr;
1968 int len = 0;
1970 if (src) {
1971 len = WideCharToMultiByte(CP_ACP, 0, src, -1, NULL, 0, NULL, NULL);
1972 *dest = CoTaskMemAlloc(len);
1973 } else {
1974 *dest = NULL;
1977 if (*dest) {
1978 WideCharToMultiByte(CP_ACP, 0, src, -1, *dest, len, NULL, NULL);
1979 hr = S_OK;
1980 } else {
1981 hr = E_OUTOFMEMORY;
1984 TRACE("%s->(%p)\n", debugstr_w(src), *dest);
1985 return hr;
1988 /*************************************************************************
1989 * SHStrDupW [SHLWAPI.@]
1991 * See SHStrDupA.
1993 HRESULT WINAPI SHStrDupW(LPCWSTR src, LPWSTR * dest)
1995 HRESULT hr;
1996 int len = 0;
1998 if (src) {
1999 len = (lstrlenW(src) + 1) * sizeof(WCHAR);
2000 *dest = CoTaskMemAlloc(len);
2001 } else {
2002 *dest = NULL;
2005 if (*dest) {
2006 memcpy(*dest, src, len);
2007 hr = S_OK;
2008 } else {
2009 hr = E_OUTOFMEMORY;
2012 TRACE("%s->(%p)\n", debugstr_w(src), *dest);
2013 return hr;
2016 /*************************************************************************
2017 * SHLWAPI_WriteReverseNum
2019 * Internal helper for SHLWAPI_WriteTimeClass.
2021 static inline LPWSTR SHLWAPI_WriteReverseNum(LPWSTR lpszOut, DWORD dwNum)
2023 *lpszOut-- = '\0';
2025 /* Write a decimal number to a string, backwards */
2028 DWORD dwNextDigit = dwNum % 10;
2029 *lpszOut-- = '0' + dwNextDigit;
2030 dwNum = (dwNum - dwNextDigit) / 10;
2031 } while (dwNum > 0);
2033 return lpszOut;
2036 /*************************************************************************
2037 * SHLWAPI_FormatSignificant
2039 * Internal helper for SHLWAPI_WriteTimeClass.
2041 static inline int SHLWAPI_FormatSignificant(LPWSTR lpszNum, int dwDigits)
2043 /* Zero non significant digits, return remaining significant digits */
2044 while (*lpszNum)
2046 lpszNum++;
2047 if (--dwDigits == 0)
2049 while (*lpszNum)
2050 *lpszNum++ = '0';
2051 return 0;
2054 return dwDigits;
2057 /*************************************************************************
2058 * SHLWAPI_WriteTimeClass
2060 * Internal helper for StrFromTimeIntervalW.
2062 static int SHLWAPI_WriteTimeClass(LPWSTR lpszOut, DWORD dwValue,
2063 UINT uClassStringId, int iDigits)
2065 WCHAR szBuff[64], *szOut = szBuff + 32;
2067 szOut = SHLWAPI_WriteReverseNum(szOut, dwValue);
2068 iDigits = SHLWAPI_FormatSignificant(szOut + 1, iDigits);
2069 *szOut = ' ';
2070 LoadStringW(shlwapi_hInstance, uClassStringId, szBuff + 32, 32);
2071 strcatW(lpszOut, szOut);
2072 return iDigits;
2075 /*************************************************************************
2076 * StrFromTimeIntervalA [SHLWAPI.@]
2078 * Format a millisecond time interval into a string
2080 * PARAMS
2081 * lpszStr [O] Output buffer for formatted time interval
2082 * cchMax [I] Size of lpszStr
2083 * dwMS [I] Number of milliseconds
2084 * iDigits [I] Number of digits to print
2086 * RETURNS
2087 * The length of the formatted string, or 0 if any parameter is invalid.
2089 * NOTES
2090 * This implementation mimics the Win32 behaviour of always writing a leading
2091 * space before the time interval begins.
2093 * iDigits is used to provide approximate times if accuracy is not important.
2094 * This number of digits will be written of the first non-zero time class
2095 * (hours/minutes/seconds). If this does not complete the time classification,
2096 * the remaining digits are changed to zeros (i.e. The time is _not_ rounded).
2097 * If there are digits remaining following the writing of a time class, the
2098 * next time class will be written.
2100 * For example, given dwMS represents 138 hours,43 minutes and 15 seconds, the
2101 * following will result from the given values of iDigits:
2103 *| iDigits 1 2 3 4 5 ...
2104 *| lpszStr "100 hr" "130 hr" "138 hr" "138 hr 40 min" "138 hr 43 min" ...
2106 INT WINAPI StrFromTimeIntervalA(LPSTR lpszStr, UINT cchMax, DWORD dwMS,
2107 int iDigits)
2109 INT iRet = 0;
2111 TRACE("(%p,%d,%d,%d)\n", lpszStr, cchMax, dwMS, iDigits);
2113 if (lpszStr && cchMax)
2115 WCHAR szBuff[128];
2116 StrFromTimeIntervalW(szBuff, sizeof(szBuff)/sizeof(WCHAR), dwMS, iDigits);
2117 WideCharToMultiByte(CP_ACP,0,szBuff,-1,lpszStr,cchMax,0,0);
2119 return iRet;
2123 /*************************************************************************
2124 * StrFromTimeIntervalW [SHLWAPI.@]
2126 * See StrFromTimeIntervalA.
2128 INT WINAPI StrFromTimeIntervalW(LPWSTR lpszStr, UINT cchMax, DWORD dwMS,
2129 int iDigits)
2131 INT iRet = 0;
2133 TRACE("(%p,%d,%d,%d)\n", lpszStr, cchMax, dwMS, iDigits);
2135 if (lpszStr && cchMax)
2137 WCHAR szCopy[128];
2138 DWORD dwHours, dwMinutes;
2140 if (!iDigits || cchMax == 1)
2142 *lpszStr = '\0';
2143 return 0;
2146 /* Calculate the time classes */
2147 dwMS = (dwMS + 500) / 1000;
2148 dwHours = dwMS / 3600;
2149 dwMS -= dwHours * 3600;
2150 dwMinutes = dwMS / 60;
2151 dwMS -= dwMinutes * 60;
2153 szCopy[0] = '\0';
2155 if (dwHours)
2156 iDigits = SHLWAPI_WriteTimeClass(szCopy, dwHours, IDS_TIME_INTERVAL_HOURS, iDigits);
2158 if (dwMinutes && iDigits)
2159 iDigits = SHLWAPI_WriteTimeClass(szCopy, dwMinutes, IDS_TIME_INTERVAL_MINUTES, iDigits);
2161 if (iDigits) /* Always write seconds if we have significant digits */
2162 SHLWAPI_WriteTimeClass(szCopy, dwMS, IDS_TIME_INTERVAL_SECONDS, iDigits);
2164 lstrcpynW(lpszStr, szCopy, cchMax);
2165 iRet = strlenW(lpszStr);
2167 return iRet;
2170 /*************************************************************************
2171 * StrIsIntlEqualA [SHLWAPI.@]
2173 * Compare two strings.
2175 * PARAMS
2176 * bCase [I] Whether to compare case sensitively
2177 * lpszStr [I] First string to compare
2178 * lpszComp [I] Second string to compare
2179 * iLen [I] Length to compare
2181 * RETURNS
2182 * TRUE If the strings are equal.
2183 * FALSE Otherwise.
2185 BOOL WINAPI StrIsIntlEqualA(BOOL bCase, LPCSTR lpszStr, LPCSTR lpszComp,
2186 int iLen)
2188 DWORD dwFlags;
2190 TRACE("(%d,%s,%s,%d)\n", bCase,
2191 debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
2193 /* FIXME: This flag is undocumented and unknown by our CompareString.
2194 * We need a define for it.
2196 dwFlags = 0x10000000;
2197 if (!bCase) dwFlags |= NORM_IGNORECASE;
2199 return (CompareStringA(GetThreadLocale(), dwFlags, lpszStr, iLen, lpszComp, iLen) == CSTR_EQUAL);
2202 /*************************************************************************
2203 * StrIsIntlEqualW [SHLWAPI.@]
2205 * See StrIsIntlEqualA.
2207 BOOL WINAPI StrIsIntlEqualW(BOOL bCase, LPCWSTR lpszStr, LPCWSTR lpszComp,
2208 int iLen)
2210 DWORD dwFlags;
2212 TRACE("(%d,%s,%s,%d)\n", bCase,
2213 debugstr_w(lpszStr),debugstr_w(lpszComp), iLen);
2215 /* FIXME: This flag is undocumented and unknown by our CompareString.
2216 * We need a define for it.
2218 dwFlags = 0x10000000;
2219 if (!bCase) dwFlags |= NORM_IGNORECASE;
2221 return (CompareStringW(GetThreadLocale(), dwFlags, lpszStr, iLen, lpszComp, iLen) == CSTR_EQUAL);
2224 /*************************************************************************
2225 * @ [SHLWAPI.399]
2227 * Copy a string to another string, up to a maximum number of characters.
2229 * PARAMS
2230 * lpszDest [O] Destination string
2231 * lpszSrc [I] Source string
2232 * iLen [I] Maximum number of chars to copy
2234 * RETURNS
2235 * Success: A pointer to the last character written to lpszDest.
2236 * Failure: lpszDest, if any arguments are invalid.
2238 LPSTR WINAPI StrCpyNXA(LPSTR lpszDest, LPCSTR lpszSrc, int iLen)
2240 TRACE("(%p,%s,%i)\n", lpszDest, debugstr_a(lpszSrc), iLen);
2242 if (lpszDest && lpszSrc && iLen > 0)
2244 while ((iLen-- > 1) && *lpszSrc)
2245 *lpszDest++ = *lpszSrc++;
2246 if (iLen >= 0)
2247 *lpszDest = '\0';
2249 return lpszDest;
2252 /*************************************************************************
2253 * @ [SHLWAPI.400]
2255 * Unicode version of StrCpyNXA.
2257 LPWSTR WINAPI StrCpyNXW(LPWSTR lpszDest, LPCWSTR lpszSrc, int iLen)
2259 TRACE("(%p,%s,%i)\n", lpszDest, debugstr_w(lpszSrc), iLen);
2261 if (lpszDest && lpszSrc && iLen > 0)
2263 while ((iLen-- > 1) && *lpszSrc)
2264 *lpszDest++ = *lpszSrc++;
2265 if (iLen >= 0)
2266 *lpszDest = '\0';
2268 return lpszDest;
2271 /*************************************************************************
2272 * StrCmpLogicalW [SHLWAPI.@]
2274 * Compare two strings, ignoring case and comparing digits as numbers.
2276 * PARAMS
2277 * lpszStr [I] First string to compare
2278 * lpszComp [I] Second string to compare
2279 * iLen [I] Length to compare
2281 * RETURNS
2282 * TRUE If the strings are equal.
2283 * FALSE Otherwise.
2285 INT WINAPI StrCmpLogicalW(LPCWSTR lpszStr, LPCWSTR lpszComp)
2287 INT iDiff;
2289 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszComp));
2291 if (lpszStr && lpszComp)
2293 while (*lpszStr)
2295 if (!*lpszComp)
2296 return 1;
2297 else if (isdigitW(*lpszStr))
2299 int iStr, iComp;
2301 if (!isdigitW(*lpszComp))
2302 return -1;
2304 /* Compare the numbers */
2305 StrToIntExW(lpszStr, 0, &iStr);
2306 StrToIntExW(lpszComp, 0, &iComp);
2308 if (iStr < iComp)
2309 return -1;
2310 else if (iStr > iComp)
2311 return 1;
2313 /* Skip */
2314 while (isdigitW(*lpszStr))
2315 lpszStr++;
2316 while (isdigitW(*lpszComp))
2317 lpszComp++;
2319 else if (isdigitW(*lpszComp))
2320 return 1;
2321 else
2323 iDiff = ChrCmpIW(*lpszStr,*lpszComp);
2324 if (iDiff > 0)
2325 return 1;
2326 else if (iDiff < 0)
2327 return -1;
2329 lpszStr++;
2330 lpszComp++;
2333 if (*lpszComp)
2334 return -1;
2336 return 0;
2339 /* Structure for formatting byte strings */
2340 typedef struct tagSHLWAPI_BYTEFORMATS
2342 LONGLONG dLimit;
2343 double dDivisor;
2344 double dNormaliser;
2345 int nDecimals;
2346 WCHAR wPrefix;
2347 } SHLWAPI_BYTEFORMATS;
2349 /*************************************************************************
2350 * StrFormatByteSizeW [SHLWAPI.@]
2352 * Create a string containing an abbreviated byte count of up to 2^63-1.
2354 * PARAMS
2355 * llBytes [I] Byte size to format
2356 * lpszDest [I] Destination for formatted string
2357 * cchMax [I] Size of lpszDest
2359 * RETURNS
2360 * lpszDest.
2362 * NOTES
2363 * There is no StrFormatByteSize64W function, it is called StrFormatByteSizeW().
2365 LPWSTR WINAPI StrFormatByteSizeW(LONGLONG llBytes, LPWSTR lpszDest, UINT cchMax)
2367 #define KB ((ULONGLONG)1024)
2368 #define MB (KB*KB)
2369 #define GB (KB*KB*KB)
2370 #define TB (KB*KB*KB*KB)
2371 #define PB (KB*KB*KB*KB*KB)
2373 static const SHLWAPI_BYTEFORMATS bfFormats[] =
2375 { 10*KB, 10.24, 100.0, 2, 'K' }, /* 10 KB */
2376 { 100*KB, 102.4, 10.0, 1, 'K' }, /* 100 KB */
2377 { 1000*KB, 1024.0, 1.0, 0, 'K' }, /* 1000 KB */
2378 { 10*MB, 10485.76, 100.0, 2, 'M' }, /* 10 MB */
2379 { 100*MB, 104857.6, 10.0, 1, 'M' }, /* 100 MB */
2380 { 1000*MB, 1048576.0, 1.0, 0, 'M' }, /* 1000 MB */
2381 { 10*GB, 10737418.24, 100.0, 2, 'G' }, /* 10 GB */
2382 { 100*GB, 107374182.4, 10.0, 1, 'G' }, /* 100 GB */
2383 { 1000*GB, 1073741824.0, 1.0, 0, 'G' }, /* 1000 GB */
2384 { 10*TB, 10485.76, 100.0, 2, 'T' }, /* 10 TB */
2385 { 100*TB, 104857.6, 10.0, 1, 'T' }, /* 100 TB */
2386 { 1000*TB, 1048576.0, 1.0, 0, 'T' }, /* 1000 TB */
2387 { 10*PB, 10737418.24, 100.00, 2, 'P' }, /* 10 PB */
2388 { 100*PB, 107374182.4, 10.00, 1, 'P' }, /* 100 PB */
2389 { 1000*PB, 1073741824.0, 1.00, 0, 'P' }, /* 1000 PB */
2390 { 0, 10995116277.76, 100.00, 2, 'E' } /* EB's, catch all */
2392 WCHAR wszAdd[] = {' ','?','B',0};
2393 double dBytes;
2394 UINT i = 0;
2396 TRACE("(0x%s,%p,%d)\n", wine_dbgstr_longlong(llBytes), lpszDest, cchMax);
2398 if (!lpszDest || !cchMax)
2399 return lpszDest;
2401 if (llBytes < 1024) /* 1K */
2403 WCHAR wszBytesFormat[64];
2404 LoadStringW(shlwapi_hInstance, IDS_BYTES_FORMAT, wszBytesFormat, 64);
2405 snprintfW(lpszDest, cchMax, wszBytesFormat, (int)llBytes);
2406 return lpszDest;
2409 /* Note that if this loop completes without finding a match, i will be
2410 * pointing at the last entry, which is a catch all for > 1000 PB
2412 while (i < sizeof(bfFormats) / sizeof(SHLWAPI_BYTEFORMATS) - 1)
2414 if (llBytes < bfFormats[i].dLimit)
2415 break;
2416 i++;
2418 /* Above 1 TB we encounter problems with FP accuracy. So for amounts above
2419 * this number we integer shift down by 1 MB first. The table above has
2420 * the divisors scaled down from the '< 10 TB' entry onwards, to account
2421 * for this. We also add a small fudge factor to get the correct result for
2422 * counts that lie exactly on a 1024 byte boundary.
2424 if (i > 8)
2425 dBytes = (double)(llBytes >> 20) + 0.001; /* Scale down by 1 MB */
2426 else
2427 dBytes = (double)llBytes + 0.00001;
2429 dBytes = floor(dBytes / bfFormats[i].dDivisor) / bfFormats[i].dNormaliser;
2431 if (!FormatDouble(dBytes, bfFormats[i].nDecimals, lpszDest, cchMax))
2432 return NULL;
2433 wszAdd[1] = bfFormats[i].wPrefix;
2434 StrCatBuffW(lpszDest, wszAdd, cchMax);
2435 return lpszDest;
2438 /*************************************************************************
2439 * StrFormatByteSize64A [SHLWAPI.@]
2441 * See StrFormatByteSizeW.
2443 LPSTR WINAPI StrFormatByteSize64A(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax)
2445 WCHAR wszBuff[32];
2447 StrFormatByteSizeW(llBytes, wszBuff, sizeof(wszBuff)/sizeof(WCHAR));
2449 if (lpszDest)
2450 WideCharToMultiByte(CP_ACP, 0, wszBuff, -1, lpszDest, cchMax, 0, 0);
2451 return lpszDest;
2454 /*************************************************************************
2455 * StrFormatByteSizeA [SHLWAPI.@]
2457 * Create a string containing an abbreviated byte count of up to 2^31-1.
2459 * PARAMS
2460 * dwBytes [I] Byte size to format
2461 * lpszDest [I] Destination for formatted string
2462 * cchMax [I] Size of lpszDest
2464 * RETURNS
2465 * lpszDest.
2467 * NOTES
2468 * The Ascii and Unicode versions of this function accept a different
2469 * integer type for dwBytes. See StrFormatByteSize64A().
2471 LPSTR WINAPI StrFormatByteSizeA(DWORD dwBytes, LPSTR lpszDest, UINT cchMax)
2473 TRACE("(%d,%p,%d)\n", dwBytes, lpszDest, cchMax);
2475 return StrFormatByteSize64A(dwBytes, lpszDest, cchMax);
2478 /*************************************************************************
2479 * @ [SHLWAPI.162]
2481 * Remove a hanging lead byte from the end of a string, if present.
2483 * PARAMS
2484 * lpStr [I] String to check for a hanging lead byte
2485 * size [I] Length of lpStr
2487 * RETURNS
2488 * Success: The new length of the string. Any hanging lead bytes are removed.
2489 * Failure: 0, if any parameters are invalid.
2491 DWORD WINAPI SHTruncateString(LPSTR lpStr, DWORD size)
2493 if (lpStr && size)
2495 LPSTR lastByte = lpStr + size - 1;
2497 while(lpStr < lastByte)
2498 lpStr += IsDBCSLeadByte(*lpStr) ? 2 : 1;
2500 if(lpStr == lastByte && IsDBCSLeadByte(*lpStr))
2502 *lpStr = '\0';
2503 size--;
2505 return size;
2507 return 0;
2510 /*************************************************************************
2511 * @ [SHLWAPI.203]
2513 * Remove a single non-trailing ampersand ('&') from a string.
2515 * PARAMS
2516 * lpszStr [I/O] String to remove ampersand from.
2518 * RETURNS
2519 * The character after the first ampersand in lpszStr, or the first character
2520 * in lpszStr if there is no ampersand in the string.
2522 char WINAPI SHStripMneumonicA(LPCSTR lpszStr)
2524 LPSTR lpszIter, lpszTmp;
2525 char ch;
2527 TRACE("(%s)\n", debugstr_a(lpszStr));
2529 ch = *lpszStr;
2531 if ((lpszIter = StrChrA(lpszStr, '&')))
2533 lpszTmp = CharNextA(lpszIter);
2534 if (*lpszTmp)
2536 if (*lpszTmp != '&')
2537 ch = *lpszTmp;
2539 memmove( lpszIter, lpszTmp, strlen(lpszTmp) + 1 );
2543 return ch;
2546 /*************************************************************************
2547 * @ [SHLWAPI.225]
2549 * Unicode version of SHStripMneumonicA.
2551 WCHAR WINAPI SHStripMneumonicW(LPCWSTR lpszStr)
2553 LPWSTR lpszIter, lpszTmp;
2554 WCHAR ch;
2556 TRACE("(%s)\n", debugstr_w(lpszStr));
2558 ch = *lpszStr;
2560 if ((lpszIter = StrChrW(lpszStr, '&')))
2562 lpszTmp = lpszIter + 1;
2563 if (*lpszTmp)
2565 if (*lpszTmp != '&')
2566 ch = *lpszTmp;
2568 memmove( lpszIter, lpszTmp, (strlenW(lpszTmp) + 1) * sizeof(WCHAR) );
2572 return ch;
2575 /*************************************************************************
2576 * @ [SHLWAPI.216]
2578 * Convert an Ascii string to Unicode.
2580 * PARAMS
2581 * dwCp [I] Code page for the conversion
2582 * lpSrcStr [I] Source Ascii string to convert
2583 * lpDstStr [O] Destination for converted Unicode string
2584 * iLen [I] Length of lpDstStr
2586 * RETURNS
2587 * The return value of the MultiByteToWideChar() function called on lpSrcStr.
2589 DWORD WINAPI SHAnsiToUnicodeCP(DWORD dwCp, LPCSTR lpSrcStr, LPWSTR lpDstStr, int iLen)
2591 DWORD dwRet;
2593 dwRet = MultiByteToWideChar(dwCp, 0, lpSrcStr, -1, lpDstStr, iLen);
2594 TRACE("%s->%s,ret=%d\n", debugstr_a(lpSrcStr), debugstr_w(lpDstStr), dwRet);
2595 return dwRet;
2598 /*************************************************************************
2599 * @ [SHLWAPI.215]
2601 * Convert an Ascii string to Unicode.
2603 * PARAMS
2604 * lpSrcStr [I] Source Ascii string to convert
2605 * lpDstStr [O] Destination for converted Unicode string
2606 * iLen [I] Length of lpDstStr
2608 * RETURNS
2609 * The return value of the MultiByteToWideChar() function called on lpSrcStr.
2611 * NOTES
2612 * This function simply calls SHAnsiToUnicodeCP with code page CP_ACP.
2614 DWORD WINAPI SHAnsiToUnicode(LPCSTR lpSrcStr, LPWSTR lpDstStr, int iLen)
2616 return SHAnsiToUnicodeCP(CP_ACP, lpSrcStr, lpDstStr, iLen);
2619 /*************************************************************************
2620 * @ [SHLWAPI.218]
2622 * Convert a Unicode string to Ascii.
2624 * PARAMS
2625 * CodePage [I] Code page to use for the conversion
2626 * lpSrcStr [I] Source Unicode string to convert
2627 * lpDstStr [O] Destination for converted Ascii string
2628 * dstlen [I] Length of buffer at lpDstStr
2630 * RETURNS
2631 * Success: The length in bytes of the result at lpDstStr (including the terminator)
2632 * Failure: When using CP_UTF8, CP_UTF7 or 0xc350 as codePage, 0 is returned and
2633 * the result is not nul-terminated.
2634 * When using a different codepage, the length in bytes of the truncated
2635 * result at lpDstStr (including the terminator) is returned and
2636 * lpDstStr is always nul-terminated.
2639 DWORD WINAPI SHUnicodeToAnsiCP(UINT CodePage, LPCWSTR lpSrcStr, LPSTR lpDstStr, int dstlen)
2641 static const WCHAR emptyW[] = { '\0' };
2642 int len , reqLen;
2643 LPSTR mem;
2645 if (!lpDstStr || !dstlen)
2646 return 0;
2648 if (!lpSrcStr)
2649 lpSrcStr = emptyW;
2651 *lpDstStr = '\0';
2653 len = strlenW(lpSrcStr) + 1;
2655 switch (CodePage)
2657 case CP_WINUNICODE:
2658 CodePage = CP_UTF8; /* Fall through... */
2659 case 0x0000C350: /* FIXME: CP_ #define */
2660 case CP_UTF7:
2661 case CP_UTF8:
2663 DWORD dwMode = 0;
2664 INT lenW = len - 1;
2665 INT needed = dstlen - 1;
2666 HRESULT hr;
2668 /* try the user supplied buffer first */
2669 hr = ConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &lenW, lpDstStr, &needed);
2670 if (hr == S_OK)
2672 lpDstStr[needed] = '\0';
2673 return needed + 1;
2676 /* user buffer too small. exclude termination and copy as much as possible */
2677 lenW = len;
2678 hr = ConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &lenW, NULL, &needed);
2679 needed++;
2680 mem = HeapAlloc(GetProcessHeap(), 0, needed);
2681 if (!mem)
2682 return 0;
2684 hr = ConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &len, mem, &needed);
2685 if (hr == S_OK)
2687 reqLen = SHTruncateString(mem, dstlen);
2688 if (reqLen > 0) memcpy(lpDstStr, mem, reqLen-1);
2690 HeapFree(GetProcessHeap(), 0, mem);
2691 return 0;
2693 default:
2694 break;
2697 /* try the user supplied buffer first */
2698 reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, lpDstStr, dstlen, NULL, NULL);
2700 if (!reqLen && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
2702 reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, NULL, 0, NULL, NULL);
2703 if (reqLen)
2705 mem = HeapAlloc(GetProcessHeap(), 0, reqLen);
2706 if (mem)
2708 WideCharToMultiByte(CodePage, 0, lpSrcStr, len, mem, reqLen, NULL, NULL);
2710 reqLen = SHTruncateString(mem, dstlen -1);
2711 reqLen++;
2713 lstrcpynA(lpDstStr, mem, reqLen);
2714 HeapFree(GetProcessHeap(), 0, mem);
2715 lpDstStr[reqLen-1] = '\0';
2719 return reqLen;
2722 /*************************************************************************
2723 * @ [SHLWAPI.217]
2725 * Convert a Unicode string to Ascii.
2727 * PARAMS
2728 * lpSrcStr [I] Source Unicode string to convert
2729 * lpDstStr [O] Destination for converted Ascii string
2730 * iLen [O] Length of lpDstStr in characters
2732 * RETURNS
2733 * See SHUnicodeToAnsiCP
2735 * NOTES
2736 * This function simply calls SHUnicodeToAnsiCP() with CodePage = CP_ACP.
2738 INT WINAPI SHUnicodeToAnsi(LPCWSTR lpSrcStr, LPSTR lpDstStr, INT iLen)
2740 return SHUnicodeToAnsiCP(CP_ACP, lpSrcStr, lpDstStr, iLen);
2743 /*************************************************************************
2744 * @ [SHLWAPI.345]
2746 * Copy one string to another.
2748 * PARAMS
2749 * lpszSrc [I] Source string to copy
2750 * lpszDst [O] Destination for copy
2751 * iLen [I] Length of lpszDst in characters
2753 * RETURNS
2754 * The length of the copied string, including the terminating NUL. lpszDst
2755 * contains iLen characters of lpszSrc.
2757 DWORD WINAPI SHAnsiToAnsi(LPCSTR lpszSrc, LPSTR lpszDst, int iLen)
2759 LPSTR lpszRet;
2761 TRACE("(%s,%p,0x%08x)\n", debugstr_a(lpszSrc), lpszDst, iLen);
2763 lpszRet = StrCpyNXA(lpszDst, lpszSrc, iLen);
2764 return lpszRet - lpszDst + 1;
2767 /*************************************************************************
2768 * @ [SHLWAPI.346]
2770 * Unicode version of SSHAnsiToAnsi.
2772 DWORD WINAPI SHUnicodeToUnicode(LPCWSTR lpszSrc, LPWSTR lpszDst, int iLen)
2774 LPWSTR lpszRet;
2776 TRACE("(%s,%p,0x%08x)\n", debugstr_w(lpszSrc), lpszDst, iLen);
2778 lpszRet = StrCpyNXW(lpszDst, lpszSrc, iLen);
2779 return lpszRet - lpszDst + 1;
2782 /*************************************************************************
2783 * @ [SHLWAPI.364]
2785 * Determine if an Ascii string converts to Unicode and back identically.
2787 * PARAMS
2788 * lpSrcStr [I] Source Unicode string to convert
2789 * lpDst [O] Destination for resulting Ascii string
2790 * iLen [I] Length of lpDst in characters
2792 * RETURNS
2793 * TRUE, since Ascii strings always convert identically.
2795 BOOL WINAPI DoesStringRoundTripA(LPCSTR lpSrcStr, LPSTR lpDst, INT iLen)
2797 lstrcpynA(lpDst, lpSrcStr, iLen);
2798 return TRUE;
2801 /*************************************************************************
2802 * @ [SHLWAPI.365]
2804 * Determine if a Unicode string converts to Ascii and back identically.
2806 * PARAMS
2807 * lpSrcStr [I] Source Unicode string to convert
2808 * lpDst [O] Destination for resulting Ascii string
2809 * iLen [I] Length of lpDst in characters
2811 * RETURNS
2812 * TRUE, if lpSrcStr converts to Ascii and back identically,
2813 * FALSE otherwise.
2815 BOOL WINAPI DoesStringRoundTripW(LPCWSTR lpSrcStr, LPSTR lpDst, INT iLen)
2817 WCHAR szBuff[MAX_PATH];
2819 SHUnicodeToAnsi(lpSrcStr, lpDst, iLen);
2820 SHAnsiToUnicode(lpDst, szBuff, MAX_PATH);
2821 return !strcmpW(lpSrcStr, szBuff);
2824 /*************************************************************************
2825 * SHLoadIndirectString [SHLWAPI.@]
2827 * If passed a string that begins with '@', extract the string from the
2828 * appropriate resource, otherwise do a straight copy.
2831 HRESULT WINAPI SHLoadIndirectString(LPCWSTR src, LPWSTR dst, UINT dst_len, void **reserved)
2833 WCHAR *dllname = NULL;
2834 HMODULE hmod = NULL;
2835 HRESULT hr = E_FAIL;
2837 TRACE("(%s %p %08x %p)\n", debugstr_w(src), dst, dst_len, reserved);
2839 if(src[0] == '@')
2841 WCHAR *index_str;
2842 int index;
2844 dst[0] = 0;
2845 dllname = StrDupW(src + 1);
2846 index_str = strchrW(dllname, ',');
2848 if(!index_str) goto end;
2850 *index_str = 0;
2851 index_str++;
2852 index = atoiW(index_str);
2854 hmod = LoadLibraryW(dllname);
2855 if(!hmod) goto end;
2857 if(index < 0)
2859 if(LoadStringW(hmod, -index, dst, dst_len))
2860 hr = S_OK;
2862 else
2863 FIXME("can't handle non-negative indices (%d)\n", index);
2865 else
2867 if(dst != src)
2868 lstrcpynW(dst, src, dst_len);
2869 hr = S_OK;
2872 TRACE("returning %s\n", debugstr_w(dst));
2873 end:
2874 if(hmod) FreeLibrary(hmod);
2875 LocalFree(dllname);
2876 return hr;
2879 BOOL WINAPI IsCharSpaceA(CHAR c)
2881 WORD CharType;
2882 return GetStringTypeA(GetSystemDefaultLCID(), CT_CTYPE1, &c, 1, &CharType) && (CharType & C1_SPACE);
2885 /*************************************************************************
2886 * @ [SHLWAPI.29]
2888 * Determine if a Unicode character is a space.
2890 * PARAMS
2891 * wc [I] Character to check.
2893 * RETURNS
2894 * TRUE, if wc is a space,
2895 * FALSE otherwise.
2897 BOOL WINAPI IsCharSpaceW(WCHAR wc)
2899 WORD CharType;
2901 return GetStringTypeW(CT_CTYPE1, &wc, 1, &CharType) && (CharType & C1_SPACE);