shlwapi: Add size parameters to function that takes array arguments.
[wine/multimedia.git] / dlls / shlwapi / string.c
blobf839546b038177d0c9557522484fd88484297a5c
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 #define COM_NO_WINDOWS_H
23 #include "config.h"
24 #include "wine/port.h"
26 #include <math.h>
27 #include <stdarg.h>
28 #include <stdio.h>
29 #include <string.h>
31 #define NONAMELESSUNION
32 #define NONAMELESSSTRUCT
33 #include "windef.h"
34 #include "winbase.h"
35 #define NO_SHLWAPI_REG
36 #define NO_SHLWAPI_STREAM
37 #include "shlwapi.h"
38 #include "wingdi.h"
39 #include "winuser.h"
40 #include "shlobj.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 /* Get a function pointer from a DLL handle */
50 #define GET_FUNC(func, module, name, fail) \
51 do { \
52 if (!func) { \
53 if (!SHLWAPI_h##module && !(SHLWAPI_h##module = LoadLibraryA(#module ".dll"))) return fail; \
54 func = (fn##func)GetProcAddress(SHLWAPI_h##module, name); \
55 if (!func) return fail; \
56 } \
57 } while (0)
59 extern HMODULE SHLWAPI_hmlang;
60 extern HINSTANCE shlwapi_hInstance;
62 typedef HRESULT (WINAPI *fnpConvertINetUnicodeToMultiByte)(LPDWORD,DWORD,LPCWSTR,LPINT,LPSTR,LPINT);
63 static fnpConvertINetUnicodeToMultiByte pConvertINetUnicodeToMultiByte;
65 static HRESULT WINAPI _SHStrDupAA(LPCSTR,LPSTR*);
66 static HRESULT WINAPI _SHStrDupAW(LPCWSTR,LPSTR*);
69 static void FillNumberFmt(NUMBERFMTW *fmt, LPWSTR decimal_buffer, int decimal_bufwlen,
70 LPWSTR thousand_buffer, int thousand_bufwlen)
72 WCHAR grouping[64];
73 WCHAR *c;
75 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_ILZERO|LOCALE_RETURN_NUMBER, (LPWSTR)&fmt->LeadingZero, sizeof(fmt->LeadingZero)/sizeof(WCHAR));
76 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_INEGNUMBER|LOCALE_RETURN_NUMBER, (LPWSTR)&fmt->LeadingZero, sizeof(fmt->NegativeOrder)/sizeof(WCHAR));
77 fmt->NumDigits = 0;
78 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, decimal_buffer, decimal_bufwlen);
79 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, thousand_buffer, thousand_bufwlen);
80 fmt->lpThousandSep = thousand_buffer;
81 fmt->lpDecimalSep = decimal_buffer;
83 /*
84 * Converting grouping string to number as described on
85 * http://blogs.msdn.com/oldnewthing/archive/2006/04/18/578251.aspx
87 fmt->Grouping = 0;
88 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SGROUPING, grouping, sizeof(grouping)/sizeof(WCHAR));
89 for (c = grouping; *c; c++)
90 if (*c >= '0' && *c < '9')
92 fmt->Grouping *= 10;
93 fmt->Grouping += *c - '0';
96 if (fmt->Grouping % 10 == 0)
97 fmt->Grouping /= 10;
98 else
99 fmt->Grouping *= 10;
102 /*************************************************************************
103 * FormatInt [internal]
105 * Format an integer according to the current locale
107 * RETURNS
108 * The number of bytes written on success or 0 on failure
110 static int FormatInt(LONGLONG qdwValue, LPWSTR pszBuf, int cchBuf)
112 NUMBERFMTW fmt;
113 WCHAR decimal[8], thousand[8];
114 WCHAR buf[24];
115 WCHAR *c;
116 BOOL neg = (qdwValue < 0);
118 FillNumberFmt(&fmt, decimal, sizeof decimal / sizeof (WCHAR),
119 thousand, sizeof thousand / sizeof (WCHAR));
121 c = &buf[24];
122 *(--c) = 0;
125 *(--c) = '0' + (qdwValue%10);
126 qdwValue /= 10;
127 } while (qdwValue > 0);
128 if (neg)
129 *(--c) = '-';
131 return GetNumberFormatW(LOCALE_USER_DEFAULT, 0, c, &fmt, pszBuf, cchBuf);
134 /*************************************************************************
135 * FormatDouble [internal]
137 * Format an integer according to the current locale. Prints the specified number of digits
138 * after the decimal point
140 * RETURNS
141 * The number of bytes written on success or 0 on failure
143 static int FormatDouble(double value, int decimals, LPWSTR pszBuf, int cchBuf)
145 static const WCHAR flfmt[] = {'%','f',0};
146 WCHAR buf[64];
147 NUMBERFMTW fmt;
148 WCHAR decimal[8], thousand[8];
150 snprintfW(buf, 64, flfmt, value);
152 FillNumberFmt(&fmt, decimal, sizeof decimal / sizeof (WCHAR),
153 thousand, sizeof thousand / sizeof (WCHAR));
154 fmt.NumDigits = decimals;
155 return GetNumberFormatW(LOCALE_USER_DEFAULT, 0, buf, &fmt, pszBuf, cchBuf);
158 /*************************************************************************
159 * SHLWAPI_ChrCmpHelperA
161 * Internal helper for SHLWAPI_ChrCmpA/ChrCMPIA.
163 * NOTES
164 * Both this function and its Unicode counterpart are very inneficient. To
165 * fix this, CompareString must be completely implemented and optimised
166 * first. Then the core character test can be taken out of that function and
167 * placed here, so that it need never be called at all. Until then, do not
168 * attempt to optimise this code unless you are willing to test that it
169 * still performs correctly.
171 static BOOL WINAPI SHLWAPI_ChrCmpHelperA(WORD ch1, WORD ch2, DWORD dwFlags)
173 char str1[3], str2[3];
175 str1[0] = LOBYTE(ch1);
176 if (IsDBCSLeadByte(str1[0]))
178 str1[1] = HIBYTE(ch1);
179 str1[2] = '\0';
181 else
182 str1[1] = '\0';
184 str2[0] = LOBYTE(ch2);
185 if (IsDBCSLeadByte(str2[0]))
187 str2[1] = HIBYTE(ch2);
188 str2[2] = '\0';
190 else
191 str2[1] = '\0';
193 return CompareStringA(GetThreadLocale(), dwFlags, str1, -1, str2, -1) - 2;
196 /*************************************************************************
197 * SHLWAPI_ChrCmpHelperW
199 * Internal helper for SHLWAPI_ChrCmpW/ChrCmpIW.
201 static BOOL WINAPI SHLWAPI_ChrCmpHelperW(WCHAR ch1, WCHAR ch2, DWORD dwFlags)
203 WCHAR str1[2], str2[2];
205 str1[0] = ch1;
206 str1[1] = '\0';
207 str2[0] = ch2;
208 str2[1] = '\0';
209 return CompareStringW(GetThreadLocale(), dwFlags, str1, 2, str2, 2) - 2;
212 /*************************************************************************
213 * SHLWAPI_ChrCmpA
215 * Internal helper function.
217 static BOOL WINAPI SHLWAPI_ChrCmpA(WORD ch1, WORD ch2)
219 return SHLWAPI_ChrCmpHelperA(ch1, ch2, 0);
222 /*************************************************************************
223 * ChrCmpIA (SHLWAPI.385)
225 * Compare two characters, ignoring case.
227 * PARAMS
228 * ch1 [I] First character to compare
229 * ch2 [I] Second character to compare
231 * RETURNS
232 * FALSE, if the characters are equal.
233 * Non-zero otherwise.
235 BOOL WINAPI ChrCmpIA(WORD ch1, WORD ch2)
237 TRACE("(%d,%d)\n", ch1, ch2);
239 return SHLWAPI_ChrCmpHelperA(ch1, ch2, NORM_IGNORECASE);
242 /*************************************************************************
243 * SHLWAPI_ChrCmpW
245 * Internal helper function.
247 static BOOL WINAPI SHLWAPI_ChrCmpW(WCHAR ch1, WCHAR ch2)
249 return SHLWAPI_ChrCmpHelperW(ch1, ch2, 0);
252 /*************************************************************************
253 * ChrCmpIW [SHLWAPI.386]
255 * See ChrCmpIA.
257 BOOL WINAPI ChrCmpIW(WCHAR ch1, WCHAR ch2)
259 return SHLWAPI_ChrCmpHelperW(ch1, ch2, NORM_IGNORECASE);
262 /*************************************************************************
263 * StrChrA [SHLWAPI.@]
265 * Find a given character in a string.
267 * PARAMS
268 * lpszStr [I] String to search in.
269 * ch [I] Character to search for.
271 * RETURNS
272 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
273 * not found.
274 * Failure: NULL, if any arguments are invalid.
276 LPSTR WINAPI StrChrA(LPCSTR lpszStr, WORD ch)
278 TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch);
280 if (lpszStr)
282 while (*lpszStr)
284 if (!SHLWAPI_ChrCmpA(*lpszStr, ch))
285 return (LPSTR)lpszStr;
286 lpszStr = CharNextA(lpszStr);
289 return NULL;
292 /*************************************************************************
293 * StrChrW [SHLWAPI.@]
295 * See StrChrA.
297 LPWSTR WINAPI StrChrW(LPCWSTR lpszStr, WCHAR ch)
299 LPWSTR lpszRet = NULL;
301 TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch);
303 if (lpszStr)
304 lpszRet = strchrW(lpszStr, ch);
305 return lpszRet;
308 /*************************************************************************
309 * StrChrIA [SHLWAPI.@]
311 * Find a given character in a string, ignoring case.
313 * PARAMS
314 * lpszStr [I] String to search in.
315 * ch [I] Character to search for.
317 * RETURNS
318 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
319 * not found.
320 * Failure: NULL, if any arguments are invalid.
322 LPSTR WINAPI StrChrIA(LPCSTR lpszStr, WORD ch)
324 TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch);
326 if (lpszStr)
328 while (*lpszStr)
330 if (!ChrCmpIA(*lpszStr, ch))
331 return (LPSTR)lpszStr;
332 lpszStr = CharNextA(lpszStr);
335 return NULL;
338 /*************************************************************************
339 * StrChrIW [SHLWAPI.@]
341 * See StrChrA.
343 LPWSTR WINAPI StrChrIW(LPCWSTR lpszStr, WCHAR ch)
345 TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch);
347 if (lpszStr)
349 ch = toupperW(ch);
350 while (*lpszStr)
352 if (toupperW(*lpszStr) == ch)
353 return (LPWSTR)lpszStr;
354 lpszStr = CharNextW(lpszStr);
356 lpszStr = NULL;
358 return (LPWSTR)lpszStr;
361 /*************************************************************************
362 * StrCmpIW [SHLWAPI.@]
364 * Compare two strings, ignoring case.
366 * PARAMS
367 * lpszStr [I] First string to compare
368 * lpszComp [I] Second string to compare
370 * RETURNS
371 * An integer less than, equal to or greater than 0, indicating that
372 * lpszStr is less than, the same, or greater than lpszComp.
374 int WINAPI StrCmpIW(LPCWSTR lpszStr, LPCWSTR lpszComp)
376 int iRet;
378 TRACE("(%s,%s)\n", debugstr_w(lpszStr),debugstr_w(lpszComp));
380 iRet = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, lpszStr, -1, lpszComp, -1);
381 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
384 /*************************************************************************
385 * StrCmpNA [SHLWAPI.@]
387 * Compare two strings, up to a maximum length.
389 * PARAMS
390 * lpszStr [I] First string to compare
391 * lpszComp [I] Second string to compare
392 * iLen [I] Maximum number of chars to compare.
394 * RETURNS
395 * An integer less than, equal to or greater than 0, indicating that
396 * lpszStr is less than, the same, or greater than lpszComp.
398 INT WINAPI StrCmpNA(LPCSTR lpszStr, LPCSTR lpszComp, INT iLen)
400 INT iRet;
402 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
404 iRet = CompareStringA(GetThreadLocale(), 0, lpszStr, iLen, lpszComp, iLen);
405 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
408 /*************************************************************************
409 * StrCmpNW [SHLWAPI.@]
411 * See StrCmpNA.
413 INT WINAPI StrCmpNW(LPCWSTR lpszStr, LPCWSTR lpszComp, INT iLen)
415 INT iRet;
417 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen);
419 iRet = CompareStringW(GetThreadLocale(), 0, lpszStr, iLen, lpszComp, iLen);
420 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
423 /*************************************************************************
424 * StrCmpNIA [SHLWAPI.@]
426 * Compare two strings, up to a maximum length, ignoring case.
428 * PARAMS
429 * lpszStr [I] First string to compare
430 * lpszComp [I] Second string to compare
431 * iLen [I] Maximum number of chars to compare.
433 * RETURNS
434 * An integer less than, equal to or greater than 0, indicating that
435 * lpszStr is less than, the same, or greater than lpszComp.
437 int WINAPI StrCmpNIA(LPCSTR lpszStr, LPCSTR lpszComp, int iLen)
439 INT iRet;
441 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
443 iRet = CompareStringA(GetThreadLocale(), NORM_IGNORECASE, lpszStr, iLen, lpszComp, iLen);
444 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
447 /*************************************************************************
448 * StrCmpNIW [SHLWAPI.@]
450 * See StrCmpNIA.
452 INT WINAPI StrCmpNIW(LPCWSTR lpszStr, LPCWSTR lpszComp, int iLen)
454 INT iRet;
456 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen);
458 iRet = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, lpszStr, iLen, lpszComp, iLen);
459 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
462 /*************************************************************************
463 * StrCmpW [SHLWAPI.@]
465 * Compare two strings.
467 * PARAMS
468 * lpszStr [I] First string to compare
469 * lpszComp [I] Second string to compare
471 * RETURNS
472 * An integer less than, equal to or greater than 0, indicating that
473 * lpszStr is less than, the same, or greater than lpszComp.
475 int WINAPI StrCmpW(LPCWSTR lpszStr, LPCWSTR lpszComp)
477 INT iRet;
479 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszComp));
481 iRet = CompareStringW(GetThreadLocale(), 0, lpszStr, -1, lpszComp, -1);
482 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
485 /*************************************************************************
486 * StrCatW [SHLWAPI.@]
488 * Concatanate two strings.
490 * PARAMS
491 * lpszStr [O] Initial string
492 * lpszSrc [I] String to concatanate
494 * RETURNS
495 * lpszStr.
497 LPWSTR WINAPI StrCatW(LPWSTR lpszStr, LPCWSTR lpszSrc)
499 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSrc));
501 strcatW(lpszStr, lpszSrc);
502 return lpszStr;
505 /*************************************************************************
506 * StrCpyW [SHLWAPI.@]
508 * Copy a string to another string.
510 * PARAMS
511 * lpszStr [O] Destination string
512 * lpszSrc [I] Source string
514 * RETURNS
515 * lpszStr.
517 LPWSTR WINAPI StrCpyW(LPWSTR lpszStr, LPCWSTR lpszSrc)
519 TRACE("(%p,%s)\n", lpszStr, debugstr_w(lpszSrc));
521 strcpyW(lpszStr, lpszSrc);
522 return lpszStr;
525 /*************************************************************************
526 * StrCpyNW [SHLWAPI.@]
528 * Copy a string to another string, up to a maximum number of characters.
530 * PARAMS
531 * lpszStr [O] Destination string
532 * lpszSrc [I] Source string
533 * iLen [I] Maximum number of chars to copy
535 * RETURNS
536 * lpszStr.
538 LPWSTR WINAPI StrCpyNW(LPWSTR lpszStr, LPCWSTR lpszSrc, int iLen)
540 TRACE("(%p,%s,%i)\n", lpszStr, debugstr_w(lpszSrc), iLen);
542 lstrcpynW(lpszStr, lpszSrc, iLen);
543 return lpszStr;
548 /*************************************************************************
549 * SHLWAPI_StrStrHelperA
551 * Internal implementation of StrStrA/StrStrIA
553 static LPSTR WINAPI SHLWAPI_StrStrHelperA(LPCSTR lpszStr, LPCSTR lpszSearch,
554 int (*pStrCmpFn)(LPCSTR,LPCSTR,size_t))
556 size_t iLen;
558 if (!lpszStr || !lpszSearch || !*lpszSearch)
559 return NULL;
561 iLen = strlen(lpszSearch);
563 while (*lpszStr)
565 if (!pStrCmpFn(lpszStr, lpszSearch, iLen))
566 return (LPSTR)lpszStr;
567 lpszStr = CharNextA(lpszStr);
569 return NULL;
572 /*************************************************************************
573 * SHLWAPI_StrStrHelperW
575 * Internal implementation of StrStrW/StrStrIW
577 static LPWSTR WINAPI SHLWAPI_StrStrHelperW(LPCWSTR lpszStr, LPCWSTR lpszSearch,
578 int (*pStrCmpFn)(LPCWSTR,LPCWSTR,int))
580 int iLen;
582 if (!lpszStr || !lpszSearch || !*lpszSearch)
583 return NULL;
585 iLen = strlenW(lpszSearch);
587 while (*lpszStr)
589 if (!pStrCmpFn(lpszStr, lpszSearch, iLen))
590 return (LPWSTR)lpszStr;
591 lpszStr = CharNextW(lpszStr);
593 return NULL;
596 /*************************************************************************
597 * StrStrA [SHLWAPI.@]
599 * Find a substring within a string.
601 * PARAMS
602 * lpszStr [I] String to search in
603 * lpszSearch [I] String to look for
605 * RETURNS
606 * The start of lpszSearch within lpszStr, or NULL if not found.
608 LPSTR WINAPI StrStrA(LPCSTR lpszStr, LPCSTR lpszSearch)
610 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
612 return SHLWAPI_StrStrHelperA(lpszStr, lpszSearch, strncmp);
615 /*************************************************************************
616 * StrStrW [SHLWAPI.@]
618 * See StrStrA.
620 LPWSTR WINAPI StrStrW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
622 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
624 return SHLWAPI_StrStrHelperW(lpszStr, lpszSearch, strncmpW);
627 /*************************************************************************
628 * StrRStrIA [SHLWAPI.@]
630 * Find the last occurrence of a substring within a string.
632 * PARAMS
633 * lpszStr [I] String to search in
634 * lpszEnd [I] End of lpszStr
635 * lpszSearch [I] String to look for
637 * RETURNS
638 * The last occurrence lpszSearch within lpszStr, or NULL if not found.
640 LPSTR WINAPI StrRStrIA(LPCSTR lpszStr, LPCSTR lpszEnd, LPCSTR lpszSearch)
642 LPSTR lpszRet = NULL;
643 WORD ch1, ch2;
644 INT iLen;
646 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
648 if (!lpszStr || !lpszSearch || !*lpszSearch)
649 return NULL;
651 if (!lpszEnd)
652 lpszEnd = lpszStr + lstrlenA(lpszStr);
654 if (IsDBCSLeadByte(*lpszSearch))
655 ch1 = *lpszSearch << 8 | lpszSearch[1];
656 else
657 ch1 = *lpszSearch;
658 iLen = lstrlenA(lpszSearch);
660 while (lpszStr <= lpszEnd && *lpszStr)
662 ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr;
663 if (!ChrCmpIA(ch1, ch2))
665 if (!StrCmpNIA(lpszStr, lpszSearch, iLen))
666 lpszRet = (LPSTR)lpszStr;
668 lpszStr = CharNextA(lpszStr);
670 return lpszRet;
673 /*************************************************************************
674 * StrRStrIW [SHLWAPI.@]
676 * See StrRStrIA.
678 LPWSTR WINAPI StrRStrIW(LPCWSTR lpszStr, LPCWSTR lpszEnd, LPCWSTR lpszSearch)
680 LPWSTR lpszRet = NULL;
681 INT iLen;
683 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
685 if (!lpszStr || !lpszSearch || !*lpszSearch)
686 return NULL;
688 if (!lpszEnd)
689 lpszEnd = lpszStr + strlenW(lpszStr);
691 iLen = strlenW(lpszSearch);
693 while (lpszStr <= lpszEnd && *lpszStr)
695 if (!ChrCmpIW(*lpszSearch, *lpszStr))
697 if (!StrCmpNIW(lpszStr, lpszSearch, iLen))
698 lpszRet = (LPWSTR)lpszStr;
700 lpszStr = CharNextW(lpszStr);
702 return lpszRet;
705 /*************************************************************************
706 * StrStrIA [SHLWAPI.@]
708 * Find a substring within a string, ignoring case.
710 * PARAMS
711 * lpszStr [I] String to search in
712 * lpszSearch [I] String to look for
714 * RETURNS
715 * The start of lpszSearch within lpszStr, or NULL if not found.
717 LPSTR WINAPI StrStrIA(LPCSTR lpszStr, LPCSTR lpszSearch)
719 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
721 return SHLWAPI_StrStrHelperA(lpszStr, lpszSearch, strncasecmp);
724 /*************************************************************************
725 * StrStrIW [SHLWAPI.@]
727 * See StrStrIA.
729 LPWSTR WINAPI StrStrIW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
731 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
733 return SHLWAPI_StrStrHelperW(lpszStr, lpszSearch, strncmpiW);
736 /*************************************************************************
737 * StrToIntA [SHLWAPI.@]
739 * Read a signed integer from a string.
741 * PARAMS
742 * lpszStr [I] String to read integer from
744 * RETURNS
745 * The signed integer value represented by the string, or 0 if no integer is
746 * present.
748 * NOTES
749 * No leading space is allowed before the number, although a leading '-' is.
751 int WINAPI StrToIntA(LPCSTR lpszStr)
753 int iRet = 0;
755 TRACE("(%s)\n", debugstr_a(lpszStr));
757 if (!lpszStr)
759 WARN("Invalid lpszStr would crash under Win32!\n");
760 return 0;
763 if (*lpszStr == '-' || isdigit(*lpszStr))
764 StrToIntExA(lpszStr, 0, &iRet);
765 return iRet;
768 /*************************************************************************
769 * StrToIntW [SHLWAPI.@]
771 * See StrToIntA.
773 int WINAPI StrToIntW(LPCWSTR lpszStr)
775 int iRet = 0;
777 TRACE("(%s)\n", debugstr_w(lpszStr));
779 if (!lpszStr)
781 WARN("Invalid lpszStr would crash under Win32!\n");
782 return 0;
785 if (*lpszStr == '-' || isdigitW(*lpszStr))
786 StrToIntExW(lpszStr, 0, &iRet);
787 return iRet;
790 /*************************************************************************
791 * StrToIntExA [SHLWAPI.@]
793 * Read an integer from a string.
795 * PARAMS
796 * lpszStr [I] String to read integer from
797 * dwFlags [I] Flags controlling the conversion
798 * lpiRet [O] Destination for read integer.
800 * RETURNS
801 * Success: TRUE. lpiRet contains the integer value represented by the string.
802 * Failure: FALSE, if the string is invalid, or no number is present.
804 * NOTES
805 * Leading whitespace, '-' and '+' are allowed before the number. If
806 * dwFlags includes STIF_SUPPORT_HEX, hexadecimal numbers are allowed, if
807 * preceded by '0x'. If this flag is not set, or there is no '0x' prefix,
808 * the string is treated as a decimal string. A leading '-' is ignored for
809 * hexadecimal numbers.
811 BOOL WINAPI StrToIntExA(LPCSTR lpszStr, DWORD dwFlags, LPINT lpiRet)
813 BOOL bNegative = FALSE;
814 int iRet = 0;
816 TRACE("(%s,%08lX,%p)\n", debugstr_a(lpszStr), dwFlags, lpiRet);
818 if (!lpszStr || !lpiRet)
820 WARN("Invalid parameter would crash under Win32!\n");
821 return FALSE;
823 if (dwFlags > STIF_SUPPORT_HEX)
825 WARN("Unknown flags (%08lX)!\n", dwFlags & ~STIF_SUPPORT_HEX);
828 /* Skip leading space, '+', '-' */
829 while (isspace(*lpszStr))
830 lpszStr = CharNextA(lpszStr);
832 if (*lpszStr == '-')
834 bNegative = TRUE;
835 lpszStr++;
837 else if (*lpszStr == '+')
838 lpszStr++;
840 if (dwFlags & STIF_SUPPORT_HEX &&
841 *lpszStr == '0' && tolower(lpszStr[1]) == 'x')
843 /* Read hex number */
844 lpszStr += 2;
846 if (!isxdigit(*lpszStr))
847 return FALSE;
849 while (isxdigit(*lpszStr))
851 iRet = iRet * 16;
852 if (isdigit(*lpszStr))
853 iRet += (*lpszStr - '0');
854 else
855 iRet += 10 + (tolower(*lpszStr) - 'a');
856 lpszStr++;
858 *lpiRet = iRet;
859 return TRUE;
862 /* Read decimal number */
863 if (!isdigit(*lpszStr))
864 return FALSE;
866 while (isdigit(*lpszStr))
868 iRet = iRet * 10;
869 iRet += (*lpszStr - '0');
870 lpszStr++;
872 *lpiRet = bNegative ? -iRet : iRet;
873 return TRUE;
876 /*************************************************************************
877 * StrToIntExW [SHLWAPI.@]
879 * See StrToIntExA.
881 BOOL WINAPI StrToIntExW(LPCWSTR lpszStr, DWORD dwFlags, LPINT lpiRet)
883 BOOL bNegative = FALSE;
884 int iRet = 0;
886 TRACE("(%s,%08lX,%p)\n", debugstr_w(lpszStr), dwFlags, lpiRet);
888 if (!lpszStr || !lpiRet)
890 WARN("Invalid parameter would crash under Win32!\n");
891 return FALSE;
893 if (dwFlags > STIF_SUPPORT_HEX)
895 WARN("Unknown flags (%08lX)!\n", dwFlags & ~STIF_SUPPORT_HEX);
898 /* Skip leading space, '+', '-' */
899 while (isspaceW(*lpszStr))
900 lpszStr = CharNextW(lpszStr);
902 if (*lpszStr == '-')
904 bNegative = TRUE;
905 lpszStr++;
907 else if (*lpszStr == '+')
908 lpszStr++;
910 if (dwFlags & STIF_SUPPORT_HEX &&
911 *lpszStr == '0' && tolowerW(lpszStr[1]) == 'x')
913 /* Read hex number */
914 lpszStr += 2;
916 if (!isxdigitW(*lpszStr))
917 return FALSE;
919 while (isxdigitW(*lpszStr))
921 iRet = iRet * 16;
922 if (isdigitW(*lpszStr))
923 iRet += (*lpszStr - '0');
924 else
925 iRet += 10 + (tolowerW(*lpszStr) - 'a');
926 lpszStr++;
928 *lpiRet = iRet;
929 return TRUE;
932 /* Read decimal number */
933 if (!isdigitW(*lpszStr))
934 return FALSE;
936 while (isdigitW(*lpszStr))
938 iRet = iRet * 10;
939 iRet += (*lpszStr - '0');
940 lpszStr++;
942 *lpiRet = bNegative ? -iRet : iRet;
943 return TRUE;
946 /*************************************************************************
947 * StrDupA [SHLWAPI.@]
949 * Duplicate a string.
951 * PARAMS
952 * lpszStr [I] String to duplicate.
954 * RETURNS
955 * Success: A pointer to a new string containing the contents of lpszStr
956 * Failure: NULL, if memory cannot be allocated
958 * NOTES
959 * The string memory is allocated with LocalAlloc(), and so should be released
960 * by calling LocalFree().
962 LPSTR WINAPI StrDupA(LPCSTR lpszStr)
964 int iLen;
965 LPSTR lpszRet;
967 TRACE("(%s)\n",debugstr_a(lpszStr));
969 iLen = lpszStr ? strlen(lpszStr) + 1 : 1;
970 lpszRet = (LPSTR)LocalAlloc(LMEM_FIXED, iLen);
972 if (lpszRet)
974 if (lpszStr)
975 memcpy(lpszRet, lpszStr, iLen);
976 else
977 *lpszRet = '\0';
979 return lpszRet;
982 /*************************************************************************
983 * StrDupW [SHLWAPI.@]
985 * See StrDupA.
987 LPWSTR WINAPI StrDupW(LPCWSTR lpszStr)
989 int iLen;
990 LPWSTR lpszRet;
992 TRACE("(%s)\n",debugstr_w(lpszStr));
994 iLen = (lpszStr ? strlenW(lpszStr) + 1 : 1) * sizeof(WCHAR);
995 lpszRet = (LPWSTR)LocalAlloc(LMEM_FIXED, iLen);
997 if (lpszRet)
999 if (lpszStr)
1000 memcpy(lpszRet, lpszStr, iLen);
1001 else
1002 *lpszRet = '\0';
1004 return lpszRet;
1007 /*************************************************************************
1008 * SHLWAPI_StrSpnHelperA
1010 * Internal implementation of StrSpnA/StrCSpnA/StrCSpnIA
1012 static int WINAPI SHLWAPI_StrSpnHelperA(LPCSTR lpszStr, LPCSTR lpszMatch,
1013 LPSTR (WINAPI *pStrChrFn)(LPCSTR,WORD),
1014 BOOL bInvert)
1016 LPCSTR lpszRead = lpszStr;
1017 if (lpszStr && *lpszStr && lpszMatch)
1019 while (*lpszRead)
1021 LPCSTR lpszTest = pStrChrFn(lpszMatch, *lpszRead);
1023 if (!bInvert && !lpszTest)
1024 break;
1025 if (bInvert && lpszTest)
1026 break;
1027 lpszRead = CharNextA(lpszRead);
1030 return lpszRead - lpszStr;
1033 /*************************************************************************
1034 * SHLWAPI_StrSpnHelperW
1036 * Internal implementation of StrSpnW/StrCSpnW/StrCSpnIW
1038 static int WINAPI SHLWAPI_StrSpnHelperW(LPCWSTR lpszStr, LPCWSTR lpszMatch,
1039 LPWSTR (WINAPI *pStrChrFn)(LPCWSTR,WCHAR),
1040 BOOL bInvert)
1042 LPCWSTR lpszRead = lpszStr;
1043 if (lpszStr && *lpszStr && lpszMatch)
1045 while (*lpszRead)
1047 LPCWSTR lpszTest = pStrChrFn(lpszMatch, *lpszRead);
1049 if (!bInvert && !lpszTest)
1050 break;
1051 if (bInvert && lpszTest)
1052 break;
1053 lpszRead = CharNextW(lpszRead);
1056 return lpszRead - lpszStr;
1059 /*************************************************************************
1060 * StrSpnA [SHLWAPI.@]
1062 * Find the length of the start of a string that contains only certain
1063 * characters.
1065 * PARAMS
1066 * lpszStr [I] String to search
1067 * lpszMatch [I] Characters that can be in the substring
1069 * RETURNS
1070 * The length of the part of lpszStr containing only chars from lpszMatch,
1071 * or 0 if any parameter is invalid.
1073 int WINAPI StrSpnA(LPCSTR lpszStr, LPCSTR lpszMatch)
1075 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1077 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, FALSE);
1080 /*************************************************************************
1081 * StrSpnW [SHLWAPI.@]
1083 * See StrSpnA.
1085 int WINAPI StrSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1087 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1089 return SHLWAPI_StrSpnHelperW(lpszStr, lpszMatch, StrChrW, FALSE);
1092 /*************************************************************************
1093 * StrCSpnA [SHLWAPI.@]
1095 * Find the length of the start of a string that does not contain certain
1096 * characters.
1098 * PARAMS
1099 * lpszStr [I] String to search
1100 * lpszMatch [I] Characters that cannot be in the substring
1102 * RETURNS
1103 * The length of the part of lpszStr containing only chars not in lpszMatch,
1104 * or 0 if any parameter is invalid.
1106 int WINAPI StrCSpnA(LPCSTR lpszStr, LPCSTR lpszMatch)
1108 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1110 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, TRUE);
1113 /*************************************************************************
1114 * StrCSpnW [SHLWAPI.@]
1116 * See StrCSpnA.
1118 int WINAPI StrCSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1120 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1122 return SHLWAPI_StrSpnHelperW(lpszStr, lpszMatch, StrChrW, TRUE);
1125 /*************************************************************************
1126 * StrCSpnIA [SHLWAPI.@]
1128 * Find the length of the start of a string that does not contain certain
1129 * characters, ignoring case.
1131 * PARAMS
1132 * lpszStr [I] String to search
1133 * lpszMatch [I] Characters that cannot be in the substring
1135 * RETURNS
1136 * The length of the part of lpszStr containing only chars not in lpszMatch,
1137 * or 0 if any parameter is invalid.
1139 int WINAPI StrCSpnIA(LPCSTR lpszStr, LPCSTR lpszMatch)
1141 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1143 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrIA, TRUE);
1146 /*************************************************************************
1147 * StrCSpnIW [SHLWAPI.@]
1149 * See StrCSpnIA.
1151 int WINAPI StrCSpnIW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1153 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1155 return SHLWAPI_StrSpnHelperW(lpszStr, lpszMatch, StrChrIW, TRUE);
1158 /*************************************************************************
1159 * StrPBrkA [SHLWAPI.@]
1161 * Search a string for any of a group of characters.
1163 * PARAMS
1164 * lpszStr [I] String to search
1165 * lpszMatch [I] Characters to match
1167 * RETURNS
1168 * A pointer to the first matching character in lpszStr, or NULL if no
1169 * match was found.
1171 LPSTR WINAPI StrPBrkA(LPCSTR lpszStr, LPCSTR lpszMatch)
1173 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1175 if (lpszStr && lpszMatch && *lpszMatch)
1177 while (*lpszStr)
1179 if (StrChrA(lpszMatch, *lpszStr))
1180 return (LPSTR)lpszStr;
1181 lpszStr = CharNextA(lpszStr);
1184 return NULL;
1187 /*************************************************************************
1188 * StrPBrkW [SHLWAPI.@]
1190 * See StrPBrkA.
1192 LPWSTR WINAPI StrPBrkW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1194 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1196 if (lpszStr && lpszMatch && *lpszMatch)
1198 while (*lpszStr)
1200 if (StrChrW(lpszMatch, *lpszStr))
1201 return (LPWSTR)lpszStr;
1202 lpszStr = CharNextW(lpszStr);
1205 return NULL;
1208 /*************************************************************************
1209 * SHLWAPI_StrRChrHelperA
1211 * Internal implementation of StrRChrA/StrRChrIA.
1213 static LPSTR WINAPI SHLWAPI_StrRChrHelperA(LPCSTR lpszStr,
1214 LPCSTR lpszEnd, WORD ch,
1215 BOOL (WINAPI *pChrCmpFn)(WORD,WORD))
1217 LPCSTR lpszRet = NULL;
1219 if (lpszStr)
1221 WORD ch2;
1223 if (!lpszEnd)
1224 lpszEnd = lpszStr + lstrlenA(lpszStr);
1226 while (*lpszStr && lpszStr <= lpszEnd)
1228 ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr;
1230 if (!pChrCmpFn(ch, ch2))
1231 lpszRet = lpszStr;
1232 lpszStr = CharNextA(lpszStr);
1235 return (LPSTR)lpszRet;
1238 /*************************************************************************
1239 * SHLWAPI_StrRChrHelperW
1241 * Internal implementation of StrRChrW/StrRChrIW.
1243 static LPWSTR WINAPI SHLWAPI_StrRChrHelperW(LPCWSTR lpszStr,
1244 LPCWSTR lpszEnd, WCHAR ch,
1245 BOOL (WINAPI *pChrCmpFn)(WCHAR,WCHAR))
1247 LPCWSTR lpszRet = NULL;
1249 if (lpszStr)
1251 if (!lpszEnd)
1252 lpszEnd = lpszStr + strlenW(lpszStr);
1254 while (*lpszStr && lpszStr <= lpszEnd)
1256 if (!pChrCmpFn(ch, *lpszStr))
1257 lpszRet = lpszStr;
1258 lpszStr = CharNextW(lpszStr);
1261 return (LPWSTR)lpszRet;
1264 /**************************************************************************
1265 * StrRChrA [SHLWAPI.@]
1267 * Find the last occurrence of a character in string.
1269 * PARAMS
1270 * lpszStr [I] String to search in
1271 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1272 * ch [I] Character to search for.
1274 * RETURNS
1275 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1276 * or NULL if not found.
1277 * Failure: NULL, if any arguments are invalid.
1279 LPSTR WINAPI StrRChrA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch)
1281 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch);
1283 return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, SHLWAPI_ChrCmpA);
1286 /**************************************************************************
1287 * StrRChrW [SHLWAPI.@]
1289 * See StrRChrA.
1291 LPWSTR WINAPI StrRChrW(LPCWSTR lpszStr, LPCWSTR lpszEnd, WORD ch)
1293 TRACE("(%s,%s,%x)\n", debugstr_w(lpszStr), debugstr_w(lpszEnd), ch);
1295 return SHLWAPI_StrRChrHelperW(lpszStr, lpszEnd, ch, SHLWAPI_ChrCmpW);
1298 /**************************************************************************
1299 * StrRChrIA [SHLWAPI.@]
1301 * Find the last occurrence of a character in string, ignoring case.
1303 * PARAMS
1304 * lpszStr [I] String to search in
1305 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1306 * ch [I] Character to search for.
1308 * RETURNS
1309 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1310 * or NULL if not found.
1311 * Failure: NULL, if any arguments are invalid.
1313 LPSTR WINAPI StrRChrIA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch)
1315 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch);
1317 return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, ChrCmpIA);
1320 /**************************************************************************
1321 * StrRChrIW [SHLWAPI.@]
1323 * See StrRChrIA.
1325 LPWSTR WINAPI StrRChrIW(LPCWSTR lpszStr, LPCWSTR lpszEnd, WORD ch)
1327 TRACE("(%s,%s,%x)\n", debugstr_w(lpszStr), debugstr_w(lpszEnd), ch);
1329 return SHLWAPI_StrRChrHelperW(lpszStr, lpszEnd, ch, ChrCmpIW);
1332 /*************************************************************************
1333 * StrCatBuffA [SHLWAPI.@]
1335 * Concatenate two strings together.
1337 * PARAMS
1338 * lpszStr [O] String to concatenate to
1339 * lpszCat [I] String to add to lpszCat
1340 * cchMax [I] Maximum number of characters for the whole string
1342 * RETURNS
1343 * lpszStr.
1345 * NOTES
1346 * cchMax determines the number of characters in the final length of the
1347 * string, not the number appended to lpszStr from lpszCat.
1349 LPSTR WINAPI StrCatBuffA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax)
1351 INT iLen;
1353 TRACE("(%p,%s,%d)\n", lpszStr, debugstr_a(lpszCat), cchMax);
1355 if (!lpszStr)
1357 WARN("Invalid lpszStr would crash under Win32!\n");
1358 return NULL;
1361 iLen = strlen(lpszStr);
1362 cchMax -= iLen;
1364 if (cchMax > 0)
1365 StrCpyNA(lpszStr + iLen, lpszCat, cchMax);
1366 return lpszStr;
1369 /*************************************************************************
1370 * StrCatBuffW [SHLWAPI.@]
1372 * See StrCatBuffA.
1374 LPWSTR WINAPI StrCatBuffW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax)
1376 INT iLen;
1378 TRACE("(%p,%s,%d)\n", lpszStr, debugstr_w(lpszCat), cchMax);
1380 if (!lpszStr)
1382 WARN("Invalid lpszStr would crash under Win32!\n");
1383 return NULL;
1386 iLen = strlenW(lpszStr);
1387 cchMax -= iLen;
1389 if (cchMax > 0)
1390 StrCpyNW(lpszStr + iLen, lpszCat, cchMax);
1391 return lpszStr;
1394 /*************************************************************************
1395 * StrRetToBufA [SHLWAPI.@]
1397 * Convert a STRRET to a normal string.
1399 * PARAMS
1400 * lpStrRet [O] STRRET to convert
1401 * pIdl [I] ITEMIDLIST for lpStrRet->uType == STRRET_OFFSET
1402 * lpszDest [O] Destination for normal string
1403 * dwLen [I] Length of lpszDest
1405 * RETURNS
1406 * Success: S_OK. lpszDest contains up to dwLen characters of the string.
1407 * If lpStrRet is of type STRRET_WSTR, its memory is freed with
1408 * CoTaskMemFree() and its type set to STRRET_CSTRA.
1409 * Failure: E_FAIL, if any parameters are invalid.
1411 HRESULT WINAPI StrRetToBufA (LPSTRRET src, const ITEMIDLIST *pidl, LPSTR dest, UINT len)
1413 /* NOTE:
1414 * This routine is identical to that in dlls/shell32/shellstring.c.
1415 * It was duplicated because not every version of Shlwapi.dll exports
1416 * StrRetToBufA. If you change one routine, change them both.
1418 TRACE("dest=%p len=0x%x strret=%p pidl=%p stub\n",dest,len,src,pidl);
1420 if (!src)
1422 WARN("Invalid lpStrRet would crash under Win32!\n");
1423 if (dest)
1424 *dest = '\0';
1425 return E_FAIL;
1428 if (!dest || !len)
1429 return E_FAIL;
1431 *dest = '\0';
1433 switch (src->uType)
1435 case STRRET_WSTR:
1436 WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, dest, len, NULL, NULL);
1437 CoTaskMemFree(src->u.pOleStr);
1438 break;
1440 case STRRET_CSTR:
1441 lstrcpynA((LPSTR)dest, src->u.cStr, len);
1442 break;
1444 case STRRET_OFFSET:
1445 lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len);
1446 break;
1448 default:
1449 FIXME("unknown type!\n");
1450 return FALSE;
1452 return S_OK;
1455 /*************************************************************************
1456 * StrRetToBufW [SHLWAPI.@]
1458 * See StrRetToBufA.
1460 HRESULT WINAPI StrRetToBufW (LPSTRRET src, const ITEMIDLIST *pidl, LPWSTR dest, UINT len)
1462 TRACE("dest=%p len=0x%x strret=%p pidl=%p stub\n",dest,len,src,pidl);
1464 if (!src)
1466 WARN("Invalid lpStrRet would crash under Win32!\n");
1467 if (dest)
1468 *dest = '\0';
1469 return E_FAIL;
1472 if (!dest || !len)
1473 return E_FAIL;
1475 *dest = '\0';
1477 switch (src->uType)
1479 case STRRET_WSTR:
1480 lstrcpynW((LPWSTR)dest, src->u.pOleStr, len);
1481 CoTaskMemFree(src->u.pOleStr);
1482 break;
1484 case STRRET_CSTR:
1485 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
1486 dest[len-1] = 0;
1487 break;
1489 case STRRET_OFFSET:
1490 if (pidl)
1492 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1,
1493 dest, len ) && len)
1494 dest[len-1] = 0;
1496 break;
1498 default:
1499 FIXME("unknown type!\n");
1500 return FALSE;
1502 return S_OK;
1505 /*************************************************************************
1506 * StrRetToStrA [SHLWAPI.@]
1508 * Converts a STRRET to a normal string.
1510 * PARAMS
1511 * lpStrRet [O] STRRET to convert
1512 * pidl [I] ITEMIDLIST for lpStrRet->uType == STRRET_OFFSET
1513 * ppszName [O] Destination for converted string
1515 * RETURNS
1516 * Success: S_OK. ppszName contains the new string, allocated with CoTaskMemAlloc().
1517 * Failure: E_FAIL, if any parameters are invalid.
1519 HRESULT WINAPI StrRetToStrA(LPSTRRET lpStrRet, const ITEMIDLIST *pidl, LPSTR *ppszName)
1521 HRESULT hRet = E_FAIL;
1523 switch (lpStrRet->uType)
1525 case STRRET_WSTR:
1526 hRet = _SHStrDupAW(lpStrRet->u.pOleStr, ppszName);
1527 CoTaskMemFree(lpStrRet->u.pOleStr);
1528 break;
1530 case STRRET_CSTR:
1531 hRet = _SHStrDupAA(lpStrRet->u.cStr, ppszName);
1532 break;
1534 case STRRET_OFFSET:
1535 hRet = _SHStrDupAA(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, ppszName);
1536 break;
1538 default:
1539 *ppszName = NULL;
1542 return hRet;
1545 /*************************************************************************
1546 * StrRetToStrW [SHLWAPI.@]
1548 * See StrRetToStrA.
1550 HRESULT WINAPI StrRetToStrW(LPSTRRET lpStrRet, const ITEMIDLIST *pidl, LPWSTR *ppszName)
1552 HRESULT hRet = E_FAIL;
1554 switch (lpStrRet->uType)
1556 case STRRET_WSTR:
1557 hRet = SHStrDupW(lpStrRet->u.pOleStr, ppszName);
1558 CoTaskMemFree(lpStrRet->u.pOleStr);
1559 break;
1561 case STRRET_CSTR:
1562 hRet = SHStrDupA(lpStrRet->u.cStr, ppszName);
1563 break;
1565 case STRRET_OFFSET:
1566 hRet = SHStrDupA(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, ppszName);
1567 break;
1569 default:
1570 *ppszName = NULL;
1573 return hRet;
1576 /* Create an ASCII string copy using SysAllocString() */
1577 static HRESULT _SHStrDupAToBSTR(LPCSTR src, BSTR *pBstrOut)
1579 *pBstrOut = NULL;
1581 if (src)
1583 INT len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0);
1584 WCHAR* szTemp = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1586 if (szTemp)
1588 MultiByteToWideChar(CP_ACP, 0, src, -1, szTemp, len);
1589 *pBstrOut = SysAllocString(szTemp);
1590 HeapFree(GetProcessHeap(), 0, szTemp);
1592 if (*pBstrOut)
1593 return S_OK;
1596 return E_OUTOFMEMORY;
1599 /*************************************************************************
1600 * StrRetToBSTR [SHLWAPI.@]
1602 * Converts a STRRET to a BSTR.
1604 * PARAMS
1605 * lpStrRet [O] STRRET to convert
1606 * pidl [I] ITEMIDLIST for lpStrRet->uType = STRRET_OFFSET
1607 * pBstrOut [O] Destination for converted BSTR
1609 * RETURNS
1610 * Success: S_OK. pBstrOut contains the new string.
1611 * Failure: E_FAIL, if any parameters are invalid.
1613 HRESULT WINAPI StrRetToBSTR(STRRET *lpStrRet, LPCITEMIDLIST pidl, BSTR* pBstrOut)
1615 HRESULT hRet = E_FAIL;
1617 switch (lpStrRet->uType)
1619 case STRRET_WSTR:
1620 *pBstrOut = SysAllocString(lpStrRet->u.pOleStr);
1621 if (*pBstrOut)
1622 hRet = S_OK;
1623 CoTaskMemFree(lpStrRet->u.pOleStr);
1624 break;
1626 case STRRET_CSTR:
1627 hRet = _SHStrDupAToBSTR(lpStrRet->u.cStr, pBstrOut);
1628 break;
1630 case STRRET_OFFSET:
1631 hRet = _SHStrDupAToBSTR(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, pBstrOut);
1632 break;
1634 default:
1635 *pBstrOut = NULL;
1638 return hRet;
1641 /*************************************************************************
1642 * StrFormatKBSizeA [SHLWAPI.@]
1644 * Create a formatted string containing a byte count in Kilobytes.
1646 * PARAMS
1647 * llBytes [I] Byte size to format
1648 * lpszDest [I] Destination for formatted string
1649 * cchMax [I] Size of lpszDest
1651 * RETURNS
1652 * lpszDest.
1654 LPSTR WINAPI StrFormatKBSizeA(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax)
1656 WCHAR wszBuf[256];
1658 if (!StrFormatKBSizeW(llBytes, wszBuf, 256))
1659 return NULL;
1660 if (!WideCharToMultiByte(CP_ACP, 0, wszBuf, -1, lpszDest, cchMax, NULL, NULL))
1661 return NULL;
1662 return lpszDest;
1665 /*************************************************************************
1666 * StrFormatKBSizeW [SHLWAPI.@]
1668 * See StrFormatKBSizeA.
1670 LPWSTR WINAPI StrFormatKBSizeW(LONGLONG llBytes, LPWSTR lpszDest, UINT cchMax)
1672 static const WCHAR kb[] = {' ','K','B',0};
1673 LONGLONG llKB = (llBytes + 1023) >> 10;
1674 int len;
1676 TRACE("(0x%s,%p,%d)\n", wine_dbgstr_longlong(llBytes), lpszDest, cchMax);
1678 if (!FormatInt(llKB, lpszDest, cchMax))
1679 return NULL;
1681 len = lstrlenW(lpszDest);
1682 if (cchMax - len < 4)
1683 return NULL;
1684 lstrcatW(lpszDest, kb);
1685 return lpszDest;
1688 /*************************************************************************
1689 * StrNCatA [SHLWAPI.@]
1691 * Concatenate two strings together.
1693 * PARAMS
1694 * lpszStr [O] String to concatenate to
1695 * lpszCat [I] String to add to lpszCat
1696 * cchMax [I] Maximum number of characters to concatenate
1698 * RETURNS
1699 * lpszStr.
1701 * NOTES
1702 * cchMax determines the number of characters that are appended to lpszStr,
1703 * not the total length of the string.
1705 LPSTR WINAPI StrNCatA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax)
1707 LPSTR lpszRet = lpszStr;
1709 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszCat), cchMax);
1711 if (!lpszStr)
1713 WARN("Invalid lpszStr would crash under Win32!\n");
1714 return NULL;
1717 StrCpyNA(lpszStr + strlen(lpszStr), lpszCat, cchMax);
1718 return lpszRet;
1721 /*************************************************************************
1722 * StrNCatW [SHLWAPI.@]
1724 * See StrNCatA.
1726 LPWSTR WINAPI StrNCatW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax)
1728 LPWSTR lpszRet = lpszStr;
1730 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszCat), cchMax);
1732 if (!lpszStr)
1734 WARN("Invalid lpszStr would crash under Win32\n");
1735 return NULL;
1738 StrCpyNW(lpszStr + strlenW(lpszStr), lpszCat, cchMax);
1739 return lpszRet;
1742 /*************************************************************************
1743 * StrTrimA [SHLWAPI.@]
1745 * Remove characters from the start and end of a string.
1747 * PARAMS
1748 * lpszStr [O] String to remove characters from
1749 * lpszTrim [I] Characters to remove from lpszStr
1751 * RETURNS
1752 * TRUE If lpszStr was valid and modified
1753 * FALSE Otherwise
1755 BOOL WINAPI StrTrimA(LPSTR lpszStr, LPCSTR lpszTrim)
1757 DWORD dwLen;
1758 LPSTR lpszRead = lpszStr;
1759 BOOL bRet = FALSE;
1761 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszTrim));
1763 if (lpszRead && *lpszRead)
1765 while (*lpszRead && StrChrA(lpszTrim, *lpszRead))
1766 lpszRead = CharNextA(lpszRead); /* Skip leading matches */
1768 dwLen = strlen(lpszRead);
1770 if (lpszRead != lpszStr)
1772 memmove(lpszStr, lpszRead, dwLen + 1);
1773 bRet = TRUE;
1775 if (dwLen > 0)
1777 lpszRead = lpszStr + dwLen;
1778 while (StrChrA(lpszTrim, lpszRead[-1]))
1779 lpszRead = CharPrevA(lpszStr, lpszRead); /* Skip trailing matches */
1781 if (lpszRead != lpszStr + dwLen)
1783 *lpszRead = '\0';
1784 bRet = TRUE;
1788 return bRet;
1791 /*************************************************************************
1792 * StrTrimW [SHLWAPI.@]
1794 * See StrTrimA.
1796 BOOL WINAPI StrTrimW(LPWSTR lpszStr, LPCWSTR lpszTrim)
1798 DWORD dwLen;
1799 LPWSTR lpszRead = lpszStr;
1800 BOOL bRet = FALSE;
1802 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszTrim));
1804 if (lpszRead && *lpszRead)
1806 while (*lpszRead && StrChrW(lpszTrim, *lpszRead))
1807 lpszRead = CharNextW(lpszRead); /* Skip leading matches */
1809 dwLen = strlenW(lpszRead);
1811 if (lpszRead != lpszStr)
1813 memmove(lpszStr, lpszRead, (dwLen + 1) * sizeof(WCHAR));
1814 bRet = TRUE;
1816 if (dwLen > 0)
1818 lpszRead = lpszStr + dwLen;
1819 while (StrChrW(lpszTrim, lpszRead[-1]))
1820 lpszRead = CharPrevW(lpszStr, lpszRead); /* Skip trailing matches */
1822 if (lpszRead != lpszStr + dwLen)
1824 *lpszRead = '\0';
1825 bRet = TRUE;
1829 return bRet;
1832 /*************************************************************************
1833 * _SHStrDupAA [INTERNAL]
1835 * Duplicates a ASCII string to ASCII. The destination buffer is allocated.
1837 static HRESULT WINAPI _SHStrDupAA(LPCSTR src, LPSTR * dest)
1839 HRESULT hr;
1840 int len = 0;
1842 if (src) {
1843 len = lstrlenA(src) + 1;
1844 *dest = CoTaskMemAlloc(len);
1845 } else {
1846 *dest = NULL;
1849 if (*dest) {
1850 lstrcpynA(*dest,src, len);
1851 hr = S_OK;
1852 } else {
1853 hr = E_OUTOFMEMORY;
1856 TRACE("%s->(%p)\n", debugstr_a(src), *dest);
1857 return hr;
1860 /*************************************************************************
1861 * SHStrDupA [SHLWAPI.@]
1863 * Return a Unicode copy of a string, in memory allocated by CoTaskMemAlloc().
1865 * PARAMS
1866 * lpszStr [I] String to copy
1867 * lppszDest [O] Destination for the new string copy
1869 * RETURNS
1870 * Success: S_OK. lppszDest contains the new string in Unicode format.
1871 * Failure: E_OUTOFMEMORY, If any arguments are invalid or memory allocation
1872 * fails.
1874 HRESULT WINAPI SHStrDupA(LPCSTR lpszStr, LPWSTR * lppszDest)
1876 HRESULT hRet;
1877 int len = 0;
1879 if (lpszStr)
1881 len = MultiByteToWideChar(0, 0, lpszStr, -1, 0, 0) * sizeof(WCHAR);
1882 *lppszDest = CoTaskMemAlloc(len);
1884 else
1885 *lppszDest = NULL;
1887 if (*lppszDest)
1889 MultiByteToWideChar(0, 0, lpszStr, -1, *lppszDest, len/sizeof(WCHAR));
1890 hRet = S_OK;
1892 else
1893 hRet = E_OUTOFMEMORY;
1895 TRACE("%s->(%p)\n", debugstr_a(lpszStr), *lppszDest);
1896 return hRet;
1899 /*************************************************************************
1900 * _SHStrDupAW [INTERNAL]
1902 * Duplicates a UNICODE to a ASCII string. The destination buffer is allocated.
1904 static HRESULT WINAPI _SHStrDupAW(LPCWSTR src, LPSTR * dest)
1906 HRESULT hr;
1907 int len = 0;
1909 if (src) {
1910 len = WideCharToMultiByte(CP_ACP, 0, src, -1, NULL, 0, NULL, NULL);
1911 *dest = CoTaskMemAlloc(len);
1912 } else {
1913 *dest = NULL;
1916 if (*dest) {
1917 WideCharToMultiByte(CP_ACP, 0, src, -1, *dest, len, NULL, NULL);
1918 hr = S_OK;
1919 } else {
1920 hr = E_OUTOFMEMORY;
1923 TRACE("%s->(%p)\n", debugstr_w(src), *dest);
1924 return hr;
1927 /*************************************************************************
1928 * SHStrDupW [SHLWAPI.@]
1930 * See SHStrDupA.
1932 HRESULT WINAPI SHStrDupW(LPCWSTR src, LPWSTR * dest)
1934 HRESULT hr;
1935 int len = 0;
1937 if (src) {
1938 len = (lstrlenW(src) + 1) * sizeof(WCHAR);
1939 *dest = CoTaskMemAlloc(len);
1940 } else {
1941 *dest = NULL;
1944 if (*dest) {
1945 memcpy(*dest, src, len);
1946 hr = S_OK;
1947 } else {
1948 hr = E_OUTOFMEMORY;
1951 TRACE("%s->(%p)\n", debugstr_w(src), *dest);
1952 return hr;
1955 /*************************************************************************
1956 * SHLWAPI_WriteReverseNum
1958 * Internal helper for SHLWAPI_WriteTimeClass.
1960 inline static LPWSTR SHLWAPI_WriteReverseNum(LPWSTR lpszOut, DWORD dwNum)
1962 *lpszOut-- = '\0';
1964 /* Write a decimal number to a string, backwards */
1967 DWORD dwNextDigit = dwNum % 10;
1968 *lpszOut-- = '0' + dwNextDigit;
1969 dwNum = (dwNum - dwNextDigit) / 10;
1970 } while (dwNum > 0);
1972 return lpszOut;
1975 /*************************************************************************
1976 * SHLWAPI_FormatSignificant
1978 * Internal helper for SHLWAPI_WriteTimeClass.
1980 inline static int SHLWAPI_FormatSignificant(LPWSTR lpszNum, int dwDigits)
1982 /* Zero non significant digits, return remaining significant digits */
1983 while (*lpszNum)
1985 lpszNum++;
1986 if (--dwDigits == 0)
1988 while (*lpszNum)
1989 *lpszNum++ = '0';
1990 return 0;
1993 return dwDigits;
1996 /*************************************************************************
1997 * SHLWAPI_WriteTimeClass
1999 * Internal helper for StrFromTimeIntervalW.
2001 static int WINAPI SHLWAPI_WriteTimeClass(LPWSTR lpszOut, DWORD dwValue,
2002 UINT uClassStringId, int iDigits)
2004 WCHAR szBuff[64], *szOut = szBuff + 32;
2006 szOut = SHLWAPI_WriteReverseNum(szOut, dwValue);
2007 iDigits = SHLWAPI_FormatSignificant(szOut + 1, iDigits);
2008 *szOut = ' ';
2009 LoadStringW(shlwapi_hInstance, uClassStringId, szBuff + 32, 32);
2010 strcatW(lpszOut, szOut);
2011 return iDigits;
2014 /*************************************************************************
2015 * StrFromTimeIntervalA [SHLWAPI.@]
2017 * Format a millisecond time interval into a string
2019 * PARAMS
2020 * lpszStr [O] Output buffer for formatted time interval
2021 * cchMax [I] Size of lpszStr
2022 * dwMS [I] Number of milliseconds
2023 * iDigits [I] Number of digits to print
2025 * RETURNS
2026 * The length of the formatted string, or 0 if any parameter is invalid.
2028 * NOTES
2029 * This implementation mimics the Win32 behaviour of always writing a leading
2030 * space before the time interval begins.
2032 * iDigits is used to provide approximate times if accuracy is not important.
2033 * This number of digits will be written of the first non-zero time class
2034 * (hours/minutes/seconds). If this does not complete the time classification,
2035 * the remaining digits are changed to zeros (i.e. The time is _not_ rounded).
2036 * If there are digits remaining following the writing of a time class, the
2037 * next time class will be written.
2039 * For example, given dwMS represents 138 hours,43 minutes and 15 seconds, the
2040 * following will result from the given values of iDigits:
2042 *| iDigits 1 2 3 4 5 ...
2043 *| lpszStr "100 hr" "130 hr" "138 hr" "138 hr 40 min" "138 hr 43 min" ...
2045 INT WINAPI StrFromTimeIntervalA(LPSTR lpszStr, UINT cchMax, DWORD dwMS,
2046 int iDigits)
2048 INT iRet = 0;
2050 TRACE("(%p,%d,%ld,%d)\n", lpszStr, cchMax, dwMS, iDigits);
2052 if (lpszStr && cchMax)
2054 WCHAR szBuff[128];
2055 StrFromTimeIntervalW(szBuff, sizeof(szBuff)/sizeof(WCHAR), dwMS, iDigits);
2056 WideCharToMultiByte(CP_ACP,0,szBuff,-1,lpszStr,cchMax,0,0);
2058 return iRet;
2062 /*************************************************************************
2063 * StrFromTimeIntervalW [SHLWAPI.@]
2065 * See StrFromTimeIntervalA.
2067 INT WINAPI StrFromTimeIntervalW(LPWSTR lpszStr, UINT cchMax, DWORD dwMS,
2068 int iDigits)
2070 INT iRet = 0;
2072 TRACE("(%p,%d,%ld,%d)\n", lpszStr, cchMax, dwMS, iDigits);
2074 if (lpszStr && cchMax)
2076 WCHAR szCopy[128];
2077 DWORD dwHours, dwMinutes;
2079 if (!iDigits || cchMax == 1)
2081 *lpszStr = '\0';
2082 return 0;
2085 /* Calculate the time classes */
2086 dwMS = (dwMS + 500) / 1000;
2087 dwHours = dwMS / 3600;
2088 dwMS -= dwHours * 3600;
2089 dwMinutes = dwMS / 60;
2090 dwMS -= dwMinutes * 60;
2092 szCopy[0] = '\0';
2094 if (dwHours)
2095 iDigits = SHLWAPI_WriteTimeClass(szCopy, dwHours, IDS_TIME_INTERVAL_HOURS, iDigits);
2097 if (dwMinutes && iDigits)
2098 iDigits = SHLWAPI_WriteTimeClass(szCopy, dwMinutes, IDS_TIME_INTERVAL_MINUTES, iDigits);
2100 if (iDigits) /* Always write seconds if we have significant digits */
2101 SHLWAPI_WriteTimeClass(szCopy, dwMS, IDS_TIME_INTERVAL_SECONDS, iDigits);
2103 lstrcpynW(lpszStr, szCopy, cchMax);
2104 iRet = strlenW(lpszStr);
2106 return iRet;
2109 /*************************************************************************
2110 * StrIsIntlEqualA [SHLWAPI.@]
2112 * Compare two strings.
2114 * PARAMS
2115 * bCase [I] Whether to compare case sensitively
2116 * lpszStr [I] First string to compare
2117 * lpszComp [I] Second string to compare
2118 * iLen [I] Length to compare
2120 * RETURNS
2121 * TRUE If the strings are equal.
2122 * FALSE Otherwise.
2124 BOOL WINAPI StrIsIntlEqualA(BOOL bCase, LPCSTR lpszStr, LPCSTR lpszComp,
2125 int iLen)
2127 DWORD dwFlags;
2129 TRACE("(%d,%s,%s,%d)\n", bCase,
2130 debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
2132 /* FIXME: This flag is undocumented and unknown by our CompareString.
2133 * We need a define for it.
2135 dwFlags = 0x10000000;
2136 if (!bCase) dwFlags |= NORM_IGNORECASE;
2138 return (CompareStringA(GetThreadLocale(), dwFlags, lpszStr, iLen, lpszComp, iLen) == CSTR_EQUAL);
2141 /*************************************************************************
2142 * StrIsIntlEqualW [SHLWAPI.@]
2144 * See StrIsIntlEqualA.
2146 BOOL WINAPI StrIsIntlEqualW(BOOL bCase, LPCWSTR lpszStr, LPCWSTR lpszComp,
2147 int iLen)
2149 DWORD dwFlags;
2151 TRACE("(%d,%s,%s,%d)\n", bCase,
2152 debugstr_w(lpszStr),debugstr_w(lpszComp), iLen);
2154 /* FIXME: This flag is undocumented and unknown by our CompareString.
2155 * We need a define for it.
2157 dwFlags = 0x10000000;
2158 if (!bCase) dwFlags |= NORM_IGNORECASE;
2160 return (CompareStringW(GetThreadLocale(), dwFlags, lpszStr, iLen, lpszComp, iLen) == CSTR_EQUAL);
2163 /*************************************************************************
2164 * @ [SHLWAPI.399]
2166 * Copy a string to another string, up to a maximum number of characters.
2168 * PARAMS
2169 * lpszDest [O] Destination string
2170 * lpszSrc [I] Source string
2171 * iLen [I] Maximum number of chars to copy
2173 * RETURNS
2174 * Success: A pointer to the last character written to lpszDest..
2175 * Failure: lpszDest, if any arguments are invalid.
2177 LPSTR WINAPI StrCpyNXA(LPSTR lpszDest, LPCSTR lpszSrc, int iLen)
2179 TRACE("(%p,%s,%i)\n", lpszDest, debugstr_a(lpszSrc), iLen);
2181 if (lpszDest && lpszSrc && iLen > 0)
2183 while ((iLen-- > 1) && *lpszSrc)
2184 *lpszDest++ = *lpszSrc++;
2185 if (iLen >= 0)
2186 *lpszDest = '\0';
2188 return lpszDest;
2191 /*************************************************************************
2192 * @ [SHLWAPI.400]
2194 * Unicode version of StrCpyNXA.
2196 LPWSTR WINAPI StrCpyNXW(LPWSTR lpszDest, LPCWSTR lpszSrc, int iLen)
2198 TRACE("(%p,%s,%i)\n", lpszDest, debugstr_w(lpszSrc), iLen);
2200 if (lpszDest && lpszSrc && iLen > 0)
2202 while ((iLen-- > 1) && *lpszSrc)
2203 *lpszDest++ = *lpszSrc++;
2204 if (iLen >= 0)
2205 *lpszDest = '\0';
2207 return lpszDest;
2210 /*************************************************************************
2211 * StrCmpLogicalW [SHLWAPI.@]
2213 * Compare two strings, ignoring case and comparing digits as numbers.
2215 * PARAMS
2216 * lpszStr [I] First string to compare
2217 * lpszComp [I] Second string to compare
2218 * iLen [I] Length to compare
2220 * RETURNS
2221 * TRUE If the strings are equal.
2222 * FALSE Otherwise.
2224 INT WINAPI StrCmpLogicalW(LPCWSTR lpszStr, LPCWSTR lpszComp)
2226 INT iDiff;
2228 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszComp));
2230 if (lpszStr && lpszComp)
2232 while (*lpszStr)
2234 if (!*lpszComp)
2235 return 1;
2236 else if (isdigitW(*lpszStr))
2238 int iStr, iComp;
2240 if (!isdigitW(*lpszComp))
2241 return -1;
2243 /* Compare the numbers */
2244 StrToIntExW(lpszStr, 0, &iStr);
2245 StrToIntExW(lpszComp, 0, &iComp);
2247 if (iStr < iComp)
2248 return -1;
2249 else if (iStr > iComp)
2250 return 1;
2252 /* Skip */
2253 while (isdigitW(*lpszStr))
2254 lpszStr++;
2255 while (isdigitW(*lpszComp))
2256 lpszComp++;
2258 else if (isdigitW(*lpszComp))
2259 return 1;
2260 else
2262 iDiff = SHLWAPI_ChrCmpHelperW(*lpszStr,*lpszComp,NORM_IGNORECASE);
2263 if (iDiff > 0)
2264 return 1;
2265 else if (iDiff < 0)
2266 return -1;
2268 lpszStr++;
2269 lpszComp++;
2272 if (*lpszComp)
2273 return -1;
2275 return 0;
2278 /* Structure for formatting byte strings */
2279 typedef struct tagSHLWAPI_BYTEFORMATS
2281 LONGLONG dLimit;
2282 double dDivisor;
2283 double dNormaliser;
2284 int nDecimals;
2285 WCHAR wPrefix;
2286 } SHLWAPI_BYTEFORMATS;
2288 /*************************************************************************
2289 * StrFormatByteSizeW [SHLWAPI.@]
2291 * Create a string containing an abbreviated byte count of up to 2^63-1.
2293 * PARAMS
2294 * llBytes [I] Byte size to format
2295 * lpszDest [I] Destination for formatted string
2296 * cchMax [I] Size of lpszDest
2298 * RETURNS
2299 * lpszDest.
2301 * NOTES
2302 * There is no StrFormatByteSize64W function, it is called StrFormatByteSizeW().
2304 LPWSTR WINAPI StrFormatByteSizeW(LONGLONG llBytes, LPWSTR lpszDest, UINT cchMax)
2306 #define KB ((ULONGLONG)1024)
2307 #define MB (KB*KB)
2308 #define GB (KB*KB*KB)
2309 #define TB (KB*KB*KB*KB)
2310 #define PB (KB*KB*KB*KB*KB)
2312 static const SHLWAPI_BYTEFORMATS bfFormats[] =
2314 { 10*KB, 10.24, 100.0, 2, 'K' }, /* 10 KB */
2315 { 100*KB, 102.4, 10.0, 1, 'K' }, /* 100 KB */
2316 { 1000*KB, 1024.0, 1.0, 0, 'K' }, /* 1000 KB */
2317 { 10*MB, 10485.76, 100.0, 2, 'M' }, /* 10 MB */
2318 { 100*MB, 104857.6, 10.0, 1, 'M' }, /* 100 MB */
2319 { 1000*MB, 1048576.0, 1.0, 0, 'M' }, /* 1000 MB */
2320 { 10*GB, 10737418.24, 100.0, 2, 'G' }, /* 10 GB */
2321 { 100*GB, 107374182.4, 10.0, 1, 'G' }, /* 100 GB */
2322 { 1000*GB, 1073741824.0, 1.0, 0, 'G' }, /* 1000 GB */
2323 { 10*TB, 10485.76, 100.0, 2, 'T' }, /* 10 TB */
2324 { 100*TB, 104857.6, 10.0, 1, 'T' }, /* 100 TB */
2325 { 1000*TB, 1048576.0, 1.0, 0, 'T' }, /* 1000 TB */
2326 { 10*PB, 10737418.24, 100.00, 2, 'P' }, /* 10 PB */
2327 { 100*PB, 107374182.4, 10.00, 1, 'P' }, /* 100 PB */
2328 { 1000*PB, 1073741824.0, 1.00, 0, 'P' }, /* 1000 PB */
2329 { 0, 10995116277.76, 100.00, 2, 'E' } /* EB's, catch all */
2331 WCHAR wszAdd[] = {' ','?','B',0};
2332 double dBytes;
2333 UINT i = 0;
2335 TRACE("(0x%s,%p,%d)\n", wine_dbgstr_longlong(llBytes), lpszDest, cchMax);
2337 if (!lpszDest || !cchMax)
2338 return lpszDest;
2340 if (llBytes < 1024) /* 1K */
2342 WCHAR wszBytesFormat[64];
2343 LoadStringW(shlwapi_hInstance, IDS_BYTES_FORMAT, wszBytesFormat, 64);
2344 snprintfW(lpszDest, cchMax, wszBytesFormat, (long)llBytes);
2345 return lpszDest;
2348 /* Note that if this loop completes without finding a match, i will be
2349 * pointing at the last entry, which is a catch all for > 1000 PB
2351 while (i < sizeof(bfFormats) / sizeof(SHLWAPI_BYTEFORMATS) - 1)
2353 if (llBytes < bfFormats[i].dLimit)
2354 break;
2355 i++;
2357 /* Above 1 TB we encounter problems with FP accuracy. So for amounts above
2358 * this number we integer shift down by 1 MB first. The table above has
2359 * the divisors scaled down from the '< 10 TB' entry onwards, to account
2360 * for this. We also add a small fudge factor to get the correct result for
2361 * counts that lie exactly on a 1024 byte boundary.
2363 if (i > 8)
2364 dBytes = (double)(llBytes >> 20) + 0.001; /* Scale down by I MB */
2365 else
2366 dBytes = (double)llBytes + 0.00001;
2368 dBytes = floor(dBytes / bfFormats[i].dDivisor) / bfFormats[i].dNormaliser;
2370 if (!FormatDouble(dBytes, bfFormats[i].nDecimals, lpszDest, cchMax))
2371 return NULL;
2372 wszAdd[1] = bfFormats[i].wPrefix;
2373 StrCatBuffW(lpszDest, wszAdd, cchMax);
2374 return lpszDest;
2377 /*************************************************************************
2378 * StrFormatByteSize64A [SHLWAPI.@]
2380 * See StrFormatByteSizeW.
2382 LPSTR WINAPI StrFormatByteSize64A(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax)
2384 WCHAR wszBuff[32];
2386 StrFormatByteSizeW(llBytes, wszBuff, sizeof(wszBuff)/sizeof(WCHAR));
2388 if (lpszDest)
2389 WideCharToMultiByte(CP_ACP, 0, wszBuff, -1, lpszDest, cchMax, 0, 0);
2390 return lpszDest;
2393 /*************************************************************************
2394 * StrFormatByteSizeA [SHLWAPI.@]
2396 * Create a string containing an abbreviated byte count of up to 2^31-1.
2398 * PARAMS
2399 * dwBytes [I] Byte size to format
2400 * lpszDest [I] Destination for formatted string
2401 * cchMax [I] Size of lpszDest
2403 * RETURNS
2404 * lpszDest.
2406 * NOTES
2407 * The Ascii and Unicode versions of this function accept a different
2408 * integer type for dwBytes. See StrFormatByteSize64A().
2410 LPSTR WINAPI StrFormatByteSizeA(DWORD dwBytes, LPSTR lpszDest, UINT cchMax)
2412 TRACE("(%ld,%p,%d)\n", dwBytes, lpszDest, cchMax);
2414 return StrFormatByteSize64A(dwBytes, lpszDest, cchMax);
2417 /*************************************************************************
2418 * @ [SHLWAPI.162]
2420 * Remove a hanging lead byte from the end of a string, if present.
2422 * PARAMS
2423 * lpStr [I] String to check for a hanging lead byte
2424 * size [I] Length of lpStr
2426 * RETURNS
2427 * Success: The new length of the string. Any hanging lead bytes are removed.
2428 * Failure: 0, if any parameters are invalid.
2430 DWORD WINAPI SHTruncateString(LPSTR lpStr, DWORD size)
2432 if (lpStr && size)
2434 LPSTR lastByte = lpStr + size - 1;
2436 while(lpStr < lastByte)
2437 lpStr += IsDBCSLeadByte(*lpStr) ? 2 : 1;
2439 if(lpStr == lastByte && IsDBCSLeadByte(*lpStr))
2441 *lpStr = '\0';
2442 size--;
2444 return size;
2446 return 0;
2449 /*************************************************************************
2450 * @ [SHLWAPI.203]
2452 * Remove a single non-trailing ampersand ('&') from a string.
2454 * PARAMS
2455 * lpszStr [I/O] String to remove ampersand from.
2457 * RETURNS
2458 * The character after the first ampersand in lpszStr, or the first character
2459 * in lpszStr if there is no ampersand in the string.
2461 char WINAPI SHStripMneumonicA(LPCSTR lpszStr)
2463 LPSTR lpszIter, lpszTmp;
2464 char ch;
2466 TRACE("(%s)\n", debugstr_a(lpszStr));
2468 ch = *lpszStr;
2470 if ((lpszIter = StrChrA(lpszStr, '&')))
2472 lpszTmp = CharNextA(lpszIter);
2473 if (lpszTmp && *lpszTmp)
2475 if (*lpszTmp != '&')
2476 ch = *lpszTmp;
2478 while (lpszIter && *lpszIter)
2480 lpszTmp = CharNextA(lpszIter);
2481 *lpszIter = *lpszTmp;
2482 lpszIter = lpszTmp;
2487 return ch;
2490 /*************************************************************************
2491 * @ [SHLWAPI.225]
2493 * Unicode version of SHStripMneumonicA.
2495 WCHAR WINAPI SHStripMneumonicW(LPCWSTR lpszStr)
2497 LPWSTR lpszIter, lpszTmp;
2498 WCHAR ch;
2500 TRACE("(%s)\n", debugstr_w(lpszStr));
2502 ch = *lpszStr;
2504 if ((lpszIter = StrChrW(lpszStr, '&')))
2506 lpszTmp = CharNextW(lpszIter);
2507 if (lpszTmp && *lpszTmp)
2509 if (*lpszTmp != '&')
2510 ch = *lpszTmp;
2512 while (lpszIter && *lpszIter)
2514 lpszTmp = CharNextW(lpszIter);
2515 *lpszIter = *lpszTmp;
2516 lpszIter = lpszTmp;
2521 return ch;
2524 /*************************************************************************
2525 * @ [SHLWAPI.216]
2527 * Convert an Ascii string to Unicode.
2529 * PARAMS
2530 * dwCp [I] Code page for the conversion
2531 * lpSrcStr [I] Source Ascii string to convert
2532 * lpDstStr [O] Destination for converted Unicode string
2533 * iLen [I] Length of lpDstStr
2535 * RETURNS
2536 * The return value of the MultiByteToWideChar() function called on lpSrcStr.
2538 DWORD WINAPI SHAnsiToUnicodeCP(DWORD dwCp, LPCSTR lpSrcStr, LPWSTR lpDstStr, int iLen)
2540 DWORD dwRet;
2542 dwRet = MultiByteToWideChar(dwCp, 0, lpSrcStr, -1, lpDstStr, iLen);
2543 TRACE("%s->%s,ret=%ld\n", debugstr_a(lpSrcStr), debugstr_w(lpDstStr), dwRet);
2544 return dwRet;
2547 /*************************************************************************
2548 * @ [SHLWAPI.215]
2550 * Convert an Ascii string to Unicode.
2552 * PARAMS
2553 * lpSrcStr [I] Source Ascii string to convert
2554 * lpDstStr [O] Destination for converted Unicode string
2555 * iLen [I] Length of lpDstStr
2557 * RETURNS
2558 * The return value of the MultiByteToWideChar() function called on lpSrcStr.
2560 * NOTES
2561 * This function simply calls SHAnsiToUnicodeCP with code page CP_ACP.
2563 DWORD WINAPI SHAnsiToUnicode(LPCSTR lpSrcStr, LPWSTR lpDstStr, int iLen)
2565 return SHAnsiToUnicodeCP(CP_ACP, lpSrcStr, lpDstStr, iLen);
2568 /*************************************************************************
2569 * @ [SHLWAPI.218]
2571 * Convert a Unicode string to Ascii.
2573 * PARAMS
2574 * CodePage [I] Code page to use for the conversion
2575 * lpSrcStr [I] Source Unicode string to convert
2576 * lpDstStr [O] Destination for converted Ascii string
2577 * lpiLen [I/O] Input length of lpDstStr/destination for length of lpDstStr
2579 * RETURNS
2580 * Success: The number of characters that result from the conversion.
2581 * Failure: 0.
2583 INT WINAPI SHUnicodeToAnsiCP(UINT CodePage, LPCWSTR lpSrcStr, LPSTR lpDstStr,
2584 LPINT lpiLen)
2586 static const WCHAR emptyW[] = { '\0' };
2587 int len , reqLen;
2588 LPSTR mem;
2590 if (!lpDstStr || !lpiLen)
2591 return 0;
2593 if (!lpSrcStr)
2594 lpSrcStr = emptyW;
2596 *lpDstStr = '\0';
2598 len = strlenW(lpSrcStr) + 1;
2600 switch (CodePage)
2602 case CP_WINUNICODE:
2603 CodePage = CP_UTF8; /* Fall through... */
2604 case 0x0000C350: /* FIXME: CP_ #define */
2605 case CP_UTF7:
2606 case CP_UTF8:
2608 DWORD dwMode = 0;
2609 INT nWideCharCount = len - 1;
2611 GET_FUNC(pConvertINetUnicodeToMultiByte, mlang, "ConvertINetUnicodeToMultiByte", 0);
2612 if (!pConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &nWideCharCount, lpDstStr,
2613 lpiLen))
2614 return 0;
2616 if (nWideCharCount < len - 1)
2618 mem = HeapAlloc(GetProcessHeap(), 0, *lpiLen);
2619 if (!mem)
2620 return 0;
2622 *lpiLen = 0;
2624 if (pConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &len, mem, lpiLen))
2626 SHTruncateString(mem, *lpiLen);
2627 lstrcpynA(lpDstStr, mem, *lpiLen + 1);
2628 HeapFree(GetProcessHeap(), 0, mem);
2629 return *lpiLen + 1;
2631 HeapFree(GetProcessHeap(), 0, mem);
2632 return *lpiLen;
2634 lpDstStr[*lpiLen] = '\0';
2635 return *lpiLen;
2637 default:
2638 break;
2641 reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, lpDstStr,
2642 *lpiLen, NULL, NULL);
2644 if (!reqLen && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
2646 reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, NULL, 0, NULL, NULL);
2647 if (reqLen)
2649 mem = HeapAlloc(GetProcessHeap(), 0, reqLen);
2650 if (mem)
2652 reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, mem,
2653 reqLen, NULL, NULL);
2655 reqLen = SHTruncateString(mem, *lpiLen);
2656 reqLen++;
2658 lstrcpynA(lpDstStr, mem, *lpiLen);
2660 HeapFree(GetProcessHeap(), 0, mem);
2664 return reqLen;
2667 /*************************************************************************
2668 * @ [SHLWAPI.217]
2670 * Convert a Unicode string to Ascii.
2672 * PARAMS
2673 * lpSrcStr [I] Source Unicode string to convert
2674 * lpDstStr [O] Destination for converted Ascii string
2675 * iLen [O] Length of lpDstStr in characters
2677 * RETURNS
2678 * See SHUnicodeToAnsiCP
2680 * NOTES
2681 * This function simply calls SHUnicodeToAnsiCP() with CodePage = CP_ACP.
2683 INT WINAPI SHUnicodeToAnsi(LPCWSTR lpSrcStr, LPSTR lpDstStr, INT iLen)
2685 INT myint = iLen;
2687 return SHUnicodeToAnsiCP(CP_ACP, lpSrcStr, lpDstStr, &myint);
2690 /*************************************************************************
2691 * @ [SHLWAPI.345]
2693 * Copy one string to another.
2695 * PARAMS
2696 * lpszSrc [I] Source string to copy
2697 * lpszDst [O] Destination for copy
2698 * iLen [I] Length of lpszDst in characters
2700 * RETURNS
2701 * The length of the copied string, including the terminating NUL. lpszDst
2702 * contains iLen characters of lpszSrc.
2704 DWORD WINAPI SHAnsiToAnsi(LPCSTR lpszSrc, LPSTR lpszDst, int iLen)
2706 LPSTR lpszRet;
2708 TRACE("(%s,%p,0x%08x)\n", debugstr_a(lpszSrc), lpszDst, iLen);
2710 lpszRet = StrCpyNXA(lpszDst, lpszSrc, iLen);
2711 return lpszRet - lpszDst + 1;
2714 /*************************************************************************
2715 * @ [SHLWAPI.346]
2717 * Unicode version of SSHAnsiToAnsi.
2719 DWORD WINAPI SHUnicodeToUnicode(LPCWSTR lpszSrc, LPWSTR lpszDst, int iLen)
2721 LPWSTR lpszRet;
2723 TRACE("(%s,%p,0x%08x)\n", debugstr_w(lpszSrc), lpszDst, iLen);
2725 lpszRet = StrCpyNXW(lpszDst, lpszSrc, iLen);
2726 return lpszRet - lpszDst + 1;
2729 /*************************************************************************
2730 * @ [SHLWAPI.364]
2732 * Determine if an Ascii string converts to Unicode and back identically.
2734 * PARAMS
2735 * lpSrcStr [I] Source Unicode string to convert
2736 * lpDst [O] Destination for resulting Ascii string
2737 * iLen [I] Length of lpDst in characters
2739 * RETURNS
2740 * TRUE, since Ascii strings always convert identically.
2742 BOOL WINAPI DoesStringRoundTripA(LPCSTR lpSrcStr, LPSTR lpDst, INT iLen)
2744 lstrcpynA(lpDst, lpSrcStr, iLen);
2745 return TRUE;
2748 /*************************************************************************
2749 * @ [SHLWAPI.365]
2751 * Determine if a Unicode string converts to Ascii and back identically.
2753 * PARAMS
2754 * lpSrcStr [I] Source Unicode string to convert
2755 * lpDst [O] Destination for resulting Ascii string
2756 * iLen [I] Length of lpDst in characters
2758 * RETURNS
2759 * TRUE, if lpSrcStr converts to Ascii and back identically,
2760 * FALSE otherwise.
2762 BOOL WINAPI DoesStringRoundTripW(LPCWSTR lpSrcStr, LPSTR lpDst, INT iLen)
2764 WCHAR szBuff[MAX_PATH];
2766 SHUnicodeToAnsi(lpSrcStr, lpDst, iLen);
2767 SHAnsiToUnicode(lpDst, szBuff, MAX_PATH);
2768 return !strcmpW(lpSrcStr, szBuff);
2771 /*************************************************************************
2772 * SHLoadIndirectString [SHLWAPI.@]
2774 * If passed a string that begins with a '@' extract the string from the
2775 * appropriate resource, otherwise do a straight copy.
2778 HRESULT WINAPI SHLoadIndirectString(LPCWSTR src, LPWSTR dst, UINT dst_len, void **reserved)
2780 WCHAR *dllname = NULL;
2781 HMODULE hmod = NULL;
2782 HRESULT hr = E_FAIL;
2784 TRACE("(%s %p %08x %p)\n", debugstr_w(src), dst, dst_len, reserved);
2786 if(src[0] == '@')
2788 WCHAR *index_str;
2789 int index;
2791 dst[0] = 0;
2792 dllname = StrDupW(src + 1);
2793 index_str = strchrW(dllname, ',');
2795 if(!index_str) goto end;
2797 *index_str = 0;
2798 index_str++;
2799 index = atoiW(index_str);
2801 hmod = LoadLibraryW(dllname);
2802 if(!hmod) goto end;
2804 if(index < 0)
2806 if(LoadStringW(hmod, -index, dst, dst_len))
2807 hr = S_OK;
2809 else
2810 FIXME("can't handle non-negative indicies (%d)\n", index);
2812 else
2814 if(dst != src)
2815 lstrcpynW(dst, src, dst_len);
2816 hr = S_OK;
2819 TRACE("returing %s\n", debugstr_w(dst));
2820 end:
2821 if(hmod) FreeLibrary(hmod);
2822 HeapFree(GetProcessHeap(), 0, dllname);
2823 return hr;