Autosyncing with Wine HEAD
[reactos.git] / reactos / dll / win32 / shlwapi / string.c
1 /*
2 * Shlwapi string functions
3 *
4 * Copyright 1998 Juergen Schmied
5 * Copyright 2002 Jon Griffiths
6 *
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.
11 *
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.
16 *
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
20 */
21
22 #include "config.h"
23 #include "wine/port.h"
24
25 #include <math.h>
26 #include <stdarg.h>
27 #include <stdio.h>
28 #include <string.h>
29
30 #define NONAMELESSUNION
31 #define NONAMELESSSTRUCT
32 #include "windef.h"
33 #include "winbase.h"
34 #define NO_SHLWAPI_REG
35 #define NO_SHLWAPI_STREAM
36 #include "shlwapi.h"
37 #include "wingdi.h"
38 #include "winuser.h"
39 #include "shlobj.h"
40 #include "mlang.h"
41 #include "ddeml.h"
42 #include "wine/unicode.h"
43 #include "wine/debug.h"
44
45 #include "resource.h"
46
47 WINE_DEFAULT_DEBUG_CHANNEL(shell);
48
49 extern HINSTANCE shlwapi_hInstance;
50
51 static HRESULT _SHStrDupAA(LPCSTR,LPSTR*);
52 static HRESULT _SHStrDupAW(LPCWSTR,LPSTR*);
53
54
55 static void FillNumberFmt(NUMBERFMTW *fmt, LPWSTR decimal_buffer, int decimal_bufwlen,
56 LPWSTR thousand_buffer, int thousand_bufwlen)
57 {
58 WCHAR grouping[64];
59 WCHAR *c;
60
61 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_ILZERO|LOCALE_RETURN_NUMBER, (LPWSTR)&fmt->LeadingZero, sizeof(fmt->LeadingZero)/sizeof(WCHAR));
62 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_INEGNUMBER|LOCALE_RETURN_NUMBER, (LPWSTR)&fmt->LeadingZero, sizeof(fmt->NegativeOrder)/sizeof(WCHAR));
63 fmt->NumDigits = 0;
64 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, decimal_buffer, decimal_bufwlen);
65 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, thousand_buffer, thousand_bufwlen);
66 fmt->lpThousandSep = thousand_buffer;
67 fmt->lpDecimalSep = decimal_buffer;
68
69 /*
70 * Converting grouping string to number as described on
71 * http://blogs.msdn.com/oldnewthing/archive/2006/04/18/578251.aspx
72 */
73 fmt->Grouping = 0;
74 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SGROUPING, grouping, sizeof(grouping)/sizeof(WCHAR));
75 for (c = grouping; *c; c++)
76 if (*c >= '0' && *c < '9')
77 {
78 fmt->Grouping *= 10;
79 fmt->Grouping += *c - '0';
80 }
81
82 if (fmt->Grouping % 10 == 0)
83 fmt->Grouping /= 10;
84 else
85 fmt->Grouping *= 10;
86 }
87
88 /*************************************************************************
89 * FormatInt [internal]
90 *
91 * Format an integer according to the current locale
92 *
93 * RETURNS
94 * The number of bytes written on success or 0 on failure
95 */
96 static int FormatInt(LONGLONG qdwValue, LPWSTR pszBuf, int cchBuf)
97 {
98 NUMBERFMTW fmt;
99 WCHAR decimal[8], thousand[8];
100 WCHAR buf[24];
101 WCHAR *c;
102 BOOL neg = (qdwValue < 0);
103
104 FillNumberFmt(&fmt, decimal, sizeof decimal / sizeof (WCHAR),
105 thousand, sizeof thousand / sizeof (WCHAR));
106
107 c = &buf[24];
108 *(--c) = 0;
109 do
110 {
111 *(--c) = '0' + (qdwValue%10);
112 qdwValue /= 10;
113 } while (qdwValue > 0);
114 if (neg)
115 *(--c) = '-';
116
117 return GetNumberFormatW(LOCALE_USER_DEFAULT, 0, c, &fmt, pszBuf, cchBuf);
118 }
119
120 /*************************************************************************
121 * FormatDouble [internal]
122 *
123 * Format an integer according to the current locale. Prints the specified number of digits
124 * after the decimal point
125 *
126 * RETURNS
127 * The number of bytes written on success or 0 on failure
128 */
129 static int FormatDouble(double value, int decimals, LPWSTR pszBuf, int cchBuf)
130 {
131 static const WCHAR flfmt[] = {'%','f',0};
132 WCHAR buf[64];
133 NUMBERFMTW fmt;
134 WCHAR decimal[8], thousand[8];
135
136 snprintfW(buf, 64, flfmt, value);
137
138 FillNumberFmt(&fmt, decimal, sizeof decimal / sizeof (WCHAR),
139 thousand, sizeof thousand / sizeof (WCHAR));
140 fmt.NumDigits = decimals;
141 return GetNumberFormatW(LOCALE_USER_DEFAULT, 0, buf, &fmt, pszBuf, cchBuf);
142 }
143
144 /*************************************************************************
145 * SHLWAPI_ChrCmpHelperA
146 *
147 * Internal helper for SHLWAPI_ChrCmpA/ChrCMPIA.
148 *
149 * NOTES
150 * Both this function and its Unicode counterpart are very inefficient. To
151 * fix this, CompareString must be completely implemented and optimised
152 * first. Then the core character test can be taken out of that function and
153 * placed here, so that it need never be called at all. Until then, do not
154 * attempt to optimise this code unless you are willing to test that it
155 * still performs correctly.
156 */
157 static BOOL SHLWAPI_ChrCmpHelperA(WORD ch1, WORD ch2, DWORD dwFlags)
158 {
159 char str1[3], str2[3];
160
161 str1[0] = LOBYTE(ch1);
162 if (IsDBCSLeadByte(str1[0]))
163 {
164 str1[1] = HIBYTE(ch1);
165 str1[2] = '\0';
166 }
167 else
168 str1[1] = '\0';
169
170 str2[0] = LOBYTE(ch2);
171 if (IsDBCSLeadByte(str2[0]))
172 {
173 str2[1] = HIBYTE(ch2);
174 str2[2] = '\0';
175 }
176 else
177 str2[1] = '\0';
178
179 return CompareStringA(GetThreadLocale(), dwFlags, str1, -1, str2, -1) - 2;
180 }
181
182 /*************************************************************************
183 * SHLWAPI_ChrCmpA
184 *
185 * Internal helper function.
186 */
187 static BOOL WINAPI SHLWAPI_ChrCmpA(WORD ch1, WORD ch2)
188 {
189 return SHLWAPI_ChrCmpHelperA(ch1, ch2, 0);
190 }
191
192 /*************************************************************************
193 * ChrCmpIA (SHLWAPI.385)
194 *
195 * Compare two characters, ignoring case.
196 *
197 * PARAMS
198 * ch1 [I] First character to compare
199 * ch2 [I] Second character to compare
200 *
201 * RETURNS
202 * FALSE, if the characters are equal.
203 * Non-zero otherwise.
204 */
205 BOOL WINAPI ChrCmpIA(WORD ch1, WORD ch2)
206 {
207 TRACE("(%d,%d)\n", ch1, ch2);
208
209 return SHLWAPI_ChrCmpHelperA(ch1, ch2, NORM_IGNORECASE);
210 }
211
212 /*************************************************************************
213 * ChrCmpIW [SHLWAPI.386]
214 *
215 * See ChrCmpIA.
216 */
217 BOOL WINAPI ChrCmpIW(WCHAR ch1, WCHAR ch2)
218 {
219 return CompareStringW(GetThreadLocale(), NORM_IGNORECASE, &ch1, 1, &ch2, 1) - 2;
220 }
221
222 /*************************************************************************
223 * StrChrA [SHLWAPI.@]
224 *
225 * Find a given character in a string.
226 *
227 * PARAMS
228 * lpszStr [I] String to search in.
229 * ch [I] Character to search for.
230 *
231 * RETURNS
232 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
233 * not found.
234 * Failure: NULL, if any arguments are invalid.
235 */
236 LPSTR WINAPI StrChrA(LPCSTR lpszStr, WORD ch)
237 {
238 TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch);
239
240 if (lpszStr)
241 {
242 while (*lpszStr)
243 {
244 if (!SHLWAPI_ChrCmpA(*lpszStr, ch))
245 return (LPSTR)lpszStr;
246 lpszStr = CharNextA(lpszStr);
247 }
248 }
249 return NULL;
250 }
251
252 /*************************************************************************
253 * StrChrW [SHLWAPI.@]
254 *
255 * See StrChrA.
256 */
257 LPWSTR WINAPI StrChrW(LPCWSTR lpszStr, WCHAR ch)
258 {
259 LPWSTR lpszRet = NULL;
260
261 TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch);
262
263 if (lpszStr)
264 lpszRet = strchrW(lpszStr, ch);
265 return lpszRet;
266 }
267
268 /*************************************************************************
269 * StrChrIA [SHLWAPI.@]
270 *
271 * Find a given character in a string, ignoring case.
272 *
273 * PARAMS
274 * lpszStr [I] String to search in.
275 * ch [I] Character to search for.
276 *
277 * RETURNS
278 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
279 * not found.
280 * Failure: NULL, if any arguments are invalid.
281 */
282 LPSTR WINAPI StrChrIA(LPCSTR lpszStr, WORD ch)
283 {
284 TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch);
285
286 if (lpszStr)
287 {
288 while (*lpszStr)
289 {
290 if (!ChrCmpIA(*lpszStr, ch))
291 return (LPSTR)lpszStr;
292 lpszStr = CharNextA(lpszStr);
293 }
294 }
295 return NULL;
296 }
297
298 /*************************************************************************
299 * StrChrIW [SHLWAPI.@]
300 *
301 * See StrChrA.
302 */
303 LPWSTR WINAPI StrChrIW(LPCWSTR lpszStr, WCHAR ch)
304 {
305 TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch);
306
307 if (lpszStr)
308 {
309 ch = toupperW(ch);
310 while (*lpszStr)
311 {
312 if (toupperW(*lpszStr) == ch)
313 return (LPWSTR)lpszStr;
314 lpszStr++;
315 }
316 lpszStr = NULL;
317 }
318 return (LPWSTR)lpszStr;
319 }
320
321 /*************************************************************************
322 * StrCmpIW [SHLWAPI.@]
323 *
324 * Compare two strings, ignoring case.
325 *
326 * PARAMS
327 * lpszStr [I] First string to compare
328 * lpszComp [I] Second string to compare
329 *
330 * RETURNS
331 * An integer less than, equal to or greater than 0, indicating that
332 * lpszStr is less than, the same, or greater than lpszComp.
333 */
334 int WINAPI StrCmpIW(LPCWSTR lpszStr, LPCWSTR lpszComp)
335 {
336 int iRet;
337
338 TRACE("(%s,%s)\n", debugstr_w(lpszStr),debugstr_w(lpszComp));
339
340 iRet = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, lpszStr, -1, lpszComp, -1);
341 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
342 }
343
344 /*************************************************************************
345 * StrCmpNA [SHLWAPI.@]
346 *
347 * Compare two strings, up to a maximum length.
348 *
349 * PARAMS
350 * lpszStr [I] First string to compare
351 * lpszComp [I] Second string to compare
352 * iLen [I] Maximum number of chars to compare.
353 *
354 * RETURNS
355 * An integer less than, equal to or greater than 0, indicating that
356 * lpszStr is less than, the same, or greater than lpszComp.
357 */
358 INT WINAPI StrCmpNA(LPCSTR lpszStr, LPCSTR lpszComp, INT iLen)
359 {
360 INT iRet;
361
362 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
363
364 iRet = CompareStringA(GetThreadLocale(), 0, lpszStr, iLen, lpszComp, iLen);
365 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
366 }
367
368 /*************************************************************************
369 * StrCmpNW [SHLWAPI.@]
370 *
371 * See StrCmpNA.
372 */
373 INT WINAPI StrCmpNW(LPCWSTR lpszStr, LPCWSTR lpszComp, INT iLen)
374 {
375 INT iRet;
376
377 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen);
378
379 iRet = CompareStringW(GetThreadLocale(), 0, lpszStr, iLen, lpszComp, iLen);
380 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
381 }
382
383 /*************************************************************************
384 * StrCmpNIA [SHLWAPI.@]
385 *
386 * Compare two strings, up to a maximum length, ignoring case.
387 *
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.
392 *
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.
396 */
397 int WINAPI StrCmpNIA(LPCSTR lpszStr, LPCSTR lpszComp, int iLen)
398 {
399 INT iRet;
400
401 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
402
403 iRet = CompareStringA(GetThreadLocale(), NORM_IGNORECASE, lpszStr, iLen, lpszComp, iLen);
404 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
405 }
406
407 /*************************************************************************
408 * StrCmpNIW [SHLWAPI.@]
409 *
410 * See StrCmpNIA.
411 */
412 INT WINAPI StrCmpNIW(LPCWSTR lpszStr, LPCWSTR lpszComp, int iLen)
413 {
414 INT iRet;
415
416 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen);
417
418 iRet = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, lpszStr, iLen, lpszComp, iLen);
419 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
420 }
421
422 /*************************************************************************
423 * StrCmpW [SHLWAPI.@]
424 *
425 * Compare two strings.
426 *
427 * PARAMS
428 * lpszStr [I] First string to compare
429 * lpszComp [I] Second string to compare
430 *
431 * RETURNS
432 * An integer less than, equal to or greater than 0, indicating that
433 * lpszStr is less than, the same, or greater than lpszComp.
434 */
435 int WINAPI StrCmpW(LPCWSTR lpszStr, LPCWSTR lpszComp)
436 {
437 INT iRet;
438
439 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszComp));
440
441 iRet = CompareStringW(GetThreadLocale(), 0, lpszStr, -1, lpszComp, -1);
442 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
443 }
444
445 /*************************************************************************
446 * StrCatW [SHLWAPI.@]
447 *
448 * Concatanate two strings.
449 *
450 * PARAMS
451 * lpszStr [O] Initial string
452 * lpszSrc [I] String to concatanate
453 *
454 * RETURNS
455 * lpszStr.
456 */
457 LPWSTR WINAPI StrCatW(LPWSTR lpszStr, LPCWSTR lpszSrc)
458 {
459 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSrc));
460
461 strcatW(lpszStr, lpszSrc);
462 return lpszStr;
463 }
464
465 /*************************************************************************
466 * StrCpyW [SHLWAPI.@]
467 *
468 * Copy a string to another string.
469 *
470 * PARAMS
471 * lpszStr [O] Destination string
472 * lpszSrc [I] Source string
473 *
474 * RETURNS
475 * lpszStr.
476 */
477 LPWSTR WINAPI StrCpyW(LPWSTR lpszStr, LPCWSTR lpszSrc)
478 {
479 TRACE("(%p,%s)\n", lpszStr, debugstr_w(lpszSrc));
480
481 strcpyW(lpszStr, lpszSrc);
482 return lpszStr;
483 }
484
485 /*************************************************************************
486 * StrCpyNW [SHLWAPI.@]
487 *
488 * Copy a string to another string, up to a maximum number of characters.
489 *
490 * PARAMS
491 * lpszStr [O] Destination string
492 * lpszSrc [I] Source string
493 * iLen [I] Maximum number of chars to copy
494 *
495 * RETURNS
496 * lpszStr.
497 */
498 LPWSTR WINAPI StrCpyNW(LPWSTR lpszStr, LPCWSTR lpszSrc, int iLen)
499 {
500 TRACE("(%p,%s,%i)\n", lpszStr, debugstr_w(lpszSrc), iLen);
501
502 lstrcpynW(lpszStr, lpszSrc, iLen);
503 return lpszStr;
504 }
505
506
507
508 /*************************************************************************
509 * SHLWAPI_StrStrHelperA
510 *
511 * Internal implementation of StrStrA/StrStrIA
512 */
513 static LPSTR SHLWAPI_StrStrHelperA(LPCSTR lpszStr, LPCSTR lpszSearch,
514 int (*pStrCmpFn)(LPCSTR,LPCSTR,size_t))
515 {
516 size_t iLen;
517
518 if (!lpszStr || !lpszSearch || !*lpszSearch)
519 return NULL;
520
521 iLen = strlen(lpszSearch);
522
523 while (*lpszStr)
524 {
525 if (!pStrCmpFn(lpszStr, lpszSearch, iLen))
526 return (LPSTR)lpszStr;
527 lpszStr = CharNextA(lpszStr);
528 }
529 return NULL;
530 }
531
532 /*************************************************************************
533 * StrStrA [SHLWAPI.@]
534 *
535 * Find a substring within a string.
536 *
537 * PARAMS
538 * lpszStr [I] String to search in
539 * lpszSearch [I] String to look for
540 *
541 * RETURNS
542 * The start of lpszSearch within lpszStr, or NULL if not found.
543 */
544 LPSTR WINAPI StrStrA(LPCSTR lpszStr, LPCSTR lpszSearch)
545 {
546 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
547
548 return SHLWAPI_StrStrHelperA(lpszStr, lpszSearch, strncmp);
549 }
550
551 /*************************************************************************
552 * StrStrW [SHLWAPI.@]
553 *
554 * See StrStrA.
555 */
556 LPWSTR WINAPI StrStrW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
557 {
558 if (!lpszStr || !lpszSearch) return NULL;
559 return strstrW( lpszStr, lpszSearch );
560 }
561
562 /*************************************************************************
563 * StrRStrIA [SHLWAPI.@]
564 *
565 * Find the last occurrence of a substring within a string.
566 *
567 * PARAMS
568 * lpszStr [I] String to search in
569 * lpszEnd [I] End of lpszStr
570 * lpszSearch [I] String to look for
571 *
572 * RETURNS
573 * The last occurrence lpszSearch within lpszStr, or NULL if not found.
574 */
575 LPSTR WINAPI StrRStrIA(LPCSTR lpszStr, LPCSTR lpszEnd, LPCSTR lpszSearch)
576 {
577 WORD ch1, ch2;
578 INT iLen;
579
580 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
581
582 if (!lpszStr || !lpszSearch || !*lpszSearch)
583 return NULL;
584
585 if (!lpszEnd)
586 lpszEnd = lpszStr + lstrlenA(lpszStr);
587 if (lpszEnd == lpszStr)
588 return NULL;
589
590 if (IsDBCSLeadByte(*lpszSearch))
591 ch1 = *lpszSearch << 8 | (UCHAR)lpszSearch[1];
592 else
593 ch1 = *lpszSearch;
594 iLen = lstrlenA(lpszSearch);
595
596 do
597 {
598 lpszEnd = CharPrevA(lpszStr, lpszEnd);
599 ch2 = IsDBCSLeadByte(*lpszEnd)? *lpszEnd << 8 | (UCHAR)lpszEnd[1] : *lpszEnd;
600 if (!ChrCmpIA(ch1, ch2))
601 {
602 if (!StrCmpNIA(lpszEnd, lpszSearch, iLen))
603 return (LPSTR)lpszEnd;
604 }
605 } while (lpszEnd > lpszStr);
606 return NULL;
607 }
608
609 /*************************************************************************
610 * StrRStrIW [SHLWAPI.@]
611 *
612 * See StrRStrIA.
613 */
614 LPWSTR WINAPI StrRStrIW(LPCWSTR lpszStr, LPCWSTR lpszEnd, LPCWSTR lpszSearch)
615 {
616 INT iLen;
617
618 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
619
620 if (!lpszStr || !lpszSearch || !*lpszSearch)
621 return NULL;
622
623 if (!lpszEnd)
624 lpszEnd = lpszStr + strlenW(lpszStr);
625
626 iLen = strlenW(lpszSearch);
627
628 while (lpszEnd > lpszStr)
629 {
630 lpszEnd--;
631 if (!StrCmpNIW(lpszEnd, lpszSearch, iLen))
632 return (LPWSTR)lpszEnd;
633 }
634 return NULL;
635 }
636
637 /*************************************************************************
638 * StrStrIA [SHLWAPI.@]
639 *
640 * Find a substring within a string, ignoring case.
641 *
642 * PARAMS
643 * lpszStr [I] String to search in
644 * lpszSearch [I] String to look for
645 *
646 * RETURNS
647 * The start of lpszSearch within lpszStr, or NULL if not found.
648 */
649 LPSTR WINAPI StrStrIA(LPCSTR lpszStr, LPCSTR lpszSearch)
650 {
651 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
652
653 return SHLWAPI_StrStrHelperA(lpszStr, lpszSearch, strncasecmp);
654 }
655
656 /*************************************************************************
657 * StrStrIW [SHLWAPI.@]
658 *
659 * See StrStrIA.
660 */
661 LPWSTR WINAPI StrStrIW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
662 {
663 int iLen;
664
665 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
666
667 if (!lpszStr || !lpszSearch || !*lpszSearch)
668 return NULL;
669
670 iLen = strlenW(lpszSearch);
671
672 while (*lpszStr)
673 {
674 if (!StrCmpNIW(lpszStr, lpszSearch, iLen))
675 return (LPWSTR)lpszStr;
676 lpszStr++;
677 }
678 return NULL;
679 }
680
681 /*************************************************************************
682 * StrToIntA [SHLWAPI.@]
683 *
684 * Read a signed integer from a string.
685 *
686 * PARAMS
687 * lpszStr [I] String to read integer from
688 *
689 * RETURNS
690 * The signed integer value represented by the string, or 0 if no integer is
691 * present.
692 *
693 * NOTES
694 * No leading space is allowed before the number, although a leading '-' is.
695 */
696 int WINAPI StrToIntA(LPCSTR lpszStr)
697 {
698 int iRet = 0;
699
700 TRACE("(%s)\n", debugstr_a(lpszStr));
701
702 if (!lpszStr)
703 {
704 WARN("Invalid lpszStr would crash under Win32!\n");
705 return 0;
706 }
707
708 if (*lpszStr == '-' || isdigit(*lpszStr))
709 StrToIntExA(lpszStr, 0, &iRet);
710 return iRet;
711 }
712
713 /*************************************************************************
714 * StrToIntW [SHLWAPI.@]
715 *
716 * See StrToIntA.
717 */
718 int WINAPI StrToIntW(LPCWSTR lpszStr)
719 {
720 int iRet = 0;
721
722 TRACE("(%s)\n", debugstr_w(lpszStr));
723
724 if (!lpszStr)
725 {
726 WARN("Invalid lpszStr would crash under Win32!\n");
727 return 0;
728 }
729
730 if (*lpszStr == '-' || isdigitW(*lpszStr))
731 StrToIntExW(lpszStr, 0, &iRet);
732 return iRet;
733 }
734
735 /*************************************************************************
736 * StrToIntExA [SHLWAPI.@]
737 *
738 * Read an integer from a string.
739 *
740 * PARAMS
741 * lpszStr [I] String to read integer from
742 * dwFlags [I] Flags controlling the conversion
743 * lpiRet [O] Destination for read integer.
744 *
745 * RETURNS
746 * Success: TRUE. lpiRet contains the integer value represented by the string.
747 * Failure: FALSE, if the string is invalid, or no number is present.
748 *
749 * NOTES
750 * Leading whitespace, '-' and '+' are allowed before the number. If
751 * dwFlags includes STIF_SUPPORT_HEX, hexadecimal numbers are allowed, if
752 * preceded by '0x'. If this flag is not set, or there is no '0x' prefix,
753 * the string is treated as a decimal string. A leading '-' is ignored for
754 * hexadecimal numbers.
755 */
756 BOOL WINAPI StrToIntExA(LPCSTR lpszStr, DWORD dwFlags, LPINT lpiRet)
757 {
758 BOOL bNegative = FALSE;
759 int iRet = 0;
760
761 TRACE("(%s,%08X,%p)\n", debugstr_a(lpszStr), dwFlags, lpiRet);
762
763 if (!lpszStr || !lpiRet)
764 {
765 WARN("Invalid parameter would crash under Win32!\n");
766 return FALSE;
767 }
768 if (dwFlags > STIF_SUPPORT_HEX)
769 {
770 WARN("Unknown flags (%08lX)!\n", dwFlags & ~STIF_SUPPORT_HEX);
771 }
772
773 /* Skip leading space, '+', '-' */
774 while (isspace(*lpszStr))
775 lpszStr = CharNextA(lpszStr);
776
777 if (*lpszStr == '-')
778 {
779 bNegative = TRUE;
780 lpszStr++;
781 }
782 else if (*lpszStr == '+')
783 lpszStr++;
784
785 if (dwFlags & STIF_SUPPORT_HEX &&
786 *lpszStr == '0' && tolower(lpszStr[1]) == 'x')
787 {
788 /* Read hex number */
789 lpszStr += 2;
790
791 if (!isxdigit(*lpszStr))
792 return FALSE;
793
794 while (isxdigit(*lpszStr))
795 {
796 iRet = iRet * 16;
797 if (isdigit(*lpszStr))
798 iRet += (*lpszStr - '0');
799 else
800 iRet += 10 + (tolower(*lpszStr) - 'a');
801 lpszStr++;
802 }
803 *lpiRet = iRet;
804 return TRUE;
805 }
806
807 /* Read decimal number */
808 if (!isdigit(*lpszStr))
809 return FALSE;
810
811 while (isdigit(*lpszStr))
812 {
813 iRet = iRet * 10;
814 iRet += (*lpszStr - '0');
815 lpszStr++;
816 }
817 *lpiRet = bNegative ? -iRet : iRet;
818 return TRUE;
819 }
820
821 /*************************************************************************
822 * StrToIntExW [SHLWAPI.@]
823 *
824 * See StrToIntExA.
825 */
826 BOOL WINAPI StrToIntExW(LPCWSTR lpszStr, DWORD dwFlags, LPINT lpiRet)
827 {
828 BOOL bNegative = FALSE;
829 int iRet = 0;
830
831 TRACE("(%s,%08X,%p)\n", debugstr_w(lpszStr), dwFlags, lpiRet);
832
833 if (!lpszStr || !lpiRet)
834 {
835 WARN("Invalid parameter would crash under Win32!\n");
836 return FALSE;
837 }
838 if (dwFlags > STIF_SUPPORT_HEX)
839 {
840 WARN("Unknown flags (%08lX)!\n", dwFlags & ~STIF_SUPPORT_HEX);
841 }
842
843 /* Skip leading space, '+', '-' */
844 while (isspaceW(*lpszStr)) lpszStr++;
845
846 if (*lpszStr == '-')
847 {
848 bNegative = TRUE;
849 lpszStr++;
850 }
851 else if (*lpszStr == '+')
852 lpszStr++;
853
854 if (dwFlags & STIF_SUPPORT_HEX &&
855 *lpszStr == '0' && tolowerW(lpszStr[1]) == 'x')
856 {
857 /* Read hex number */
858 lpszStr += 2;
859
860 if (!isxdigitW(*lpszStr))
861 return FALSE;
862
863 while (isxdigitW(*lpszStr))
864 {
865 iRet = iRet * 16;
866 if (isdigitW(*lpszStr))
867 iRet += (*lpszStr - '0');
868 else
869 iRet += 10 + (tolowerW(*lpszStr) - 'a');
870 lpszStr++;
871 }
872 *lpiRet = iRet;
873 return TRUE;
874 }
875
876 /* Read decimal number */
877 if (!isdigitW(*lpszStr))
878 return FALSE;
879
880 while (isdigitW(*lpszStr))
881 {
882 iRet = iRet * 10;
883 iRet += (*lpszStr - '0');
884 lpszStr++;
885 }
886 *lpiRet = bNegative ? -iRet : iRet;
887 return TRUE;
888 }
889
890 /*************************************************************************
891 * StrDupA [SHLWAPI.@]
892 *
893 * Duplicate a string.
894 *
895 * PARAMS
896 * lpszStr [I] String to duplicate.
897 *
898 * RETURNS
899 * Success: A pointer to a new string containing the contents of lpszStr
900 * Failure: NULL, if memory cannot be allocated
901 *
902 * NOTES
903 * The string memory is allocated with LocalAlloc(), and so should be released
904 * by calling LocalFree().
905 */
906 LPSTR WINAPI StrDupA(LPCSTR lpszStr)
907 {
908 int iLen;
909 LPSTR lpszRet;
910
911 TRACE("(%s)\n",debugstr_a(lpszStr));
912
913 iLen = lpszStr ? strlen(lpszStr) + 1 : 1;
914 lpszRet = (LPSTR)LocalAlloc(LMEM_FIXED, iLen);
915
916 if (lpszRet)
917 {
918 if (lpszStr)
919 memcpy(lpszRet, lpszStr, iLen);
920 else
921 *lpszRet = '\0';
922 }
923 return lpszRet;
924 }
925
926 /*************************************************************************
927 * StrDupW [SHLWAPI.@]
928 *
929 * See StrDupA.
930 */
931 LPWSTR WINAPI StrDupW(LPCWSTR lpszStr)
932 {
933 int iLen;
934 LPWSTR lpszRet;
935
936 TRACE("(%s)\n",debugstr_w(lpszStr));
937
938 iLen = (lpszStr ? strlenW(lpszStr) + 1 : 1) * sizeof(WCHAR);
939 lpszRet = (LPWSTR)LocalAlloc(LMEM_FIXED, iLen);
940
941 if (lpszRet)
942 {
943 if (lpszStr)
944 memcpy(lpszRet, lpszStr, iLen);
945 else
946 *lpszRet = '\0';
947 }
948 return lpszRet;
949 }
950
951 /*************************************************************************
952 * SHLWAPI_StrSpnHelperA
953 *
954 * Internal implementation of StrSpnA/StrCSpnA/StrCSpnIA
955 */
956 static int SHLWAPI_StrSpnHelperA(LPCSTR lpszStr, LPCSTR lpszMatch,
957 LPSTR (WINAPI *pStrChrFn)(LPCSTR,WORD),
958 BOOL bInvert)
959 {
960 LPCSTR lpszRead = lpszStr;
961 if (lpszStr && *lpszStr && lpszMatch)
962 {
963 while (*lpszRead)
964 {
965 LPCSTR lpszTest = pStrChrFn(lpszMatch, *lpszRead);
966
967 if (!bInvert && !lpszTest)
968 break;
969 if (bInvert && lpszTest)
970 break;
971 lpszRead = CharNextA(lpszRead);
972 };
973 }
974 return lpszRead - lpszStr;
975 }
976
977 /*************************************************************************
978 * StrSpnA [SHLWAPI.@]
979 *
980 * Find the length of the start of a string that contains only certain
981 * characters.
982 *
983 * PARAMS
984 * lpszStr [I] String to search
985 * lpszMatch [I] Characters that can be in the substring
986 *
987 * RETURNS
988 * The length of the part of lpszStr containing only chars from lpszMatch,
989 * or 0 if any parameter is invalid.
990 */
991 int WINAPI StrSpnA(LPCSTR lpszStr, LPCSTR lpszMatch)
992 {
993 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
994
995 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, FALSE);
996 }
997
998 /*************************************************************************
999 * StrSpnW [SHLWAPI.@]
1000 *
1001 * See StrSpnA.
1002 */
1003 int WINAPI StrSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1004 {
1005 if (!lpszStr || !lpszMatch) return 0;
1006 return strspnW( lpszStr, lpszMatch );
1007 }
1008
1009 /*************************************************************************
1010 * StrCSpnA [SHLWAPI.@]
1011 *
1012 * Find the length of the start of a string that does not contain certain
1013 * characters.
1014 *
1015 * PARAMS
1016 * lpszStr [I] String to search
1017 * lpszMatch [I] Characters that cannot be in the substring
1018 *
1019 * RETURNS
1020 * The length of the part of lpszStr containing only chars not in lpszMatch,
1021 * or 0 if any parameter is invalid.
1022 */
1023 int WINAPI StrCSpnA(LPCSTR lpszStr, LPCSTR lpszMatch)
1024 {
1025 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1026
1027 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, TRUE);
1028 }
1029
1030 /*************************************************************************
1031 * StrCSpnW [SHLWAPI.@]
1032 *
1033 * See StrCSpnA.
1034 */
1035 int WINAPI StrCSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1036 {
1037 if (!lpszStr || !lpszMatch) return 0;
1038 return strcspnW( lpszStr, lpszMatch );
1039 }
1040
1041 /*************************************************************************
1042 * StrCSpnIA [SHLWAPI.@]
1043 *
1044 * Find the length of the start of a string that does not contain certain
1045 * characters, ignoring case.
1046 *
1047 * PARAMS
1048 * lpszStr [I] String to search
1049 * lpszMatch [I] Characters that cannot be in the substring
1050 *
1051 * RETURNS
1052 * The length of the part of lpszStr containing only chars not in lpszMatch,
1053 * or 0 if any parameter is invalid.
1054 */
1055 int WINAPI StrCSpnIA(LPCSTR lpszStr, LPCSTR lpszMatch)
1056 {
1057 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1058
1059 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrIA, TRUE);
1060 }
1061
1062 /*************************************************************************
1063 * StrCSpnIW [SHLWAPI.@]
1064 *
1065 * See StrCSpnIA.
1066 */
1067 int WINAPI StrCSpnIW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1068 {
1069 LPCWSTR lpszRead = lpszStr;
1070
1071 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
1072
1073 if (lpszStr && *lpszStr && lpszMatch)
1074 {
1075 while (*lpszRead)
1076 {
1077 if (StrChrIW(lpszMatch, *lpszRead)) break;
1078 lpszRead++;
1079 }
1080 }
1081 return lpszRead - lpszStr;
1082 }
1083
1084 /*************************************************************************
1085 * StrPBrkA [SHLWAPI.@]
1086 *
1087 * Search a string for any of a group of characters.
1088 *
1089 * PARAMS
1090 * lpszStr [I] String to search
1091 * lpszMatch [I] Characters to match
1092 *
1093 * RETURNS
1094 * A pointer to the first matching character in lpszStr, or NULL if no
1095 * match was found.
1096 */
1097 LPSTR WINAPI StrPBrkA(LPCSTR lpszStr, LPCSTR lpszMatch)
1098 {
1099 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
1100
1101 if (lpszStr && lpszMatch && *lpszMatch)
1102 {
1103 while (*lpszStr)
1104 {
1105 if (StrChrA(lpszMatch, *lpszStr))
1106 return (LPSTR)lpszStr;
1107 lpszStr = CharNextA(lpszStr);
1108 }
1109 }
1110 return NULL;
1111 }
1112
1113 /*************************************************************************
1114 * StrPBrkW [SHLWAPI.@]
1115 *
1116 * See StrPBrkA.
1117 */
1118 LPWSTR WINAPI StrPBrkW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
1119 {
1120 if (!lpszStr || !lpszMatch) return NULL;
1121 return strpbrkW( lpszStr, lpszMatch );
1122 }
1123
1124 /*************************************************************************
1125 * SHLWAPI_StrRChrHelperA
1126 *
1127 * Internal implementation of StrRChrA/StrRChrIA.
1128 */
1129 static LPSTR SHLWAPI_StrRChrHelperA(LPCSTR lpszStr,
1130 LPCSTR lpszEnd, WORD ch,
1131 BOOL (WINAPI *pChrCmpFn)(WORD,WORD))
1132 {
1133 LPCSTR lpszRet = NULL;
1134
1135 if (lpszStr)
1136 {
1137 WORD ch2;
1138
1139 if (!lpszEnd)
1140 lpszEnd = lpszStr + lstrlenA(lpszStr);
1141
1142 while (*lpszStr && lpszStr <= lpszEnd)
1143 {
1144 ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr;
1145
1146 if (!pChrCmpFn(ch, ch2))
1147 lpszRet = lpszStr;
1148 lpszStr = CharNextA(lpszStr);
1149 }
1150 }
1151 return (LPSTR)lpszRet;
1152 }
1153
1154 /**************************************************************************
1155 * StrRChrA [SHLWAPI.@]
1156 *
1157 * Find the last occurrence of a character in string.
1158 *
1159 * PARAMS
1160 * lpszStr [I] String to search in
1161 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1162 * ch [I] Character to search for.
1163 *
1164 * RETURNS
1165 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1166 * or NULL if not found.
1167 * Failure: NULL, if any arguments are invalid.
1168 */
1169 LPSTR WINAPI StrRChrA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch)
1170 {
1171 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch);
1172
1173 return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, SHLWAPI_ChrCmpA);
1174 }
1175
1176 /**************************************************************************
1177 * StrRChrW [SHLWAPI.@]
1178 *
1179 * See StrRChrA.
1180 */
1181 LPWSTR WINAPI StrRChrW(LPCWSTR str, LPCWSTR end, WORD ch)
1182 {
1183 WCHAR *ret = NULL;
1184
1185 if (!str) return NULL;
1186 if (!end) end = str + strlenW(str);
1187 while (str < end)
1188 {
1189 if (*str == ch) ret = (WCHAR *)str;
1190 str++;
1191 }
1192 return ret;
1193 }
1194
1195 /**************************************************************************
1196 * StrRChrIA [SHLWAPI.@]
1197 *
1198 * Find the last occurrence of a character in string, ignoring case.
1199 *
1200 * PARAMS
1201 * lpszStr [I] String to search in
1202 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
1203 * ch [I] Character to search for.
1204 *
1205 * RETURNS
1206 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
1207 * or NULL if not found.
1208 * Failure: NULL, if any arguments are invalid.
1209 */
1210 LPSTR WINAPI StrRChrIA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch)
1211 {
1212 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch);
1213
1214 return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, ChrCmpIA);
1215 }
1216
1217 /**************************************************************************
1218 * StrRChrIW [SHLWAPI.@]
1219 *
1220 * See StrRChrIA.
1221 */
1222 LPWSTR WINAPI StrRChrIW(LPCWSTR str, LPCWSTR end, WORD ch)
1223 {
1224 WCHAR *ret = NULL;
1225
1226 if (!str) return NULL;
1227 if (!end) end = str + strlenW(str);
1228 while (str < end)
1229 {
1230 if (!ChrCmpIW(*str, ch)) ret = (WCHAR *)str;
1231 str++;
1232 }
1233 return ret;
1234 }
1235
1236 /*************************************************************************
1237 * StrCatBuffA [SHLWAPI.@]
1238 *
1239 * Concatenate two strings together.
1240 *
1241 * PARAMS
1242 * lpszStr [O] String to concatenate to
1243 * lpszCat [I] String to add to lpszCat
1244 * cchMax [I] Maximum number of characters for the whole string
1245 *
1246 * RETURNS
1247 * lpszStr.
1248 *
1249 * NOTES
1250 * cchMax determines the number of characters in the final length of the
1251 * string, not the number appended to lpszStr from lpszCat.
1252 */
1253 LPSTR WINAPI StrCatBuffA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax)
1254 {
1255 INT iLen;
1256
1257 TRACE("(%p,%s,%d)\n", lpszStr, debugstr_a(lpszCat), cchMax);
1258
1259 if (!lpszStr)
1260 {
1261 WARN("Invalid lpszStr would crash under Win32!\n");
1262 return NULL;
1263 }
1264
1265 iLen = strlen(lpszStr);
1266 cchMax -= iLen;
1267
1268 if (cchMax > 0)
1269 StrCpyNA(lpszStr + iLen, lpszCat, cchMax);
1270 return lpszStr;
1271 }
1272
1273 /*************************************************************************
1274 * StrCatBuffW [SHLWAPI.@]
1275 *
1276 * See StrCatBuffA.
1277 */
1278 LPWSTR WINAPI StrCatBuffW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax)
1279 {
1280 INT iLen;
1281
1282 TRACE("(%p,%s,%d)\n", lpszStr, debugstr_w(lpszCat), cchMax);
1283
1284 if (!lpszStr)
1285 {
1286 WARN("Invalid lpszStr would crash under Win32!\n");
1287 return NULL;
1288 }
1289
1290 iLen = strlenW(lpszStr);
1291 cchMax -= iLen;
1292
1293 if (cchMax > 0)
1294 StrCpyNW(lpszStr + iLen, lpszCat, cchMax);
1295 return lpszStr;
1296 }
1297
1298 /*************************************************************************
1299 * StrRetToBufA [SHLWAPI.@]
1300 *
1301 * Convert a STRRET to a normal string.
1302 *
1303 * PARAMS
1304 * lpStrRet [O] STRRET to convert
1305 * pIdl [I] ITEMIDLIST for lpStrRet->uType == STRRET_OFFSET
1306 * lpszDest [O] Destination for normal string
1307 * dwLen [I] Length of lpszDest
1308 *
1309 * RETURNS
1310 * Success: S_OK. lpszDest contains up to dwLen characters of the string.
1311 * If lpStrRet is of type STRRET_WSTR, its memory is freed with
1312 * CoTaskMemFree() and its type set to STRRET_CSTRA.
1313 * Failure: E_FAIL, if any parameters are invalid.
1314 */
1315 HRESULT WINAPI StrRetToBufA (LPSTRRET src, const ITEMIDLIST *pidl, LPSTR dest, UINT len)
1316 {
1317 /* NOTE:
1318 * This routine is identical to that in dlls/shell32/shellstring.c.
1319 * It was duplicated because not every version of Shlwapi.dll exports
1320 * StrRetToBufA. If you change one routine, change them both.
1321 */
1322 TRACE("dest=%p len=0x%x strret=%p pidl=%p stub\n",dest,len,src,pidl);
1323
1324 if (!src)
1325 {
1326 WARN("Invalid lpStrRet would crash under Win32!\n");
1327 if (dest)
1328 *dest = '\0';
1329 return E_FAIL;
1330 }
1331
1332 if (!dest || !len)
1333 return E_FAIL;
1334
1335 *dest = '\0';
1336
1337 switch (src->uType)
1338 {
1339 case STRRET_WSTR:
1340 WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, dest, len, NULL, NULL);
1341 CoTaskMemFree(src->u.pOleStr);
1342 break;
1343
1344 case STRRET_CSTR:
1345 lstrcpynA((LPSTR)dest, src->u.cStr, len);
1346 break;
1347
1348 case STRRET_OFFSET:
1349 lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len);
1350 break;
1351
1352 default:
1353 FIXME("unknown type!\n");
1354 return FALSE;
1355 }
1356 return S_OK;
1357 }
1358
1359 /*************************************************************************
1360 * StrRetToBufW [SHLWAPI.@]
1361 *
1362 * See StrRetToBufA.
1363 */
1364 HRESULT WINAPI StrRetToBufW (LPSTRRET src, const ITEMIDLIST *pidl, LPWSTR dest, UINT len)
1365 {
1366 TRACE("dest=%p len=0x%x strret=%p pidl=%p stub\n",dest,len,src,pidl);
1367
1368 if (!src)
1369 {
1370 WARN("Invalid lpStrRet would crash under Win32!\n");
1371 if (dest)
1372 *dest = '\0';
1373 return E_FAIL;
1374 }
1375
1376 if (!dest || !len)
1377 return E_FAIL;
1378
1379 *dest = '\0';
1380
1381 switch (src->uType)
1382 {
1383 case STRRET_WSTR:
1384 lstrcpynW((LPWSTR)dest, src->u.pOleStr, len);
1385 CoTaskMemFree(src->u.pOleStr);
1386 break;
1387
1388 case STRRET_CSTR:
1389 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len)
1390 dest[len-1] = 0;
1391 break;
1392
1393 case STRRET_OFFSET:
1394 if (pidl)
1395 {
1396 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1,
1397 dest, len ) && len)
1398 dest[len-1] = 0;
1399 }
1400 break;
1401
1402 default:
1403 FIXME("unknown type!\n");
1404 return FALSE;
1405 }
1406 return S_OK;
1407 }
1408
1409 /*************************************************************************
1410 * StrRetToStrA [SHLWAPI.@]
1411 *
1412 * Converts a STRRET to a normal string.
1413 *
1414 * PARAMS
1415 * lpStrRet [O] STRRET to convert
1416 * pidl [I] ITEMIDLIST for lpStrRet->uType == STRRET_OFFSET
1417 * ppszName [O] Destination for converted string
1418 *
1419 * RETURNS
1420 * Success: S_OK. ppszName contains the new string, allocated with CoTaskMemAlloc().
1421 * Failure: E_FAIL, if any parameters are invalid.
1422 */
1423 HRESULT WINAPI StrRetToStrA(LPSTRRET lpStrRet, const ITEMIDLIST *pidl, LPSTR *ppszName)
1424 {
1425 HRESULT hRet = E_FAIL;
1426
1427 switch (lpStrRet->uType)
1428 {
1429 case STRRET_WSTR:
1430 hRet = _SHStrDupAW(lpStrRet->u.pOleStr, ppszName);
1431 CoTaskMemFree(lpStrRet->u.pOleStr);
1432 break;
1433
1434 case STRRET_CSTR:
1435 hRet = _SHStrDupAA(lpStrRet->u.cStr, ppszName);
1436 break;
1437
1438 case STRRET_OFFSET:
1439 hRet = _SHStrDupAA(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, ppszName);
1440 break;
1441
1442 default:
1443 *ppszName = NULL;
1444 }
1445
1446 return hRet;
1447 }
1448
1449 /*************************************************************************
1450 * StrRetToStrW [SHLWAPI.@]
1451 *
1452 * See StrRetToStrA.
1453 */
1454 HRESULT WINAPI StrRetToStrW(LPSTRRET lpStrRet, const ITEMIDLIST *pidl, LPWSTR *ppszName)
1455 {
1456 HRESULT hRet = E_FAIL;
1457
1458 switch (lpStrRet->uType)
1459 {
1460 case STRRET_WSTR:
1461 hRet = SHStrDupW(lpStrRet->u.pOleStr, ppszName);
1462 CoTaskMemFree(lpStrRet->u.pOleStr);
1463 break;
1464
1465 case STRRET_CSTR:
1466 hRet = SHStrDupA(lpStrRet->u.cStr, ppszName);
1467 break;
1468
1469 case STRRET_OFFSET:
1470 hRet = SHStrDupA(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, ppszName);
1471 break;
1472
1473 default:
1474 *ppszName = NULL;
1475 }
1476
1477 return hRet;
1478 }
1479
1480 /* Create an ASCII string copy using SysAllocString() */
1481 static HRESULT _SHStrDupAToBSTR(LPCSTR src, BSTR *pBstrOut)
1482 {
1483 *pBstrOut = NULL;
1484
1485 if (src)
1486 {
1487 INT len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0);
1488 WCHAR* szTemp = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1489
1490 if (szTemp)
1491 {
1492 MultiByteToWideChar(CP_ACP, 0, src, -1, szTemp, len);
1493 *pBstrOut = SysAllocString(szTemp);
1494 HeapFree(GetProcessHeap(), 0, szTemp);
1495
1496 if (*pBstrOut)
1497 return S_OK;
1498 }
1499 }
1500 return E_OUTOFMEMORY;
1501 }
1502
1503 /*************************************************************************
1504 * StrRetToBSTR [SHLWAPI.@]
1505 *
1506 * Converts a STRRET to a BSTR.
1507 *
1508 * PARAMS
1509 * lpStrRet [O] STRRET to convert
1510 * pidl [I] ITEMIDLIST for lpStrRet->uType = STRRET_OFFSET
1511 * pBstrOut [O] Destination for converted BSTR
1512 *
1513 * RETURNS
1514 * Success: S_OK. pBstrOut contains the new string.
1515 * Failure: E_FAIL, if any parameters are invalid.
1516 */
1517 HRESULT WINAPI StrRetToBSTR(STRRET *lpStrRet, LPCITEMIDLIST pidl, BSTR* pBstrOut)
1518 {
1519 HRESULT hRet = E_FAIL;
1520
1521 switch (lpStrRet->uType)
1522 {
1523 case STRRET_WSTR:
1524 *pBstrOut = SysAllocString(lpStrRet->u.pOleStr);
1525 if (*pBstrOut)
1526 hRet = S_OK;
1527 CoTaskMemFree(lpStrRet->u.pOleStr);
1528 break;
1529
1530 case STRRET_CSTR:
1531 hRet = _SHStrDupAToBSTR(lpStrRet->u.cStr, pBstrOut);
1532 break;
1533
1534 case STRRET_OFFSET:
1535 hRet = _SHStrDupAToBSTR(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, pBstrOut);
1536 break;
1537
1538 default:
1539 *pBstrOut = NULL;
1540 }
1541
1542 return hRet;
1543 }
1544
1545 /*************************************************************************
1546 * StrFormatKBSizeA [SHLWAPI.@]
1547 *
1548 * Create a formatted string containing a byte count in Kilobytes.
1549 *
1550 * PARAMS
1551 * llBytes [I] Byte size to format
1552 * lpszDest [I] Destination for formatted string
1553 * cchMax [I] Size of lpszDest
1554 *
1555 * RETURNS
1556 * lpszDest.
1557 */
1558 LPSTR WINAPI StrFormatKBSizeA(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax)
1559 {
1560 WCHAR wszBuf[256];
1561
1562 if (!StrFormatKBSizeW(llBytes, wszBuf, 256))
1563 return NULL;
1564 if (!WideCharToMultiByte(CP_ACP, 0, wszBuf, -1, lpszDest, cchMax, NULL, NULL))
1565 return NULL;
1566 return lpszDest;
1567 }
1568
1569 /*************************************************************************
1570 * StrFormatKBSizeW [SHLWAPI.@]
1571 *
1572 * See StrFormatKBSizeA.
1573 */
1574 LPWSTR WINAPI StrFormatKBSizeW(LONGLONG llBytes, LPWSTR lpszDest, UINT cchMax)
1575 {
1576 static const WCHAR kb[] = {' ','K','B',0};
1577 LONGLONG llKB = (llBytes + 1023) >> 10;
1578 int len;
1579
1580 TRACE("(0x%s,%p,%d)\n", wine_dbgstr_longlong(llBytes), lpszDest, cchMax);
1581
1582 if (!FormatInt(llKB, lpszDest, cchMax))
1583 return NULL;
1584
1585 len = lstrlenW(lpszDest);
1586 if (cchMax - len < 4)
1587 return NULL;
1588 lstrcatW(lpszDest, kb);
1589 return lpszDest;
1590 }
1591
1592 /*************************************************************************
1593 * StrNCatA [SHLWAPI.@]
1594 *
1595 * Concatenate two strings together.
1596 *
1597 * PARAMS
1598 * lpszStr [O] String to concatenate to
1599 * lpszCat [I] String to add to lpszCat
1600 * cchMax [I] Maximum number of characters to concatenate
1601 *
1602 * RETURNS
1603 * lpszStr.
1604 *
1605 * NOTES
1606 * cchMax determines the number of characters that are appended to lpszStr,
1607 * not the total length of the string.
1608 */
1609 LPSTR WINAPI StrNCatA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax)
1610 {
1611 LPSTR lpszRet = lpszStr;
1612
1613 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszCat), cchMax);
1614
1615 if (!lpszStr)
1616 {
1617 WARN("Invalid lpszStr would crash under Win32!\n");
1618 return NULL;
1619 }
1620
1621 StrCpyNA(lpszStr + strlen(lpszStr), lpszCat, cchMax);
1622 return lpszRet;
1623 }
1624
1625 /*************************************************************************
1626 * StrNCatW [SHLWAPI.@]
1627 *
1628 * See StrNCatA.
1629 */
1630 LPWSTR WINAPI StrNCatW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax)
1631 {
1632 LPWSTR lpszRet = lpszStr;
1633
1634 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszCat), cchMax);
1635
1636 if (!lpszStr)
1637 {
1638 WARN("Invalid lpszStr would crash under Win32\n");
1639 return NULL;
1640 }
1641
1642 StrCpyNW(lpszStr + strlenW(lpszStr), lpszCat, cchMax);
1643 return lpszRet;
1644 }
1645
1646 /*************************************************************************
1647 * StrTrimA [SHLWAPI.@]
1648 *
1649 * Remove characters from the start and end of a string.
1650 *
1651 * PARAMS
1652 * lpszStr [O] String to remove characters from
1653 * lpszTrim [I] Characters to remove from lpszStr
1654 *
1655 * RETURNS
1656 * TRUE If lpszStr was valid and modified
1657 * FALSE Otherwise
1658 */
1659 BOOL WINAPI StrTrimA(LPSTR lpszStr, LPCSTR lpszTrim)
1660 {
1661 DWORD dwLen;
1662 LPSTR lpszRead = lpszStr;
1663 BOOL bRet = FALSE;
1664
1665 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszTrim));
1666
1667 if (lpszRead && *lpszRead)
1668 {
1669 while (*lpszRead && StrChrA(lpszTrim, *lpszRead))
1670 lpszRead = CharNextA(lpszRead); /* Skip leading matches */
1671
1672 dwLen = strlen(lpszRead);
1673
1674 if (lpszRead != lpszStr)
1675 {
1676 memmove(lpszStr, lpszRead, dwLen + 1);
1677 bRet = TRUE;
1678 }
1679 if (dwLen > 0)
1680 {
1681 lpszRead = lpszStr + dwLen;
1682 while (StrChrA(lpszTrim, lpszRead[-1]))
1683 lpszRead = CharPrevA(lpszStr, lpszRead); /* Skip trailing matches */
1684
1685 if (lpszRead != lpszStr + dwLen)
1686 {
1687 *lpszRead = '\0';
1688 bRet = TRUE;
1689 }
1690 }
1691 }
1692 return bRet;
1693 }
1694
1695 /*************************************************************************
1696 * StrTrimW [SHLWAPI.@]
1697 *
1698 * See StrTrimA.
1699 */
1700 BOOL WINAPI StrTrimW(LPWSTR lpszStr, LPCWSTR lpszTrim)
1701 {
1702 DWORD dwLen;
1703 LPWSTR lpszRead = lpszStr;
1704 BOOL bRet = FALSE;
1705
1706 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszTrim));
1707
1708 if (lpszRead && *lpszRead)
1709 {
1710 while (*lpszRead && StrChrW(lpszTrim, *lpszRead)) lpszRead++;
1711
1712 dwLen = strlenW(lpszRead);
1713
1714 if (lpszRead != lpszStr)
1715 {
1716 memmove(lpszStr, lpszRead, (dwLen + 1) * sizeof(WCHAR));
1717 bRet = TRUE;
1718 }
1719 if (dwLen > 0)
1720 {
1721 lpszRead = lpszStr + dwLen;
1722 while (StrChrW(lpszTrim, lpszRead[-1]))
1723 lpszRead--; /* Skip trailing matches */
1724
1725 if (lpszRead != lpszStr + dwLen)
1726 {
1727 *lpszRead = '\0';
1728 bRet = TRUE;
1729 }
1730 }
1731 }
1732 return bRet;
1733 }
1734
1735 /*************************************************************************
1736 * _SHStrDupAA [INTERNAL]
1737 *
1738 * Duplicates a ASCII string to ASCII. The destination buffer is allocated.
1739 */
1740 static HRESULT _SHStrDupAA(LPCSTR src, LPSTR * dest)
1741 {
1742 HRESULT hr;
1743 int len = 0;
1744
1745 if (src) {
1746 len = lstrlenA(src) + 1;
1747 *dest = CoTaskMemAlloc(len);
1748 } else {
1749 *dest = NULL;
1750 }
1751
1752 if (*dest) {
1753 lstrcpynA(*dest,src, len);
1754 hr = S_OK;
1755 } else {
1756 hr = E_OUTOFMEMORY;
1757 }
1758
1759 TRACE("%s->(%p)\n", debugstr_a(src), *dest);
1760 return hr;
1761 }
1762
1763 /*************************************************************************
1764 * SHStrDupA [SHLWAPI.@]
1765 *
1766 * Return a Unicode copy of a string, in memory allocated by CoTaskMemAlloc().
1767 *
1768 * PARAMS
1769 * lpszStr [I] String to copy
1770 * lppszDest [O] Destination for the new string copy
1771 *
1772 * RETURNS
1773 * Success: S_OK. lppszDest contains the new string in Unicode format.
1774 * Failure: E_OUTOFMEMORY, If any arguments are invalid or memory allocation
1775 * fails.
1776 */
1777 HRESULT WINAPI SHStrDupA(LPCSTR lpszStr, LPWSTR * lppszDest)
1778 {
1779 HRESULT hRet;
1780 int len = 0;
1781
1782 if (lpszStr)
1783 {
1784 len = MultiByteToWideChar(0, 0, lpszStr, -1, 0, 0) * sizeof(WCHAR);
1785 *lppszDest = CoTaskMemAlloc(len);
1786 }
1787 else
1788 *lppszDest = NULL;
1789
1790 if (*lppszDest)
1791 {
1792 MultiByteToWideChar(0, 0, lpszStr, -1, *lppszDest, len/sizeof(WCHAR));
1793 hRet = S_OK;
1794 }
1795 else
1796 hRet = E_OUTOFMEMORY;
1797
1798 TRACE("%s->(%p)\n", debugstr_a(lpszStr), *lppszDest);
1799 return hRet;
1800 }
1801
1802 /*************************************************************************
1803 * _SHStrDupAW [INTERNAL]
1804 *
1805 * Duplicates a UNICODE to a ASCII string. The destination buffer is allocated.
1806 */
1807 static HRESULT _SHStrDupAW(LPCWSTR src, LPSTR * dest)
1808 {
1809 HRESULT hr;
1810 int len = 0;
1811
1812 if (src) {
1813 len = WideCharToMultiByte(CP_ACP, 0, src, -1, NULL, 0, NULL, NULL);
1814 *dest = CoTaskMemAlloc(len);
1815 } else {
1816 *dest = NULL;
1817 }
1818
1819 if (*dest) {
1820 WideCharToMultiByte(CP_ACP, 0, src, -1, *dest, len, NULL, NULL);
1821 hr = S_OK;
1822 } else {
1823 hr = E_OUTOFMEMORY;
1824 }
1825
1826 TRACE("%s->(%p)\n", debugstr_w(src), *dest);
1827 return hr;
1828 }
1829
1830 /*************************************************************************
1831 * SHStrDupW [SHLWAPI.@]
1832 *
1833 * See SHStrDupA.
1834 */
1835 HRESULT WINAPI SHStrDupW(LPCWSTR src, LPWSTR * dest)
1836 {
1837 HRESULT hr;
1838 int len = 0;
1839
1840 if (src) {
1841 len = (lstrlenW(src) + 1) * sizeof(WCHAR);
1842 *dest = CoTaskMemAlloc(len);
1843 } else {
1844 *dest = NULL;
1845 }
1846
1847 if (*dest) {
1848 memcpy(*dest, src, len);
1849 hr = S_OK;
1850 } else {
1851 hr = E_OUTOFMEMORY;
1852 }
1853
1854 TRACE("%s->(%p)\n", debugstr_w(src), *dest);
1855 return hr;
1856 }
1857
1858 /*************************************************************************
1859 * SHLWAPI_WriteReverseNum
1860 *
1861 * Internal helper for SHLWAPI_WriteTimeClass.
1862 */
1863 static inline LPWSTR SHLWAPI_WriteReverseNum(LPWSTR lpszOut, DWORD dwNum)
1864 {
1865 *lpszOut-- = '\0';
1866
1867 /* Write a decimal number to a string, backwards */
1868 do
1869 {
1870 DWORD dwNextDigit = dwNum % 10;
1871 *lpszOut-- = '0' + dwNextDigit;
1872 dwNum = (dwNum - dwNextDigit) / 10;
1873 } while (dwNum > 0);
1874
1875 return lpszOut;
1876 }
1877
1878 /*************************************************************************
1879 * SHLWAPI_FormatSignificant
1880 *
1881 * Internal helper for SHLWAPI_WriteTimeClass.
1882 */
1883 static inline int SHLWAPI_FormatSignificant(LPWSTR lpszNum, int dwDigits)
1884 {
1885 /* Zero non significant digits, return remaining significant digits */
1886 while (*lpszNum)
1887 {
1888 lpszNum++;
1889 if (--dwDigits == 0)
1890 {
1891 while (*lpszNum)
1892 *lpszNum++ = '0';
1893 return 0;
1894 }
1895 }
1896 return dwDigits;
1897 }
1898
1899 /*************************************************************************
1900 * SHLWAPI_WriteTimeClass
1901 *
1902 * Internal helper for StrFromTimeIntervalW.
1903 */
1904 static int SHLWAPI_WriteTimeClass(LPWSTR lpszOut, DWORD dwValue,
1905 UINT uClassStringId, int iDigits)
1906 {
1907 WCHAR szBuff[64], *szOut = szBuff + 32;
1908
1909 szOut = SHLWAPI_WriteReverseNum(szOut, dwValue);
1910 iDigits = SHLWAPI_FormatSignificant(szOut + 1, iDigits);
1911 *szOut = ' ';
1912 LoadStringW(shlwapi_hInstance, uClassStringId, szBuff + 32, 32);
1913 strcatW(lpszOut, szOut);
1914 return iDigits;
1915 }
1916
1917 /*************************************************************************
1918 * StrFromTimeIntervalA [SHLWAPI.@]
1919 *
1920 * Format a millisecond time interval into a string
1921 *
1922 * PARAMS
1923 * lpszStr [O] Output buffer for formatted time interval
1924 * cchMax [I] Size of lpszStr
1925 * dwMS [I] Number of milliseconds
1926 * iDigits [I] Number of digits to print
1927 *
1928 * RETURNS
1929 * The length of the formatted string, or 0 if any parameter is invalid.
1930 *
1931 * NOTES
1932 * This implementation mimics the Win32 behaviour of always writing a leading
1933 * space before the time interval begins.
1934 *
1935 * iDigits is used to provide approximate times if accuracy is not important.
1936 * This number of digits will be written of the first non-zero time class
1937 * (hours/minutes/seconds). If this does not complete the time classification,
1938 * the remaining digits are changed to zeros (i.e. The time is _not_ rounded).
1939 * If there are digits remaining following the writing of a time class, the
1940 * next time class will be written.
1941 *
1942 * For example, given dwMS represents 138 hours,43 minutes and 15 seconds, the
1943 * following will result from the given values of iDigits:
1944 *
1945 *| iDigits 1 2 3 4 5 ...
1946 *| lpszStr "100 hr" "130 hr" "138 hr" "138 hr 40 min" "138 hr 43 min" ...
1947 */
1948 INT WINAPI StrFromTimeIntervalA(LPSTR lpszStr, UINT cchMax, DWORD dwMS,
1949 int iDigits)
1950 {
1951 INT iRet = 0;
1952
1953 TRACE("(%p,%d,%d,%d)\n", lpszStr, cchMax, dwMS, iDigits);
1954
1955 if (lpszStr && cchMax)
1956 {
1957 WCHAR szBuff[128];
1958 StrFromTimeIntervalW(szBuff, sizeof(szBuff)/sizeof(WCHAR), dwMS, iDigits);
1959 WideCharToMultiByte(CP_ACP,0,szBuff,-1,lpszStr,cchMax,0,0);
1960 }
1961 return iRet;
1962 }
1963
1964
1965 /*************************************************************************
1966 * StrFromTimeIntervalW [SHLWAPI.@]
1967 *
1968 * See StrFromTimeIntervalA.
1969 */
1970 INT WINAPI StrFromTimeIntervalW(LPWSTR lpszStr, UINT cchMax, DWORD dwMS,
1971 int iDigits)
1972 {
1973 INT iRet = 0;
1974
1975 TRACE("(%p,%d,%d,%d)\n", lpszStr, cchMax, dwMS, iDigits);
1976
1977 if (lpszStr && cchMax)
1978 {
1979 WCHAR szCopy[128];
1980 DWORD dwHours, dwMinutes;
1981
1982 if (!iDigits || cchMax == 1)
1983 {
1984 *lpszStr = '\0';
1985 return 0;
1986 }
1987
1988 /* Calculate the time classes */
1989 dwMS = (dwMS + 500) / 1000;
1990 dwHours = dwMS / 3600;
1991 dwMS -= dwHours * 3600;
1992 dwMinutes = dwMS / 60;
1993 dwMS -= dwMinutes * 60;
1994
1995 szCopy[0] = '\0';
1996
1997 if (dwHours)
1998 iDigits = SHLWAPI_WriteTimeClass(szCopy, dwHours, IDS_TIME_INTERVAL_HOURS, iDigits);
1999
2000 if (dwMinutes && iDigits)
2001 iDigits = SHLWAPI_WriteTimeClass(szCopy, dwMinutes, IDS_TIME_INTERVAL_MINUTES, iDigits);
2002
2003 if (iDigits) /* Always write seconds if we have significant digits */
2004 SHLWAPI_WriteTimeClass(szCopy, dwMS, IDS_TIME_INTERVAL_SECONDS, iDigits);
2005
2006 lstrcpynW(lpszStr, szCopy, cchMax);
2007 iRet = strlenW(lpszStr);
2008 }
2009 return iRet;
2010 }
2011
2012 /*************************************************************************
2013 * StrIsIntlEqualA [SHLWAPI.@]
2014 *
2015 * Compare two strings.
2016 *
2017 * PARAMS
2018 * bCase [I] Whether to compare case sensitively
2019 * lpszStr [I] First string to compare
2020 * lpszComp [I] Second string to compare
2021 * iLen [I] Length to compare
2022 *
2023 * RETURNS
2024 * TRUE If the strings are equal.
2025 * FALSE Otherwise.
2026 */
2027 BOOL WINAPI StrIsIntlEqualA(BOOL bCase, LPCSTR lpszStr, LPCSTR lpszComp,
2028 int iLen)
2029 {
2030 DWORD dwFlags;
2031
2032 TRACE("(%d,%s,%s,%d)\n", bCase,
2033 debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
2034
2035 /* FIXME: This flag is undocumented and unknown by our CompareString.
2036 * We need a define for it.
2037 */
2038 dwFlags = 0x10000000;
2039 if (!bCase) dwFlags |= NORM_IGNORECASE;
2040
2041 return (CompareStringA(GetThreadLocale(), dwFlags, lpszStr, iLen, lpszComp, iLen) == CSTR_EQUAL);
2042 }
2043
2044 /*************************************************************************
2045 * StrIsIntlEqualW [SHLWAPI.@]
2046 *
2047 * See StrIsIntlEqualA.
2048 */
2049 BOOL WINAPI StrIsIntlEqualW(BOOL bCase, LPCWSTR lpszStr, LPCWSTR lpszComp,
2050 int iLen)
2051 {
2052 DWORD dwFlags;
2053
2054 TRACE("(%d,%s,%s,%d)\n", bCase,
2055 debugstr_w(lpszStr),debugstr_w(lpszComp), iLen);
2056
2057 /* FIXME: This flag is undocumented and unknown by our CompareString.
2058 * We need a define for it.
2059 */
2060 dwFlags = 0x10000000;
2061 if (!bCase) dwFlags |= NORM_IGNORECASE;
2062
2063 return (CompareStringW(GetThreadLocale(), dwFlags, lpszStr, iLen, lpszComp, iLen) == CSTR_EQUAL);
2064 }
2065
2066 /*************************************************************************
2067 * @ [SHLWAPI.399]
2068 *
2069 * Copy a string to another string, up to a maximum number of characters.
2070 *
2071 * PARAMS
2072 * lpszDest [O] Destination string
2073 * lpszSrc [I] Source string
2074 * iLen [I] Maximum number of chars to copy
2075 *
2076 * RETURNS
2077 * Success: A pointer to the last character written to lpszDest.
2078 * Failure: lpszDest, if any arguments are invalid.
2079 */
2080 LPSTR WINAPI StrCpyNXA(LPSTR lpszDest, LPCSTR lpszSrc, int iLen)
2081 {
2082 TRACE("(%p,%s,%i)\n", lpszDest, debugstr_a(lpszSrc), iLen);
2083
2084 if (lpszDest && lpszSrc && iLen > 0)
2085 {
2086 while ((iLen-- > 1) && *lpszSrc)
2087 *lpszDest++ = *lpszSrc++;
2088 if (iLen >= 0)
2089 *lpszDest = '\0';
2090 }
2091 return lpszDest;
2092 }
2093
2094 /*************************************************************************
2095 * @ [SHLWAPI.400]
2096 *
2097 * Unicode version of StrCpyNXA.
2098 */
2099 LPWSTR WINAPI StrCpyNXW(LPWSTR lpszDest, LPCWSTR lpszSrc, int iLen)
2100 {
2101 TRACE("(%p,%s,%i)\n", lpszDest, debugstr_w(lpszSrc), iLen);
2102
2103 if (lpszDest && lpszSrc && iLen > 0)
2104 {
2105 while ((iLen-- > 1) && *lpszSrc)
2106 *lpszDest++ = *lpszSrc++;
2107 if (iLen >= 0)
2108 *lpszDest = '\0';
2109 }
2110 return lpszDest;
2111 }
2112
2113 /*************************************************************************
2114 * StrCmpLogicalW [SHLWAPI.@]
2115 *
2116 * Compare two strings, ignoring case and comparing digits as numbers.
2117 *
2118 * PARAMS
2119 * lpszStr [I] First string to compare
2120 * lpszComp [I] Second string to compare
2121 * iLen [I] Length to compare
2122 *
2123 * RETURNS
2124 * TRUE If the strings are equal.
2125 * FALSE Otherwise.
2126 */
2127 INT WINAPI StrCmpLogicalW(LPCWSTR lpszStr, LPCWSTR lpszComp)
2128 {
2129 INT iDiff;
2130
2131 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszComp));
2132
2133 if (lpszStr && lpszComp)
2134 {
2135 while (*lpszStr)
2136 {
2137 if (!*lpszComp)
2138 return 1;
2139 else if (isdigitW(*lpszStr))
2140 {
2141 int iStr, iComp;
2142
2143 if (!isdigitW(*lpszComp))
2144 return -1;
2145
2146 /* Compare the numbers */
2147 StrToIntExW(lpszStr, 0, &iStr);
2148 StrToIntExW(lpszComp, 0, &iComp);
2149
2150 if (iStr < iComp)
2151 return -1;
2152 else if (iStr > iComp)
2153 return 1;
2154
2155 /* Skip */
2156 while (isdigitW(*lpszStr))
2157 lpszStr++;
2158 while (isdigitW(*lpszComp))
2159 lpszComp++;
2160 }
2161 else if (isdigitW(*lpszComp))
2162 return 1;
2163 else
2164 {
2165 iDiff = ChrCmpIW(*lpszStr,*lpszComp);
2166 if (iDiff > 0)
2167 return 1;
2168 else if (iDiff < 0)
2169 return -1;
2170
2171 lpszStr++;
2172 lpszComp++;
2173 }
2174 }
2175 if (*lpszComp)
2176 return -1;
2177 }
2178 return 0;
2179 }
2180
2181 /* Structure for formatting byte strings */
2182 typedef struct tagSHLWAPI_BYTEFORMATS
2183 {
2184 LONGLONG dLimit;
2185 double dDivisor;
2186 double dNormaliser;
2187 int nDecimals;
2188 WCHAR wPrefix;
2189 } SHLWAPI_BYTEFORMATS;
2190
2191 /*************************************************************************
2192 * StrFormatByteSizeW [SHLWAPI.@]
2193 *
2194 * Create a string containing an abbreviated byte count of up to 2^63-1.
2195 *
2196 * PARAMS
2197 * llBytes [I] Byte size to format
2198 * lpszDest [I] Destination for formatted string
2199 * cchMax [I] Size of lpszDest
2200 *
2201 * RETURNS
2202 * lpszDest.
2203 *
2204 * NOTES
2205 * There is no StrFormatByteSize64W function, it is called StrFormatByteSizeW().
2206 */
2207 LPWSTR WINAPI StrFormatByteSizeW(LONGLONG llBytes, LPWSTR lpszDest, UINT cchMax)
2208 {
2209 #define KB ((ULONGLONG)1024)
2210 #define MB (KB*KB)
2211 #define GB (KB*KB*KB)
2212 #define TB (KB*KB*KB*KB)
2213 #define PB (KB*KB*KB*KB*KB)
2214
2215 static const SHLWAPI_BYTEFORMATS bfFormats[] =
2216 {
2217 { 10*KB, 10.24, 100.0, 2, 'K' }, /* 10 KB */
2218 { 100*KB, 102.4, 10.0, 1, 'K' }, /* 100 KB */
2219 { 1000*KB, 1024.0, 1.0, 0, 'K' }, /* 1000 KB */
2220 { 10*MB, 10485.76, 100.0, 2, 'M' }, /* 10 MB */
2221 { 100*MB, 104857.6, 10.0, 1, 'M' }, /* 100 MB */
2222 { 1000*MB, 1048576.0, 1.0, 0, 'M' }, /* 1000 MB */
2223 { 10*GB, 10737418.24, 100.0, 2, 'G' }, /* 10 GB */
2224 { 100*GB, 107374182.4, 10.0, 1, 'G' }, /* 100 GB */
2225 { 1000*GB, 1073741824.0, 1.0, 0, 'G' }, /* 1000 GB */
2226 { 10*TB, 10485.76, 100.0, 2, 'T' }, /* 10 TB */
2227 { 100*TB, 104857.6, 10.0, 1, 'T' }, /* 100 TB */
2228 { 1000*TB, 1048576.0, 1.0, 0, 'T' }, /* 1000 TB */
2229 { 10*PB, 10737418.24, 100.00, 2, 'P' }, /* 10 PB */
2230 { 100*PB, 107374182.4, 10.00, 1, 'P' }, /* 100 PB */
2231 { 1000*PB, 1073741824.0, 1.00, 0, 'P' }, /* 1000 PB */
2232 { 0, 10995116277.76, 100.00, 2, 'E' } /* EB's, catch all */
2233 };
2234 WCHAR wszAdd[] = {' ','?','B',0};
2235 double dBytes;
2236 UINT i = 0;
2237
2238 TRACE("(0x%s,%p,%d)\n", wine_dbgstr_longlong(llBytes), lpszDest, cchMax);
2239
2240 if (!lpszDest || !cchMax)
2241 return lpszDest;
2242
2243 if (llBytes < 1024) /* 1K */
2244 {
2245 WCHAR wszBytesFormat[64];
2246 LoadStringW(shlwapi_hInstance, IDS_BYTES_FORMAT, wszBytesFormat, 64);
2247 snprintfW(lpszDest, cchMax, wszBytesFormat, (long)llBytes);
2248 return lpszDest;
2249 }
2250
2251 /* Note that if this loop completes without finding a match, i will be
2252 * pointing at the last entry, which is a catch all for > 1000 PB
2253 */
2254 while (i < sizeof(bfFormats) / sizeof(SHLWAPI_BYTEFORMATS) - 1)
2255 {
2256 if (llBytes < bfFormats[i].dLimit)
2257 break;
2258 i++;
2259 }
2260 /* Above 1 TB we encounter problems with FP accuracy. So for amounts above
2261 * this number we integer shift down by 1 MB first. The table above has
2262 * the divisors scaled down from the '< 10 TB' entry onwards, to account
2263 * for this. We also add a small fudge factor to get the correct result for
2264 * counts that lie exactly on a 1024 byte boundary.
2265 */
2266 if (i > 8)
2267 dBytes = (double)(llBytes >> 20) + 0.001; /* Scale down by I MB */
2268 else
2269 dBytes = (double)llBytes + 0.00001;
2270
2271 dBytes = floor(dBytes / bfFormats[i].dDivisor) / bfFormats[i].dNormaliser;
2272
2273 if (!FormatDouble(dBytes, bfFormats[i].nDecimals, lpszDest, cchMax))
2274 return NULL;
2275 wszAdd[1] = bfFormats[i].wPrefix;
2276 StrCatBuffW(lpszDest, wszAdd, cchMax);
2277 return lpszDest;
2278 }
2279
2280 /*************************************************************************
2281 * StrFormatByteSize64A [SHLWAPI.@]
2282 *
2283 * See StrFormatByteSizeW.
2284 */
2285 LPSTR WINAPI StrFormatByteSize64A(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax)
2286 {
2287 WCHAR wszBuff[32];
2288
2289 StrFormatByteSizeW(llBytes, wszBuff, sizeof(wszBuff)/sizeof(WCHAR));
2290
2291 if (lpszDest)
2292 WideCharToMultiByte(CP_ACP, 0, wszBuff, -1, lpszDest, cchMax, 0, 0);
2293 return lpszDest;
2294 }
2295
2296 /*************************************************************************
2297 * StrFormatByteSizeA [SHLWAPI.@]
2298 *
2299 * Create a string containing an abbreviated byte count of up to 2^31-1.
2300 *
2301 * PARAMS
2302 * dwBytes [I] Byte size to format
2303 * lpszDest [I] Destination for formatted string
2304 * cchMax [I] Size of lpszDest
2305 *
2306 * RETURNS
2307 * lpszDest.
2308 *
2309 * NOTES
2310 * The Ascii and Unicode versions of this function accept a different
2311 * integer type for dwBytes. See StrFormatByteSize64A().
2312 */
2313 LPSTR WINAPI StrFormatByteSizeA(DWORD dwBytes, LPSTR lpszDest, UINT cchMax)
2314 {
2315 TRACE("(%d,%p,%d)\n", dwBytes, lpszDest, cchMax);
2316
2317 return StrFormatByteSize64A(dwBytes, lpszDest, cchMax);
2318 }
2319
2320 /*************************************************************************
2321 * @ [SHLWAPI.162]
2322 *
2323 * Remove a hanging lead byte from the end of a string, if present.
2324 *
2325 * PARAMS
2326 * lpStr [I] String to check for a hanging lead byte
2327 * size [I] Length of lpStr
2328 *
2329 * RETURNS
2330 * Success: The new length of the string. Any hanging lead bytes are removed.
2331 * Failure: 0, if any parameters are invalid.
2332 */
2333 DWORD WINAPI SHTruncateString(LPSTR lpStr, DWORD size)
2334 {
2335 if (lpStr && size)
2336 {
2337 LPSTR lastByte = lpStr + size - 1;
2338
2339 while(lpStr < lastByte)
2340 lpStr += IsDBCSLeadByte(*lpStr) ? 2 : 1;
2341
2342 if(lpStr == lastByte && IsDBCSLeadByte(*lpStr))
2343 {
2344 *lpStr = '\0';
2345 size--;
2346 }
2347 return size;
2348 }
2349 return 0;
2350 }
2351
2352 /*************************************************************************
2353 * @ [SHLWAPI.203]
2354 *
2355 * Remove a single non-trailing ampersand ('&') from a string.
2356 *
2357 * PARAMS
2358 * lpszStr [I/O] String to remove ampersand from.
2359 *
2360 * RETURNS
2361 * The character after the first ampersand in lpszStr, or the first character
2362 * in lpszStr if there is no ampersand in the string.
2363 */
2364 char WINAPI SHStripMneumonicA(LPCSTR lpszStr)
2365 {
2366 LPSTR lpszIter, lpszTmp;
2367 char ch;
2368
2369 TRACE("(%s)\n", debugstr_a(lpszStr));
2370
2371 ch = *lpszStr;
2372
2373 if ((lpszIter = StrChrA(lpszStr, '&')))
2374 {
2375 lpszTmp = CharNextA(lpszIter);
2376 if (lpszTmp && *lpszTmp)
2377 {
2378 if (*lpszTmp != '&')
2379 ch = *lpszTmp;
2380
2381 while (lpszIter && *lpszIter)
2382 {
2383 lpszTmp = CharNextA(lpszIter);
2384 *lpszIter = *lpszTmp;
2385 lpszIter = lpszTmp;
2386 }
2387 }
2388 }
2389
2390 return ch;
2391 }
2392
2393 /*************************************************************************
2394 * @ [SHLWAPI.225]
2395 *
2396 * Unicode version of SHStripMneumonicA.
2397 */
2398 WCHAR WINAPI SHStripMneumonicW(LPCWSTR lpszStr)
2399 {
2400 LPWSTR lpszIter, lpszTmp;
2401 WCHAR ch;
2402
2403 TRACE("(%s)\n", debugstr_w(lpszStr));
2404
2405 ch = *lpszStr;
2406
2407 if ((lpszIter = StrChrW(lpszStr, '&')))
2408 {
2409 lpszTmp = lpszIter + 1;
2410 if (lpszTmp && *lpszTmp)
2411 {
2412 if (*lpszTmp != '&')
2413 ch = *lpszTmp;
2414
2415 while (lpszIter && *lpszIter)
2416 {
2417 lpszTmp = lpszIter + 1;
2418 *lpszIter = *lpszTmp;
2419 lpszIter = lpszTmp;
2420 }
2421 }
2422 }
2423
2424 return ch;
2425 }
2426
2427 /*************************************************************************
2428 * @ [SHLWAPI.216]
2429 *
2430 * Convert an Ascii string to Unicode.
2431 *
2432 * PARAMS
2433 * dwCp [I] Code page for the conversion
2434 * lpSrcStr [I] Source Ascii string to convert
2435 * lpDstStr [O] Destination for converted Unicode string
2436 * iLen [I] Length of lpDstStr
2437 *
2438 * RETURNS
2439 * The return value of the MultiByteToWideChar() function called on lpSrcStr.
2440 */
2441 DWORD WINAPI SHAnsiToUnicodeCP(DWORD dwCp, LPCSTR lpSrcStr, LPWSTR lpDstStr, int iLen)
2442 {
2443 DWORD dwRet;
2444
2445 dwRet = MultiByteToWideChar(dwCp, 0, lpSrcStr, -1, lpDstStr, iLen);
2446 TRACE("%s->%s,ret=%d\n", debugstr_a(lpSrcStr), debugstr_w(lpDstStr), dwRet);
2447 return dwRet;
2448 }
2449
2450 /*************************************************************************
2451 * @ [SHLWAPI.215]
2452 *
2453 * Convert an Ascii string to Unicode.
2454 *
2455 * PARAMS
2456 * lpSrcStr [I] Source Ascii string to convert
2457 * lpDstStr [O] Destination for converted Unicode string
2458 * iLen [I] Length of lpDstStr
2459 *
2460 * RETURNS
2461 * The return value of the MultiByteToWideChar() function called on lpSrcStr.
2462 *
2463 * NOTES
2464 * This function simply calls SHAnsiToUnicodeCP with code page CP_ACP.
2465 */
2466 DWORD WINAPI SHAnsiToUnicode(LPCSTR lpSrcStr, LPWSTR lpDstStr, int iLen)
2467 {
2468 return SHAnsiToUnicodeCP(CP_ACP, lpSrcStr, lpDstStr, iLen);
2469 }
2470
2471 /*************************************************************************
2472 * @ [SHLWAPI.218]
2473 *
2474 * Convert a Unicode string to Ascii.
2475 *
2476 * PARAMS
2477 * CodePage [I] Code page to use for the conversion
2478 * lpSrcStr [I] Source Unicode string to convert
2479 * lpDstStr [O] Destination for converted Ascii string
2480 * lpiLen [I/O] Input length of lpDstStr/destination for length of lpDstStr
2481 *
2482 * RETURNS
2483 * Success: The number of characters that result from the conversion.
2484 * Failure: 0.
2485 */
2486 INT WINAPI SHUnicodeToAnsiCP(UINT CodePage, LPCWSTR lpSrcStr, LPSTR lpDstStr,
2487 LPINT lpiLen)
2488 {
2489 static const WCHAR emptyW[] = { '\0' };
2490 int len , reqLen;
2491 LPSTR mem;
2492
2493 if (!lpDstStr || !lpiLen)
2494 return 0;
2495
2496 if (!lpSrcStr)
2497 lpSrcStr = emptyW;
2498
2499 *lpDstStr = '\0';
2500
2501 len = strlenW(lpSrcStr) + 1;
2502
2503 switch (CodePage)
2504 {
2505 case CP_WINUNICODE:
2506 CodePage = CP_UTF8; /* Fall through... */
2507 case 0x0000C350: /* FIXME: CP_ #define */
2508 case CP_UTF7:
2509 case CP_UTF8:
2510 {
2511 DWORD dwMode = 0;
2512 INT nWideCharCount = len - 1;
2513
2514 if (!ConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &nWideCharCount, lpDstStr,
2515 lpiLen))
2516 return 0;
2517
2518 if (nWideCharCount < len - 1)
2519 {
2520 mem = HeapAlloc(GetProcessHeap(), 0, *lpiLen);
2521 if (!mem)
2522 return 0;
2523
2524 *lpiLen = 0;
2525
2526 if (ConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &len, mem, lpiLen))
2527 {
2528 SHTruncateString(mem, *lpiLen);
2529 lstrcpynA(lpDstStr, mem, *lpiLen + 1);
2530 HeapFree(GetProcessHeap(), 0, mem);
2531 return *lpiLen + 1;
2532 }
2533 HeapFree(GetProcessHeap(), 0, mem);
2534 return *lpiLen;
2535 }
2536 lpDstStr[*lpiLen] = '\0';
2537 return *lpiLen;
2538 }
2539 default:
2540 break;
2541 }
2542
2543 reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, lpDstStr,
2544 *lpiLen, NULL, NULL);
2545
2546 if (!reqLen && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
2547 {
2548 reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, NULL, 0, NULL, NULL);
2549 if (reqLen)
2550 {
2551 mem = HeapAlloc(GetProcessHeap(), 0, reqLen);
2552 if (mem)
2553 {
2554 reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, mem,
2555 reqLen, NULL, NULL);
2556
2557 reqLen = SHTruncateString(mem, *lpiLen);
2558 reqLen++;
2559
2560 lstrcpynA(lpDstStr, mem, *lpiLen);
2561
2562 HeapFree(GetProcessHeap(), 0, mem);
2563 }
2564 }
2565 }
2566 return reqLen;
2567 }
2568
2569 /*************************************************************************
2570 * @ [SHLWAPI.217]
2571 *
2572 * Convert a Unicode string to Ascii.
2573 *
2574 * PARAMS
2575 * lpSrcStr [I] Source Unicode string to convert
2576 * lpDstStr [O] Destination for converted Ascii string
2577 * iLen [O] Length of lpDstStr in characters
2578 *
2579 * RETURNS
2580 * See SHUnicodeToAnsiCP
2581
2582 * NOTES
2583 * This function simply calls SHUnicodeToAnsiCP() with CodePage = CP_ACP.
2584 */
2585 INT WINAPI SHUnicodeToAnsi(LPCWSTR lpSrcStr, LPSTR lpDstStr, INT iLen)
2586 {
2587 INT myint = iLen;
2588
2589 return SHUnicodeToAnsiCP(CP_ACP, lpSrcStr, lpDstStr, &myint);
2590 }
2591
2592 /*************************************************************************
2593 * @ [SHLWAPI.345]
2594 *
2595 * Copy one string to another.
2596 *
2597 * PARAMS
2598 * lpszSrc [I] Source string to copy
2599 * lpszDst [O] Destination for copy
2600 * iLen [I] Length of lpszDst in characters
2601 *
2602 * RETURNS
2603 * The length of the copied string, including the terminating NUL. lpszDst
2604 * contains iLen characters of lpszSrc.
2605 */
2606 DWORD WINAPI SHAnsiToAnsi(LPCSTR lpszSrc, LPSTR lpszDst, int iLen)
2607 {
2608 LPSTR lpszRet;
2609
2610 TRACE("(%s,%p,0x%08x)\n", debugstr_a(lpszSrc), lpszDst, iLen);
2611
2612 lpszRet = StrCpyNXA(lpszDst, lpszSrc, iLen);
2613 return lpszRet - lpszDst + 1;
2614 }
2615
2616 /*************************************************************************
2617 * @ [SHLWAPI.346]
2618 *
2619 * Unicode version of SSHAnsiToAnsi.
2620 */
2621 DWORD WINAPI SHUnicodeToUnicode(LPCWSTR lpszSrc, LPWSTR lpszDst, int iLen)
2622 {
2623 LPWSTR lpszRet;
2624
2625 TRACE("(%s,%p,0x%08x)\n", debugstr_w(lpszSrc), lpszDst, iLen);
2626
2627 lpszRet = StrCpyNXW(lpszDst, lpszSrc, iLen);
2628 return lpszRet - lpszDst + 1;
2629 }
2630
2631 /*************************************************************************
2632 * @ [SHLWAPI.364]
2633 *
2634 * Determine if an Ascii string converts to Unicode and back identically.
2635 *
2636 * PARAMS
2637 * lpSrcStr [I] Source Unicode string to convert
2638 * lpDst [O] Destination for resulting Ascii string
2639 * iLen [I] Length of lpDst in characters
2640 *
2641 * RETURNS
2642 * TRUE, since Ascii strings always convert identically.
2643 */
2644 BOOL WINAPI DoesStringRoundTripA(LPCSTR lpSrcStr, LPSTR lpDst, INT iLen)
2645 {
2646 lstrcpynA(lpDst, lpSrcStr, iLen);
2647 return TRUE;
2648 }
2649
2650 /*************************************************************************
2651 * @ [SHLWAPI.365]
2652 *
2653 * Determine if a Unicode string converts to Ascii and back identically.
2654 *
2655 * PARAMS
2656 * lpSrcStr [I] Source Unicode string to convert
2657 * lpDst [O] Destination for resulting Ascii string
2658 * iLen [I] Length of lpDst in characters
2659 *
2660 * RETURNS
2661 * TRUE, if lpSrcStr converts to Ascii and back identically,
2662 * FALSE otherwise.
2663 */
2664 BOOL WINAPI DoesStringRoundTripW(LPCWSTR lpSrcStr, LPSTR lpDst, INT iLen)
2665 {
2666 WCHAR szBuff[MAX_PATH];
2667
2668 SHUnicodeToAnsi(lpSrcStr, lpDst, iLen);
2669 SHAnsiToUnicode(lpDst, szBuff, MAX_PATH);
2670 return !strcmpW(lpSrcStr, szBuff);
2671 }
2672
2673 /*************************************************************************
2674 * SHLoadIndirectString [SHLWAPI.@]
2675 *
2676 * If passed a string that begins with '@', extract the string from the
2677 * appropriate resource, otherwise do a straight copy.
2678 *
2679 */
2680 HRESULT WINAPI SHLoadIndirectString(LPCWSTR src, LPWSTR dst, UINT dst_len, void **reserved)
2681 {
2682 WCHAR *dllname = NULL;
2683 HMODULE hmod = NULL;
2684 HRESULT hr = E_FAIL;
2685
2686 TRACE("(%s %p %08x %p)\n", debugstr_w(src), dst, dst_len, reserved);
2687
2688 if(src[0] == '@')
2689 {
2690 WCHAR *index_str;
2691 int index;
2692
2693 dst[0] = 0;
2694 dllname = StrDupW(src + 1);
2695 index_str = strchrW(dllname, ',');
2696
2697 if(!index_str) goto end;
2698
2699 *index_str = 0;
2700 index_str++;
2701 index = atoiW(index_str);
2702
2703 hmod = LoadLibraryW(dllname);
2704 if(!hmod) goto end;
2705
2706 if(index < 0)
2707 {
2708 if(LoadStringW(hmod, -index, dst, dst_len))
2709 hr = S_OK;
2710 }
2711 else
2712 FIXME("can't handle non-negative indices (%d)\n", index);
2713 }
2714 else
2715 {
2716 if(dst != src)
2717 lstrcpynW(dst, src, dst_len);
2718 hr = S_OK;
2719 }
2720
2721 TRACE("returning %s\n", debugstr_w(dst));
2722 end:
2723 if(hmod) FreeLibrary(hmod);
2724 HeapFree(GetProcessHeap(), 0, dllname);
2725 return hr;
2726 }