quartz: Update null renderer to use the BaseRenderer from strmbase.
[wine.git] / dlls / shlwapi / string.c
blobc65d5760964c3107e4bab7e5f9b11d73d3dd445e
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) - 2;
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) - 2;
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 int iRet;
357 TRACE("(%s,%s)\n", debugstr_w(lpszStr),debugstr_w(lpszComp));
359 iRet = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, lpszStr, -1, lpszComp, -1);
360 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
363 /*************************************************************************
364 * StrCmpNA [SHLWAPI.@]
366 * Compare two strings, up to a maximum length.
368 * PARAMS
369 * lpszStr [I] First string to compare
370 * lpszComp [I] Second string to compare
371 * iLen [I] Maximum number of chars to compare.
373 * RETURNS
374 * An integer less than, equal to or greater than 0, indicating that
375 * lpszStr is less than, the same, or greater than lpszComp.
377 INT WINAPI StrCmpNA(LPCSTR lpszStr, LPCSTR lpszComp, INT iLen)
379 INT iRet;
381 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
383 iRet = CompareStringA(GetThreadLocale(), 0, lpszStr, iLen, lpszComp, iLen);
384 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
387 /*************************************************************************
388 * StrCmpNW [SHLWAPI.@]
390 * See StrCmpNA.
392 INT WINAPI StrCmpNW(LPCWSTR lpszStr, LPCWSTR lpszComp, INT iLen)
394 INT iRet;
396 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen);
398 iRet = CompareStringW(GetThreadLocale(), 0, lpszStr, iLen, lpszComp, iLen);
399 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
402 /*************************************************************************
403 * StrCmpNIA [SHLWAPI.@]
405 * Compare two strings, up to a maximum length, ignoring case.
407 * PARAMS
408 * lpszStr [I] First string to compare
409 * lpszComp [I] Second string to compare
410 * iLen [I] Maximum number of chars to compare.
412 * RETURNS
413 * An integer less than, equal to or greater than 0, indicating that
414 * lpszStr is less than, the same, or greater than lpszComp.
416 int WINAPI StrCmpNIA(LPCSTR lpszStr, LPCSTR lpszComp, int iLen)
418 INT iRet;
420 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
422 iRet = CompareStringA(GetThreadLocale(), NORM_IGNORECASE, lpszStr, iLen, lpszComp, iLen);
423 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
426 /*************************************************************************
427 * StrCmpNIW [SHLWAPI.@]
429 * See StrCmpNIA.
431 INT WINAPI StrCmpNIW(LPCWSTR lpszStr, LPCWSTR lpszComp, int iLen)
433 INT iRet;
435 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen);
437 iRet = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, lpszStr, iLen, lpszComp, iLen);
438 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
441 /*************************************************************************
442 * StrCmpW [SHLWAPI.@]
444 * Compare two strings.
446 * PARAMS
447 * lpszStr [I] First string to compare
448 * lpszComp [I] Second string to compare
450 * RETURNS
451 * An integer less than, equal to or greater than 0, indicating that
452 * lpszStr is less than, the same, or greater than lpszComp.
454 int WINAPI StrCmpW(LPCWSTR lpszStr, LPCWSTR lpszComp)
456 INT iRet;
458 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszComp));
460 iRet = CompareStringW(GetThreadLocale(), 0, lpszStr, -1, lpszComp, -1);
461 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
464 /*************************************************************************
465 * StrCatW [SHLWAPI.@]
467 * Concatenate two strings.
469 * PARAMS
470 * lpszStr [O] Initial string
471 * lpszSrc [I] String to concatenate
473 * RETURNS
474 * lpszStr.
476 LPWSTR WINAPI StrCatW(LPWSTR lpszStr, LPCWSTR lpszSrc)
478 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSrc));
480 strcatW(lpszStr, lpszSrc);
481 return lpszStr;
484 /*************************************************************************
485 * StrCpyW [SHLWAPI.@]
487 * Copy a string to another string.
489 * PARAMS
490 * lpszStr [O] Destination string
491 * lpszSrc [I] Source string
493 * RETURNS
494 * lpszStr.
496 LPWSTR WINAPI StrCpyW(LPWSTR lpszStr, LPCWSTR lpszSrc)
498 TRACE("(%p,%s)\n", lpszStr, debugstr_w(lpszSrc));
500 strcpyW(lpszStr, lpszSrc);
501 return lpszStr;
504 /*************************************************************************
505 * StrCpyNW [SHLWAPI.@]
507 * Copy a string to another string, up to a maximum number of characters.
509 * PARAMS
510 * dst [O] Destination string
511 * src [I] Source string
512 * count [I] Maximum number of chars to copy
514 * RETURNS
515 * dst.
517 LPWSTR WINAPI StrCpyNW(LPWSTR dst, LPCWSTR src, int count)
519 LPWSTR d = dst;
520 LPCWSTR s = src;
522 TRACE("(%p,%s,%i)\n", dst, debugstr_w(src), count);
524 if (s)
526 while ((count > 1) && *s)
528 count--;
529 *d++ = *s++;
532 if (count) *d = 0;
534 return dst;
537 /*************************************************************************
538 * SHLWAPI_StrStrHelperA
540 * Internal implementation of StrStrA/StrStrIA
542 static LPSTR SHLWAPI_StrStrHelperA(LPCSTR lpszStr, LPCSTR lpszSearch,
543 INT (WINAPI *pStrCmpFn)(LPCSTR,LPCSTR,INT))
545 size_t iLen;
547 if (!lpszStr || !lpszSearch || !*lpszSearch)
548 return NULL;
550 iLen = strlen(lpszSearch);
552 while (*lpszStr)
554 if (!pStrCmpFn(lpszStr, lpszSearch, iLen))
555 return (LPSTR)lpszStr;
556 lpszStr = CharNextA(lpszStr);
558 return NULL;
561 /*************************************************************************
562 * StrStrA [SHLWAPI.@]
564 * Find a substring within a string.
566 * PARAMS
567 * lpszStr [I] String to search in
568 * lpszSearch [I] String to look for
570 * RETURNS
571 * The start of lpszSearch within lpszStr, or NULL if not found.
573 LPSTR WINAPI StrStrA(LPCSTR lpszStr, LPCSTR lpszSearch)
575 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
577 return SHLWAPI_StrStrHelperA(lpszStr, lpszSearch, StrCmpNA);
580 /*************************************************************************
581 * StrStrW [SHLWAPI.@]
583 * See StrStrA.
585 LPWSTR WINAPI StrStrW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
587 TRACE("(%s, %s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
589 if (!lpszStr || !lpszSearch || !*lpszSearch) return NULL;
590 return strstrW( lpszStr, lpszSearch );
593 /*************************************************************************
594 * StrRStrIA [SHLWAPI.@]
596 * Find the last occurrence of a substring within a string.
598 * PARAMS
599 * lpszStr [I] String to search in
600 * lpszEnd [I] End of lpszStr
601 * lpszSearch [I] String to look for
603 * RETURNS
604 * The last occurrence lpszSearch within lpszStr, or NULL if not found.
606 LPSTR WINAPI StrRStrIA(LPCSTR lpszStr, LPCSTR lpszEnd, LPCSTR lpszSearch)
608 WORD ch1, ch2;
609 INT iLen;
611 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
613 if (!lpszStr || !lpszSearch || !*lpszSearch)
614 return NULL;
616 if (!lpszEnd)
617 lpszEnd = lpszStr + lstrlenA(lpszStr);
618 if (lpszEnd == lpszStr)
619 return NULL;
621 if (IsDBCSLeadByte(*lpszSearch))
622 ch1 = *lpszSearch << 8 | (UCHAR)lpszSearch[1];
623 else
624 ch1 = *lpszSearch;
625 iLen = lstrlenA(lpszSearch);
629 lpszEnd = CharPrevA(lpszStr, lpszEnd);
630 ch2 = IsDBCSLeadByte(*lpszEnd)? *lpszEnd << 8 | (UCHAR)lpszEnd[1] : *lpszEnd;
631 if (!ChrCmpIA(ch1, ch2))
633 if (!StrCmpNIA(lpszEnd, lpszSearch, iLen))
634 return (LPSTR)lpszEnd;
636 } while (lpszEnd > lpszStr);
637 return NULL;
640 /*************************************************************************
641 * StrRStrIW [SHLWAPI.@]
643 * See StrRStrIA.
645 LPWSTR WINAPI StrRStrIW(LPCWSTR lpszStr, LPCWSTR lpszEnd, LPCWSTR lpszSearch)
647 INT iLen;
649 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
651 if (!lpszStr || !lpszSearch || !*lpszSearch)
652 return NULL;
654 if (!lpszEnd)
655 lpszEnd = lpszStr + strlenW(lpszStr);
657 iLen = strlenW(lpszSearch);
659 while (lpszEnd > lpszStr)
661 lpszEnd--;
662 if (!StrCmpNIW(lpszEnd, lpszSearch, iLen))
663 return (LPWSTR)lpszEnd;
665 return NULL;
668 /*************************************************************************
669 * StrStrIA [SHLWAPI.@]
671 * Find a substring within a string, ignoring case.
673 * PARAMS
674 * lpszStr [I] String to search in
675 * lpszSearch [I] String to look for
677 * RETURNS
678 * The start of lpszSearch within lpszStr, or NULL if not found.
680 LPSTR WINAPI StrStrIA(LPCSTR lpszStr, LPCSTR lpszSearch)
682 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
684 return SHLWAPI_StrStrHelperA(lpszStr, lpszSearch, StrCmpNIA);
687 /*************************************************************************
688 * StrStrIW [SHLWAPI.@]
690 * See StrStrIA.
692 LPWSTR WINAPI StrStrIW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
694 int iLen;
696 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
698 if (!lpszStr || !lpszSearch || !*lpszSearch)
699 return NULL;
701 iLen = strlenW(lpszSearch);
703 while (*lpszStr)
705 if (!StrCmpNIW(lpszStr, lpszSearch, iLen))
706 return (LPWSTR)lpszStr;
707 lpszStr++;
709 return NULL;
712 /*************************************************************************
713 * StrStrNW [SHLWAPI.@]
715 * Find a substring within a string up to a given number of initial characters.
717 * PARAMS
718 * lpFirst [I] String to search in
719 * lpSrch [I] String to look for
720 * cchMax [I] Maximum number of initial search characters
722 * RETURNS
723 * The start of lpFirst within lpSrch, or NULL if not found.
725 LPWSTR WINAPI StrStrNW(LPCWSTR lpFirst, LPCWSTR lpSrch, UINT cchMax)
727 UINT i;
728 int len;
730 TRACE("(%s, %s, %u)\n", debugstr_w(lpFirst), debugstr_w(lpSrch), cchMax);
732 if (!lpFirst || !lpSrch || !*lpSrch || !cchMax)
733 return NULL;
735 len = strlenW(lpSrch);
737 for (i = cchMax; *lpFirst && (i > 0); i--, lpFirst++)
739 if (!strncmpW(lpFirst, lpSrch, len))
740 return (LPWSTR)lpFirst;
743 return NULL;
746 /*************************************************************************
747 * StrStrNIW [SHLWAPI.@]
749 * Find a substring within a string up to a given number of initial characters,
750 * ignoring case.
752 * PARAMS
753 * lpFirst [I] String to search in
754 * lpSrch [I] String to look for
755 * cchMax [I] Maximum number of initial search characters
757 * RETURNS
758 * The start of lpFirst within lpSrch, or NULL if not found.
760 LPWSTR WINAPI StrStrNIW(LPCWSTR lpFirst, LPCWSTR lpSrch, UINT cchMax)
762 UINT i;
763 int len;
765 TRACE("(%s, %s, %u)\n", debugstr_w(lpFirst), debugstr_w(lpSrch), cchMax);
767 if (!lpFirst || !lpSrch || !*lpSrch || !cchMax)
768 return NULL;
770 len = strlenW(lpSrch);
772 for (i = cchMax; *lpFirst && (i > 0); i--, lpFirst++)
774 if (!strncmpiW(lpFirst, lpSrch, len))
775 return (LPWSTR)lpFirst;
778 return NULL;
781 /*************************************************************************
782 * StrToIntA [SHLWAPI.@]
784 * Read a signed integer from a string.
786 * PARAMS
787 * lpszStr [I] String to read integer from
789 * RETURNS
790 * The signed integer value represented by the string, or 0 if no integer is
791 * present.
793 * NOTES
794 * No leading space is allowed before the number, although a leading '-' is.
796 int WINAPI StrToIntA(LPCSTR lpszStr)
798 int iRet = 0;
800 TRACE("(%s)\n", debugstr_a(lpszStr));
802 if (!lpszStr)
804 WARN("Invalid lpszStr would crash under Win32!\n");
805 return 0;
808 if (*lpszStr == '-' || isdigit(*lpszStr))
809 StrToIntExA(lpszStr, 0, &iRet);
810 return iRet;
813 /*************************************************************************
814 * StrToIntW [SHLWAPI.@]
816 * See StrToIntA.
818 int WINAPI StrToIntW(LPCWSTR lpszStr)
820 int iRet = 0;
822 TRACE("(%s)\n", debugstr_w(lpszStr));
824 if (!lpszStr)
826 WARN("Invalid lpszStr would crash under Win32!\n");
827 return 0;
830 if (*lpszStr == '-' || isdigitW(*lpszStr))
831 StrToIntExW(lpszStr, 0, &iRet);
832 return iRet;
835 /*************************************************************************
836 * StrToIntExA [SHLWAPI.@]
838 * Read an integer from a string.
840 * PARAMS
841 * lpszStr [I] String to read integer from
842 * dwFlags [I] Flags controlling the conversion
843 * lpiRet [O] Destination for read integer.
845 * RETURNS
846 * Success: TRUE. lpiRet contains the integer value represented by the string.
847 * Failure: FALSE, if the string is invalid, or no number is present.
849 * NOTES
850 * Leading whitespace, '-' and '+' are allowed before the number. If
851 * dwFlags includes STIF_SUPPORT_HEX, hexadecimal numbers are allowed, if
852 * preceded by '0x'. If this flag is not set, or there is no '0x' prefix,
853 * the string is treated as a decimal string. A leading '-' is ignored for
854 * hexadecimal numbers.
856 BOOL WINAPI StrToIntExA(LPCSTR lpszStr, DWORD dwFlags, LPINT lpiRet)
858 LONGLONG li;
859 BOOL bRes;
861 TRACE("(%s,%08X,%p)\n", debugstr_a(lpszStr), dwFlags, lpiRet);
863 bRes = StrToInt64ExA(lpszStr, dwFlags, &li);
864 if (bRes) *lpiRet = li;
865 return bRes;
868 /*************************************************************************
869 * StrToInt64ExA [SHLWAPI.@]
871 * See StrToIntExA.
873 BOOL WINAPI StrToInt64ExA(LPCSTR lpszStr, DWORD dwFlags, LONGLONG *lpiRet)
875 BOOL bNegative = FALSE;
876 LONGLONG iRet = 0;
878 TRACE("(%s,%08X,%p)\n", debugstr_a(lpszStr), dwFlags, lpiRet);
880 if (!lpszStr || !lpiRet)
882 WARN("Invalid parameter would crash under Win32!\n");
883 return FALSE;
885 if (dwFlags > STIF_SUPPORT_HEX) WARN("Unknown flags %08x\n", dwFlags);
887 /* Skip leading space, '+', '-' */
888 while (isspace(*lpszStr))
889 lpszStr = CharNextA(lpszStr);
891 if (*lpszStr == '-')
893 bNegative = TRUE;
894 lpszStr++;
896 else if (*lpszStr == '+')
897 lpszStr++;
899 if (dwFlags & STIF_SUPPORT_HEX &&
900 *lpszStr == '0' && tolower(lpszStr[1]) == 'x')
902 /* Read hex number */
903 lpszStr += 2;
905 if (!isxdigit(*lpszStr))
906 return FALSE;
908 while (isxdigit(*lpszStr))
910 iRet = iRet * 16;
911 if (isdigit(*lpszStr))
912 iRet += (*lpszStr - '0');
913 else
914 iRet += 10 + (tolower(*lpszStr) - 'a');
915 lpszStr++;
917 *lpiRet = iRet;
918 return TRUE;
921 /* Read decimal number */
922 if (!isdigit(*lpszStr))
923 return FALSE;
925 while (isdigit(*lpszStr))
927 iRet = iRet * 10;
928 iRet += (*lpszStr - '0');
929 lpszStr++;
931 *lpiRet = bNegative ? -iRet : iRet;
932 return TRUE;
935 /*************************************************************************
936 * StrToIntExW [SHLWAPI.@]
938 * See StrToIntExA.
940 BOOL WINAPI StrToIntExW(LPCWSTR lpszStr, DWORD dwFlags, LPINT lpiRet)
942 LONGLONG li;
943 BOOL bRes;
945 TRACE("(%s,%08X,%p)\n", debugstr_w(lpszStr), dwFlags, lpiRet);
947 bRes = StrToInt64ExW(lpszStr, dwFlags, &li);
948 if (bRes) *lpiRet = li;
949 return bRes;
952 /*************************************************************************
953 * StrToInt64ExW [SHLWAPI.@]
955 * See StrToIntExA.
957 BOOL WINAPI StrToInt64ExW(LPCWSTR lpszStr, DWORD dwFlags, LONGLONG *lpiRet)
959 BOOL bNegative = FALSE;
960 LONGLONG iRet = 0;
962 TRACE("(%s,%08X,%p)\n", debugstr_w(lpszStr), dwFlags, lpiRet);
964 if (!lpszStr || !lpiRet)
966 WARN("Invalid parameter would crash under Win32!\n");
967 return FALSE;
969 if (dwFlags > STIF_SUPPORT_HEX) WARN("Unknown flags %08x\n", dwFlags);
971 /* Skip leading space, '+', '-' */
972 while (isspaceW(*lpszStr)) lpszStr++;
974 if (*lpszStr == '-')
976 bNegative = TRUE;
977 lpszStr++;
979 else if (*lpszStr == '+')
980 lpszStr++;
982 if (dwFlags & STIF_SUPPORT_HEX &&
983 *lpszStr == '0' && tolowerW(lpszStr[1]) == 'x')
985 /* Read hex number */
986 lpszStr += 2;
988 if (!isxdigitW(*lpszStr))
989 return FALSE;
991 while (isxdigitW(*lpszStr))
993 iRet = iRet * 16;
994 if (isdigitW(*lpszStr))
995 iRet += (*lpszStr - '0');
996 else
997 iRet += 10 + (tolowerW(*lpszStr) - 'a');
998 lpszStr++;
1000 *lpiRet = iRet;
1001 return TRUE;
1004 /* Read decimal number */
1005 if (!isdigitW(*lpszStr))
1006 return FALSE;
1008 while (isdigitW(*lpszStr))
1010 iRet = iRet * 10;
1011 iRet += (*lpszStr - '0');
1012 lpszStr++;
1014 *lpiRet = bNegative ? -iRet : iRet;
1015 return TRUE;
1018 /*************************************************************************
1019 * StrDupA [SHLWAPI.@]
1021 * Duplicate a string.
1023 * PARAMS
1024 * lpszStr [I] String to duplicate.
1026 * RETURNS
1027 * Success: A pointer to a new string containing the contents of lpszStr
1028 * Failure: NULL, if memory cannot be allocated
1030 * NOTES
1031 * The string memory is allocated with LocalAlloc(), and so should be released
1032 * by calling LocalFree().
1034 LPSTR WINAPI StrDupA(LPCSTR lpszStr)
1036 int iLen;
1037 LPSTR lpszRet;
1039 TRACE("(%s)\n",debugstr_a(lpszStr));
1041 iLen = lpszStr ? strlen(lpszStr) + 1 : 1;
1042 lpszRet = LocalAlloc(LMEM_FIXED, iLen);
1044 if (lpszRet)
1046 if (lpszStr)
1047 memcpy(lpszRet, lpszStr, iLen);
1048 else
1049 *lpszRet = '\0';
1051 return lpszRet;
1054 /*************************************************************************
1055 * StrDupW [SHLWAPI.@]
1057 * See StrDupA.
1059 LPWSTR WINAPI StrDupW(LPCWSTR lpszStr)
1061 int iLen;
1062 LPWSTR lpszRet;
1064 TRACE("(%s)\n",debugstr_w(lpszStr));
1066 iLen = (lpszStr ? strlenW(lpszStr) + 1 : 1) * sizeof(WCHAR);
1067 lpszRet = LocalAlloc(LMEM_FIXED, iLen);
1069 if (lpszRet)
1071 if (lpszStr)
1072 memcpy(lpszRet, lpszStr, iLen);
1073 else
1074 *lpszRet = '\0';
1076 return lpszRet;
1079 /*************************************************************************
1080 * SHLWAPI_StrSpnHelperA
1082 * Internal implementation of StrSpnA/StrCSpnA/StrCSpnIA
1084 static int SHLWAPI_StrSpnHelperA(LPCSTR lpszStr, LPCSTR lpszMatch,
1085 LPSTR (WINAPI *pStrChrFn)(LPCSTR,WORD),
1086 BOOL bInvert)
1088 LPCSTR lpszRead = lpszStr;
1089 if (lpszStr && *lpszStr && lpszMatch)
1091 while (*lpszRead)
1093 LPCSTR lpszTest = pStrChrFn(lpszMatch, *lpszRead);
1095 if (!bInvert && !lpszTest)
1096 break;
1097 if (bInvert && lpszTest)
1098 break;
1099 lpszRead = CharNextA(lpszRead);
1102 return lpszRead - lpszStr;
1105 /*************************************************************************
1106 * StrSpnA [SHLWAPI.@]
1108 * Find the length of the start of a string that contains only certain
1109 * characters.
1111 * PARAMS
1112 * lpszStr [I] String to search
1113 * lpszMatch [I] Characters that can be in the substring
1115 * RETURNS
1116 * The length of the part of lpszStr containing only chars from lpszMatch,
1117 * or 0 if any parameter is invalid.
1119 int WINAPI StrSpnA(LPCSTR lpszStr, LPCSTR lpszMatch)
1121 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1123 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, FALSE);
1126 /*************************************************************************
1127 * StrSpnW [SHLWAPI.@]
1129 * See StrSpnA.
1131 int WINAPI StrSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1133 if (!lpszStr || !lpszMatch) return 0;
1134 return strspnW( lpszStr, lpszMatch );
1137 /*************************************************************************
1138 * StrCSpnA [SHLWAPI.@]
1140 * Find the length of the start of a string that does not contain certain
1141 * characters.
1143 * PARAMS
1144 * lpszStr [I] String to search
1145 * lpszMatch [I] Characters that cannot be in the substring
1147 * RETURNS
1148 * The length of the part of lpszStr containing only chars not in lpszMatch,
1149 * or 0 if any parameter is invalid.
1151 int WINAPI StrCSpnA(LPCSTR lpszStr, LPCSTR lpszMatch)
1153 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1155 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, TRUE);
1158 /*************************************************************************
1159 * StrCSpnW [SHLWAPI.@]
1161 * See StrCSpnA.
1163 int WINAPI StrCSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1165 if (!lpszStr || !lpszMatch) return 0;
1166 return strcspnW( lpszStr, lpszMatch );
1169 /*************************************************************************
1170 * StrCSpnIA [SHLWAPI.@]
1172 * Find the length of the start of a string that does not contain certain
1173 * characters, ignoring case.
1175 * PARAMS
1176 * lpszStr [I] String to search
1177 * lpszMatch [I] Characters that cannot be in the substring
1179 * RETURNS
1180 * The length of the part of lpszStr containing only chars not in lpszMatch,
1181 * or 0 if any parameter is invalid.
1183 int WINAPI StrCSpnIA(LPCSTR lpszStr, LPCSTR lpszMatch)
1185 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1187 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrIA, TRUE);
1190 /*************************************************************************
1191 * StrCSpnIW [SHLWAPI.@]
1193 * See StrCSpnIA.
1195 int WINAPI StrCSpnIW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1197 LPCWSTR lpszRead = lpszStr;
1199 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1201 if (lpszStr && *lpszStr && lpszMatch)
1203 while (*lpszRead)
1205 if (StrChrIW(lpszMatch, *lpszRead)) break;
1206 lpszRead++;
1209 return lpszRead - lpszStr;
1212 /*************************************************************************
1213 * StrPBrkA [SHLWAPI.@]
1215 * Search a string for any of a group of characters.
1217 * PARAMS
1218 * lpszStr [I] String to search
1219 * lpszMatch [I] Characters to match
1221 * RETURNS
1222 * A pointer to the first matching character in lpszStr, or NULL if no
1223 * match was found.
1225 LPSTR WINAPI StrPBrkA(LPCSTR lpszStr, LPCSTR lpszMatch)
1227 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1229 if (lpszStr && lpszMatch && *lpszMatch)
1231 while (*lpszStr)
1233 if (StrChrA(lpszMatch, *lpszStr))
1234 return (LPSTR)lpszStr;
1235 lpszStr = CharNextA(lpszStr);
1238 return NULL;
1241 /*************************************************************************
1242 * StrPBrkW [SHLWAPI.@]
1244 * See StrPBrkA.
1246 LPWSTR WINAPI StrPBrkW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1248 if (!lpszStr || !lpszMatch) return NULL;
1249 return strpbrkW( lpszStr, lpszMatch );
1252 /*************************************************************************
1253 * SHLWAPI_StrRChrHelperA
1255 * Internal implementation of StrRChrA/StrRChrIA.
1257 static LPSTR SHLWAPI_StrRChrHelperA(LPCSTR lpszStr,
1258 LPCSTR lpszEnd, WORD ch,
1259 BOOL (WINAPI *pChrCmpFn)(WORD,WORD))
1261 LPCSTR lpszRet = NULL;
1263 if (lpszStr)
1265 WORD ch2;
1267 if (!lpszEnd)
1268 lpszEnd = lpszStr + lstrlenA(lpszStr);
1270 while (*lpszStr && lpszStr <= lpszEnd)
1272 ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr;
1274 if (!pChrCmpFn(ch, ch2))
1275 lpszRet = lpszStr;
1276 lpszStr = CharNextA(lpszStr);
1279 return (LPSTR)lpszRet;
1282 /**************************************************************************
1283 * StrRChrA [SHLWAPI.@]
1285 * Find the last occurrence of a character in string.
1287 * PARAMS
1288 * lpszStr [I] String to search in
1289 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1290 * ch [I] Character to search for.
1292 * RETURNS
1293 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1294 * or NULL if not found.
1295 * Failure: NULL, if any arguments are invalid.
1297 LPSTR WINAPI StrRChrA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch)
1299 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch);
1301 return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, SHLWAPI_ChrCmpA);
1304 /**************************************************************************
1305 * StrRChrW [SHLWAPI.@]
1307 * See StrRChrA.
1309 LPWSTR WINAPI StrRChrW(LPCWSTR str, LPCWSTR end, WORD ch)
1311 WCHAR *ret = NULL;
1313 if (!str) return NULL;
1314 if (!end) end = str + strlenW(str);
1315 while (str < end)
1317 if (*str == ch) ret = (WCHAR *)str;
1318 str++;
1320 return ret;
1323 /**************************************************************************
1324 * StrRChrIA [SHLWAPI.@]
1326 * Find the last occurrence of a character in string, ignoring case.
1328 * PARAMS
1329 * lpszStr [I] String to search in
1330 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1331 * ch [I] Character to search for.
1333 * RETURNS
1334 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1335 * or NULL if not found.
1336 * Failure: NULL, if any arguments are invalid.
1338 LPSTR WINAPI StrRChrIA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch)
1340 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch);
1342 return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, ChrCmpIA);
1345 /**************************************************************************
1346 * StrRChrIW [SHLWAPI.@]
1348 * See StrRChrIA.
1350 LPWSTR WINAPI StrRChrIW(LPCWSTR str, LPCWSTR end, WORD ch)
1352 WCHAR *ret = NULL;
1354 if (!str) return NULL;
1355 if (!end) end = str + strlenW(str);
1356 while (str < end)
1358 if (!ChrCmpIW(*str, ch)) ret = (WCHAR *)str;
1359 str++;
1361 return ret;
1364 /*************************************************************************
1365 * StrCatBuffA [SHLWAPI.@]
1367 * Concatenate two strings together.
1369 * PARAMS
1370 * lpszStr [O] String to concatenate to
1371 * lpszCat [I] String to add to lpszCat
1372 * cchMax [I] Maximum number of characters for the whole string
1374 * RETURNS
1375 * lpszStr.
1377 * NOTES
1378 * cchMax determines the number of characters in the final length of the
1379 * string, not the number appended to lpszStr from lpszCat.
1381 LPSTR WINAPI StrCatBuffA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax)
1383 INT iLen;
1385 TRACE("(%p,%s,%d)\n", lpszStr, debugstr_a(lpszCat), cchMax);
1387 if (!lpszStr)
1389 WARN("Invalid lpszStr would crash under Win32!\n");
1390 return NULL;
1393 iLen = strlen(lpszStr);
1394 cchMax -= iLen;
1396 if (cchMax > 0)
1397 StrCpyNA(lpszStr + iLen, lpszCat, cchMax);
1398 return lpszStr;
1401 /*************************************************************************
1402 * StrCatBuffW [SHLWAPI.@]
1404 * See StrCatBuffA.
1406 LPWSTR WINAPI StrCatBuffW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax)
1408 INT iLen;
1410 TRACE("(%p,%s,%d)\n", lpszStr, debugstr_w(lpszCat), cchMax);
1412 if (!lpszStr)
1414 WARN("Invalid lpszStr would crash under Win32!\n");
1415 return NULL;
1418 iLen = strlenW(lpszStr);
1419 cchMax -= iLen;
1421 if (cchMax > 0)
1422 StrCpyNW(lpszStr + iLen, lpszCat, cchMax);
1423 return lpszStr;
1426 /*************************************************************************
1427 * StrRetToBufA [SHLWAPI.@]
1429 * Convert a STRRET to a normal string.
1431 * PARAMS
1432 * lpStrRet [O] STRRET to convert
1433 * pIdl [I] ITEMIDLIST for lpStrRet->uType == STRRET_OFFSET
1434 * lpszDest [O] Destination for normal string
1435 * dwLen [I] Length of lpszDest
1437 * RETURNS
1438 * Success: S_OK. lpszDest contains up to dwLen characters of the string.
1439 * If lpStrRet is of type STRRET_WSTR, its memory is freed with
1440 * CoTaskMemFree() and its type set to STRRET_CSTRA.
1441 * Failure: E_FAIL, if any parameters are invalid.
1443 HRESULT WINAPI StrRetToBufA (LPSTRRET src, const ITEMIDLIST *pidl, LPSTR dest, UINT len)
1445 /* NOTE:
1446 * This routine is identical to that in dlls/shell32/shellstring.c.
1447 * It was duplicated because not every version of Shlwapi.dll exports
1448 * StrRetToBufA. If you change one routine, change them both.
1450 TRACE("dest=%p len=0x%x strret=%p pidl=%p stub\n",dest,len,src,pidl);
1452 if (!src)
1454 WARN("Invalid lpStrRet would crash under Win32!\n");
1455 if (dest)
1456 *dest = '\0';
1457 return E_FAIL;
1460 if (!dest || !len)
1461 return E_FAIL;
1463 *dest = '\0';
1465 switch (src->uType)
1467 case STRRET_WSTR:
1468 WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, dest, len, NULL, NULL);
1469 CoTaskMemFree(src->u.pOleStr);
1470 break;
1472 case STRRET_CSTR:
1473 lstrcpynA(dest, src->u.cStr, len);
1474 break;
1476 case STRRET_OFFSET:
1477 lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len);
1478 break;
1480 default:
1481 FIXME("unknown type!\n");
1482 return FALSE;
1484 return S_OK;
1487 /*************************************************************************
1488 * StrRetToBufW [SHLWAPI.@]
1490 * See StrRetToBufA.
1492 HRESULT WINAPI StrRetToBufW (LPSTRRET src, const ITEMIDLIST *pidl, LPWSTR dest, UINT len)
1494 TRACE("dest=%p len=0x%x strret=%p pidl=%p stub\n",dest,len,src,pidl);
1496 if (!src)
1498 WARN("Invalid lpStrRet would crash under Win32!\n");
1499 if (dest)
1500 *dest = '\0';
1501 return E_FAIL;
1504 if (!dest || !len)
1505 return E_FAIL;
1507 *dest = '\0';
1509 switch (src->uType)
1511 case STRRET_WSTR:
1512 lstrcpynW(dest, src->u.pOleStr, len);
1513 CoTaskMemFree(src->u.pOleStr);
1514 break;
1516 case STRRET_CSTR:
1517 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ))
1518 dest[len-1] = 0;
1519 break;
1521 case STRRET_OFFSET:
1522 if (pidl)
1524 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1,
1525 dest, len ))
1526 dest[len-1] = 0;
1528 break;
1530 default:
1531 FIXME("unknown type!\n");
1532 return FALSE;
1534 return S_OK;
1537 /*************************************************************************
1538 * StrRetToStrA [SHLWAPI.@]
1540 * Converts a STRRET to a normal string.
1542 * PARAMS
1543 * lpStrRet [O] STRRET to convert
1544 * pidl [I] ITEMIDLIST for lpStrRet->uType == STRRET_OFFSET
1545 * ppszName [O] Destination for converted string
1547 * RETURNS
1548 * Success: S_OK. ppszName contains the new string, allocated with CoTaskMemAlloc().
1549 * Failure: E_FAIL, if any parameters are invalid.
1551 HRESULT WINAPI StrRetToStrA(LPSTRRET lpStrRet, const ITEMIDLIST *pidl, LPSTR *ppszName)
1553 HRESULT hRet = E_FAIL;
1555 switch (lpStrRet->uType)
1557 case STRRET_WSTR:
1558 hRet = _SHStrDupAW(lpStrRet->u.pOleStr, ppszName);
1559 CoTaskMemFree(lpStrRet->u.pOleStr);
1560 break;
1562 case STRRET_CSTR:
1563 hRet = _SHStrDupAA(lpStrRet->u.cStr, ppszName);
1564 break;
1566 case STRRET_OFFSET:
1567 hRet = _SHStrDupAA(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, ppszName);
1568 break;
1570 default:
1571 *ppszName = NULL;
1574 return hRet;
1577 /*************************************************************************
1578 * StrRetToStrW [SHLWAPI.@]
1580 * See StrRetToStrA.
1582 HRESULT WINAPI StrRetToStrW(LPSTRRET lpStrRet, const ITEMIDLIST *pidl, LPWSTR *ppszName)
1584 HRESULT hRet = E_FAIL;
1586 switch (lpStrRet->uType)
1588 case STRRET_WSTR:
1589 hRet = SHStrDupW(lpStrRet->u.pOleStr, ppszName);
1590 CoTaskMemFree(lpStrRet->u.pOleStr);
1591 break;
1593 case STRRET_CSTR:
1594 hRet = SHStrDupA(lpStrRet->u.cStr, ppszName);
1595 break;
1597 case STRRET_OFFSET:
1598 hRet = SHStrDupA(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, ppszName);
1599 break;
1601 default:
1602 *ppszName = NULL;
1605 return hRet;
1608 /* Create an ASCII string copy using SysAllocString() */
1609 static HRESULT _SHStrDupAToBSTR(LPCSTR src, BSTR *pBstrOut)
1611 *pBstrOut = NULL;
1613 if (src)
1615 INT len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0);
1616 WCHAR* szTemp = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1618 if (szTemp)
1620 MultiByteToWideChar(CP_ACP, 0, src, -1, szTemp, len);
1621 *pBstrOut = SysAllocString(szTemp);
1622 HeapFree(GetProcessHeap(), 0, szTemp);
1624 if (*pBstrOut)
1625 return S_OK;
1628 return E_OUTOFMEMORY;
1631 /*************************************************************************
1632 * StrRetToBSTR [SHLWAPI.@]
1634 * Converts a STRRET to a BSTR.
1636 * PARAMS
1637 * lpStrRet [O] STRRET to convert
1638 * pidl [I] ITEMIDLIST for lpStrRet->uType = STRRET_OFFSET
1639 * pBstrOut [O] Destination for converted BSTR
1641 * RETURNS
1642 * Success: S_OK. pBstrOut contains the new string.
1643 * Failure: E_FAIL, if any parameters are invalid.
1645 HRESULT WINAPI StrRetToBSTR(STRRET *lpStrRet, LPCITEMIDLIST pidl, BSTR* pBstrOut)
1647 HRESULT hRet = E_FAIL;
1649 switch (lpStrRet->uType)
1651 case STRRET_WSTR:
1652 *pBstrOut = SysAllocString(lpStrRet->u.pOleStr);
1653 if (*pBstrOut)
1654 hRet = S_OK;
1655 CoTaskMemFree(lpStrRet->u.pOleStr);
1656 break;
1658 case STRRET_CSTR:
1659 hRet = _SHStrDupAToBSTR(lpStrRet->u.cStr, pBstrOut);
1660 break;
1662 case STRRET_OFFSET:
1663 hRet = _SHStrDupAToBSTR(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, pBstrOut);
1664 break;
1666 default:
1667 *pBstrOut = NULL;
1670 return hRet;
1673 /*************************************************************************
1674 * StrFormatKBSizeA [SHLWAPI.@]
1676 * Create a formatted string containing a byte count in Kilobytes.
1678 * PARAMS
1679 * llBytes [I] Byte size to format
1680 * lpszDest [I] Destination for formatted string
1681 * cchMax [I] Size of lpszDest
1683 * RETURNS
1684 * lpszDest.
1686 LPSTR WINAPI StrFormatKBSizeA(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax)
1688 WCHAR wszBuf[256];
1690 if (!StrFormatKBSizeW(llBytes, wszBuf, 256))
1691 return NULL;
1692 if (!WideCharToMultiByte(CP_ACP, 0, wszBuf, -1, lpszDest, cchMax, NULL, NULL))
1693 return NULL;
1694 return lpszDest;
1697 /*************************************************************************
1698 * StrFormatKBSizeW [SHLWAPI.@]
1700 * See StrFormatKBSizeA.
1702 LPWSTR WINAPI StrFormatKBSizeW(LONGLONG llBytes, LPWSTR lpszDest, UINT cchMax)
1704 static const WCHAR kb[] = {' ','K','B',0};
1705 LONGLONG llKB = (llBytes + 1023) >> 10;
1706 int len;
1708 TRACE("(0x%s,%p,%d)\n", wine_dbgstr_longlong(llBytes), lpszDest, cchMax);
1710 if (!FormatInt(llKB, lpszDest, cchMax))
1711 return NULL;
1713 len = lstrlenW(lpszDest);
1714 if (cchMax - len < 4)
1715 return NULL;
1716 lstrcatW(lpszDest, kb);
1717 return lpszDest;
1720 /*************************************************************************
1721 * StrNCatA [SHLWAPI.@]
1723 * Concatenate two strings together.
1725 * PARAMS
1726 * lpszStr [O] String to concatenate to
1727 * lpszCat [I] String to add to lpszCat
1728 * cchMax [I] Maximum number of characters to concatenate
1730 * RETURNS
1731 * lpszStr.
1733 * NOTES
1734 * cchMax determines the number of characters that are appended to lpszStr,
1735 * not the total length of the string.
1737 LPSTR WINAPI StrNCatA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax)
1739 LPSTR lpszRet = lpszStr;
1741 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszCat), cchMax);
1743 if (!lpszStr)
1745 WARN("Invalid lpszStr would crash under Win32!\n");
1746 return NULL;
1749 StrCpyNA(lpszStr + strlen(lpszStr), lpszCat, cchMax);
1750 return lpszRet;
1753 /*************************************************************************
1754 * StrNCatW [SHLWAPI.@]
1756 * See StrNCatA.
1758 LPWSTR WINAPI StrNCatW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax)
1760 LPWSTR lpszRet = lpszStr;
1762 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszCat), cchMax);
1764 if (!lpszStr)
1766 WARN("Invalid lpszStr would crash under Win32\n");
1767 return NULL;
1770 StrCpyNW(lpszStr + strlenW(lpszStr), lpszCat, cchMax);
1771 return lpszRet;
1774 /*************************************************************************
1775 * StrTrimA [SHLWAPI.@]
1777 * Remove characters from the start and end of a string.
1779 * PARAMS
1780 * lpszStr [O] String to remove characters from
1781 * lpszTrim [I] Characters to remove from lpszStr
1783 * RETURNS
1784 * TRUE If lpszStr was valid and modified
1785 * FALSE Otherwise
1787 BOOL WINAPI StrTrimA(LPSTR lpszStr, LPCSTR lpszTrim)
1789 DWORD dwLen;
1790 LPSTR lpszRead = lpszStr;
1791 BOOL bRet = FALSE;
1793 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszTrim));
1795 if (lpszRead && *lpszRead)
1797 while (*lpszRead && StrChrA(lpszTrim, *lpszRead))
1798 lpszRead = CharNextA(lpszRead); /* Skip leading matches */
1800 dwLen = strlen(lpszRead);
1802 if (lpszRead != lpszStr)
1804 memmove(lpszStr, lpszRead, dwLen + 1);
1805 bRet = TRUE;
1807 if (dwLen > 0)
1809 lpszRead = lpszStr + dwLen;
1810 while (StrChrA(lpszTrim, lpszRead[-1]))
1811 lpszRead = CharPrevA(lpszStr, lpszRead); /* Skip trailing matches */
1813 if (lpszRead != lpszStr + dwLen)
1815 *lpszRead = '\0';
1816 bRet = TRUE;
1820 return bRet;
1823 /*************************************************************************
1824 * StrTrimW [SHLWAPI.@]
1826 * See StrTrimA.
1828 BOOL WINAPI StrTrimW(LPWSTR lpszStr, LPCWSTR lpszTrim)
1830 DWORD dwLen;
1831 LPWSTR lpszRead = lpszStr;
1832 BOOL bRet = FALSE;
1834 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszTrim));
1836 if (lpszRead && *lpszRead)
1838 while (*lpszRead && StrChrW(lpszTrim, *lpszRead)) lpszRead++;
1840 dwLen = strlenW(lpszRead);
1842 if (lpszRead != lpszStr)
1844 memmove(lpszStr, lpszRead, (dwLen + 1) * sizeof(WCHAR));
1845 bRet = TRUE;
1847 if (dwLen > 0)
1849 lpszRead = lpszStr + dwLen;
1850 while (StrChrW(lpszTrim, lpszRead[-1]))
1851 lpszRead--; /* Skip trailing matches */
1853 if (lpszRead != lpszStr + dwLen)
1855 *lpszRead = '\0';
1856 bRet = TRUE;
1860 return bRet;
1863 /*************************************************************************
1864 * _SHStrDupAA [INTERNAL]
1866 * Duplicates a ASCII string to ASCII. The destination buffer is allocated.
1868 static HRESULT _SHStrDupAA(LPCSTR src, LPSTR * dest)
1870 HRESULT hr;
1871 int len = 0;
1873 if (src) {
1874 len = lstrlenA(src) + 1;
1875 *dest = CoTaskMemAlloc(len);
1876 } else {
1877 *dest = NULL;
1880 if (*dest) {
1881 lstrcpynA(*dest,src, len);
1882 hr = S_OK;
1883 } else {
1884 hr = E_OUTOFMEMORY;
1887 TRACE("%s->(%p)\n", debugstr_a(src), *dest);
1888 return hr;
1891 /*************************************************************************
1892 * SHStrDupA [SHLWAPI.@]
1894 * Return a Unicode copy of a string, in memory allocated by CoTaskMemAlloc().
1896 * PARAMS
1897 * lpszStr [I] String to copy
1898 * lppszDest [O] Destination for the new string copy
1900 * RETURNS
1901 * Success: S_OK. lppszDest contains the new string in Unicode format.
1902 * Failure: E_OUTOFMEMORY, If any arguments are invalid or memory allocation
1903 * fails.
1905 HRESULT WINAPI SHStrDupA(LPCSTR lpszStr, LPWSTR * lppszDest)
1907 HRESULT hRet;
1908 int len = 0;
1910 if (lpszStr)
1912 len = MultiByteToWideChar(0, 0, lpszStr, -1, 0, 0) * sizeof(WCHAR);
1913 *lppszDest = CoTaskMemAlloc(len);
1915 else
1916 *lppszDest = NULL;
1918 if (*lppszDest)
1920 MultiByteToWideChar(0, 0, lpszStr, -1, *lppszDest, len/sizeof(WCHAR));
1921 hRet = S_OK;
1923 else
1924 hRet = E_OUTOFMEMORY;
1926 TRACE("%s->(%p)\n", debugstr_a(lpszStr), *lppszDest);
1927 return hRet;
1930 /*************************************************************************
1931 * _SHStrDupAW [INTERNAL]
1933 * Duplicates a UNICODE to a ASCII string. The destination buffer is allocated.
1935 static HRESULT _SHStrDupAW(LPCWSTR src, LPSTR * dest)
1937 HRESULT hr;
1938 int len = 0;
1940 if (src) {
1941 len = WideCharToMultiByte(CP_ACP, 0, src, -1, NULL, 0, NULL, NULL);
1942 *dest = CoTaskMemAlloc(len);
1943 } else {
1944 *dest = NULL;
1947 if (*dest) {
1948 WideCharToMultiByte(CP_ACP, 0, src, -1, *dest, len, NULL, NULL);
1949 hr = S_OK;
1950 } else {
1951 hr = E_OUTOFMEMORY;
1954 TRACE("%s->(%p)\n", debugstr_w(src), *dest);
1955 return hr;
1958 /*************************************************************************
1959 * SHStrDupW [SHLWAPI.@]
1961 * See SHStrDupA.
1963 HRESULT WINAPI SHStrDupW(LPCWSTR src, LPWSTR * dest)
1965 HRESULT hr;
1966 int len = 0;
1968 if (src) {
1969 len = (lstrlenW(src) + 1) * sizeof(WCHAR);
1970 *dest = CoTaskMemAlloc(len);
1971 } else {
1972 *dest = NULL;
1975 if (*dest) {
1976 memcpy(*dest, src, len);
1977 hr = S_OK;
1978 } else {
1979 hr = E_OUTOFMEMORY;
1982 TRACE("%s->(%p)\n", debugstr_w(src), *dest);
1983 return hr;
1986 /*************************************************************************
1987 * SHLWAPI_WriteReverseNum
1989 * Internal helper for SHLWAPI_WriteTimeClass.
1991 static inline LPWSTR SHLWAPI_WriteReverseNum(LPWSTR lpszOut, DWORD dwNum)
1993 *lpszOut-- = '\0';
1995 /* Write a decimal number to a string, backwards */
1998 DWORD dwNextDigit = dwNum % 10;
1999 *lpszOut-- = '0' + dwNextDigit;
2000 dwNum = (dwNum - dwNextDigit) / 10;
2001 } while (dwNum > 0);
2003 return lpszOut;
2006 /*************************************************************************
2007 * SHLWAPI_FormatSignificant
2009 * Internal helper for SHLWAPI_WriteTimeClass.
2011 static inline int SHLWAPI_FormatSignificant(LPWSTR lpszNum, int dwDigits)
2013 /* Zero non significant digits, return remaining significant digits */
2014 while (*lpszNum)
2016 lpszNum++;
2017 if (--dwDigits == 0)
2019 while (*lpszNum)
2020 *lpszNum++ = '0';
2021 return 0;
2024 return dwDigits;
2027 /*************************************************************************
2028 * SHLWAPI_WriteTimeClass
2030 * Internal helper for StrFromTimeIntervalW.
2032 static int SHLWAPI_WriteTimeClass(LPWSTR lpszOut, DWORD dwValue,
2033 UINT uClassStringId, int iDigits)
2035 WCHAR szBuff[64], *szOut = szBuff + 32;
2037 szOut = SHLWAPI_WriteReverseNum(szOut, dwValue);
2038 iDigits = SHLWAPI_FormatSignificant(szOut + 1, iDigits);
2039 *szOut = ' ';
2040 LoadStringW(shlwapi_hInstance, uClassStringId, szBuff + 32, 32);
2041 strcatW(lpszOut, szOut);
2042 return iDigits;
2045 /*************************************************************************
2046 * StrFromTimeIntervalA [SHLWAPI.@]
2048 * Format a millisecond time interval into a string
2050 * PARAMS
2051 * lpszStr [O] Output buffer for formatted time interval
2052 * cchMax [I] Size of lpszStr
2053 * dwMS [I] Number of milliseconds
2054 * iDigits [I] Number of digits to print
2056 * RETURNS
2057 * The length of the formatted string, or 0 if any parameter is invalid.
2059 * NOTES
2060 * This implementation mimics the Win32 behaviour of always writing a leading
2061 * space before the time interval begins.
2063 * iDigits is used to provide approximate times if accuracy is not important.
2064 * This number of digits will be written of the first non-zero time class
2065 * (hours/minutes/seconds). If this does not complete the time classification,
2066 * the remaining digits are changed to zeros (i.e. The time is _not_ rounded).
2067 * If there are digits remaining following the writing of a time class, the
2068 * next time class will be written.
2070 * For example, given dwMS represents 138 hours,43 minutes and 15 seconds, the
2071 * following will result from the given values of iDigits:
2073 *| iDigits 1 2 3 4 5 ...
2074 *| lpszStr "100 hr" "130 hr" "138 hr" "138 hr 40 min" "138 hr 43 min" ...
2076 INT WINAPI StrFromTimeIntervalA(LPSTR 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 szBuff[128];
2086 StrFromTimeIntervalW(szBuff, sizeof(szBuff)/sizeof(WCHAR), dwMS, iDigits);
2087 WideCharToMultiByte(CP_ACP,0,szBuff,-1,lpszStr,cchMax,0,0);
2089 return iRet;
2093 /*************************************************************************
2094 * StrFromTimeIntervalW [SHLWAPI.@]
2096 * See StrFromTimeIntervalA.
2098 INT WINAPI StrFromTimeIntervalW(LPWSTR lpszStr, UINT cchMax, DWORD dwMS,
2099 int iDigits)
2101 INT iRet = 0;
2103 TRACE("(%p,%d,%d,%d)\n", lpszStr, cchMax, dwMS, iDigits);
2105 if (lpszStr && cchMax)
2107 WCHAR szCopy[128];
2108 DWORD dwHours, dwMinutes;
2110 if (!iDigits || cchMax == 1)
2112 *lpszStr = '\0';
2113 return 0;
2116 /* Calculate the time classes */
2117 dwMS = (dwMS + 500) / 1000;
2118 dwHours = dwMS / 3600;
2119 dwMS -= dwHours * 3600;
2120 dwMinutes = dwMS / 60;
2121 dwMS -= dwMinutes * 60;
2123 szCopy[0] = '\0';
2125 if (dwHours)
2126 iDigits = SHLWAPI_WriteTimeClass(szCopy, dwHours, IDS_TIME_INTERVAL_HOURS, iDigits);
2128 if (dwMinutes && iDigits)
2129 iDigits = SHLWAPI_WriteTimeClass(szCopy, dwMinutes, IDS_TIME_INTERVAL_MINUTES, iDigits);
2131 if (iDigits) /* Always write seconds if we have significant digits */
2132 SHLWAPI_WriteTimeClass(szCopy, dwMS, IDS_TIME_INTERVAL_SECONDS, iDigits);
2134 lstrcpynW(lpszStr, szCopy, cchMax);
2135 iRet = strlenW(lpszStr);
2137 return iRet;
2140 /*************************************************************************
2141 * StrIsIntlEqualA [SHLWAPI.@]
2143 * Compare two strings.
2145 * PARAMS
2146 * bCase [I] Whether to compare case sensitively
2147 * lpszStr [I] First string to compare
2148 * lpszComp [I] Second string to compare
2149 * iLen [I] Length to compare
2151 * RETURNS
2152 * TRUE If the strings are equal.
2153 * FALSE Otherwise.
2155 BOOL WINAPI StrIsIntlEqualA(BOOL bCase, LPCSTR lpszStr, LPCSTR lpszComp,
2156 int iLen)
2158 DWORD dwFlags;
2160 TRACE("(%d,%s,%s,%d)\n", bCase,
2161 debugstr_a(lpszStr), debugstr_a(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 (CompareStringA(GetThreadLocale(), dwFlags, lpszStr, iLen, lpszComp, iLen) == CSTR_EQUAL);
2172 /*************************************************************************
2173 * StrIsIntlEqualW [SHLWAPI.@]
2175 * See StrIsIntlEqualA.
2177 BOOL WINAPI StrIsIntlEqualW(BOOL bCase, LPCWSTR lpszStr, LPCWSTR lpszComp,
2178 int iLen)
2180 DWORD dwFlags;
2182 TRACE("(%d,%s,%s,%d)\n", bCase,
2183 debugstr_w(lpszStr),debugstr_w(lpszComp), iLen);
2185 /* FIXME: This flag is undocumented and unknown by our CompareString.
2186 * We need a define for it.
2188 dwFlags = 0x10000000;
2189 if (!bCase) dwFlags |= NORM_IGNORECASE;
2191 return (CompareStringW(GetThreadLocale(), dwFlags, lpszStr, iLen, lpszComp, iLen) == CSTR_EQUAL);
2194 /*************************************************************************
2195 * @ [SHLWAPI.399]
2197 * Copy a string to another string, up to a maximum number of characters.
2199 * PARAMS
2200 * lpszDest [O] Destination string
2201 * lpszSrc [I] Source string
2202 * iLen [I] Maximum number of chars to copy
2204 * RETURNS
2205 * Success: A pointer to the last character written to lpszDest.
2206 * Failure: lpszDest, if any arguments are invalid.
2208 LPSTR WINAPI StrCpyNXA(LPSTR lpszDest, LPCSTR lpszSrc, int iLen)
2210 TRACE("(%p,%s,%i)\n", lpszDest, debugstr_a(lpszSrc), iLen);
2212 if (lpszDest && lpszSrc && iLen > 0)
2214 while ((iLen-- > 1) && *lpszSrc)
2215 *lpszDest++ = *lpszSrc++;
2216 if (iLen >= 0)
2217 *lpszDest = '\0';
2219 return lpszDest;
2222 /*************************************************************************
2223 * @ [SHLWAPI.400]
2225 * Unicode version of StrCpyNXA.
2227 LPWSTR WINAPI StrCpyNXW(LPWSTR lpszDest, LPCWSTR lpszSrc, int iLen)
2229 TRACE("(%p,%s,%i)\n", lpszDest, debugstr_w(lpszSrc), iLen);
2231 if (lpszDest && lpszSrc && iLen > 0)
2233 while ((iLen-- > 1) && *lpszSrc)
2234 *lpszDest++ = *lpszSrc++;
2235 if (iLen >= 0)
2236 *lpszDest = '\0';
2238 return lpszDest;
2241 /*************************************************************************
2242 * StrCmpLogicalW [SHLWAPI.@]
2244 * Compare two strings, ignoring case and comparing digits as numbers.
2246 * PARAMS
2247 * lpszStr [I] First string to compare
2248 * lpszComp [I] Second string to compare
2249 * iLen [I] Length to compare
2251 * RETURNS
2252 * TRUE If the strings are equal.
2253 * FALSE Otherwise.
2255 INT WINAPI StrCmpLogicalW(LPCWSTR lpszStr, LPCWSTR lpszComp)
2257 INT iDiff;
2259 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszComp));
2261 if (lpszStr && lpszComp)
2263 while (*lpszStr)
2265 if (!*lpszComp)
2266 return 1;
2267 else if (isdigitW(*lpszStr))
2269 int iStr, iComp;
2271 if (!isdigitW(*lpszComp))
2272 return -1;
2274 /* Compare the numbers */
2275 StrToIntExW(lpszStr, 0, &iStr);
2276 StrToIntExW(lpszComp, 0, &iComp);
2278 if (iStr < iComp)
2279 return -1;
2280 else if (iStr > iComp)
2281 return 1;
2283 /* Skip */
2284 while (isdigitW(*lpszStr))
2285 lpszStr++;
2286 while (isdigitW(*lpszComp))
2287 lpszComp++;
2289 else if (isdigitW(*lpszComp))
2290 return 1;
2291 else
2293 iDiff = ChrCmpIW(*lpszStr,*lpszComp);
2294 if (iDiff > 0)
2295 return 1;
2296 else if (iDiff < 0)
2297 return -1;
2299 lpszStr++;
2300 lpszComp++;
2303 if (*lpszComp)
2304 return -1;
2306 return 0;
2309 /* Structure for formatting byte strings */
2310 typedef struct tagSHLWAPI_BYTEFORMATS
2312 LONGLONG dLimit;
2313 double dDivisor;
2314 double dNormaliser;
2315 int nDecimals;
2316 WCHAR wPrefix;
2317 } SHLWAPI_BYTEFORMATS;
2319 /*************************************************************************
2320 * StrFormatByteSizeW [SHLWAPI.@]
2322 * Create a string containing an abbreviated byte count of up to 2^63-1.
2324 * PARAMS
2325 * llBytes [I] Byte size to format
2326 * lpszDest [I] Destination for formatted string
2327 * cchMax [I] Size of lpszDest
2329 * RETURNS
2330 * lpszDest.
2332 * NOTES
2333 * There is no StrFormatByteSize64W function, it is called StrFormatByteSizeW().
2335 LPWSTR WINAPI StrFormatByteSizeW(LONGLONG llBytes, LPWSTR lpszDest, UINT cchMax)
2337 #define KB ((ULONGLONG)1024)
2338 #define MB (KB*KB)
2339 #define GB (KB*KB*KB)
2340 #define TB (KB*KB*KB*KB)
2341 #define PB (KB*KB*KB*KB*KB)
2343 static const SHLWAPI_BYTEFORMATS bfFormats[] =
2345 { 10*KB, 10.24, 100.0, 2, 'K' }, /* 10 KB */
2346 { 100*KB, 102.4, 10.0, 1, 'K' }, /* 100 KB */
2347 { 1000*KB, 1024.0, 1.0, 0, 'K' }, /* 1000 KB */
2348 { 10*MB, 10485.76, 100.0, 2, 'M' }, /* 10 MB */
2349 { 100*MB, 104857.6, 10.0, 1, 'M' }, /* 100 MB */
2350 { 1000*MB, 1048576.0, 1.0, 0, 'M' }, /* 1000 MB */
2351 { 10*GB, 10737418.24, 100.0, 2, 'G' }, /* 10 GB */
2352 { 100*GB, 107374182.4, 10.0, 1, 'G' }, /* 100 GB */
2353 { 1000*GB, 1073741824.0, 1.0, 0, 'G' }, /* 1000 GB */
2354 { 10*TB, 10485.76, 100.0, 2, 'T' }, /* 10 TB */
2355 { 100*TB, 104857.6, 10.0, 1, 'T' }, /* 100 TB */
2356 { 1000*TB, 1048576.0, 1.0, 0, 'T' }, /* 1000 TB */
2357 { 10*PB, 10737418.24, 100.00, 2, 'P' }, /* 10 PB */
2358 { 100*PB, 107374182.4, 10.00, 1, 'P' }, /* 100 PB */
2359 { 1000*PB, 1073741824.0, 1.00, 0, 'P' }, /* 1000 PB */
2360 { 0, 10995116277.76, 100.00, 2, 'E' } /* EB's, catch all */
2362 WCHAR wszAdd[] = {' ','?','B',0};
2363 double dBytes;
2364 UINT i = 0;
2366 TRACE("(0x%s,%p,%d)\n", wine_dbgstr_longlong(llBytes), lpszDest, cchMax);
2368 if (!lpszDest || !cchMax)
2369 return lpszDest;
2371 if (llBytes < 1024) /* 1K */
2373 WCHAR wszBytesFormat[64];
2374 LoadStringW(shlwapi_hInstance, IDS_BYTES_FORMAT, wszBytesFormat, 64);
2375 snprintfW(lpszDest, cchMax, wszBytesFormat, (int)llBytes);
2376 return lpszDest;
2379 /* Note that if this loop completes without finding a match, i will be
2380 * pointing at the last entry, which is a catch all for > 1000 PB
2382 while (i < sizeof(bfFormats) / sizeof(SHLWAPI_BYTEFORMATS) - 1)
2384 if (llBytes < bfFormats[i].dLimit)
2385 break;
2386 i++;
2388 /* Above 1 TB we encounter problems with FP accuracy. So for amounts above
2389 * this number we integer shift down by 1 MB first. The table above has
2390 * the divisors scaled down from the '< 10 TB' entry onwards, to account
2391 * for this. We also add a small fudge factor to get the correct result for
2392 * counts that lie exactly on a 1024 byte boundary.
2394 if (i > 8)
2395 dBytes = (double)(llBytes >> 20) + 0.001; /* Scale down by 1 MB */
2396 else
2397 dBytes = (double)llBytes + 0.00001;
2399 dBytes = floor(dBytes / bfFormats[i].dDivisor) / bfFormats[i].dNormaliser;
2401 if (!FormatDouble(dBytes, bfFormats[i].nDecimals, lpszDest, cchMax))
2402 return NULL;
2403 wszAdd[1] = bfFormats[i].wPrefix;
2404 StrCatBuffW(lpszDest, wszAdd, cchMax);
2405 return lpszDest;
2408 /*************************************************************************
2409 * StrFormatByteSize64A [SHLWAPI.@]
2411 * See StrFormatByteSizeW.
2413 LPSTR WINAPI StrFormatByteSize64A(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax)
2415 WCHAR wszBuff[32];
2417 StrFormatByteSizeW(llBytes, wszBuff, sizeof(wszBuff)/sizeof(WCHAR));
2419 if (lpszDest)
2420 WideCharToMultiByte(CP_ACP, 0, wszBuff, -1, lpszDest, cchMax, 0, 0);
2421 return lpszDest;
2424 /*************************************************************************
2425 * StrFormatByteSizeA [SHLWAPI.@]
2427 * Create a string containing an abbreviated byte count of up to 2^31-1.
2429 * PARAMS
2430 * dwBytes [I] Byte size to format
2431 * lpszDest [I] Destination for formatted string
2432 * cchMax [I] Size of lpszDest
2434 * RETURNS
2435 * lpszDest.
2437 * NOTES
2438 * The Ascii and Unicode versions of this function accept a different
2439 * integer type for dwBytes. See StrFormatByteSize64A().
2441 LPSTR WINAPI StrFormatByteSizeA(DWORD dwBytes, LPSTR lpszDest, UINT cchMax)
2443 TRACE("(%d,%p,%d)\n", dwBytes, lpszDest, cchMax);
2445 return StrFormatByteSize64A(dwBytes, lpszDest, cchMax);
2448 /*************************************************************************
2449 * @ [SHLWAPI.162]
2451 * Remove a hanging lead byte from the end of a string, if present.
2453 * PARAMS
2454 * lpStr [I] String to check for a hanging lead byte
2455 * size [I] Length of lpStr
2457 * RETURNS
2458 * Success: The new length of the string. Any hanging lead bytes are removed.
2459 * Failure: 0, if any parameters are invalid.
2461 DWORD WINAPI SHTruncateString(LPSTR lpStr, DWORD size)
2463 if (lpStr && size)
2465 LPSTR lastByte = lpStr + size - 1;
2467 while(lpStr < lastByte)
2468 lpStr += IsDBCSLeadByte(*lpStr) ? 2 : 1;
2470 if(lpStr == lastByte && IsDBCSLeadByte(*lpStr))
2472 *lpStr = '\0';
2473 size--;
2475 return size;
2477 return 0;
2480 /*************************************************************************
2481 * @ [SHLWAPI.203]
2483 * Remove a single non-trailing ampersand ('&') from a string.
2485 * PARAMS
2486 * lpszStr [I/O] String to remove ampersand from.
2488 * RETURNS
2489 * The character after the first ampersand in lpszStr, or the first character
2490 * in lpszStr if there is no ampersand in the string.
2492 char WINAPI SHStripMneumonicA(LPCSTR lpszStr)
2494 LPSTR lpszIter, lpszTmp;
2495 char ch;
2497 TRACE("(%s)\n", debugstr_a(lpszStr));
2499 ch = *lpszStr;
2501 if ((lpszIter = StrChrA(lpszStr, '&')))
2503 lpszTmp = CharNextA(lpszIter);
2504 if (*lpszTmp)
2506 if (*lpszTmp != '&')
2507 ch = *lpszTmp;
2509 memmove( lpszIter, lpszTmp, strlen(lpszTmp) + 1 );
2513 return ch;
2516 /*************************************************************************
2517 * @ [SHLWAPI.225]
2519 * Unicode version of SHStripMneumonicA.
2521 WCHAR WINAPI SHStripMneumonicW(LPCWSTR lpszStr)
2523 LPWSTR lpszIter, lpszTmp;
2524 WCHAR ch;
2526 TRACE("(%s)\n", debugstr_w(lpszStr));
2528 ch = *lpszStr;
2530 if ((lpszIter = StrChrW(lpszStr, '&')))
2532 lpszTmp = lpszIter + 1;
2533 if (*lpszTmp)
2535 if (*lpszTmp != '&')
2536 ch = *lpszTmp;
2538 memmove( lpszIter, lpszTmp, (strlenW(lpszTmp) + 1) * sizeof(WCHAR) );
2542 return ch;
2545 /*************************************************************************
2546 * @ [SHLWAPI.216]
2548 * Convert an Ascii string to Unicode.
2550 * PARAMS
2551 * dwCp [I] Code page for the conversion
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 DWORD WINAPI SHAnsiToUnicodeCP(DWORD dwCp, LPCSTR lpSrcStr, LPWSTR lpDstStr, int iLen)
2561 DWORD dwRet;
2563 dwRet = MultiByteToWideChar(dwCp, 0, lpSrcStr, -1, lpDstStr, iLen);
2564 TRACE("%s->%s,ret=%d\n", debugstr_a(lpSrcStr), debugstr_w(lpDstStr), dwRet);
2565 return dwRet;
2568 /*************************************************************************
2569 * @ [SHLWAPI.215]
2571 * Convert an Ascii string to Unicode.
2573 * PARAMS
2574 * lpSrcStr [I] Source Ascii string to convert
2575 * lpDstStr [O] Destination for converted Unicode string
2576 * iLen [I] Length of lpDstStr
2578 * RETURNS
2579 * The return value of the MultiByteToWideChar() function called on lpSrcStr.
2581 * NOTES
2582 * This function simply calls SHAnsiToUnicodeCP with code page CP_ACP.
2584 DWORD WINAPI SHAnsiToUnicode(LPCSTR lpSrcStr, LPWSTR lpDstStr, int iLen)
2586 return SHAnsiToUnicodeCP(CP_ACP, lpSrcStr, lpDstStr, iLen);
2589 /*************************************************************************
2590 * @ [SHLWAPI.218]
2592 * Convert a Unicode string to Ascii.
2594 * PARAMS
2595 * CodePage [I] Code page to use for the conversion
2596 * lpSrcStr [I] Source Unicode string to convert
2597 * lpDstStr [O] Destination for converted Ascii string
2598 * dstlen [I] Length of buffer at lpDstStr
2600 * RETURNS
2601 * Success: The length in bytes of the result at lpDstStr (including the terminator)
2602 * Failure: When using CP_UTF8, CP_UTF7 or 0xc350 as codePage, 0 is returned and
2603 * the result is not nul-terminated.
2604 * When using a different codepage, the length in bytes of the truncated
2605 * result at lpDstStr (including the terminator) is returned and
2606 * lpDstStr is always nul-terminated.
2609 DWORD WINAPI SHUnicodeToAnsiCP(UINT CodePage, LPCWSTR lpSrcStr, LPSTR lpDstStr, int dstlen)
2611 static const WCHAR emptyW[] = { '\0' };
2612 int len , reqLen;
2613 LPSTR mem;
2615 if (!lpDstStr || !dstlen)
2616 return 0;
2618 if (!lpSrcStr)
2619 lpSrcStr = emptyW;
2621 *lpDstStr = '\0';
2623 len = strlenW(lpSrcStr) + 1;
2625 switch (CodePage)
2627 case CP_WINUNICODE:
2628 CodePage = CP_UTF8; /* Fall through... */
2629 case 0x0000C350: /* FIXME: CP_ #define */
2630 case CP_UTF7:
2631 case CP_UTF8:
2633 DWORD dwMode = 0;
2634 INT lenW = len - 1;
2635 INT needed = dstlen - 1;
2636 HRESULT hr;
2638 /* try the user supplied buffer first */
2639 hr = ConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &lenW, lpDstStr, &needed);
2640 if (hr == S_OK)
2642 lpDstStr[needed] = '\0';
2643 return needed + 1;
2646 /* user buffer too small. exclude termination and copy as much as possible */
2647 lenW = len;
2648 hr = ConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &lenW, NULL, &needed);
2649 needed++;
2650 mem = HeapAlloc(GetProcessHeap(), 0, needed);
2651 if (!mem)
2652 return 0;
2654 hr = ConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &len, mem, &needed);
2655 if (hr == S_OK)
2657 reqLen = SHTruncateString(mem, dstlen);
2658 if (reqLen > 0) memcpy(lpDstStr, mem, reqLen-1);
2660 HeapFree(GetProcessHeap(), 0, mem);
2661 return 0;
2663 default:
2664 break;
2667 /* try the user supplied buffer first */
2668 reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, lpDstStr, dstlen, NULL, NULL);
2670 if (!reqLen && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
2672 reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, NULL, 0, NULL, NULL);
2673 if (reqLen)
2675 mem = HeapAlloc(GetProcessHeap(), 0, reqLen);
2676 if (mem)
2678 reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, mem,
2679 reqLen, NULL, NULL);
2681 reqLen = SHTruncateString(mem, dstlen -1);
2682 reqLen++;
2684 lstrcpynA(lpDstStr, mem, reqLen);
2685 HeapFree(GetProcessHeap(), 0, mem);
2686 lpDstStr[reqLen-1] = '\0';
2690 return reqLen;
2693 /*************************************************************************
2694 * @ [SHLWAPI.217]
2696 * Convert a Unicode string to Ascii.
2698 * PARAMS
2699 * lpSrcStr [I] Source Unicode string to convert
2700 * lpDstStr [O] Destination for converted Ascii string
2701 * iLen [O] Length of lpDstStr in characters
2703 * RETURNS
2704 * See SHUnicodeToAnsiCP
2706 * NOTES
2707 * This function simply calls SHUnicodeToAnsiCP() with CodePage = CP_ACP.
2709 INT WINAPI SHUnicodeToAnsi(LPCWSTR lpSrcStr, LPSTR lpDstStr, INT iLen)
2711 return SHUnicodeToAnsiCP(CP_ACP, lpSrcStr, lpDstStr, iLen);
2714 /*************************************************************************
2715 * @ [SHLWAPI.345]
2717 * Copy one string to another.
2719 * PARAMS
2720 * lpszSrc [I] Source string to copy
2721 * lpszDst [O] Destination for copy
2722 * iLen [I] Length of lpszDst in characters
2724 * RETURNS
2725 * The length of the copied string, including the terminating NUL. lpszDst
2726 * contains iLen characters of lpszSrc.
2728 DWORD WINAPI SHAnsiToAnsi(LPCSTR lpszSrc, LPSTR lpszDst, int iLen)
2730 LPSTR lpszRet;
2732 TRACE("(%s,%p,0x%08x)\n", debugstr_a(lpszSrc), lpszDst, iLen);
2734 lpszRet = StrCpyNXA(lpszDst, lpszSrc, iLen);
2735 return lpszRet - lpszDst + 1;
2738 /*************************************************************************
2739 * @ [SHLWAPI.346]
2741 * Unicode version of SSHAnsiToAnsi.
2743 DWORD WINAPI SHUnicodeToUnicode(LPCWSTR lpszSrc, LPWSTR lpszDst, int iLen)
2745 LPWSTR lpszRet;
2747 TRACE("(%s,%p,0x%08x)\n", debugstr_w(lpszSrc), lpszDst, iLen);
2749 lpszRet = StrCpyNXW(lpszDst, lpszSrc, iLen);
2750 return lpszRet - lpszDst + 1;
2753 /*************************************************************************
2754 * @ [SHLWAPI.364]
2756 * Determine if an Ascii string converts to Unicode and back identically.
2758 * PARAMS
2759 * lpSrcStr [I] Source Unicode string to convert
2760 * lpDst [O] Destination for resulting Ascii string
2761 * iLen [I] Length of lpDst in characters
2763 * RETURNS
2764 * TRUE, since Ascii strings always convert identically.
2766 BOOL WINAPI DoesStringRoundTripA(LPCSTR lpSrcStr, LPSTR lpDst, INT iLen)
2768 lstrcpynA(lpDst, lpSrcStr, iLen);
2769 return TRUE;
2772 /*************************************************************************
2773 * @ [SHLWAPI.365]
2775 * Determine if a Unicode string converts to Ascii and back identically.
2777 * PARAMS
2778 * lpSrcStr [I] Source Unicode string to convert
2779 * lpDst [O] Destination for resulting Ascii string
2780 * iLen [I] Length of lpDst in characters
2782 * RETURNS
2783 * TRUE, if lpSrcStr converts to Ascii and back identically,
2784 * FALSE otherwise.
2786 BOOL WINAPI DoesStringRoundTripW(LPCWSTR lpSrcStr, LPSTR lpDst, INT iLen)
2788 WCHAR szBuff[MAX_PATH];
2790 SHUnicodeToAnsi(lpSrcStr, lpDst, iLen);
2791 SHAnsiToUnicode(lpDst, szBuff, MAX_PATH);
2792 return !strcmpW(lpSrcStr, szBuff);
2795 /*************************************************************************
2796 * SHLoadIndirectString [SHLWAPI.@]
2798 * If passed a string that begins with '@', extract the string from the
2799 * appropriate resource, otherwise do a straight copy.
2802 HRESULT WINAPI SHLoadIndirectString(LPCWSTR src, LPWSTR dst, UINT dst_len, void **reserved)
2804 WCHAR *dllname = NULL;
2805 HMODULE hmod = NULL;
2806 HRESULT hr = E_FAIL;
2808 TRACE("(%s %p %08x %p)\n", debugstr_w(src), dst, dst_len, reserved);
2810 if(src[0] == '@')
2812 WCHAR *index_str;
2813 int index;
2815 dst[0] = 0;
2816 dllname = StrDupW(src + 1);
2817 index_str = strchrW(dllname, ',');
2819 if(!index_str) goto end;
2821 *index_str = 0;
2822 index_str++;
2823 index = atoiW(index_str);
2825 hmod = LoadLibraryW(dllname);
2826 if(!hmod) goto end;
2828 if(index < 0)
2830 if(LoadStringW(hmod, -index, dst, dst_len))
2831 hr = S_OK;
2833 else
2834 FIXME("can't handle non-negative indices (%d)\n", index);
2836 else
2838 if(dst != src)
2839 lstrcpynW(dst, src, dst_len);
2840 hr = S_OK;
2843 TRACE("returning %s\n", debugstr_w(dst));
2844 end:
2845 if(hmod) FreeLibrary(hmod);
2846 HeapFree(GetProcessHeap(), 0, dllname);
2847 return hr;