shlwapi: Remove redundant "not NULL" checks of the len arg (coccicheck).
[wine/hacks.git] / dlls / shlwapi / string.c
bloba0269b6cb37fbe85fe4c2df5e6bd1f8b1e629fe9
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 bytes 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 bytes 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 if (!lpszStr || !lpszSearch) return NULL;
588 return strstrW( lpszStr, lpszSearch );
591 /*************************************************************************
592 * StrRStrIA [SHLWAPI.@]
594 * Find the last occurrence of a substring within a string.
596 * PARAMS
597 * lpszStr [I] String to search in
598 * lpszEnd [I] End of lpszStr
599 * lpszSearch [I] String to look for
601 * RETURNS
602 * The last occurrence lpszSearch within lpszStr, or NULL if not found.
604 LPSTR WINAPI StrRStrIA(LPCSTR lpszStr, LPCSTR lpszEnd, LPCSTR lpszSearch)
606 WORD ch1, ch2;
607 INT iLen;
609 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
611 if (!lpszStr || !lpszSearch || !*lpszSearch)
612 return NULL;
614 if (!lpszEnd)
615 lpszEnd = lpszStr + lstrlenA(lpszStr);
616 if (lpszEnd == lpszStr)
617 return NULL;
619 if (IsDBCSLeadByte(*lpszSearch))
620 ch1 = *lpszSearch << 8 | (UCHAR)lpszSearch[1];
621 else
622 ch1 = *lpszSearch;
623 iLen = lstrlenA(lpszSearch);
627 lpszEnd = CharPrevA(lpszStr, lpszEnd);
628 ch2 = IsDBCSLeadByte(*lpszEnd)? *lpszEnd << 8 | (UCHAR)lpszEnd[1] : *lpszEnd;
629 if (!ChrCmpIA(ch1, ch2))
631 if (!StrCmpNIA(lpszEnd, lpszSearch, iLen))
632 return (LPSTR)lpszEnd;
634 } while (lpszEnd > lpszStr);
635 return NULL;
638 /*************************************************************************
639 * StrRStrIW [SHLWAPI.@]
641 * See StrRStrIA.
643 LPWSTR WINAPI StrRStrIW(LPCWSTR lpszStr, LPCWSTR lpszEnd, LPCWSTR lpszSearch)
645 INT iLen;
647 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
649 if (!lpszStr || !lpszSearch || !*lpszSearch)
650 return NULL;
652 if (!lpszEnd)
653 lpszEnd = lpszStr + strlenW(lpszStr);
655 iLen = strlenW(lpszSearch);
657 while (lpszEnd > lpszStr)
659 lpszEnd--;
660 if (!StrCmpNIW(lpszEnd, lpszSearch, iLen))
661 return (LPWSTR)lpszEnd;
663 return NULL;
666 /*************************************************************************
667 * StrStrIA [SHLWAPI.@]
669 * Find a substring within a string, ignoring case.
671 * PARAMS
672 * lpszStr [I] String to search in
673 * lpszSearch [I] String to look for
675 * RETURNS
676 * The start of lpszSearch within lpszStr, or NULL if not found.
678 LPSTR WINAPI StrStrIA(LPCSTR lpszStr, LPCSTR lpszSearch)
680 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
682 return SHLWAPI_StrStrHelperA(lpszStr, lpszSearch, StrCmpNIA);
685 /*************************************************************************
686 * StrStrIW [SHLWAPI.@]
688 * See StrStrIA.
690 LPWSTR WINAPI StrStrIW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
692 int iLen;
694 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
696 if (!lpszStr || !lpszSearch || !*lpszSearch)
697 return NULL;
699 iLen = strlenW(lpszSearch);
701 while (*lpszStr)
703 if (!StrCmpNIW(lpszStr, lpszSearch, iLen))
704 return (LPWSTR)lpszStr;
705 lpszStr++;
707 return NULL;
710 /*************************************************************************
711 * StrToIntA [SHLWAPI.@]
713 * Read a signed integer from a string.
715 * PARAMS
716 * lpszStr [I] String to read integer from
718 * RETURNS
719 * The signed integer value represented by the string, or 0 if no integer is
720 * present.
722 * NOTES
723 * No leading space is allowed before the number, although a leading '-' is.
725 int WINAPI StrToIntA(LPCSTR lpszStr)
727 int iRet = 0;
729 TRACE("(%s)\n", debugstr_a(lpszStr));
731 if (!lpszStr)
733 WARN("Invalid lpszStr would crash under Win32!\n");
734 return 0;
737 if (*lpszStr == '-' || isdigit(*lpszStr))
738 StrToIntExA(lpszStr, 0, &iRet);
739 return iRet;
742 /*************************************************************************
743 * StrToIntW [SHLWAPI.@]
745 * See StrToIntA.
747 int WINAPI StrToIntW(LPCWSTR lpszStr)
749 int iRet = 0;
751 TRACE("(%s)\n", debugstr_w(lpszStr));
753 if (!lpszStr)
755 WARN("Invalid lpszStr would crash under Win32!\n");
756 return 0;
759 if (*lpszStr == '-' || isdigitW(*lpszStr))
760 StrToIntExW(lpszStr, 0, &iRet);
761 return iRet;
764 /*************************************************************************
765 * StrToIntExA [SHLWAPI.@]
767 * Read an integer from a string.
769 * PARAMS
770 * lpszStr [I] String to read integer from
771 * dwFlags [I] Flags controlling the conversion
772 * lpiRet [O] Destination for read integer.
774 * RETURNS
775 * Success: TRUE. lpiRet contains the integer value represented by the string.
776 * Failure: FALSE, if the string is invalid, or no number is present.
778 * NOTES
779 * Leading whitespace, '-' and '+' are allowed before the number. If
780 * dwFlags includes STIF_SUPPORT_HEX, hexadecimal numbers are allowed, if
781 * preceded by '0x'. If this flag is not set, or there is no '0x' prefix,
782 * the string is treated as a decimal string. A leading '-' is ignored for
783 * hexadecimal numbers.
785 BOOL WINAPI StrToIntExA(LPCSTR lpszStr, DWORD dwFlags, LPINT lpiRet)
787 BOOL bNegative = FALSE;
788 int iRet = 0;
790 TRACE("(%s,%08X,%p)\n", debugstr_a(lpszStr), dwFlags, lpiRet);
792 if (!lpszStr || !lpiRet)
794 WARN("Invalid parameter would crash under Win32!\n");
795 return FALSE;
797 if (dwFlags > STIF_SUPPORT_HEX)
799 WARN("Unknown flags (%08lX)!\n", dwFlags & ~STIF_SUPPORT_HEX);
802 /* Skip leading space, '+', '-' */
803 while (isspace(*lpszStr))
804 lpszStr = CharNextA(lpszStr);
806 if (*lpszStr == '-')
808 bNegative = TRUE;
809 lpszStr++;
811 else if (*lpszStr == '+')
812 lpszStr++;
814 if (dwFlags & STIF_SUPPORT_HEX &&
815 *lpszStr == '0' && tolower(lpszStr[1]) == 'x')
817 /* Read hex number */
818 lpszStr += 2;
820 if (!isxdigit(*lpszStr))
821 return FALSE;
823 while (isxdigit(*lpszStr))
825 iRet = iRet * 16;
826 if (isdigit(*lpszStr))
827 iRet += (*lpszStr - '0');
828 else
829 iRet += 10 + (tolower(*lpszStr) - 'a');
830 lpszStr++;
832 *lpiRet = iRet;
833 return TRUE;
836 /* Read decimal number */
837 if (!isdigit(*lpszStr))
838 return FALSE;
840 while (isdigit(*lpszStr))
842 iRet = iRet * 10;
843 iRet += (*lpszStr - '0');
844 lpszStr++;
846 *lpiRet = bNegative ? -iRet : iRet;
847 return TRUE;
850 /*************************************************************************
851 * StrToIntExW [SHLWAPI.@]
853 * See StrToIntExA.
855 BOOL WINAPI StrToIntExW(LPCWSTR lpszStr, DWORD dwFlags, LPINT lpiRet)
857 BOOL bNegative = FALSE;
858 int iRet = 0;
860 TRACE("(%s,%08X,%p)\n", debugstr_w(lpszStr), dwFlags, lpiRet);
862 if (!lpszStr || !lpiRet)
864 WARN("Invalid parameter would crash under Win32!\n");
865 return FALSE;
867 if (dwFlags > STIF_SUPPORT_HEX)
869 WARN("Unknown flags (%08lX)!\n", dwFlags & ~STIF_SUPPORT_HEX);
872 /* Skip leading space, '+', '-' */
873 while (isspaceW(*lpszStr)) lpszStr++;
875 if (*lpszStr == '-')
877 bNegative = TRUE;
878 lpszStr++;
880 else if (*lpszStr == '+')
881 lpszStr++;
883 if (dwFlags & STIF_SUPPORT_HEX &&
884 *lpszStr == '0' && tolowerW(lpszStr[1]) == 'x')
886 /* Read hex number */
887 lpszStr += 2;
889 if (!isxdigitW(*lpszStr))
890 return FALSE;
892 while (isxdigitW(*lpszStr))
894 iRet = iRet * 16;
895 if (isdigitW(*lpszStr))
896 iRet += (*lpszStr - '0');
897 else
898 iRet += 10 + (tolowerW(*lpszStr) - 'a');
899 lpszStr++;
901 *lpiRet = iRet;
902 return TRUE;
905 /* Read decimal number */
906 if (!isdigitW(*lpszStr))
907 return FALSE;
909 while (isdigitW(*lpszStr))
911 iRet = iRet * 10;
912 iRet += (*lpszStr - '0');
913 lpszStr++;
915 *lpiRet = bNegative ? -iRet : iRet;
916 return TRUE;
919 /*************************************************************************
920 * StrDupA [SHLWAPI.@]
922 * Duplicate a string.
924 * PARAMS
925 * lpszStr [I] String to duplicate.
927 * RETURNS
928 * Success: A pointer to a new string containing the contents of lpszStr
929 * Failure: NULL, if memory cannot be allocated
931 * NOTES
932 * The string memory is allocated with LocalAlloc(), and so should be released
933 * by calling LocalFree().
935 LPSTR WINAPI StrDupA(LPCSTR lpszStr)
937 int iLen;
938 LPSTR lpszRet;
940 TRACE("(%s)\n",debugstr_a(lpszStr));
942 iLen = lpszStr ? strlen(lpszStr) + 1 : 1;
943 lpszRet = LocalAlloc(LMEM_FIXED, iLen);
945 if (lpszRet)
947 if (lpszStr)
948 memcpy(lpszRet, lpszStr, iLen);
949 else
950 *lpszRet = '\0';
952 return lpszRet;
955 /*************************************************************************
956 * StrDupW [SHLWAPI.@]
958 * See StrDupA.
960 LPWSTR WINAPI StrDupW(LPCWSTR lpszStr)
962 int iLen;
963 LPWSTR lpszRet;
965 TRACE("(%s)\n",debugstr_w(lpszStr));
967 iLen = (lpszStr ? strlenW(lpszStr) + 1 : 1) * sizeof(WCHAR);
968 lpszRet = LocalAlloc(LMEM_FIXED, iLen);
970 if (lpszRet)
972 if (lpszStr)
973 memcpy(lpszRet, lpszStr, iLen);
974 else
975 *lpszRet = '\0';
977 return lpszRet;
980 /*************************************************************************
981 * SHLWAPI_StrSpnHelperA
983 * Internal implementation of StrSpnA/StrCSpnA/StrCSpnIA
985 static int SHLWAPI_StrSpnHelperA(LPCSTR lpszStr, LPCSTR lpszMatch,
986 LPSTR (WINAPI *pStrChrFn)(LPCSTR,WORD),
987 BOOL bInvert)
989 LPCSTR lpszRead = lpszStr;
990 if (lpszStr && *lpszStr && lpszMatch)
992 while (*lpszRead)
994 LPCSTR lpszTest = pStrChrFn(lpszMatch, *lpszRead);
996 if (!bInvert && !lpszTest)
997 break;
998 if (bInvert && lpszTest)
999 break;
1000 lpszRead = CharNextA(lpszRead);
1003 return lpszRead - lpszStr;
1006 /*************************************************************************
1007 * StrSpnA [SHLWAPI.@]
1009 * Find the length of the start of a string that contains only certain
1010 * characters.
1012 * PARAMS
1013 * lpszStr [I] String to search
1014 * lpszMatch [I] Characters that can be in the substring
1016 * RETURNS
1017 * The length of the part of lpszStr containing only chars from lpszMatch,
1018 * or 0 if any parameter is invalid.
1020 int WINAPI StrSpnA(LPCSTR lpszStr, LPCSTR lpszMatch)
1022 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1024 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, FALSE);
1027 /*************************************************************************
1028 * StrSpnW [SHLWAPI.@]
1030 * See StrSpnA.
1032 int WINAPI StrSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1034 if (!lpszStr || !lpszMatch) return 0;
1035 return strspnW( lpszStr, lpszMatch );
1038 /*************************************************************************
1039 * StrCSpnA [SHLWAPI.@]
1041 * Find the length of the start of a string that does not contain certain
1042 * characters.
1044 * PARAMS
1045 * lpszStr [I] String to search
1046 * lpszMatch [I] Characters that cannot be in the substring
1048 * RETURNS
1049 * The length of the part of lpszStr containing only chars not in lpszMatch,
1050 * or 0 if any parameter is invalid.
1052 int WINAPI StrCSpnA(LPCSTR lpszStr, LPCSTR lpszMatch)
1054 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1056 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, TRUE);
1059 /*************************************************************************
1060 * StrCSpnW [SHLWAPI.@]
1062 * See StrCSpnA.
1064 int WINAPI StrCSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1066 if (!lpszStr || !lpszMatch) return 0;
1067 return strcspnW( lpszStr, lpszMatch );
1070 /*************************************************************************
1071 * StrCSpnIA [SHLWAPI.@]
1073 * Find the length of the start of a string that does not contain certain
1074 * characters, ignoring case.
1076 * PARAMS
1077 * lpszStr [I] String to search
1078 * lpszMatch [I] Characters that cannot be in the substring
1080 * RETURNS
1081 * The length of the part of lpszStr containing only chars not in lpszMatch,
1082 * or 0 if any parameter is invalid.
1084 int WINAPI StrCSpnIA(LPCSTR lpszStr, LPCSTR lpszMatch)
1086 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1088 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrIA, TRUE);
1091 /*************************************************************************
1092 * StrCSpnIW [SHLWAPI.@]
1094 * See StrCSpnIA.
1096 int WINAPI StrCSpnIW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1098 LPCWSTR lpszRead = lpszStr;
1100 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1102 if (lpszStr && *lpszStr && lpszMatch)
1104 while (*lpszRead)
1106 if (StrChrIW(lpszMatch, *lpszRead)) break;
1107 lpszRead++;
1110 return lpszRead - lpszStr;
1113 /*************************************************************************
1114 * StrPBrkA [SHLWAPI.@]
1116 * Search a string for any of a group of characters.
1118 * PARAMS
1119 * lpszStr [I] String to search
1120 * lpszMatch [I] Characters to match
1122 * RETURNS
1123 * A pointer to the first matching character in lpszStr, or NULL if no
1124 * match was found.
1126 LPSTR WINAPI StrPBrkA(LPCSTR lpszStr, LPCSTR lpszMatch)
1128 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1130 if (lpszStr && lpszMatch && *lpszMatch)
1132 while (*lpszStr)
1134 if (StrChrA(lpszMatch, *lpszStr))
1135 return (LPSTR)lpszStr;
1136 lpszStr = CharNextA(lpszStr);
1139 return NULL;
1142 /*************************************************************************
1143 * StrPBrkW [SHLWAPI.@]
1145 * See StrPBrkA.
1147 LPWSTR WINAPI StrPBrkW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1149 if (!lpszStr || !lpszMatch) return NULL;
1150 return strpbrkW( lpszStr, lpszMatch );
1153 /*************************************************************************
1154 * SHLWAPI_StrRChrHelperA
1156 * Internal implementation of StrRChrA/StrRChrIA.
1158 static LPSTR SHLWAPI_StrRChrHelperA(LPCSTR lpszStr,
1159 LPCSTR lpszEnd, WORD ch,
1160 BOOL (WINAPI *pChrCmpFn)(WORD,WORD))
1162 LPCSTR lpszRet = NULL;
1164 if (lpszStr)
1166 WORD ch2;
1168 if (!lpszEnd)
1169 lpszEnd = lpszStr + lstrlenA(lpszStr);
1171 while (*lpszStr && lpszStr <= lpszEnd)
1173 ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr;
1175 if (!pChrCmpFn(ch, ch2))
1176 lpszRet = lpszStr;
1177 lpszStr = CharNextA(lpszStr);
1180 return (LPSTR)lpszRet;
1183 /**************************************************************************
1184 * StrRChrA [SHLWAPI.@]
1186 * Find the last occurrence of a character in string.
1188 * PARAMS
1189 * lpszStr [I] String to search in
1190 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1191 * ch [I] Character to search for.
1193 * RETURNS
1194 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1195 * or NULL if not found.
1196 * Failure: NULL, if any arguments are invalid.
1198 LPSTR WINAPI StrRChrA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch)
1200 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch);
1202 return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, SHLWAPI_ChrCmpA);
1205 /**************************************************************************
1206 * StrRChrW [SHLWAPI.@]
1208 * See StrRChrA.
1210 LPWSTR WINAPI StrRChrW(LPCWSTR str, LPCWSTR end, WORD ch)
1212 WCHAR *ret = NULL;
1214 if (!str) return NULL;
1215 if (!end) end = str + strlenW(str);
1216 while (str < end)
1218 if (*str == ch) ret = (WCHAR *)str;
1219 str++;
1221 return ret;
1224 /**************************************************************************
1225 * StrRChrIA [SHLWAPI.@]
1227 * Find the last occurrence of a character in string, ignoring case.
1229 * PARAMS
1230 * lpszStr [I] String to search in
1231 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1232 * ch [I] Character to search for.
1234 * RETURNS
1235 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1236 * or NULL if not found.
1237 * Failure: NULL, if any arguments are invalid.
1239 LPSTR WINAPI StrRChrIA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch)
1241 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch);
1243 return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, ChrCmpIA);
1246 /**************************************************************************
1247 * StrRChrIW [SHLWAPI.@]
1249 * See StrRChrIA.
1251 LPWSTR WINAPI StrRChrIW(LPCWSTR str, LPCWSTR end, WORD ch)
1253 WCHAR *ret = NULL;
1255 if (!str) return NULL;
1256 if (!end) end = str + strlenW(str);
1257 while (str < end)
1259 if (!ChrCmpIW(*str, ch)) ret = (WCHAR *)str;
1260 str++;
1262 return ret;
1265 /*************************************************************************
1266 * StrCatBuffA [SHLWAPI.@]
1268 * Concatenate two strings together.
1270 * PARAMS
1271 * lpszStr [O] String to concatenate to
1272 * lpszCat [I] String to add to lpszCat
1273 * cchMax [I] Maximum number of characters for the whole string
1275 * RETURNS
1276 * lpszStr.
1278 * NOTES
1279 * cchMax determines the number of characters in the final length of the
1280 * string, not the number appended to lpszStr from lpszCat.
1282 LPSTR WINAPI StrCatBuffA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax)
1284 INT iLen;
1286 TRACE("(%p,%s,%d)\n", lpszStr, debugstr_a(lpszCat), cchMax);
1288 if (!lpszStr)
1290 WARN("Invalid lpszStr would crash under Win32!\n");
1291 return NULL;
1294 iLen = strlen(lpszStr);
1295 cchMax -= iLen;
1297 if (cchMax > 0)
1298 StrCpyNA(lpszStr + iLen, lpszCat, cchMax);
1299 return lpszStr;
1302 /*************************************************************************
1303 * StrCatBuffW [SHLWAPI.@]
1305 * See StrCatBuffA.
1307 LPWSTR WINAPI StrCatBuffW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax)
1309 INT iLen;
1311 TRACE("(%p,%s,%d)\n", lpszStr, debugstr_w(lpszCat), cchMax);
1313 if (!lpszStr)
1315 WARN("Invalid lpszStr would crash under Win32!\n");
1316 return NULL;
1319 iLen = strlenW(lpszStr);
1320 cchMax -= iLen;
1322 if (cchMax > 0)
1323 StrCpyNW(lpszStr + iLen, lpszCat, cchMax);
1324 return lpszStr;
1327 /*************************************************************************
1328 * StrRetToBufA [SHLWAPI.@]
1330 * Convert a STRRET to a normal string.
1332 * PARAMS
1333 * lpStrRet [O] STRRET to convert
1334 * pIdl [I] ITEMIDLIST for lpStrRet->uType == STRRET_OFFSET
1335 * lpszDest [O] Destination for normal string
1336 * dwLen [I] Length of lpszDest
1338 * RETURNS
1339 * Success: S_OK. lpszDest contains up to dwLen characters of the string.
1340 * If lpStrRet is of type STRRET_WSTR, its memory is freed with
1341 * CoTaskMemFree() and its type set to STRRET_CSTRA.
1342 * Failure: E_FAIL, if any parameters are invalid.
1344 HRESULT WINAPI StrRetToBufA (LPSTRRET src, const ITEMIDLIST *pidl, LPSTR dest, UINT len)
1346 /* NOTE:
1347 * This routine is identical to that in dlls/shell32/shellstring.c.
1348 * It was duplicated because not every version of Shlwapi.dll exports
1349 * StrRetToBufA. If you change one routine, change them both.
1351 TRACE("dest=%p len=0x%x strret=%p pidl=%p stub\n",dest,len,src,pidl);
1353 if (!src)
1355 WARN("Invalid lpStrRet would crash under Win32!\n");
1356 if (dest)
1357 *dest = '\0';
1358 return E_FAIL;
1361 if (!dest || !len)
1362 return E_FAIL;
1364 *dest = '\0';
1366 switch (src->uType)
1368 case STRRET_WSTR:
1369 WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, dest, len, NULL, NULL);
1370 CoTaskMemFree(src->u.pOleStr);
1371 break;
1373 case STRRET_CSTR:
1374 lstrcpynA(dest, src->u.cStr, len);
1375 break;
1377 case STRRET_OFFSET:
1378 lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len);
1379 break;
1381 default:
1382 FIXME("unknown type!\n");
1383 return FALSE;
1385 return S_OK;
1388 /*************************************************************************
1389 * StrRetToBufW [SHLWAPI.@]
1391 * See StrRetToBufA.
1393 HRESULT WINAPI StrRetToBufW (LPSTRRET src, const ITEMIDLIST *pidl, LPWSTR dest, UINT len)
1395 TRACE("dest=%p len=0x%x strret=%p pidl=%p stub\n",dest,len,src,pidl);
1397 if (!src)
1399 WARN("Invalid lpStrRet would crash under Win32!\n");
1400 if (dest)
1401 *dest = '\0';
1402 return E_FAIL;
1405 if (!dest || !len)
1406 return E_FAIL;
1408 *dest = '\0';
1410 switch (src->uType)
1412 case STRRET_WSTR:
1413 lstrcpynW(dest, src->u.pOleStr, len);
1414 CoTaskMemFree(src->u.pOleStr);
1415 break;
1417 case STRRET_CSTR:
1418 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ))
1419 dest[len-1] = 0;
1420 break;
1422 case STRRET_OFFSET:
1423 if (pidl)
1425 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1,
1426 dest, len ))
1427 dest[len-1] = 0;
1429 break;
1431 default:
1432 FIXME("unknown type!\n");
1433 return FALSE;
1435 return S_OK;
1438 /*************************************************************************
1439 * StrRetToStrA [SHLWAPI.@]
1441 * Converts a STRRET to a normal string.
1443 * PARAMS
1444 * lpStrRet [O] STRRET to convert
1445 * pidl [I] ITEMIDLIST for lpStrRet->uType == STRRET_OFFSET
1446 * ppszName [O] Destination for converted string
1448 * RETURNS
1449 * Success: S_OK. ppszName contains the new string, allocated with CoTaskMemAlloc().
1450 * Failure: E_FAIL, if any parameters are invalid.
1452 HRESULT WINAPI StrRetToStrA(LPSTRRET lpStrRet, const ITEMIDLIST *pidl, LPSTR *ppszName)
1454 HRESULT hRet = E_FAIL;
1456 switch (lpStrRet->uType)
1458 case STRRET_WSTR:
1459 hRet = _SHStrDupAW(lpStrRet->u.pOleStr, ppszName);
1460 CoTaskMemFree(lpStrRet->u.pOleStr);
1461 break;
1463 case STRRET_CSTR:
1464 hRet = _SHStrDupAA(lpStrRet->u.cStr, ppszName);
1465 break;
1467 case STRRET_OFFSET:
1468 hRet = _SHStrDupAA(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, ppszName);
1469 break;
1471 default:
1472 *ppszName = NULL;
1475 return hRet;
1478 /*************************************************************************
1479 * StrRetToStrW [SHLWAPI.@]
1481 * See StrRetToStrA.
1483 HRESULT WINAPI StrRetToStrW(LPSTRRET lpStrRet, const ITEMIDLIST *pidl, LPWSTR *ppszName)
1485 HRESULT hRet = E_FAIL;
1487 switch (lpStrRet->uType)
1489 case STRRET_WSTR:
1490 hRet = SHStrDupW(lpStrRet->u.pOleStr, ppszName);
1491 CoTaskMemFree(lpStrRet->u.pOleStr);
1492 break;
1494 case STRRET_CSTR:
1495 hRet = SHStrDupA(lpStrRet->u.cStr, ppszName);
1496 break;
1498 case STRRET_OFFSET:
1499 hRet = SHStrDupA(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, ppszName);
1500 break;
1502 default:
1503 *ppszName = NULL;
1506 return hRet;
1509 /* Create an ASCII string copy using SysAllocString() */
1510 static HRESULT _SHStrDupAToBSTR(LPCSTR src, BSTR *pBstrOut)
1512 *pBstrOut = NULL;
1514 if (src)
1516 INT len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0);
1517 WCHAR* szTemp = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1519 if (szTemp)
1521 MultiByteToWideChar(CP_ACP, 0, src, -1, szTemp, len);
1522 *pBstrOut = SysAllocString(szTemp);
1523 HeapFree(GetProcessHeap(), 0, szTemp);
1525 if (*pBstrOut)
1526 return S_OK;
1529 return E_OUTOFMEMORY;
1532 /*************************************************************************
1533 * StrRetToBSTR [SHLWAPI.@]
1535 * Converts a STRRET to a BSTR.
1537 * PARAMS
1538 * lpStrRet [O] STRRET to convert
1539 * pidl [I] ITEMIDLIST for lpStrRet->uType = STRRET_OFFSET
1540 * pBstrOut [O] Destination for converted BSTR
1542 * RETURNS
1543 * Success: S_OK. pBstrOut contains the new string.
1544 * Failure: E_FAIL, if any parameters are invalid.
1546 HRESULT WINAPI StrRetToBSTR(STRRET *lpStrRet, LPCITEMIDLIST pidl, BSTR* pBstrOut)
1548 HRESULT hRet = E_FAIL;
1550 switch (lpStrRet->uType)
1552 case STRRET_WSTR:
1553 *pBstrOut = SysAllocString(lpStrRet->u.pOleStr);
1554 if (*pBstrOut)
1555 hRet = S_OK;
1556 CoTaskMemFree(lpStrRet->u.pOleStr);
1557 break;
1559 case STRRET_CSTR:
1560 hRet = _SHStrDupAToBSTR(lpStrRet->u.cStr, pBstrOut);
1561 break;
1563 case STRRET_OFFSET:
1564 hRet = _SHStrDupAToBSTR(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, pBstrOut);
1565 break;
1567 default:
1568 *pBstrOut = NULL;
1571 return hRet;
1574 /*************************************************************************
1575 * StrFormatKBSizeA [SHLWAPI.@]
1577 * Create a formatted string containing a byte count in Kilobytes.
1579 * PARAMS
1580 * llBytes [I] Byte size to format
1581 * lpszDest [I] Destination for formatted string
1582 * cchMax [I] Size of lpszDest
1584 * RETURNS
1585 * lpszDest.
1587 LPSTR WINAPI StrFormatKBSizeA(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax)
1589 WCHAR wszBuf[256];
1591 if (!StrFormatKBSizeW(llBytes, wszBuf, 256))
1592 return NULL;
1593 if (!WideCharToMultiByte(CP_ACP, 0, wszBuf, -1, lpszDest, cchMax, NULL, NULL))
1594 return NULL;
1595 return lpszDest;
1598 /*************************************************************************
1599 * StrFormatKBSizeW [SHLWAPI.@]
1601 * See StrFormatKBSizeA.
1603 LPWSTR WINAPI StrFormatKBSizeW(LONGLONG llBytes, LPWSTR lpszDest, UINT cchMax)
1605 static const WCHAR kb[] = {' ','K','B',0};
1606 LONGLONG llKB = (llBytes + 1023) >> 10;
1607 int len;
1609 TRACE("(0x%s,%p,%d)\n", wine_dbgstr_longlong(llBytes), lpszDest, cchMax);
1611 if (!FormatInt(llKB, lpszDest, cchMax))
1612 return NULL;
1614 len = lstrlenW(lpszDest);
1615 if (cchMax - len < 4)
1616 return NULL;
1617 lstrcatW(lpszDest, kb);
1618 return lpszDest;
1621 /*************************************************************************
1622 * StrNCatA [SHLWAPI.@]
1624 * Concatenate two strings together.
1626 * PARAMS
1627 * lpszStr [O] String to concatenate to
1628 * lpszCat [I] String to add to lpszCat
1629 * cchMax [I] Maximum number of characters to concatenate
1631 * RETURNS
1632 * lpszStr.
1634 * NOTES
1635 * cchMax determines the number of characters that are appended to lpszStr,
1636 * not the total length of the string.
1638 LPSTR WINAPI StrNCatA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax)
1640 LPSTR lpszRet = lpszStr;
1642 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszCat), cchMax);
1644 if (!lpszStr)
1646 WARN("Invalid lpszStr would crash under Win32!\n");
1647 return NULL;
1650 StrCpyNA(lpszStr + strlen(lpszStr), lpszCat, cchMax);
1651 return lpszRet;
1654 /*************************************************************************
1655 * StrNCatW [SHLWAPI.@]
1657 * See StrNCatA.
1659 LPWSTR WINAPI StrNCatW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax)
1661 LPWSTR lpszRet = lpszStr;
1663 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszCat), cchMax);
1665 if (!lpszStr)
1667 WARN("Invalid lpszStr would crash under Win32\n");
1668 return NULL;
1671 StrCpyNW(lpszStr + strlenW(lpszStr), lpszCat, cchMax);
1672 return lpszRet;
1675 /*************************************************************************
1676 * StrTrimA [SHLWAPI.@]
1678 * Remove characters from the start and end of a string.
1680 * PARAMS
1681 * lpszStr [O] String to remove characters from
1682 * lpszTrim [I] Characters to remove from lpszStr
1684 * RETURNS
1685 * TRUE If lpszStr was valid and modified
1686 * FALSE Otherwise
1688 BOOL WINAPI StrTrimA(LPSTR lpszStr, LPCSTR lpszTrim)
1690 DWORD dwLen;
1691 LPSTR lpszRead = lpszStr;
1692 BOOL bRet = FALSE;
1694 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszTrim));
1696 if (lpszRead && *lpszRead)
1698 while (*lpszRead && StrChrA(lpszTrim, *lpszRead))
1699 lpszRead = CharNextA(lpszRead); /* Skip leading matches */
1701 dwLen = strlen(lpszRead);
1703 if (lpszRead != lpszStr)
1705 memmove(lpszStr, lpszRead, dwLen + 1);
1706 bRet = TRUE;
1708 if (dwLen > 0)
1710 lpszRead = lpszStr + dwLen;
1711 while (StrChrA(lpszTrim, lpszRead[-1]))
1712 lpszRead = CharPrevA(lpszStr, lpszRead); /* Skip trailing matches */
1714 if (lpszRead != lpszStr + dwLen)
1716 *lpszRead = '\0';
1717 bRet = TRUE;
1721 return bRet;
1724 /*************************************************************************
1725 * StrTrimW [SHLWAPI.@]
1727 * See StrTrimA.
1729 BOOL WINAPI StrTrimW(LPWSTR lpszStr, LPCWSTR lpszTrim)
1731 DWORD dwLen;
1732 LPWSTR lpszRead = lpszStr;
1733 BOOL bRet = FALSE;
1735 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszTrim));
1737 if (lpszRead && *lpszRead)
1739 while (*lpszRead && StrChrW(lpszTrim, *lpszRead)) lpszRead++;
1741 dwLen = strlenW(lpszRead);
1743 if (lpszRead != lpszStr)
1745 memmove(lpszStr, lpszRead, (dwLen + 1) * sizeof(WCHAR));
1746 bRet = TRUE;
1748 if (dwLen > 0)
1750 lpszRead = lpszStr + dwLen;
1751 while (StrChrW(lpszTrim, lpszRead[-1]))
1752 lpszRead--; /* Skip trailing matches */
1754 if (lpszRead != lpszStr + dwLen)
1756 *lpszRead = '\0';
1757 bRet = TRUE;
1761 return bRet;
1764 /*************************************************************************
1765 * _SHStrDupAA [INTERNAL]
1767 * Duplicates a ASCII string to ASCII. The destination buffer is allocated.
1769 static HRESULT _SHStrDupAA(LPCSTR src, LPSTR * dest)
1771 HRESULT hr;
1772 int len = 0;
1774 if (src) {
1775 len = lstrlenA(src) + 1;
1776 *dest = CoTaskMemAlloc(len);
1777 } else {
1778 *dest = NULL;
1781 if (*dest) {
1782 lstrcpynA(*dest,src, len);
1783 hr = S_OK;
1784 } else {
1785 hr = E_OUTOFMEMORY;
1788 TRACE("%s->(%p)\n", debugstr_a(src), *dest);
1789 return hr;
1792 /*************************************************************************
1793 * SHStrDupA [SHLWAPI.@]
1795 * Return a Unicode copy of a string, in memory allocated by CoTaskMemAlloc().
1797 * PARAMS
1798 * lpszStr [I] String to copy
1799 * lppszDest [O] Destination for the new string copy
1801 * RETURNS
1802 * Success: S_OK. lppszDest contains the new string in Unicode format.
1803 * Failure: E_OUTOFMEMORY, If any arguments are invalid or memory allocation
1804 * fails.
1806 HRESULT WINAPI SHStrDupA(LPCSTR lpszStr, LPWSTR * lppszDest)
1808 HRESULT hRet;
1809 int len = 0;
1811 if (lpszStr)
1813 len = MultiByteToWideChar(0, 0, lpszStr, -1, 0, 0) * sizeof(WCHAR);
1814 *lppszDest = CoTaskMemAlloc(len);
1816 else
1817 *lppszDest = NULL;
1819 if (*lppszDest)
1821 MultiByteToWideChar(0, 0, lpszStr, -1, *lppszDest, len/sizeof(WCHAR));
1822 hRet = S_OK;
1824 else
1825 hRet = E_OUTOFMEMORY;
1827 TRACE("%s->(%p)\n", debugstr_a(lpszStr), *lppszDest);
1828 return hRet;
1831 /*************************************************************************
1832 * _SHStrDupAW [INTERNAL]
1834 * Duplicates a UNICODE to a ASCII string. The destination buffer is allocated.
1836 static HRESULT _SHStrDupAW(LPCWSTR src, LPSTR * dest)
1838 HRESULT hr;
1839 int len = 0;
1841 if (src) {
1842 len = WideCharToMultiByte(CP_ACP, 0, src, -1, NULL, 0, NULL, NULL);
1843 *dest = CoTaskMemAlloc(len);
1844 } else {
1845 *dest = NULL;
1848 if (*dest) {
1849 WideCharToMultiByte(CP_ACP, 0, src, -1, *dest, len, NULL, NULL);
1850 hr = S_OK;
1851 } else {
1852 hr = E_OUTOFMEMORY;
1855 TRACE("%s->(%p)\n", debugstr_w(src), *dest);
1856 return hr;
1859 /*************************************************************************
1860 * SHStrDupW [SHLWAPI.@]
1862 * See SHStrDupA.
1864 HRESULT WINAPI SHStrDupW(LPCWSTR src, LPWSTR * dest)
1866 HRESULT hr;
1867 int len = 0;
1869 if (src) {
1870 len = (lstrlenW(src) + 1) * sizeof(WCHAR);
1871 *dest = CoTaskMemAlloc(len);
1872 } else {
1873 *dest = NULL;
1876 if (*dest) {
1877 memcpy(*dest, src, len);
1878 hr = S_OK;
1879 } else {
1880 hr = E_OUTOFMEMORY;
1883 TRACE("%s->(%p)\n", debugstr_w(src), *dest);
1884 return hr;
1887 /*************************************************************************
1888 * SHLWAPI_WriteReverseNum
1890 * Internal helper for SHLWAPI_WriteTimeClass.
1892 static inline LPWSTR SHLWAPI_WriteReverseNum(LPWSTR lpszOut, DWORD dwNum)
1894 *lpszOut-- = '\0';
1896 /* Write a decimal number to a string, backwards */
1899 DWORD dwNextDigit = dwNum % 10;
1900 *lpszOut-- = '0' + dwNextDigit;
1901 dwNum = (dwNum - dwNextDigit) / 10;
1902 } while (dwNum > 0);
1904 return lpszOut;
1907 /*************************************************************************
1908 * SHLWAPI_FormatSignificant
1910 * Internal helper for SHLWAPI_WriteTimeClass.
1912 static inline int SHLWAPI_FormatSignificant(LPWSTR lpszNum, int dwDigits)
1914 /* Zero non significant digits, return remaining significant digits */
1915 while (*lpszNum)
1917 lpszNum++;
1918 if (--dwDigits == 0)
1920 while (*lpszNum)
1921 *lpszNum++ = '0';
1922 return 0;
1925 return dwDigits;
1928 /*************************************************************************
1929 * SHLWAPI_WriteTimeClass
1931 * Internal helper for StrFromTimeIntervalW.
1933 static int SHLWAPI_WriteTimeClass(LPWSTR lpszOut, DWORD dwValue,
1934 UINT uClassStringId, int iDigits)
1936 WCHAR szBuff[64], *szOut = szBuff + 32;
1938 szOut = SHLWAPI_WriteReverseNum(szOut, dwValue);
1939 iDigits = SHLWAPI_FormatSignificant(szOut + 1, iDigits);
1940 *szOut = ' ';
1941 LoadStringW(shlwapi_hInstance, uClassStringId, szBuff + 32, 32);
1942 strcatW(lpszOut, szOut);
1943 return iDigits;
1946 /*************************************************************************
1947 * StrFromTimeIntervalA [SHLWAPI.@]
1949 * Format a millisecond time interval into a string
1951 * PARAMS
1952 * lpszStr [O] Output buffer for formatted time interval
1953 * cchMax [I] Size of lpszStr
1954 * dwMS [I] Number of milliseconds
1955 * iDigits [I] Number of digits to print
1957 * RETURNS
1958 * The length of the formatted string, or 0 if any parameter is invalid.
1960 * NOTES
1961 * This implementation mimics the Win32 behaviour of always writing a leading
1962 * space before the time interval begins.
1964 * iDigits is used to provide approximate times if accuracy is not important.
1965 * This number of digits will be written of the first non-zero time class
1966 * (hours/minutes/seconds). If this does not complete the time classification,
1967 * the remaining digits are changed to zeros (i.e. The time is _not_ rounded).
1968 * If there are digits remaining following the writing of a time class, the
1969 * next time class will be written.
1971 * For example, given dwMS represents 138 hours,43 minutes and 15 seconds, the
1972 * following will result from the given values of iDigits:
1974 *| iDigits 1 2 3 4 5 ...
1975 *| lpszStr "100 hr" "130 hr" "138 hr" "138 hr 40 min" "138 hr 43 min" ...
1977 INT WINAPI StrFromTimeIntervalA(LPSTR lpszStr, UINT cchMax, DWORD dwMS,
1978 int iDigits)
1980 INT iRet = 0;
1982 TRACE("(%p,%d,%d,%d)\n", lpszStr, cchMax, dwMS, iDigits);
1984 if (lpszStr && cchMax)
1986 WCHAR szBuff[128];
1987 StrFromTimeIntervalW(szBuff, sizeof(szBuff)/sizeof(WCHAR), dwMS, iDigits);
1988 WideCharToMultiByte(CP_ACP,0,szBuff,-1,lpszStr,cchMax,0,0);
1990 return iRet;
1994 /*************************************************************************
1995 * StrFromTimeIntervalW [SHLWAPI.@]
1997 * See StrFromTimeIntervalA.
1999 INT WINAPI StrFromTimeIntervalW(LPWSTR lpszStr, UINT cchMax, DWORD dwMS,
2000 int iDigits)
2002 INT iRet = 0;
2004 TRACE("(%p,%d,%d,%d)\n", lpszStr, cchMax, dwMS, iDigits);
2006 if (lpszStr && cchMax)
2008 WCHAR szCopy[128];
2009 DWORD dwHours, dwMinutes;
2011 if (!iDigits || cchMax == 1)
2013 *lpszStr = '\0';
2014 return 0;
2017 /* Calculate the time classes */
2018 dwMS = (dwMS + 500) / 1000;
2019 dwHours = dwMS / 3600;
2020 dwMS -= dwHours * 3600;
2021 dwMinutes = dwMS / 60;
2022 dwMS -= dwMinutes * 60;
2024 szCopy[0] = '\0';
2026 if (dwHours)
2027 iDigits = SHLWAPI_WriteTimeClass(szCopy, dwHours, IDS_TIME_INTERVAL_HOURS, iDigits);
2029 if (dwMinutes && iDigits)
2030 iDigits = SHLWAPI_WriteTimeClass(szCopy, dwMinutes, IDS_TIME_INTERVAL_MINUTES, iDigits);
2032 if (iDigits) /* Always write seconds if we have significant digits */
2033 SHLWAPI_WriteTimeClass(szCopy, dwMS, IDS_TIME_INTERVAL_SECONDS, iDigits);
2035 lstrcpynW(lpszStr, szCopy, cchMax);
2036 iRet = strlenW(lpszStr);
2038 return iRet;
2041 /*************************************************************************
2042 * StrIsIntlEqualA [SHLWAPI.@]
2044 * Compare two strings.
2046 * PARAMS
2047 * bCase [I] Whether to compare case sensitively
2048 * lpszStr [I] First string to compare
2049 * lpszComp [I] Second string to compare
2050 * iLen [I] Length to compare
2052 * RETURNS
2053 * TRUE If the strings are equal.
2054 * FALSE Otherwise.
2056 BOOL WINAPI StrIsIntlEqualA(BOOL bCase, LPCSTR lpszStr, LPCSTR lpszComp,
2057 int iLen)
2059 DWORD dwFlags;
2061 TRACE("(%d,%s,%s,%d)\n", bCase,
2062 debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
2064 /* FIXME: This flag is undocumented and unknown by our CompareString.
2065 * We need a define for it.
2067 dwFlags = 0x10000000;
2068 if (!bCase) dwFlags |= NORM_IGNORECASE;
2070 return (CompareStringA(GetThreadLocale(), dwFlags, lpszStr, iLen, lpszComp, iLen) == CSTR_EQUAL);
2073 /*************************************************************************
2074 * StrIsIntlEqualW [SHLWAPI.@]
2076 * See StrIsIntlEqualA.
2078 BOOL WINAPI StrIsIntlEqualW(BOOL bCase, LPCWSTR lpszStr, LPCWSTR lpszComp,
2079 int iLen)
2081 DWORD dwFlags;
2083 TRACE("(%d,%s,%s,%d)\n", bCase,
2084 debugstr_w(lpszStr),debugstr_w(lpszComp), iLen);
2086 /* FIXME: This flag is undocumented and unknown by our CompareString.
2087 * We need a define for it.
2089 dwFlags = 0x10000000;
2090 if (!bCase) dwFlags |= NORM_IGNORECASE;
2092 return (CompareStringW(GetThreadLocale(), dwFlags, lpszStr, iLen, lpszComp, iLen) == CSTR_EQUAL);
2095 /*************************************************************************
2096 * @ [SHLWAPI.399]
2098 * Copy a string to another string, up to a maximum number of characters.
2100 * PARAMS
2101 * lpszDest [O] Destination string
2102 * lpszSrc [I] Source string
2103 * iLen [I] Maximum number of chars to copy
2105 * RETURNS
2106 * Success: A pointer to the last character written to lpszDest.
2107 * Failure: lpszDest, if any arguments are invalid.
2109 LPSTR WINAPI StrCpyNXA(LPSTR lpszDest, LPCSTR lpszSrc, int iLen)
2111 TRACE("(%p,%s,%i)\n", lpszDest, debugstr_a(lpszSrc), iLen);
2113 if (lpszDest && lpszSrc && iLen > 0)
2115 while ((iLen-- > 1) && *lpszSrc)
2116 *lpszDest++ = *lpszSrc++;
2117 if (iLen >= 0)
2118 *lpszDest = '\0';
2120 return lpszDest;
2123 /*************************************************************************
2124 * @ [SHLWAPI.400]
2126 * Unicode version of StrCpyNXA.
2128 LPWSTR WINAPI StrCpyNXW(LPWSTR lpszDest, LPCWSTR lpszSrc, int iLen)
2130 TRACE("(%p,%s,%i)\n", lpszDest, debugstr_w(lpszSrc), iLen);
2132 if (lpszDest && lpszSrc && iLen > 0)
2134 while ((iLen-- > 1) && *lpszSrc)
2135 *lpszDest++ = *lpszSrc++;
2136 if (iLen >= 0)
2137 *lpszDest = '\0';
2139 return lpszDest;
2142 /*************************************************************************
2143 * StrCmpLogicalW [SHLWAPI.@]
2145 * Compare two strings, ignoring case and comparing digits as numbers.
2147 * PARAMS
2148 * lpszStr [I] First string to compare
2149 * lpszComp [I] Second string to compare
2150 * iLen [I] Length to compare
2152 * RETURNS
2153 * TRUE If the strings are equal.
2154 * FALSE Otherwise.
2156 INT WINAPI StrCmpLogicalW(LPCWSTR lpszStr, LPCWSTR lpszComp)
2158 INT iDiff;
2160 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszComp));
2162 if (lpszStr && lpszComp)
2164 while (*lpszStr)
2166 if (!*lpszComp)
2167 return 1;
2168 else if (isdigitW(*lpszStr))
2170 int iStr, iComp;
2172 if (!isdigitW(*lpszComp))
2173 return -1;
2175 /* Compare the numbers */
2176 StrToIntExW(lpszStr, 0, &iStr);
2177 StrToIntExW(lpszComp, 0, &iComp);
2179 if (iStr < iComp)
2180 return -1;
2181 else if (iStr > iComp)
2182 return 1;
2184 /* Skip */
2185 while (isdigitW(*lpszStr))
2186 lpszStr++;
2187 while (isdigitW(*lpszComp))
2188 lpszComp++;
2190 else if (isdigitW(*lpszComp))
2191 return 1;
2192 else
2194 iDiff = ChrCmpIW(*lpszStr,*lpszComp);
2195 if (iDiff > 0)
2196 return 1;
2197 else if (iDiff < 0)
2198 return -1;
2200 lpszStr++;
2201 lpszComp++;
2204 if (*lpszComp)
2205 return -1;
2207 return 0;
2210 /* Structure for formatting byte strings */
2211 typedef struct tagSHLWAPI_BYTEFORMATS
2213 LONGLONG dLimit;
2214 double dDivisor;
2215 double dNormaliser;
2216 int nDecimals;
2217 WCHAR wPrefix;
2218 } SHLWAPI_BYTEFORMATS;
2220 /*************************************************************************
2221 * StrFormatByteSizeW [SHLWAPI.@]
2223 * Create a string containing an abbreviated byte count of up to 2^63-1.
2225 * PARAMS
2226 * llBytes [I] Byte size to format
2227 * lpszDest [I] Destination for formatted string
2228 * cchMax [I] Size of lpszDest
2230 * RETURNS
2231 * lpszDest.
2233 * NOTES
2234 * There is no StrFormatByteSize64W function, it is called StrFormatByteSizeW().
2236 LPWSTR WINAPI StrFormatByteSizeW(LONGLONG llBytes, LPWSTR lpszDest, UINT cchMax)
2238 #define KB ((ULONGLONG)1024)
2239 #define MB (KB*KB)
2240 #define GB (KB*KB*KB)
2241 #define TB (KB*KB*KB*KB)
2242 #define PB (KB*KB*KB*KB*KB)
2244 static const SHLWAPI_BYTEFORMATS bfFormats[] =
2246 { 10*KB, 10.24, 100.0, 2, 'K' }, /* 10 KB */
2247 { 100*KB, 102.4, 10.0, 1, 'K' }, /* 100 KB */
2248 { 1000*KB, 1024.0, 1.0, 0, 'K' }, /* 1000 KB */
2249 { 10*MB, 10485.76, 100.0, 2, 'M' }, /* 10 MB */
2250 { 100*MB, 104857.6, 10.0, 1, 'M' }, /* 100 MB */
2251 { 1000*MB, 1048576.0, 1.0, 0, 'M' }, /* 1000 MB */
2252 { 10*GB, 10737418.24, 100.0, 2, 'G' }, /* 10 GB */
2253 { 100*GB, 107374182.4, 10.0, 1, 'G' }, /* 100 GB */
2254 { 1000*GB, 1073741824.0, 1.0, 0, 'G' }, /* 1000 GB */
2255 { 10*TB, 10485.76, 100.0, 2, 'T' }, /* 10 TB */
2256 { 100*TB, 104857.6, 10.0, 1, 'T' }, /* 100 TB */
2257 { 1000*TB, 1048576.0, 1.0, 0, 'T' }, /* 1000 TB */
2258 { 10*PB, 10737418.24, 100.00, 2, 'P' }, /* 10 PB */
2259 { 100*PB, 107374182.4, 10.00, 1, 'P' }, /* 100 PB */
2260 { 1000*PB, 1073741824.0, 1.00, 0, 'P' }, /* 1000 PB */
2261 { 0, 10995116277.76, 100.00, 2, 'E' } /* EB's, catch all */
2263 WCHAR wszAdd[] = {' ','?','B',0};
2264 double dBytes;
2265 UINT i = 0;
2267 TRACE("(0x%s,%p,%d)\n", wine_dbgstr_longlong(llBytes), lpszDest, cchMax);
2269 if (!lpszDest || !cchMax)
2270 return lpszDest;
2272 if (llBytes < 1024) /* 1K */
2274 WCHAR wszBytesFormat[64];
2275 LoadStringW(shlwapi_hInstance, IDS_BYTES_FORMAT, wszBytesFormat, 64);
2276 snprintfW(lpszDest, cchMax, wszBytesFormat, (long)llBytes);
2277 return lpszDest;
2280 /* Note that if this loop completes without finding a match, i will be
2281 * pointing at the last entry, which is a catch all for > 1000 PB
2283 while (i < sizeof(bfFormats) / sizeof(SHLWAPI_BYTEFORMATS) - 1)
2285 if (llBytes < bfFormats[i].dLimit)
2286 break;
2287 i++;
2289 /* Above 1 TB we encounter problems with FP accuracy. So for amounts above
2290 * this number we integer shift down by 1 MB first. The table above has
2291 * the divisors scaled down from the '< 10 TB' entry onwards, to account
2292 * for this. We also add a small fudge factor to get the correct result for
2293 * counts that lie exactly on a 1024 byte boundary.
2295 if (i > 8)
2296 dBytes = (double)(llBytes >> 20) + 0.001; /* Scale down by I MB */
2297 else
2298 dBytes = (double)llBytes + 0.00001;
2300 dBytes = floor(dBytes / bfFormats[i].dDivisor) / bfFormats[i].dNormaliser;
2302 if (!FormatDouble(dBytes, bfFormats[i].nDecimals, lpszDest, cchMax))
2303 return NULL;
2304 wszAdd[1] = bfFormats[i].wPrefix;
2305 StrCatBuffW(lpszDest, wszAdd, cchMax);
2306 return lpszDest;
2309 /*************************************************************************
2310 * StrFormatByteSize64A [SHLWAPI.@]
2312 * See StrFormatByteSizeW.
2314 LPSTR WINAPI StrFormatByteSize64A(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax)
2316 WCHAR wszBuff[32];
2318 StrFormatByteSizeW(llBytes, wszBuff, sizeof(wszBuff)/sizeof(WCHAR));
2320 if (lpszDest)
2321 WideCharToMultiByte(CP_ACP, 0, wszBuff, -1, lpszDest, cchMax, 0, 0);
2322 return lpszDest;
2325 /*************************************************************************
2326 * StrFormatByteSizeA [SHLWAPI.@]
2328 * Create a string containing an abbreviated byte count of up to 2^31-1.
2330 * PARAMS
2331 * dwBytes [I] Byte size to format
2332 * lpszDest [I] Destination for formatted string
2333 * cchMax [I] Size of lpszDest
2335 * RETURNS
2336 * lpszDest.
2338 * NOTES
2339 * The Ascii and Unicode versions of this function accept a different
2340 * integer type for dwBytes. See StrFormatByteSize64A().
2342 LPSTR WINAPI StrFormatByteSizeA(DWORD dwBytes, LPSTR lpszDest, UINT cchMax)
2344 TRACE("(%d,%p,%d)\n", dwBytes, lpszDest, cchMax);
2346 return StrFormatByteSize64A(dwBytes, lpszDest, cchMax);
2349 /*************************************************************************
2350 * @ [SHLWAPI.162]
2352 * Remove a hanging lead byte from the end of a string, if present.
2354 * PARAMS
2355 * lpStr [I] String to check for a hanging lead byte
2356 * size [I] Length of lpStr
2358 * RETURNS
2359 * Success: The new length of the string. Any hanging lead bytes are removed.
2360 * Failure: 0, if any parameters are invalid.
2362 DWORD WINAPI SHTruncateString(LPSTR lpStr, DWORD size)
2364 if (lpStr && size)
2366 LPSTR lastByte = lpStr + size - 1;
2368 while(lpStr < lastByte)
2369 lpStr += IsDBCSLeadByte(*lpStr) ? 2 : 1;
2371 if(lpStr == lastByte && IsDBCSLeadByte(*lpStr))
2373 *lpStr = '\0';
2374 size--;
2376 return size;
2378 return 0;
2381 /*************************************************************************
2382 * @ [SHLWAPI.203]
2384 * Remove a single non-trailing ampersand ('&') from a string.
2386 * PARAMS
2387 * lpszStr [I/O] String to remove ampersand from.
2389 * RETURNS
2390 * The character after the first ampersand in lpszStr, or the first character
2391 * in lpszStr if there is no ampersand in the string.
2393 char WINAPI SHStripMneumonicA(LPCSTR lpszStr)
2395 LPSTR lpszIter, lpszTmp;
2396 char ch;
2398 TRACE("(%s)\n", debugstr_a(lpszStr));
2400 ch = *lpszStr;
2402 if ((lpszIter = StrChrA(lpszStr, '&')))
2404 lpszTmp = CharNextA(lpszIter);
2405 if (lpszTmp && *lpszTmp)
2407 if (*lpszTmp != '&')
2408 ch = *lpszTmp;
2410 while (lpszIter && *lpszIter)
2412 lpszTmp = CharNextA(lpszIter);
2413 *lpszIter = *lpszTmp;
2414 lpszIter = lpszTmp;
2419 return ch;
2422 /*************************************************************************
2423 * @ [SHLWAPI.225]
2425 * Unicode version of SHStripMneumonicA.
2427 WCHAR WINAPI SHStripMneumonicW(LPCWSTR lpszStr)
2429 LPWSTR lpszIter, lpszTmp;
2430 WCHAR ch;
2432 TRACE("(%s)\n", debugstr_w(lpszStr));
2434 ch = *lpszStr;
2436 if ((lpszIter = StrChrW(lpszStr, '&')))
2438 lpszTmp = lpszIter + 1;
2439 if (lpszTmp && *lpszTmp)
2441 if (*lpszTmp != '&')
2442 ch = *lpszTmp;
2444 while (lpszIter && *lpszIter)
2446 lpszTmp = lpszIter + 1;
2447 *lpszIter = *lpszTmp;
2448 lpszIter = lpszTmp;
2453 return ch;
2456 /*************************************************************************
2457 * @ [SHLWAPI.216]
2459 * Convert an Ascii string to Unicode.
2461 * PARAMS
2462 * dwCp [I] Code page for the conversion
2463 * lpSrcStr [I] Source Ascii string to convert
2464 * lpDstStr [O] Destination for converted Unicode string
2465 * iLen [I] Length of lpDstStr
2467 * RETURNS
2468 * The return value of the MultiByteToWideChar() function called on lpSrcStr.
2470 DWORD WINAPI SHAnsiToUnicodeCP(DWORD dwCp, LPCSTR lpSrcStr, LPWSTR lpDstStr, int iLen)
2472 DWORD dwRet;
2474 dwRet = MultiByteToWideChar(dwCp, 0, lpSrcStr, -1, lpDstStr, iLen);
2475 TRACE("%s->%s,ret=%d\n", debugstr_a(lpSrcStr), debugstr_w(lpDstStr), dwRet);
2476 return dwRet;
2479 /*************************************************************************
2480 * @ [SHLWAPI.215]
2482 * Convert an Ascii string to Unicode.
2484 * PARAMS
2485 * lpSrcStr [I] Source Ascii string to convert
2486 * lpDstStr [O] Destination for converted Unicode string
2487 * iLen [I] Length of lpDstStr
2489 * RETURNS
2490 * The return value of the MultiByteToWideChar() function called on lpSrcStr.
2492 * NOTES
2493 * This function simply calls SHAnsiToUnicodeCP with code page CP_ACP.
2495 DWORD WINAPI SHAnsiToUnicode(LPCSTR lpSrcStr, LPWSTR lpDstStr, int iLen)
2497 return SHAnsiToUnicodeCP(CP_ACP, lpSrcStr, lpDstStr, iLen);
2500 /*************************************************************************
2501 * @ [SHLWAPI.218]
2503 * Convert a Unicode string to Ascii.
2505 * PARAMS
2506 * CodePage [I] Code page to use for the conversion
2507 * lpSrcStr [I] Source Unicode string to convert
2508 * lpDstStr [O] Destination for converted Ascii string
2509 * dstlen [I] Length of buffer at lpDstStr
2511 * RETURNS
2512 * Success: The length in bytes of the result at lpDstStr (including the terminator)
2513 * Failure: When using CP_UTF8, CP_UTF7 or 0xc350 as codePage, 0 is returned and
2514 * the result is not nul-terminated.
2515 * When using a different codepage, the length in bytes of the truncated
2516 * result at lpDstStr (including the terminator) is returned and
2517 * lpDstStr is always nul-terminated.
2520 DWORD WINAPI SHUnicodeToAnsiCP(UINT CodePage, LPCWSTR lpSrcStr, LPSTR lpDstStr, int dstlen)
2522 static const WCHAR emptyW[] = { '\0' };
2523 int len , reqLen;
2524 LPSTR mem;
2526 if (!lpDstStr || !dstlen)
2527 return 0;
2529 if (!lpSrcStr)
2530 lpSrcStr = emptyW;
2532 *lpDstStr = '\0';
2534 len = strlenW(lpSrcStr) + 1;
2536 switch (CodePage)
2538 case CP_WINUNICODE:
2539 CodePage = CP_UTF8; /* Fall through... */
2540 case 0x0000C350: /* FIXME: CP_ #define */
2541 case CP_UTF7:
2542 case CP_UTF8:
2544 DWORD dwMode = 0;
2545 INT lenW = len - 1;
2546 INT needed = dstlen - 1;
2547 HRESULT hr;
2549 /* try the user supplied buffer first */
2550 hr = ConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &lenW, lpDstStr, &needed);
2551 if (hr == S_OK)
2553 lpDstStr[needed] = '\0';
2554 return needed + 1;
2557 /* user buffer too small. exclude termination and copy as much as possible */
2558 lenW = len;
2559 hr = ConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &lenW, NULL, &needed);
2560 needed++;
2561 mem = HeapAlloc(GetProcessHeap(), 0, needed);
2562 if (!mem)
2563 return 0;
2565 hr = ConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &len, mem, &needed);
2566 if (hr == S_OK)
2568 reqLen = SHTruncateString(mem, dstlen);
2569 if (reqLen > 0) memcpy(lpDstStr, mem, reqLen-1);
2571 HeapFree(GetProcessHeap(), 0, mem);
2572 return 0;
2574 default:
2575 break;
2578 /* try the user supplied buffer first */
2579 reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, lpDstStr, dstlen, NULL, NULL);
2581 if (!reqLen && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
2583 reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, NULL, 0, NULL, NULL);
2584 if (reqLen)
2586 mem = HeapAlloc(GetProcessHeap(), 0, reqLen);
2587 if (mem)
2589 reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, mem,
2590 reqLen, NULL, NULL);
2592 reqLen = SHTruncateString(mem, dstlen -1);
2593 reqLen++;
2595 lstrcpynA(lpDstStr, mem, reqLen);
2596 HeapFree(GetProcessHeap(), 0, mem);
2597 lpDstStr[reqLen-1] = '\0';
2601 return reqLen;
2604 /*************************************************************************
2605 * @ [SHLWAPI.217]
2607 * Convert a Unicode string to Ascii.
2609 * PARAMS
2610 * lpSrcStr [I] Source Unicode string to convert
2611 * lpDstStr [O] Destination for converted Ascii string
2612 * iLen [O] Length of lpDstStr in characters
2614 * RETURNS
2615 * See SHUnicodeToAnsiCP
2617 * NOTES
2618 * This function simply calls SHUnicodeToAnsiCP() with CodePage = CP_ACP.
2620 INT WINAPI SHUnicodeToAnsi(LPCWSTR lpSrcStr, LPSTR lpDstStr, INT iLen)
2622 return SHUnicodeToAnsiCP(CP_ACP, lpSrcStr, lpDstStr, iLen);
2625 /*************************************************************************
2626 * @ [SHLWAPI.345]
2628 * Copy one string to another.
2630 * PARAMS
2631 * lpszSrc [I] Source string to copy
2632 * lpszDst [O] Destination for copy
2633 * iLen [I] Length of lpszDst in characters
2635 * RETURNS
2636 * The length of the copied string, including the terminating NUL. lpszDst
2637 * contains iLen characters of lpszSrc.
2639 DWORD WINAPI SHAnsiToAnsi(LPCSTR lpszSrc, LPSTR lpszDst, int iLen)
2641 LPSTR lpszRet;
2643 TRACE("(%s,%p,0x%08x)\n", debugstr_a(lpszSrc), lpszDst, iLen);
2645 lpszRet = StrCpyNXA(lpszDst, lpszSrc, iLen);
2646 return lpszRet - lpszDst + 1;
2649 /*************************************************************************
2650 * @ [SHLWAPI.346]
2652 * Unicode version of SSHAnsiToAnsi.
2654 DWORD WINAPI SHUnicodeToUnicode(LPCWSTR lpszSrc, LPWSTR lpszDst, int iLen)
2656 LPWSTR lpszRet;
2658 TRACE("(%s,%p,0x%08x)\n", debugstr_w(lpszSrc), lpszDst, iLen);
2660 lpszRet = StrCpyNXW(lpszDst, lpszSrc, iLen);
2661 return lpszRet - lpszDst + 1;
2664 /*************************************************************************
2665 * @ [SHLWAPI.364]
2667 * Determine if an Ascii string converts to Unicode and back identically.
2669 * PARAMS
2670 * lpSrcStr [I] Source Unicode string to convert
2671 * lpDst [O] Destination for resulting Ascii string
2672 * iLen [I] Length of lpDst in characters
2674 * RETURNS
2675 * TRUE, since Ascii strings always convert identically.
2677 BOOL WINAPI DoesStringRoundTripA(LPCSTR lpSrcStr, LPSTR lpDst, INT iLen)
2679 lstrcpynA(lpDst, lpSrcStr, iLen);
2680 return TRUE;
2683 /*************************************************************************
2684 * @ [SHLWAPI.365]
2686 * Determine if a Unicode string converts to Ascii and back identically.
2688 * PARAMS
2689 * lpSrcStr [I] Source Unicode string to convert
2690 * lpDst [O] Destination for resulting Ascii string
2691 * iLen [I] Length of lpDst in characters
2693 * RETURNS
2694 * TRUE, if lpSrcStr converts to Ascii and back identically,
2695 * FALSE otherwise.
2697 BOOL WINAPI DoesStringRoundTripW(LPCWSTR lpSrcStr, LPSTR lpDst, INT iLen)
2699 WCHAR szBuff[MAX_PATH];
2701 SHUnicodeToAnsi(lpSrcStr, lpDst, iLen);
2702 SHAnsiToUnicode(lpDst, szBuff, MAX_PATH);
2703 return !strcmpW(lpSrcStr, szBuff);
2706 /*************************************************************************
2707 * SHLoadIndirectString [SHLWAPI.@]
2709 * If passed a string that begins with '@', extract the string from the
2710 * appropriate resource, otherwise do a straight copy.
2713 HRESULT WINAPI SHLoadIndirectString(LPCWSTR src, LPWSTR dst, UINT dst_len, void **reserved)
2715 WCHAR *dllname = NULL;
2716 HMODULE hmod = NULL;
2717 HRESULT hr = E_FAIL;
2719 TRACE("(%s %p %08x %p)\n", debugstr_w(src), dst, dst_len, reserved);
2721 if(src[0] == '@')
2723 WCHAR *index_str;
2724 int index;
2726 dst[0] = 0;
2727 dllname = StrDupW(src + 1);
2728 index_str = strchrW(dllname, ',');
2730 if(!index_str) goto end;
2732 *index_str = 0;
2733 index_str++;
2734 index = atoiW(index_str);
2736 hmod = LoadLibraryW(dllname);
2737 if(!hmod) goto end;
2739 if(index < 0)
2741 if(LoadStringW(hmod, -index, dst, dst_len))
2742 hr = S_OK;
2744 else
2745 FIXME("can't handle non-negative indices (%d)\n", index);
2747 else
2749 if(dst != src)
2750 lstrcpynW(dst, src, dst_len);
2751 hr = S_OK;
2754 TRACE("returning %s\n", debugstr_w(dst));
2755 end:
2756 if(hmod) FreeLibrary(hmod);
2757 HeapFree(GetProcessHeap(), 0, dllname);
2758 return hr;