wined3d: Use D3DCUBEMAP_FACES consistently in the WINED3D namespace.
[wine/wine64.git] / dlls / shlwapi / string.c
blobb8cabf1beb5d795e15313b1a030d040724ea70a1
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 "ddeml.h"
41 #include "wine/unicode.h"
42 #include "wine/debug.h"
44 #include "resource.h"
46 WINE_DEFAULT_DEBUG_CHANNEL(shell);
48 /* Get a function pointer from a DLL handle */
49 #define GET_FUNC(func, module, name, fail) \
50 do { \
51 if (!func) { \
52 if (!SHLWAPI_h##module && !(SHLWAPI_h##module = LoadLibraryA(#module ".dll"))) return fail; \
53 func = (fn##func)GetProcAddress(SHLWAPI_h##module, name); \
54 if (!func) return fail; \
55 } \
56 } while (0)
58 extern HMODULE SHLWAPI_hmlang;
59 extern HINSTANCE shlwapi_hInstance;
61 typedef HRESULT (WINAPI *fnpConvertINetUnicodeToMultiByte)(LPDWORD,DWORD,LPCWSTR,LPINT,LPSTR,LPINT);
62 static fnpConvertINetUnicodeToMultiByte pConvertINetUnicodeToMultiByte;
64 static HRESULT WINAPI _SHStrDupAA(LPCSTR,LPSTR*);
65 static HRESULT WINAPI _SHStrDupAW(LPCWSTR,LPSTR*);
68 static void FillNumberFmt(NUMBERFMTW *fmt, LPWSTR decimal_buffer, int decimal_bufwlen,
69 LPWSTR thousand_buffer, int thousand_bufwlen)
71 WCHAR grouping[64];
72 WCHAR *c;
74 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_ILZERO|LOCALE_RETURN_NUMBER, (LPWSTR)&fmt->LeadingZero, sizeof(fmt->LeadingZero)/sizeof(WCHAR));
75 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_INEGNUMBER|LOCALE_RETURN_NUMBER, (LPWSTR)&fmt->LeadingZero, sizeof(fmt->NegativeOrder)/sizeof(WCHAR));
76 fmt->NumDigits = 0;
77 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, decimal_buffer, decimal_bufwlen);
78 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, thousand_buffer, thousand_bufwlen);
79 fmt->lpThousandSep = thousand_buffer;
80 fmt->lpDecimalSep = decimal_buffer;
82 /*
83 * Converting grouping string to number as described on
84 * http://blogs.msdn.com/oldnewthing/archive/2006/04/18/578251.aspx
86 fmt->Grouping = 0;
87 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SGROUPING, grouping, sizeof(grouping)/sizeof(WCHAR));
88 for (c = grouping; *c; c++)
89 if (*c >= '0' && *c < '9')
91 fmt->Grouping *= 10;
92 fmt->Grouping += *c - '0';
95 if (fmt->Grouping % 10 == 0)
96 fmt->Grouping /= 10;
97 else
98 fmt->Grouping *= 10;
101 /*************************************************************************
102 * FormatInt [internal]
104 * Format an integer according to the current locale
106 * RETURNS
107 * The number of bytes written on success or 0 on failure
109 static int FormatInt(LONGLONG qdwValue, LPWSTR pszBuf, int cchBuf)
111 NUMBERFMTW fmt;
112 WCHAR decimal[8], thousand[8];
113 WCHAR buf[24];
114 WCHAR *c;
115 BOOL neg = (qdwValue < 0);
117 FillNumberFmt(&fmt, decimal, sizeof decimal / sizeof (WCHAR),
118 thousand, sizeof thousand / sizeof (WCHAR));
120 c = &buf[24];
121 *(--c) = 0;
124 *(--c) = '0' + (qdwValue%10);
125 qdwValue /= 10;
126 } while (qdwValue > 0);
127 if (neg)
128 *(--c) = '-';
130 return GetNumberFormatW(LOCALE_USER_DEFAULT, 0, c, &fmt, pszBuf, cchBuf);
133 /*************************************************************************
134 * FormatDouble [internal]
136 * Format an integer according to the current locale. Prints the specified number of digits
137 * after the decimal point
139 * RETURNS
140 * The number of bytes written on success or 0 on failure
142 static int FormatDouble(double value, int decimals, LPWSTR pszBuf, int cchBuf)
144 static const WCHAR flfmt[] = {'%','f',0};
145 WCHAR buf[64];
146 NUMBERFMTW fmt;
147 WCHAR decimal[8], thousand[8];
149 snprintfW(buf, 64, flfmt, value);
151 FillNumberFmt(&fmt, decimal, sizeof decimal / sizeof (WCHAR),
152 thousand, sizeof thousand / sizeof (WCHAR));
153 fmt.NumDigits = decimals;
154 return GetNumberFormatW(LOCALE_USER_DEFAULT, 0, buf, &fmt, pszBuf, cchBuf);
157 /*************************************************************************
158 * SHLWAPI_ChrCmpHelperA
160 * Internal helper for SHLWAPI_ChrCmpA/ChrCMPIA.
162 * NOTES
163 * Both this function and its Unicode counterpart are very inneficient. To
164 * fix this, CompareString must be completely implemented and optimised
165 * first. Then the core character test can be taken out of that function and
166 * placed here, so that it need never be called at all. Until then, do not
167 * attempt to optimise this code unless you are willing to test that it
168 * still performs correctly.
170 static BOOL WINAPI SHLWAPI_ChrCmpHelperA(WORD ch1, WORD ch2, DWORD dwFlags)
172 char str1[3], str2[3];
174 str1[0] = LOBYTE(ch1);
175 if (IsDBCSLeadByte(str1[0]))
177 str1[1] = HIBYTE(ch1);
178 str1[2] = '\0';
180 else
181 str1[1] = '\0';
183 str2[0] = LOBYTE(ch2);
184 if (IsDBCSLeadByte(str2[0]))
186 str2[1] = HIBYTE(ch2);
187 str2[2] = '\0';
189 else
190 str2[1] = '\0';
192 return CompareStringA(GetThreadLocale(), dwFlags, str1, -1, str2, -1) - 2;
195 /*************************************************************************
196 * SHLWAPI_ChrCmpHelperW
198 * Internal helper for SHLWAPI_ChrCmpW/ChrCmpIW.
200 static BOOL WINAPI SHLWAPI_ChrCmpHelperW(WCHAR ch1, WCHAR ch2, DWORD dwFlags)
202 WCHAR str1[2], str2[2];
204 str1[0] = ch1;
205 str1[1] = '\0';
206 str2[0] = ch2;
207 str2[1] = '\0';
208 return CompareStringW(GetThreadLocale(), dwFlags, str1, 2, str2, 2) - 2;
211 /*************************************************************************
212 * SHLWAPI_ChrCmpA
214 * Internal helper function.
216 static BOOL WINAPI SHLWAPI_ChrCmpA(WORD ch1, WORD ch2)
218 return SHLWAPI_ChrCmpHelperA(ch1, ch2, 0);
221 /*************************************************************************
222 * ChrCmpIA (SHLWAPI.385)
224 * Compare two characters, ignoring case.
226 * PARAMS
227 * ch1 [I] First character to compare
228 * ch2 [I] Second character to compare
230 * RETURNS
231 * FALSE, if the characters are equal.
232 * Non-zero otherwise.
234 BOOL WINAPI ChrCmpIA(WORD ch1, WORD ch2)
236 TRACE("(%d,%d)\n", ch1, ch2);
238 return SHLWAPI_ChrCmpHelperA(ch1, ch2, NORM_IGNORECASE);
241 /*************************************************************************
242 * SHLWAPI_ChrCmpW
244 * Internal helper function.
246 static BOOL WINAPI SHLWAPI_ChrCmpW(WCHAR ch1, WCHAR ch2)
248 return SHLWAPI_ChrCmpHelperW(ch1, ch2, 0);
251 /*************************************************************************
252 * ChrCmpIW [SHLWAPI.386]
254 * See ChrCmpIA.
256 BOOL WINAPI ChrCmpIW(WCHAR ch1, WCHAR ch2)
258 return SHLWAPI_ChrCmpHelperW(ch1, ch2, NORM_IGNORECASE);
261 /*************************************************************************
262 * StrChrA [SHLWAPI.@]
264 * Find a given character in a string.
266 * PARAMS
267 * lpszStr [I] String to search in.
268 * ch [I] Character to search for.
270 * RETURNS
271 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
272 * not found.
273 * Failure: NULL, if any arguments are invalid.
275 LPSTR WINAPI StrChrA(LPCSTR lpszStr, WORD ch)
277 TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch);
279 if (lpszStr)
281 while (*lpszStr)
283 if (!SHLWAPI_ChrCmpA(*lpszStr, ch))
284 return (LPSTR)lpszStr;
285 lpszStr = CharNextA(lpszStr);
288 return NULL;
291 /*************************************************************************
292 * StrChrW [SHLWAPI.@]
294 * See StrChrA.
296 LPWSTR WINAPI StrChrW(LPCWSTR lpszStr, WCHAR ch)
298 LPWSTR lpszRet = NULL;
300 TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch);
302 if (lpszStr)
303 lpszRet = strchrW(lpszStr, ch);
304 return lpszRet;
307 /*************************************************************************
308 * StrChrIA [SHLWAPI.@]
310 * Find a given character in a string, ignoring case.
312 * PARAMS
313 * lpszStr [I] String to search in.
314 * ch [I] Character to search for.
316 * RETURNS
317 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
318 * not found.
319 * Failure: NULL, if any arguments are invalid.
321 LPSTR WINAPI StrChrIA(LPCSTR lpszStr, WORD ch)
323 TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch);
325 if (lpszStr)
327 while (*lpszStr)
329 if (!ChrCmpIA(*lpszStr, ch))
330 return (LPSTR)lpszStr;
331 lpszStr = CharNextA(lpszStr);
334 return NULL;
337 /*************************************************************************
338 * StrChrIW [SHLWAPI.@]
340 * See StrChrA.
342 LPWSTR WINAPI StrChrIW(LPCWSTR lpszStr, WCHAR ch)
344 TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch);
346 if (lpszStr)
348 ch = toupperW(ch);
349 while (*lpszStr)
351 if (toupperW(*lpszStr) == ch)
352 return (LPWSTR)lpszStr;
353 lpszStr = CharNextW(lpszStr);
355 lpszStr = NULL;
357 return (LPWSTR)lpszStr;
360 /*************************************************************************
361 * StrCmpIW [SHLWAPI.@]
363 * Compare two strings, ignoring case.
365 * PARAMS
366 * lpszStr [I] First string to compare
367 * lpszComp [I] Second string to compare
369 * RETURNS
370 * An integer less than, equal to or greater than 0, indicating that
371 * lpszStr is less than, the same, or greater than lpszComp.
373 int WINAPI StrCmpIW(LPCWSTR lpszStr, LPCWSTR lpszComp)
375 int iRet;
377 TRACE("(%s,%s)\n", debugstr_w(lpszStr),debugstr_w(lpszComp));
379 iRet = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, lpszStr, -1, lpszComp, -1);
380 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
383 /*************************************************************************
384 * StrCmpNA [SHLWAPI.@]
386 * Compare two strings, up to a maximum length.
388 * PARAMS
389 * lpszStr [I] First string to compare
390 * lpszComp [I] Second string to compare
391 * iLen [I] Maximum number of chars to compare.
393 * RETURNS
394 * An integer less than, equal to or greater than 0, indicating that
395 * lpszStr is less than, the same, or greater than lpszComp.
397 INT WINAPI StrCmpNA(LPCSTR lpszStr, LPCSTR lpszComp, INT iLen)
399 INT iRet;
401 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
403 iRet = CompareStringA(GetThreadLocale(), 0, lpszStr, iLen, lpszComp, iLen);
404 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
407 /*************************************************************************
408 * StrCmpNW [SHLWAPI.@]
410 * See StrCmpNA.
412 INT WINAPI StrCmpNW(LPCWSTR lpszStr, LPCWSTR lpszComp, INT iLen)
414 INT iRet;
416 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen);
418 iRet = CompareStringW(GetThreadLocale(), 0, lpszStr, iLen, lpszComp, iLen);
419 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
422 /*************************************************************************
423 * StrCmpNIA [SHLWAPI.@]
425 * Compare two strings, up to a maximum length, ignoring case.
427 * PARAMS
428 * lpszStr [I] First string to compare
429 * lpszComp [I] Second string to compare
430 * iLen [I] Maximum number of chars to compare.
432 * RETURNS
433 * An integer less than, equal to or greater than 0, indicating that
434 * lpszStr is less than, the same, or greater than lpszComp.
436 int WINAPI StrCmpNIA(LPCSTR lpszStr, LPCSTR lpszComp, int iLen)
438 INT iRet;
440 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
442 iRet = CompareStringA(GetThreadLocale(), NORM_IGNORECASE, lpszStr, iLen, lpszComp, iLen);
443 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
446 /*************************************************************************
447 * StrCmpNIW [SHLWAPI.@]
449 * See StrCmpNIA.
451 INT WINAPI StrCmpNIW(LPCWSTR lpszStr, LPCWSTR lpszComp, int iLen)
453 INT iRet;
455 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen);
457 iRet = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, lpszStr, iLen, lpszComp, iLen);
458 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
461 /*************************************************************************
462 * StrCmpW [SHLWAPI.@]
464 * Compare two strings.
466 * PARAMS
467 * lpszStr [I] First string to compare
468 * lpszComp [I] Second string to compare
470 * RETURNS
471 * An integer less than, equal to or greater than 0, indicating that
472 * lpszStr is less than, the same, or greater than lpszComp.
474 int WINAPI StrCmpW(LPCWSTR lpszStr, LPCWSTR lpszComp)
476 INT iRet;
478 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszComp));
480 iRet = CompareStringW(GetThreadLocale(), 0, lpszStr, -1, lpszComp, -1);
481 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
484 /*************************************************************************
485 * StrCatW [SHLWAPI.@]
487 * Concatanate two strings.
489 * PARAMS
490 * lpszStr [O] Initial string
491 * lpszSrc [I] String to concatanate
493 * RETURNS
494 * lpszStr.
496 LPWSTR WINAPI StrCatW(LPWSTR lpszStr, LPCWSTR lpszSrc)
498 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSrc));
500 strcatW(lpszStr, lpszSrc);
501 return lpszStr;
504 /*************************************************************************
505 * StrCpyW [SHLWAPI.@]
507 * Copy a string to another string.
509 * PARAMS
510 * lpszStr [O] Destination string
511 * lpszSrc [I] Source string
513 * RETURNS
514 * lpszStr.
516 LPWSTR WINAPI StrCpyW(LPWSTR lpszStr, LPCWSTR lpszSrc)
518 TRACE("(%p,%s)\n", lpszStr, debugstr_w(lpszSrc));
520 strcpyW(lpszStr, lpszSrc);
521 return lpszStr;
524 /*************************************************************************
525 * StrCpyNW [SHLWAPI.@]
527 * Copy a string to another string, up to a maximum number of characters.
529 * PARAMS
530 * lpszStr [O] Destination string
531 * lpszSrc [I] Source string
532 * iLen [I] Maximum number of chars to copy
534 * RETURNS
535 * lpszStr.
537 LPWSTR WINAPI StrCpyNW(LPWSTR lpszStr, LPCWSTR lpszSrc, int iLen)
539 TRACE("(%p,%s,%i)\n", lpszStr, debugstr_w(lpszSrc), iLen);
541 lstrcpynW(lpszStr, lpszSrc, iLen);
542 return lpszStr;
547 /*************************************************************************
548 * SHLWAPI_StrStrHelperA
550 * Internal implementation of StrStrA/StrStrIA
552 static LPSTR WINAPI SHLWAPI_StrStrHelperA(LPCSTR lpszStr, LPCSTR lpszSearch,
553 int (*pStrCmpFn)(LPCSTR,LPCSTR,size_t))
555 size_t iLen;
557 if (!lpszStr || !lpszSearch || !*lpszSearch)
558 return NULL;
560 iLen = strlen(lpszSearch);
562 while (*lpszStr)
564 if (!pStrCmpFn(lpszStr, lpszSearch, iLen))
565 return (LPSTR)lpszStr;
566 lpszStr = CharNextA(lpszStr);
568 return NULL;
571 /*************************************************************************
572 * SHLWAPI_StrStrHelperW
574 * Internal implementation of StrStrW/StrStrIW
576 static LPWSTR WINAPI SHLWAPI_StrStrHelperW(LPCWSTR lpszStr, LPCWSTR lpszSearch,
577 int (*pStrCmpFn)(LPCWSTR,LPCWSTR,int))
579 int iLen;
581 if (!lpszStr || !lpszSearch || !*lpszSearch)
582 return NULL;
584 iLen = strlenW(lpszSearch);
586 while (*lpszStr)
588 if (!pStrCmpFn(lpszStr, lpszSearch, iLen))
589 return (LPWSTR)lpszStr;
590 lpszStr = CharNextW(lpszStr);
592 return NULL;
595 /*************************************************************************
596 * StrStrA [SHLWAPI.@]
598 * Find a substring within a string.
600 * PARAMS
601 * lpszStr [I] String to search in
602 * lpszSearch [I] String to look for
604 * RETURNS
605 * The start of lpszSearch within lpszStr, or NULL if not found.
607 LPSTR WINAPI StrStrA(LPCSTR lpszStr, LPCSTR lpszSearch)
609 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
611 return SHLWAPI_StrStrHelperA(lpszStr, lpszSearch, strncmp);
614 /*************************************************************************
615 * StrStrW [SHLWAPI.@]
617 * See StrStrA.
619 LPWSTR WINAPI StrStrW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
621 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
623 return SHLWAPI_StrStrHelperW(lpszStr, lpszSearch, strncmpW);
626 /*************************************************************************
627 * StrRStrIA [SHLWAPI.@]
629 * Find the last occurrence of a substring within a string.
631 * PARAMS
632 * lpszStr [I] String to search in
633 * lpszEnd [I] End of lpszStr
634 * lpszSearch [I] String to look for
636 * RETURNS
637 * The last occurrence lpszSearch within lpszStr, or NULL if not found.
639 LPSTR WINAPI StrRStrIA(LPCSTR lpszStr, LPCSTR lpszEnd, LPCSTR lpszSearch)
641 WORD ch1, ch2;
642 INT iLen;
644 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
646 if (!lpszStr || !lpszSearch || !*lpszSearch)
647 return NULL;
649 if (!lpszEnd)
650 lpszEnd = lpszStr + lstrlenA(lpszStr);
651 if (lpszEnd == lpszStr)
652 return NULL;
654 if (IsDBCSLeadByte(*lpszSearch))
655 ch1 = *lpszSearch << 8 | (UCHAR)lpszSearch[1];
656 else
657 ch1 = *lpszSearch;
658 iLen = lstrlenA(lpszSearch);
662 lpszEnd = CharPrevA(lpszStr, lpszEnd);
663 ch2 = IsDBCSLeadByte(*lpszEnd)? *lpszEnd << 8 | (UCHAR)lpszEnd[1] : *lpszEnd;
664 if (!ChrCmpIA(ch1, ch2))
666 if (!StrCmpNIA(lpszEnd, lpszSearch, iLen))
667 return (LPSTR)lpszEnd;
669 } while (lpszEnd > lpszStr);
670 return NULL;
673 /*************************************************************************
674 * StrRStrIW [SHLWAPI.@]
676 * See StrRStrIA.
678 LPWSTR WINAPI StrRStrIW(LPCWSTR lpszStr, LPCWSTR lpszEnd, LPCWSTR lpszSearch)
680 INT iLen;
682 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
684 if (!lpszStr || !lpszSearch || !*lpszSearch)
685 return NULL;
687 if (!lpszEnd)
688 lpszEnd = lpszStr + strlenW(lpszStr);
689 if (lpszEnd == lpszStr)
690 return NULL;
692 iLen = strlenW(lpszSearch);
696 lpszEnd = CharPrevW(lpszStr, lpszEnd);
697 if (!ChrCmpIW(*lpszSearch, *lpszEnd))
699 if (!StrCmpNIW(lpszEnd, lpszSearch, iLen))
700 return (LPWSTR)lpszEnd;
702 } while (lpszEnd > lpszStr);
703 return NULL;
706 /*************************************************************************
707 * StrStrIA [SHLWAPI.@]
709 * Find a substring within a string, ignoring case.
711 * PARAMS
712 * lpszStr [I] String to search in
713 * lpszSearch [I] String to look for
715 * RETURNS
716 * The start of lpszSearch within lpszStr, or NULL if not found.
718 LPSTR WINAPI StrStrIA(LPCSTR lpszStr, LPCSTR lpszSearch)
720 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
722 return SHLWAPI_StrStrHelperA(lpszStr, lpszSearch, strncasecmp);
725 /*************************************************************************
726 * StrStrIW [SHLWAPI.@]
728 * See StrStrIA.
730 LPWSTR WINAPI StrStrIW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
732 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
734 return SHLWAPI_StrStrHelperW(lpszStr, lpszSearch, strncmpiW);
737 /*************************************************************************
738 * StrToIntA [SHLWAPI.@]
740 * Read a signed integer from a string.
742 * PARAMS
743 * lpszStr [I] String to read integer from
745 * RETURNS
746 * The signed integer value represented by the string, or 0 if no integer is
747 * present.
749 * NOTES
750 * No leading space is allowed before the number, although a leading '-' is.
752 int WINAPI StrToIntA(LPCSTR lpszStr)
754 int iRet = 0;
756 TRACE("(%s)\n", debugstr_a(lpszStr));
758 if (!lpszStr)
760 WARN("Invalid lpszStr would crash under Win32!\n");
761 return 0;
764 if (*lpszStr == '-' || isdigit(*lpszStr))
765 StrToIntExA(lpszStr, 0, &iRet);
766 return iRet;
769 /*************************************************************************
770 * StrToIntW [SHLWAPI.@]
772 * See StrToIntA.
774 int WINAPI StrToIntW(LPCWSTR lpszStr)
776 int iRet = 0;
778 TRACE("(%s)\n", debugstr_w(lpszStr));
780 if (!lpszStr)
782 WARN("Invalid lpszStr would crash under Win32!\n");
783 return 0;
786 if (*lpszStr == '-' || isdigitW(*lpszStr))
787 StrToIntExW(lpszStr, 0, &iRet);
788 return iRet;
791 /*************************************************************************
792 * StrToIntExA [SHLWAPI.@]
794 * Read an integer from a string.
796 * PARAMS
797 * lpszStr [I] String to read integer from
798 * dwFlags [I] Flags controlling the conversion
799 * lpiRet [O] Destination for read integer.
801 * RETURNS
802 * Success: TRUE. lpiRet contains the integer value represented by the string.
803 * Failure: FALSE, if the string is invalid, or no number is present.
805 * NOTES
806 * Leading whitespace, '-' and '+' are allowed before the number. If
807 * dwFlags includes STIF_SUPPORT_HEX, hexadecimal numbers are allowed, if
808 * preceded by '0x'. If this flag is not set, or there is no '0x' prefix,
809 * the string is treated as a decimal string. A leading '-' is ignored for
810 * hexadecimal numbers.
812 BOOL WINAPI StrToIntExA(LPCSTR lpszStr, DWORD dwFlags, LPINT lpiRet)
814 BOOL bNegative = FALSE;
815 int iRet = 0;
817 TRACE("(%s,%08X,%p)\n", debugstr_a(lpszStr), dwFlags, lpiRet);
819 if (!lpszStr || !lpiRet)
821 WARN("Invalid parameter would crash under Win32!\n");
822 return FALSE;
824 if (dwFlags > STIF_SUPPORT_HEX)
826 WARN("Unknown flags (%08lX)!\n", dwFlags & ~STIF_SUPPORT_HEX);
829 /* Skip leading space, '+', '-' */
830 while (isspace(*lpszStr))
831 lpszStr = CharNextA(lpszStr);
833 if (*lpszStr == '-')
835 bNegative = TRUE;
836 lpszStr++;
838 else if (*lpszStr == '+')
839 lpszStr++;
841 if (dwFlags & STIF_SUPPORT_HEX &&
842 *lpszStr == '0' && tolower(lpszStr[1]) == 'x')
844 /* Read hex number */
845 lpszStr += 2;
847 if (!isxdigit(*lpszStr))
848 return FALSE;
850 while (isxdigit(*lpszStr))
852 iRet = iRet * 16;
853 if (isdigit(*lpszStr))
854 iRet += (*lpszStr - '0');
855 else
856 iRet += 10 + (tolower(*lpszStr) - 'a');
857 lpszStr++;
859 *lpiRet = iRet;
860 return TRUE;
863 /* Read decimal number */
864 if (!isdigit(*lpszStr))
865 return FALSE;
867 while (isdigit(*lpszStr))
869 iRet = iRet * 10;
870 iRet += (*lpszStr - '0');
871 lpszStr++;
873 *lpiRet = bNegative ? -iRet : iRet;
874 return TRUE;
877 /*************************************************************************
878 * StrToIntExW [SHLWAPI.@]
880 * See StrToIntExA.
882 BOOL WINAPI StrToIntExW(LPCWSTR lpszStr, DWORD dwFlags, LPINT lpiRet)
884 BOOL bNegative = FALSE;
885 int iRet = 0;
887 TRACE("(%s,%08X,%p)\n", debugstr_w(lpszStr), dwFlags, lpiRet);
889 if (!lpszStr || !lpiRet)
891 WARN("Invalid parameter would crash under Win32!\n");
892 return FALSE;
894 if (dwFlags > STIF_SUPPORT_HEX)
896 WARN("Unknown flags (%08lX)!\n", dwFlags & ~STIF_SUPPORT_HEX);
899 /* Skip leading space, '+', '-' */
900 while (isspaceW(*lpszStr))
901 lpszStr = CharNextW(lpszStr);
903 if (*lpszStr == '-')
905 bNegative = TRUE;
906 lpszStr++;
908 else if (*lpszStr == '+')
909 lpszStr++;
911 if (dwFlags & STIF_SUPPORT_HEX &&
912 *lpszStr == '0' && tolowerW(lpszStr[1]) == 'x')
914 /* Read hex number */
915 lpszStr += 2;
917 if (!isxdigitW(*lpszStr))
918 return FALSE;
920 while (isxdigitW(*lpszStr))
922 iRet = iRet * 16;
923 if (isdigitW(*lpszStr))
924 iRet += (*lpszStr - '0');
925 else
926 iRet += 10 + (tolowerW(*lpszStr) - 'a');
927 lpszStr++;
929 *lpiRet = iRet;
930 return TRUE;
933 /* Read decimal number */
934 if (!isdigitW(*lpszStr))
935 return FALSE;
937 while (isdigitW(*lpszStr))
939 iRet = iRet * 10;
940 iRet += (*lpszStr - '0');
941 lpszStr++;
943 *lpiRet = bNegative ? -iRet : iRet;
944 return TRUE;
947 /*************************************************************************
948 * StrDupA [SHLWAPI.@]
950 * Duplicate a string.
952 * PARAMS
953 * lpszStr [I] String to duplicate.
955 * RETURNS
956 * Success: A pointer to a new string containing the contents of lpszStr
957 * Failure: NULL, if memory cannot be allocated
959 * NOTES
960 * The string memory is allocated with LocalAlloc(), and so should be released
961 * by calling LocalFree().
963 LPSTR WINAPI StrDupA(LPCSTR lpszStr)
965 int iLen;
966 LPSTR lpszRet;
968 TRACE("(%s)\n",debugstr_a(lpszStr));
970 iLen = lpszStr ? strlen(lpszStr) + 1 : 1;
971 lpszRet = (LPSTR)LocalAlloc(LMEM_FIXED, iLen);
973 if (lpszRet)
975 if (lpszStr)
976 memcpy(lpszRet, lpszStr, iLen);
977 else
978 *lpszRet = '\0';
980 return lpszRet;
983 /*************************************************************************
984 * StrDupW [SHLWAPI.@]
986 * See StrDupA.
988 LPWSTR WINAPI StrDupW(LPCWSTR lpszStr)
990 int iLen;
991 LPWSTR lpszRet;
993 TRACE("(%s)\n",debugstr_w(lpszStr));
995 iLen = (lpszStr ? strlenW(lpszStr) + 1 : 1) * sizeof(WCHAR);
996 lpszRet = (LPWSTR)LocalAlloc(LMEM_FIXED, iLen);
998 if (lpszRet)
1000 if (lpszStr)
1001 memcpy(lpszRet, lpszStr, iLen);
1002 else
1003 *lpszRet = '\0';
1005 return lpszRet;
1008 /*************************************************************************
1009 * SHLWAPI_StrSpnHelperA
1011 * Internal implementation of StrSpnA/StrCSpnA/StrCSpnIA
1013 static int WINAPI SHLWAPI_StrSpnHelperA(LPCSTR lpszStr, LPCSTR lpszMatch,
1014 LPSTR (WINAPI *pStrChrFn)(LPCSTR,WORD),
1015 BOOL bInvert)
1017 LPCSTR lpszRead = lpszStr;
1018 if (lpszStr && *lpszStr && lpszMatch)
1020 while (*lpszRead)
1022 LPCSTR lpszTest = pStrChrFn(lpszMatch, *lpszRead);
1024 if (!bInvert && !lpszTest)
1025 break;
1026 if (bInvert && lpszTest)
1027 break;
1028 lpszRead = CharNextA(lpszRead);
1031 return lpszRead - lpszStr;
1034 /*************************************************************************
1035 * SHLWAPI_StrSpnHelperW
1037 * Internal implementation of StrSpnW/StrCSpnW/StrCSpnIW
1039 static int WINAPI SHLWAPI_StrSpnHelperW(LPCWSTR lpszStr, LPCWSTR lpszMatch,
1040 LPWSTR (WINAPI *pStrChrFn)(LPCWSTR,WCHAR),
1041 BOOL bInvert)
1043 LPCWSTR lpszRead = lpszStr;
1044 if (lpszStr && *lpszStr && lpszMatch)
1046 while (*lpszRead)
1048 LPCWSTR lpszTest = pStrChrFn(lpszMatch, *lpszRead);
1050 if (!bInvert && !lpszTest)
1051 break;
1052 if (bInvert && lpszTest)
1053 break;
1054 lpszRead = CharNextW(lpszRead);
1057 return lpszRead - lpszStr;
1060 /*************************************************************************
1061 * StrSpnA [SHLWAPI.@]
1063 * Find the length of the start of a string that contains only certain
1064 * characters.
1066 * PARAMS
1067 * lpszStr [I] String to search
1068 * lpszMatch [I] Characters that can be in the substring
1070 * RETURNS
1071 * The length of the part of lpszStr containing only chars from lpszMatch,
1072 * or 0 if any parameter is invalid.
1074 int WINAPI StrSpnA(LPCSTR lpszStr, LPCSTR lpszMatch)
1076 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1078 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, FALSE);
1081 /*************************************************************************
1082 * StrSpnW [SHLWAPI.@]
1084 * See StrSpnA.
1086 int WINAPI StrSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1088 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1090 return SHLWAPI_StrSpnHelperW(lpszStr, lpszMatch, StrChrW, FALSE);
1093 /*************************************************************************
1094 * StrCSpnA [SHLWAPI.@]
1096 * Find the length of the start of a string that does not contain certain
1097 * characters.
1099 * PARAMS
1100 * lpszStr [I] String to search
1101 * lpszMatch [I] Characters that cannot be in the substring
1103 * RETURNS
1104 * The length of the part of lpszStr containing only chars not in lpszMatch,
1105 * or 0 if any parameter is invalid.
1107 int WINAPI StrCSpnA(LPCSTR lpszStr, LPCSTR lpszMatch)
1109 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1111 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, TRUE);
1114 /*************************************************************************
1115 * StrCSpnW [SHLWAPI.@]
1117 * See StrCSpnA.
1119 int WINAPI StrCSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1121 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1123 return SHLWAPI_StrSpnHelperW(lpszStr, lpszMatch, StrChrW, TRUE);
1126 /*************************************************************************
1127 * StrCSpnIA [SHLWAPI.@]
1129 * Find the length of the start of a string that does not contain certain
1130 * characters, ignoring case.
1132 * PARAMS
1133 * lpszStr [I] String to search
1134 * lpszMatch [I] Characters that cannot be in the substring
1136 * RETURNS
1137 * The length of the part of lpszStr containing only chars not in lpszMatch,
1138 * or 0 if any parameter is invalid.
1140 int WINAPI StrCSpnIA(LPCSTR lpszStr, LPCSTR lpszMatch)
1142 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1144 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrIA, TRUE);
1147 /*************************************************************************
1148 * StrCSpnIW [SHLWAPI.@]
1150 * See StrCSpnIA.
1152 int WINAPI StrCSpnIW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1154 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1156 return SHLWAPI_StrSpnHelperW(lpszStr, lpszMatch, StrChrIW, TRUE);
1159 /*************************************************************************
1160 * StrPBrkA [SHLWAPI.@]
1162 * Search a string for any of a group of characters.
1164 * PARAMS
1165 * lpszStr [I] String to search
1166 * lpszMatch [I] Characters to match
1168 * RETURNS
1169 * A pointer to the first matching character in lpszStr, or NULL if no
1170 * match was found.
1172 LPSTR WINAPI StrPBrkA(LPCSTR lpszStr, LPCSTR lpszMatch)
1174 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1176 if (lpszStr && lpszMatch && *lpszMatch)
1178 while (*lpszStr)
1180 if (StrChrA(lpszMatch, *lpszStr))
1181 return (LPSTR)lpszStr;
1182 lpszStr = CharNextA(lpszStr);
1185 return NULL;
1188 /*************************************************************************
1189 * StrPBrkW [SHLWAPI.@]
1191 * See StrPBrkA.
1193 LPWSTR WINAPI StrPBrkW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1195 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1197 if (lpszStr && lpszMatch && *lpszMatch)
1199 while (*lpszStr)
1201 if (StrChrW(lpszMatch, *lpszStr))
1202 return (LPWSTR)lpszStr;
1203 lpszStr = CharNextW(lpszStr);
1206 return NULL;
1209 /*************************************************************************
1210 * SHLWAPI_StrRChrHelperA
1212 * Internal implementation of StrRChrA/StrRChrIA.
1214 static LPSTR WINAPI SHLWAPI_StrRChrHelperA(LPCSTR lpszStr,
1215 LPCSTR lpszEnd, WORD ch,
1216 BOOL (WINAPI *pChrCmpFn)(WORD,WORD))
1218 LPCSTR lpszRet = NULL;
1220 if (lpszStr)
1222 WORD ch2;
1224 if (!lpszEnd)
1225 lpszEnd = lpszStr + lstrlenA(lpszStr);
1227 while (*lpszStr && lpszStr <= lpszEnd)
1229 ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr;
1231 if (!pChrCmpFn(ch, ch2))
1232 lpszRet = lpszStr;
1233 lpszStr = CharNextA(lpszStr);
1236 return (LPSTR)lpszRet;
1239 /*************************************************************************
1240 * SHLWAPI_StrRChrHelperW
1242 * Internal implementation of StrRChrW/StrRChrIW.
1244 static LPWSTR WINAPI SHLWAPI_StrRChrHelperW(LPCWSTR lpszStr,
1245 LPCWSTR lpszEnd, WCHAR ch,
1246 BOOL (WINAPI *pChrCmpFn)(WCHAR,WCHAR))
1248 LPCWSTR lpszRet = NULL;
1250 if (lpszStr)
1252 if (!lpszEnd)
1253 lpszEnd = lpszStr + strlenW(lpszStr);
1255 while (*lpszStr && lpszStr <= lpszEnd)
1257 if (!pChrCmpFn(ch, *lpszStr))
1258 lpszRet = lpszStr;
1259 lpszStr = CharNextW(lpszStr);
1262 return (LPWSTR)lpszRet;
1265 /**************************************************************************
1266 * StrRChrA [SHLWAPI.@]
1268 * Find the last occurrence of a character in string.
1270 * PARAMS
1271 * lpszStr [I] String to search in
1272 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1273 * ch [I] Character to search for.
1275 * RETURNS
1276 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1277 * or NULL if not found.
1278 * Failure: NULL, if any arguments are invalid.
1280 LPSTR WINAPI StrRChrA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch)
1282 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch);
1284 return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, SHLWAPI_ChrCmpA);
1287 /**************************************************************************
1288 * StrRChrW [SHLWAPI.@]
1290 * See StrRChrA.
1292 LPWSTR WINAPI StrRChrW(LPCWSTR lpszStr, LPCWSTR lpszEnd, WORD ch)
1294 TRACE("(%s,%s,%x)\n", debugstr_w(lpszStr), debugstr_w(lpszEnd), ch);
1296 return SHLWAPI_StrRChrHelperW(lpszStr, lpszEnd, ch, SHLWAPI_ChrCmpW);
1299 /**************************************************************************
1300 * StrRChrIA [SHLWAPI.@]
1302 * Find the last occurrence of a character in string, ignoring case.
1304 * PARAMS
1305 * lpszStr [I] String to search in
1306 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1307 * ch [I] Character to search for.
1309 * RETURNS
1310 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1311 * or NULL if not found.
1312 * Failure: NULL, if any arguments are invalid.
1314 LPSTR WINAPI StrRChrIA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch)
1316 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch);
1318 return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, ChrCmpIA);
1321 /**************************************************************************
1322 * StrRChrIW [SHLWAPI.@]
1324 * See StrRChrIA.
1326 LPWSTR WINAPI StrRChrIW(LPCWSTR lpszStr, LPCWSTR lpszEnd, WORD ch)
1328 TRACE("(%s,%s,%x)\n", debugstr_w(lpszStr), debugstr_w(lpszEnd), ch);
1330 return SHLWAPI_StrRChrHelperW(lpszStr, lpszEnd, ch, ChrCmpIW);
1333 /*************************************************************************
1334 * StrCatBuffA [SHLWAPI.@]
1336 * Concatenate two strings together.
1338 * PARAMS
1339 * lpszStr [O] String to concatenate to
1340 * lpszCat [I] String to add to lpszCat
1341 * cchMax [I] Maximum number of characters for the whole string
1343 * RETURNS
1344 * lpszStr.
1346 * NOTES
1347 * cchMax determines the number of characters in the final length of the
1348 * string, not the number appended to lpszStr from lpszCat.
1350 LPSTR WINAPI StrCatBuffA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax)
1352 INT iLen;
1354 TRACE("(%p,%s,%d)\n", lpszStr, debugstr_a(lpszCat), cchMax);
1356 if (!lpszStr)
1358 WARN("Invalid lpszStr would crash under Win32!\n");
1359 return NULL;
1362 iLen = strlen(lpszStr);
1363 cchMax -= iLen;
1365 if (cchMax > 0)
1366 StrCpyNA(lpszStr + iLen, lpszCat, cchMax);
1367 return lpszStr;
1370 /*************************************************************************
1371 * StrCatBuffW [SHLWAPI.@]
1373 * See StrCatBuffA.
1375 LPWSTR WINAPI StrCatBuffW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax)
1377 INT iLen;
1379 TRACE("(%p,%s,%d)\n", lpszStr, debugstr_w(lpszCat), cchMax);
1381 if (!lpszStr)
1383 WARN("Invalid lpszStr would crash under Win32!\n");
1384 return NULL;
1387 iLen = strlenW(lpszStr);
1388 cchMax -= iLen;
1390 if (cchMax > 0)
1391 StrCpyNW(lpszStr + iLen, lpszCat, cchMax);
1392 return lpszStr;
1395 /*************************************************************************
1396 * StrRetToBufA [SHLWAPI.@]
1398 * Convert a STRRET to a normal string.
1400 * PARAMS
1401 * lpStrRet [O] STRRET to convert
1402 * pIdl [I] ITEMIDLIST for lpStrRet->uType == STRRET_OFFSET
1403 * lpszDest [O] Destination for normal string
1404 * dwLen [I] Length of lpszDest
1406 * RETURNS
1407 * Success: S_OK. lpszDest contains up to dwLen characters of the string.
1408 * If lpStrRet is of type STRRET_WSTR, its memory is freed with
1409 * CoTaskMemFree() and its type set to STRRET_CSTRA.
1410 * Failure: E_FAIL, if any parameters are invalid.
1412 HRESULT WINAPI StrRetToBufA (LPSTRRET src, const ITEMIDLIST *pidl, LPSTR dest, UINT len)
1414 /* NOTE:
1415 * This routine is identical to that in dlls/shell32/shellstring.c.
1416 * It was duplicated because not every version of Shlwapi.dll exports
1417 * StrRetToBufA. If you change one routine, change them both.
1419 TRACE("dest=%p len=0x%x strret=%p pidl=%p stub\n",dest,len,src,pidl);
1421 if (!src)
1423 WARN("Invalid lpStrRet would crash under Win32!\n");
1424 if (dest)
1425 *dest = '\0';
1426 return E_FAIL;
1429 if (!dest || !len)
1430 return E_FAIL;
1432 *dest = '\0';
1434 switch (src->uType)
1436 case STRRET_WSTR:
1437 WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, dest, len, NULL, NULL);
1438 CoTaskMemFree(src->u.pOleStr);
1439 break;
1441 case STRRET_CSTR:
1442 lstrcpynA((LPSTR)dest, src->u.cStr, len);
1443 break;
1445 case STRRET_OFFSET:
1446 lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len);
1447 break;
1449 default:
1450 FIXME("unknown type!\n");
1451 return FALSE;
1453 return S_OK;
1456 /*************************************************************************
1457 * StrRetToBufW [SHLWAPI.@]
1459 * See StrRetToBufA.
1461 HRESULT WINAPI StrRetToBufW (LPSTRRET src, const ITEMIDLIST *pidl, LPWSTR dest, UINT len)
1463 TRACE("dest=%p len=0x%x strret=%p pidl=%p stub\n",dest,len,src,pidl);
1465 if (!src)
1467 WARN("Invalid lpStrRet would crash under Win32!\n");
1468 if (dest)
1469 *dest = '\0';
1470 return E_FAIL;
1473 if (!dest || !len)
1474 return E_FAIL;
1476 *dest = '\0';
1478 switch (src->uType)
1480 case STRRET_WSTR:
1481 lstrcpynW((LPWSTR)dest, src->u.pOleStr, len);
1482 CoTaskMemFree(src->u.pOleStr);
1483 break;
1485 case STRRET_CSTR:
1486 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
1487 dest[len-1] = 0;
1488 break;
1490 case STRRET_OFFSET:
1491 if (pidl)
1493 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1,
1494 dest, len ) && len)
1495 dest[len-1] = 0;
1497 break;
1499 default:
1500 FIXME("unknown type!\n");
1501 return FALSE;
1503 return S_OK;
1506 /*************************************************************************
1507 * StrRetToStrA [SHLWAPI.@]
1509 * Converts a STRRET to a normal string.
1511 * PARAMS
1512 * lpStrRet [O] STRRET to convert
1513 * pidl [I] ITEMIDLIST for lpStrRet->uType == STRRET_OFFSET
1514 * ppszName [O] Destination for converted string
1516 * RETURNS
1517 * Success: S_OK. ppszName contains the new string, allocated with CoTaskMemAlloc().
1518 * Failure: E_FAIL, if any parameters are invalid.
1520 HRESULT WINAPI StrRetToStrA(LPSTRRET lpStrRet, const ITEMIDLIST *pidl, LPSTR *ppszName)
1522 HRESULT hRet = E_FAIL;
1524 switch (lpStrRet->uType)
1526 case STRRET_WSTR:
1527 hRet = _SHStrDupAW(lpStrRet->u.pOleStr, ppszName);
1528 CoTaskMemFree(lpStrRet->u.pOleStr);
1529 break;
1531 case STRRET_CSTR:
1532 hRet = _SHStrDupAA(lpStrRet->u.cStr, ppszName);
1533 break;
1535 case STRRET_OFFSET:
1536 hRet = _SHStrDupAA(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, ppszName);
1537 break;
1539 default:
1540 *ppszName = NULL;
1543 return hRet;
1546 /*************************************************************************
1547 * StrRetToStrW [SHLWAPI.@]
1549 * See StrRetToStrA.
1551 HRESULT WINAPI StrRetToStrW(LPSTRRET lpStrRet, const ITEMIDLIST *pidl, LPWSTR *ppszName)
1553 HRESULT hRet = E_FAIL;
1555 switch (lpStrRet->uType)
1557 case STRRET_WSTR:
1558 hRet = SHStrDupW(lpStrRet->u.pOleStr, ppszName);
1559 CoTaskMemFree(lpStrRet->u.pOleStr);
1560 break;
1562 case STRRET_CSTR:
1563 hRet = SHStrDupA(lpStrRet->u.cStr, ppszName);
1564 break;
1566 case STRRET_OFFSET:
1567 hRet = SHStrDupA(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, ppszName);
1568 break;
1570 default:
1571 *ppszName = NULL;
1574 return hRet;
1577 /* Create an ASCII string copy using SysAllocString() */
1578 static HRESULT _SHStrDupAToBSTR(LPCSTR src, BSTR *pBstrOut)
1580 *pBstrOut = NULL;
1582 if (src)
1584 INT len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0);
1585 WCHAR* szTemp = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1587 if (szTemp)
1589 MultiByteToWideChar(CP_ACP, 0, src, -1, szTemp, len);
1590 *pBstrOut = SysAllocString(szTemp);
1591 HeapFree(GetProcessHeap(), 0, szTemp);
1593 if (*pBstrOut)
1594 return S_OK;
1597 return E_OUTOFMEMORY;
1600 /*************************************************************************
1601 * StrRetToBSTR [SHLWAPI.@]
1603 * Converts a STRRET to a BSTR.
1605 * PARAMS
1606 * lpStrRet [O] STRRET to convert
1607 * pidl [I] ITEMIDLIST for lpStrRet->uType = STRRET_OFFSET
1608 * pBstrOut [O] Destination for converted BSTR
1610 * RETURNS
1611 * Success: S_OK. pBstrOut contains the new string.
1612 * Failure: E_FAIL, if any parameters are invalid.
1614 HRESULT WINAPI StrRetToBSTR(STRRET *lpStrRet, LPCITEMIDLIST pidl, BSTR* pBstrOut)
1616 HRESULT hRet = E_FAIL;
1618 switch (lpStrRet->uType)
1620 case STRRET_WSTR:
1621 *pBstrOut = SysAllocString(lpStrRet->u.pOleStr);
1622 if (*pBstrOut)
1623 hRet = S_OK;
1624 CoTaskMemFree(lpStrRet->u.pOleStr);
1625 break;
1627 case STRRET_CSTR:
1628 hRet = _SHStrDupAToBSTR(lpStrRet->u.cStr, pBstrOut);
1629 break;
1631 case STRRET_OFFSET:
1632 hRet = _SHStrDupAToBSTR(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, pBstrOut);
1633 break;
1635 default:
1636 *pBstrOut = NULL;
1639 return hRet;
1642 /*************************************************************************
1643 * StrFormatKBSizeA [SHLWAPI.@]
1645 * Create a formatted string containing a byte count in Kilobytes.
1647 * PARAMS
1648 * llBytes [I] Byte size to format
1649 * lpszDest [I] Destination for formatted string
1650 * cchMax [I] Size of lpszDest
1652 * RETURNS
1653 * lpszDest.
1655 LPSTR WINAPI StrFormatKBSizeA(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax)
1657 WCHAR wszBuf[256];
1659 if (!StrFormatKBSizeW(llBytes, wszBuf, 256))
1660 return NULL;
1661 if (!WideCharToMultiByte(CP_ACP, 0, wszBuf, -1, lpszDest, cchMax, NULL, NULL))
1662 return NULL;
1663 return lpszDest;
1666 /*************************************************************************
1667 * StrFormatKBSizeW [SHLWAPI.@]
1669 * See StrFormatKBSizeA.
1671 LPWSTR WINAPI StrFormatKBSizeW(LONGLONG llBytes, LPWSTR lpszDest, UINT cchMax)
1673 static const WCHAR kb[] = {' ','K','B',0};
1674 LONGLONG llKB = (llBytes + 1023) >> 10;
1675 int len;
1677 TRACE("(0x%s,%p,%d)\n", wine_dbgstr_longlong(llBytes), lpszDest, cchMax);
1679 if (!FormatInt(llKB, lpszDest, cchMax))
1680 return NULL;
1682 len = lstrlenW(lpszDest);
1683 if (cchMax - len < 4)
1684 return NULL;
1685 lstrcatW(lpszDest, kb);
1686 return lpszDest;
1689 /*************************************************************************
1690 * StrNCatA [SHLWAPI.@]
1692 * Concatenate two strings together.
1694 * PARAMS
1695 * lpszStr [O] String to concatenate to
1696 * lpszCat [I] String to add to lpszCat
1697 * cchMax [I] Maximum number of characters to concatenate
1699 * RETURNS
1700 * lpszStr.
1702 * NOTES
1703 * cchMax determines the number of characters that are appended to lpszStr,
1704 * not the total length of the string.
1706 LPSTR WINAPI StrNCatA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax)
1708 LPSTR lpszRet = lpszStr;
1710 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszCat), cchMax);
1712 if (!lpszStr)
1714 WARN("Invalid lpszStr would crash under Win32!\n");
1715 return NULL;
1718 StrCpyNA(lpszStr + strlen(lpszStr), lpszCat, cchMax);
1719 return lpszRet;
1722 /*************************************************************************
1723 * StrNCatW [SHLWAPI.@]
1725 * See StrNCatA.
1727 LPWSTR WINAPI StrNCatW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax)
1729 LPWSTR lpszRet = lpszStr;
1731 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszCat), cchMax);
1733 if (!lpszStr)
1735 WARN("Invalid lpszStr would crash under Win32\n");
1736 return NULL;
1739 StrCpyNW(lpszStr + strlenW(lpszStr), lpszCat, cchMax);
1740 return lpszRet;
1743 /*************************************************************************
1744 * StrTrimA [SHLWAPI.@]
1746 * Remove characters from the start and end of a string.
1748 * PARAMS
1749 * lpszStr [O] String to remove characters from
1750 * lpszTrim [I] Characters to remove from lpszStr
1752 * RETURNS
1753 * TRUE If lpszStr was valid and modified
1754 * FALSE Otherwise
1756 BOOL WINAPI StrTrimA(LPSTR lpszStr, LPCSTR lpszTrim)
1758 DWORD dwLen;
1759 LPSTR lpszRead = lpszStr;
1760 BOOL bRet = FALSE;
1762 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszTrim));
1764 if (lpszRead && *lpszRead)
1766 while (*lpszRead && StrChrA(lpszTrim, *lpszRead))
1767 lpszRead = CharNextA(lpszRead); /* Skip leading matches */
1769 dwLen = strlen(lpszRead);
1771 if (lpszRead != lpszStr)
1773 memmove(lpszStr, lpszRead, dwLen + 1);
1774 bRet = TRUE;
1776 if (dwLen > 0)
1778 lpszRead = lpszStr + dwLen;
1779 while (StrChrA(lpszTrim, lpszRead[-1]))
1780 lpszRead = CharPrevA(lpszStr, lpszRead); /* Skip trailing matches */
1782 if (lpszRead != lpszStr + dwLen)
1784 *lpszRead = '\0';
1785 bRet = TRUE;
1789 return bRet;
1792 /*************************************************************************
1793 * StrTrimW [SHLWAPI.@]
1795 * See StrTrimA.
1797 BOOL WINAPI StrTrimW(LPWSTR lpszStr, LPCWSTR lpszTrim)
1799 DWORD dwLen;
1800 LPWSTR lpszRead = lpszStr;
1801 BOOL bRet = FALSE;
1803 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszTrim));
1805 if (lpszRead && *lpszRead)
1807 while (*lpszRead && StrChrW(lpszTrim, *lpszRead))
1808 lpszRead = CharNextW(lpszRead); /* Skip leading matches */
1810 dwLen = strlenW(lpszRead);
1812 if (lpszRead != lpszStr)
1814 memmove(lpszStr, lpszRead, (dwLen + 1) * sizeof(WCHAR));
1815 bRet = TRUE;
1817 if (dwLen > 0)
1819 lpszRead = lpszStr + dwLen;
1820 while (StrChrW(lpszTrim, lpszRead[-1]))
1821 lpszRead = CharPrevW(lpszStr, lpszRead); /* Skip trailing matches */
1823 if (lpszRead != lpszStr + dwLen)
1825 *lpszRead = '\0';
1826 bRet = TRUE;
1830 return bRet;
1833 /*************************************************************************
1834 * _SHStrDupAA [INTERNAL]
1836 * Duplicates a ASCII string to ASCII. The destination buffer is allocated.
1838 static HRESULT WINAPI _SHStrDupAA(LPCSTR src, LPSTR * dest)
1840 HRESULT hr;
1841 int len = 0;
1843 if (src) {
1844 len = lstrlenA(src) + 1;
1845 *dest = CoTaskMemAlloc(len);
1846 } else {
1847 *dest = NULL;
1850 if (*dest) {
1851 lstrcpynA(*dest,src, len);
1852 hr = S_OK;
1853 } else {
1854 hr = E_OUTOFMEMORY;
1857 TRACE("%s->(%p)\n", debugstr_a(src), *dest);
1858 return hr;
1861 /*************************************************************************
1862 * SHStrDupA [SHLWAPI.@]
1864 * Return a Unicode copy of a string, in memory allocated by CoTaskMemAlloc().
1866 * PARAMS
1867 * lpszStr [I] String to copy
1868 * lppszDest [O] Destination for the new string copy
1870 * RETURNS
1871 * Success: S_OK. lppszDest contains the new string in Unicode format.
1872 * Failure: E_OUTOFMEMORY, If any arguments are invalid or memory allocation
1873 * fails.
1875 HRESULT WINAPI SHStrDupA(LPCSTR lpszStr, LPWSTR * lppszDest)
1877 HRESULT hRet;
1878 int len = 0;
1880 if (lpszStr)
1882 len = MultiByteToWideChar(0, 0, lpszStr, -1, 0, 0) * sizeof(WCHAR);
1883 *lppszDest = CoTaskMemAlloc(len);
1885 else
1886 *lppszDest = NULL;
1888 if (*lppszDest)
1890 MultiByteToWideChar(0, 0, lpszStr, -1, *lppszDest, len/sizeof(WCHAR));
1891 hRet = S_OK;
1893 else
1894 hRet = E_OUTOFMEMORY;
1896 TRACE("%s->(%p)\n", debugstr_a(lpszStr), *lppszDest);
1897 return hRet;
1900 /*************************************************************************
1901 * _SHStrDupAW [INTERNAL]
1903 * Duplicates a UNICODE to a ASCII string. The destination buffer is allocated.
1905 static HRESULT WINAPI _SHStrDupAW(LPCWSTR src, LPSTR * dest)
1907 HRESULT hr;
1908 int len = 0;
1910 if (src) {
1911 len = WideCharToMultiByte(CP_ACP, 0, src, -1, NULL, 0, NULL, NULL);
1912 *dest = CoTaskMemAlloc(len);
1913 } else {
1914 *dest = NULL;
1917 if (*dest) {
1918 WideCharToMultiByte(CP_ACP, 0, src, -1, *dest, len, NULL, NULL);
1919 hr = S_OK;
1920 } else {
1921 hr = E_OUTOFMEMORY;
1924 TRACE("%s->(%p)\n", debugstr_w(src), *dest);
1925 return hr;
1928 /*************************************************************************
1929 * SHStrDupW [SHLWAPI.@]
1931 * See SHStrDupA.
1933 HRESULT WINAPI SHStrDupW(LPCWSTR src, LPWSTR * dest)
1935 HRESULT hr;
1936 int len = 0;
1938 if (src) {
1939 len = (lstrlenW(src) + 1) * sizeof(WCHAR);
1940 *dest = CoTaskMemAlloc(len);
1941 } else {
1942 *dest = NULL;
1945 if (*dest) {
1946 memcpy(*dest, src, len);
1947 hr = S_OK;
1948 } else {
1949 hr = E_OUTOFMEMORY;
1952 TRACE("%s->(%p)\n", debugstr_w(src), *dest);
1953 return hr;
1956 /*************************************************************************
1957 * SHLWAPI_WriteReverseNum
1959 * Internal helper for SHLWAPI_WriteTimeClass.
1961 inline static LPWSTR SHLWAPI_WriteReverseNum(LPWSTR lpszOut, DWORD dwNum)
1963 *lpszOut-- = '\0';
1965 /* Write a decimal number to a string, backwards */
1968 DWORD dwNextDigit = dwNum % 10;
1969 *lpszOut-- = '0' + dwNextDigit;
1970 dwNum = (dwNum - dwNextDigit) / 10;
1971 } while (dwNum > 0);
1973 return lpszOut;
1976 /*************************************************************************
1977 * SHLWAPI_FormatSignificant
1979 * Internal helper for SHLWAPI_WriteTimeClass.
1981 inline static int SHLWAPI_FormatSignificant(LPWSTR lpszNum, int dwDigits)
1983 /* Zero non significant digits, return remaining significant digits */
1984 while (*lpszNum)
1986 lpszNum++;
1987 if (--dwDigits == 0)
1989 while (*lpszNum)
1990 *lpszNum++ = '0';
1991 return 0;
1994 return dwDigits;
1997 /*************************************************************************
1998 * SHLWAPI_WriteTimeClass
2000 * Internal helper for StrFromTimeIntervalW.
2002 static int WINAPI SHLWAPI_WriteTimeClass(LPWSTR lpszOut, DWORD dwValue,
2003 UINT uClassStringId, int iDigits)
2005 WCHAR szBuff[64], *szOut = szBuff + 32;
2007 szOut = SHLWAPI_WriteReverseNum(szOut, dwValue);
2008 iDigits = SHLWAPI_FormatSignificant(szOut + 1, iDigits);
2009 *szOut = ' ';
2010 LoadStringW(shlwapi_hInstance, uClassStringId, szBuff + 32, 32);
2011 strcatW(lpszOut, szOut);
2012 return iDigits;
2015 /*************************************************************************
2016 * StrFromTimeIntervalA [SHLWAPI.@]
2018 * Format a millisecond time interval into a string
2020 * PARAMS
2021 * lpszStr [O] Output buffer for formatted time interval
2022 * cchMax [I] Size of lpszStr
2023 * dwMS [I] Number of milliseconds
2024 * iDigits [I] Number of digits to print
2026 * RETURNS
2027 * The length of the formatted string, or 0 if any parameter is invalid.
2029 * NOTES
2030 * This implementation mimics the Win32 behaviour of always writing a leading
2031 * space before the time interval begins.
2033 * iDigits is used to provide approximate times if accuracy is not important.
2034 * This number of digits will be written of the first non-zero time class
2035 * (hours/minutes/seconds). If this does not complete the time classification,
2036 * the remaining digits are changed to zeros (i.e. The time is _not_ rounded).
2037 * If there are digits remaining following the writing of a time class, the
2038 * next time class will be written.
2040 * For example, given dwMS represents 138 hours,43 minutes and 15 seconds, the
2041 * following will result from the given values of iDigits:
2043 *| iDigits 1 2 3 4 5 ...
2044 *| lpszStr "100 hr" "130 hr" "138 hr" "138 hr 40 min" "138 hr 43 min" ...
2046 INT WINAPI StrFromTimeIntervalA(LPSTR lpszStr, UINT cchMax, DWORD dwMS,
2047 int iDigits)
2049 INT iRet = 0;
2051 TRACE("(%p,%d,%d,%d)\n", lpszStr, cchMax, dwMS, iDigits);
2053 if (lpszStr && cchMax)
2055 WCHAR szBuff[128];
2056 StrFromTimeIntervalW(szBuff, sizeof(szBuff)/sizeof(WCHAR), dwMS, iDigits);
2057 WideCharToMultiByte(CP_ACP,0,szBuff,-1,lpszStr,cchMax,0,0);
2059 return iRet;
2063 /*************************************************************************
2064 * StrFromTimeIntervalW [SHLWAPI.@]
2066 * See StrFromTimeIntervalA.
2068 INT WINAPI StrFromTimeIntervalW(LPWSTR lpszStr, UINT cchMax, DWORD dwMS,
2069 int iDigits)
2071 INT iRet = 0;
2073 TRACE("(%p,%d,%d,%d)\n", lpszStr, cchMax, dwMS, iDigits);
2075 if (lpszStr && cchMax)
2077 WCHAR szCopy[128];
2078 DWORD dwHours, dwMinutes;
2080 if (!iDigits || cchMax == 1)
2082 *lpszStr = '\0';
2083 return 0;
2086 /* Calculate the time classes */
2087 dwMS = (dwMS + 500) / 1000;
2088 dwHours = dwMS / 3600;
2089 dwMS -= dwHours * 3600;
2090 dwMinutes = dwMS / 60;
2091 dwMS -= dwMinutes * 60;
2093 szCopy[0] = '\0';
2095 if (dwHours)
2096 iDigits = SHLWAPI_WriteTimeClass(szCopy, dwHours, IDS_TIME_INTERVAL_HOURS, iDigits);
2098 if (dwMinutes && iDigits)
2099 iDigits = SHLWAPI_WriteTimeClass(szCopy, dwMinutes, IDS_TIME_INTERVAL_MINUTES, iDigits);
2101 if (iDigits) /* Always write seconds if we have significant digits */
2102 SHLWAPI_WriteTimeClass(szCopy, dwMS, IDS_TIME_INTERVAL_SECONDS, iDigits);
2104 lstrcpynW(lpszStr, szCopy, cchMax);
2105 iRet = strlenW(lpszStr);
2107 return iRet;
2110 /*************************************************************************
2111 * StrIsIntlEqualA [SHLWAPI.@]
2113 * Compare two strings.
2115 * PARAMS
2116 * bCase [I] Whether to compare case sensitively
2117 * lpszStr [I] First string to compare
2118 * lpszComp [I] Second string to compare
2119 * iLen [I] Length to compare
2121 * RETURNS
2122 * TRUE If the strings are equal.
2123 * FALSE Otherwise.
2125 BOOL WINAPI StrIsIntlEqualA(BOOL bCase, LPCSTR lpszStr, LPCSTR lpszComp,
2126 int iLen)
2128 DWORD dwFlags;
2130 TRACE("(%d,%s,%s,%d)\n", bCase,
2131 debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
2133 /* FIXME: This flag is undocumented and unknown by our CompareString.
2134 * We need a define for it.
2136 dwFlags = 0x10000000;
2137 if (!bCase) dwFlags |= NORM_IGNORECASE;
2139 return (CompareStringA(GetThreadLocale(), dwFlags, lpszStr, iLen, lpszComp, iLen) == CSTR_EQUAL);
2142 /*************************************************************************
2143 * StrIsIntlEqualW [SHLWAPI.@]
2145 * See StrIsIntlEqualA.
2147 BOOL WINAPI StrIsIntlEqualW(BOOL bCase, LPCWSTR lpszStr, LPCWSTR lpszComp,
2148 int iLen)
2150 DWORD dwFlags;
2152 TRACE("(%d,%s,%s,%d)\n", bCase,
2153 debugstr_w(lpszStr),debugstr_w(lpszComp), iLen);
2155 /* FIXME: This flag is undocumented and unknown by our CompareString.
2156 * We need a define for it.
2158 dwFlags = 0x10000000;
2159 if (!bCase) dwFlags |= NORM_IGNORECASE;
2161 return (CompareStringW(GetThreadLocale(), dwFlags, lpszStr, iLen, lpszComp, iLen) == CSTR_EQUAL);
2164 /*************************************************************************
2165 * @ [SHLWAPI.399]
2167 * Copy a string to another string, up to a maximum number of characters.
2169 * PARAMS
2170 * lpszDest [O] Destination string
2171 * lpszSrc [I] Source string
2172 * iLen [I] Maximum number of chars to copy
2174 * RETURNS
2175 * Success: A pointer to the last character written to lpszDest..
2176 * Failure: lpszDest, if any arguments are invalid.
2178 LPSTR WINAPI StrCpyNXA(LPSTR lpszDest, LPCSTR lpszSrc, int iLen)
2180 TRACE("(%p,%s,%i)\n", lpszDest, debugstr_a(lpszSrc), iLen);
2182 if (lpszDest && lpszSrc && iLen > 0)
2184 while ((iLen-- > 1) && *lpszSrc)
2185 *lpszDest++ = *lpszSrc++;
2186 if (iLen >= 0)
2187 *lpszDest = '\0';
2189 return lpszDest;
2192 /*************************************************************************
2193 * @ [SHLWAPI.400]
2195 * Unicode version of StrCpyNXA.
2197 LPWSTR WINAPI StrCpyNXW(LPWSTR lpszDest, LPCWSTR lpszSrc, int iLen)
2199 TRACE("(%p,%s,%i)\n", lpszDest, debugstr_w(lpszSrc), iLen);
2201 if (lpszDest && lpszSrc && iLen > 0)
2203 while ((iLen-- > 1) && *lpszSrc)
2204 *lpszDest++ = *lpszSrc++;
2205 if (iLen >= 0)
2206 *lpszDest = '\0';
2208 return lpszDest;
2211 /*************************************************************************
2212 * StrCmpLogicalW [SHLWAPI.@]
2214 * Compare two strings, ignoring case and comparing digits as numbers.
2216 * PARAMS
2217 * lpszStr [I] First string to compare
2218 * lpszComp [I] Second string to compare
2219 * iLen [I] Length to compare
2221 * RETURNS
2222 * TRUE If the strings are equal.
2223 * FALSE Otherwise.
2225 INT WINAPI StrCmpLogicalW(LPCWSTR lpszStr, LPCWSTR lpszComp)
2227 INT iDiff;
2229 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszComp));
2231 if (lpszStr && lpszComp)
2233 while (*lpszStr)
2235 if (!*lpszComp)
2236 return 1;
2237 else if (isdigitW(*lpszStr))
2239 int iStr, iComp;
2241 if (!isdigitW(*lpszComp))
2242 return -1;
2244 /* Compare the numbers */
2245 StrToIntExW(lpszStr, 0, &iStr);
2246 StrToIntExW(lpszComp, 0, &iComp);
2248 if (iStr < iComp)
2249 return -1;
2250 else if (iStr > iComp)
2251 return 1;
2253 /* Skip */
2254 while (isdigitW(*lpszStr))
2255 lpszStr++;
2256 while (isdigitW(*lpszComp))
2257 lpszComp++;
2259 else if (isdigitW(*lpszComp))
2260 return 1;
2261 else
2263 iDiff = SHLWAPI_ChrCmpHelperW(*lpszStr,*lpszComp,NORM_IGNORECASE);
2264 if (iDiff > 0)
2265 return 1;
2266 else if (iDiff < 0)
2267 return -1;
2269 lpszStr++;
2270 lpszComp++;
2273 if (*lpszComp)
2274 return -1;
2276 return 0;
2279 /* Structure for formatting byte strings */
2280 typedef struct tagSHLWAPI_BYTEFORMATS
2282 LONGLONG dLimit;
2283 double dDivisor;
2284 double dNormaliser;
2285 int nDecimals;
2286 WCHAR wPrefix;
2287 } SHLWAPI_BYTEFORMATS;
2289 /*************************************************************************
2290 * StrFormatByteSizeW [SHLWAPI.@]
2292 * Create a string containing an abbreviated byte count of up to 2^63-1.
2294 * PARAMS
2295 * llBytes [I] Byte size to format
2296 * lpszDest [I] Destination for formatted string
2297 * cchMax [I] Size of lpszDest
2299 * RETURNS
2300 * lpszDest.
2302 * NOTES
2303 * There is no StrFormatByteSize64W function, it is called StrFormatByteSizeW().
2305 LPWSTR WINAPI StrFormatByteSizeW(LONGLONG llBytes, LPWSTR lpszDest, UINT cchMax)
2307 #define KB ((ULONGLONG)1024)
2308 #define MB (KB*KB)
2309 #define GB (KB*KB*KB)
2310 #define TB (KB*KB*KB*KB)
2311 #define PB (KB*KB*KB*KB*KB)
2313 static const SHLWAPI_BYTEFORMATS bfFormats[] =
2315 { 10*KB, 10.24, 100.0, 2, 'K' }, /* 10 KB */
2316 { 100*KB, 102.4, 10.0, 1, 'K' }, /* 100 KB */
2317 { 1000*KB, 1024.0, 1.0, 0, 'K' }, /* 1000 KB */
2318 { 10*MB, 10485.76, 100.0, 2, 'M' }, /* 10 MB */
2319 { 100*MB, 104857.6, 10.0, 1, 'M' }, /* 100 MB */
2320 { 1000*MB, 1048576.0, 1.0, 0, 'M' }, /* 1000 MB */
2321 { 10*GB, 10737418.24, 100.0, 2, 'G' }, /* 10 GB */
2322 { 100*GB, 107374182.4, 10.0, 1, 'G' }, /* 100 GB */
2323 { 1000*GB, 1073741824.0, 1.0, 0, 'G' }, /* 1000 GB */
2324 { 10*TB, 10485.76, 100.0, 2, 'T' }, /* 10 TB */
2325 { 100*TB, 104857.6, 10.0, 1, 'T' }, /* 100 TB */
2326 { 1000*TB, 1048576.0, 1.0, 0, 'T' }, /* 1000 TB */
2327 { 10*PB, 10737418.24, 100.00, 2, 'P' }, /* 10 PB */
2328 { 100*PB, 107374182.4, 10.00, 1, 'P' }, /* 100 PB */
2329 { 1000*PB, 1073741824.0, 1.00, 0, 'P' }, /* 1000 PB */
2330 { 0, 10995116277.76, 100.00, 2, 'E' } /* EB's, catch all */
2332 WCHAR wszAdd[] = {' ','?','B',0};
2333 double dBytes;
2334 UINT i = 0;
2336 TRACE("(0x%s,%p,%d)\n", wine_dbgstr_longlong(llBytes), lpszDest, cchMax);
2338 if (!lpszDest || !cchMax)
2339 return lpszDest;
2341 if (llBytes < 1024) /* 1K */
2343 WCHAR wszBytesFormat[64];
2344 LoadStringW(shlwapi_hInstance, IDS_BYTES_FORMAT, wszBytesFormat, 64);
2345 snprintfW(lpszDest, cchMax, wszBytesFormat, (long)llBytes);
2346 return lpszDest;
2349 /* Note that if this loop completes without finding a match, i will be
2350 * pointing at the last entry, which is a catch all for > 1000 PB
2352 while (i < sizeof(bfFormats) / sizeof(SHLWAPI_BYTEFORMATS) - 1)
2354 if (llBytes < bfFormats[i].dLimit)
2355 break;
2356 i++;
2358 /* Above 1 TB we encounter problems with FP accuracy. So for amounts above
2359 * this number we integer shift down by 1 MB first. The table above has
2360 * the divisors scaled down from the '< 10 TB' entry onwards, to account
2361 * for this. We also add a small fudge factor to get the correct result for
2362 * counts that lie exactly on a 1024 byte boundary.
2364 if (i > 8)
2365 dBytes = (double)(llBytes >> 20) + 0.001; /* Scale down by I MB */
2366 else
2367 dBytes = (double)llBytes + 0.00001;
2369 dBytes = floor(dBytes / bfFormats[i].dDivisor) / bfFormats[i].dNormaliser;
2371 if (!FormatDouble(dBytes, bfFormats[i].nDecimals, lpszDest, cchMax))
2372 return NULL;
2373 wszAdd[1] = bfFormats[i].wPrefix;
2374 StrCatBuffW(lpszDest, wszAdd, cchMax);
2375 return lpszDest;
2378 /*************************************************************************
2379 * StrFormatByteSize64A [SHLWAPI.@]
2381 * See StrFormatByteSizeW.
2383 LPSTR WINAPI StrFormatByteSize64A(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax)
2385 WCHAR wszBuff[32];
2387 StrFormatByteSizeW(llBytes, wszBuff, sizeof(wszBuff)/sizeof(WCHAR));
2389 if (lpszDest)
2390 WideCharToMultiByte(CP_ACP, 0, wszBuff, -1, lpszDest, cchMax, 0, 0);
2391 return lpszDest;
2394 /*************************************************************************
2395 * StrFormatByteSizeA [SHLWAPI.@]
2397 * Create a string containing an abbreviated byte count of up to 2^31-1.
2399 * PARAMS
2400 * dwBytes [I] Byte size to format
2401 * lpszDest [I] Destination for formatted string
2402 * cchMax [I] Size of lpszDest
2404 * RETURNS
2405 * lpszDest.
2407 * NOTES
2408 * The Ascii and Unicode versions of this function accept a different
2409 * integer type for dwBytes. See StrFormatByteSize64A().
2411 LPSTR WINAPI StrFormatByteSizeA(DWORD dwBytes, LPSTR lpszDest, UINT cchMax)
2413 TRACE("(%d,%p,%d)\n", dwBytes, lpszDest, cchMax);
2415 return StrFormatByteSize64A(dwBytes, lpszDest, cchMax);
2418 /*************************************************************************
2419 * @ [SHLWAPI.162]
2421 * Remove a hanging lead byte from the end of a string, if present.
2423 * PARAMS
2424 * lpStr [I] String to check for a hanging lead byte
2425 * size [I] Length of lpStr
2427 * RETURNS
2428 * Success: The new length of the string. Any hanging lead bytes are removed.
2429 * Failure: 0, if any parameters are invalid.
2431 DWORD WINAPI SHTruncateString(LPSTR lpStr, DWORD size)
2433 if (lpStr && size)
2435 LPSTR lastByte = lpStr + size - 1;
2437 while(lpStr < lastByte)
2438 lpStr += IsDBCSLeadByte(*lpStr) ? 2 : 1;
2440 if(lpStr == lastByte && IsDBCSLeadByte(*lpStr))
2442 *lpStr = '\0';
2443 size--;
2445 return size;
2447 return 0;
2450 /*************************************************************************
2451 * @ [SHLWAPI.203]
2453 * Remove a single non-trailing ampersand ('&') from a string.
2455 * PARAMS
2456 * lpszStr [I/O] String to remove ampersand from.
2458 * RETURNS
2459 * The character after the first ampersand in lpszStr, or the first character
2460 * in lpszStr if there is no ampersand in the string.
2462 char WINAPI SHStripMneumonicA(LPCSTR lpszStr)
2464 LPSTR lpszIter, lpszTmp;
2465 char ch;
2467 TRACE("(%s)\n", debugstr_a(lpszStr));
2469 ch = *lpszStr;
2471 if ((lpszIter = StrChrA(lpszStr, '&')))
2473 lpszTmp = CharNextA(lpszIter);
2474 if (lpszTmp && *lpszTmp)
2476 if (*lpszTmp != '&')
2477 ch = *lpszTmp;
2479 while (lpszIter && *lpszIter)
2481 lpszTmp = CharNextA(lpszIter);
2482 *lpszIter = *lpszTmp;
2483 lpszIter = lpszTmp;
2488 return ch;
2491 /*************************************************************************
2492 * @ [SHLWAPI.225]
2494 * Unicode version of SHStripMneumonicA.
2496 WCHAR WINAPI SHStripMneumonicW(LPCWSTR lpszStr)
2498 LPWSTR lpszIter, lpszTmp;
2499 WCHAR ch;
2501 TRACE("(%s)\n", debugstr_w(lpszStr));
2503 ch = *lpszStr;
2505 if ((lpszIter = StrChrW(lpszStr, '&')))
2507 lpszTmp = CharNextW(lpszIter);
2508 if (lpszTmp && *lpszTmp)
2510 if (*lpszTmp != '&')
2511 ch = *lpszTmp;
2513 while (lpszIter && *lpszIter)
2515 lpszTmp = CharNextW(lpszIter);
2516 *lpszIter = *lpszTmp;
2517 lpszIter = lpszTmp;
2522 return ch;
2525 /*************************************************************************
2526 * @ [SHLWAPI.216]
2528 * Convert an Ascii string to Unicode.
2530 * PARAMS
2531 * dwCp [I] Code page for the conversion
2532 * lpSrcStr [I] Source Ascii string to convert
2533 * lpDstStr [O] Destination for converted Unicode string
2534 * iLen [I] Length of lpDstStr
2536 * RETURNS
2537 * The return value of the MultiByteToWideChar() function called on lpSrcStr.
2539 DWORD WINAPI SHAnsiToUnicodeCP(DWORD dwCp, LPCSTR lpSrcStr, LPWSTR lpDstStr, int iLen)
2541 DWORD dwRet;
2543 dwRet = MultiByteToWideChar(dwCp, 0, lpSrcStr, -1, lpDstStr, iLen);
2544 TRACE("%s->%s,ret=%d\n", debugstr_a(lpSrcStr), debugstr_w(lpDstStr), dwRet);
2545 return dwRet;
2548 /*************************************************************************
2549 * @ [SHLWAPI.215]
2551 * Convert an Ascii string to Unicode.
2553 * PARAMS
2554 * lpSrcStr [I] Source Ascii string to convert
2555 * lpDstStr [O] Destination for converted Unicode string
2556 * iLen [I] Length of lpDstStr
2558 * RETURNS
2559 * The return value of the MultiByteToWideChar() function called on lpSrcStr.
2561 * NOTES
2562 * This function simply calls SHAnsiToUnicodeCP with code page CP_ACP.
2564 DWORD WINAPI SHAnsiToUnicode(LPCSTR lpSrcStr, LPWSTR lpDstStr, int iLen)
2566 return SHAnsiToUnicodeCP(CP_ACP, lpSrcStr, lpDstStr, iLen);
2569 /*************************************************************************
2570 * @ [SHLWAPI.218]
2572 * Convert a Unicode string to Ascii.
2574 * PARAMS
2575 * CodePage [I] Code page to use for the conversion
2576 * lpSrcStr [I] Source Unicode string to convert
2577 * lpDstStr [O] Destination for converted Ascii string
2578 * lpiLen [I/O] Input length of lpDstStr/destination for length of lpDstStr
2580 * RETURNS
2581 * Success: The number of characters that result from the conversion.
2582 * Failure: 0.
2584 INT WINAPI SHUnicodeToAnsiCP(UINT CodePage, LPCWSTR lpSrcStr, LPSTR lpDstStr,
2585 LPINT lpiLen)
2587 static const WCHAR emptyW[] = { '\0' };
2588 int len , reqLen;
2589 LPSTR mem;
2591 if (!lpDstStr || !lpiLen)
2592 return 0;
2594 if (!lpSrcStr)
2595 lpSrcStr = emptyW;
2597 *lpDstStr = '\0';
2599 len = strlenW(lpSrcStr) + 1;
2601 switch (CodePage)
2603 case CP_WINUNICODE:
2604 CodePage = CP_UTF8; /* Fall through... */
2605 case 0x0000C350: /* FIXME: CP_ #define */
2606 case CP_UTF7:
2607 case CP_UTF8:
2609 DWORD dwMode = 0;
2610 INT nWideCharCount = len - 1;
2612 GET_FUNC(pConvertINetUnicodeToMultiByte, mlang, "ConvertINetUnicodeToMultiByte", 0);
2613 if (!pConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &nWideCharCount, lpDstStr,
2614 lpiLen))
2615 return 0;
2617 if (nWideCharCount < len - 1)
2619 mem = HeapAlloc(GetProcessHeap(), 0, *lpiLen);
2620 if (!mem)
2621 return 0;
2623 *lpiLen = 0;
2625 if (pConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &len, mem, lpiLen))
2627 SHTruncateString(mem, *lpiLen);
2628 lstrcpynA(lpDstStr, mem, *lpiLen + 1);
2629 HeapFree(GetProcessHeap(), 0, mem);
2630 return *lpiLen + 1;
2632 HeapFree(GetProcessHeap(), 0, mem);
2633 return *lpiLen;
2635 lpDstStr[*lpiLen] = '\0';
2636 return *lpiLen;
2638 default:
2639 break;
2642 reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, lpDstStr,
2643 *lpiLen, NULL, NULL);
2645 if (!reqLen && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
2647 reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, NULL, 0, NULL, NULL);
2648 if (reqLen)
2650 mem = HeapAlloc(GetProcessHeap(), 0, reqLen);
2651 if (mem)
2653 reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, mem,
2654 reqLen, NULL, NULL);
2656 reqLen = SHTruncateString(mem, *lpiLen);
2657 reqLen++;
2659 lstrcpynA(lpDstStr, mem, *lpiLen);
2661 HeapFree(GetProcessHeap(), 0, mem);
2665 return reqLen;
2668 /*************************************************************************
2669 * @ [SHLWAPI.217]
2671 * Convert a Unicode string to Ascii.
2673 * PARAMS
2674 * lpSrcStr [I] Source Unicode string to convert
2675 * lpDstStr [O] Destination for converted Ascii string
2676 * iLen [O] Length of lpDstStr in characters
2678 * RETURNS
2679 * See SHUnicodeToAnsiCP
2681 * NOTES
2682 * This function simply calls SHUnicodeToAnsiCP() with CodePage = CP_ACP.
2684 INT WINAPI SHUnicodeToAnsi(LPCWSTR lpSrcStr, LPSTR lpDstStr, INT iLen)
2686 INT myint = iLen;
2688 return SHUnicodeToAnsiCP(CP_ACP, lpSrcStr, lpDstStr, &myint);
2691 /*************************************************************************
2692 * @ [SHLWAPI.345]
2694 * Copy one string to another.
2696 * PARAMS
2697 * lpszSrc [I] Source string to copy
2698 * lpszDst [O] Destination for copy
2699 * iLen [I] Length of lpszDst in characters
2701 * RETURNS
2702 * The length of the copied string, including the terminating NUL. lpszDst
2703 * contains iLen characters of lpszSrc.
2705 DWORD WINAPI SHAnsiToAnsi(LPCSTR lpszSrc, LPSTR lpszDst, int iLen)
2707 LPSTR lpszRet;
2709 TRACE("(%s,%p,0x%08x)\n", debugstr_a(lpszSrc), lpszDst, iLen);
2711 lpszRet = StrCpyNXA(lpszDst, lpszSrc, iLen);
2712 return lpszRet - lpszDst + 1;
2715 /*************************************************************************
2716 * @ [SHLWAPI.346]
2718 * Unicode version of SSHAnsiToAnsi.
2720 DWORD WINAPI SHUnicodeToUnicode(LPCWSTR lpszSrc, LPWSTR lpszDst, int iLen)
2722 LPWSTR lpszRet;
2724 TRACE("(%s,%p,0x%08x)\n", debugstr_w(lpszSrc), lpszDst, iLen);
2726 lpszRet = StrCpyNXW(lpszDst, lpszSrc, iLen);
2727 return lpszRet - lpszDst + 1;
2730 /*************************************************************************
2731 * @ [SHLWAPI.364]
2733 * Determine if an Ascii string converts to Unicode and back identically.
2735 * PARAMS
2736 * lpSrcStr [I] Source Unicode string to convert
2737 * lpDst [O] Destination for resulting Ascii string
2738 * iLen [I] Length of lpDst in characters
2740 * RETURNS
2741 * TRUE, since Ascii strings always convert identically.
2743 BOOL WINAPI DoesStringRoundTripA(LPCSTR lpSrcStr, LPSTR lpDst, INT iLen)
2745 lstrcpynA(lpDst, lpSrcStr, iLen);
2746 return TRUE;
2749 /*************************************************************************
2750 * @ [SHLWAPI.365]
2752 * Determine if a Unicode string converts to Ascii and back identically.
2754 * PARAMS
2755 * lpSrcStr [I] Source Unicode string to convert
2756 * lpDst [O] Destination for resulting Ascii string
2757 * iLen [I] Length of lpDst in characters
2759 * RETURNS
2760 * TRUE, if lpSrcStr converts to Ascii and back identically,
2761 * FALSE otherwise.
2763 BOOL WINAPI DoesStringRoundTripW(LPCWSTR lpSrcStr, LPSTR lpDst, INT iLen)
2765 WCHAR szBuff[MAX_PATH];
2767 SHUnicodeToAnsi(lpSrcStr, lpDst, iLen);
2768 SHAnsiToUnicode(lpDst, szBuff, MAX_PATH);
2769 return !strcmpW(lpSrcStr, szBuff);
2772 /*************************************************************************
2773 * SHLoadIndirectString [SHLWAPI.@]
2775 * If passed a string that begins with a '@' extract the string from the
2776 * appropriate resource, otherwise do a straight copy.
2779 HRESULT WINAPI SHLoadIndirectString(LPCWSTR src, LPWSTR dst, UINT dst_len, void **reserved)
2781 WCHAR *dllname = NULL;
2782 HMODULE hmod = NULL;
2783 HRESULT hr = E_FAIL;
2785 TRACE("(%s %p %08x %p)\n", debugstr_w(src), dst, dst_len, reserved);
2787 if(src[0] == '@')
2789 WCHAR *index_str;
2790 int index;
2792 dst[0] = 0;
2793 dllname = StrDupW(src + 1);
2794 index_str = strchrW(dllname, ',');
2796 if(!index_str) goto end;
2798 *index_str = 0;
2799 index_str++;
2800 index = atoiW(index_str);
2802 hmod = LoadLibraryW(dllname);
2803 if(!hmod) goto end;
2805 if(index < 0)
2807 if(LoadStringW(hmod, -index, dst, dst_len))
2808 hr = S_OK;
2810 else
2811 FIXME("can't handle non-negative indices (%d)\n", index);
2813 else
2815 if(dst != src)
2816 lstrcpynW(dst, src, dst_len);
2817 hr = S_OK;
2820 TRACE("returning %s\n", debugstr_w(dst));
2821 end:
2822 if(hmod) FreeLibrary(hmod);
2823 HeapFree(GetProcessHeap(), 0, dllname);
2824 return hr;