ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

string.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.