wininet: Fix szCacheContent in URLCacheContainer_OpenIndex.
[wine/hacks.git] / dlls / shlwapi / string.c
blob82ee06192419b2832c78b8dbad6f03da0dd8acb7
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 WINAPI _SHStrDupAA(LPCSTR,LPSTR*);
52 static HRESULT WINAPI _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 WINAPI 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_ChrCmpHelperW
185 * Internal helper for SHLWAPI_ChrCmpW/ChrCmpIW.
187 static BOOL WINAPI SHLWAPI_ChrCmpHelperW(WCHAR ch1, WCHAR ch2, DWORD dwFlags)
189 WCHAR str1[2], str2[2];
191 str1[0] = ch1;
192 str1[1] = '\0';
193 str2[0] = ch2;
194 str2[1] = '\0';
195 return CompareStringW(GetThreadLocale(), dwFlags, str1, 2, str2, 2) - 2;
198 /*************************************************************************
199 * SHLWAPI_ChrCmpA
201 * Internal helper function.
203 static BOOL WINAPI SHLWAPI_ChrCmpA(WORD ch1, WORD ch2)
205 return SHLWAPI_ChrCmpHelperA(ch1, ch2, 0);
208 /*************************************************************************
209 * ChrCmpIA (SHLWAPI.385)
211 * Compare two characters, ignoring case.
213 * PARAMS
214 * ch1 [I] First character to compare
215 * ch2 [I] Second character to compare
217 * RETURNS
218 * FALSE, if the characters are equal.
219 * Non-zero otherwise.
221 BOOL WINAPI ChrCmpIA(WORD ch1, WORD ch2)
223 TRACE("(%d,%d)\n", ch1, ch2);
225 return SHLWAPI_ChrCmpHelperA(ch1, ch2, NORM_IGNORECASE);
228 /*************************************************************************
229 * SHLWAPI_ChrCmpW
231 * Internal helper function.
233 static BOOL WINAPI SHLWAPI_ChrCmpW(WCHAR ch1, WCHAR ch2)
235 return SHLWAPI_ChrCmpHelperW(ch1, ch2, 0);
238 /*************************************************************************
239 * ChrCmpIW [SHLWAPI.386]
241 * See ChrCmpIA.
243 BOOL WINAPI ChrCmpIW(WCHAR ch1, WCHAR ch2)
245 return SHLWAPI_ChrCmpHelperW(ch1, ch2, NORM_IGNORECASE);
248 /*************************************************************************
249 * StrChrA [SHLWAPI.@]
251 * Find a given character in a string.
253 * PARAMS
254 * lpszStr [I] String to search in.
255 * ch [I] Character to search for.
257 * RETURNS
258 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
259 * not found.
260 * Failure: NULL, if any arguments are invalid.
262 LPSTR WINAPI StrChrA(LPCSTR lpszStr, WORD ch)
264 TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch);
266 if (lpszStr)
268 while (*lpszStr)
270 if (!SHLWAPI_ChrCmpA(*lpszStr, ch))
271 return (LPSTR)lpszStr;
272 lpszStr = CharNextA(lpszStr);
275 return NULL;
278 /*************************************************************************
279 * StrChrW [SHLWAPI.@]
281 * See StrChrA.
283 LPWSTR WINAPI StrChrW(LPCWSTR lpszStr, WCHAR ch)
285 LPWSTR lpszRet = NULL;
287 TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch);
289 if (lpszStr)
290 lpszRet = strchrW(lpszStr, ch);
291 return lpszRet;
294 /*************************************************************************
295 * StrChrIA [SHLWAPI.@]
297 * Find a given character in a string, ignoring case.
299 * PARAMS
300 * lpszStr [I] String to search in.
301 * ch [I] Character to search for.
303 * RETURNS
304 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
305 * not found.
306 * Failure: NULL, if any arguments are invalid.
308 LPSTR WINAPI StrChrIA(LPCSTR lpszStr, WORD ch)
310 TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch);
312 if (lpszStr)
314 while (*lpszStr)
316 if (!ChrCmpIA(*lpszStr, ch))
317 return (LPSTR)lpszStr;
318 lpszStr = CharNextA(lpszStr);
321 return NULL;
324 /*************************************************************************
325 * StrChrIW [SHLWAPI.@]
327 * See StrChrA.
329 LPWSTR WINAPI StrChrIW(LPCWSTR lpszStr, WCHAR ch)
331 TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch);
333 if (lpszStr)
335 ch = toupperW(ch);
336 while (*lpszStr)
338 if (toupperW(*lpszStr) == ch)
339 return (LPWSTR)lpszStr;
340 lpszStr = CharNextW(lpszStr);
342 lpszStr = NULL;
344 return (LPWSTR)lpszStr;
347 /*************************************************************************
348 * StrCmpIW [SHLWAPI.@]
350 * Compare two strings, ignoring case.
352 * PARAMS
353 * lpszStr [I] First string to compare
354 * lpszComp [I] Second string to compare
356 * RETURNS
357 * An integer less than, equal to or greater than 0, indicating that
358 * lpszStr is less than, the same, or greater than lpszComp.
360 int WINAPI StrCmpIW(LPCWSTR lpszStr, LPCWSTR lpszComp)
362 int iRet;
364 TRACE("(%s,%s)\n", debugstr_w(lpszStr),debugstr_w(lpszComp));
366 iRet = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, lpszStr, -1, lpszComp, -1);
367 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
370 /*************************************************************************
371 * StrCmpNA [SHLWAPI.@]
373 * Compare two strings, up to a maximum length.
375 * PARAMS
376 * lpszStr [I] First string to compare
377 * lpszComp [I] Second string to compare
378 * iLen [I] Maximum number of chars to compare.
380 * RETURNS
381 * An integer less than, equal to or greater than 0, indicating that
382 * lpszStr is less than, the same, or greater than lpszComp.
384 INT WINAPI StrCmpNA(LPCSTR lpszStr, LPCSTR lpszComp, INT iLen)
386 INT iRet;
388 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
390 iRet = CompareStringA(GetThreadLocale(), 0, lpszStr, iLen, lpszComp, iLen);
391 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
394 /*************************************************************************
395 * StrCmpNW [SHLWAPI.@]
397 * See StrCmpNA.
399 INT WINAPI StrCmpNW(LPCWSTR lpszStr, LPCWSTR lpszComp, INT iLen)
401 INT iRet;
403 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen);
405 iRet = CompareStringW(GetThreadLocale(), 0, lpszStr, iLen, lpszComp, iLen);
406 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
409 /*************************************************************************
410 * StrCmpNIA [SHLWAPI.@]
412 * Compare two strings, up to a maximum length, ignoring case.
414 * PARAMS
415 * lpszStr [I] First string to compare
416 * lpszComp [I] Second string to compare
417 * iLen [I] Maximum number of chars to compare.
419 * RETURNS
420 * An integer less than, equal to or greater than 0, indicating that
421 * lpszStr is less than, the same, or greater than lpszComp.
423 int WINAPI StrCmpNIA(LPCSTR lpszStr, LPCSTR lpszComp, int iLen)
425 INT iRet;
427 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
429 iRet = CompareStringA(GetThreadLocale(), NORM_IGNORECASE, lpszStr, iLen, lpszComp, iLen);
430 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
433 /*************************************************************************
434 * StrCmpNIW [SHLWAPI.@]
436 * See StrCmpNIA.
438 INT WINAPI StrCmpNIW(LPCWSTR lpszStr, LPCWSTR lpszComp, int iLen)
440 INT iRet;
442 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen);
444 iRet = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, lpszStr, iLen, lpszComp, iLen);
445 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
448 /*************************************************************************
449 * StrCmpW [SHLWAPI.@]
451 * Compare two strings.
453 * PARAMS
454 * lpszStr [I] First string to compare
455 * lpszComp [I] Second string to compare
457 * RETURNS
458 * An integer less than, equal to or greater than 0, indicating that
459 * lpszStr is less than, the same, or greater than lpszComp.
461 int WINAPI StrCmpW(LPCWSTR lpszStr, LPCWSTR lpszComp)
463 INT iRet;
465 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszComp));
467 iRet = CompareStringW(GetThreadLocale(), 0, lpszStr, -1, lpszComp, -1);
468 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
471 /*************************************************************************
472 * StrCatW [SHLWAPI.@]
474 * Concatanate two strings.
476 * PARAMS
477 * lpszStr [O] Initial string
478 * lpszSrc [I] String to concatanate
480 * RETURNS
481 * lpszStr.
483 LPWSTR WINAPI StrCatW(LPWSTR lpszStr, LPCWSTR lpszSrc)
485 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSrc));
487 strcatW(lpszStr, lpszSrc);
488 return lpszStr;
491 /*************************************************************************
492 * StrCpyW [SHLWAPI.@]
494 * Copy a string to another string.
496 * PARAMS
497 * lpszStr [O] Destination string
498 * lpszSrc [I] Source string
500 * RETURNS
501 * lpszStr.
503 LPWSTR WINAPI StrCpyW(LPWSTR lpszStr, LPCWSTR lpszSrc)
505 TRACE("(%p,%s)\n", lpszStr, debugstr_w(lpszSrc));
507 strcpyW(lpszStr, lpszSrc);
508 return lpszStr;
511 /*************************************************************************
512 * StrCpyNW [SHLWAPI.@]
514 * Copy a string to another string, up to a maximum number of characters.
516 * PARAMS
517 * lpszStr [O] Destination string
518 * lpszSrc [I] Source string
519 * iLen [I] Maximum number of chars to copy
521 * RETURNS
522 * lpszStr.
524 LPWSTR WINAPI StrCpyNW(LPWSTR lpszStr, LPCWSTR lpszSrc, int iLen)
526 TRACE("(%p,%s,%i)\n", lpszStr, debugstr_w(lpszSrc), iLen);
528 lstrcpynW(lpszStr, lpszSrc, iLen);
529 return lpszStr;
534 /*************************************************************************
535 * SHLWAPI_StrStrHelperA
537 * Internal implementation of StrStrA/StrStrIA
539 static LPSTR WINAPI SHLWAPI_StrStrHelperA(LPCSTR lpszStr, LPCSTR lpszSearch,
540 int (*pStrCmpFn)(LPCSTR,LPCSTR,size_t))
542 size_t iLen;
544 if (!lpszStr || !lpszSearch || !*lpszSearch)
545 return NULL;
547 iLen = strlen(lpszSearch);
549 while (*lpszStr)
551 if (!pStrCmpFn(lpszStr, lpszSearch, iLen))
552 return (LPSTR)lpszStr;
553 lpszStr = CharNextA(lpszStr);
555 return NULL;
558 /*************************************************************************
559 * SHLWAPI_StrStrHelperW
561 * Internal implementation of StrStrW/StrStrIW
563 static LPWSTR WINAPI SHLWAPI_StrStrHelperW(LPCWSTR lpszStr, LPCWSTR lpszSearch,
564 int (*pStrCmpFn)(LPCWSTR,LPCWSTR,int))
566 int iLen;
568 if (!lpszStr || !lpszSearch || !*lpszSearch)
569 return NULL;
571 iLen = strlenW(lpszSearch);
573 while (*lpszStr)
575 if (!pStrCmpFn(lpszStr, lpszSearch, iLen))
576 return (LPWSTR)lpszStr;
577 lpszStr = CharNextW(lpszStr);
579 return NULL;
582 /*************************************************************************
583 * StrStrA [SHLWAPI.@]
585 * Find a substring within a string.
587 * PARAMS
588 * lpszStr [I] String to search in
589 * lpszSearch [I] String to look for
591 * RETURNS
592 * The start of lpszSearch within lpszStr, or NULL if not found.
594 LPSTR WINAPI StrStrA(LPCSTR lpszStr, LPCSTR lpszSearch)
596 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
598 return SHLWAPI_StrStrHelperA(lpszStr, lpszSearch, strncmp);
601 /*************************************************************************
602 * StrStrW [SHLWAPI.@]
604 * See StrStrA.
606 LPWSTR WINAPI StrStrW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
608 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
610 return SHLWAPI_StrStrHelperW(lpszStr, lpszSearch, strncmpW);
613 /*************************************************************************
614 * StrRStrIA [SHLWAPI.@]
616 * Find the last occurrence of a substring within a string.
618 * PARAMS
619 * lpszStr [I] String to search in
620 * lpszEnd [I] End of lpszStr
621 * lpszSearch [I] String to look for
623 * RETURNS
624 * The last occurrence lpszSearch within lpszStr, or NULL if not found.
626 LPSTR WINAPI StrRStrIA(LPCSTR lpszStr, LPCSTR lpszEnd, LPCSTR lpszSearch)
628 WORD ch1, ch2;
629 INT iLen;
631 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
633 if (!lpszStr || !lpszSearch || !*lpszSearch)
634 return NULL;
636 if (!lpszEnd)
637 lpszEnd = lpszStr + lstrlenA(lpszStr);
638 if (lpszEnd == lpszStr)
639 return NULL;
641 if (IsDBCSLeadByte(*lpszSearch))
642 ch1 = *lpszSearch << 8 | (UCHAR)lpszSearch[1];
643 else
644 ch1 = *lpszSearch;
645 iLen = lstrlenA(lpszSearch);
649 lpszEnd = CharPrevA(lpszStr, lpszEnd);
650 ch2 = IsDBCSLeadByte(*lpszEnd)? *lpszEnd << 8 | (UCHAR)lpszEnd[1] : *lpszEnd;
651 if (!ChrCmpIA(ch1, ch2))
653 if (!StrCmpNIA(lpszEnd, lpszSearch, iLen))
654 return (LPSTR)lpszEnd;
656 } while (lpszEnd > lpszStr);
657 return NULL;
660 /*************************************************************************
661 * StrRStrIW [SHLWAPI.@]
663 * See StrRStrIA.
665 LPWSTR WINAPI StrRStrIW(LPCWSTR lpszStr, LPCWSTR lpszEnd, LPCWSTR lpszSearch)
667 INT iLen;
669 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
671 if (!lpszStr || !lpszSearch || !*lpszSearch)
672 return NULL;
674 if (!lpszEnd)
675 lpszEnd = lpszStr + strlenW(lpszStr);
676 if (lpszEnd == lpszStr)
677 return NULL;
679 iLen = strlenW(lpszSearch);
683 lpszEnd = CharPrevW(lpszStr, lpszEnd);
684 if (!ChrCmpIW(*lpszSearch, *lpszEnd))
686 if (!StrCmpNIW(lpszEnd, lpszSearch, iLen))
687 return (LPWSTR)lpszEnd;
689 } while (lpszEnd > lpszStr);
690 return NULL;
693 /*************************************************************************
694 * StrStrIA [SHLWAPI.@]
696 * Find a substring within a string, ignoring case.
698 * PARAMS
699 * lpszStr [I] String to search in
700 * lpszSearch [I] String to look for
702 * RETURNS
703 * The start of lpszSearch within lpszStr, or NULL if not found.
705 LPSTR WINAPI StrStrIA(LPCSTR lpszStr, LPCSTR lpszSearch)
707 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
709 return SHLWAPI_StrStrHelperA(lpszStr, lpszSearch, strncasecmp);
712 /*************************************************************************
713 * StrStrIW [SHLWAPI.@]
715 * See StrStrIA.
717 LPWSTR WINAPI StrStrIW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
719 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
721 return SHLWAPI_StrStrHelperW(lpszStr, lpszSearch, strncmpiW);
724 /*************************************************************************
725 * StrToIntA [SHLWAPI.@]
727 * Read a signed integer from a string.
729 * PARAMS
730 * lpszStr [I] String to read integer from
732 * RETURNS
733 * The signed integer value represented by the string, or 0 if no integer is
734 * present.
736 * NOTES
737 * No leading space is allowed before the number, although a leading '-' is.
739 int WINAPI StrToIntA(LPCSTR lpszStr)
741 int iRet = 0;
743 TRACE("(%s)\n", debugstr_a(lpszStr));
745 if (!lpszStr)
747 WARN("Invalid lpszStr would crash under Win32!\n");
748 return 0;
751 if (*lpszStr == '-' || isdigit(*lpszStr))
752 StrToIntExA(lpszStr, 0, &iRet);
753 return iRet;
756 /*************************************************************************
757 * StrToIntW [SHLWAPI.@]
759 * See StrToIntA.
761 int WINAPI StrToIntW(LPCWSTR lpszStr)
763 int iRet = 0;
765 TRACE("(%s)\n", debugstr_w(lpszStr));
767 if (!lpszStr)
769 WARN("Invalid lpszStr would crash under Win32!\n");
770 return 0;
773 if (*lpszStr == '-' || isdigitW(*lpszStr))
774 StrToIntExW(lpszStr, 0, &iRet);
775 return iRet;
778 /*************************************************************************
779 * StrToIntExA [SHLWAPI.@]
781 * Read an integer from a string.
783 * PARAMS
784 * lpszStr [I] String to read integer from
785 * dwFlags [I] Flags controlling the conversion
786 * lpiRet [O] Destination for read integer.
788 * RETURNS
789 * Success: TRUE. lpiRet contains the integer value represented by the string.
790 * Failure: FALSE, if the string is invalid, or no number is present.
792 * NOTES
793 * Leading whitespace, '-' and '+' are allowed before the number. If
794 * dwFlags includes STIF_SUPPORT_HEX, hexadecimal numbers are allowed, if
795 * preceded by '0x'. If this flag is not set, or there is no '0x' prefix,
796 * the string is treated as a decimal string. A leading '-' is ignored for
797 * hexadecimal numbers.
799 BOOL WINAPI StrToIntExA(LPCSTR lpszStr, DWORD dwFlags, LPINT lpiRet)
801 BOOL bNegative = FALSE;
802 int iRet = 0;
804 TRACE("(%s,%08X,%p)\n", debugstr_a(lpszStr), dwFlags, lpiRet);
806 if (!lpszStr || !lpiRet)
808 WARN("Invalid parameter would crash under Win32!\n");
809 return FALSE;
811 if (dwFlags > STIF_SUPPORT_HEX)
813 WARN("Unknown flags (%08lX)!\n", dwFlags & ~STIF_SUPPORT_HEX);
816 /* Skip leading space, '+', '-' */
817 while (isspace(*lpszStr))
818 lpszStr = CharNextA(lpszStr);
820 if (*lpszStr == '-')
822 bNegative = TRUE;
823 lpszStr++;
825 else if (*lpszStr == '+')
826 lpszStr++;
828 if (dwFlags & STIF_SUPPORT_HEX &&
829 *lpszStr == '0' && tolower(lpszStr[1]) == 'x')
831 /* Read hex number */
832 lpszStr += 2;
834 if (!isxdigit(*lpszStr))
835 return FALSE;
837 while (isxdigit(*lpszStr))
839 iRet = iRet * 16;
840 if (isdigit(*lpszStr))
841 iRet += (*lpszStr - '0');
842 else
843 iRet += 10 + (tolower(*lpszStr) - 'a');
844 lpszStr++;
846 *lpiRet = iRet;
847 return TRUE;
850 /* Read decimal number */
851 if (!isdigit(*lpszStr))
852 return FALSE;
854 while (isdigit(*lpszStr))
856 iRet = iRet * 10;
857 iRet += (*lpszStr - '0');
858 lpszStr++;
860 *lpiRet = bNegative ? -iRet : iRet;
861 return TRUE;
864 /*************************************************************************
865 * StrToIntExW [SHLWAPI.@]
867 * See StrToIntExA.
869 BOOL WINAPI StrToIntExW(LPCWSTR lpszStr, DWORD dwFlags, LPINT lpiRet)
871 BOOL bNegative = FALSE;
872 int iRet = 0;
874 TRACE("(%s,%08X,%p)\n", debugstr_w(lpszStr), dwFlags, lpiRet);
876 if (!lpszStr || !lpiRet)
878 WARN("Invalid parameter would crash under Win32!\n");
879 return FALSE;
881 if (dwFlags > STIF_SUPPORT_HEX)
883 WARN("Unknown flags (%08lX)!\n", dwFlags & ~STIF_SUPPORT_HEX);
886 /* Skip leading space, '+', '-' */
887 while (isspaceW(*lpszStr))
888 lpszStr = CharNextW(lpszStr);
890 if (*lpszStr == '-')
892 bNegative = TRUE;
893 lpszStr++;
895 else if (*lpszStr == '+')
896 lpszStr++;
898 if (dwFlags & STIF_SUPPORT_HEX &&
899 *lpszStr == '0' && tolowerW(lpszStr[1]) == 'x')
901 /* Read hex number */
902 lpszStr += 2;
904 if (!isxdigitW(*lpszStr))
905 return FALSE;
907 while (isxdigitW(*lpszStr))
909 iRet = iRet * 16;
910 if (isdigitW(*lpszStr))
911 iRet += (*lpszStr - '0');
912 else
913 iRet += 10 + (tolowerW(*lpszStr) - 'a');
914 lpszStr++;
916 *lpiRet = iRet;
917 return TRUE;
920 /* Read decimal number */
921 if (!isdigitW(*lpszStr))
922 return FALSE;
924 while (isdigitW(*lpszStr))
926 iRet = iRet * 10;
927 iRet += (*lpszStr - '0');
928 lpszStr++;
930 *lpiRet = bNegative ? -iRet : iRet;
931 return TRUE;
934 /*************************************************************************
935 * StrDupA [SHLWAPI.@]
937 * Duplicate a string.
939 * PARAMS
940 * lpszStr [I] String to duplicate.
942 * RETURNS
943 * Success: A pointer to a new string containing the contents of lpszStr
944 * Failure: NULL, if memory cannot be allocated
946 * NOTES
947 * The string memory is allocated with LocalAlloc(), and so should be released
948 * by calling LocalFree().
950 LPSTR WINAPI StrDupA(LPCSTR lpszStr)
952 int iLen;
953 LPSTR lpszRet;
955 TRACE("(%s)\n",debugstr_a(lpszStr));
957 iLen = lpszStr ? strlen(lpszStr) + 1 : 1;
958 lpszRet = (LPSTR)LocalAlloc(LMEM_FIXED, iLen);
960 if (lpszRet)
962 if (lpszStr)
963 memcpy(lpszRet, lpszStr, iLen);
964 else
965 *lpszRet = '\0';
967 return lpszRet;
970 /*************************************************************************
971 * StrDupW [SHLWAPI.@]
973 * See StrDupA.
975 LPWSTR WINAPI StrDupW(LPCWSTR lpszStr)
977 int iLen;
978 LPWSTR lpszRet;
980 TRACE("(%s)\n",debugstr_w(lpszStr));
982 iLen = (lpszStr ? strlenW(lpszStr) + 1 : 1) * sizeof(WCHAR);
983 lpszRet = (LPWSTR)LocalAlloc(LMEM_FIXED, iLen);
985 if (lpszRet)
987 if (lpszStr)
988 memcpy(lpszRet, lpszStr, iLen);
989 else
990 *lpszRet = '\0';
992 return lpszRet;
995 /*************************************************************************
996 * SHLWAPI_StrSpnHelperA
998 * Internal implementation of StrSpnA/StrCSpnA/StrCSpnIA
1000 static int WINAPI SHLWAPI_StrSpnHelperA(LPCSTR lpszStr, LPCSTR lpszMatch,
1001 LPSTR (WINAPI *pStrChrFn)(LPCSTR,WORD),
1002 BOOL bInvert)
1004 LPCSTR lpszRead = lpszStr;
1005 if (lpszStr && *lpszStr && lpszMatch)
1007 while (*lpszRead)
1009 LPCSTR lpszTest = pStrChrFn(lpszMatch, *lpszRead);
1011 if (!bInvert && !lpszTest)
1012 break;
1013 if (bInvert && lpszTest)
1014 break;
1015 lpszRead = CharNextA(lpszRead);
1018 return lpszRead - lpszStr;
1021 /*************************************************************************
1022 * SHLWAPI_StrSpnHelperW
1024 * Internal implementation of StrSpnW/StrCSpnW/StrCSpnIW
1026 static int WINAPI SHLWAPI_StrSpnHelperW(LPCWSTR lpszStr, LPCWSTR lpszMatch,
1027 LPWSTR (WINAPI *pStrChrFn)(LPCWSTR,WCHAR),
1028 BOOL bInvert)
1030 LPCWSTR lpszRead = lpszStr;
1031 if (lpszStr && *lpszStr && lpszMatch)
1033 while (*lpszRead)
1035 LPCWSTR lpszTest = pStrChrFn(lpszMatch, *lpszRead);
1037 if (!bInvert && !lpszTest)
1038 break;
1039 if (bInvert && lpszTest)
1040 break;
1041 lpszRead = CharNextW(lpszRead);
1044 return lpszRead - lpszStr;
1047 /*************************************************************************
1048 * StrSpnA [SHLWAPI.@]
1050 * Find the length of the start of a string that contains only certain
1051 * characters.
1053 * PARAMS
1054 * lpszStr [I] String to search
1055 * lpszMatch [I] Characters that can be in the substring
1057 * RETURNS
1058 * The length of the part of lpszStr containing only chars from lpszMatch,
1059 * or 0 if any parameter is invalid.
1061 int WINAPI StrSpnA(LPCSTR lpszStr, LPCSTR lpszMatch)
1063 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1065 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, FALSE);
1068 /*************************************************************************
1069 * StrSpnW [SHLWAPI.@]
1071 * See StrSpnA.
1073 int WINAPI StrSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1075 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1077 return SHLWAPI_StrSpnHelperW(lpszStr, lpszMatch, StrChrW, FALSE);
1080 /*************************************************************************
1081 * StrCSpnA [SHLWAPI.@]
1083 * Find the length of the start of a string that does not contain certain
1084 * characters.
1086 * PARAMS
1087 * lpszStr [I] String to search
1088 * lpszMatch [I] Characters that cannot be in the substring
1090 * RETURNS
1091 * The length of the part of lpszStr containing only chars not in lpszMatch,
1092 * or 0 if any parameter is invalid.
1094 int WINAPI StrCSpnA(LPCSTR lpszStr, LPCSTR lpszMatch)
1096 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1098 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, TRUE);
1101 /*************************************************************************
1102 * StrCSpnW [SHLWAPI.@]
1104 * See StrCSpnA.
1106 int WINAPI StrCSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1108 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1110 return SHLWAPI_StrSpnHelperW(lpszStr, lpszMatch, StrChrW, TRUE);
1113 /*************************************************************************
1114 * StrCSpnIA [SHLWAPI.@]
1116 * Find the length of the start of a string that does not contain certain
1117 * characters, ignoring case.
1119 * PARAMS
1120 * lpszStr [I] String to search
1121 * lpszMatch [I] Characters that cannot be in the substring
1123 * RETURNS
1124 * The length of the part of lpszStr containing only chars not in lpszMatch,
1125 * or 0 if any parameter is invalid.
1127 int WINAPI StrCSpnIA(LPCSTR lpszStr, LPCSTR lpszMatch)
1129 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1131 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrIA, TRUE);
1134 /*************************************************************************
1135 * StrCSpnIW [SHLWAPI.@]
1137 * See StrCSpnIA.
1139 int WINAPI StrCSpnIW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1141 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1143 return SHLWAPI_StrSpnHelperW(lpszStr, lpszMatch, StrChrIW, TRUE);
1146 /*************************************************************************
1147 * StrPBrkA [SHLWAPI.@]
1149 * Search a string for any of a group of characters.
1151 * PARAMS
1152 * lpszStr [I] String to search
1153 * lpszMatch [I] Characters to match
1155 * RETURNS
1156 * A pointer to the first matching character in lpszStr, or NULL if no
1157 * match was found.
1159 LPSTR WINAPI StrPBrkA(LPCSTR lpszStr, LPCSTR lpszMatch)
1161 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1163 if (lpszStr && lpszMatch && *lpszMatch)
1165 while (*lpszStr)
1167 if (StrChrA(lpszMatch, *lpszStr))
1168 return (LPSTR)lpszStr;
1169 lpszStr = CharNextA(lpszStr);
1172 return NULL;
1175 /*************************************************************************
1176 * StrPBrkW [SHLWAPI.@]
1178 * See StrPBrkA.
1180 LPWSTR WINAPI StrPBrkW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1182 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1184 if (lpszStr && lpszMatch && *lpszMatch)
1186 while (*lpszStr)
1188 if (StrChrW(lpszMatch, *lpszStr))
1189 return (LPWSTR)lpszStr;
1190 lpszStr = CharNextW(lpszStr);
1193 return NULL;
1196 /*************************************************************************
1197 * SHLWAPI_StrRChrHelperA
1199 * Internal implementation of StrRChrA/StrRChrIA.
1201 static LPSTR WINAPI SHLWAPI_StrRChrHelperA(LPCSTR lpszStr,
1202 LPCSTR lpszEnd, WORD ch,
1203 BOOL (WINAPI *pChrCmpFn)(WORD,WORD))
1205 LPCSTR lpszRet = NULL;
1207 if (lpszStr)
1209 WORD ch2;
1211 if (!lpszEnd)
1212 lpszEnd = lpszStr + lstrlenA(lpszStr);
1214 while (*lpszStr && lpszStr <= lpszEnd)
1216 ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr;
1218 if (!pChrCmpFn(ch, ch2))
1219 lpszRet = lpszStr;
1220 lpszStr = CharNextA(lpszStr);
1223 return (LPSTR)lpszRet;
1226 /*************************************************************************
1227 * SHLWAPI_StrRChrHelperW
1229 * Internal implementation of StrRChrW/StrRChrIW.
1231 static LPWSTR WINAPI SHLWAPI_StrRChrHelperW(LPCWSTR lpszStr,
1232 LPCWSTR lpszEnd, WCHAR ch,
1233 BOOL (WINAPI *pChrCmpFn)(WCHAR,WCHAR))
1235 LPCWSTR lpszRet = NULL;
1237 if (lpszStr)
1239 if (!lpszEnd)
1240 lpszEnd = lpszStr + strlenW(lpszStr);
1242 while (*lpszStr && lpszStr <= lpszEnd)
1244 if (!pChrCmpFn(ch, *lpszStr))
1245 lpszRet = lpszStr;
1246 lpszStr = CharNextW(lpszStr);
1249 return (LPWSTR)lpszRet;
1252 /**************************************************************************
1253 * StrRChrA [SHLWAPI.@]
1255 * Find the last occurrence of a character in string.
1257 * PARAMS
1258 * lpszStr [I] String to search in
1259 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1260 * ch [I] Character to search for.
1262 * RETURNS
1263 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1264 * or NULL if not found.
1265 * Failure: NULL, if any arguments are invalid.
1267 LPSTR WINAPI StrRChrA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch)
1269 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch);
1271 return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, SHLWAPI_ChrCmpA);
1274 /**************************************************************************
1275 * StrRChrW [SHLWAPI.@]
1277 * See StrRChrA.
1279 LPWSTR WINAPI StrRChrW(LPCWSTR lpszStr, LPCWSTR lpszEnd, WORD ch)
1281 TRACE("(%s,%s,%x)\n", debugstr_w(lpszStr), debugstr_w(lpszEnd), ch);
1283 return SHLWAPI_StrRChrHelperW(lpszStr, lpszEnd, ch, SHLWAPI_ChrCmpW);
1286 /**************************************************************************
1287 * StrRChrIA [SHLWAPI.@]
1289 * Find the last occurrence of a character in string, ignoring case.
1291 * PARAMS
1292 * lpszStr [I] String to search in
1293 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1294 * ch [I] Character to search for.
1296 * RETURNS
1297 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1298 * or NULL if not found.
1299 * Failure: NULL, if any arguments are invalid.
1301 LPSTR WINAPI StrRChrIA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch)
1303 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch);
1305 return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, ChrCmpIA);
1308 /**************************************************************************
1309 * StrRChrIW [SHLWAPI.@]
1311 * See StrRChrIA.
1313 LPWSTR WINAPI StrRChrIW(LPCWSTR lpszStr, LPCWSTR lpszEnd, WORD ch)
1315 TRACE("(%s,%s,%x)\n", debugstr_w(lpszStr), debugstr_w(lpszEnd), ch);
1317 return SHLWAPI_StrRChrHelperW(lpszStr, lpszEnd, ch, ChrCmpIW);
1320 /*************************************************************************
1321 * StrCatBuffA [SHLWAPI.@]
1323 * Concatenate two strings together.
1325 * PARAMS
1326 * lpszStr [O] String to concatenate to
1327 * lpszCat [I] String to add to lpszCat
1328 * cchMax [I] Maximum number of characters for the whole string
1330 * RETURNS
1331 * lpszStr.
1333 * NOTES
1334 * cchMax determines the number of characters in the final length of the
1335 * string, not the number appended to lpszStr from lpszCat.
1337 LPSTR WINAPI StrCatBuffA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax)
1339 INT iLen;
1341 TRACE("(%p,%s,%d)\n", lpszStr, debugstr_a(lpszCat), cchMax);
1343 if (!lpszStr)
1345 WARN("Invalid lpszStr would crash under Win32!\n");
1346 return NULL;
1349 iLen = strlen(lpszStr);
1350 cchMax -= iLen;
1352 if (cchMax > 0)
1353 StrCpyNA(lpszStr + iLen, lpszCat, cchMax);
1354 return lpszStr;
1357 /*************************************************************************
1358 * StrCatBuffW [SHLWAPI.@]
1360 * See StrCatBuffA.
1362 LPWSTR WINAPI StrCatBuffW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax)
1364 INT iLen;
1366 TRACE("(%p,%s,%d)\n", lpszStr, debugstr_w(lpszCat), cchMax);
1368 if (!lpszStr)
1370 WARN("Invalid lpszStr would crash under Win32!\n");
1371 return NULL;
1374 iLen = strlenW(lpszStr);
1375 cchMax -= iLen;
1377 if (cchMax > 0)
1378 StrCpyNW(lpszStr + iLen, lpszCat, cchMax);
1379 return lpszStr;
1382 /*************************************************************************
1383 * StrRetToBufA [SHLWAPI.@]
1385 * Convert a STRRET to a normal string.
1387 * PARAMS
1388 * lpStrRet [O] STRRET to convert
1389 * pIdl [I] ITEMIDLIST for lpStrRet->uType == STRRET_OFFSET
1390 * lpszDest [O] Destination for normal string
1391 * dwLen [I] Length of lpszDest
1393 * RETURNS
1394 * Success: S_OK. lpszDest contains up to dwLen characters of the string.
1395 * If lpStrRet is of type STRRET_WSTR, its memory is freed with
1396 * CoTaskMemFree() and its type set to STRRET_CSTRA.
1397 * Failure: E_FAIL, if any parameters are invalid.
1399 HRESULT WINAPI StrRetToBufA (LPSTRRET src, const ITEMIDLIST *pidl, LPSTR dest, UINT len)
1401 /* NOTE:
1402 * This routine is identical to that in dlls/shell32/shellstring.c.
1403 * It was duplicated because not every version of Shlwapi.dll exports
1404 * StrRetToBufA. If you change one routine, change them both.
1406 TRACE("dest=%p len=0x%x strret=%p pidl=%p stub\n",dest,len,src,pidl);
1408 if (!src)
1410 WARN("Invalid lpStrRet would crash under Win32!\n");
1411 if (dest)
1412 *dest = '\0';
1413 return E_FAIL;
1416 if (!dest || !len)
1417 return E_FAIL;
1419 *dest = '\0';
1421 switch (src->uType)
1423 case STRRET_WSTR:
1424 WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, dest, len, NULL, NULL);
1425 CoTaskMemFree(src->u.pOleStr);
1426 break;
1428 case STRRET_CSTR:
1429 lstrcpynA((LPSTR)dest, src->u.cStr, len);
1430 break;
1432 case STRRET_OFFSET:
1433 lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len);
1434 break;
1436 default:
1437 FIXME("unknown type!\n");
1438 return FALSE;
1440 return S_OK;
1443 /*************************************************************************
1444 * StrRetToBufW [SHLWAPI.@]
1446 * See StrRetToBufA.
1448 HRESULT WINAPI StrRetToBufW (LPSTRRET src, const ITEMIDLIST *pidl, LPWSTR dest, UINT len)
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 lstrcpynW((LPWSTR)dest, src->u.pOleStr, len);
1469 CoTaskMemFree(src->u.pOleStr);
1470 break;
1472 case STRRET_CSTR:
1473 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
1474 dest[len-1] = 0;
1475 break;
1477 case STRRET_OFFSET:
1478 if (pidl)
1480 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1,
1481 dest, len ) && len)
1482 dest[len-1] = 0;
1484 break;
1486 default:
1487 FIXME("unknown type!\n");
1488 return FALSE;
1490 return S_OK;
1493 /*************************************************************************
1494 * StrRetToStrA [SHLWAPI.@]
1496 * Converts a STRRET to a normal string.
1498 * PARAMS
1499 * lpStrRet [O] STRRET to convert
1500 * pidl [I] ITEMIDLIST for lpStrRet->uType == STRRET_OFFSET
1501 * ppszName [O] Destination for converted string
1503 * RETURNS
1504 * Success: S_OK. ppszName contains the new string, allocated with CoTaskMemAlloc().
1505 * Failure: E_FAIL, if any parameters are invalid.
1507 HRESULT WINAPI StrRetToStrA(LPSTRRET lpStrRet, const ITEMIDLIST *pidl, LPSTR *ppszName)
1509 HRESULT hRet = E_FAIL;
1511 switch (lpStrRet->uType)
1513 case STRRET_WSTR:
1514 hRet = _SHStrDupAW(lpStrRet->u.pOleStr, ppszName);
1515 CoTaskMemFree(lpStrRet->u.pOleStr);
1516 break;
1518 case STRRET_CSTR:
1519 hRet = _SHStrDupAA(lpStrRet->u.cStr, ppszName);
1520 break;
1522 case STRRET_OFFSET:
1523 hRet = _SHStrDupAA(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, ppszName);
1524 break;
1526 default:
1527 *ppszName = NULL;
1530 return hRet;
1533 /*************************************************************************
1534 * StrRetToStrW [SHLWAPI.@]
1536 * See StrRetToStrA.
1538 HRESULT WINAPI StrRetToStrW(LPSTRRET lpStrRet, const ITEMIDLIST *pidl, LPWSTR *ppszName)
1540 HRESULT hRet = E_FAIL;
1542 switch (lpStrRet->uType)
1544 case STRRET_WSTR:
1545 hRet = SHStrDupW(lpStrRet->u.pOleStr, ppszName);
1546 CoTaskMemFree(lpStrRet->u.pOleStr);
1547 break;
1549 case STRRET_CSTR:
1550 hRet = SHStrDupA(lpStrRet->u.cStr, ppszName);
1551 break;
1553 case STRRET_OFFSET:
1554 hRet = SHStrDupA(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, ppszName);
1555 break;
1557 default:
1558 *ppszName = NULL;
1561 return hRet;
1564 /* Create an ASCII string copy using SysAllocString() */
1565 static HRESULT _SHStrDupAToBSTR(LPCSTR src, BSTR *pBstrOut)
1567 *pBstrOut = NULL;
1569 if (src)
1571 INT len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0);
1572 WCHAR* szTemp = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1574 if (szTemp)
1576 MultiByteToWideChar(CP_ACP, 0, src, -1, szTemp, len);
1577 *pBstrOut = SysAllocString(szTemp);
1578 HeapFree(GetProcessHeap(), 0, szTemp);
1580 if (*pBstrOut)
1581 return S_OK;
1584 return E_OUTOFMEMORY;
1587 /*************************************************************************
1588 * StrRetToBSTR [SHLWAPI.@]
1590 * Converts a STRRET to a BSTR.
1592 * PARAMS
1593 * lpStrRet [O] STRRET to convert
1594 * pidl [I] ITEMIDLIST for lpStrRet->uType = STRRET_OFFSET
1595 * pBstrOut [O] Destination for converted BSTR
1597 * RETURNS
1598 * Success: S_OK. pBstrOut contains the new string.
1599 * Failure: E_FAIL, if any parameters are invalid.
1601 HRESULT WINAPI StrRetToBSTR(STRRET *lpStrRet, LPCITEMIDLIST pidl, BSTR* pBstrOut)
1603 HRESULT hRet = E_FAIL;
1605 switch (lpStrRet->uType)
1607 case STRRET_WSTR:
1608 *pBstrOut = SysAllocString(lpStrRet->u.pOleStr);
1609 if (*pBstrOut)
1610 hRet = S_OK;
1611 CoTaskMemFree(lpStrRet->u.pOleStr);
1612 break;
1614 case STRRET_CSTR:
1615 hRet = _SHStrDupAToBSTR(lpStrRet->u.cStr, pBstrOut);
1616 break;
1618 case STRRET_OFFSET:
1619 hRet = _SHStrDupAToBSTR(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, pBstrOut);
1620 break;
1622 default:
1623 *pBstrOut = NULL;
1626 return hRet;
1629 /*************************************************************************
1630 * StrFormatKBSizeA [SHLWAPI.@]
1632 * Create a formatted string containing a byte count in Kilobytes.
1634 * PARAMS
1635 * llBytes [I] Byte size to format
1636 * lpszDest [I] Destination for formatted string
1637 * cchMax [I] Size of lpszDest
1639 * RETURNS
1640 * lpszDest.
1642 LPSTR WINAPI StrFormatKBSizeA(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax)
1644 WCHAR wszBuf[256];
1646 if (!StrFormatKBSizeW(llBytes, wszBuf, 256))
1647 return NULL;
1648 if (!WideCharToMultiByte(CP_ACP, 0, wszBuf, -1, lpszDest, cchMax, NULL, NULL))
1649 return NULL;
1650 return lpszDest;
1653 /*************************************************************************
1654 * StrFormatKBSizeW [SHLWAPI.@]
1656 * See StrFormatKBSizeA.
1658 LPWSTR WINAPI StrFormatKBSizeW(LONGLONG llBytes, LPWSTR lpszDest, UINT cchMax)
1660 static const WCHAR kb[] = {' ','K','B',0};
1661 LONGLONG llKB = (llBytes + 1023) >> 10;
1662 int len;
1664 TRACE("(0x%s,%p,%d)\n", wine_dbgstr_longlong(llBytes), lpszDest, cchMax);
1666 if (!FormatInt(llKB, lpszDest, cchMax))
1667 return NULL;
1669 len = lstrlenW(lpszDest);
1670 if (cchMax - len < 4)
1671 return NULL;
1672 lstrcatW(lpszDest, kb);
1673 return lpszDest;
1676 /*************************************************************************
1677 * StrNCatA [SHLWAPI.@]
1679 * Concatenate two strings together.
1681 * PARAMS
1682 * lpszStr [O] String to concatenate to
1683 * lpszCat [I] String to add to lpszCat
1684 * cchMax [I] Maximum number of characters to concatenate
1686 * RETURNS
1687 * lpszStr.
1689 * NOTES
1690 * cchMax determines the number of characters that are appended to lpszStr,
1691 * not the total length of the string.
1693 LPSTR WINAPI StrNCatA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax)
1695 LPSTR lpszRet = lpszStr;
1697 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszCat), cchMax);
1699 if (!lpszStr)
1701 WARN("Invalid lpszStr would crash under Win32!\n");
1702 return NULL;
1705 StrCpyNA(lpszStr + strlen(lpszStr), lpszCat, cchMax);
1706 return lpszRet;
1709 /*************************************************************************
1710 * StrNCatW [SHLWAPI.@]
1712 * See StrNCatA.
1714 LPWSTR WINAPI StrNCatW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax)
1716 LPWSTR lpszRet = lpszStr;
1718 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszCat), cchMax);
1720 if (!lpszStr)
1722 WARN("Invalid lpszStr would crash under Win32\n");
1723 return NULL;
1726 StrCpyNW(lpszStr + strlenW(lpszStr), lpszCat, cchMax);
1727 return lpszRet;
1730 /*************************************************************************
1731 * StrTrimA [SHLWAPI.@]
1733 * Remove characters from the start and end of a string.
1735 * PARAMS
1736 * lpszStr [O] String to remove characters from
1737 * lpszTrim [I] Characters to remove from lpszStr
1739 * RETURNS
1740 * TRUE If lpszStr was valid and modified
1741 * FALSE Otherwise
1743 BOOL WINAPI StrTrimA(LPSTR lpszStr, LPCSTR lpszTrim)
1745 DWORD dwLen;
1746 LPSTR lpszRead = lpszStr;
1747 BOOL bRet = FALSE;
1749 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszTrim));
1751 if (lpszRead && *lpszRead)
1753 while (*lpszRead && StrChrA(lpszTrim, *lpszRead))
1754 lpszRead = CharNextA(lpszRead); /* Skip leading matches */
1756 dwLen = strlen(lpszRead);
1758 if (lpszRead != lpszStr)
1760 memmove(lpszStr, lpszRead, dwLen + 1);
1761 bRet = TRUE;
1763 if (dwLen > 0)
1765 lpszRead = lpszStr + dwLen;
1766 while (StrChrA(lpszTrim, lpszRead[-1]))
1767 lpszRead = CharPrevA(lpszStr, lpszRead); /* Skip trailing matches */
1769 if (lpszRead != lpszStr + dwLen)
1771 *lpszRead = '\0';
1772 bRet = TRUE;
1776 return bRet;
1779 /*************************************************************************
1780 * StrTrimW [SHLWAPI.@]
1782 * See StrTrimA.
1784 BOOL WINAPI StrTrimW(LPWSTR lpszStr, LPCWSTR lpszTrim)
1786 DWORD dwLen;
1787 LPWSTR lpszRead = lpszStr;
1788 BOOL bRet = FALSE;
1790 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszTrim));
1792 if (lpszRead && *lpszRead)
1794 while (*lpszRead && StrChrW(lpszTrim, *lpszRead))
1795 lpszRead = CharNextW(lpszRead); /* Skip leading matches */
1797 dwLen = strlenW(lpszRead);
1799 if (lpszRead != lpszStr)
1801 memmove(lpszStr, lpszRead, (dwLen + 1) * sizeof(WCHAR));
1802 bRet = TRUE;
1804 if (dwLen > 0)
1806 lpszRead = lpszStr + dwLen;
1807 while (StrChrW(lpszTrim, lpszRead[-1]))
1808 lpszRead = CharPrevW(lpszStr, lpszRead); /* Skip trailing matches */
1810 if (lpszRead != lpszStr + dwLen)
1812 *lpszRead = '\0';
1813 bRet = TRUE;
1817 return bRet;
1820 /*************************************************************************
1821 * _SHStrDupAA [INTERNAL]
1823 * Duplicates a ASCII string to ASCII. The destination buffer is allocated.
1825 static HRESULT WINAPI _SHStrDupAA(LPCSTR src, LPSTR * dest)
1827 HRESULT hr;
1828 int len = 0;
1830 if (src) {
1831 len = lstrlenA(src) + 1;
1832 *dest = CoTaskMemAlloc(len);
1833 } else {
1834 *dest = NULL;
1837 if (*dest) {
1838 lstrcpynA(*dest,src, len);
1839 hr = S_OK;
1840 } else {
1841 hr = E_OUTOFMEMORY;
1844 TRACE("%s->(%p)\n", debugstr_a(src), *dest);
1845 return hr;
1848 /*************************************************************************
1849 * SHStrDupA [SHLWAPI.@]
1851 * Return a Unicode copy of a string, in memory allocated by CoTaskMemAlloc().
1853 * PARAMS
1854 * lpszStr [I] String to copy
1855 * lppszDest [O] Destination for the new string copy
1857 * RETURNS
1858 * Success: S_OK. lppszDest contains the new string in Unicode format.
1859 * Failure: E_OUTOFMEMORY, If any arguments are invalid or memory allocation
1860 * fails.
1862 HRESULT WINAPI SHStrDupA(LPCSTR lpszStr, LPWSTR * lppszDest)
1864 HRESULT hRet;
1865 int len = 0;
1867 if (lpszStr)
1869 len = MultiByteToWideChar(0, 0, lpszStr, -1, 0, 0) * sizeof(WCHAR);
1870 *lppszDest = CoTaskMemAlloc(len);
1872 else
1873 *lppszDest = NULL;
1875 if (*lppszDest)
1877 MultiByteToWideChar(0, 0, lpszStr, -1, *lppszDest, len/sizeof(WCHAR));
1878 hRet = S_OK;
1880 else
1881 hRet = E_OUTOFMEMORY;
1883 TRACE("%s->(%p)\n", debugstr_a(lpszStr), *lppszDest);
1884 return hRet;
1887 /*************************************************************************
1888 * _SHStrDupAW [INTERNAL]
1890 * Duplicates a UNICODE to a ASCII string. The destination buffer is allocated.
1892 static HRESULT WINAPI _SHStrDupAW(LPCWSTR src, LPSTR * dest)
1894 HRESULT hr;
1895 int len = 0;
1897 if (src) {
1898 len = WideCharToMultiByte(CP_ACP, 0, src, -1, NULL, 0, NULL, NULL);
1899 *dest = CoTaskMemAlloc(len);
1900 } else {
1901 *dest = NULL;
1904 if (*dest) {
1905 WideCharToMultiByte(CP_ACP, 0, src, -1, *dest, len, NULL, NULL);
1906 hr = S_OK;
1907 } else {
1908 hr = E_OUTOFMEMORY;
1911 TRACE("%s->(%p)\n", debugstr_w(src), *dest);
1912 return hr;
1915 /*************************************************************************
1916 * SHStrDupW [SHLWAPI.@]
1918 * See SHStrDupA.
1920 HRESULT WINAPI SHStrDupW(LPCWSTR src, LPWSTR * dest)
1922 HRESULT hr;
1923 int len = 0;
1925 if (src) {
1926 len = (lstrlenW(src) + 1) * sizeof(WCHAR);
1927 *dest = CoTaskMemAlloc(len);
1928 } else {
1929 *dest = NULL;
1932 if (*dest) {
1933 memcpy(*dest, src, len);
1934 hr = S_OK;
1935 } else {
1936 hr = E_OUTOFMEMORY;
1939 TRACE("%s->(%p)\n", debugstr_w(src), *dest);
1940 return hr;
1943 /*************************************************************************
1944 * SHLWAPI_WriteReverseNum
1946 * Internal helper for SHLWAPI_WriteTimeClass.
1948 static inline LPWSTR SHLWAPI_WriteReverseNum(LPWSTR lpszOut, DWORD dwNum)
1950 *lpszOut-- = '\0';
1952 /* Write a decimal number to a string, backwards */
1955 DWORD dwNextDigit = dwNum % 10;
1956 *lpszOut-- = '0' + dwNextDigit;
1957 dwNum = (dwNum - dwNextDigit) / 10;
1958 } while (dwNum > 0);
1960 return lpszOut;
1963 /*************************************************************************
1964 * SHLWAPI_FormatSignificant
1966 * Internal helper for SHLWAPI_WriteTimeClass.
1968 static inline int SHLWAPI_FormatSignificant(LPWSTR lpszNum, int dwDigits)
1970 /* Zero non significant digits, return remaining significant digits */
1971 while (*lpszNum)
1973 lpszNum++;
1974 if (--dwDigits == 0)
1976 while (*lpszNum)
1977 *lpszNum++ = '0';
1978 return 0;
1981 return dwDigits;
1984 /*************************************************************************
1985 * SHLWAPI_WriteTimeClass
1987 * Internal helper for StrFromTimeIntervalW.
1989 static int WINAPI SHLWAPI_WriteTimeClass(LPWSTR lpszOut, DWORD dwValue,
1990 UINT uClassStringId, int iDigits)
1992 WCHAR szBuff[64], *szOut = szBuff + 32;
1994 szOut = SHLWAPI_WriteReverseNum(szOut, dwValue);
1995 iDigits = SHLWAPI_FormatSignificant(szOut + 1, iDigits);
1996 *szOut = ' ';
1997 LoadStringW(shlwapi_hInstance, uClassStringId, szBuff + 32, 32);
1998 strcatW(lpszOut, szOut);
1999 return iDigits;
2002 /*************************************************************************
2003 * StrFromTimeIntervalA [SHLWAPI.@]
2005 * Format a millisecond time interval into a string
2007 * PARAMS
2008 * lpszStr [O] Output buffer for formatted time interval
2009 * cchMax [I] Size of lpszStr
2010 * dwMS [I] Number of milliseconds
2011 * iDigits [I] Number of digits to print
2013 * RETURNS
2014 * The length of the formatted string, or 0 if any parameter is invalid.
2016 * NOTES
2017 * This implementation mimics the Win32 behaviour of always writing a leading
2018 * space before the time interval begins.
2020 * iDigits is used to provide approximate times if accuracy is not important.
2021 * This number of digits will be written of the first non-zero time class
2022 * (hours/minutes/seconds). If this does not complete the time classification,
2023 * the remaining digits are changed to zeros (i.e. The time is _not_ rounded).
2024 * If there are digits remaining following the writing of a time class, the
2025 * next time class will be written.
2027 * For example, given dwMS represents 138 hours,43 minutes and 15 seconds, the
2028 * following will result from the given values of iDigits:
2030 *| iDigits 1 2 3 4 5 ...
2031 *| lpszStr "100 hr" "130 hr" "138 hr" "138 hr 40 min" "138 hr 43 min" ...
2033 INT WINAPI StrFromTimeIntervalA(LPSTR lpszStr, UINT cchMax, DWORD dwMS,
2034 int iDigits)
2036 INT iRet = 0;
2038 TRACE("(%p,%d,%d,%d)\n", lpszStr, cchMax, dwMS, iDigits);
2040 if (lpszStr && cchMax)
2042 WCHAR szBuff[128];
2043 StrFromTimeIntervalW(szBuff, sizeof(szBuff)/sizeof(WCHAR), dwMS, iDigits);
2044 WideCharToMultiByte(CP_ACP,0,szBuff,-1,lpszStr,cchMax,0,0);
2046 return iRet;
2050 /*************************************************************************
2051 * StrFromTimeIntervalW [SHLWAPI.@]
2053 * See StrFromTimeIntervalA.
2055 INT WINAPI StrFromTimeIntervalW(LPWSTR lpszStr, UINT cchMax, DWORD dwMS,
2056 int iDigits)
2058 INT iRet = 0;
2060 TRACE("(%p,%d,%d,%d)\n", lpszStr, cchMax, dwMS, iDigits);
2062 if (lpszStr && cchMax)
2064 WCHAR szCopy[128];
2065 DWORD dwHours, dwMinutes;
2067 if (!iDigits || cchMax == 1)
2069 *lpszStr = '\0';
2070 return 0;
2073 /* Calculate the time classes */
2074 dwMS = (dwMS + 500) / 1000;
2075 dwHours = dwMS / 3600;
2076 dwMS -= dwHours * 3600;
2077 dwMinutes = dwMS / 60;
2078 dwMS -= dwMinutes * 60;
2080 szCopy[0] = '\0';
2082 if (dwHours)
2083 iDigits = SHLWAPI_WriteTimeClass(szCopy, dwHours, IDS_TIME_INTERVAL_HOURS, iDigits);
2085 if (dwMinutes && iDigits)
2086 iDigits = SHLWAPI_WriteTimeClass(szCopy, dwMinutes, IDS_TIME_INTERVAL_MINUTES, iDigits);
2088 if (iDigits) /* Always write seconds if we have significant digits */
2089 SHLWAPI_WriteTimeClass(szCopy, dwMS, IDS_TIME_INTERVAL_SECONDS, iDigits);
2091 lstrcpynW(lpszStr, szCopy, cchMax);
2092 iRet = strlenW(lpszStr);
2094 return iRet;
2097 /*************************************************************************
2098 * StrIsIntlEqualA [SHLWAPI.@]
2100 * Compare two strings.
2102 * PARAMS
2103 * bCase [I] Whether to compare case sensitively
2104 * lpszStr [I] First string to compare
2105 * lpszComp [I] Second string to compare
2106 * iLen [I] Length to compare
2108 * RETURNS
2109 * TRUE If the strings are equal.
2110 * FALSE Otherwise.
2112 BOOL WINAPI StrIsIntlEqualA(BOOL bCase, LPCSTR lpszStr, LPCSTR lpszComp,
2113 int iLen)
2115 DWORD dwFlags;
2117 TRACE("(%d,%s,%s,%d)\n", bCase,
2118 debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
2120 /* FIXME: This flag is undocumented and unknown by our CompareString.
2121 * We need a define for it.
2123 dwFlags = 0x10000000;
2124 if (!bCase) dwFlags |= NORM_IGNORECASE;
2126 return (CompareStringA(GetThreadLocale(), dwFlags, lpszStr, iLen, lpszComp, iLen) == CSTR_EQUAL);
2129 /*************************************************************************
2130 * StrIsIntlEqualW [SHLWAPI.@]
2132 * See StrIsIntlEqualA.
2134 BOOL WINAPI StrIsIntlEqualW(BOOL bCase, LPCWSTR lpszStr, LPCWSTR lpszComp,
2135 int iLen)
2137 DWORD dwFlags;
2139 TRACE("(%d,%s,%s,%d)\n", bCase,
2140 debugstr_w(lpszStr),debugstr_w(lpszComp), iLen);
2142 /* FIXME: This flag is undocumented and unknown by our CompareString.
2143 * We need a define for it.
2145 dwFlags = 0x10000000;
2146 if (!bCase) dwFlags |= NORM_IGNORECASE;
2148 return (CompareStringW(GetThreadLocale(), dwFlags, lpszStr, iLen, lpszComp, iLen) == CSTR_EQUAL);
2151 /*************************************************************************
2152 * @ [SHLWAPI.399]
2154 * Copy a string to another string, up to a maximum number of characters.
2156 * PARAMS
2157 * lpszDest [O] Destination string
2158 * lpszSrc [I] Source string
2159 * iLen [I] Maximum number of chars to copy
2161 * RETURNS
2162 * Success: A pointer to the last character written to lpszDest.
2163 * Failure: lpszDest, if any arguments are invalid.
2165 LPSTR WINAPI StrCpyNXA(LPSTR lpszDest, LPCSTR lpszSrc, int iLen)
2167 TRACE("(%p,%s,%i)\n", lpszDest, debugstr_a(lpszSrc), iLen);
2169 if (lpszDest && lpszSrc && iLen > 0)
2171 while ((iLen-- > 1) && *lpszSrc)
2172 *lpszDest++ = *lpszSrc++;
2173 if (iLen >= 0)
2174 *lpszDest = '\0';
2176 return lpszDest;
2179 /*************************************************************************
2180 * @ [SHLWAPI.400]
2182 * Unicode version of StrCpyNXA.
2184 LPWSTR WINAPI StrCpyNXW(LPWSTR lpszDest, LPCWSTR lpszSrc, int iLen)
2186 TRACE("(%p,%s,%i)\n", lpszDest, debugstr_w(lpszSrc), iLen);
2188 if (lpszDest && lpszSrc && iLen > 0)
2190 while ((iLen-- > 1) && *lpszSrc)
2191 *lpszDest++ = *lpszSrc++;
2192 if (iLen >= 0)
2193 *lpszDest = '\0';
2195 return lpszDest;
2198 /*************************************************************************
2199 * StrCmpLogicalW [SHLWAPI.@]
2201 * Compare two strings, ignoring case and comparing digits as numbers.
2203 * PARAMS
2204 * lpszStr [I] First string to compare
2205 * lpszComp [I] Second string to compare
2206 * iLen [I] Length to compare
2208 * RETURNS
2209 * TRUE If the strings are equal.
2210 * FALSE Otherwise.
2212 INT WINAPI StrCmpLogicalW(LPCWSTR lpszStr, LPCWSTR lpszComp)
2214 INT iDiff;
2216 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszComp));
2218 if (lpszStr && lpszComp)
2220 while (*lpszStr)
2222 if (!*lpszComp)
2223 return 1;
2224 else if (isdigitW(*lpszStr))
2226 int iStr, iComp;
2228 if (!isdigitW(*lpszComp))
2229 return -1;
2231 /* Compare the numbers */
2232 StrToIntExW(lpszStr, 0, &iStr);
2233 StrToIntExW(lpszComp, 0, &iComp);
2235 if (iStr < iComp)
2236 return -1;
2237 else if (iStr > iComp)
2238 return 1;
2240 /* Skip */
2241 while (isdigitW(*lpszStr))
2242 lpszStr++;
2243 while (isdigitW(*lpszComp))
2244 lpszComp++;
2246 else if (isdigitW(*lpszComp))
2247 return 1;
2248 else
2250 iDiff = SHLWAPI_ChrCmpHelperW(*lpszStr,*lpszComp,NORM_IGNORECASE);
2251 if (iDiff > 0)
2252 return 1;
2253 else if (iDiff < 0)
2254 return -1;
2256 lpszStr++;
2257 lpszComp++;
2260 if (*lpszComp)
2261 return -1;
2263 return 0;
2266 /* Structure for formatting byte strings */
2267 typedef struct tagSHLWAPI_BYTEFORMATS
2269 LONGLONG dLimit;
2270 double dDivisor;
2271 double dNormaliser;
2272 int nDecimals;
2273 WCHAR wPrefix;
2274 } SHLWAPI_BYTEFORMATS;
2276 /*************************************************************************
2277 * StrFormatByteSizeW [SHLWAPI.@]
2279 * Create a string containing an abbreviated byte count of up to 2^63-1.
2281 * PARAMS
2282 * llBytes [I] Byte size to format
2283 * lpszDest [I] Destination for formatted string
2284 * cchMax [I] Size of lpszDest
2286 * RETURNS
2287 * lpszDest.
2289 * NOTES
2290 * There is no StrFormatByteSize64W function, it is called StrFormatByteSizeW().
2292 LPWSTR WINAPI StrFormatByteSizeW(LONGLONG llBytes, LPWSTR lpszDest, UINT cchMax)
2294 #define KB ((ULONGLONG)1024)
2295 #define MB (KB*KB)
2296 #define GB (KB*KB*KB)
2297 #define TB (KB*KB*KB*KB)
2298 #define PB (KB*KB*KB*KB*KB)
2300 static const SHLWAPI_BYTEFORMATS bfFormats[] =
2302 { 10*KB, 10.24, 100.0, 2, 'K' }, /* 10 KB */
2303 { 100*KB, 102.4, 10.0, 1, 'K' }, /* 100 KB */
2304 { 1000*KB, 1024.0, 1.0, 0, 'K' }, /* 1000 KB */
2305 { 10*MB, 10485.76, 100.0, 2, 'M' }, /* 10 MB */
2306 { 100*MB, 104857.6, 10.0, 1, 'M' }, /* 100 MB */
2307 { 1000*MB, 1048576.0, 1.0, 0, 'M' }, /* 1000 MB */
2308 { 10*GB, 10737418.24, 100.0, 2, 'G' }, /* 10 GB */
2309 { 100*GB, 107374182.4, 10.0, 1, 'G' }, /* 100 GB */
2310 { 1000*GB, 1073741824.0, 1.0, 0, 'G' }, /* 1000 GB */
2311 { 10*TB, 10485.76, 100.0, 2, 'T' }, /* 10 TB */
2312 { 100*TB, 104857.6, 10.0, 1, 'T' }, /* 100 TB */
2313 { 1000*TB, 1048576.0, 1.0, 0, 'T' }, /* 1000 TB */
2314 { 10*PB, 10737418.24, 100.00, 2, 'P' }, /* 10 PB */
2315 { 100*PB, 107374182.4, 10.00, 1, 'P' }, /* 100 PB */
2316 { 1000*PB, 1073741824.0, 1.00, 0, 'P' }, /* 1000 PB */
2317 { 0, 10995116277.76, 100.00, 2, 'E' } /* EB's, catch all */
2319 WCHAR wszAdd[] = {' ','?','B',0};
2320 double dBytes;
2321 UINT i = 0;
2323 TRACE("(0x%s,%p,%d)\n", wine_dbgstr_longlong(llBytes), lpszDest, cchMax);
2325 if (!lpszDest || !cchMax)
2326 return lpszDest;
2328 if (llBytes < 1024) /* 1K */
2330 WCHAR wszBytesFormat[64];
2331 LoadStringW(shlwapi_hInstance, IDS_BYTES_FORMAT, wszBytesFormat, 64);
2332 snprintfW(lpszDest, cchMax, wszBytesFormat, (long)llBytes);
2333 return lpszDest;
2336 /* Note that if this loop completes without finding a match, i will be
2337 * pointing at the last entry, which is a catch all for > 1000 PB
2339 while (i < sizeof(bfFormats) / sizeof(SHLWAPI_BYTEFORMATS) - 1)
2341 if (llBytes < bfFormats[i].dLimit)
2342 break;
2343 i++;
2345 /* Above 1 TB we encounter problems with FP accuracy. So for amounts above
2346 * this number we integer shift down by 1 MB first. The table above has
2347 * the divisors scaled down from the '< 10 TB' entry onwards, to account
2348 * for this. We also add a small fudge factor to get the correct result for
2349 * counts that lie exactly on a 1024 byte boundary.
2351 if (i > 8)
2352 dBytes = (double)(llBytes >> 20) + 0.001; /* Scale down by I MB */
2353 else
2354 dBytes = (double)llBytes + 0.00001;
2356 dBytes = floor(dBytes / bfFormats[i].dDivisor) / bfFormats[i].dNormaliser;
2358 if (!FormatDouble(dBytes, bfFormats[i].nDecimals, lpszDest, cchMax))
2359 return NULL;
2360 wszAdd[1] = bfFormats[i].wPrefix;
2361 StrCatBuffW(lpszDest, wszAdd, cchMax);
2362 return lpszDest;
2365 /*************************************************************************
2366 * StrFormatByteSize64A [SHLWAPI.@]
2368 * See StrFormatByteSizeW.
2370 LPSTR WINAPI StrFormatByteSize64A(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax)
2372 WCHAR wszBuff[32];
2374 StrFormatByteSizeW(llBytes, wszBuff, sizeof(wszBuff)/sizeof(WCHAR));
2376 if (lpszDest)
2377 WideCharToMultiByte(CP_ACP, 0, wszBuff, -1, lpszDest, cchMax, 0, 0);
2378 return lpszDest;
2381 /*************************************************************************
2382 * StrFormatByteSizeA [SHLWAPI.@]
2384 * Create a string containing an abbreviated byte count of up to 2^31-1.
2386 * PARAMS
2387 * dwBytes [I] Byte size to format
2388 * lpszDest [I] Destination for formatted string
2389 * cchMax [I] Size of lpszDest
2391 * RETURNS
2392 * lpszDest.
2394 * NOTES
2395 * The Ascii and Unicode versions of this function accept a different
2396 * integer type for dwBytes. See StrFormatByteSize64A().
2398 LPSTR WINAPI StrFormatByteSizeA(DWORD dwBytes, LPSTR lpszDest, UINT cchMax)
2400 TRACE("(%d,%p,%d)\n", dwBytes, lpszDest, cchMax);
2402 return StrFormatByteSize64A(dwBytes, lpszDest, cchMax);
2405 /*************************************************************************
2406 * @ [SHLWAPI.162]
2408 * Remove a hanging lead byte from the end of a string, if present.
2410 * PARAMS
2411 * lpStr [I] String to check for a hanging lead byte
2412 * size [I] Length of lpStr
2414 * RETURNS
2415 * Success: The new length of the string. Any hanging lead bytes are removed.
2416 * Failure: 0, if any parameters are invalid.
2418 DWORD WINAPI SHTruncateString(LPSTR lpStr, DWORD size)
2420 if (lpStr && size)
2422 LPSTR lastByte = lpStr + size - 1;
2424 while(lpStr < lastByte)
2425 lpStr += IsDBCSLeadByte(*lpStr) ? 2 : 1;
2427 if(lpStr == lastByte && IsDBCSLeadByte(*lpStr))
2429 *lpStr = '\0';
2430 size--;
2432 return size;
2434 return 0;
2437 /*************************************************************************
2438 * @ [SHLWAPI.203]
2440 * Remove a single non-trailing ampersand ('&') from a string.
2442 * PARAMS
2443 * lpszStr [I/O] String to remove ampersand from.
2445 * RETURNS
2446 * The character after the first ampersand in lpszStr, or the first character
2447 * in lpszStr if there is no ampersand in the string.
2449 char WINAPI SHStripMneumonicA(LPCSTR lpszStr)
2451 LPSTR lpszIter, lpszTmp;
2452 char ch;
2454 TRACE("(%s)\n", debugstr_a(lpszStr));
2456 ch = *lpszStr;
2458 if ((lpszIter = StrChrA(lpszStr, '&')))
2460 lpszTmp = CharNextA(lpszIter);
2461 if (lpszTmp && *lpszTmp)
2463 if (*lpszTmp != '&')
2464 ch = *lpszTmp;
2466 while (lpszIter && *lpszIter)
2468 lpszTmp = CharNextA(lpszIter);
2469 *lpszIter = *lpszTmp;
2470 lpszIter = lpszTmp;
2475 return ch;
2478 /*************************************************************************
2479 * @ [SHLWAPI.225]
2481 * Unicode version of SHStripMneumonicA.
2483 WCHAR WINAPI SHStripMneumonicW(LPCWSTR lpszStr)
2485 LPWSTR lpszIter, lpszTmp;
2486 WCHAR ch;
2488 TRACE("(%s)\n", debugstr_w(lpszStr));
2490 ch = *lpszStr;
2492 if ((lpszIter = StrChrW(lpszStr, '&')))
2494 lpszTmp = CharNextW(lpszIter);
2495 if (lpszTmp && *lpszTmp)
2497 if (*lpszTmp != '&')
2498 ch = *lpszTmp;
2500 while (lpszIter && *lpszIter)
2502 lpszTmp = CharNextW(lpszIter);
2503 *lpszIter = *lpszTmp;
2504 lpszIter = lpszTmp;
2509 return ch;
2512 /*************************************************************************
2513 * @ [SHLWAPI.216]
2515 * Convert an Ascii string to Unicode.
2517 * PARAMS
2518 * dwCp [I] Code page for the conversion
2519 * lpSrcStr [I] Source Ascii string to convert
2520 * lpDstStr [O] Destination for converted Unicode string
2521 * iLen [I] Length of lpDstStr
2523 * RETURNS
2524 * The return value of the MultiByteToWideChar() function called on lpSrcStr.
2526 DWORD WINAPI SHAnsiToUnicodeCP(DWORD dwCp, LPCSTR lpSrcStr, LPWSTR lpDstStr, int iLen)
2528 DWORD dwRet;
2530 dwRet = MultiByteToWideChar(dwCp, 0, lpSrcStr, -1, lpDstStr, iLen);
2531 TRACE("%s->%s,ret=%d\n", debugstr_a(lpSrcStr), debugstr_w(lpDstStr), dwRet);
2532 return dwRet;
2535 /*************************************************************************
2536 * @ [SHLWAPI.215]
2538 * Convert an Ascii string to Unicode.
2540 * PARAMS
2541 * lpSrcStr [I] Source Ascii string to convert
2542 * lpDstStr [O] Destination for converted Unicode string
2543 * iLen [I] Length of lpDstStr
2545 * RETURNS
2546 * The return value of the MultiByteToWideChar() function called on lpSrcStr.
2548 * NOTES
2549 * This function simply calls SHAnsiToUnicodeCP with code page CP_ACP.
2551 DWORD WINAPI SHAnsiToUnicode(LPCSTR lpSrcStr, LPWSTR lpDstStr, int iLen)
2553 return SHAnsiToUnicodeCP(CP_ACP, lpSrcStr, lpDstStr, iLen);
2556 /*************************************************************************
2557 * @ [SHLWAPI.218]
2559 * Convert a Unicode string to Ascii.
2561 * PARAMS
2562 * CodePage [I] Code page to use for the conversion
2563 * lpSrcStr [I] Source Unicode string to convert
2564 * lpDstStr [O] Destination for converted Ascii string
2565 * lpiLen [I/O] Input length of lpDstStr/destination for length of lpDstStr
2567 * RETURNS
2568 * Success: The number of characters that result from the conversion.
2569 * Failure: 0.
2571 INT WINAPI SHUnicodeToAnsiCP(UINT CodePage, LPCWSTR lpSrcStr, LPSTR lpDstStr,
2572 LPINT lpiLen)
2574 static const WCHAR emptyW[] = { '\0' };
2575 int len , reqLen;
2576 LPSTR mem;
2578 if (!lpDstStr || !lpiLen)
2579 return 0;
2581 if (!lpSrcStr)
2582 lpSrcStr = emptyW;
2584 *lpDstStr = '\0';
2586 len = strlenW(lpSrcStr) + 1;
2588 switch (CodePage)
2590 case CP_WINUNICODE:
2591 CodePage = CP_UTF8; /* Fall through... */
2592 case 0x0000C350: /* FIXME: CP_ #define */
2593 case CP_UTF7:
2594 case CP_UTF8:
2596 DWORD dwMode = 0;
2597 INT nWideCharCount = len - 1;
2599 if (!ConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &nWideCharCount, lpDstStr,
2600 lpiLen))
2601 return 0;
2603 if (nWideCharCount < len - 1)
2605 mem = HeapAlloc(GetProcessHeap(), 0, *lpiLen);
2606 if (!mem)
2607 return 0;
2609 *lpiLen = 0;
2611 if (ConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &len, mem, lpiLen))
2613 SHTruncateString(mem, *lpiLen);
2614 lstrcpynA(lpDstStr, mem, *lpiLen + 1);
2615 HeapFree(GetProcessHeap(), 0, mem);
2616 return *lpiLen + 1;
2618 HeapFree(GetProcessHeap(), 0, mem);
2619 return *lpiLen;
2621 lpDstStr[*lpiLen] = '\0';
2622 return *lpiLen;
2624 default:
2625 break;
2628 reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, lpDstStr,
2629 *lpiLen, NULL, NULL);
2631 if (!reqLen && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
2633 reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, NULL, 0, NULL, NULL);
2634 if (reqLen)
2636 mem = HeapAlloc(GetProcessHeap(), 0, reqLen);
2637 if (mem)
2639 reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, mem,
2640 reqLen, NULL, NULL);
2642 reqLen = SHTruncateString(mem, *lpiLen);
2643 reqLen++;
2645 lstrcpynA(lpDstStr, mem, *lpiLen);
2647 HeapFree(GetProcessHeap(), 0, mem);
2651 return reqLen;
2654 /*************************************************************************
2655 * @ [SHLWAPI.217]
2657 * Convert a Unicode string to Ascii.
2659 * PARAMS
2660 * lpSrcStr [I] Source Unicode string to convert
2661 * lpDstStr [O] Destination for converted Ascii string
2662 * iLen [O] Length of lpDstStr in characters
2664 * RETURNS
2665 * See SHUnicodeToAnsiCP
2667 * NOTES
2668 * This function simply calls SHUnicodeToAnsiCP() with CodePage = CP_ACP.
2670 INT WINAPI SHUnicodeToAnsi(LPCWSTR lpSrcStr, LPSTR lpDstStr, INT iLen)
2672 INT myint = iLen;
2674 return SHUnicodeToAnsiCP(CP_ACP, lpSrcStr, lpDstStr, &myint);
2677 /*************************************************************************
2678 * @ [SHLWAPI.345]
2680 * Copy one string to another.
2682 * PARAMS
2683 * lpszSrc [I] Source string to copy
2684 * lpszDst [O] Destination for copy
2685 * iLen [I] Length of lpszDst in characters
2687 * RETURNS
2688 * The length of the copied string, including the terminating NUL. lpszDst
2689 * contains iLen characters of lpszSrc.
2691 DWORD WINAPI SHAnsiToAnsi(LPCSTR lpszSrc, LPSTR lpszDst, int iLen)
2693 LPSTR lpszRet;
2695 TRACE("(%s,%p,0x%08x)\n", debugstr_a(lpszSrc), lpszDst, iLen);
2697 lpszRet = StrCpyNXA(lpszDst, lpszSrc, iLen);
2698 return lpszRet - lpszDst + 1;
2701 /*************************************************************************
2702 * @ [SHLWAPI.346]
2704 * Unicode version of SSHAnsiToAnsi.
2706 DWORD WINAPI SHUnicodeToUnicode(LPCWSTR lpszSrc, LPWSTR lpszDst, int iLen)
2708 LPWSTR lpszRet;
2710 TRACE("(%s,%p,0x%08x)\n", debugstr_w(lpszSrc), lpszDst, iLen);
2712 lpszRet = StrCpyNXW(lpszDst, lpszSrc, iLen);
2713 return lpszRet - lpszDst + 1;
2716 /*************************************************************************
2717 * @ [SHLWAPI.364]
2719 * Determine if an Ascii string converts to Unicode and back identically.
2721 * PARAMS
2722 * lpSrcStr [I] Source Unicode string to convert
2723 * lpDst [O] Destination for resulting Ascii string
2724 * iLen [I] Length of lpDst in characters
2726 * RETURNS
2727 * TRUE, since Ascii strings always convert identically.
2729 BOOL WINAPI DoesStringRoundTripA(LPCSTR lpSrcStr, LPSTR lpDst, INT iLen)
2731 lstrcpynA(lpDst, lpSrcStr, iLen);
2732 return TRUE;
2735 /*************************************************************************
2736 * @ [SHLWAPI.365]
2738 * Determine if a Unicode string converts to Ascii and back identically.
2740 * PARAMS
2741 * lpSrcStr [I] Source Unicode string to convert
2742 * lpDst [O] Destination for resulting Ascii string
2743 * iLen [I] Length of lpDst in characters
2745 * RETURNS
2746 * TRUE, if lpSrcStr converts to Ascii and back identically,
2747 * FALSE otherwise.
2749 BOOL WINAPI DoesStringRoundTripW(LPCWSTR lpSrcStr, LPSTR lpDst, INT iLen)
2751 WCHAR szBuff[MAX_PATH];
2753 SHUnicodeToAnsi(lpSrcStr, lpDst, iLen);
2754 SHAnsiToUnicode(lpDst, szBuff, MAX_PATH);
2755 return !strcmpW(lpSrcStr, szBuff);
2758 /*************************************************************************
2759 * SHLoadIndirectString [SHLWAPI.@]
2761 * If passed a string that begins with '@', extract the string from the
2762 * appropriate resource, otherwise do a straight copy.
2765 HRESULT WINAPI SHLoadIndirectString(LPCWSTR src, LPWSTR dst, UINT dst_len, void **reserved)
2767 WCHAR *dllname = NULL;
2768 HMODULE hmod = NULL;
2769 HRESULT hr = E_FAIL;
2771 TRACE("(%s %p %08x %p)\n", debugstr_w(src), dst, dst_len, reserved);
2773 if(src[0] == '@')
2775 WCHAR *index_str;
2776 int index;
2778 dst[0] = 0;
2779 dllname = StrDupW(src + 1);
2780 index_str = strchrW(dllname, ',');
2782 if(!index_str) goto end;
2784 *index_str = 0;
2785 index_str++;
2786 index = atoiW(index_str);
2788 hmod = LoadLibraryW(dllname);
2789 if(!hmod) goto end;
2791 if(index < 0)
2793 if(LoadStringW(hmod, -index, dst, dst_len))
2794 hr = S_OK;
2796 else
2797 FIXME("can't handle non-negative indices (%d)\n", index);
2799 else
2801 if(dst != src)
2802 lstrcpynW(dst, src, dst_len);
2803 hr = S_OK;
2806 TRACE("returning %s\n", debugstr_w(dst));
2807 end:
2808 if(hmod) FreeLibrary(hmod);
2809 HeapFree(GetProcessHeap(), 0, dllname);
2810 return hr;