Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenstring.c
Go to the documentation of this file.
00001 /* 00002 * Shlwapi string functions 00003 * 00004 * Copyright 1998 Juergen Schmied 00005 * Copyright 2002 Jon Griffiths 00006 * 00007 * This library is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2.1 of the License, or (at your option) any later version. 00011 * 00012 * This library is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with this library; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00020 */ 00021 00022 #include "config.h" 00023 #include "wine/port.h" 00024 00025 #include <math.h> 00026 #include <stdarg.h> 00027 #include <stdio.h> 00028 #include <string.h> 00029 00030 #define NONAMELESSUNION 00031 #define NONAMELESSSTRUCT 00032 #include "windef.h" 00033 #include "winbase.h" 00034 #define NO_SHLWAPI_REG 00035 #define NO_SHLWAPI_STREAM 00036 #include "shlwapi.h" 00037 #include "wingdi.h" 00038 #include "winuser.h" 00039 #include "shlobj.h" 00040 #include "mlang.h" 00041 #include "ddeml.h" 00042 #include "wine/unicode.h" 00043 #include "wine/debug.h" 00044 00045 #include "resource.h" 00046 00047 WINE_DEFAULT_DEBUG_CHANNEL(shell); 00048 00049 extern HINSTANCE shlwapi_hInstance; 00050 00051 static HRESULT _SHStrDupAA(LPCSTR,LPSTR*); 00052 static HRESULT _SHStrDupAW(LPCWSTR,LPSTR*); 00053 00054 00055 static void FillNumberFmt(NUMBERFMTW *fmt, LPWSTR decimal_buffer, int decimal_bufwlen, 00056 LPWSTR thousand_buffer, int thousand_bufwlen) 00057 { 00058 WCHAR grouping[64]; 00059 WCHAR *c; 00060 00061 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_ILZERO|LOCALE_RETURN_NUMBER, (LPWSTR)&fmt->LeadingZero, sizeof(fmt->LeadingZero)/sizeof(WCHAR)); 00062 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_INEGNUMBER|LOCALE_RETURN_NUMBER, (LPWSTR)&fmt->LeadingZero, sizeof(fmt->NegativeOrder)/sizeof(WCHAR)); 00063 fmt->NumDigits = 0; 00064 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, decimal_buffer, decimal_bufwlen); 00065 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, thousand_buffer, thousand_bufwlen); 00066 fmt->lpThousandSep = thousand_buffer; 00067 fmt->lpDecimalSep = decimal_buffer; 00068 00069 /* 00070 * Converting grouping string to number as described on 00071 * http://blogs.msdn.com/oldnewthing/archive/2006/04/18/578251.aspx 00072 */ 00073 fmt->Grouping = 0; 00074 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SGROUPING, grouping, sizeof(grouping)/sizeof(WCHAR)); 00075 for (c = grouping; *c; c++) 00076 if (*c >= '0' && *c < '9') 00077 { 00078 fmt->Grouping *= 10; 00079 fmt->Grouping += *c - '0'; 00080 } 00081 00082 if (fmt->Grouping % 10 == 0) 00083 fmt->Grouping /= 10; 00084 else 00085 fmt->Grouping *= 10; 00086 } 00087 00088 /************************************************************************* 00089 * FormatInt [internal] 00090 * 00091 * Format an integer according to the current locale 00092 * 00093 * RETURNS 00094 * The number of characters written on success or 0 on failure 00095 */ 00096 static int FormatInt(LONGLONG qdwValue, LPWSTR pszBuf, int cchBuf) 00097 { 00098 NUMBERFMTW fmt; 00099 WCHAR decimal[8], thousand[8]; 00100 WCHAR buf[24]; 00101 WCHAR *c; 00102 BOOL neg = (qdwValue < 0); 00103 00104 FillNumberFmt(&fmt, decimal, sizeof decimal / sizeof (WCHAR), 00105 thousand, sizeof thousand / sizeof (WCHAR)); 00106 00107 c = &buf[24]; 00108 *(--c) = 0; 00109 do 00110 { 00111 *(--c) = '0' + (qdwValue%10); 00112 qdwValue /= 10; 00113 } while (qdwValue > 0); 00114 if (neg) 00115 *(--c) = '-'; 00116 00117 return GetNumberFormatW(LOCALE_USER_DEFAULT, 0, c, &fmt, pszBuf, cchBuf); 00118 } 00119 00120 /************************************************************************* 00121 * FormatDouble [internal] 00122 * 00123 * Format an integer according to the current locale. Prints the specified number of digits 00124 * after the decimal point 00125 * 00126 * RETURNS 00127 * The number of characters written on success or 0 on failure 00128 */ 00129 static int FormatDouble(double value, int decimals, LPWSTR pszBuf, int cchBuf) 00130 { 00131 static const WCHAR flfmt[] = {'%','f',0}; 00132 WCHAR buf[64]; 00133 NUMBERFMTW fmt; 00134 WCHAR decimal[8], thousand[8]; 00135 00136 snprintfW(buf, 64, flfmt, value); 00137 00138 FillNumberFmt(&fmt, decimal, sizeof decimal / sizeof (WCHAR), 00139 thousand, sizeof thousand / sizeof (WCHAR)); 00140 fmt.NumDigits = decimals; 00141 return GetNumberFormatW(LOCALE_USER_DEFAULT, 0, buf, &fmt, pszBuf, cchBuf); 00142 } 00143 00144 /************************************************************************* 00145 * SHLWAPI_ChrCmpHelperA 00146 * 00147 * Internal helper for SHLWAPI_ChrCmpA/ChrCMPIA. 00148 * 00149 * NOTES 00150 * Both this function and its Unicode counterpart are very inefficient. To 00151 * fix this, CompareString must be completely implemented and optimised 00152 * first. Then the core character test can be taken out of that function and 00153 * placed here, so that it need never be called at all. Until then, do not 00154 * attempt to optimise this code unless you are willing to test that it 00155 * still performs correctly. 00156 */ 00157 static BOOL SHLWAPI_ChrCmpHelperA(WORD ch1, WORD ch2, DWORD dwFlags) 00158 { 00159 char str1[3], str2[3]; 00160 00161 str1[0] = LOBYTE(ch1); 00162 if (IsDBCSLeadByte(str1[0])) 00163 { 00164 str1[1] = HIBYTE(ch1); 00165 str1[2] = '\0'; 00166 } 00167 else 00168 str1[1] = '\0'; 00169 00170 str2[0] = LOBYTE(ch2); 00171 if (IsDBCSLeadByte(str2[0])) 00172 { 00173 str2[1] = HIBYTE(ch2); 00174 str2[2] = '\0'; 00175 } 00176 else 00177 str2[1] = '\0'; 00178 00179 return CompareStringA(GetThreadLocale(), dwFlags, str1, -1, str2, -1) - 2; 00180 } 00181 00182 /************************************************************************* 00183 * SHLWAPI_ChrCmpA 00184 * 00185 * Internal helper function. 00186 */ 00187 static BOOL WINAPI SHLWAPI_ChrCmpA(WORD ch1, WORD ch2) 00188 { 00189 return SHLWAPI_ChrCmpHelperA(ch1, ch2, 0); 00190 } 00191 00192 /************************************************************************* 00193 * ChrCmpIA (SHLWAPI.385) 00194 * 00195 * Compare two characters, ignoring case. 00196 * 00197 * PARAMS 00198 * ch1 [I] First character to compare 00199 * ch2 [I] Second character to compare 00200 * 00201 * RETURNS 00202 * FALSE, if the characters are equal. 00203 * Non-zero otherwise. 00204 */ 00205 BOOL WINAPI ChrCmpIA(WORD ch1, WORD ch2) 00206 { 00207 TRACE("(%d,%d)\n", ch1, ch2); 00208 00209 return SHLWAPI_ChrCmpHelperA(ch1, ch2, NORM_IGNORECASE); 00210 } 00211 00212 /************************************************************************* 00213 * ChrCmpIW [SHLWAPI.386] 00214 * 00215 * See ChrCmpIA. 00216 */ 00217 BOOL WINAPI ChrCmpIW(WCHAR ch1, WCHAR ch2) 00218 { 00219 return CompareStringW(GetThreadLocale(), NORM_IGNORECASE, &ch1, 1, &ch2, 1) - 2; 00220 } 00221 00222 /************************************************************************* 00223 * StrChrA [SHLWAPI.@] 00224 * 00225 * Find a given character in a string. 00226 * 00227 * PARAMS 00228 * lpszStr [I] String to search in. 00229 * ch [I] Character to search for. 00230 * 00231 * RETURNS 00232 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if 00233 * not found. 00234 * Failure: NULL, if any arguments are invalid. 00235 */ 00236 LPSTR WINAPI StrChrA(LPCSTR lpszStr, WORD ch) 00237 { 00238 TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch); 00239 00240 if (lpszStr) 00241 { 00242 while (*lpszStr) 00243 { 00244 if (!SHLWAPI_ChrCmpA(*lpszStr, ch)) 00245 return (LPSTR)lpszStr; 00246 lpszStr = CharNextA(lpszStr); 00247 } 00248 } 00249 return NULL; 00250 } 00251 00252 /************************************************************************* 00253 * StrChrW [SHLWAPI.@] 00254 * 00255 * See StrChrA. 00256 */ 00257 LPWSTR WINAPI StrChrW(LPCWSTR lpszStr, WCHAR ch) 00258 { 00259 LPWSTR lpszRet = NULL; 00260 00261 TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch); 00262 00263 if (lpszStr) 00264 lpszRet = strchrW(lpszStr, ch); 00265 return lpszRet; 00266 } 00267 00268 /************************************************************************* 00269 * StrChrIA [SHLWAPI.@] 00270 * 00271 * Find a given character in a string, ignoring case. 00272 * 00273 * PARAMS 00274 * lpszStr [I] String to search in. 00275 * ch [I] Character to search for. 00276 * 00277 * RETURNS 00278 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if 00279 * not found. 00280 * Failure: NULL, if any arguments are invalid. 00281 */ 00282 LPSTR WINAPI StrChrIA(LPCSTR lpszStr, WORD ch) 00283 { 00284 TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch); 00285 00286 if (lpszStr) 00287 { 00288 while (*lpszStr) 00289 { 00290 if (!ChrCmpIA(*lpszStr, ch)) 00291 return (LPSTR)lpszStr; 00292 lpszStr = CharNextA(lpszStr); 00293 } 00294 } 00295 return NULL; 00296 } 00297 00298 /************************************************************************* 00299 * StrChrIW [SHLWAPI.@] 00300 * 00301 * See StrChrA. 00302 */ 00303 LPWSTR WINAPI StrChrIW(LPCWSTR lpszStr, WCHAR ch) 00304 { 00305 TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch); 00306 00307 if (lpszStr) 00308 { 00309 ch = toupperW(ch); 00310 while (*lpszStr) 00311 { 00312 if (toupperW(*lpszStr) == ch) 00313 return (LPWSTR)lpszStr; 00314 lpszStr++; 00315 } 00316 lpszStr = NULL; 00317 } 00318 return (LPWSTR)lpszStr; 00319 } 00320 00321 /************************************************************************* 00322 * StrChrNW [SHLWAPI.@] 00323 */ 00324 LPWSTR WINAPI StrChrNW(LPCWSTR lpszStr, WCHAR ch, UINT cchMax) 00325 { 00326 TRACE("(%s(%i),%i)\n", debugstr_wn(lpszStr,cchMax), cchMax, ch); 00327 00328 if (lpszStr) 00329 { 00330 while (*lpszStr && cchMax-- > 0) 00331 { 00332 if (*lpszStr == ch) 00333 return (LPWSTR)lpszStr; 00334 lpszStr++; 00335 } 00336 } 00337 return NULL; 00338 } 00339 00340 /************************************************************************* 00341 * StrCmpIW [SHLWAPI.@] 00342 * 00343 * Compare two strings, ignoring case. 00344 * 00345 * PARAMS 00346 * lpszStr [I] First string to compare 00347 * lpszComp [I] Second string to compare 00348 * 00349 * RETURNS 00350 * An integer less than, equal to or greater than 0, indicating that 00351 * lpszStr is less than, the same, or greater than lpszComp. 00352 */ 00353 int WINAPI StrCmpIW(LPCWSTR lpszStr, LPCWSTR lpszComp) 00354 { 00355 int iRet; 00356 00357 TRACE("(%s,%s)\n", debugstr_w(lpszStr),debugstr_w(lpszComp)); 00358 00359 iRet = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, lpszStr, -1, lpszComp, -1); 00360 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0; 00361 } 00362 00363 /************************************************************************* 00364 * StrCmpNA [SHLWAPI.@] 00365 * 00366 * Compare two strings, up to a maximum length. 00367 * 00368 * PARAMS 00369 * lpszStr [I] First string to compare 00370 * lpszComp [I] Second string to compare 00371 * iLen [I] Maximum number of chars to compare. 00372 * 00373 * RETURNS 00374 * An integer less than, equal to or greater than 0, indicating that 00375 * lpszStr is less than, the same, or greater than lpszComp. 00376 */ 00377 INT WINAPI StrCmpNA(LPCSTR lpszStr, LPCSTR lpszComp, INT iLen) 00378 { 00379 INT iRet; 00380 00381 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen); 00382 00383 iRet = CompareStringA(GetThreadLocale(), 0, lpszStr, iLen, lpszComp, iLen); 00384 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0; 00385 } 00386 00387 /************************************************************************* 00388 * StrCmpNW [SHLWAPI.@] 00389 * 00390 * See StrCmpNA. 00391 */ 00392 INT WINAPI StrCmpNW(LPCWSTR lpszStr, LPCWSTR lpszComp, INT iLen) 00393 { 00394 INT iRet; 00395 00396 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen); 00397 00398 iRet = CompareStringW(GetThreadLocale(), 0, lpszStr, iLen, lpszComp, iLen); 00399 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0; 00400 } 00401 00402 /************************************************************************* 00403 * StrCmpNIA [SHLWAPI.@] 00404 * 00405 * Compare two strings, up to a maximum length, ignoring case. 00406 * 00407 * PARAMS 00408 * lpszStr [I] First string to compare 00409 * lpszComp [I] Second string to compare 00410 * iLen [I] Maximum number of chars to compare. 00411 * 00412 * RETURNS 00413 * An integer less than, equal to or greater than 0, indicating that 00414 * lpszStr is less than, the same, or greater than lpszComp. 00415 */ 00416 int WINAPI StrCmpNIA(LPCSTR lpszStr, LPCSTR lpszComp, int iLen) 00417 { 00418 INT iRet; 00419 00420 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen); 00421 00422 iRet = CompareStringA(GetThreadLocale(), NORM_IGNORECASE, lpszStr, iLen, lpszComp, iLen); 00423 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0; 00424 } 00425 00426 /************************************************************************* 00427 * StrCmpNIW [SHLWAPI.@] 00428 * 00429 * See StrCmpNIA. 00430 */ 00431 INT WINAPI StrCmpNIW(LPCWSTR lpszStr, LPCWSTR lpszComp, int iLen) 00432 { 00433 INT iRet; 00434 00435 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen); 00436 00437 iRet = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, lpszStr, iLen, lpszComp, iLen); 00438 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0; 00439 } 00440 00441 /************************************************************************* 00442 * StrCmpW [SHLWAPI.@] 00443 * 00444 * Compare two strings. 00445 * 00446 * PARAMS 00447 * lpszStr [I] First string to compare 00448 * lpszComp [I] Second string to compare 00449 * 00450 * RETURNS 00451 * An integer less than, equal to or greater than 0, indicating that 00452 * lpszStr is less than, the same, or greater than lpszComp. 00453 */ 00454 int WINAPI StrCmpW(LPCWSTR lpszStr, LPCWSTR lpszComp) 00455 { 00456 INT iRet; 00457 00458 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszComp)); 00459 00460 iRet = CompareStringW(GetThreadLocale(), 0, lpszStr, -1, lpszComp, -1); 00461 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0; 00462 } 00463 00464 /************************************************************************* 00465 * StrCatW [SHLWAPI.@] 00466 * 00467 * Concatenate two strings. 00468 * 00469 * PARAMS 00470 * lpszStr [O] Initial string 00471 * lpszSrc [I] String to concatenate 00472 * 00473 * RETURNS 00474 * lpszStr. 00475 */ 00476 LPWSTR WINAPI StrCatW(LPWSTR lpszStr, LPCWSTR lpszSrc) 00477 { 00478 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSrc)); 00479 00480 strcatW(lpszStr, lpszSrc); 00481 return lpszStr; 00482 } 00483 00484 /************************************************************************* 00485 * StrCpyW [SHLWAPI.@] 00486 * 00487 * Copy a string to another string. 00488 * 00489 * PARAMS 00490 * lpszStr [O] Destination string 00491 * lpszSrc [I] Source string 00492 * 00493 * RETURNS 00494 * lpszStr. 00495 */ 00496 LPWSTR WINAPI StrCpyW(LPWSTR lpszStr, LPCWSTR lpszSrc) 00497 { 00498 TRACE("(%p,%s)\n", lpszStr, debugstr_w(lpszSrc)); 00499 00500 strcpyW(lpszStr, lpszSrc); 00501 return lpszStr; 00502 } 00503 00504 /************************************************************************* 00505 * StrCpyNW [SHLWAPI.@] 00506 * 00507 * Copy a string to another string, up to a maximum number of characters. 00508 * 00509 * PARAMS 00510 * dst [O] Destination string 00511 * src [I] Source string 00512 * count [I] Maximum number of chars to copy 00513 * 00514 * RETURNS 00515 * dst. 00516 */ 00517 LPWSTR WINAPI StrCpyNW(LPWSTR dst, LPCWSTR src, int count) 00518 { 00519 LPWSTR d = dst; 00520 LPCWSTR s = src; 00521 00522 TRACE("(%p,%s,%i)\n", dst, debugstr_w(src), count); 00523 00524 if (s) 00525 { 00526 while ((count > 1) && *s) 00527 { 00528 count--; 00529 *d++ = *s++; 00530 } 00531 } 00532 if (count) *d = 0; 00533 00534 return dst; 00535 } 00536 00537 /************************************************************************* 00538 * SHLWAPI_StrStrHelperA 00539 * 00540 * Internal implementation of StrStrA/StrStrIA 00541 */ 00542 static LPSTR SHLWAPI_StrStrHelperA(LPCSTR lpszStr, LPCSTR lpszSearch, 00543 INT (WINAPI *pStrCmpFn)(LPCSTR,LPCSTR,INT)) 00544 { 00545 size_t iLen; 00546 00547 if (!lpszStr || !lpszSearch || !*lpszSearch) 00548 return NULL; 00549 00550 iLen = strlen(lpszSearch); 00551 00552 while (*lpszStr) 00553 { 00554 if (!pStrCmpFn(lpszStr, lpszSearch, iLen)) 00555 return (LPSTR)lpszStr; 00556 lpszStr = CharNextA(lpszStr); 00557 } 00558 return NULL; 00559 } 00560 00561 /************************************************************************* 00562 * StrStrA [SHLWAPI.@] 00563 * 00564 * Find a substring within a string. 00565 * 00566 * PARAMS 00567 * lpszStr [I] String to search in 00568 * lpszSearch [I] String to look for 00569 * 00570 * RETURNS 00571 * The start of lpszSearch within lpszStr, or NULL if not found. 00572 */ 00573 LPSTR WINAPI StrStrA(LPCSTR lpszStr, LPCSTR lpszSearch) 00574 { 00575 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch)); 00576 00577 return SHLWAPI_StrStrHelperA(lpszStr, lpszSearch, StrCmpNA); 00578 } 00579 00580 /************************************************************************* 00581 * StrStrW [SHLWAPI.@] 00582 * 00583 * See StrStrA. 00584 */ 00585 LPWSTR WINAPI StrStrW(LPCWSTR lpszStr, LPCWSTR lpszSearch) 00586 { 00587 TRACE("(%s, %s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch)); 00588 00589 if (!lpszStr || !lpszSearch || !*lpszSearch) return NULL; 00590 return strstrW( lpszStr, lpszSearch ); 00591 } 00592 00593 /************************************************************************* 00594 * StrRStrIA [SHLWAPI.@] 00595 * 00596 * Find the last occurrence of a substring within a string. 00597 * 00598 * PARAMS 00599 * lpszStr [I] String to search in 00600 * lpszEnd [I] End of lpszStr 00601 * lpszSearch [I] String to look for 00602 * 00603 * RETURNS 00604 * The last occurrence lpszSearch within lpszStr, or NULL if not found. 00605 */ 00606 LPSTR WINAPI StrRStrIA(LPCSTR lpszStr, LPCSTR lpszEnd, LPCSTR lpszSearch) 00607 { 00608 WORD ch1, ch2; 00609 INT iLen; 00610 00611 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch)); 00612 00613 if (!lpszStr || !lpszSearch || !*lpszSearch) 00614 return NULL; 00615 00616 if (!lpszEnd) 00617 lpszEnd = lpszStr + lstrlenA(lpszStr); 00618 if (lpszEnd == lpszStr) 00619 return NULL; 00620 00621 if (IsDBCSLeadByte(*lpszSearch)) 00622 ch1 = *lpszSearch << 8 | (UCHAR)lpszSearch[1]; 00623 else 00624 ch1 = *lpszSearch; 00625 iLen = lstrlenA(lpszSearch); 00626 00627 do 00628 { 00629 lpszEnd = CharPrevA(lpszStr, lpszEnd); 00630 ch2 = IsDBCSLeadByte(*lpszEnd)? *lpszEnd << 8 | (UCHAR)lpszEnd[1] : *lpszEnd; 00631 if (!ChrCmpIA(ch1, ch2)) 00632 { 00633 if (!StrCmpNIA(lpszEnd, lpszSearch, iLen)) 00634 return (LPSTR)lpszEnd; 00635 } 00636 } while (lpszEnd > lpszStr); 00637 return NULL; 00638 } 00639 00640 /************************************************************************* 00641 * StrRStrIW [SHLWAPI.@] 00642 * 00643 * See StrRStrIA. 00644 */ 00645 LPWSTR WINAPI StrRStrIW(LPCWSTR lpszStr, LPCWSTR lpszEnd, LPCWSTR lpszSearch) 00646 { 00647 INT iLen; 00648 00649 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch)); 00650 00651 if (!lpszStr || !lpszSearch || !*lpszSearch) 00652 return NULL; 00653 00654 if (!lpszEnd) 00655 lpszEnd = lpszStr + strlenW(lpszStr); 00656 00657 iLen = strlenW(lpszSearch); 00658 00659 while (lpszEnd > lpszStr) 00660 { 00661 lpszEnd--; 00662 if (!StrCmpNIW(lpszEnd, lpszSearch, iLen)) 00663 return (LPWSTR)lpszEnd; 00664 } 00665 return NULL; 00666 } 00667 00668 /************************************************************************* 00669 * StrStrIA [SHLWAPI.@] 00670 * 00671 * Find a substring within a string, ignoring case. 00672 * 00673 * PARAMS 00674 * lpszStr [I] String to search in 00675 * lpszSearch [I] String to look for 00676 * 00677 * RETURNS 00678 * The start of lpszSearch within lpszStr, or NULL if not found. 00679 */ 00680 LPSTR WINAPI StrStrIA(LPCSTR lpszStr, LPCSTR lpszSearch) 00681 { 00682 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch)); 00683 00684 return SHLWAPI_StrStrHelperA(lpszStr, lpszSearch, StrCmpNIA); 00685 } 00686 00687 /************************************************************************* 00688 * StrStrIW [SHLWAPI.@] 00689 * 00690 * See StrStrIA. 00691 */ 00692 LPWSTR WINAPI StrStrIW(LPCWSTR lpszStr, LPCWSTR lpszSearch) 00693 { 00694 int iLen; 00695 00696 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch)); 00697 00698 if (!lpszStr || !lpszSearch || !*lpszSearch) 00699 return NULL; 00700 00701 iLen = strlenW(lpszSearch); 00702 00703 while (*lpszStr) 00704 { 00705 if (!StrCmpNIW(lpszStr, lpszSearch, iLen)) 00706 return (LPWSTR)lpszStr; 00707 lpszStr++; 00708 } 00709 return NULL; 00710 } 00711 00712 /************************************************************************* 00713 * StrStrNW [SHLWAPI.@] 00714 * 00715 * Find a substring within a string up to a given number of initial characters. 00716 * 00717 * PARAMS 00718 * lpFirst [I] String to search in 00719 * lpSrch [I] String to look for 00720 * cchMax [I] Maximum number of initial search characters 00721 * 00722 * RETURNS 00723 * The start of lpFirst within lpSrch, or NULL if not found. 00724 */ 00725 LPWSTR WINAPI StrStrNW(LPCWSTR lpFirst, LPCWSTR lpSrch, UINT cchMax) 00726 { 00727 UINT i; 00728 int len; 00729 00730 TRACE("(%s, %s, %u)\n", debugstr_w(lpFirst), debugstr_w(lpSrch), cchMax); 00731 00732 if (!lpFirst || !lpSrch || !*lpSrch || !cchMax) 00733 return NULL; 00734 00735 len = strlenW(lpSrch); 00736 00737 for (i = cchMax; *lpFirst && (i > 0); i--, lpFirst++) 00738 { 00739 if (!strncmpW(lpFirst, lpSrch, len)) 00740 return (LPWSTR)lpFirst; 00741 } 00742 00743 return NULL; 00744 } 00745 00746 /************************************************************************* 00747 * StrStrNIW [SHLWAPI.@] 00748 * 00749 * Find a substring within a string up to a given number of initial characters, 00750 * ignoring case. 00751 * 00752 * PARAMS 00753 * lpFirst [I] String to search in 00754 * lpSrch [I] String to look for 00755 * cchMax [I] Maximum number of initial search characters 00756 * 00757 * RETURNS 00758 * The start of lpFirst within lpSrch, or NULL if not found. 00759 */ 00760 LPWSTR WINAPI StrStrNIW(LPCWSTR lpFirst, LPCWSTR lpSrch, UINT cchMax) 00761 { 00762 UINT i; 00763 int len; 00764 00765 TRACE("(%s, %s, %u)\n", debugstr_w(lpFirst), debugstr_w(lpSrch), cchMax); 00766 00767 if (!lpFirst || !lpSrch || !*lpSrch || !cchMax) 00768 return NULL; 00769 00770 len = strlenW(lpSrch); 00771 00772 for (i = cchMax; *lpFirst && (i > 0); i--, lpFirst++) 00773 { 00774 if (!strncmpiW(lpFirst, lpSrch, len)) 00775 return (LPWSTR)lpFirst; 00776 } 00777 00778 return NULL; 00779 } 00780 00781 /************************************************************************* 00782 * StrToIntA [SHLWAPI.@] 00783 * 00784 * Read a signed integer from a string. 00785 * 00786 * PARAMS 00787 * lpszStr [I] String to read integer from 00788 * 00789 * RETURNS 00790 * The signed integer value represented by the string, or 0 if no integer is 00791 * present. 00792 * 00793 * NOTES 00794 * No leading space is allowed before the number, although a leading '-' is. 00795 */ 00796 int WINAPI StrToIntA(LPCSTR lpszStr) 00797 { 00798 int iRet = 0; 00799 00800 TRACE("(%s)\n", debugstr_a(lpszStr)); 00801 00802 if (!lpszStr) 00803 { 00804 WARN("Invalid lpszStr would crash under Win32!\n"); 00805 return 0; 00806 } 00807 00808 if (*lpszStr == '-' || isdigit(*lpszStr)) 00809 StrToIntExA(lpszStr, 0, &iRet); 00810 return iRet; 00811 } 00812 00813 /************************************************************************* 00814 * StrToIntW [SHLWAPI.@] 00815 * 00816 * See StrToIntA. 00817 */ 00818 int WINAPI StrToIntW(LPCWSTR lpszStr) 00819 { 00820 int iRet = 0; 00821 00822 TRACE("(%s)\n", debugstr_w(lpszStr)); 00823 00824 if (!lpszStr) 00825 { 00826 WARN("Invalid lpszStr would crash under Win32!\n"); 00827 return 0; 00828 } 00829 00830 if (*lpszStr == '-' || isdigitW(*lpszStr)) 00831 StrToIntExW(lpszStr, 0, &iRet); 00832 return iRet; 00833 } 00834 00835 /************************************************************************* 00836 * StrToIntExA [SHLWAPI.@] 00837 * 00838 * Read an integer from a string. 00839 * 00840 * PARAMS 00841 * lpszStr [I] String to read integer from 00842 * dwFlags [I] Flags controlling the conversion 00843 * lpiRet [O] Destination for read integer. 00844 * 00845 * RETURNS 00846 * Success: TRUE. lpiRet contains the integer value represented by the string. 00847 * Failure: FALSE, if the string is invalid, or no number is present. 00848 * 00849 * NOTES 00850 * Leading whitespace, '-' and '+' are allowed before the number. If 00851 * dwFlags includes STIF_SUPPORT_HEX, hexadecimal numbers are allowed, if 00852 * preceded by '0x'. If this flag is not set, or there is no '0x' prefix, 00853 * the string is treated as a decimal string. A leading '-' is ignored for 00854 * hexadecimal numbers. 00855 */ 00856 BOOL WINAPI StrToIntExA(LPCSTR lpszStr, DWORD dwFlags, LPINT lpiRet) 00857 { 00858 BOOL bNegative = FALSE; 00859 int iRet = 0; 00860 00861 TRACE("(%s,%08X,%p)\n", debugstr_a(lpszStr), dwFlags, lpiRet); 00862 00863 if (!lpszStr || !lpiRet) 00864 { 00865 WARN("Invalid parameter would crash under Win32!\n"); 00866 return FALSE; 00867 } 00868 if (dwFlags > STIF_SUPPORT_HEX) 00869 { 00870 WARN("Unknown flags (%08lX)!\n", dwFlags & ~STIF_SUPPORT_HEX); 00871 } 00872 00873 /* Skip leading space, '+', '-' */ 00874 while (isspace(*lpszStr)) 00875 lpszStr = CharNextA(lpszStr); 00876 00877 if (*lpszStr == '-') 00878 { 00879 bNegative = TRUE; 00880 lpszStr++; 00881 } 00882 else if (*lpszStr == '+') 00883 lpszStr++; 00884 00885 if (dwFlags & STIF_SUPPORT_HEX && 00886 *lpszStr == '0' && tolower(lpszStr[1]) == 'x') 00887 { 00888 /* Read hex number */ 00889 lpszStr += 2; 00890 00891 if (!isxdigit(*lpszStr)) 00892 return FALSE; 00893 00894 while (isxdigit(*lpszStr)) 00895 { 00896 iRet = iRet * 16; 00897 if (isdigit(*lpszStr)) 00898 iRet += (*lpszStr - '0'); 00899 else 00900 iRet += 10 + (tolower(*lpszStr) - 'a'); 00901 lpszStr++; 00902 } 00903 *lpiRet = iRet; 00904 return TRUE; 00905 } 00906 00907 /* Read decimal number */ 00908 if (!isdigit(*lpszStr)) 00909 return FALSE; 00910 00911 while (isdigit(*lpszStr)) 00912 { 00913 iRet = iRet * 10; 00914 iRet += (*lpszStr - '0'); 00915 lpszStr++; 00916 } 00917 *lpiRet = bNegative ? -iRet : iRet; 00918 return TRUE; 00919 } 00920 00921 /************************************************************************* 00922 * StrToIntExW [SHLWAPI.@] 00923 * 00924 * See StrToIntExA. 00925 */ 00926 BOOL WINAPI StrToIntExW(LPCWSTR lpszStr, DWORD dwFlags, LPINT lpiRet) 00927 { 00928 BOOL bNegative = FALSE; 00929 int iRet = 0; 00930 00931 TRACE("(%s,%08X,%p)\n", debugstr_w(lpszStr), dwFlags, lpiRet); 00932 00933 if (!lpszStr || !lpiRet) 00934 { 00935 WARN("Invalid parameter would crash under Win32!\n"); 00936 return FALSE; 00937 } 00938 if (dwFlags > STIF_SUPPORT_HEX) 00939 { 00940 WARN("Unknown flags (%08lX)!\n", dwFlags & ~STIF_SUPPORT_HEX); 00941 } 00942 00943 /* Skip leading space, '+', '-' */ 00944 while (isspaceW(*lpszStr)) lpszStr++; 00945 00946 if (*lpszStr == '-') 00947 { 00948 bNegative = TRUE; 00949 lpszStr++; 00950 } 00951 else if (*lpszStr == '+') 00952 lpszStr++; 00953 00954 if (dwFlags & STIF_SUPPORT_HEX && 00955 *lpszStr == '0' && tolowerW(lpszStr[1]) == 'x') 00956 { 00957 /* Read hex number */ 00958 lpszStr += 2; 00959 00960 if (!isxdigitW(*lpszStr)) 00961 return FALSE; 00962 00963 while (isxdigitW(*lpszStr)) 00964 { 00965 iRet = iRet * 16; 00966 if (isdigitW(*lpszStr)) 00967 iRet += (*lpszStr - '0'); 00968 else 00969 iRet += 10 + (tolowerW(*lpszStr) - 'a'); 00970 lpszStr++; 00971 } 00972 *lpiRet = iRet; 00973 return TRUE; 00974 } 00975 00976 /* Read decimal number */ 00977 if (!isdigitW(*lpszStr)) 00978 return FALSE; 00979 00980 while (isdigitW(*lpszStr)) 00981 { 00982 iRet = iRet * 10; 00983 iRet += (*lpszStr - '0'); 00984 lpszStr++; 00985 } 00986 *lpiRet = bNegative ? -iRet : iRet; 00987 return TRUE; 00988 } 00989 00990 /************************************************************************* 00991 * StrDupA [SHLWAPI.@] 00992 * 00993 * Duplicate a string. 00994 * 00995 * PARAMS 00996 * lpszStr [I] String to duplicate. 00997 * 00998 * RETURNS 00999 * Success: A pointer to a new string containing the contents of lpszStr 01000 * Failure: NULL, if memory cannot be allocated 01001 * 01002 * NOTES 01003 * The string memory is allocated with LocalAlloc(), and so should be released 01004 * by calling LocalFree(). 01005 */ 01006 LPSTR WINAPI StrDupA(LPCSTR lpszStr) 01007 { 01008 int iLen; 01009 LPSTR lpszRet; 01010 01011 TRACE("(%s)\n",debugstr_a(lpszStr)); 01012 01013 iLen = lpszStr ? strlen(lpszStr) + 1 : 1; 01014 lpszRet = LocalAlloc(LMEM_FIXED, iLen); 01015 01016 if (lpszRet) 01017 { 01018 if (lpszStr) 01019 memcpy(lpszRet, lpszStr, iLen); 01020 else 01021 *lpszRet = '\0'; 01022 } 01023 return lpszRet; 01024 } 01025 01026 /************************************************************************* 01027 * StrDupW [SHLWAPI.@] 01028 * 01029 * See StrDupA. 01030 */ 01031 LPWSTR WINAPI StrDupW(LPCWSTR lpszStr) 01032 { 01033 int iLen; 01034 LPWSTR lpszRet; 01035 01036 TRACE("(%s)\n",debugstr_w(lpszStr)); 01037 01038 iLen = (lpszStr ? strlenW(lpszStr) + 1 : 1) * sizeof(WCHAR); 01039 lpszRet = LocalAlloc(LMEM_FIXED, iLen); 01040 01041 if (lpszRet) 01042 { 01043 if (lpszStr) 01044 memcpy(lpszRet, lpszStr, iLen); 01045 else 01046 *lpszRet = '\0'; 01047 } 01048 return lpszRet; 01049 } 01050 01051 /************************************************************************* 01052 * SHLWAPI_StrSpnHelperA 01053 * 01054 * Internal implementation of StrSpnA/StrCSpnA/StrCSpnIA 01055 */ 01056 static int SHLWAPI_StrSpnHelperA(LPCSTR lpszStr, LPCSTR lpszMatch, 01057 LPSTR (WINAPI *pStrChrFn)(LPCSTR,WORD), 01058 BOOL bInvert) 01059 { 01060 LPCSTR lpszRead = lpszStr; 01061 if (lpszStr && *lpszStr && lpszMatch) 01062 { 01063 while (*lpszRead) 01064 { 01065 LPCSTR lpszTest = pStrChrFn(lpszMatch, *lpszRead); 01066 01067 if (!bInvert && !lpszTest) 01068 break; 01069 if (bInvert && lpszTest) 01070 break; 01071 lpszRead = CharNextA(lpszRead); 01072 }; 01073 } 01074 return lpszRead - lpszStr; 01075 } 01076 01077 /************************************************************************* 01078 * StrSpnA [SHLWAPI.@] 01079 * 01080 * Find the length of the start of a string that contains only certain 01081 * characters. 01082 * 01083 * PARAMS 01084 * lpszStr [I] String to search 01085 * lpszMatch [I] Characters that can be in the substring 01086 * 01087 * RETURNS 01088 * The length of the part of lpszStr containing only chars from lpszMatch, 01089 * or 0 if any parameter is invalid. 01090 */ 01091 int WINAPI StrSpnA(LPCSTR lpszStr, LPCSTR lpszMatch) 01092 { 01093 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch)); 01094 01095 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, FALSE); 01096 } 01097 01098 /************************************************************************* 01099 * StrSpnW [SHLWAPI.@] 01100 * 01101 * See StrSpnA. 01102 */ 01103 int WINAPI StrSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch) 01104 { 01105 if (!lpszStr || !lpszMatch) return 0; 01106 return strspnW( lpszStr, lpszMatch ); 01107 } 01108 01109 /************************************************************************* 01110 * StrCSpnA [SHLWAPI.@] 01111 * 01112 * Find the length of the start of a string that does not contain certain 01113 * characters. 01114 * 01115 * PARAMS 01116 * lpszStr [I] String to search 01117 * lpszMatch [I] Characters that cannot be in the substring 01118 * 01119 * RETURNS 01120 * The length of the part of lpszStr containing only chars not in lpszMatch, 01121 * or 0 if any parameter is invalid. 01122 */ 01123 int WINAPI StrCSpnA(LPCSTR lpszStr, LPCSTR lpszMatch) 01124 { 01125 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch)); 01126 01127 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, TRUE); 01128 } 01129 01130 /************************************************************************* 01131 * StrCSpnW [SHLWAPI.@] 01132 * 01133 * See StrCSpnA. 01134 */ 01135 int WINAPI StrCSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch) 01136 { 01137 if (!lpszStr || !lpszMatch) return 0; 01138 return strcspnW( lpszStr, lpszMatch ); 01139 } 01140 01141 /************************************************************************* 01142 * StrCSpnIA [SHLWAPI.@] 01143 * 01144 * Find the length of the start of a string that does not contain certain 01145 * characters, ignoring case. 01146 * 01147 * PARAMS 01148 * lpszStr [I] String to search 01149 * lpszMatch [I] Characters that cannot be in the substring 01150 * 01151 * RETURNS 01152 * The length of the part of lpszStr containing only chars not in lpszMatch, 01153 * or 0 if any parameter is invalid. 01154 */ 01155 int WINAPI StrCSpnIA(LPCSTR lpszStr, LPCSTR lpszMatch) 01156 { 01157 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch)); 01158 01159 return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrIA, TRUE); 01160 } 01161 01162 /************************************************************************* 01163 * StrCSpnIW [SHLWAPI.@] 01164 * 01165 * See StrCSpnIA. 01166 */ 01167 int WINAPI StrCSpnIW(LPCWSTR lpszStr, LPCWSTR lpszMatch) 01168 { 01169 LPCWSTR lpszRead = lpszStr; 01170 01171 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch)); 01172 01173 if (lpszStr && *lpszStr && lpszMatch) 01174 { 01175 while (*lpszRead) 01176 { 01177 if (StrChrIW(lpszMatch, *lpszRead)) break; 01178 lpszRead++; 01179 } 01180 } 01181 return lpszRead - lpszStr; 01182 } 01183 01184 /************************************************************************* 01185 * StrPBrkA [SHLWAPI.@] 01186 * 01187 * Search a string for any of a group of characters. 01188 * 01189 * PARAMS 01190 * lpszStr [I] String to search 01191 * lpszMatch [I] Characters to match 01192 * 01193 * RETURNS 01194 * A pointer to the first matching character in lpszStr, or NULL if no 01195 * match was found. 01196 */ 01197 LPSTR WINAPI StrPBrkA(LPCSTR lpszStr, LPCSTR lpszMatch) 01198 { 01199 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch)); 01200 01201 if (lpszStr && lpszMatch && *lpszMatch) 01202 { 01203 while (*lpszStr) 01204 { 01205 if (StrChrA(lpszMatch, *lpszStr)) 01206 return (LPSTR)lpszStr; 01207 lpszStr = CharNextA(lpszStr); 01208 } 01209 } 01210 return NULL; 01211 } 01212 01213 /************************************************************************* 01214 * StrPBrkW [SHLWAPI.@] 01215 * 01216 * See StrPBrkA. 01217 */ 01218 LPWSTR WINAPI StrPBrkW(LPCWSTR lpszStr, LPCWSTR lpszMatch) 01219 { 01220 if (!lpszStr || !lpszMatch) return NULL; 01221 return strpbrkW( lpszStr, lpszMatch ); 01222 } 01223 01224 /************************************************************************* 01225 * SHLWAPI_StrRChrHelperA 01226 * 01227 * Internal implementation of StrRChrA/StrRChrIA. 01228 */ 01229 static LPSTR SHLWAPI_StrRChrHelperA(LPCSTR lpszStr, 01230 LPCSTR lpszEnd, WORD ch, 01231 BOOL (WINAPI *pChrCmpFn)(WORD,WORD)) 01232 { 01233 LPCSTR lpszRet = NULL; 01234 01235 if (lpszStr) 01236 { 01237 WORD ch2; 01238 01239 if (!lpszEnd) 01240 lpszEnd = lpszStr + lstrlenA(lpszStr); 01241 01242 while (*lpszStr && lpszStr <= lpszEnd) 01243 { 01244 ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr; 01245 01246 if (!pChrCmpFn(ch, ch2)) 01247 lpszRet = lpszStr; 01248 lpszStr = CharNextA(lpszStr); 01249 } 01250 } 01251 return (LPSTR)lpszRet; 01252 } 01253 01254 /************************************************************************** 01255 * StrRChrA [SHLWAPI.@] 01256 * 01257 * Find the last occurrence of a character in string. 01258 * 01259 * PARAMS 01260 * lpszStr [I] String to search in 01261 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr 01262 * ch [I] Character to search for. 01263 * 01264 * RETURNS 01265 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd, 01266 * or NULL if not found. 01267 * Failure: NULL, if any arguments are invalid. 01268 */ 01269 LPSTR WINAPI StrRChrA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch) 01270 { 01271 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch); 01272 01273 return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, SHLWAPI_ChrCmpA); 01274 } 01275 01276 /************************************************************************** 01277 * StrRChrW [SHLWAPI.@] 01278 * 01279 * See StrRChrA. 01280 */ 01281 LPWSTR WINAPI StrRChrW(LPCWSTR str, LPCWSTR end, WORD ch) 01282 { 01283 WCHAR *ret = NULL; 01284 01285 if (!str) return NULL; 01286 if (!end) end = str + strlenW(str); 01287 while (str < end) 01288 { 01289 if (*str == ch) ret = (WCHAR *)str; 01290 str++; 01291 } 01292 return ret; 01293 } 01294 01295 /************************************************************************** 01296 * StrRChrIA [SHLWAPI.@] 01297 * 01298 * Find the last occurrence of a character in string, ignoring case. 01299 * 01300 * PARAMS 01301 * lpszStr [I] String to search in 01302 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr 01303 * ch [I] Character to search for. 01304 * 01305 * RETURNS 01306 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd, 01307 * or NULL if not found. 01308 * Failure: NULL, if any arguments are invalid. 01309 */ 01310 LPSTR WINAPI StrRChrIA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch) 01311 { 01312 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch); 01313 01314 return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, ChrCmpIA); 01315 } 01316 01317 /************************************************************************** 01318 * StrRChrIW [SHLWAPI.@] 01319 * 01320 * See StrRChrIA. 01321 */ 01322 LPWSTR WINAPI StrRChrIW(LPCWSTR str, LPCWSTR end, WORD ch) 01323 { 01324 WCHAR *ret = NULL; 01325 01326 if (!str) return NULL; 01327 if (!end) end = str + strlenW(str); 01328 while (str < end) 01329 { 01330 if (!ChrCmpIW(*str, ch)) ret = (WCHAR *)str; 01331 str++; 01332 } 01333 return ret; 01334 } 01335 01336 /************************************************************************* 01337 * StrCatBuffA [SHLWAPI.@] 01338 * 01339 * Concatenate two strings together. 01340 * 01341 * PARAMS 01342 * lpszStr [O] String to concatenate to 01343 * lpszCat [I] String to add to lpszCat 01344 * cchMax [I] Maximum number of characters for the whole string 01345 * 01346 * RETURNS 01347 * lpszStr. 01348 * 01349 * NOTES 01350 * cchMax determines the number of characters in the final length of the 01351 * string, not the number appended to lpszStr from lpszCat. 01352 */ 01353 LPSTR WINAPI StrCatBuffA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax) 01354 { 01355 INT iLen; 01356 01357 TRACE("(%p,%s,%d)\n", lpszStr, debugstr_a(lpszCat), cchMax); 01358 01359 if (!lpszStr) 01360 { 01361 WARN("Invalid lpszStr would crash under Win32!\n"); 01362 return NULL; 01363 } 01364 01365 iLen = strlen(lpszStr); 01366 cchMax -= iLen; 01367 01368 if (cchMax > 0) 01369 StrCpyNA(lpszStr + iLen, lpszCat, cchMax); 01370 return lpszStr; 01371 } 01372 01373 /************************************************************************* 01374 * StrCatBuffW [SHLWAPI.@] 01375 * 01376 * See StrCatBuffA. 01377 */ 01378 LPWSTR WINAPI StrCatBuffW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax) 01379 { 01380 INT iLen; 01381 01382 TRACE("(%p,%s,%d)\n", lpszStr, debugstr_w(lpszCat), cchMax); 01383 01384 if (!lpszStr) 01385 { 01386 WARN("Invalid lpszStr would crash under Win32!\n"); 01387 return NULL; 01388 } 01389 01390 iLen = strlenW(lpszStr); 01391 cchMax -= iLen; 01392 01393 if (cchMax > 0) 01394 StrCpyNW(lpszStr + iLen, lpszCat, cchMax); 01395 return lpszStr; 01396 } 01397 01398 /************************************************************************* 01399 * StrRetToBufA [SHLWAPI.@] 01400 * 01401 * Convert a STRRET to a normal string. 01402 * 01403 * PARAMS 01404 * lpStrRet [O] STRRET to convert 01405 * pIdl [I] ITEMIDLIST for lpStrRet->uType == STRRET_OFFSET 01406 * lpszDest [O] Destination for normal string 01407 * dwLen [I] Length of lpszDest 01408 * 01409 * RETURNS 01410 * Success: S_OK. lpszDest contains up to dwLen characters of the string. 01411 * If lpStrRet is of type STRRET_WSTR, its memory is freed with 01412 * CoTaskMemFree() and its type set to STRRET_CSTRA. 01413 * Failure: E_FAIL, if any parameters are invalid. 01414 */ 01415 HRESULT WINAPI StrRetToBufA (LPSTRRET src, const ITEMIDLIST *pidl, LPSTR dest, UINT len) 01416 { 01417 /* NOTE: 01418 * This routine is identical to that in dlls/shell32/shellstring.c. 01419 * It was duplicated because not every version of Shlwapi.dll exports 01420 * StrRetToBufA. If you change one routine, change them both. 01421 */ 01422 TRACE("dest=%p len=0x%x strret=%p pidl=%p stub\n",dest,len,src,pidl); 01423 01424 if (!src) 01425 { 01426 WARN("Invalid lpStrRet would crash under Win32!\n"); 01427 if (dest) 01428 *dest = '\0'; 01429 return E_FAIL; 01430 } 01431 01432 if (!dest || !len) 01433 return E_FAIL; 01434 01435 *dest = '\0'; 01436 01437 switch (src->uType) 01438 { 01439 case STRRET_WSTR: 01440 WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, dest, len, NULL, NULL); 01441 CoTaskMemFree(src->u.pOleStr); 01442 break; 01443 01444 case STRRET_CSTR: 01445 lstrcpynA(dest, src->u.cStr, len); 01446 break; 01447 01448 case STRRET_OFFSET: 01449 lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len); 01450 break; 01451 01452 default: 01453 FIXME("unknown type!\n"); 01454 return FALSE; 01455 } 01456 return S_OK; 01457 } 01458 01459 /************************************************************************* 01460 * StrRetToBufW [SHLWAPI.@] 01461 * 01462 * See StrRetToBufA. 01463 */ 01464 HRESULT WINAPI StrRetToBufW (LPSTRRET src, const ITEMIDLIST *pidl, LPWSTR dest, UINT len) 01465 { 01466 TRACE("dest=%p len=0x%x strret=%p pidl=%p stub\n",dest,len,src,pidl); 01467 01468 if (!src) 01469 { 01470 WARN("Invalid lpStrRet would crash under Win32!\n"); 01471 if (dest) 01472 *dest = '\0'; 01473 return E_FAIL; 01474 } 01475 01476 if (!dest || !len) 01477 return E_FAIL; 01478 01479 *dest = '\0'; 01480 01481 switch (src->uType) 01482 { 01483 case STRRET_WSTR: 01484 lstrcpynW(dest, src->u.pOleStr, len); 01485 CoTaskMemFree(src->u.pOleStr); 01486 break; 01487 01488 case STRRET_CSTR: 01489 if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len )) 01490 dest[len-1] = 0; 01491 break; 01492 01493 case STRRET_OFFSET: 01494 if (pidl) 01495 { 01496 if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1, 01497 dest, len )) 01498 dest[len-1] = 0; 01499 } 01500 break; 01501 01502 default: 01503 FIXME("unknown type!\n"); 01504 return FALSE; 01505 } 01506 return S_OK; 01507 } 01508 01509 /************************************************************************* 01510 * StrRetToStrA [SHLWAPI.@] 01511 * 01512 * Converts a STRRET to a normal string. 01513 * 01514 * PARAMS 01515 * lpStrRet [O] STRRET to convert 01516 * pidl [I] ITEMIDLIST for lpStrRet->uType == STRRET_OFFSET 01517 * ppszName [O] Destination for converted string 01518 * 01519 * RETURNS 01520 * Success: S_OK. ppszName contains the new string, allocated with CoTaskMemAlloc(). 01521 * Failure: E_FAIL, if any parameters are invalid. 01522 */ 01523 HRESULT WINAPI StrRetToStrA(LPSTRRET lpStrRet, const ITEMIDLIST *pidl, LPSTR *ppszName) 01524 { 01525 HRESULT hRet = E_FAIL; 01526 01527 switch (lpStrRet->uType) 01528 { 01529 case STRRET_WSTR: 01530 hRet = _SHStrDupAW(lpStrRet->u.pOleStr, ppszName); 01531 CoTaskMemFree(lpStrRet->u.pOleStr); 01532 break; 01533 01534 case STRRET_CSTR: 01535 hRet = _SHStrDupAA(lpStrRet->u.cStr, ppszName); 01536 break; 01537 01538 case STRRET_OFFSET: 01539 hRet = _SHStrDupAA(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, ppszName); 01540 break; 01541 01542 default: 01543 *ppszName = NULL; 01544 } 01545 01546 return hRet; 01547 } 01548 01549 /************************************************************************* 01550 * StrRetToStrW [SHLWAPI.@] 01551 * 01552 * See StrRetToStrA. 01553 */ 01554 HRESULT WINAPI StrRetToStrW(LPSTRRET lpStrRet, const ITEMIDLIST *pidl, LPWSTR *ppszName) 01555 { 01556 HRESULT hRet = E_FAIL; 01557 01558 switch (lpStrRet->uType) 01559 { 01560 case STRRET_WSTR: 01561 hRet = SHStrDupW(lpStrRet->u.pOleStr, ppszName); 01562 CoTaskMemFree(lpStrRet->u.pOleStr); 01563 break; 01564 01565 case STRRET_CSTR: 01566 hRet = SHStrDupA(lpStrRet->u.cStr, ppszName); 01567 break; 01568 01569 case STRRET_OFFSET: 01570 hRet = SHStrDupA(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, ppszName); 01571 break; 01572 01573 default: 01574 *ppszName = NULL; 01575 } 01576 01577 return hRet; 01578 } 01579 01580 /* Create an ASCII string copy using SysAllocString() */ 01581 static HRESULT _SHStrDupAToBSTR(LPCSTR src, BSTR *pBstrOut) 01582 { 01583 *pBstrOut = NULL; 01584 01585 if (src) 01586 { 01587 INT len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0); 01588 WCHAR* szTemp = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 01589 01590 if (szTemp) 01591 { 01592 MultiByteToWideChar(CP_ACP, 0, src, -1, szTemp, len); 01593 *pBstrOut = SysAllocString(szTemp); 01594 HeapFree(GetProcessHeap(), 0, szTemp); 01595 01596 if (*pBstrOut) 01597 return S_OK; 01598 } 01599 } 01600 return E_OUTOFMEMORY; 01601 } 01602 01603 /************************************************************************* 01604 * StrRetToBSTR [SHLWAPI.@] 01605 * 01606 * Converts a STRRET to a BSTR. 01607 * 01608 * PARAMS 01609 * lpStrRet [O] STRRET to convert 01610 * pidl [I] ITEMIDLIST for lpStrRet->uType = STRRET_OFFSET 01611 * pBstrOut [O] Destination for converted BSTR 01612 * 01613 * RETURNS 01614 * Success: S_OK. pBstrOut contains the new string. 01615 * Failure: E_FAIL, if any parameters are invalid. 01616 */ 01617 HRESULT WINAPI StrRetToBSTR(STRRET *lpStrRet, LPCITEMIDLIST pidl, BSTR* pBstrOut) 01618 { 01619 HRESULT hRet = E_FAIL; 01620 01621 switch (lpStrRet->uType) 01622 { 01623 case STRRET_WSTR: 01624 *pBstrOut = SysAllocString(lpStrRet->u.pOleStr); 01625 if (*pBstrOut) 01626 hRet = S_OK; 01627 CoTaskMemFree(lpStrRet->u.pOleStr); 01628 break; 01629 01630 case STRRET_CSTR: 01631 hRet = _SHStrDupAToBSTR(lpStrRet->u.cStr, pBstrOut); 01632 break; 01633 01634 case STRRET_OFFSET: 01635 hRet = _SHStrDupAToBSTR(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, pBstrOut); 01636 break; 01637 01638 default: 01639 *pBstrOut = NULL; 01640 } 01641 01642 return hRet; 01643 } 01644 01645 /************************************************************************* 01646 * StrFormatKBSizeA [SHLWAPI.@] 01647 * 01648 * Create a formatted string containing a byte count in Kilobytes. 01649 * 01650 * PARAMS 01651 * llBytes [I] Byte size to format 01652 * lpszDest [I] Destination for formatted string 01653 * cchMax [I] Size of lpszDest 01654 * 01655 * RETURNS 01656 * lpszDest. 01657 */ 01658 LPSTR WINAPI StrFormatKBSizeA(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax) 01659 { 01660 WCHAR wszBuf[256]; 01661 01662 if (!StrFormatKBSizeW(llBytes, wszBuf, 256)) 01663 return NULL; 01664 if (!WideCharToMultiByte(CP_ACP, 0, wszBuf, -1, lpszDest, cchMax, NULL, NULL)) 01665 return NULL; 01666 return lpszDest; 01667 } 01668 01669 /************************************************************************* 01670 * StrFormatKBSizeW [SHLWAPI.@] 01671 * 01672 * See StrFormatKBSizeA. 01673 */ 01674 LPWSTR WINAPI StrFormatKBSizeW(LONGLONG llBytes, LPWSTR lpszDest, UINT cchMax) 01675 { 01676 static const WCHAR kb[] = {' ','K','B',0}; 01677 LONGLONG llKB = (llBytes + 1023) >> 10; 01678 int len; 01679 01680 TRACE("(0x%s,%p,%d)\n", wine_dbgstr_longlong(llBytes), lpszDest, cchMax); 01681 01682 if (!FormatInt(llKB, lpszDest, cchMax)) 01683 return NULL; 01684 01685 len = lstrlenW(lpszDest); 01686 if (cchMax - len < 4) 01687 return NULL; 01688 lstrcatW(lpszDest, kb); 01689 return lpszDest; 01690 } 01691 01692 /************************************************************************* 01693 * StrNCatA [SHLWAPI.@] 01694 * 01695 * Concatenate two strings together. 01696 * 01697 * PARAMS 01698 * lpszStr [O] String to concatenate to 01699 * lpszCat [I] String to add to lpszCat 01700 * cchMax [I] Maximum number of characters to concatenate 01701 * 01702 * RETURNS 01703 * lpszStr. 01704 * 01705 * NOTES 01706 * cchMax determines the number of characters that are appended to lpszStr, 01707 * not the total length of the string. 01708 */ 01709 LPSTR WINAPI StrNCatA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax) 01710 { 01711 LPSTR lpszRet = lpszStr; 01712 01713 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszCat), cchMax); 01714 01715 if (!lpszStr) 01716 { 01717 WARN("Invalid lpszStr would crash under Win32!\n"); 01718 return NULL; 01719 } 01720 01721 StrCpyNA(lpszStr + strlen(lpszStr), lpszCat, cchMax); 01722 return lpszRet; 01723 } 01724 01725 /************************************************************************* 01726 * StrNCatW [SHLWAPI.@] 01727 * 01728 * See StrNCatA. 01729 */ 01730 LPWSTR WINAPI StrNCatW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax) 01731 { 01732 LPWSTR lpszRet = lpszStr; 01733 01734 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszCat), cchMax); 01735 01736 if (!lpszStr) 01737 { 01738 WARN("Invalid lpszStr would crash under Win32\n"); 01739 return NULL; 01740 } 01741 01742 StrCpyNW(lpszStr + strlenW(lpszStr), lpszCat, cchMax); 01743 return lpszRet; 01744 } 01745 01746 /************************************************************************* 01747 * StrTrimA [SHLWAPI.@] 01748 * 01749 * Remove characters from the start and end of a string. 01750 * 01751 * PARAMS 01752 * lpszStr [O] String to remove characters from 01753 * lpszTrim [I] Characters to remove from lpszStr 01754 * 01755 * RETURNS 01756 * TRUE If lpszStr was valid and modified 01757 * FALSE Otherwise 01758 */ 01759 BOOL WINAPI StrTrimA(LPSTR lpszStr, LPCSTR lpszTrim) 01760 { 01761 DWORD dwLen; 01762 LPSTR lpszRead = lpszStr; 01763 BOOL bRet = FALSE; 01764 01765 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszTrim)); 01766 01767 if (lpszRead && *lpszRead) 01768 { 01769 while (*lpszRead && StrChrA(lpszTrim, *lpszRead)) 01770 lpszRead = CharNextA(lpszRead); /* Skip leading matches */ 01771 01772 dwLen = strlen(lpszRead); 01773 01774 if (lpszRead != lpszStr) 01775 { 01776 memmove(lpszStr, lpszRead, dwLen + 1); 01777 bRet = TRUE; 01778 } 01779 if (dwLen > 0) 01780 { 01781 lpszRead = lpszStr + dwLen; 01782 while (StrChrA(lpszTrim, lpszRead[-1])) 01783 lpszRead = CharPrevA(lpszStr, lpszRead); /* Skip trailing matches */ 01784 01785 if (lpszRead != lpszStr + dwLen) 01786 { 01787 *lpszRead = '\0'; 01788 bRet = TRUE; 01789 } 01790 } 01791 } 01792 return bRet; 01793 } 01794 01795 /************************************************************************* 01796 * StrTrimW [SHLWAPI.@] 01797 * 01798 * See StrTrimA. 01799 */ 01800 BOOL WINAPI StrTrimW(LPWSTR lpszStr, LPCWSTR lpszTrim) 01801 { 01802 DWORD dwLen; 01803 LPWSTR lpszRead = lpszStr; 01804 BOOL bRet = FALSE; 01805 01806 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszTrim)); 01807 01808 if (lpszRead && *lpszRead) 01809 { 01810 while (*lpszRead && StrChrW(lpszTrim, *lpszRead)) lpszRead++; 01811 01812 dwLen = strlenW(lpszRead); 01813 01814 if (lpszRead != lpszStr) 01815 { 01816 memmove(lpszStr, lpszRead, (dwLen + 1) * sizeof(WCHAR)); 01817 bRet = TRUE; 01818 } 01819 if (dwLen > 0) 01820 { 01821 lpszRead = lpszStr + dwLen; 01822 while (StrChrW(lpszTrim, lpszRead[-1])) 01823 lpszRead--; /* Skip trailing matches */ 01824 01825 if (lpszRead != lpszStr + dwLen) 01826 { 01827 *lpszRead = '\0'; 01828 bRet = TRUE; 01829 } 01830 } 01831 } 01832 return bRet; 01833 } 01834 01835 /************************************************************************* 01836 * _SHStrDupAA [INTERNAL] 01837 * 01838 * Duplicates a ASCII string to ASCII. The destination buffer is allocated. 01839 */ 01840 static HRESULT _SHStrDupAA(LPCSTR src, LPSTR * dest) 01841 { 01842 HRESULT hr; 01843 int len = 0; 01844 01845 if (src) { 01846 len = lstrlenA(src) + 1; 01847 *dest = CoTaskMemAlloc(len); 01848 } else { 01849 *dest = NULL; 01850 } 01851 01852 if (*dest) { 01853 lstrcpynA(*dest,src, len); 01854 hr = S_OK; 01855 } else { 01856 hr = E_OUTOFMEMORY; 01857 } 01858 01859 TRACE("%s->(%p)\n", debugstr_a(src), *dest); 01860 return hr; 01861 } 01862 01863 /************************************************************************* 01864 * SHStrDupA [SHLWAPI.@] 01865 * 01866 * Return a Unicode copy of a string, in memory allocated by CoTaskMemAlloc(). 01867 * 01868 * PARAMS 01869 * lpszStr [I] String to copy 01870 * lppszDest [O] Destination for the new string copy 01871 * 01872 * RETURNS 01873 * Success: S_OK. lppszDest contains the new string in Unicode format. 01874 * Failure: E_OUTOFMEMORY, If any arguments are invalid or memory allocation 01875 * fails. 01876 */ 01877 HRESULT WINAPI SHStrDupA(LPCSTR lpszStr, LPWSTR * lppszDest) 01878 { 01879 HRESULT hRet; 01880 int len = 0; 01881 01882 if (lpszStr) 01883 { 01884 len = MultiByteToWideChar(0, 0, lpszStr, -1, 0, 0) * sizeof(WCHAR); 01885 *lppszDest = CoTaskMemAlloc(len); 01886 } 01887 else 01888 *lppszDest = NULL; 01889 01890 if (*lppszDest) 01891 { 01892 MultiByteToWideChar(0, 0, lpszStr, -1, *lppszDest, len/sizeof(WCHAR)); 01893 hRet = S_OK; 01894 } 01895 else 01896 hRet = E_OUTOFMEMORY; 01897 01898 TRACE("%s->(%p)\n", debugstr_a(lpszStr), *lppszDest); 01899 return hRet; 01900 } 01901 01902 /************************************************************************* 01903 * _SHStrDupAW [INTERNAL] 01904 * 01905 * Duplicates a UNICODE to a ASCII string. The destination buffer is allocated. 01906 */ 01907 static HRESULT _SHStrDupAW(LPCWSTR src, LPSTR * dest) 01908 { 01909 HRESULT hr; 01910 int len = 0; 01911 01912 if (src) { 01913 len = WideCharToMultiByte(CP_ACP, 0, src, -1, NULL, 0, NULL, NULL); 01914 *dest = CoTaskMemAlloc(len); 01915 } else { 01916 *dest = NULL; 01917 } 01918 01919 if (*dest) { 01920 WideCharToMultiByte(CP_ACP, 0, src, -1, *dest, len, NULL, NULL); 01921 hr = S_OK; 01922 } else { 01923 hr = E_OUTOFMEMORY; 01924 } 01925 01926 TRACE("%s->(%p)\n", debugstr_w(src), *dest); 01927 return hr; 01928 } 01929 01930 /************************************************************************* 01931 * SHStrDupW [SHLWAPI.@] 01932 * 01933 * See SHStrDupA. 01934 */ 01935 HRESULT WINAPI SHStrDupW(LPCWSTR src, LPWSTR * dest) 01936 { 01937 HRESULT hr; 01938 int len = 0; 01939 01940 if (src) { 01941 len = (lstrlenW(src) + 1) * sizeof(WCHAR); 01942 *dest = CoTaskMemAlloc(len); 01943 } else { 01944 *dest = NULL; 01945 } 01946 01947 if (*dest) { 01948 memcpy(*dest, src, len); 01949 hr = S_OK; 01950 } else { 01951 hr = E_OUTOFMEMORY; 01952 } 01953 01954 TRACE("%s->(%p)\n", debugstr_w(src), *dest); 01955 return hr; 01956 } 01957 01958 /************************************************************************* 01959 * SHLWAPI_WriteReverseNum 01960 * 01961 * Internal helper for SHLWAPI_WriteTimeClass. 01962 */ 01963 static inline LPWSTR SHLWAPI_WriteReverseNum(LPWSTR lpszOut, DWORD dwNum) 01964 { 01965 *lpszOut-- = '\0'; 01966 01967 /* Write a decimal number to a string, backwards */ 01968 do 01969 { 01970 DWORD dwNextDigit = dwNum % 10; 01971 *lpszOut-- = '0' + dwNextDigit; 01972 dwNum = (dwNum - dwNextDigit) / 10; 01973 } while (dwNum > 0); 01974 01975 return lpszOut; 01976 } 01977 01978 /************************************************************************* 01979 * SHLWAPI_FormatSignificant 01980 * 01981 * Internal helper for SHLWAPI_WriteTimeClass. 01982 */ 01983 static inline int SHLWAPI_FormatSignificant(LPWSTR lpszNum, int dwDigits) 01984 { 01985 /* Zero non significant digits, return remaining significant digits */ 01986 while (*lpszNum) 01987 { 01988 lpszNum++; 01989 if (--dwDigits == 0) 01990 { 01991 while (*lpszNum) 01992 *lpszNum++ = '0'; 01993 return 0; 01994 } 01995 } 01996 return dwDigits; 01997 } 01998 01999 /************************************************************************* 02000 * SHLWAPI_WriteTimeClass 02001 * 02002 * Internal helper for StrFromTimeIntervalW. 02003 */ 02004 static int SHLWAPI_WriteTimeClass(LPWSTR lpszOut, DWORD dwValue, 02005 UINT uClassStringId, int iDigits) 02006 { 02007 WCHAR szBuff[64], *szOut = szBuff + 32; 02008 02009 szOut = SHLWAPI_WriteReverseNum(szOut, dwValue); 02010 iDigits = SHLWAPI_FormatSignificant(szOut + 1, iDigits); 02011 *szOut = ' '; 02012 LoadStringW(shlwapi_hInstance, uClassStringId, szBuff + 32, 32); 02013 strcatW(lpszOut, szOut); 02014 return iDigits; 02015 } 02016 02017 /************************************************************************* 02018 * StrFromTimeIntervalA [SHLWAPI.@] 02019 * 02020 * Format a millisecond time interval into a string 02021 * 02022 * PARAMS 02023 * lpszStr [O] Output buffer for formatted time interval 02024 * cchMax [I] Size of lpszStr 02025 * dwMS [I] Number of milliseconds 02026 * iDigits [I] Number of digits to print 02027 * 02028 * RETURNS 02029 * The length of the formatted string, or 0 if any parameter is invalid. 02030 * 02031 * NOTES 02032 * This implementation mimics the Win32 behaviour of always writing a leading 02033 * space before the time interval begins. 02034 * 02035 * iDigits is used to provide approximate times if accuracy is not important. 02036 * This number of digits will be written of the first non-zero time class 02037 * (hours/minutes/seconds). If this does not complete the time classification, 02038 * the remaining digits are changed to zeros (i.e. The time is _not_ rounded). 02039 * If there are digits remaining following the writing of a time class, the 02040 * next time class will be written. 02041 * 02042 * For example, given dwMS represents 138 hours,43 minutes and 15 seconds, the 02043 * following will result from the given values of iDigits: 02044 * 02045 *| iDigits 1 2 3 4 5 ... 02046 *| lpszStr "100 hr" "130 hr" "138 hr" "138 hr 40 min" "138 hr 43 min" ... 02047 */ 02048 INT WINAPI StrFromTimeIntervalA(LPSTR lpszStr, UINT cchMax, DWORD dwMS, 02049 int iDigits) 02050 { 02051 INT iRet = 0; 02052 02053 TRACE("(%p,%d,%d,%d)\n", lpszStr, cchMax, dwMS, iDigits); 02054 02055 if (lpszStr && cchMax) 02056 { 02057 WCHAR szBuff[128]; 02058 StrFromTimeIntervalW(szBuff, sizeof(szBuff)/sizeof(WCHAR), dwMS, iDigits); 02059 WideCharToMultiByte(CP_ACP,0,szBuff,-1,lpszStr,cchMax,0,0); 02060 } 02061 return iRet; 02062 } 02063 02064 02065 /************************************************************************* 02066 * StrFromTimeIntervalW [SHLWAPI.@] 02067 * 02068 * See StrFromTimeIntervalA. 02069 */ 02070 INT WINAPI StrFromTimeIntervalW(LPWSTR lpszStr, UINT cchMax, DWORD dwMS, 02071 int iDigits) 02072 { 02073 INT iRet = 0; 02074 02075 TRACE("(%p,%d,%d,%d)\n", lpszStr, cchMax, dwMS, iDigits); 02076 02077 if (lpszStr && cchMax) 02078 { 02079 WCHAR szCopy[128]; 02080 DWORD dwHours, dwMinutes; 02081 02082 if (!iDigits || cchMax == 1) 02083 { 02084 *lpszStr = '\0'; 02085 return 0; 02086 } 02087 02088 /* Calculate the time classes */ 02089 dwMS = (dwMS + 500) / 1000; 02090 dwHours = dwMS / 3600; 02091 dwMS -= dwHours * 3600; 02092 dwMinutes = dwMS / 60; 02093 dwMS -= dwMinutes * 60; 02094 02095 szCopy[0] = '\0'; 02096 02097 if (dwHours) 02098 iDigits = SHLWAPI_WriteTimeClass(szCopy, dwHours, IDS_TIME_INTERVAL_HOURS, iDigits); 02099 02100 if (dwMinutes && iDigits) 02101 iDigits = SHLWAPI_WriteTimeClass(szCopy, dwMinutes, IDS_TIME_INTERVAL_MINUTES, iDigits); 02102 02103 if (iDigits) /* Always write seconds if we have significant digits */ 02104 SHLWAPI_WriteTimeClass(szCopy, dwMS, IDS_TIME_INTERVAL_SECONDS, iDigits); 02105 02106 lstrcpynW(lpszStr, szCopy, cchMax); 02107 iRet = strlenW(lpszStr); 02108 } 02109 return iRet; 02110 } 02111 02112 /************************************************************************* 02113 * StrIsIntlEqualA [SHLWAPI.@] 02114 * 02115 * Compare two strings. 02116 * 02117 * PARAMS 02118 * bCase [I] Whether to compare case sensitively 02119 * lpszStr [I] First string to compare 02120 * lpszComp [I] Second string to compare 02121 * iLen [I] Length to compare 02122 * 02123 * RETURNS 02124 * TRUE If the strings are equal. 02125 * FALSE Otherwise. 02126 */ 02127 BOOL WINAPI StrIsIntlEqualA(BOOL bCase, LPCSTR lpszStr, LPCSTR lpszComp, 02128 int iLen) 02129 { 02130 DWORD dwFlags; 02131 02132 TRACE("(%d,%s,%s,%d)\n", bCase, 02133 debugstr_a(lpszStr), debugstr_a(lpszComp), iLen); 02134 02135 /* FIXME: This flag is undocumented and unknown by our CompareString. 02136 * We need a define for it. 02137 */ 02138 dwFlags = 0x10000000; 02139 if (!bCase) dwFlags |= NORM_IGNORECASE; 02140 02141 return (CompareStringA(GetThreadLocale(), dwFlags, lpszStr, iLen, lpszComp, iLen) == CSTR_EQUAL); 02142 } 02143 02144 /************************************************************************* 02145 * StrIsIntlEqualW [SHLWAPI.@] 02146 * 02147 * See StrIsIntlEqualA. 02148 */ 02149 BOOL WINAPI StrIsIntlEqualW(BOOL bCase, LPCWSTR lpszStr, LPCWSTR lpszComp, 02150 int iLen) 02151 { 02152 DWORD dwFlags; 02153 02154 TRACE("(%d,%s,%s,%d)\n", bCase, 02155 debugstr_w(lpszStr),debugstr_w(lpszComp), iLen); 02156 02157 /* FIXME: This flag is undocumented and unknown by our CompareString. 02158 * We need a define for it. 02159 */ 02160 dwFlags = 0x10000000; 02161 if (!bCase) dwFlags |= NORM_IGNORECASE; 02162 02163 return (CompareStringW(GetThreadLocale(), dwFlags, lpszStr, iLen, lpszComp, iLen) == CSTR_EQUAL); 02164 } 02165 02166 /************************************************************************* 02167 * @ [SHLWAPI.399] 02168 * 02169 * Copy a string to another string, up to a maximum number of characters. 02170 * 02171 * PARAMS 02172 * lpszDest [O] Destination string 02173 * lpszSrc [I] Source string 02174 * iLen [I] Maximum number of chars to copy 02175 * 02176 * RETURNS 02177 * Success: A pointer to the last character written to lpszDest. 02178 * Failure: lpszDest, if any arguments are invalid. 02179 */ 02180 LPSTR WINAPI StrCpyNXA(LPSTR lpszDest, LPCSTR lpszSrc, int iLen) 02181 { 02182 TRACE("(%p,%s,%i)\n", lpszDest, debugstr_a(lpszSrc), iLen); 02183 02184 if (lpszDest && lpszSrc && iLen > 0) 02185 { 02186 while ((iLen-- > 1) && *lpszSrc) 02187 *lpszDest++ = *lpszSrc++; 02188 if (iLen >= 0) 02189 *lpszDest = '\0'; 02190 } 02191 return lpszDest; 02192 } 02193 02194 /************************************************************************* 02195 * @ [SHLWAPI.400] 02196 * 02197 * Unicode version of StrCpyNXA. 02198 */ 02199 LPWSTR WINAPI StrCpyNXW(LPWSTR lpszDest, LPCWSTR lpszSrc, int iLen) 02200 { 02201 TRACE("(%p,%s,%i)\n", lpszDest, debugstr_w(lpszSrc), iLen); 02202 02203 if (lpszDest && lpszSrc && iLen > 0) 02204 { 02205 while ((iLen-- > 1) && *lpszSrc) 02206 *lpszDest++ = *lpszSrc++; 02207 if (iLen >= 0) 02208 *lpszDest = '\0'; 02209 } 02210 return lpszDest; 02211 } 02212 02213 /************************************************************************* 02214 * StrCmpLogicalW [SHLWAPI.@] 02215 * 02216 * Compare two strings, ignoring case and comparing digits as numbers. 02217 * 02218 * PARAMS 02219 * lpszStr [I] First string to compare 02220 * lpszComp [I] Second string to compare 02221 * iLen [I] Length to compare 02222 * 02223 * RETURNS 02224 * TRUE If the strings are equal. 02225 * FALSE Otherwise. 02226 */ 02227 INT WINAPI StrCmpLogicalW(LPCWSTR lpszStr, LPCWSTR lpszComp) 02228 { 02229 INT iDiff; 02230 02231 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszComp)); 02232 02233 if (lpszStr && lpszComp) 02234 { 02235 while (*lpszStr) 02236 { 02237 if (!*lpszComp) 02238 return 1; 02239 else if (isdigitW(*lpszStr)) 02240 { 02241 int iStr, iComp; 02242 02243 if (!isdigitW(*lpszComp)) 02244 return -1; 02245 02246 /* Compare the numbers */ 02247 StrToIntExW(lpszStr, 0, &iStr); 02248 StrToIntExW(lpszComp, 0, &iComp); 02249 02250 if (iStr < iComp) 02251 return -1; 02252 else if (iStr > iComp) 02253 return 1; 02254 02255 /* Skip */ 02256 while (isdigitW(*lpszStr)) 02257 lpszStr++; 02258 while (isdigitW(*lpszComp)) 02259 lpszComp++; 02260 } 02261 else if (isdigitW(*lpszComp)) 02262 return 1; 02263 else 02264 { 02265 iDiff = ChrCmpIW(*lpszStr,*lpszComp); 02266 if (iDiff > 0) 02267 return 1; 02268 else if (iDiff < 0) 02269 return -1; 02270 02271 lpszStr++; 02272 lpszComp++; 02273 } 02274 } 02275 if (*lpszComp) 02276 return -1; 02277 } 02278 return 0; 02279 } 02280 02281 /* Structure for formatting byte strings */ 02282 typedef struct tagSHLWAPI_BYTEFORMATS 02283 { 02284 LONGLONG dLimit; 02285 double dDivisor; 02286 double dNormaliser; 02287 int nDecimals; 02288 WCHAR wPrefix; 02289 } SHLWAPI_BYTEFORMATS; 02290 02291 /************************************************************************* 02292 * StrFormatByteSizeW [SHLWAPI.@] 02293 * 02294 * Create a string containing an abbreviated byte count of up to 2^63-1. 02295 * 02296 * PARAMS 02297 * llBytes [I] Byte size to format 02298 * lpszDest [I] Destination for formatted string 02299 * cchMax [I] Size of lpszDest 02300 * 02301 * RETURNS 02302 * lpszDest. 02303 * 02304 * NOTES 02305 * There is no StrFormatByteSize64W function, it is called StrFormatByteSizeW(). 02306 */ 02307 LPWSTR WINAPI StrFormatByteSizeW(LONGLONG llBytes, LPWSTR lpszDest, UINT cchMax) 02308 { 02309 #define KB ((ULONGLONG)1024) 02310 #define MB (KB*KB) 02311 #define GB (KB*KB*KB) 02312 #define TB (KB*KB*KB*KB) 02313 #define PB (KB*KB*KB*KB*KB) 02314 02315 static const SHLWAPI_BYTEFORMATS bfFormats[] = 02316 { 02317 { 10*KB, 10.24, 100.0, 2, 'K' }, /* 10 KB */ 02318 { 100*KB, 102.4, 10.0, 1, 'K' }, /* 100 KB */ 02319 { 1000*KB, 1024.0, 1.0, 0, 'K' }, /* 1000 KB */ 02320 { 10*MB, 10485.76, 100.0, 2, 'M' }, /* 10 MB */ 02321 { 100*MB, 104857.6, 10.0, 1, 'M' }, /* 100 MB */ 02322 { 1000*MB, 1048576.0, 1.0, 0, 'M' }, /* 1000 MB */ 02323 { 10*GB, 10737418.24, 100.0, 2, 'G' }, /* 10 GB */ 02324 { 100*GB, 107374182.4, 10.0, 1, 'G' }, /* 100 GB */ 02325 { 1000*GB, 1073741824.0, 1.0, 0, 'G' }, /* 1000 GB */ 02326 { 10*TB, 10485.76, 100.0, 2, 'T' }, /* 10 TB */ 02327 { 100*TB, 104857.6, 10.0, 1, 'T' }, /* 100 TB */ 02328 { 1000*TB, 1048576.0, 1.0, 0, 'T' }, /* 1000 TB */ 02329 { 10*PB, 10737418.24, 100.00, 2, 'P' }, /* 10 PB */ 02330 { 100*PB, 107374182.4, 10.00, 1, 'P' }, /* 100 PB */ 02331 { 1000*PB, 1073741824.0, 1.00, 0, 'P' }, /* 1000 PB */ 02332 { 0, 10995116277.76, 100.00, 2, 'E' } /* EB's, catch all */ 02333 }; 02334 WCHAR wszAdd[] = {' ','?','B',0}; 02335 double dBytes; 02336 UINT i = 0; 02337 02338 TRACE("(0x%s,%p,%d)\n", wine_dbgstr_longlong(llBytes), lpszDest, cchMax); 02339 02340 if (!lpszDest || !cchMax) 02341 return lpszDest; 02342 02343 if (llBytes < 1024) /* 1K */ 02344 { 02345 WCHAR wszBytesFormat[64]; 02346 LoadStringW(shlwapi_hInstance, IDS_BYTES_FORMAT, wszBytesFormat, 64); 02347 snprintfW(lpszDest, cchMax, wszBytesFormat, (long)llBytes); 02348 return lpszDest; 02349 } 02350 02351 /* Note that if this loop completes without finding a match, i will be 02352 * pointing at the last entry, which is a catch all for > 1000 PB 02353 */ 02354 while (i < sizeof(bfFormats) / sizeof(SHLWAPI_BYTEFORMATS) - 1) 02355 { 02356 if (llBytes < bfFormats[i].dLimit) 02357 break; 02358 i++; 02359 } 02360 /* Above 1 TB we encounter problems with FP accuracy. So for amounts above 02361 * this number we integer shift down by 1 MB first. The table above has 02362 * the divisors scaled down from the '< 10 TB' entry onwards, to account 02363 * for this. We also add a small fudge factor to get the correct result for 02364 * counts that lie exactly on a 1024 byte boundary. 02365 */ 02366 if (i > 8) 02367 dBytes = (double)(llBytes >> 20) + 0.001; /* Scale down by I MB */ 02368 else 02369 dBytes = (double)llBytes + 0.00001; 02370 02371 dBytes = floor(dBytes / bfFormats[i].dDivisor) / bfFormats[i].dNormaliser; 02372 02373 if (!FormatDouble(dBytes, bfFormats[i].nDecimals, lpszDest, cchMax)) 02374 return NULL; 02375 wszAdd[1] = bfFormats[i].wPrefix; 02376 StrCatBuffW(lpszDest, wszAdd, cchMax); 02377 return lpszDest; 02378 } 02379 02380 /************************************************************************* 02381 * StrFormatByteSize64A [SHLWAPI.@] 02382 * 02383 * See StrFormatByteSizeW. 02384 */ 02385 LPSTR WINAPI StrFormatByteSize64A(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax) 02386 { 02387 WCHAR wszBuff[32]; 02388 02389 StrFormatByteSizeW(llBytes, wszBuff, sizeof(wszBuff)/sizeof(WCHAR)); 02390 02391 if (lpszDest) 02392 WideCharToMultiByte(CP_ACP, 0, wszBuff, -1, lpszDest, cchMax, 0, 0); 02393 return lpszDest; 02394 } 02395 02396 /************************************************************************* 02397 * StrFormatByteSizeA [SHLWAPI.@] 02398 * 02399 * Create a string containing an abbreviated byte count of up to 2^31-1. 02400 * 02401 * PARAMS 02402 * dwBytes [I] Byte size to format 02403 * lpszDest [I] Destination for formatted string 02404 * cchMax [I] Size of lpszDest 02405 * 02406 * RETURNS 02407 * lpszDest. 02408 * 02409 * NOTES 02410 * The Ascii and Unicode versions of this function accept a different 02411 * integer type for dwBytes. See StrFormatByteSize64A(). 02412 */ 02413 LPSTR WINAPI StrFormatByteSizeA(DWORD dwBytes, LPSTR lpszDest, UINT cchMax) 02414 { 02415 TRACE("(%d,%p,%d)\n", dwBytes, lpszDest, cchMax); 02416 02417 return StrFormatByteSize64A(dwBytes, lpszDest, cchMax); 02418 } 02419 02420 /************************************************************************* 02421 * @ [SHLWAPI.162] 02422 * 02423 * Remove a hanging lead byte from the end of a string, if present. 02424 * 02425 * PARAMS 02426 * lpStr [I] String to check for a hanging lead byte 02427 * size [I] Length of lpStr 02428 * 02429 * RETURNS 02430 * Success: The new length of the string. Any hanging lead bytes are removed. 02431 * Failure: 0, if any parameters are invalid. 02432 */ 02433 DWORD WINAPI SHTruncateString(LPSTR lpStr, DWORD size) 02434 { 02435 if (lpStr && size) 02436 { 02437 LPSTR lastByte = lpStr + size - 1; 02438 02439 while(lpStr < lastByte) 02440 lpStr += IsDBCSLeadByte(*lpStr) ? 2 : 1; 02441 02442 if(lpStr == lastByte && IsDBCSLeadByte(*lpStr)) 02443 { 02444 *lpStr = '\0'; 02445 size--; 02446 } 02447 return size; 02448 } 02449 return 0; 02450 } 02451 02452 /************************************************************************* 02453 * @ [SHLWAPI.203] 02454 * 02455 * Remove a single non-trailing ampersand ('&') from a string. 02456 * 02457 * PARAMS 02458 * lpszStr [I/O] String to remove ampersand from. 02459 * 02460 * RETURNS 02461 * The character after the first ampersand in lpszStr, or the first character 02462 * in lpszStr if there is no ampersand in the string. 02463 */ 02464 char WINAPI SHStripMneumonicA(LPCSTR lpszStr) 02465 { 02466 LPSTR lpszIter, lpszTmp; 02467 char ch; 02468 02469 TRACE("(%s)\n", debugstr_a(lpszStr)); 02470 02471 ch = *lpszStr; 02472 02473 if ((lpszIter = StrChrA(lpszStr, '&'))) 02474 { 02475 lpszTmp = CharNextA(lpszIter); 02476 if (lpszTmp && *lpszTmp) 02477 { 02478 if (*lpszTmp != '&') 02479 ch = *lpszTmp; 02480 02481 while (lpszIter && *lpszIter) 02482 { 02483 lpszTmp = CharNextA(lpszIter); 02484 *lpszIter = *lpszTmp; 02485 lpszIter = lpszTmp; 02486 } 02487 } 02488 } 02489 02490 return ch; 02491 } 02492 02493 /************************************************************************* 02494 * @ [SHLWAPI.225] 02495 * 02496 * Unicode version of SHStripMneumonicA. 02497 */ 02498 WCHAR WINAPI SHStripMneumonicW(LPCWSTR lpszStr) 02499 { 02500 LPWSTR lpszIter, lpszTmp; 02501 WCHAR ch; 02502 02503 TRACE("(%s)\n", debugstr_w(lpszStr)); 02504 02505 ch = *lpszStr; 02506 02507 if ((lpszIter = StrChrW(lpszStr, '&'))) 02508 { 02509 lpszTmp = lpszIter + 1; 02510 if (lpszTmp && *lpszTmp) 02511 { 02512 if (*lpszTmp != '&') 02513 ch = *lpszTmp; 02514 02515 while (lpszIter && *lpszIter) 02516 { 02517 lpszTmp = lpszIter + 1; 02518 *lpszIter = *lpszTmp; 02519 lpszIter = lpszTmp; 02520 } 02521 } 02522 } 02523 02524 return ch; 02525 } 02526 02527 /************************************************************************* 02528 * @ [SHLWAPI.216] 02529 * 02530 * Convert an Ascii string to Unicode. 02531 * 02532 * PARAMS 02533 * dwCp [I] Code page for the conversion 02534 * lpSrcStr [I] Source Ascii string to convert 02535 * lpDstStr [O] Destination for converted Unicode string 02536 * iLen [I] Length of lpDstStr 02537 * 02538 * RETURNS 02539 * The return value of the MultiByteToWideChar() function called on lpSrcStr. 02540 */ 02541 DWORD WINAPI SHAnsiToUnicodeCP(DWORD dwCp, LPCSTR lpSrcStr, LPWSTR lpDstStr, int iLen) 02542 { 02543 DWORD dwRet; 02544 02545 dwRet = MultiByteToWideChar(dwCp, 0, lpSrcStr, -1, lpDstStr, iLen); 02546 TRACE("%s->%s,ret=%d\n", debugstr_a(lpSrcStr), debugstr_w(lpDstStr), dwRet); 02547 return dwRet; 02548 } 02549 02550 /************************************************************************* 02551 * @ [SHLWAPI.215] 02552 * 02553 * Convert an Ascii string to Unicode. 02554 * 02555 * PARAMS 02556 * lpSrcStr [I] Source Ascii string to convert 02557 * lpDstStr [O] Destination for converted Unicode string 02558 * iLen [I] Length of lpDstStr 02559 * 02560 * RETURNS 02561 * The return value of the MultiByteToWideChar() function called on lpSrcStr. 02562 * 02563 * NOTES 02564 * This function simply calls SHAnsiToUnicodeCP with code page CP_ACP. 02565 */ 02566 DWORD WINAPI SHAnsiToUnicode(LPCSTR lpSrcStr, LPWSTR lpDstStr, int iLen) 02567 { 02568 return SHAnsiToUnicodeCP(CP_ACP, lpSrcStr, lpDstStr, iLen); 02569 } 02570 02571 /************************************************************************* 02572 * @ [SHLWAPI.218] 02573 * 02574 * Convert a Unicode string to Ascii. 02575 * 02576 * PARAMS 02577 * CodePage [I] Code page to use for the conversion 02578 * lpSrcStr [I] Source Unicode string to convert 02579 * lpDstStr [O] Destination for converted Ascii string 02580 * dstlen [I] Length of buffer at lpDstStr 02581 * 02582 * RETURNS 02583 * Success: The length in bytes of the result at lpDstStr (including the terminator) 02584 * Failure: When using CP_UTF8, CP_UTF7 or 0xc350 as codePage, 0 is returned and 02585 * the result is not nul-terminated. 02586 * When using a different codepage, the length in bytes of the truncated 02587 * result at lpDstStr (including the terminator) is returned and 02588 * lpDstStr is always nul-terminated. 02589 * 02590 */ 02591 DWORD WINAPI SHUnicodeToAnsiCP(UINT CodePage, LPCWSTR lpSrcStr, LPSTR lpDstStr, int dstlen) 02592 { 02593 static const WCHAR emptyW[] = { '\0' }; 02594 int len , reqLen; 02595 LPSTR mem; 02596 02597 if (!lpDstStr || !dstlen) 02598 return 0; 02599 02600 if (!lpSrcStr) 02601 lpSrcStr = emptyW; 02602 02603 *lpDstStr = '\0'; 02604 02605 len = strlenW(lpSrcStr) + 1; 02606 02607 switch (CodePage) 02608 { 02609 case CP_WINUNICODE: 02610 CodePage = CP_UTF8; /* Fall through... */ 02611 case 0x0000C350: /* FIXME: CP_ #define */ 02612 case CP_UTF7: 02613 case CP_UTF8: 02614 { 02615 DWORD dwMode = 0; 02616 INT lenW = len - 1; 02617 INT needed = dstlen - 1; 02618 HRESULT hr; 02619 02620 /* try the user supplied buffer first */ 02621 hr = ConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &lenW, lpDstStr, &needed); 02622 if (hr == S_OK) 02623 { 02624 lpDstStr[needed] = '\0'; 02625 return needed + 1; 02626 } 02627 02628 /* user buffer too small. exclude termination and copy as much as possible */ 02629 lenW = len; 02630 hr = ConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &lenW, NULL, &needed); 02631 needed++; 02632 mem = HeapAlloc(GetProcessHeap(), 0, needed); 02633 if (!mem) 02634 return 0; 02635 02636 hr = ConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &len, mem, &needed); 02637 if (hr == S_OK) 02638 { 02639 reqLen = SHTruncateString(mem, dstlen); 02640 if (reqLen > 0) memcpy(lpDstStr, mem, reqLen-1); 02641 } 02642 HeapFree(GetProcessHeap(), 0, mem); 02643 return 0; 02644 } 02645 default: 02646 break; 02647 } 02648 02649 /* try the user supplied buffer first */ 02650 reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, lpDstStr, dstlen, NULL, NULL); 02651 02652 if (!reqLen && GetLastError() == ERROR_INSUFFICIENT_BUFFER) 02653 { 02654 reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, NULL, 0, NULL, NULL); 02655 if (reqLen) 02656 { 02657 mem = HeapAlloc(GetProcessHeap(), 0, reqLen); 02658 if (mem) 02659 { 02660 reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, mem, 02661 reqLen, NULL, NULL); 02662 02663 reqLen = SHTruncateString(mem, dstlen -1); 02664 reqLen++; 02665 02666 lstrcpynA(lpDstStr, mem, reqLen); 02667 HeapFree(GetProcessHeap(), 0, mem); 02668 lpDstStr[reqLen-1] = '\0'; 02669 } 02670 } 02671 } 02672 return reqLen; 02673 } 02674 02675 /************************************************************************* 02676 * @ [SHLWAPI.217] 02677 * 02678 * Convert a Unicode string to Ascii. 02679 * 02680 * PARAMS 02681 * lpSrcStr [I] Source Unicode string to convert 02682 * lpDstStr [O] Destination for converted Ascii string 02683 * iLen [O] Length of lpDstStr in characters 02684 * 02685 * RETURNS 02686 * See SHUnicodeToAnsiCP 02687 02688 * NOTES 02689 * This function simply calls SHUnicodeToAnsiCP() with CodePage = CP_ACP. 02690 */ 02691 INT WINAPI SHUnicodeToAnsi(LPCWSTR lpSrcStr, LPSTR lpDstStr, INT iLen) 02692 { 02693 return SHUnicodeToAnsiCP(CP_ACP, lpSrcStr, lpDstStr, iLen); 02694 } 02695 02696 /************************************************************************* 02697 * @ [SHLWAPI.345] 02698 * 02699 * Copy one string to another. 02700 * 02701 * PARAMS 02702 * lpszSrc [I] Source string to copy 02703 * lpszDst [O] Destination for copy 02704 * iLen [I] Length of lpszDst in characters 02705 * 02706 * RETURNS 02707 * The length of the copied string, including the terminating NUL. lpszDst 02708 * contains iLen characters of lpszSrc. 02709 */ 02710 DWORD WINAPI SHAnsiToAnsi(LPCSTR lpszSrc, LPSTR lpszDst, int iLen) 02711 { 02712 LPSTR lpszRet; 02713 02714 TRACE("(%s,%p,0x%08x)\n", debugstr_a(lpszSrc), lpszDst, iLen); 02715 02716 lpszRet = StrCpyNXA(lpszDst, lpszSrc, iLen); 02717 return lpszRet - lpszDst + 1; 02718 } 02719 02720 /************************************************************************* 02721 * @ [SHLWAPI.346] 02722 * 02723 * Unicode version of SSHAnsiToAnsi. 02724 */ 02725 DWORD WINAPI SHUnicodeToUnicode(LPCWSTR lpszSrc, LPWSTR lpszDst, int iLen) 02726 { 02727 LPWSTR lpszRet; 02728 02729 TRACE("(%s,%p,0x%08x)\n", debugstr_w(lpszSrc), lpszDst, iLen); 02730 02731 lpszRet = StrCpyNXW(lpszDst, lpszSrc, iLen); 02732 return lpszRet - lpszDst + 1; 02733 } 02734 02735 /************************************************************************* 02736 * @ [SHLWAPI.364] 02737 * 02738 * Determine if an Ascii string converts to Unicode and back identically. 02739 * 02740 * PARAMS 02741 * lpSrcStr [I] Source Unicode string to convert 02742 * lpDst [O] Destination for resulting Ascii string 02743 * iLen [I] Length of lpDst in characters 02744 * 02745 * RETURNS 02746 * TRUE, since Ascii strings always convert identically. 02747 */ 02748 BOOL WINAPI DoesStringRoundTripA(LPCSTR lpSrcStr, LPSTR lpDst, INT iLen) 02749 { 02750 lstrcpynA(lpDst, lpSrcStr, iLen); 02751 return TRUE; 02752 } 02753 02754 /************************************************************************* 02755 * @ [SHLWAPI.365] 02756 * 02757 * Determine if a Unicode string converts to Ascii and back identically. 02758 * 02759 * PARAMS 02760 * lpSrcStr [I] Source Unicode string to convert 02761 * lpDst [O] Destination for resulting Ascii string 02762 * iLen [I] Length of lpDst in characters 02763 * 02764 * RETURNS 02765 * TRUE, if lpSrcStr converts to Ascii and back identically, 02766 * FALSE otherwise. 02767 */ 02768 BOOL WINAPI DoesStringRoundTripW(LPCWSTR lpSrcStr, LPSTR lpDst, INT iLen) 02769 { 02770 WCHAR szBuff[MAX_PATH]; 02771 02772 SHUnicodeToAnsi(lpSrcStr, lpDst, iLen); 02773 SHAnsiToUnicode(lpDst, szBuff, MAX_PATH); 02774 return !strcmpW(lpSrcStr, szBuff); 02775 } 02776 02777 /************************************************************************* 02778 * SHLoadIndirectString [SHLWAPI.@] 02779 * 02780 * If passed a string that begins with '@', extract the string from the 02781 * appropriate resource, otherwise do a straight copy. 02782 * 02783 */ 02784 HRESULT WINAPI SHLoadIndirectString(LPCWSTR src, LPWSTR dst, UINT dst_len, void **reserved) 02785 { 02786 WCHAR *dllname = NULL; 02787 HMODULE hmod = NULL; 02788 HRESULT hr = E_FAIL; 02789 02790 TRACE("(%s %p %08x %p)\n", debugstr_w(src), dst, dst_len, reserved); 02791 02792 if(src[0] == '@') 02793 { 02794 WCHAR *index_str; 02795 int index; 02796 02797 dst[0] = 0; 02798 dllname = StrDupW(src + 1); 02799 index_str = strchrW(dllname, ','); 02800 02801 if(!index_str) goto end; 02802 02803 *index_str = 0; 02804 index_str++; 02805 index = atoiW(index_str); 02806 02807 hmod = LoadLibraryW(dllname); 02808 if(!hmod) goto end; 02809 02810 if(index < 0) 02811 { 02812 if(LoadStringW(hmod, -index, dst, dst_len)) 02813 hr = S_OK; 02814 } 02815 else 02816 FIXME("can't handle non-negative indices (%d)\n", index); 02817 } 02818 else 02819 { 02820 if(dst != src) 02821 lstrcpynW(dst, src, dst_len); 02822 hr = S_OK; 02823 } 02824 02825 TRACE("returning %s\n", debugstr_w(dst)); 02826 end: 02827 if(hmod) FreeLibrary(hmod); 02828 HeapFree(GetProcessHeap(), 0, dllname); 02829 return hr; 02830 } Generated on Sat May 26 2012 04:16:32 for ReactOS by
1.7.6.1
|