wined3d: Simplify DISCARD / READONLY handling in wined3d_buffer_map() a bit.
[wine/multimedia.git] / dlls / shlwapi / string.c
blob1a4ad146439ffe2d59be0cf1868743ef96a5749f
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
31 #define NONAMELESSSTRUCT
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] Maximum 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] Maximum 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 * StrCpyW [SHLWAPI.@]
464 * Copy a string to another string.
466 * PARAMS
467 * lpszStr [O] Destination string
468 * lpszSrc [I] Source string
470 * RETURNS
471 * lpszStr.
473 LPWSTR WINAPI StrCpyW(LPWSTR lpszStr, LPCWSTR lpszSrc)
475 TRACE("(%p,%s)\n", lpszStr, debugstr_w(lpszSrc));
477 if (lpszStr && lpszSrc)
478 strcpyW(lpszStr, lpszSrc);
479 return lpszStr;
482 /*************************************************************************
483 * StrCpyNW [SHLWAPI.@]
485 * Copy a string to another string, up to a maximum number of characters.
487 * PARAMS
488 * dst [O] Destination string
489 * src [I] Source string
490 * count [I] Maximum number of chars to copy
492 * RETURNS
493 * dst.
495 LPWSTR WINAPI StrCpyNW(LPWSTR dst, LPCWSTR src, int count)
497 LPWSTR d = dst;
498 LPCWSTR s = src;
500 TRACE("(%p,%s,%i)\n", dst, debugstr_w(src), count);
502 if (s)
504 while ((count > 1) && *s)
506 count--;
507 *d++ = *s++;
510 if (count) *d = 0;
512 return dst;
515 /*************************************************************************
516 * SHLWAPI_StrStrHelperA
518 * Internal implementation of StrStrA/StrStrIA
520 static LPSTR SHLWAPI_StrStrHelperA(LPCSTR lpszStr, LPCSTR lpszSearch,
521 INT (WINAPI *pStrCmpFn)(LPCSTR,LPCSTR,INT))
523 size_t iLen;
525 if (!lpszStr || !lpszSearch || !*lpszSearch)
526 return NULL;
528 iLen = strlen(lpszSearch);
530 while (*lpszStr)
532 if (!pStrCmpFn(lpszStr, lpszSearch, iLen))
533 return (LPSTR)lpszStr;
534 lpszStr = CharNextA(lpszStr);
536 return NULL;
539 /*************************************************************************
540 * StrStrA [SHLWAPI.@]
542 * Find a substring within a string.
544 * PARAMS
545 * lpszStr [I] String to search in
546 * lpszSearch [I] String to look for
548 * RETURNS
549 * The start of lpszSearch within lpszStr, or NULL if not found.
551 LPSTR WINAPI StrStrA(LPCSTR lpszStr, LPCSTR lpszSearch)
553 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
555 return SHLWAPI_StrStrHelperA(lpszStr, lpszSearch, StrCmpNA);
558 /*************************************************************************
559 * StrStrW [SHLWAPI.@]
561 * See StrStrA.
563 LPWSTR WINAPI StrStrW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
565 TRACE("(%s, %s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
567 if (!lpszStr || !lpszSearch || !*lpszSearch) return NULL;
568 return strstrW( lpszStr, lpszSearch );
571 /*************************************************************************
572 * StrRStrIA [SHLWAPI.@]
574 * Find the last occurrence of a substring within a string.
576 * PARAMS
577 * lpszStr [I] String to search in
578 * lpszEnd [I] End of lpszStr
579 * lpszSearch [I] String to look for
581 * RETURNS
582 * The last occurrence lpszSearch within lpszStr, or NULL if not found.
584 LPSTR WINAPI StrRStrIA(LPCSTR lpszStr, LPCSTR lpszEnd, LPCSTR lpszSearch)
586 WORD ch1, ch2;
587 INT iLen;
589 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
591 if (!lpszStr || !lpszSearch || !*lpszSearch)
592 return NULL;
594 if (!lpszEnd)
595 lpszEnd = lpszStr + lstrlenA(lpszStr);
596 if (lpszEnd == lpszStr)
597 return NULL;
599 if (IsDBCSLeadByte(*lpszSearch))
600 ch1 = *lpszSearch << 8 | (UCHAR)lpszSearch[1];
601 else
602 ch1 = *lpszSearch;
603 iLen = lstrlenA(lpszSearch);
607 lpszEnd = CharPrevA(lpszStr, lpszEnd);
608 ch2 = IsDBCSLeadByte(*lpszEnd)? *lpszEnd << 8 | (UCHAR)lpszEnd[1] : *lpszEnd;
609 if (!ChrCmpIA(ch1, ch2))
611 if (!StrCmpNIA(lpszEnd, lpszSearch, iLen))
612 return (LPSTR)lpszEnd;
614 } while (lpszEnd > lpszStr);
615 return NULL;
618 /*************************************************************************
619 * StrRStrIW [SHLWAPI.@]
621 * See StrRStrIA.
623 LPWSTR WINAPI StrRStrIW(LPCWSTR lpszStr, LPCWSTR lpszEnd, LPCWSTR lpszSearch)
625 INT iLen;
627 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
629 if (!lpszStr || !lpszSearch || !*lpszSearch)
630 return NULL;
632 if (!lpszEnd)
633 lpszEnd = lpszStr + strlenW(lpszStr);
635 iLen = strlenW(lpszSearch);
637 while (lpszEnd > lpszStr)
639 lpszEnd--;
640 if (!StrCmpNIW(lpszEnd, lpszSearch, iLen))
641 return (LPWSTR)lpszEnd;
643 return NULL;
646 /*************************************************************************
647 * StrStrIA [SHLWAPI.@]
649 * Find a substring within a string, ignoring case.
651 * PARAMS
652 * lpszStr [I] String to search in
653 * lpszSearch [I] String to look for
655 * RETURNS
656 * The start of lpszSearch within lpszStr, or NULL if not found.
658 LPSTR WINAPI StrStrIA(LPCSTR lpszStr, LPCSTR lpszSearch)
660 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
662 return SHLWAPI_StrStrHelperA(lpszStr, lpszSearch, StrCmpNIA);
665 /*************************************************************************
666 * StrStrIW [SHLWAPI.@]
668 * See StrStrIA.
670 LPWSTR WINAPI StrStrIW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
672 int iLen;
674 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
676 if (!lpszStr || !lpszSearch || !*lpszSearch)
677 return NULL;
679 iLen = strlenW(lpszSearch);
681 while (*lpszStr)
683 if (!StrCmpNIW(lpszStr, lpszSearch, iLen))
684 return (LPWSTR)lpszStr;
685 lpszStr++;
687 return NULL;
690 /*************************************************************************
691 * StrStrNW [SHLWAPI.@]
693 * Find a substring within a string up to a given number of initial characters.
695 * PARAMS
696 * lpFirst [I] String to search in
697 * lpSrch [I] String to look for
698 * cchMax [I] Maximum number of initial search characters
700 * RETURNS
701 * The start of lpFirst within lpSrch, or NULL if not found.
703 LPWSTR WINAPI StrStrNW(LPCWSTR lpFirst, LPCWSTR lpSrch, UINT cchMax)
705 UINT i;
706 int len;
708 TRACE("(%s, %s, %u)\n", debugstr_w(lpFirst), debugstr_w(lpSrch), cchMax);
710 if (!lpFirst || !lpSrch || !*lpSrch || !cchMax)
711 return NULL;
713 len = strlenW(lpSrch);
715 for (i = cchMax; *lpFirst && (i > 0); i--, lpFirst++)
717 if (!strncmpW(lpFirst, lpSrch, len))
718 return (LPWSTR)lpFirst;
721 return NULL;
724 /*************************************************************************
725 * StrStrNIW [SHLWAPI.@]
727 * Find a substring within a string up to a given number of initial characters,
728 * ignoring case.
730 * PARAMS
731 * lpFirst [I] String to search in
732 * lpSrch [I] String to look for
733 * cchMax [I] Maximum number of initial search characters
735 * RETURNS
736 * The start of lpFirst within lpSrch, or NULL if not found.
738 LPWSTR WINAPI StrStrNIW(LPCWSTR lpFirst, LPCWSTR lpSrch, UINT cchMax)
740 UINT i;
741 int len;
743 TRACE("(%s, %s, %u)\n", debugstr_w(lpFirst), debugstr_w(lpSrch), cchMax);
745 if (!lpFirst || !lpSrch || !*lpSrch || !cchMax)
746 return NULL;
748 len = strlenW(lpSrch);
750 for (i = cchMax; *lpFirst && (i > 0); i--, lpFirst++)
752 if (!strncmpiW(lpFirst, lpSrch, len))
753 return (LPWSTR)lpFirst;
756 return NULL;
759 /*************************************************************************
760 * StrToIntA [SHLWAPI.@]
762 * Read a signed integer from a string.
764 * PARAMS
765 * lpszStr [I] String to read integer from
767 * RETURNS
768 * The signed integer value represented by the string, or 0 if no integer is
769 * present.
771 * NOTES
772 * No leading space is allowed before the number, although a leading '-' is.
774 int WINAPI StrToIntA(LPCSTR lpszStr)
776 int iRet = 0;
778 TRACE("(%s)\n", debugstr_a(lpszStr));
780 if (!lpszStr)
782 WARN("Invalid lpszStr would crash under Win32!\n");
783 return 0;
786 if (*lpszStr == '-' || isdigit(*lpszStr))
787 StrToIntExA(lpszStr, 0, &iRet);
788 return iRet;
791 /*************************************************************************
792 * StrToIntW [SHLWAPI.@]
794 * See StrToIntA.
796 int WINAPI StrToIntW(LPCWSTR lpszStr)
798 int iRet = 0;
800 TRACE("(%s)\n", debugstr_w(lpszStr));
802 if (!lpszStr)
804 WARN("Invalid lpszStr would crash under Win32!\n");
805 return 0;
808 if (*lpszStr == '-' || isdigitW(*lpszStr))
809 StrToIntExW(lpszStr, 0, &iRet);
810 return iRet;
813 /*************************************************************************
814 * StrToIntExA [SHLWAPI.@]
816 * Read an integer from a string.
818 * PARAMS
819 * lpszStr [I] String to read integer from
820 * dwFlags [I] Flags controlling the conversion
821 * lpiRet [O] Destination for read integer.
823 * RETURNS
824 * Success: TRUE. lpiRet contains the integer value represented by the string.
825 * Failure: FALSE, if the string is invalid, or no number is present.
827 * NOTES
828 * Leading whitespace, '-' and '+' are allowed before the number. If
829 * dwFlags includes STIF_SUPPORT_HEX, hexadecimal numbers are allowed, if
830 * preceded by '0x'. If this flag is not set, or there is no '0x' prefix,
831 * the string is treated as a decimal string. A leading '-' is ignored for
832 * hexadecimal numbers.
834 BOOL WINAPI StrToIntExA(LPCSTR lpszStr, DWORD dwFlags, LPINT lpiRet)
836 LONGLONG li;
837 BOOL bRes;
839 TRACE("(%s,%08X,%p)\n", debugstr_a(lpszStr), dwFlags, lpiRet);
841 bRes = StrToInt64ExA(lpszStr, dwFlags, &li);
842 if (bRes) *lpiRet = li;
843 return bRes;
846 /*************************************************************************
847 * StrToInt64ExA [SHLWAPI.@]
849 * See StrToIntExA.
851 BOOL WINAPI StrToInt64ExA(LPCSTR lpszStr, DWORD dwFlags, LONGLONG *lpiRet)
853 BOOL bNegative = FALSE;
854 LONGLONG iRet = 0;
856 TRACE("(%s,%08X,%p)\n", debugstr_a(lpszStr), dwFlags, lpiRet);
858 if (!lpszStr || !lpiRet)
860 WARN("Invalid parameter would crash under Win32!\n");
861 return FALSE;
863 if (dwFlags > STIF_SUPPORT_HEX) WARN("Unknown flags %08x\n", dwFlags);
865 /* Skip leading space, '+', '-' */
866 while (isspace(*lpszStr))
867 lpszStr = CharNextA(lpszStr);
869 if (*lpszStr == '-')
871 bNegative = TRUE;
872 lpszStr++;
874 else if (*lpszStr == '+')
875 lpszStr++;
877 if (dwFlags & STIF_SUPPORT_HEX &&
878 *lpszStr == '0' && tolower(lpszStr[1]) == 'x')
880 /* Read hex number */
881 lpszStr += 2;
883 if (!isxdigit(*lpszStr))
884 return FALSE;
886 while (isxdigit(*lpszStr))
888 iRet = iRet * 16;
889 if (isdigit(*lpszStr))
890 iRet += (*lpszStr - '0');
891 else
892 iRet += 10 + (tolower(*lpszStr) - 'a');
893 lpszStr++;
895 *lpiRet = iRet;
896 return TRUE;
899 /* Read decimal number */
900 if (!isdigit(*lpszStr))
901 return FALSE;
903 while (isdigit(*lpszStr))
905 iRet = iRet * 10;
906 iRet += (*lpszStr - '0');
907 lpszStr++;
909 *lpiRet = bNegative ? -iRet : iRet;
910 return TRUE;
913 /*************************************************************************
914 * StrToIntExW [SHLWAPI.@]
916 * See StrToIntExA.
918 BOOL WINAPI StrToIntExW(LPCWSTR lpszStr, DWORD dwFlags, LPINT lpiRet)
920 LONGLONG li;
921 BOOL bRes;
923 TRACE("(%s,%08X,%p)\n", debugstr_w(lpszStr), dwFlags, lpiRet);
925 bRes = StrToInt64ExW(lpszStr, dwFlags, &li);
926 if (bRes) *lpiRet = li;
927 return bRes;
930 /*************************************************************************
931 * StrToInt64ExW [SHLWAPI.@]
933 * See StrToIntExA.
935 BOOL WINAPI StrToInt64ExW(LPCWSTR lpszStr, DWORD dwFlags, LONGLONG *lpiRet)
937 BOOL bNegative = FALSE;
938 LONGLONG iRet = 0;
940 TRACE("(%s,%08X,%p)\n", debugstr_w(lpszStr), dwFlags, lpiRet);
942 if (!lpszStr || !lpiRet)
944 WARN("Invalid parameter would crash under Win32!\n");
945 return FALSE;
947 if (dwFlags > STIF_SUPPORT_HEX) WARN("Unknown flags %08x\n", dwFlags);
949 /* Skip leading space, '+', '-' */
950 while (isspaceW(*lpszStr)) lpszStr++;
952 if (*lpszStr == '-')
954 bNegative = TRUE;
955 lpszStr++;
957 else if (*lpszStr == '+')
958 lpszStr++;
960 if (dwFlags & STIF_SUPPORT_HEX &&
961 *lpszStr == '0' && tolowerW(lpszStr[1]) == 'x')
963 /* Read hex number */
964 lpszStr += 2;
966 if (!isxdigitW(*lpszStr))
967 return FALSE;
969 while (isxdigitW(*lpszStr))
971 iRet = iRet * 16;
972 if (isdigitW(*lpszStr))
973 iRet += (*lpszStr - '0');
974 else
975 iRet += 10 + (tolowerW(*lpszStr) - 'a');
976 lpszStr++;
978 *lpiRet = iRet;
979 return TRUE;
982 /* Read decimal number */
983 if (!isdigitW(*lpszStr))
984 return FALSE;
986 while (isdigitW(*lpszStr))
988 iRet = iRet * 10;
989 iRet += (*lpszStr - '0');
990 lpszStr++;
992 *lpiRet = bNegative ? -iRet : iRet;
993 return TRUE;
996 /*************************************************************************
997 * StrDupA [SHLWAPI.@]
999 * Duplicate a string.
1001 * PARAMS
1002 * lpszStr [I] String to duplicate.
1004 * RETURNS
1005 * Success: A pointer to a new string containing the contents of lpszStr
1006 * Failure: NULL, if memory cannot be allocated
1008 * NOTES
1009 * The string memory is allocated with LocalAlloc(), and so should be released
1010 * by calling LocalFree().
1012 LPSTR WINAPI StrDupA(LPCSTR lpszStr)
1014 int iLen;
1015 LPSTR lpszRet;
1017 TRACE("(%s)\n",debugstr_a(lpszStr));
1019 iLen = lpszStr ? strlen(lpszStr) + 1 : 1;
1020 lpszRet = LocalAlloc(LMEM_FIXED, iLen);
1022 if (lpszRet)
1024 if (lpszStr)
1025 memcpy(lpszRet, lpszStr, iLen);
1026 else
1027 *lpszRet = '\0';
1029 return lpszRet;
1032 /*************************************************************************
1033 * StrDupW [SHLWAPI.@]
1035 * See StrDupA.
1037 LPWSTR WINAPI StrDupW(LPCWSTR lpszStr)
1039 int iLen;
1040 LPWSTR lpszRet;
1042 TRACE("(%s)\n",debugstr_w(lpszStr));
1044 iLen = (lpszStr ? strlenW(lpszStr) + 1 : 1) * sizeof(WCHAR);
1045 lpszRet = LocalAlloc(LMEM_FIXED, iLen);
1047 if (lpszRet)
1049 if (lpszStr)
1050 memcpy(lpszRet, lpszStr, iLen);
1051 else
1052 *lpszRet = '\0';
1054 return lpszRet;
1057 /*************************************************************************
1058 * SHLWAPI_StrSpnHelperA
1060 * Internal implementation of StrSpnA/StrCSpnA/StrCSpnIA
1062 static int SHLWAPI_StrSpnHelperA(LPCSTR lpszStr, LPCSTR lpszMatch,
1063 LPSTR (WINAPI *pStrChrFn)(LPCSTR,WORD),
1064 BOOL bInvert)
1066 LPCSTR lpszRead = lpszStr;
1067 if (lpszStr && *lpszStr && lpszMatch)
1069 while (*lpszRead)
1071 LPCSTR lpszTest = pStrChrFn(lpszMatch, *lpszRead);
1073 if (!bInvert && !lpszTest)
1074 break;
1075 if (bInvert && lpszTest)
1076 break;
1077 lpszRead = CharNextA(lpszRead);
1080 return lpszRead - lpszStr;
1083 /*************************************************************************
1084 * StrSpnA [SHLWAPI.@]
1086 * Find the length of the start of a string that contains only certain
1087 * characters.
1089 * PARAMS
1090 * lpszStr [I] String to search
1091 * lpszMatch [I] Characters that can be in the substring
1093 * RETURNS
1094 * The length of the part of lpszStr containing only chars from lpszMatch,
1095 * or 0 if any parameter is invalid.
1097 int WINAPI StrSpnA(LPCSTR lpszStr, LPCSTR lpszMatch)
1099 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1101 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, FALSE);
1104 /*************************************************************************
1105 * StrSpnW [SHLWAPI.@]
1107 * See StrSpnA.
1109 int WINAPI StrSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1111 if (!lpszStr || !lpszMatch) return 0;
1112 return strspnW( lpszStr, lpszMatch );
1115 /*************************************************************************
1116 * StrCSpnA [SHLWAPI.@]
1118 * Find the length of the start of a string that does not contain certain
1119 * characters.
1121 * PARAMS
1122 * lpszStr [I] String to search
1123 * lpszMatch [I] Characters that cannot be in the substring
1125 * RETURNS
1126 * The length of the part of lpszStr containing only chars not in lpszMatch,
1127 * or 0 if any parameter is invalid.
1129 int WINAPI StrCSpnA(LPCSTR lpszStr, LPCSTR lpszMatch)
1131 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1133 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, TRUE);
1136 /*************************************************************************
1137 * StrCSpnW [SHLWAPI.@]
1139 * See StrCSpnA.
1141 int WINAPI StrCSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1143 if (!lpszStr || !lpszMatch) return 0;
1144 return strcspnW( lpszStr, lpszMatch );
1147 /*************************************************************************
1148 * StrCSpnIA [SHLWAPI.@]
1150 * Find the length of the start of a string that does not contain certain
1151 * characters, ignoring case.
1153 * PARAMS
1154 * lpszStr [I] String to search
1155 * lpszMatch [I] Characters that cannot be in the substring
1157 * RETURNS
1158 * The length of the part of lpszStr containing only chars not in lpszMatch,
1159 * or 0 if any parameter is invalid.
1161 int WINAPI StrCSpnIA(LPCSTR lpszStr, LPCSTR lpszMatch)
1163 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1165 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrIA, TRUE);
1168 /*************************************************************************
1169 * StrCSpnIW [SHLWAPI.@]
1171 * See StrCSpnIA.
1173 int WINAPI StrCSpnIW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1175 LPCWSTR lpszRead = lpszStr;
1177 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1179 if (lpszStr && *lpszStr && lpszMatch)
1181 while (*lpszRead)
1183 if (StrChrIW(lpszMatch, *lpszRead)) break;
1184 lpszRead++;
1187 return lpszRead - lpszStr;
1190 /*************************************************************************
1191 * StrPBrkA [SHLWAPI.@]
1193 * Search a string for any of a group of characters.
1195 * PARAMS
1196 * lpszStr [I] String to search
1197 * lpszMatch [I] Characters to match
1199 * RETURNS
1200 * A pointer to the first matching character in lpszStr, or NULL if no
1201 * match was found.
1203 LPSTR WINAPI StrPBrkA(LPCSTR lpszStr, LPCSTR lpszMatch)
1205 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1207 if (lpszStr && lpszMatch && *lpszMatch)
1209 while (*lpszStr)
1211 if (StrChrA(lpszMatch, *lpszStr))
1212 return (LPSTR)lpszStr;
1213 lpszStr = CharNextA(lpszStr);
1216 return NULL;
1219 /*************************************************************************
1220 * StrPBrkW [SHLWAPI.@]
1222 * See StrPBrkA.
1224 LPWSTR WINAPI StrPBrkW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1226 if (!lpszStr || !lpszMatch) return NULL;
1227 return strpbrkW( lpszStr, lpszMatch );
1230 /*************************************************************************
1231 * SHLWAPI_StrRChrHelperA
1233 * Internal implementation of StrRChrA/StrRChrIA.
1235 static LPSTR SHLWAPI_StrRChrHelperA(LPCSTR lpszStr,
1236 LPCSTR lpszEnd, WORD ch,
1237 BOOL (WINAPI *pChrCmpFn)(WORD,WORD))
1239 LPCSTR lpszRet = NULL;
1241 if (lpszStr)
1243 WORD ch2;
1245 if (!lpszEnd)
1246 lpszEnd = lpszStr + lstrlenA(lpszStr);
1248 while (*lpszStr && lpszStr <= lpszEnd)
1250 ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr;
1252 if (!pChrCmpFn(ch, ch2))
1253 lpszRet = lpszStr;
1254 lpszStr = CharNextA(lpszStr);
1257 return (LPSTR)lpszRet;
1260 /**************************************************************************
1261 * StrRChrA [SHLWAPI.@]
1263 * Find the last occurrence of a character in string.
1265 * PARAMS
1266 * lpszStr [I] String to search in
1267 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1268 * ch [I] Character to search for.
1270 * RETURNS
1271 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1272 * or NULL if not found.
1273 * Failure: NULL, if any arguments are invalid.
1275 LPSTR WINAPI StrRChrA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch)
1277 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch);
1279 return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, SHLWAPI_ChrCmpA);
1282 /**************************************************************************
1283 * StrRChrW [SHLWAPI.@]
1285 * See StrRChrA.
1287 LPWSTR WINAPI StrRChrW(LPCWSTR str, LPCWSTR end, WORD ch)
1289 WCHAR *ret = NULL;
1291 if (!str) return NULL;
1292 if (!end) end = str + strlenW(str);
1293 while (str < end)
1295 if (*str == ch) ret = (WCHAR *)str;
1296 str++;
1298 return ret;
1301 /**************************************************************************
1302 * StrRChrIA [SHLWAPI.@]
1304 * Find the last occurrence of a character in string, ignoring case.
1306 * PARAMS
1307 * lpszStr [I] String to search in
1308 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1309 * ch [I] Character to search for.
1311 * RETURNS
1312 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1313 * or NULL if not found.
1314 * Failure: NULL, if any arguments are invalid.
1316 LPSTR WINAPI StrRChrIA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch)
1318 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch);
1320 return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, ChrCmpIA);
1323 /**************************************************************************
1324 * StrRChrIW [SHLWAPI.@]
1326 * See StrRChrIA.
1328 LPWSTR WINAPI StrRChrIW(LPCWSTR str, LPCWSTR end, WORD ch)
1330 WCHAR *ret = NULL;
1332 if (!str) return NULL;
1333 if (!end) end = str + strlenW(str);
1334 while (str < end)
1336 if (!ChrCmpIW(*str, ch)) ret = (WCHAR *)str;
1337 str++;
1339 return ret;
1342 /*************************************************************************
1343 * StrCatBuffA [SHLWAPI.@]
1345 * Concatenate two strings together.
1347 * PARAMS
1348 * lpszStr [O] String to concatenate to
1349 * lpszCat [I] String to add to lpszCat
1350 * cchMax [I] Maximum number of characters for the whole string
1352 * RETURNS
1353 * lpszStr.
1355 * NOTES
1356 * cchMax determines the number of characters in the final length of the
1357 * string, not the number appended to lpszStr from lpszCat.
1359 LPSTR WINAPI StrCatBuffA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax)
1361 INT iLen;
1363 TRACE("(%p,%s,%d)\n", lpszStr, debugstr_a(lpszCat), cchMax);
1365 if (!lpszStr)
1367 WARN("Invalid lpszStr would crash under Win32!\n");
1368 return NULL;
1371 iLen = strlen(lpszStr);
1372 cchMax -= iLen;
1374 if (cchMax > 0)
1375 StrCpyNA(lpszStr + iLen, lpszCat, cchMax);
1376 return lpszStr;
1379 /*************************************************************************
1380 * StrCatBuffW [SHLWAPI.@]
1382 * See StrCatBuffA.
1384 LPWSTR WINAPI StrCatBuffW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax)
1386 INT iLen;
1388 TRACE("(%p,%s,%d)\n", lpszStr, debugstr_w(lpszCat), cchMax);
1390 if (!lpszStr)
1392 WARN("Invalid lpszStr would crash under Win32!\n");
1393 return NULL;
1396 iLen = strlenW(lpszStr);
1397 cchMax -= iLen;
1399 if (cchMax > 0)
1400 StrCpyNW(lpszStr + iLen, lpszCat, cchMax);
1401 return lpszStr;
1404 /*************************************************************************
1405 * StrRetToBufA [SHLWAPI.@]
1407 * Convert a STRRET to a normal string.
1409 * PARAMS
1410 * lpStrRet [O] STRRET to convert
1411 * pIdl [I] ITEMIDLIST for lpStrRet->uType == STRRET_OFFSET
1412 * lpszDest [O] Destination for normal string
1413 * dwLen [I] Length of lpszDest
1415 * RETURNS
1416 * Success: S_OK. lpszDest contains up to dwLen characters of the string.
1417 * If lpStrRet is of type STRRET_WSTR, its memory is freed with
1418 * CoTaskMemFree() and its type set to STRRET_CSTRA.
1419 * Failure: E_FAIL, if any parameters are invalid.
1421 HRESULT WINAPI StrRetToBufA (LPSTRRET src, const ITEMIDLIST *pidl, LPSTR dest, UINT len)
1423 /* NOTE:
1424 * This routine is identical to that in dlls/shell32/shellstring.c.
1425 * It was duplicated because not every version of Shlwapi.dll exports
1426 * StrRetToBufA. If you change one routine, change them both.
1428 TRACE("dest=%p len=0x%x strret=%p pidl=%p\n", dest, len, src, pidl);
1430 if (!src)
1432 WARN("Invalid lpStrRet would crash under Win32!\n");
1433 if (dest)
1434 *dest = '\0';
1435 return E_FAIL;
1438 if (!dest || !len)
1439 return E_FAIL;
1441 *dest = '\0';
1443 switch (src->uType)
1445 case STRRET_WSTR:
1446 WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, dest, len, NULL, NULL);
1447 CoTaskMemFree(src->u.pOleStr);
1448 break;
1450 case STRRET_CSTR:
1451 lstrcpynA(dest, src->u.cStr, len);
1452 break;
1454 case STRRET_OFFSET:
1455 lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len);
1456 break;
1458 default:
1459 FIXME("unknown type!\n");
1460 return FALSE;
1462 return S_OK;
1465 /*************************************************************************
1466 * StrRetToBufW [SHLWAPI.@]
1468 * See StrRetToBufA.
1470 HRESULT WINAPI StrRetToBufW (LPSTRRET src, const ITEMIDLIST *pidl, LPWSTR dest, UINT len)
1472 TRACE("dest=%p len=0x%x strret=%p pidl=%p\n", dest, len, src, pidl);
1474 if (!src)
1476 WARN("Invalid lpStrRet would crash under Win32!\n");
1477 if (dest)
1478 *dest = '\0';
1479 return E_FAIL;
1482 if (!dest || !len)
1483 return E_FAIL;
1485 *dest = '\0';
1487 switch (src->uType)
1489 case STRRET_WSTR:
1490 lstrcpynW(dest, src->u.pOleStr, len);
1491 CoTaskMemFree(src->u.pOleStr);
1492 break;
1494 case STRRET_CSTR:
1495 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ))
1496 dest[len-1] = 0;
1497 break;
1499 case STRRET_OFFSET:
1500 if (pidl)
1502 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1,
1503 dest, len ))
1504 dest[len-1] = 0;
1506 break;
1508 default:
1509 FIXME("unknown type!\n");
1510 return FALSE;
1512 return S_OK;
1515 /*************************************************************************
1516 * StrRetToStrA [SHLWAPI.@]
1518 * Converts a STRRET to a normal string.
1520 * PARAMS
1521 * lpStrRet [O] STRRET to convert
1522 * pidl [I] ITEMIDLIST for lpStrRet->uType == STRRET_OFFSET
1523 * ppszName [O] Destination for converted string
1525 * RETURNS
1526 * Success: S_OK. ppszName contains the new string, allocated with CoTaskMemAlloc().
1527 * Failure: E_FAIL, if any parameters are invalid.
1529 HRESULT WINAPI StrRetToStrA(LPSTRRET lpStrRet, const ITEMIDLIST *pidl, LPSTR *ppszName)
1531 HRESULT hRet = E_FAIL;
1533 switch (lpStrRet->uType)
1535 case STRRET_WSTR:
1536 hRet = _SHStrDupAW(lpStrRet->u.pOleStr, ppszName);
1537 CoTaskMemFree(lpStrRet->u.pOleStr);
1538 break;
1540 case STRRET_CSTR:
1541 hRet = _SHStrDupAA(lpStrRet->u.cStr, ppszName);
1542 break;
1544 case STRRET_OFFSET:
1545 hRet = _SHStrDupAA(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, ppszName);
1546 break;
1548 default:
1549 *ppszName = NULL;
1552 return hRet;
1555 /*************************************************************************
1556 * StrRetToStrW [SHLWAPI.@]
1558 * See StrRetToStrA.
1560 HRESULT WINAPI StrRetToStrW(LPSTRRET lpStrRet, const ITEMIDLIST *pidl, LPWSTR *ppszName)
1562 HRESULT hRet = E_FAIL;
1564 switch (lpStrRet->uType)
1566 case STRRET_WSTR:
1567 hRet = SHStrDupW(lpStrRet->u.pOleStr, ppszName);
1568 CoTaskMemFree(lpStrRet->u.pOleStr);
1569 break;
1571 case STRRET_CSTR:
1572 hRet = SHStrDupA(lpStrRet->u.cStr, ppszName);
1573 break;
1575 case STRRET_OFFSET:
1576 hRet = SHStrDupA(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, ppszName);
1577 break;
1579 default:
1580 *ppszName = NULL;
1583 return hRet;
1586 /* Create an ASCII string copy using SysAllocString() */
1587 static HRESULT _SHStrDupAToBSTR(LPCSTR src, BSTR *pBstrOut)
1589 *pBstrOut = NULL;
1591 if (src)
1593 INT len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0);
1594 WCHAR* szTemp = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1596 if (szTemp)
1598 MultiByteToWideChar(CP_ACP, 0, src, -1, szTemp, len);
1599 *pBstrOut = SysAllocString(szTemp);
1600 HeapFree(GetProcessHeap(), 0, szTemp);
1602 if (*pBstrOut)
1603 return S_OK;
1606 return E_OUTOFMEMORY;
1609 /*************************************************************************
1610 * StrRetToBSTR [SHLWAPI.@]
1612 * Converts a STRRET to a BSTR.
1614 * PARAMS
1615 * lpStrRet [O] STRRET to convert
1616 * pidl [I] ITEMIDLIST for lpStrRet->uType = STRRET_OFFSET
1617 * pBstrOut [O] Destination for converted BSTR
1619 * RETURNS
1620 * Success: S_OK. pBstrOut contains the new string.
1621 * Failure: E_FAIL, if any parameters are invalid.
1623 HRESULT WINAPI StrRetToBSTR(STRRET *lpStrRet, LPCITEMIDLIST pidl, BSTR* pBstrOut)
1625 HRESULT hRet = E_FAIL;
1627 switch (lpStrRet->uType)
1629 case STRRET_WSTR:
1630 *pBstrOut = SysAllocString(lpStrRet->u.pOleStr);
1631 if (*pBstrOut)
1632 hRet = S_OK;
1633 CoTaskMemFree(lpStrRet->u.pOleStr);
1634 break;
1636 case STRRET_CSTR:
1637 hRet = _SHStrDupAToBSTR(lpStrRet->u.cStr, pBstrOut);
1638 break;
1640 case STRRET_OFFSET:
1641 hRet = _SHStrDupAToBSTR(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, pBstrOut);
1642 break;
1644 default:
1645 *pBstrOut = NULL;
1648 return hRet;
1651 /*************************************************************************
1652 * StrFormatKBSizeA [SHLWAPI.@]
1654 * Create a formatted string containing a byte count in Kilobytes.
1656 * PARAMS
1657 * llBytes [I] Byte size to format
1658 * lpszDest [I] Destination for formatted string
1659 * cchMax [I] Size of lpszDest
1661 * RETURNS
1662 * lpszDest.
1664 LPSTR WINAPI StrFormatKBSizeA(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax)
1666 WCHAR wszBuf[256];
1668 if (!StrFormatKBSizeW(llBytes, wszBuf, 256))
1669 return NULL;
1670 if (!WideCharToMultiByte(CP_ACP, 0, wszBuf, -1, lpszDest, cchMax, NULL, NULL))
1671 return NULL;
1672 return lpszDest;
1675 /*************************************************************************
1676 * StrFormatKBSizeW [SHLWAPI.@]
1678 * See StrFormatKBSizeA.
1680 LPWSTR WINAPI StrFormatKBSizeW(LONGLONG llBytes, LPWSTR lpszDest, UINT cchMax)
1682 static const WCHAR kb[] = {' ','K','B',0};
1683 LONGLONG llKB = (llBytes + 1023) >> 10;
1684 int len;
1686 TRACE("(0x%s,%p,%d)\n", wine_dbgstr_longlong(llBytes), lpszDest, cchMax);
1688 if (!FormatInt(llKB, lpszDest, cchMax))
1689 return NULL;
1691 len = lstrlenW(lpszDest);
1692 if (cchMax - len < 4)
1693 return NULL;
1694 lstrcatW(lpszDest, kb);
1695 return lpszDest;
1698 /*************************************************************************
1699 * StrNCatA [SHLWAPI.@]
1701 * Concatenate two strings together.
1703 * PARAMS
1704 * lpszStr [O] String to concatenate to
1705 * lpszCat [I] String to add to lpszCat
1706 * cchMax [I] Maximum number of characters to concatenate
1708 * RETURNS
1709 * lpszStr.
1711 * NOTES
1712 * cchMax determines the number of characters that are appended to lpszStr,
1713 * not the total length of the string.
1715 LPSTR WINAPI StrNCatA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax)
1717 LPSTR lpszRet = lpszStr;
1719 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszCat), cchMax);
1721 if (!lpszStr)
1723 WARN("Invalid lpszStr would crash under Win32!\n");
1724 return NULL;
1727 StrCpyNA(lpszStr + strlen(lpszStr), lpszCat, cchMax);
1728 return lpszRet;
1731 /*************************************************************************
1732 * StrNCatW [SHLWAPI.@]
1734 * See StrNCatA.
1736 LPWSTR WINAPI StrNCatW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax)
1738 LPWSTR lpszRet = lpszStr;
1740 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszCat), cchMax);
1742 if (!lpszStr)
1744 WARN("Invalid lpszStr would crash under Win32\n");
1745 return NULL;
1748 StrCpyNW(lpszStr + strlenW(lpszStr), lpszCat, cchMax);
1749 return lpszRet;
1752 /*************************************************************************
1753 * StrTrimA [SHLWAPI.@]
1755 * Remove characters from the start and end of a string.
1757 * PARAMS
1758 * lpszStr [O] String to remove characters from
1759 * lpszTrim [I] Characters to remove from lpszStr
1761 * RETURNS
1762 * TRUE If lpszStr was valid and modified
1763 * FALSE Otherwise
1765 BOOL WINAPI StrTrimA(LPSTR lpszStr, LPCSTR lpszTrim)
1767 DWORD dwLen;
1768 LPSTR lpszRead = lpszStr;
1769 BOOL bRet = FALSE;
1771 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszTrim));
1773 if (lpszRead && *lpszRead)
1775 while (*lpszRead && StrChrA(lpszTrim, *lpszRead))
1776 lpszRead = CharNextA(lpszRead); /* Skip leading matches */
1778 dwLen = strlen(lpszRead);
1780 if (lpszRead != lpszStr)
1782 memmove(lpszStr, lpszRead, dwLen + 1);
1783 bRet = TRUE;
1785 if (dwLen > 0)
1787 lpszRead = lpszStr + dwLen;
1788 while (StrChrA(lpszTrim, lpszRead[-1]))
1789 lpszRead = CharPrevA(lpszStr, lpszRead); /* Skip trailing matches */
1791 if (lpszRead != lpszStr + dwLen)
1793 *lpszRead = '\0';
1794 bRet = TRUE;
1798 return bRet;
1801 /*************************************************************************
1802 * StrTrimW [SHLWAPI.@]
1804 * See StrTrimA.
1806 BOOL WINAPI StrTrimW(LPWSTR lpszStr, LPCWSTR lpszTrim)
1808 DWORD dwLen;
1809 LPWSTR lpszRead = lpszStr;
1810 BOOL bRet = FALSE;
1812 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszTrim));
1814 if (lpszRead && *lpszRead)
1816 while (*lpszRead && StrChrW(lpszTrim, *lpszRead)) lpszRead++;
1818 dwLen = strlenW(lpszRead);
1820 if (lpszRead != lpszStr)
1822 memmove(lpszStr, lpszRead, (dwLen + 1) * sizeof(WCHAR));
1823 bRet = TRUE;
1825 if (dwLen > 0)
1827 lpszRead = lpszStr + dwLen;
1828 while (StrChrW(lpszTrim, lpszRead[-1]))
1829 lpszRead--; /* Skip trailing matches */
1831 if (lpszRead != lpszStr + dwLen)
1833 *lpszRead = '\0';
1834 bRet = TRUE;
1838 return bRet;
1841 /*************************************************************************
1842 * _SHStrDupAA [INTERNAL]
1844 * Duplicates a ASCII string to ASCII. The destination buffer is allocated.
1846 static HRESULT _SHStrDupAA(LPCSTR src, LPSTR * dest)
1848 HRESULT hr;
1849 int len = 0;
1851 if (src) {
1852 len = lstrlenA(src) + 1;
1853 *dest = CoTaskMemAlloc(len);
1854 } else {
1855 *dest = NULL;
1858 if (*dest) {
1859 lstrcpynA(*dest,src, len);
1860 hr = S_OK;
1861 } else {
1862 hr = E_OUTOFMEMORY;
1865 TRACE("%s->(%p)\n", debugstr_a(src), *dest);
1866 return hr;
1869 /*************************************************************************
1870 * SHStrDupA [SHLWAPI.@]
1872 * Return a Unicode copy of a string, in memory allocated by CoTaskMemAlloc().
1874 * PARAMS
1875 * lpszStr [I] String to copy
1876 * lppszDest [O] Destination for the new string copy
1878 * RETURNS
1879 * Success: S_OK. lppszDest contains the new string in Unicode format.
1880 * Failure: E_OUTOFMEMORY, If any arguments are invalid or memory allocation
1881 * fails.
1883 HRESULT WINAPI SHStrDupA(LPCSTR lpszStr, LPWSTR * lppszDest)
1885 HRESULT hRet;
1886 int len = 0;
1888 if (lpszStr)
1890 len = MultiByteToWideChar(CP_ACP, 0, lpszStr, -1, NULL, 0) * sizeof(WCHAR);
1891 *lppszDest = CoTaskMemAlloc(len);
1893 else
1894 *lppszDest = NULL;
1896 if (*lppszDest)
1898 MultiByteToWideChar(CP_ACP, 0, lpszStr, -1, *lppszDest, len/sizeof(WCHAR));
1899 hRet = S_OK;
1901 else
1902 hRet = E_OUTOFMEMORY;
1904 TRACE("%s->(%p)\n", debugstr_a(lpszStr), *lppszDest);
1905 return hRet;
1908 /*************************************************************************
1909 * _SHStrDupAW [INTERNAL]
1911 * Duplicates a UNICODE to a ASCII string. The destination buffer is allocated.
1913 static HRESULT _SHStrDupAW(LPCWSTR src, LPSTR * dest)
1915 HRESULT hr;
1916 int len = 0;
1918 if (src) {
1919 len = WideCharToMultiByte(CP_ACP, 0, src, -1, NULL, 0, NULL, NULL);
1920 *dest = CoTaskMemAlloc(len);
1921 } else {
1922 *dest = NULL;
1925 if (*dest) {
1926 WideCharToMultiByte(CP_ACP, 0, src, -1, *dest, len, NULL, NULL);
1927 hr = S_OK;
1928 } else {
1929 hr = E_OUTOFMEMORY;
1932 TRACE("%s->(%p)\n", debugstr_w(src), *dest);
1933 return hr;
1936 /*************************************************************************
1937 * SHStrDupW [SHLWAPI.@]
1939 * See SHStrDupA.
1941 HRESULT WINAPI SHStrDupW(LPCWSTR src, LPWSTR * dest)
1943 HRESULT hr;
1944 int len = 0;
1946 if (src) {
1947 len = (lstrlenW(src) + 1) * sizeof(WCHAR);
1948 *dest = CoTaskMemAlloc(len);
1949 } else {
1950 *dest = NULL;
1953 if (*dest) {
1954 memcpy(*dest, src, len);
1955 hr = S_OK;
1956 } else {
1957 hr = E_OUTOFMEMORY;
1960 TRACE("%s->(%p)\n", debugstr_w(src), *dest);
1961 return hr;
1964 /*************************************************************************
1965 * SHLWAPI_WriteReverseNum
1967 * Internal helper for SHLWAPI_WriteTimeClass.
1969 static inline LPWSTR SHLWAPI_WriteReverseNum(LPWSTR lpszOut, DWORD dwNum)
1971 *lpszOut-- = '\0';
1973 /* Write a decimal number to a string, backwards */
1976 DWORD dwNextDigit = dwNum % 10;
1977 *lpszOut-- = '0' + dwNextDigit;
1978 dwNum = (dwNum - dwNextDigit) / 10;
1979 } while (dwNum > 0);
1981 return lpszOut;
1984 /*************************************************************************
1985 * SHLWAPI_FormatSignificant
1987 * Internal helper for SHLWAPI_WriteTimeClass.
1989 static inline int SHLWAPI_FormatSignificant(LPWSTR lpszNum, int dwDigits)
1991 /* Zero non significant digits, return remaining significant digits */
1992 while (*lpszNum)
1994 lpszNum++;
1995 if (--dwDigits == 0)
1997 while (*lpszNum)
1998 *lpszNum++ = '0';
1999 return 0;
2002 return dwDigits;
2005 /*************************************************************************
2006 * SHLWAPI_WriteTimeClass
2008 * Internal helper for StrFromTimeIntervalW.
2010 static int SHLWAPI_WriteTimeClass(LPWSTR lpszOut, DWORD dwValue,
2011 UINT uClassStringId, int iDigits)
2013 WCHAR szBuff[64], *szOut = szBuff + 32;
2015 szOut = SHLWAPI_WriteReverseNum(szOut, dwValue);
2016 iDigits = SHLWAPI_FormatSignificant(szOut + 1, iDigits);
2017 *szOut = ' ';
2018 LoadStringW(shlwapi_hInstance, uClassStringId, szBuff + 32, 32);
2019 strcatW(lpszOut, szOut);
2020 return iDigits;
2023 /*************************************************************************
2024 * StrFromTimeIntervalA [SHLWAPI.@]
2026 * Format a millisecond time interval into a string
2028 * PARAMS
2029 * lpszStr [O] Output buffer for formatted time interval
2030 * cchMax [I] Size of lpszStr
2031 * dwMS [I] Number of milliseconds
2032 * iDigits [I] Number of digits to print
2034 * RETURNS
2035 * The length of the formatted string, or 0 if any parameter is invalid.
2037 * NOTES
2038 * This implementation mimics the Win32 behaviour of always writing a leading
2039 * space before the time interval begins.
2041 * iDigits is used to provide approximate times if accuracy is not important.
2042 * This number of digits will be written of the first non-zero time class
2043 * (hours/minutes/seconds). If this does not complete the time classification,
2044 * the remaining digits are changed to zeros (i.e. The time is _not_ rounded).
2045 * If there are digits remaining following the writing of a time class, the
2046 * next time class will be written.
2048 * For example, given dwMS represents 138 hours,43 minutes and 15 seconds, the
2049 * following will result from the given values of iDigits:
2051 *| iDigits 1 2 3 4 5 ...
2052 *| lpszStr "100 hr" "130 hr" "138 hr" "138 hr 40 min" "138 hr 43 min" ...
2054 INT WINAPI StrFromTimeIntervalA(LPSTR lpszStr, UINT cchMax, DWORD dwMS,
2055 int iDigits)
2057 INT iRet = 0;
2059 TRACE("(%p,%d,%d,%d)\n", lpszStr, cchMax, dwMS, iDigits);
2061 if (lpszStr && cchMax)
2063 WCHAR szBuff[128];
2064 StrFromTimeIntervalW(szBuff, sizeof(szBuff)/sizeof(WCHAR), dwMS, iDigits);
2065 WideCharToMultiByte(CP_ACP,0,szBuff,-1,lpszStr,cchMax,0,0);
2067 return iRet;
2071 /*************************************************************************
2072 * StrFromTimeIntervalW [SHLWAPI.@]
2074 * See StrFromTimeIntervalA.
2076 INT WINAPI StrFromTimeIntervalW(LPWSTR lpszStr, UINT cchMax, DWORD dwMS,
2077 int iDigits)
2079 INT iRet = 0;
2081 TRACE("(%p,%d,%d,%d)\n", lpszStr, cchMax, dwMS, iDigits);
2083 if (lpszStr && cchMax)
2085 WCHAR szCopy[128];
2086 DWORD dwHours, dwMinutes;
2088 if (!iDigits || cchMax == 1)
2090 *lpszStr = '\0';
2091 return 0;
2094 /* Calculate the time classes */
2095 dwMS = (dwMS + 500) / 1000;
2096 dwHours = dwMS / 3600;
2097 dwMS -= dwHours * 3600;
2098 dwMinutes = dwMS / 60;
2099 dwMS -= dwMinutes * 60;
2101 szCopy[0] = '\0';
2103 if (dwHours)
2104 iDigits = SHLWAPI_WriteTimeClass(szCopy, dwHours, IDS_TIME_INTERVAL_HOURS, iDigits);
2106 if (dwMinutes && iDigits)
2107 iDigits = SHLWAPI_WriteTimeClass(szCopy, dwMinutes, IDS_TIME_INTERVAL_MINUTES, iDigits);
2109 if (iDigits) /* Always write seconds if we have significant digits */
2110 SHLWAPI_WriteTimeClass(szCopy, dwMS, IDS_TIME_INTERVAL_SECONDS, iDigits);
2112 lstrcpynW(lpszStr, szCopy, cchMax);
2113 iRet = strlenW(lpszStr);
2115 return iRet;
2118 /*************************************************************************
2119 * StrIsIntlEqualA [SHLWAPI.@]
2121 * Compare two strings.
2123 * PARAMS
2124 * bCase [I] Whether to compare case sensitively
2125 * lpszStr [I] First string to compare
2126 * lpszComp [I] Second string to compare
2127 * iLen [I] Length to compare
2129 * RETURNS
2130 * TRUE If the strings are equal.
2131 * FALSE Otherwise.
2133 BOOL WINAPI StrIsIntlEqualA(BOOL bCase, LPCSTR lpszStr, LPCSTR lpszComp,
2134 int iLen)
2136 DWORD dwFlags;
2138 TRACE("(%d,%s,%s,%d)\n", bCase,
2139 debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
2141 /* FIXME: This flag is undocumented and unknown by our CompareString.
2142 * We need a define for it.
2144 dwFlags = 0x10000000;
2145 if (!bCase) dwFlags |= NORM_IGNORECASE;
2147 return (CompareStringA(GetThreadLocale(), dwFlags, lpszStr, iLen, lpszComp, iLen) == CSTR_EQUAL);
2150 /*************************************************************************
2151 * StrIsIntlEqualW [SHLWAPI.@]
2153 * See StrIsIntlEqualA.
2155 BOOL WINAPI StrIsIntlEqualW(BOOL bCase, LPCWSTR lpszStr, LPCWSTR lpszComp,
2156 int iLen)
2158 DWORD dwFlags;
2160 TRACE("(%d,%s,%s,%d)\n", bCase,
2161 debugstr_w(lpszStr),debugstr_w(lpszComp), iLen);
2163 /* FIXME: This flag is undocumented and unknown by our CompareString.
2164 * We need a define for it.
2166 dwFlags = 0x10000000;
2167 if (!bCase) dwFlags |= NORM_IGNORECASE;
2169 return (CompareStringW(GetThreadLocale(), dwFlags, lpszStr, iLen, lpszComp, iLen) == CSTR_EQUAL);
2172 /*************************************************************************
2173 * @ [SHLWAPI.399]
2175 * Copy a string to another string, up to a maximum number of characters.
2177 * PARAMS
2178 * lpszDest [O] Destination string
2179 * lpszSrc [I] Source string
2180 * iLen [I] Maximum number of chars to copy
2182 * RETURNS
2183 * Success: A pointer to the last character written to lpszDest.
2184 * Failure: lpszDest, if any arguments are invalid.
2186 LPSTR WINAPI StrCpyNXA(LPSTR lpszDest, LPCSTR lpszSrc, int iLen)
2188 TRACE("(%p,%s,%i)\n", lpszDest, debugstr_a(lpszSrc), iLen);
2190 if (lpszDest && lpszSrc && iLen > 0)
2192 while ((iLen-- > 1) && *lpszSrc)
2193 *lpszDest++ = *lpszSrc++;
2194 if (iLen >= 0)
2195 *lpszDest = '\0';
2197 return lpszDest;
2200 /*************************************************************************
2201 * @ [SHLWAPI.400]
2203 * Unicode version of StrCpyNXA.
2205 LPWSTR WINAPI StrCpyNXW(LPWSTR lpszDest, LPCWSTR lpszSrc, int iLen)
2207 TRACE("(%p,%s,%i)\n", lpszDest, debugstr_w(lpszSrc), iLen);
2209 if (lpszDest && lpszSrc && iLen > 0)
2211 while ((iLen-- > 1) && *lpszSrc)
2212 *lpszDest++ = *lpszSrc++;
2213 if (iLen >= 0)
2214 *lpszDest = '\0';
2216 return lpszDest;
2219 /*************************************************************************
2220 * StrCmpLogicalW [SHLWAPI.@]
2222 * Compare two strings, ignoring case and comparing digits as numbers.
2224 * PARAMS
2225 * lpszStr [I] First string to compare
2226 * lpszComp [I] Second string to compare
2227 * iLen [I] Length to compare
2229 * RETURNS
2230 * TRUE If the strings are equal.
2231 * FALSE Otherwise.
2233 INT WINAPI StrCmpLogicalW(LPCWSTR lpszStr, LPCWSTR lpszComp)
2235 INT iDiff;
2237 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszComp));
2239 if (lpszStr && lpszComp)
2241 while (*lpszStr)
2243 if (!*lpszComp)
2244 return 1;
2245 else if (isdigitW(*lpszStr))
2247 int iStr, iComp;
2249 if (!isdigitW(*lpszComp))
2250 return -1;
2252 /* Compare the numbers */
2253 StrToIntExW(lpszStr, 0, &iStr);
2254 StrToIntExW(lpszComp, 0, &iComp);
2256 if (iStr < iComp)
2257 return -1;
2258 else if (iStr > iComp)
2259 return 1;
2261 /* Skip */
2262 while (isdigitW(*lpszStr))
2263 lpszStr++;
2264 while (isdigitW(*lpszComp))
2265 lpszComp++;
2267 else if (isdigitW(*lpszComp))
2268 return 1;
2269 else
2271 iDiff = ChrCmpIW(*lpszStr,*lpszComp);
2272 if (iDiff > 0)
2273 return 1;
2274 else if (iDiff < 0)
2275 return -1;
2277 lpszStr++;
2278 lpszComp++;
2281 if (*lpszComp)
2282 return -1;
2284 return 0;
2287 /* Structure for formatting byte strings */
2288 typedef struct tagSHLWAPI_BYTEFORMATS
2290 LONGLONG dLimit;
2291 double dDivisor;
2292 double dNormaliser;
2293 int nDecimals;
2294 WCHAR wPrefix;
2295 } SHLWAPI_BYTEFORMATS;
2297 /*************************************************************************
2298 * StrFormatByteSizeW [SHLWAPI.@]
2300 * Create a string containing an abbreviated byte count of up to 2^63-1.
2302 * PARAMS
2303 * llBytes [I] Byte size to format
2304 * lpszDest [I] Destination for formatted string
2305 * cchMax [I] Size of lpszDest
2307 * RETURNS
2308 * lpszDest.
2310 * NOTES
2311 * There is no StrFormatByteSize64W function, it is called StrFormatByteSizeW().
2313 LPWSTR WINAPI StrFormatByteSizeW(LONGLONG llBytes, LPWSTR lpszDest, UINT cchMax)
2315 #define KB ((ULONGLONG)1024)
2316 #define MB (KB*KB)
2317 #define GB (KB*KB*KB)
2318 #define TB (KB*KB*KB*KB)
2319 #define PB (KB*KB*KB*KB*KB)
2321 static const SHLWAPI_BYTEFORMATS bfFormats[] =
2323 { 10*KB, 10.24, 100.0, 2, 'K' }, /* 10 KB */
2324 { 100*KB, 102.4, 10.0, 1, 'K' }, /* 100 KB */
2325 { 1000*KB, 1024.0, 1.0, 0, 'K' }, /* 1000 KB */
2326 { 10*MB, 10485.76, 100.0, 2, 'M' }, /* 10 MB */
2327 { 100*MB, 104857.6, 10.0, 1, 'M' }, /* 100 MB */
2328 { 1000*MB, 1048576.0, 1.0, 0, 'M' }, /* 1000 MB */
2329 { 10*GB, 10737418.24, 100.0, 2, 'G' }, /* 10 GB */
2330 { 100*GB, 107374182.4, 10.0, 1, 'G' }, /* 100 GB */
2331 { 1000*GB, 1073741824.0, 1.0, 0, 'G' }, /* 1000 GB */
2332 { 10*TB, 10485.76, 100.0, 2, 'T' }, /* 10 TB */
2333 { 100*TB, 104857.6, 10.0, 1, 'T' }, /* 100 TB */
2334 { 1000*TB, 1048576.0, 1.0, 0, 'T' }, /* 1000 TB */
2335 { 10*PB, 10737418.24, 100.00, 2, 'P' }, /* 10 PB */
2336 { 100*PB, 107374182.4, 10.00, 1, 'P' }, /* 100 PB */
2337 { 1000*PB, 1073741824.0, 1.00, 0, 'P' }, /* 1000 PB */
2338 { 0, 10995116277.76, 100.00, 2, 'E' } /* EB's, catch all */
2340 WCHAR wszAdd[] = {' ','?','B',0};
2341 double dBytes;
2342 UINT i = 0;
2344 TRACE("(0x%s,%p,%d)\n", wine_dbgstr_longlong(llBytes), lpszDest, cchMax);
2346 if (!lpszDest || !cchMax)
2347 return lpszDest;
2349 if (llBytes < 1024) /* 1K */
2351 WCHAR wszBytesFormat[64];
2352 LoadStringW(shlwapi_hInstance, IDS_BYTES_FORMAT, wszBytesFormat, 64);
2353 snprintfW(lpszDest, cchMax, wszBytesFormat, (int)llBytes);
2354 return lpszDest;
2357 /* Note that if this loop completes without finding a match, i will be
2358 * pointing at the last entry, which is a catch all for > 1000 PB
2360 while (i < sizeof(bfFormats) / sizeof(SHLWAPI_BYTEFORMATS) - 1)
2362 if (llBytes < bfFormats[i].dLimit)
2363 break;
2364 i++;
2366 /* Above 1 TB we encounter problems with FP accuracy. So for amounts above
2367 * this number we integer shift down by 1 MB first. The table above has
2368 * the divisors scaled down from the '< 10 TB' entry onwards, to account
2369 * for this. We also add a small fudge factor to get the correct result for
2370 * counts that lie exactly on a 1024 byte boundary.
2372 if (i > 8)
2373 dBytes = (double)(llBytes >> 20) + 0.001; /* Scale down by 1 MB */
2374 else
2375 dBytes = (double)llBytes + 0.00001;
2377 dBytes = floor(dBytes / bfFormats[i].dDivisor) / bfFormats[i].dNormaliser;
2379 if (!FormatDouble(dBytes, bfFormats[i].nDecimals, lpszDest, cchMax))
2380 return NULL;
2381 wszAdd[1] = bfFormats[i].wPrefix;
2382 StrCatBuffW(lpszDest, wszAdd, cchMax);
2383 return lpszDest;
2386 /*************************************************************************
2387 * StrFormatByteSize64A [SHLWAPI.@]
2389 * See StrFormatByteSizeW.
2391 LPSTR WINAPI StrFormatByteSize64A(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax)
2393 WCHAR wszBuff[32];
2395 StrFormatByteSizeW(llBytes, wszBuff, sizeof(wszBuff)/sizeof(WCHAR));
2397 if (lpszDest)
2398 WideCharToMultiByte(CP_ACP, 0, wszBuff, -1, lpszDest, cchMax, 0, 0);
2399 return lpszDest;
2402 /*************************************************************************
2403 * StrFormatByteSizeA [SHLWAPI.@]
2405 * Create a string containing an abbreviated byte count of up to 2^31-1.
2407 * PARAMS
2408 * dwBytes [I] Byte size to format
2409 * lpszDest [I] Destination for formatted string
2410 * cchMax [I] Size of lpszDest
2412 * RETURNS
2413 * lpszDest.
2415 * NOTES
2416 * The Ascii and Unicode versions of this function accept a different
2417 * integer type for dwBytes. See StrFormatByteSize64A().
2419 LPSTR WINAPI StrFormatByteSizeA(DWORD dwBytes, LPSTR lpszDest, UINT cchMax)
2421 TRACE("(%d,%p,%d)\n", dwBytes, lpszDest, cchMax);
2423 return StrFormatByteSize64A(dwBytes, lpszDest, cchMax);
2426 /*************************************************************************
2427 * @ [SHLWAPI.162]
2429 * Remove a hanging lead byte from the end of a string, if present.
2431 * PARAMS
2432 * lpStr [I] String to check for a hanging lead byte
2433 * size [I] Length of lpStr
2435 * RETURNS
2436 * Success: The new length of the string. Any hanging lead bytes are removed.
2437 * Failure: 0, if any parameters are invalid.
2439 DWORD WINAPI SHTruncateString(LPSTR lpStr, DWORD size)
2441 if (lpStr && size)
2443 LPSTR lastByte = lpStr + size - 1;
2445 while(lpStr < lastByte)
2446 lpStr += IsDBCSLeadByte(*lpStr) ? 2 : 1;
2448 if(lpStr == lastByte && IsDBCSLeadByte(*lpStr))
2450 *lpStr = '\0';
2451 size--;
2453 return size;
2455 return 0;
2458 /*************************************************************************
2459 * @ [SHLWAPI.203]
2461 * Remove a single non-trailing ampersand ('&') from a string.
2463 * PARAMS
2464 * lpszStr [I/O] String to remove ampersand from.
2466 * RETURNS
2467 * The character after the first ampersand in lpszStr, or the first character
2468 * in lpszStr if there is no ampersand in the string.
2470 char WINAPI SHStripMneumonicA(LPCSTR lpszStr)
2472 LPSTR lpszIter, lpszTmp;
2473 char ch;
2475 TRACE("(%s)\n", debugstr_a(lpszStr));
2477 ch = *lpszStr;
2479 if ((lpszIter = StrChrA(lpszStr, '&')))
2481 lpszTmp = CharNextA(lpszIter);
2482 if (*lpszTmp)
2484 if (*lpszTmp != '&')
2485 ch = *lpszTmp;
2487 memmove( lpszIter, lpszTmp, strlen(lpszTmp) + 1 );
2491 return ch;
2494 /*************************************************************************
2495 * @ [SHLWAPI.225]
2497 * Unicode version of SHStripMneumonicA.
2499 WCHAR WINAPI SHStripMneumonicW(LPCWSTR lpszStr)
2501 LPWSTR lpszIter, lpszTmp;
2502 WCHAR ch;
2504 TRACE("(%s)\n", debugstr_w(lpszStr));
2506 ch = *lpszStr;
2508 if ((lpszIter = StrChrW(lpszStr, '&')))
2510 lpszTmp = lpszIter + 1;
2511 if (*lpszTmp)
2513 if (*lpszTmp != '&')
2514 ch = *lpszTmp;
2516 memmove( lpszIter, lpszTmp, (strlenW(lpszTmp) + 1) * sizeof(WCHAR) );
2520 return ch;
2523 /*************************************************************************
2524 * @ [SHLWAPI.216]
2526 * Convert an Ascii string to Unicode.
2528 * PARAMS
2529 * dwCp [I] Code page for the conversion
2530 * lpSrcStr [I] Source Ascii string to convert
2531 * lpDstStr [O] Destination for converted Unicode string
2532 * iLen [I] Length of lpDstStr
2534 * RETURNS
2535 * The return value of the MultiByteToWideChar() function called on lpSrcStr.
2537 DWORD WINAPI SHAnsiToUnicodeCP(DWORD dwCp, LPCSTR lpSrcStr, LPWSTR lpDstStr, int iLen)
2539 DWORD dwRet;
2541 dwRet = MultiByteToWideChar(dwCp, 0, lpSrcStr, -1, lpDstStr, iLen);
2542 TRACE("%s->%s,ret=%d\n", debugstr_a(lpSrcStr), debugstr_w(lpDstStr), dwRet);
2543 return dwRet;
2546 /*************************************************************************
2547 * @ [SHLWAPI.215]
2549 * Convert an Ascii string to Unicode.
2551 * PARAMS
2552 * lpSrcStr [I] Source Ascii string to convert
2553 * lpDstStr [O] Destination for converted Unicode string
2554 * iLen [I] Length of lpDstStr
2556 * RETURNS
2557 * The return value of the MultiByteToWideChar() function called on lpSrcStr.
2559 * NOTES
2560 * This function simply calls SHAnsiToUnicodeCP with code page CP_ACP.
2562 DWORD WINAPI SHAnsiToUnicode(LPCSTR lpSrcStr, LPWSTR lpDstStr, int iLen)
2564 return SHAnsiToUnicodeCP(CP_ACP, lpSrcStr, lpDstStr, iLen);
2567 /*************************************************************************
2568 * @ [SHLWAPI.218]
2570 * Convert a Unicode string to Ascii.
2572 * PARAMS
2573 * CodePage [I] Code page to use for the conversion
2574 * lpSrcStr [I] Source Unicode string to convert
2575 * lpDstStr [O] Destination for converted Ascii string
2576 * dstlen [I] Length of buffer at lpDstStr
2578 * RETURNS
2579 * Success: The length in bytes of the result at lpDstStr (including the terminator)
2580 * Failure: When using CP_UTF8, CP_UTF7 or 0xc350 as codePage, 0 is returned and
2581 * the result is not nul-terminated.
2582 * When using a different codepage, the length in bytes of the truncated
2583 * result at lpDstStr (including the terminator) is returned and
2584 * lpDstStr is always nul-terminated.
2587 DWORD WINAPI SHUnicodeToAnsiCP(UINT CodePage, LPCWSTR lpSrcStr, LPSTR lpDstStr, int dstlen)
2589 static const WCHAR emptyW[] = { '\0' };
2590 int len , reqLen;
2591 LPSTR mem;
2593 if (!lpDstStr || !dstlen)
2594 return 0;
2596 if (!lpSrcStr)
2597 lpSrcStr = emptyW;
2599 *lpDstStr = '\0';
2601 len = strlenW(lpSrcStr) + 1;
2603 switch (CodePage)
2605 case CP_WINUNICODE:
2606 CodePage = CP_UTF8; /* Fall through... */
2607 case 0x0000C350: /* FIXME: CP_ #define */
2608 case CP_UTF7:
2609 case CP_UTF8:
2611 DWORD dwMode = 0;
2612 INT lenW = len - 1;
2613 INT needed = dstlen - 1;
2614 HRESULT hr;
2616 /* try the user supplied buffer first */
2617 hr = ConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &lenW, lpDstStr, &needed);
2618 if (hr == S_OK)
2620 lpDstStr[needed] = '\0';
2621 return needed + 1;
2624 /* user buffer too small. exclude termination and copy as much as possible */
2625 lenW = len;
2626 hr = ConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &lenW, NULL, &needed);
2627 needed++;
2628 mem = HeapAlloc(GetProcessHeap(), 0, needed);
2629 if (!mem)
2630 return 0;
2632 hr = ConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &len, mem, &needed);
2633 if (hr == S_OK)
2635 reqLen = SHTruncateString(mem, dstlen);
2636 if (reqLen > 0) memcpy(lpDstStr, mem, reqLen-1);
2638 HeapFree(GetProcessHeap(), 0, mem);
2639 return 0;
2641 default:
2642 break;
2645 /* try the user supplied buffer first */
2646 reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, lpDstStr, dstlen, NULL, NULL);
2648 if (!reqLen && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
2650 reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, NULL, 0, NULL, NULL);
2651 if (reqLen)
2653 mem = HeapAlloc(GetProcessHeap(), 0, reqLen);
2654 if (mem)
2656 reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, mem,
2657 reqLen, NULL, NULL);
2659 reqLen = SHTruncateString(mem, dstlen -1);
2660 reqLen++;
2662 lstrcpynA(lpDstStr, mem, reqLen);
2663 HeapFree(GetProcessHeap(), 0, mem);
2664 lpDstStr[reqLen-1] = '\0';
2668 return reqLen;
2671 /*************************************************************************
2672 * @ [SHLWAPI.217]
2674 * Convert a Unicode string to Ascii.
2676 * PARAMS
2677 * lpSrcStr [I] Source Unicode string to convert
2678 * lpDstStr [O] Destination for converted Ascii string
2679 * iLen [O] Length of lpDstStr in characters
2681 * RETURNS
2682 * See SHUnicodeToAnsiCP
2684 * NOTES
2685 * This function simply calls SHUnicodeToAnsiCP() with CodePage = CP_ACP.
2687 INT WINAPI SHUnicodeToAnsi(LPCWSTR lpSrcStr, LPSTR lpDstStr, INT iLen)
2689 return SHUnicodeToAnsiCP(CP_ACP, lpSrcStr, lpDstStr, iLen);
2692 /*************************************************************************
2693 * @ [SHLWAPI.345]
2695 * Copy one string to another.
2697 * PARAMS
2698 * lpszSrc [I] Source string to copy
2699 * lpszDst [O] Destination for copy
2700 * iLen [I] Length of lpszDst in characters
2702 * RETURNS
2703 * The length of the copied string, including the terminating NUL. lpszDst
2704 * contains iLen characters of lpszSrc.
2706 DWORD WINAPI SHAnsiToAnsi(LPCSTR lpszSrc, LPSTR lpszDst, int iLen)
2708 LPSTR lpszRet;
2710 TRACE("(%s,%p,0x%08x)\n", debugstr_a(lpszSrc), lpszDst, iLen);
2712 lpszRet = StrCpyNXA(lpszDst, lpszSrc, iLen);
2713 return lpszRet - lpszDst + 1;
2716 /*************************************************************************
2717 * @ [SHLWAPI.346]
2719 * Unicode version of SSHAnsiToAnsi.
2721 DWORD WINAPI SHUnicodeToUnicode(LPCWSTR lpszSrc, LPWSTR lpszDst, int iLen)
2723 LPWSTR lpszRet;
2725 TRACE("(%s,%p,0x%08x)\n", debugstr_w(lpszSrc), lpszDst, iLen);
2727 lpszRet = StrCpyNXW(lpszDst, lpszSrc, iLen);
2728 return lpszRet - lpszDst + 1;
2731 /*************************************************************************
2732 * @ [SHLWAPI.364]
2734 * Determine if an Ascii string converts to Unicode and back identically.
2736 * PARAMS
2737 * lpSrcStr [I] Source Unicode string to convert
2738 * lpDst [O] Destination for resulting Ascii string
2739 * iLen [I] Length of lpDst in characters
2741 * RETURNS
2742 * TRUE, since Ascii strings always convert identically.
2744 BOOL WINAPI DoesStringRoundTripA(LPCSTR lpSrcStr, LPSTR lpDst, INT iLen)
2746 lstrcpynA(lpDst, lpSrcStr, iLen);
2747 return TRUE;
2750 /*************************************************************************
2751 * @ [SHLWAPI.365]
2753 * Determine if a Unicode string converts to Ascii and back identically.
2755 * PARAMS
2756 * lpSrcStr [I] Source Unicode string to convert
2757 * lpDst [O] Destination for resulting Ascii string
2758 * iLen [I] Length of lpDst in characters
2760 * RETURNS
2761 * TRUE, if lpSrcStr converts to Ascii and back identically,
2762 * FALSE otherwise.
2764 BOOL WINAPI DoesStringRoundTripW(LPCWSTR lpSrcStr, LPSTR lpDst, INT iLen)
2766 WCHAR szBuff[MAX_PATH];
2768 SHUnicodeToAnsi(lpSrcStr, lpDst, iLen);
2769 SHAnsiToUnicode(lpDst, szBuff, MAX_PATH);
2770 return !strcmpW(lpSrcStr, szBuff);
2773 /*************************************************************************
2774 * SHLoadIndirectString [SHLWAPI.@]
2776 * If passed a string that begins with '@', extract the string from the
2777 * appropriate resource, otherwise do a straight copy.
2780 HRESULT WINAPI SHLoadIndirectString(LPCWSTR src, LPWSTR dst, UINT dst_len, void **reserved)
2782 WCHAR *dllname = NULL;
2783 HMODULE hmod = NULL;
2784 HRESULT hr = E_FAIL;
2786 TRACE("(%s %p %08x %p)\n", debugstr_w(src), dst, dst_len, reserved);
2788 if(src[0] == '@')
2790 WCHAR *index_str;
2791 int index;
2793 dst[0] = 0;
2794 dllname = StrDupW(src + 1);
2795 index_str = strchrW(dllname, ',');
2797 if(!index_str) goto end;
2799 *index_str = 0;
2800 index_str++;
2801 index = atoiW(index_str);
2803 hmod = LoadLibraryW(dllname);
2804 if(!hmod) goto end;
2806 if(index < 0)
2808 if(LoadStringW(hmod, -index, dst, dst_len))
2809 hr = S_OK;
2811 else
2812 FIXME("can't handle non-negative indices (%d)\n", index);
2814 else
2816 if(dst != src)
2817 lstrcpynW(dst, src, dst_len);
2818 hr = S_OK;
2821 TRACE("returning %s\n", debugstr_w(dst));
2822 end:
2823 if(hmod) FreeLibrary(hmod);
2824 HeapFree(GetProcessHeap(), 0, dllname);
2825 return hr;
2828 BOOL WINAPI IsCharSpaceA(CHAR c)
2830 WORD CharType;
2831 return GetStringTypeA(GetSystemDefaultLCID(), CT_CTYPE1, &c, 1, &CharType) && (CharType & C1_SPACE);
2834 /*************************************************************************
2835 * @ [SHLWAPI.29]
2837 * Determine if a Unicode character is a space.
2839 * PARAMS
2840 * wc [I] Character to check.
2842 * RETURNS
2843 * TRUE, if wc is a space,
2844 * FALSE otherwise.
2846 BOOL WINAPI IsCharSpaceW(WCHAR wc)
2848 WORD CharType;
2850 return GetStringTypeW(CT_CTYPE1, &wc, 1, &CharType) && (CharType & C1_SPACE);