2005-07-31 12:11:56 +00:00
|
|
|
/*
|
|
|
|
* Shlwapi string functions
|
|
|
|
*
|
|
|
|
* Copyright 1998 Juergen Schmied
|
|
|
|
* Copyright 2002 Jon Griffiths
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
2007-08-07 07:27:43 +00:00
|
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
2005-07-31 12:11:56 +00:00
|
|
|
*/
|
|
|
|
|
2018-03-04 12:17:11 +00:00
|
|
|
#include "config.h"
|
|
|
|
#include "wine/port.h"
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
#include <math.h>
|
2018-03-04 12:17:11 +00:00
|
|
|
#include <stdarg.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#define NONAMELESSUNION
|
|
|
|
|
|
|
|
#include "windef.h"
|
|
|
|
#include "winbase.h"
|
|
|
|
#define NO_SHLWAPI_REG
|
|
|
|
#define NO_SHLWAPI_STREAM
|
|
|
|
#include "shlwapi.h"
|
|
|
|
#include "wingdi.h"
|
|
|
|
#include "winuser.h"
|
|
|
|
#include "shlobj.h"
|
|
|
|
#include "mlang.h"
|
|
|
|
#include "ddeml.h"
|
|
|
|
#include "wine/unicode.h"
|
|
|
|
#include "wine/debug.h"
|
|
|
|
|
|
|
|
#include "resource.h"
|
|
|
|
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(shell);
|
2005-07-31 12:11:56 +00:00
|
|
|
|
2007-08-07 07:27:43 +00:00
|
|
|
extern HINSTANCE shlwapi_hInstance;
|
|
|
|
|
|
|
|
static HRESULT _SHStrDupAA(LPCSTR,LPSTR*);
|
|
|
|
static HRESULT _SHStrDupAW(LPCWSTR,LPSTR*);
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
|
2007-08-07 07:27:43 +00:00
|
|
|
static void FillNumberFmt(NUMBERFMTW *fmt, LPWSTR decimal_buffer, int decimal_bufwlen,
|
|
|
|
LPWSTR thousand_buffer, int thousand_bufwlen)
|
|
|
|
{
|
|
|
|
WCHAR grouping[64];
|
|
|
|
WCHAR *c;
|
2005-07-31 12:11:56 +00:00
|
|
|
|
2007-08-07 07:27:43 +00:00
|
|
|
GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_ILZERO|LOCALE_RETURN_NUMBER, (LPWSTR)&fmt->LeadingZero, sizeof(fmt->LeadingZero)/sizeof(WCHAR));
|
|
|
|
GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_INEGNUMBER|LOCALE_RETURN_NUMBER, (LPWSTR)&fmt->LeadingZero, sizeof(fmt->NegativeOrder)/sizeof(WCHAR));
|
|
|
|
fmt->NumDigits = 0;
|
|
|
|
GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, decimal_buffer, decimal_bufwlen);
|
|
|
|
GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, thousand_buffer, thousand_bufwlen);
|
|
|
|
fmt->lpThousandSep = thousand_buffer;
|
|
|
|
fmt->lpDecimalSep = decimal_buffer;
|
|
|
|
|
2007-11-29 11:15:59 +00:00
|
|
|
/*
|
|
|
|
* Converting grouping string to number as described on
|
2007-08-07 07:27:43 +00:00
|
|
|
* http://blogs.msdn.com/oldnewthing/archive/2006/04/18/578251.aspx
|
|
|
|
*/
|
|
|
|
fmt->Grouping = 0;
|
|
|
|
GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SGROUPING, grouping, sizeof(grouping)/sizeof(WCHAR));
|
|
|
|
for (c = grouping; *c; c++)
|
|
|
|
if (*c >= '0' && *c < '9')
|
|
|
|
{
|
|
|
|
fmt->Grouping *= 10;
|
|
|
|
fmt->Grouping += *c - '0';
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fmt->Grouping % 10 == 0)
|
|
|
|
fmt->Grouping /= 10;
|
|
|
|
else
|
|
|
|
fmt->Grouping *= 10;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* FormatInt [internal]
|
|
|
|
*
|
|
|
|
* Format an integer according to the current locale
|
|
|
|
*
|
|
|
|
* RETURNS
|
2010-08-07 22:41:23 +00:00
|
|
|
* The number of characters written on success or 0 on failure
|
2007-08-07 07:27:43 +00:00
|
|
|
*/
|
|
|
|
static int FormatInt(LONGLONG qdwValue, LPWSTR pszBuf, int cchBuf)
|
|
|
|
{
|
|
|
|
NUMBERFMTW fmt;
|
|
|
|
WCHAR decimal[8], thousand[8];
|
|
|
|
WCHAR buf[24];
|
|
|
|
WCHAR *c;
|
|
|
|
BOOL neg = (qdwValue < 0);
|
|
|
|
|
|
|
|
FillNumberFmt(&fmt, decimal, sizeof decimal / sizeof (WCHAR),
|
|
|
|
thousand, sizeof thousand / sizeof (WCHAR));
|
|
|
|
|
|
|
|
c = &buf[24];
|
|
|
|
*(--c) = 0;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
*(--c) = '0' + (qdwValue%10);
|
|
|
|
qdwValue /= 10;
|
|
|
|
} while (qdwValue > 0);
|
|
|
|
if (neg)
|
|
|
|
*(--c) = '-';
|
2007-11-29 11:15:59 +00:00
|
|
|
|
2007-08-07 07:27:43 +00:00
|
|
|
return GetNumberFormatW(LOCALE_USER_DEFAULT, 0, c, &fmt, pszBuf, cchBuf);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* FormatDouble [internal]
|
|
|
|
*
|
|
|
|
* Format an integer according to the current locale. Prints the specified number of digits
|
|
|
|
* after the decimal point
|
|
|
|
*
|
|
|
|
* RETURNS
|
2010-08-07 22:41:23 +00:00
|
|
|
* The number of characters written on success or 0 on failure
|
2007-08-07 07:27:43 +00:00
|
|
|
*/
|
|
|
|
static int FormatDouble(double value, int decimals, LPWSTR pszBuf, int cchBuf)
|
|
|
|
{
|
|
|
|
static const WCHAR flfmt[] = {'%','f',0};
|
|
|
|
WCHAR buf[64];
|
|
|
|
NUMBERFMTW fmt;
|
|
|
|
WCHAR decimal[8], thousand[8];
|
2007-11-29 11:15:59 +00:00
|
|
|
|
2007-08-07 07:27:43 +00:00
|
|
|
snprintfW(buf, 64, flfmt, value);
|
|
|
|
|
|
|
|
FillNumberFmt(&fmt, decimal, sizeof decimal / sizeof (WCHAR),
|
|
|
|
thousand, sizeof thousand / sizeof (WCHAR));
|
|
|
|
fmt.NumDigits = decimals;
|
|
|
|
return GetNumberFormatW(LOCALE_USER_DEFAULT, 0, buf, &fmt, pszBuf, cchBuf);
|
|
|
|
}
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* SHLWAPI_ChrCmpHelperA
|
|
|
|
*
|
|
|
|
* Internal helper for SHLWAPI_ChrCmpA/ChrCMPIA.
|
|
|
|
*
|
|
|
|
* NOTES
|
2007-08-07 07:27:43 +00:00
|
|
|
* Both this function and its Unicode counterpart are very inefficient. To
|
2005-07-31 12:11:56 +00:00
|
|
|
* fix this, CompareString must be completely implemented and optimised
|
|
|
|
* first. Then the core character test can be taken out of that function and
|
|
|
|
* placed here, so that it need never be called at all. Until then, do not
|
|
|
|
* attempt to optimise this code unless you are willing to test that it
|
|
|
|
* still performs correctly.
|
|
|
|
*/
|
2007-08-07 07:27:43 +00:00
|
|
|
static BOOL SHLWAPI_ChrCmpHelperA(WORD ch1, WORD ch2, DWORD dwFlags)
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
|
|
|
char str1[3], str2[3];
|
|
|
|
|
|
|
|
str1[0] = LOBYTE(ch1);
|
|
|
|
if (IsDBCSLeadByte(str1[0]))
|
|
|
|
{
|
|
|
|
str1[1] = HIBYTE(ch1);
|
|
|
|
str1[2] = '\0';
|
|
|
|
}
|
|
|
|
else
|
|
|
|
str1[1] = '\0';
|
|
|
|
|
|
|
|
str2[0] = LOBYTE(ch2);
|
|
|
|
if (IsDBCSLeadByte(str2[0]))
|
|
|
|
{
|
|
|
|
str2[1] = HIBYTE(ch2);
|
|
|
|
str2[2] = '\0';
|
|
|
|
}
|
|
|
|
else
|
|
|
|
str2[1] = '\0';
|
|
|
|
|
2012-09-29 13:14:20 +00:00
|
|
|
return CompareStringA(GetThreadLocale(), dwFlags, str1, -1, str2, -1) - CSTR_EQUAL;
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* SHLWAPI_ChrCmpA
|
|
|
|
*
|
|
|
|
* Internal helper function.
|
|
|
|
*/
|
|
|
|
static BOOL WINAPI SHLWAPI_ChrCmpA(WORD ch1, WORD ch2)
|
|
|
|
{
|
|
|
|
return SHLWAPI_ChrCmpHelperA(ch1, ch2, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* ChrCmpIA (SHLWAPI.385)
|
|
|
|
*
|
|
|
|
* Compare two characters, ignoring case.
|
|
|
|
*
|
|
|
|
* PARAMS
|
|
|
|
* ch1 [I] First character to compare
|
|
|
|
* ch2 [I] Second character to compare
|
|
|
|
*
|
|
|
|
* RETURNS
|
|
|
|
* FALSE, if the characters are equal.
|
|
|
|
* Non-zero otherwise.
|
|
|
|
*/
|
|
|
|
BOOL WINAPI ChrCmpIA(WORD ch1, WORD ch2)
|
|
|
|
{
|
|
|
|
TRACE("(%d,%d)\n", ch1, ch2);
|
|
|
|
|
|
|
|
return SHLWAPI_ChrCmpHelperA(ch1, ch2, NORM_IGNORECASE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* ChrCmpIW [SHLWAPI.386]
|
|
|
|
*
|
|
|
|
* See ChrCmpIA.
|
|
|
|
*/
|
|
|
|
BOOL WINAPI ChrCmpIW(WCHAR ch1, WCHAR ch2)
|
|
|
|
{
|
2012-09-29 13:14:20 +00:00
|
|
|
return CompareStringW(GetThreadLocale(), NORM_IGNORECASE, &ch1, 1, &ch2, 1) - CSTR_EQUAL;
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* StrChrA [SHLWAPI.@]
|
|
|
|
*
|
|
|
|
* Find a given character in a string.
|
|
|
|
*
|
|
|
|
* PARAMS
|
|
|
|
* lpszStr [I] String to search in.
|
|
|
|
* ch [I] Character to search for.
|
|
|
|
*
|
|
|
|
* RETURNS
|
|
|
|
* Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
|
|
|
|
* not found.
|
|
|
|
* Failure: NULL, if any arguments are invalid.
|
|
|
|
*/
|
|
|
|
LPSTR WINAPI StrChrA(LPCSTR lpszStr, WORD ch)
|
|
|
|
{
|
|
|
|
TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch);
|
|
|
|
|
|
|
|
if (lpszStr)
|
|
|
|
{
|
|
|
|
while (*lpszStr)
|
|
|
|
{
|
|
|
|
if (!SHLWAPI_ChrCmpA(*lpszStr, ch))
|
|
|
|
return (LPSTR)lpszStr;
|
|
|
|
lpszStr = CharNextA(lpszStr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* StrChrW [SHLWAPI.@]
|
|
|
|
*
|
|
|
|
* See StrChrA.
|
|
|
|
*/
|
|
|
|
LPWSTR WINAPI StrChrW(LPCWSTR lpszStr, WCHAR ch)
|
|
|
|
{
|
|
|
|
LPWSTR lpszRet = NULL;
|
|
|
|
|
|
|
|
TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch);
|
|
|
|
|
|
|
|
if (lpszStr)
|
|
|
|
lpszRet = strchrW(lpszStr, ch);
|
|
|
|
return lpszRet;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* StrChrIA [SHLWAPI.@]
|
|
|
|
*
|
|
|
|
* Find a given character in a string, ignoring case.
|
|
|
|
*
|
|
|
|
* PARAMS
|
|
|
|
* lpszStr [I] String to search in.
|
|
|
|
* ch [I] Character to search for.
|
|
|
|
*
|
|
|
|
* RETURNS
|
|
|
|
* Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
|
|
|
|
* not found.
|
|
|
|
* Failure: NULL, if any arguments are invalid.
|
|
|
|
*/
|
|
|
|
LPSTR WINAPI StrChrIA(LPCSTR lpszStr, WORD ch)
|
|
|
|
{
|
|
|
|
TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch);
|
|
|
|
|
|
|
|
if (lpszStr)
|
|
|
|
{
|
|
|
|
while (*lpszStr)
|
|
|
|
{
|
|
|
|
if (!ChrCmpIA(*lpszStr, ch))
|
|
|
|
return (LPSTR)lpszStr;
|
|
|
|
lpszStr = CharNextA(lpszStr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* StrChrIW [SHLWAPI.@]
|
|
|
|
*
|
|
|
|
* See StrChrA.
|
|
|
|
*/
|
|
|
|
LPWSTR WINAPI StrChrIW(LPCWSTR lpszStr, WCHAR ch)
|
|
|
|
{
|
|
|
|
TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch);
|
|
|
|
|
|
|
|
if (lpszStr)
|
|
|
|
{
|
|
|
|
ch = toupperW(ch);
|
|
|
|
while (*lpszStr)
|
|
|
|
{
|
|
|
|
if (toupperW(*lpszStr) == ch)
|
|
|
|
return (LPWSTR)lpszStr;
|
2007-08-07 07:27:43 +00:00
|
|
|
lpszStr++;
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
|
|
|
lpszStr = NULL;
|
|
|
|
}
|
|
|
|
return (LPWSTR)lpszStr;
|
|
|
|
}
|
|
|
|
|
2009-09-26 10:48:07 +00:00
|
|
|
/*************************************************************************
|
|
|
|
* StrChrNW [SHLWAPI.@]
|
|
|
|
*/
|
|
|
|
LPWSTR WINAPI StrChrNW(LPCWSTR lpszStr, WCHAR ch, UINT cchMax)
|
|
|
|
{
|
|
|
|
TRACE("(%s(%i),%i)\n", debugstr_wn(lpszStr,cchMax), cchMax, ch);
|
|
|
|
|
|
|
|
if (lpszStr)
|
|
|
|
{
|
|
|
|
while (*lpszStr && cchMax-- > 0)
|
|
|
|
{
|
|
|
|
if (*lpszStr == ch)
|
|
|
|
return (LPWSTR)lpszStr;
|
|
|
|
lpszStr++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2005-07-31 12:11:56 +00:00
|
|
|
/*************************************************************************
|
|
|
|
* StrCmpIW [SHLWAPI.@]
|
|
|
|
*
|
|
|
|
* Compare two strings, ignoring case.
|
|
|
|
*
|
|
|
|
* PARAMS
|
|
|
|
* lpszStr [I] First string to compare
|
|
|
|
* lpszComp [I] Second string to compare
|
|
|
|
*
|
|
|
|
* RETURNS
|
|
|
|
* An integer less than, equal to or greater than 0, indicating that
|
|
|
|
* lpszStr is less than, the same, or greater than lpszComp.
|
|
|
|
*/
|
|
|
|
int WINAPI StrCmpIW(LPCWSTR lpszStr, LPCWSTR lpszComp)
|
|
|
|
{
|
|
|
|
TRACE("(%s,%s)\n", debugstr_w(lpszStr),debugstr_w(lpszComp));
|
2012-09-29 13:14:20 +00:00
|
|
|
return CompareStringW(GetThreadLocale(), NORM_IGNORECASE, lpszStr, -1, lpszComp, -1) - CSTR_EQUAL;
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* StrCmpNA [SHLWAPI.@]
|
|
|
|
*
|
|
|
|
* Compare two strings, up to a maximum length.
|
|
|
|
*
|
|
|
|
* PARAMS
|
|
|
|
* lpszStr [I] First string to compare
|
|
|
|
* lpszComp [I] Second string to compare
|
2015-04-25 10:59:08 +00:00
|
|
|
* iLen [I] Number of chars to compare
|
2005-07-31 12:11:56 +00:00
|
|
|
*
|
|
|
|
* RETURNS
|
|
|
|
* An integer less than, equal to or greater than 0, indicating that
|
|
|
|
* lpszStr is less than, the same, or greater than lpszComp.
|
|
|
|
*/
|
|
|
|
INT WINAPI StrCmpNA(LPCSTR lpszStr, LPCSTR lpszComp, INT iLen)
|
|
|
|
{
|
|
|
|
TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
|
2012-09-29 13:14:20 +00:00
|
|
|
return CompareStringA(GetThreadLocale(), 0, lpszStr, iLen, lpszComp, iLen) - CSTR_EQUAL;
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* StrCmpNW [SHLWAPI.@]
|
|
|
|
*
|
|
|
|
* See StrCmpNA.
|
|
|
|
*/
|
|
|
|
INT WINAPI StrCmpNW(LPCWSTR lpszStr, LPCWSTR lpszComp, INT iLen)
|
|
|
|
{
|
|
|
|
TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen);
|
2012-09-29 13:14:20 +00:00
|
|
|
return CompareStringW(GetThreadLocale(), 0, lpszStr, iLen, lpszComp, iLen) - CSTR_EQUAL;
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* StrCmpNIA [SHLWAPI.@]
|
|
|
|
*
|
|
|
|
* Compare two strings, up to a maximum length, ignoring case.
|
|
|
|
*
|
|
|
|
* PARAMS
|
|
|
|
* lpszStr [I] First string to compare
|
|
|
|
* lpszComp [I] Second string to compare
|
2015-04-25 10:59:08 +00:00
|
|
|
* iLen [I] Number of chars to compare
|
2005-07-31 12:11:56 +00:00
|
|
|
*
|
|
|
|
* RETURNS
|
|
|
|
* An integer less than, equal to or greater than 0, indicating that
|
|
|
|
* lpszStr is less than, the same, or greater than lpszComp.
|
|
|
|
*/
|
|
|
|
int WINAPI StrCmpNIA(LPCSTR lpszStr, LPCSTR lpszComp, int iLen)
|
|
|
|
{
|
|
|
|
TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
|
2012-09-29 13:14:20 +00:00
|
|
|
return CompareStringA(GetThreadLocale(), NORM_IGNORECASE, lpszStr, iLen, lpszComp, iLen) - CSTR_EQUAL;
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* StrCmpNIW [SHLWAPI.@]
|
|
|
|
*
|
|
|
|
* See StrCmpNIA.
|
|
|
|
*/
|
|
|
|
INT WINAPI StrCmpNIW(LPCWSTR lpszStr, LPCWSTR lpszComp, int iLen)
|
|
|
|
{
|
|
|
|
TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen);
|
2012-09-29 13:14:20 +00:00
|
|
|
return CompareStringW(GetThreadLocale(), NORM_IGNORECASE, lpszStr, iLen, lpszComp, iLen) - CSTR_EQUAL;
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* StrCmpW [SHLWAPI.@]
|
|
|
|
*
|
|
|
|
* Compare two strings.
|
|
|
|
*
|
|
|
|
* PARAMS
|
|
|
|
* lpszStr [I] First string to compare
|
|
|
|
* lpszComp [I] Second string to compare
|
|
|
|
*
|
|
|
|
* RETURNS
|
|
|
|
* An integer less than, equal to or greater than 0, indicating that
|
|
|
|
* lpszStr is less than, the same, or greater than lpszComp.
|
|
|
|
*/
|
|
|
|
int WINAPI StrCmpW(LPCWSTR lpszStr, LPCWSTR lpszComp)
|
|
|
|
{
|
|
|
|
TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszComp));
|
2012-09-29 13:14:20 +00:00
|
|
|
return CompareStringW(GetThreadLocale(), 0, lpszStr, -1, lpszComp, -1) - CSTR_EQUAL;
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* StrCatW [SHLWAPI.@]
|
|
|
|
*
|
2008-06-08 17:13:54 +00:00
|
|
|
* Concatenate two strings.
|
2005-07-31 12:11:56 +00:00
|
|
|
*
|
|
|
|
* PARAMS
|
|
|
|
* lpszStr [O] Initial string
|
2008-06-08 17:13:54 +00:00
|
|
|
* lpszSrc [I] String to concatenate
|
2005-07-31 12:11:56 +00:00
|
|
|
*
|
|
|
|
* RETURNS
|
|
|
|
* lpszStr.
|
|
|
|
*/
|
|
|
|
LPWSTR WINAPI StrCatW(LPWSTR lpszStr, LPCWSTR lpszSrc)
|
|
|
|
{
|
|
|
|
TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSrc));
|
|
|
|
|
2012-09-29 13:14:20 +00:00
|
|
|
if (lpszStr && lpszSrc)
|
|
|
|
strcatW(lpszStr, lpszSrc);
|
2005-07-31 12:11:56 +00:00
|
|
|
return lpszStr;
|
|
|
|
}
|
|
|
|
|
2014-12-19 13:20:42 +00:00
|
|
|
/*************************************************************************
|
|
|
|
* StrCatChainW [SHLWAPI.@]
|
|
|
|
*
|
|
|
|
* Concatenates two unicode strings.
|
|
|
|
*
|
|
|
|
* PARAMS
|
|
|
|
* lpszStr [O] Initial string
|
|
|
|
* cchMax [I] Length of destination buffer
|
|
|
|
* ichAt [I] Offset from the destination buffer to begin concatenation
|
|
|
|
* lpszCat [I] String to concatenate
|
|
|
|
*
|
|
|
|
* RETURNS
|
|
|
|
* The offset from the beginning of pszDst to the terminating NULL.
|
|
|
|
*/
|
|
|
|
DWORD WINAPI StrCatChainW(LPWSTR lpszStr, DWORD cchMax, DWORD ichAt, LPCWSTR lpszCat)
|
|
|
|
{
|
|
|
|
TRACE("(%s,%u,%d,%s)\n", debugstr_w(lpszStr), cchMax, ichAt, debugstr_w(lpszCat));
|
|
|
|
|
|
|
|
if (ichAt == -1)
|
|
|
|
ichAt = strlenW(lpszStr);
|
|
|
|
|
|
|
|
if (!cchMax)
|
|
|
|
return ichAt;
|
|
|
|
|
|
|
|
if (ichAt == cchMax)
|
|
|
|
ichAt--;
|
|
|
|
|
|
|
|
if (lpszCat && ichAt < cchMax)
|
|
|
|
{
|
|
|
|
lpszStr += ichAt;
|
|
|
|
while (ichAt < cchMax - 1 && *lpszCat)
|
|
|
|
{
|
|
|
|
*lpszStr++ = *lpszCat++;
|
|
|
|
ichAt++;
|
|
|
|
}
|
|
|
|
*lpszStr = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ichAt;
|
|
|
|
}
|
|
|
|
|
2005-07-31 12:11:56 +00:00
|
|
|
/*************************************************************************
|
|
|
|
* StrCpyW [SHLWAPI.@]
|
|
|
|
*
|
|
|
|
* Copy a string to another string.
|
|
|
|
*
|
|
|
|
* PARAMS
|
|
|
|
* lpszStr [O] Destination string
|
|
|
|
* lpszSrc [I] Source string
|
|
|
|
*
|
|
|
|
* RETURNS
|
|
|
|
* lpszStr.
|
|
|
|
*/
|
|
|
|
LPWSTR WINAPI StrCpyW(LPWSTR lpszStr, LPCWSTR lpszSrc)
|
|
|
|
{
|
|
|
|
TRACE("(%p,%s)\n", lpszStr, debugstr_w(lpszSrc));
|
|
|
|
|
2012-09-29 13:14:20 +00:00
|
|
|
if (lpszStr && lpszSrc)
|
|
|
|
strcpyW(lpszStr, lpszSrc);
|
2005-07-31 12:11:56 +00:00
|
|
|
return lpszStr;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* StrCpyNW [SHLWAPI.@]
|
|
|
|
*
|
|
|
|
* Copy a string to another string, up to a maximum number of characters.
|
|
|
|
*
|
|
|
|
* PARAMS
|
2010-03-21 15:14:34 +00:00
|
|
|
* dst [O] Destination string
|
|
|
|
* src [I] Source string
|
|
|
|
* count [I] Maximum number of chars to copy
|
2005-07-31 12:11:56 +00:00
|
|
|
*
|
|
|
|
* RETURNS
|
2010-03-21 15:14:34 +00:00
|
|
|
* dst.
|
2005-07-31 12:11:56 +00:00
|
|
|
*/
|
2010-03-21 15:14:34 +00:00
|
|
|
LPWSTR WINAPI StrCpyNW(LPWSTR dst, LPCWSTR src, int count)
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
2010-03-21 15:14:34 +00:00
|
|
|
LPWSTR d = dst;
|
|
|
|
LPCWSTR s = src;
|
2005-07-31 12:11:56 +00:00
|
|
|
|
2010-03-21 15:14:34 +00:00
|
|
|
TRACE("(%p,%s,%i)\n", dst, debugstr_w(src), count);
|
2005-07-31 12:11:56 +00:00
|
|
|
|
2010-03-21 15:14:34 +00:00
|
|
|
if (s)
|
|
|
|
{
|
|
|
|
while ((count > 1) && *s)
|
|
|
|
{
|
|
|
|
count--;
|
|
|
|
*d++ = *s++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (count) *d = 0;
|
2005-07-31 12:11:56 +00:00
|
|
|
|
2010-03-21 15:14:34 +00:00
|
|
|
return dst;
|
|
|
|
}
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* SHLWAPI_StrStrHelperA
|
|
|
|
*
|
|
|
|
* Internal implementation of StrStrA/StrStrIA
|
|
|
|
*/
|
2007-08-07 07:27:43 +00:00
|
|
|
static LPSTR SHLWAPI_StrStrHelperA(LPCSTR lpszStr, LPCSTR lpszSearch,
|
2008-07-08 19:27:29 +00:00
|
|
|
INT (WINAPI *pStrCmpFn)(LPCSTR,LPCSTR,INT))
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
|
|
|
size_t iLen;
|
2015-04-25 10:59:08 +00:00
|
|
|
LPCSTR end;
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
if (!lpszStr || !lpszSearch || !*lpszSearch)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
iLen = strlen(lpszSearch);
|
2015-04-25 10:59:08 +00:00
|
|
|
end = lpszStr + strlen(lpszStr);
|
2005-07-31 12:11:56 +00:00
|
|
|
|
2015-04-25 10:59:08 +00:00
|
|
|
while (lpszStr + iLen <= end)
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
|
|
|
if (!pStrCmpFn(lpszStr, lpszSearch, iLen))
|
|
|
|
return (LPSTR)lpszStr;
|
|
|
|
lpszStr = CharNextA(lpszStr);
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* StrStrA [SHLWAPI.@]
|
|
|
|
*
|
|
|
|
* Find a substring within a string.
|
|
|
|
*
|
|
|
|
* PARAMS
|
|
|
|
* lpszStr [I] String to search in
|
|
|
|
* lpszSearch [I] String to look for
|
|
|
|
*
|
|
|
|
* RETURNS
|
|
|
|
* The start of lpszSearch within lpszStr, or NULL if not found.
|
|
|
|
*/
|
|
|
|
LPSTR WINAPI StrStrA(LPCSTR lpszStr, LPCSTR lpszSearch)
|
|
|
|
{
|
|
|
|
TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
|
|
|
|
|
2008-07-08 19:27:29 +00:00
|
|
|
return SHLWAPI_StrStrHelperA(lpszStr, lpszSearch, StrCmpNA);
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* StrStrW [SHLWAPI.@]
|
|
|
|
*
|
|
|
|
* See StrStrA.
|
|
|
|
*/
|
|
|
|
LPWSTR WINAPI StrStrW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
|
|
|
|
{
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
TRACE("(%s, %s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
|
|
|
|
|
|
|
|
if (!lpszStr || !lpszSearch || !*lpszSearch) return NULL;
|
2007-08-07 07:27:43 +00:00
|
|
|
return strstrW( lpszStr, lpszSearch );
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* StrRStrIA [SHLWAPI.@]
|
|
|
|
*
|
|
|
|
* Find the last occurrence of a substring within a string.
|
|
|
|
*
|
|
|
|
* PARAMS
|
|
|
|
* lpszStr [I] String to search in
|
|
|
|
* lpszEnd [I] End of lpszStr
|
|
|
|
* lpszSearch [I] String to look for
|
|
|
|
*
|
|
|
|
* RETURNS
|
|
|
|
* The last occurrence lpszSearch within lpszStr, or NULL if not found.
|
|
|
|
*/
|
|
|
|
LPSTR WINAPI StrRStrIA(LPCSTR lpszStr, LPCSTR lpszEnd, LPCSTR lpszSearch)
|
|
|
|
{
|
2015-04-25 10:59:08 +00:00
|
|
|
LPSTR lpszRet = NULL;
|
2005-07-31 12:11:56 +00:00
|
|
|
WORD ch1, ch2;
|
|
|
|
INT iLen;
|
|
|
|
|
|
|
|
TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
|
|
|
|
|
|
|
|
if (!lpszStr || !lpszSearch || !*lpszSearch)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (IsDBCSLeadByte(*lpszSearch))
|
2007-08-07 07:27:43 +00:00
|
|
|
ch1 = *lpszSearch << 8 | (UCHAR)lpszSearch[1];
|
2005-07-31 12:11:56 +00:00
|
|
|
else
|
|
|
|
ch1 = *lpszSearch;
|
|
|
|
iLen = lstrlenA(lpszSearch);
|
|
|
|
|
2015-04-25 10:59:08 +00:00
|
|
|
if (!lpszEnd)
|
|
|
|
lpszEnd = lpszStr + lstrlenA(lpszStr);
|
|
|
|
else /* reproduce the broken behaviour on Windows */
|
|
|
|
lpszEnd += min(iLen - 1, lstrlenA(lpszEnd));
|
|
|
|
|
|
|
|
while (lpszStr + iLen <= lpszEnd && *lpszStr)
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
2015-04-25 10:59:08 +00:00
|
|
|
ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | (UCHAR)lpszStr[1] : *lpszStr;
|
2005-07-31 12:11:56 +00:00
|
|
|
if (!ChrCmpIA(ch1, ch2))
|
|
|
|
{
|
2015-04-25 10:59:08 +00:00
|
|
|
if (!StrCmpNIA(lpszStr, lpszSearch, iLen))
|
|
|
|
lpszRet = (LPSTR)lpszStr;
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
2015-04-25 10:59:08 +00:00
|
|
|
lpszStr = CharNextA(lpszStr);
|
|
|
|
}
|
|
|
|
return lpszRet;
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* StrRStrIW [SHLWAPI.@]
|
|
|
|
*
|
|
|
|
* See StrRStrIA.
|
|
|
|
*/
|
|
|
|
LPWSTR WINAPI StrRStrIW(LPCWSTR lpszStr, LPCWSTR lpszEnd, LPCWSTR lpszSearch)
|
|
|
|
{
|
2015-04-25 10:59:08 +00:00
|
|
|
LPWSTR lpszRet = NULL;
|
2005-07-31 12:11:56 +00:00
|
|
|
INT iLen;
|
|
|
|
|
|
|
|
TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
|
|
|
|
|
|
|
|
if (!lpszStr || !lpszSearch || !*lpszSearch)
|
|
|
|
return NULL;
|
|
|
|
|
2015-04-25 10:59:08 +00:00
|
|
|
iLen = strlenW(lpszSearch);
|
|
|
|
|
2005-07-31 12:11:56 +00:00
|
|
|
if (!lpszEnd)
|
|
|
|
lpszEnd = lpszStr + strlenW(lpszStr);
|
2015-04-25 10:59:08 +00:00
|
|
|
else /* reproduce the broken behaviour on Windows */
|
|
|
|
lpszEnd += min(iLen - 1, lstrlenW(lpszEnd));
|
2005-07-31 12:11:56 +00:00
|
|
|
|
2015-04-25 10:59:08 +00:00
|
|
|
while (lpszStr + iLen <= lpszEnd && *lpszStr)
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
2015-04-25 10:59:08 +00:00
|
|
|
if (!ChrCmpIW(*lpszSearch, *lpszStr))
|
|
|
|
{
|
|
|
|
if (!StrCmpNIW(lpszStr, lpszSearch, iLen))
|
|
|
|
lpszRet = (LPWSTR)lpszStr;
|
|
|
|
}
|
|
|
|
lpszStr++;
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
2015-04-25 10:59:08 +00:00
|
|
|
return lpszRet;
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* StrStrIA [SHLWAPI.@]
|
|
|
|
*
|
|
|
|
* Find a substring within a string, ignoring case.
|
|
|
|
*
|
|
|
|
* PARAMS
|
|
|
|
* lpszStr [I] String to search in
|
|
|
|
* lpszSearch [I] String to look for
|
|
|
|
*
|
|
|
|
* RETURNS
|
|
|
|
* The start of lpszSearch within lpszStr, or NULL if not found.
|
|
|
|
*/
|
|
|
|
LPSTR WINAPI StrStrIA(LPCSTR lpszStr, LPCSTR lpszSearch)
|
|
|
|
{
|
|
|
|
TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
|
|
|
|
|
2008-07-08 19:27:29 +00:00
|
|
|
return SHLWAPI_StrStrHelperA(lpszStr, lpszSearch, StrCmpNIA);
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* StrStrIW [SHLWAPI.@]
|
|
|
|
*
|
|
|
|
* See StrStrIA.
|
|
|
|
*/
|
|
|
|
LPWSTR WINAPI StrStrIW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
|
|
|
|
{
|
2007-08-07 07:27:43 +00:00
|
|
|
int iLen;
|
2015-04-25 10:59:08 +00:00
|
|
|
LPCWSTR end;
|
2007-08-07 07:27:43 +00:00
|
|
|
|
2005-07-31 12:11:56 +00:00
|
|
|
TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
|
|
|
|
|
2007-08-07 07:27:43 +00:00
|
|
|
if (!lpszStr || !lpszSearch || !*lpszSearch)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
iLen = strlenW(lpszSearch);
|
2015-04-25 10:59:08 +00:00
|
|
|
end = lpszStr + strlenW(lpszStr);
|
2007-08-07 07:27:43 +00:00
|
|
|
|
2015-04-25 10:59:08 +00:00
|
|
|
while (lpszStr + iLen <= end)
|
2007-08-07 07:27:43 +00:00
|
|
|
{
|
|
|
|
if (!StrCmpNIW(lpszStr, lpszSearch, iLen))
|
|
|
|
return (LPWSTR)lpszStr;
|
|
|
|
lpszStr++;
|
|
|
|
}
|
|
|
|
return NULL;
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
|
|
|
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
/*************************************************************************
|
|
|
|
* StrStrNW [SHLWAPI.@]
|
|
|
|
*
|
|
|
|
* Find a substring within a string up to a given number of initial characters.
|
|
|
|
*
|
|
|
|
* PARAMS
|
|
|
|
* lpFirst [I] String to search in
|
|
|
|
* lpSrch [I] String to look for
|
|
|
|
* cchMax [I] Maximum number of initial search characters
|
|
|
|
*
|
|
|
|
* RETURNS
|
|
|
|
* The start of lpFirst within lpSrch, or NULL if not found.
|
|
|
|
*/
|
|
|
|
LPWSTR WINAPI StrStrNW(LPCWSTR lpFirst, LPCWSTR lpSrch, UINT cchMax)
|
|
|
|
{
|
|
|
|
UINT i;
|
|
|
|
int len;
|
|
|
|
|
|
|
|
TRACE("(%s, %s, %u)\n", debugstr_w(lpFirst), debugstr_w(lpSrch), cchMax);
|
|
|
|
|
|
|
|
if (!lpFirst || !lpSrch || !*lpSrch || !cchMax)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
len = strlenW(lpSrch);
|
|
|
|
|
|
|
|
for (i = cchMax; *lpFirst && (i > 0); i--, lpFirst++)
|
|
|
|
{
|
|
|
|
if (!strncmpW(lpFirst, lpSrch, len))
|
|
|
|
return (LPWSTR)lpFirst;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* StrStrNIW [SHLWAPI.@]
|
|
|
|
*
|
|
|
|
* Find a substring within a string up to a given number of initial characters,
|
|
|
|
* ignoring case.
|
|
|
|
*
|
|
|
|
* PARAMS
|
|
|
|
* lpFirst [I] String to search in
|
|
|
|
* lpSrch [I] String to look for
|
|
|
|
* cchMax [I] Maximum number of initial search characters
|
|
|
|
*
|
|
|
|
* RETURNS
|
|
|
|
* The start of lpFirst within lpSrch, or NULL if not found.
|
|
|
|
*/
|
|
|
|
LPWSTR WINAPI StrStrNIW(LPCWSTR lpFirst, LPCWSTR lpSrch, UINT cchMax)
|
|
|
|
{
|
|
|
|
UINT i;
|
|
|
|
int len;
|
|
|
|
|
|
|
|
TRACE("(%s, %s, %u)\n", debugstr_w(lpFirst), debugstr_w(lpSrch), cchMax);
|
|
|
|
|
|
|
|
if (!lpFirst || !lpSrch || !*lpSrch || !cchMax)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
len = strlenW(lpSrch);
|
|
|
|
|
|
|
|
for (i = cchMax; *lpFirst && (i > 0); i--, lpFirst++)
|
|
|
|
{
|
|
|
|
if (!strncmpiW(lpFirst, lpSrch, len))
|
|
|
|
return (LPWSTR)lpFirst;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2005-07-31 12:11:56 +00:00
|
|
|
/*************************************************************************
|
|
|
|
* StrToIntA [SHLWAPI.@]
|
|
|
|
*
|
|
|
|
* Read a signed integer from a string.
|
|
|
|
*
|
|
|
|
* PARAMS
|
|
|
|
* lpszStr [I] String to read integer from
|
|
|
|
*
|
|
|
|
* RETURNS
|
|
|
|
* The signed integer value represented by the string, or 0 if no integer is
|
|
|
|
* present.
|
|
|
|
*
|
|
|
|
* NOTES
|
|
|
|
* No leading space is allowed before the number, although a leading '-' is.
|
|
|
|
*/
|
|
|
|
int WINAPI StrToIntA(LPCSTR lpszStr)
|
|
|
|
{
|
|
|
|
int iRet = 0;
|
|
|
|
|
|
|
|
TRACE("(%s)\n", debugstr_a(lpszStr));
|
|
|
|
|
|
|
|
if (!lpszStr)
|
|
|
|
{
|
|
|
|
WARN("Invalid lpszStr would crash under Win32!\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*lpszStr == '-' || isdigit(*lpszStr))
|
|
|
|
StrToIntExA(lpszStr, 0, &iRet);
|
|
|
|
return iRet;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* StrToIntW [SHLWAPI.@]
|
|
|
|
*
|
|
|
|
* See StrToIntA.
|
|
|
|
*/
|
|
|
|
int WINAPI StrToIntW(LPCWSTR lpszStr)
|
|
|
|
{
|
|
|
|
int iRet = 0;
|
|
|
|
|
|
|
|
TRACE("(%s)\n", debugstr_w(lpszStr));
|
|
|
|
|
|
|
|
if (!lpszStr)
|
|
|
|
{
|
|
|
|
WARN("Invalid lpszStr would crash under Win32!\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*lpszStr == '-' || isdigitW(*lpszStr))
|
|
|
|
StrToIntExW(lpszStr, 0, &iRet);
|
|
|
|
return iRet;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* StrToIntExA [SHLWAPI.@]
|
|
|
|
*
|
|
|
|
* Read an integer from a string.
|
|
|
|
*
|
|
|
|
* PARAMS
|
|
|
|
* lpszStr [I] String to read integer from
|
|
|
|
* dwFlags [I] Flags controlling the conversion
|
|
|
|
* lpiRet [O] Destination for read integer.
|
|
|
|
*
|
|
|
|
* RETURNS
|
|
|
|
* Success: TRUE. lpiRet contains the integer value represented by the string.
|
|
|
|
* Failure: FALSE, if the string is invalid, or no number is present.
|
|
|
|
*
|
|
|
|
* NOTES
|
|
|
|
* Leading whitespace, '-' and '+' are allowed before the number. If
|
|
|
|
* dwFlags includes STIF_SUPPORT_HEX, hexadecimal numbers are allowed, if
|
|
|
|
* preceded by '0x'. If this flag is not set, or there is no '0x' prefix,
|
|
|
|
* the string is treated as a decimal string. A leading '-' is ignored for
|
|
|
|
* hexadecimal numbers.
|
|
|
|
*/
|
|
|
|
BOOL WINAPI StrToIntExA(LPCSTR lpszStr, DWORD dwFlags, LPINT lpiRet)
|
2012-09-29 13:14:20 +00:00
|
|
|
{
|
|
|
|
LONGLONG li;
|
|
|
|
BOOL bRes;
|
|
|
|
|
|
|
|
TRACE("(%s,%08X,%p)\n", debugstr_a(lpszStr), dwFlags, lpiRet);
|
|
|
|
|
|
|
|
bRes = StrToInt64ExA(lpszStr, dwFlags, &li);
|
|
|
|
if (bRes) *lpiRet = li;
|
|
|
|
return bRes;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* StrToInt64ExA [SHLWAPI.@]
|
|
|
|
*
|
|
|
|
* See StrToIntExA.
|
|
|
|
*/
|
|
|
|
BOOL WINAPI StrToInt64ExA(LPCSTR lpszStr, DWORD dwFlags, LONGLONG *lpiRet)
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
|
|
|
BOOL bNegative = FALSE;
|
2012-09-29 13:14:20 +00:00
|
|
|
LONGLONG iRet = 0;
|
2005-07-31 12:11:56 +00:00
|
|
|
|
2007-08-07 07:27:43 +00:00
|
|
|
TRACE("(%s,%08X,%p)\n", debugstr_a(lpszStr), dwFlags, lpiRet);
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
if (!lpszStr || !lpiRet)
|
|
|
|
{
|
|
|
|
WARN("Invalid parameter would crash under Win32!\n");
|
|
|
|
return FALSE;
|
|
|
|
}
|
2012-09-29 13:14:20 +00:00
|
|
|
if (dwFlags > STIF_SUPPORT_HEX) WARN("Unknown flags %08x\n", dwFlags);
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
/* Skip leading space, '+', '-' */
|
|
|
|
while (isspace(*lpszStr))
|
|
|
|
lpszStr = CharNextA(lpszStr);
|
|
|
|
|
|
|
|
if (*lpszStr == '-')
|
|
|
|
{
|
|
|
|
bNegative = TRUE;
|
|
|
|
lpszStr++;
|
|
|
|
}
|
|
|
|
else if (*lpszStr == '+')
|
|
|
|
lpszStr++;
|
|
|
|
|
|
|
|
if (dwFlags & STIF_SUPPORT_HEX &&
|
|
|
|
*lpszStr == '0' && tolower(lpszStr[1]) == 'x')
|
|
|
|
{
|
|
|
|
/* Read hex number */
|
|
|
|
lpszStr += 2;
|
|
|
|
|
|
|
|
if (!isxdigit(*lpszStr))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
while (isxdigit(*lpszStr))
|
|
|
|
{
|
|
|
|
iRet = iRet * 16;
|
|
|
|
if (isdigit(*lpszStr))
|
|
|
|
iRet += (*lpszStr - '0');
|
|
|
|
else
|
|
|
|
iRet += 10 + (tolower(*lpszStr) - 'a');
|
|
|
|
lpszStr++;
|
|
|
|
}
|
|
|
|
*lpiRet = iRet;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Read decimal number */
|
|
|
|
if (!isdigit(*lpszStr))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
while (isdigit(*lpszStr))
|
|
|
|
{
|
|
|
|
iRet = iRet * 10;
|
|
|
|
iRet += (*lpszStr - '0');
|
|
|
|
lpszStr++;
|
|
|
|
}
|
|
|
|
*lpiRet = bNegative ? -iRet : iRet;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* StrToIntExW [SHLWAPI.@]
|
|
|
|
*
|
|
|
|
* See StrToIntExA.
|
|
|
|
*/
|
|
|
|
BOOL WINAPI StrToIntExW(LPCWSTR lpszStr, DWORD dwFlags, LPINT lpiRet)
|
2012-09-29 13:14:20 +00:00
|
|
|
{
|
|
|
|
LONGLONG li;
|
|
|
|
BOOL bRes;
|
|
|
|
|
|
|
|
TRACE("(%s,%08X,%p)\n", debugstr_w(lpszStr), dwFlags, lpiRet);
|
|
|
|
|
|
|
|
bRes = StrToInt64ExW(lpszStr, dwFlags, &li);
|
|
|
|
if (bRes) *lpiRet = li;
|
|
|
|
return bRes;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* StrToInt64ExW [SHLWAPI.@]
|
|
|
|
*
|
|
|
|
* See StrToIntExA.
|
|
|
|
*/
|
|
|
|
BOOL WINAPI StrToInt64ExW(LPCWSTR lpszStr, DWORD dwFlags, LONGLONG *lpiRet)
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
|
|
|
BOOL bNegative = FALSE;
|
2012-09-29 13:14:20 +00:00
|
|
|
LONGLONG iRet = 0;
|
2005-07-31 12:11:56 +00:00
|
|
|
|
2007-08-07 07:27:43 +00:00
|
|
|
TRACE("(%s,%08X,%p)\n", debugstr_w(lpszStr), dwFlags, lpiRet);
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
if (!lpszStr || !lpiRet)
|
|
|
|
{
|
|
|
|
WARN("Invalid parameter would crash under Win32!\n");
|
|
|
|
return FALSE;
|
|
|
|
}
|
2012-09-29 13:14:20 +00:00
|
|
|
if (dwFlags > STIF_SUPPORT_HEX) WARN("Unknown flags %08x\n", dwFlags);
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
/* Skip leading space, '+', '-' */
|
2007-08-07 07:27:43 +00:00
|
|
|
while (isspaceW(*lpszStr)) lpszStr++;
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
if (*lpszStr == '-')
|
|
|
|
{
|
|
|
|
bNegative = TRUE;
|
|
|
|
lpszStr++;
|
|
|
|
}
|
|
|
|
else if (*lpszStr == '+')
|
|
|
|
lpszStr++;
|
|
|
|
|
|
|
|
if (dwFlags & STIF_SUPPORT_HEX &&
|
|
|
|
*lpszStr == '0' && tolowerW(lpszStr[1]) == 'x')
|
|
|
|
{
|
|
|
|
/* Read hex number */
|
|
|
|
lpszStr += 2;
|
|
|
|
|
|
|
|
if (!isxdigitW(*lpszStr))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
while (isxdigitW(*lpszStr))
|
|
|
|
{
|
|
|
|
iRet = iRet * 16;
|
|
|
|
if (isdigitW(*lpszStr))
|
|
|
|
iRet += (*lpszStr - '0');
|
|
|
|
else
|
|
|
|
iRet += 10 + (tolowerW(*lpszStr) - 'a');
|
|
|
|
lpszStr++;
|
|
|
|
}
|
|
|
|
*lpiRet = iRet;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Read decimal number */
|
|
|
|
if (!isdigitW(*lpszStr))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
while (isdigitW(*lpszStr))
|
|
|
|
{
|
|
|
|
iRet = iRet * 10;
|
|
|
|
iRet += (*lpszStr - '0');
|
|
|
|
lpszStr++;
|
|
|
|
}
|
|
|
|
*lpiRet = bNegative ? -iRet : iRet;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* StrDupA [SHLWAPI.@]
|
|
|
|
*
|
|
|
|
* Duplicate a string.
|
|
|
|
*
|
|
|
|
* PARAMS
|
|
|
|
* lpszStr [I] String to duplicate.
|
|
|
|
*
|
|
|
|
* RETURNS
|
|
|
|
* Success: A pointer to a new string containing the contents of lpszStr
|
|
|
|
* Failure: NULL, if memory cannot be allocated
|
|
|
|
*
|
|
|
|
* NOTES
|
|
|
|
* The string memory is allocated with LocalAlloc(), and so should be released
|
|
|
|
* by calling LocalFree().
|
|
|
|
*/
|
|
|
|
LPSTR WINAPI StrDupA(LPCSTR lpszStr)
|
|
|
|
{
|
|
|
|
int iLen;
|
|
|
|
LPSTR lpszRet;
|
|
|
|
|
|
|
|
TRACE("(%s)\n",debugstr_a(lpszStr));
|
|
|
|
|
|
|
|
iLen = lpszStr ? strlen(lpszStr) + 1 : 1;
|
2009-01-21 15:57:21 +00:00
|
|
|
lpszRet = LocalAlloc(LMEM_FIXED, iLen);
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
if (lpszRet)
|
|
|
|
{
|
|
|
|
if (lpszStr)
|
|
|
|
memcpy(lpszRet, lpszStr, iLen);
|
|
|
|
else
|
|
|
|
*lpszRet = '\0';
|
|
|
|
}
|
|
|
|
return lpszRet;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* StrDupW [SHLWAPI.@]
|
|
|
|
*
|
|
|
|
* See StrDupA.
|
|
|
|
*/
|
|
|
|
LPWSTR WINAPI StrDupW(LPCWSTR lpszStr)
|
|
|
|
{
|
|
|
|
int iLen;
|
|
|
|
LPWSTR lpszRet;
|
|
|
|
|
|
|
|
TRACE("(%s)\n",debugstr_w(lpszStr));
|
|
|
|
|
|
|
|
iLen = (lpszStr ? strlenW(lpszStr) + 1 : 1) * sizeof(WCHAR);
|
2009-01-21 15:57:21 +00:00
|
|
|
lpszRet = LocalAlloc(LMEM_FIXED, iLen);
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
if (lpszRet)
|
|
|
|
{
|
|
|
|
if (lpszStr)
|
|
|
|
memcpy(lpszRet, lpszStr, iLen);
|
|
|
|
else
|
|
|
|
*lpszRet = '\0';
|
|
|
|
}
|
|
|
|
return lpszRet;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* SHLWAPI_StrSpnHelperA
|
|
|
|
*
|
|
|
|
* Internal implementation of StrSpnA/StrCSpnA/StrCSpnIA
|
|
|
|
*/
|
2007-08-07 07:27:43 +00:00
|
|
|
static int SHLWAPI_StrSpnHelperA(LPCSTR lpszStr, LPCSTR lpszMatch,
|
|
|
|
LPSTR (WINAPI *pStrChrFn)(LPCSTR,WORD),
|
|
|
|
BOOL bInvert)
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
|
|
|
LPCSTR lpszRead = lpszStr;
|
|
|
|
if (lpszStr && *lpszStr && lpszMatch)
|
|
|
|
{
|
|
|
|
while (*lpszRead)
|
|
|
|
{
|
|
|
|
LPCSTR lpszTest = pStrChrFn(lpszMatch, *lpszRead);
|
|
|
|
|
|
|
|
if (!bInvert && !lpszTest)
|
|
|
|
break;
|
|
|
|
if (bInvert && lpszTest)
|
|
|
|
break;
|
|
|
|
lpszRead = CharNextA(lpszRead);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
return lpszRead - lpszStr;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* StrSpnA [SHLWAPI.@]
|
|
|
|
*
|
|
|
|
* Find the length of the start of a string that contains only certain
|
|
|
|
* characters.
|
|
|
|
*
|
|
|
|
* PARAMS
|
|
|
|
* lpszStr [I] String to search
|
|
|
|
* lpszMatch [I] Characters that can be in the substring
|
|
|
|
*
|
|
|
|
* RETURNS
|
|
|
|
* The length of the part of lpszStr containing only chars from lpszMatch,
|
|
|
|
* or 0 if any parameter is invalid.
|
|
|
|
*/
|
|
|
|
int WINAPI StrSpnA(LPCSTR lpszStr, LPCSTR lpszMatch)
|
|
|
|
{
|
|
|
|
TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
|
|
|
|
|
|
|
|
return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* StrSpnW [SHLWAPI.@]
|
|
|
|
*
|
|
|
|
* See StrSpnA.
|
|
|
|
*/
|
|
|
|
int WINAPI StrSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
|
|
|
|
{
|
2007-08-07 07:27:43 +00:00
|
|
|
if (!lpszStr || !lpszMatch) return 0;
|
|
|
|
return strspnW( lpszStr, lpszMatch );
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* StrCSpnA [SHLWAPI.@]
|
|
|
|
*
|
|
|
|
* Find the length of the start of a string that does not contain certain
|
|
|
|
* characters.
|
|
|
|
*
|
|
|
|
* PARAMS
|
|
|
|
* lpszStr [I] String to search
|
|
|
|
* lpszMatch [I] Characters that cannot be in the substring
|
|
|
|
*
|
|
|
|
* RETURNS
|
|
|
|
* The length of the part of lpszStr containing only chars not in lpszMatch,
|
|
|
|
* or 0 if any parameter is invalid.
|
|
|
|
*/
|
|
|
|
int WINAPI StrCSpnA(LPCSTR lpszStr, LPCSTR lpszMatch)
|
|
|
|
{
|
|
|
|
TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
|
|
|
|
|
|
|
|
return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* StrCSpnW [SHLWAPI.@]
|
|
|
|
*
|
|
|
|
* See StrCSpnA.
|
|
|
|
*/
|
|
|
|
int WINAPI StrCSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
|
|
|
|
{
|
2007-08-07 07:27:43 +00:00
|
|
|
if (!lpszStr || !lpszMatch) return 0;
|
|
|
|
return strcspnW( lpszStr, lpszMatch );
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* StrCSpnIA [SHLWAPI.@]
|
|
|
|
*
|
|
|
|
* Find the length of the start of a string that does not contain certain
|
|
|
|
* characters, ignoring case.
|
|
|
|
*
|
|
|
|
* PARAMS
|
|
|
|
* lpszStr [I] String to search
|
|
|
|
* lpszMatch [I] Characters that cannot be in the substring
|
|
|
|
*
|
|
|
|
* RETURNS
|
|
|
|
* The length of the part of lpszStr containing only chars not in lpszMatch,
|
|
|
|
* or 0 if any parameter is invalid.
|
|
|
|
*/
|
|
|
|
int WINAPI StrCSpnIA(LPCSTR lpszStr, LPCSTR lpszMatch)
|
|
|
|
{
|
|
|
|
TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
|
|
|
|
|
|
|
|
return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrIA, TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* StrCSpnIW [SHLWAPI.@]
|
|
|
|
*
|
|
|
|
* See StrCSpnIA.
|
|
|
|
*/
|
|
|
|
int WINAPI StrCSpnIW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
|
|
|
|
{
|
2007-08-07 07:27:43 +00:00
|
|
|
LPCWSTR lpszRead = lpszStr;
|
|
|
|
|
2005-07-31 12:11:56 +00:00
|
|
|
TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
|
|
|
|
|
2007-08-07 07:27:43 +00:00
|
|
|
if (lpszStr && *lpszStr && lpszMatch)
|
|
|
|
{
|
|
|
|
while (*lpszRead)
|
|
|
|
{
|
|
|
|
if (StrChrIW(lpszMatch, *lpszRead)) break;
|
|
|
|
lpszRead++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return lpszRead - lpszStr;
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* StrPBrkA [SHLWAPI.@]
|
|
|
|
*
|
|
|
|
* Search a string for any of a group of characters.
|
|
|
|
*
|
|
|
|
* PARAMS
|
|
|
|
* lpszStr [I] String to search
|
|
|
|
* lpszMatch [I] Characters to match
|
|
|
|
*
|
|
|
|
* RETURNS
|
|
|
|
* A pointer to the first matching character in lpszStr, or NULL if no
|
|
|
|
* match was found.
|
|
|
|
*/
|
|
|
|
LPSTR WINAPI StrPBrkA(LPCSTR lpszStr, LPCSTR lpszMatch)
|
|
|
|
{
|
|
|
|
TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
|
|
|
|
|
|
|
|
if (lpszStr && lpszMatch && *lpszMatch)
|
|
|
|
{
|
|
|
|
while (*lpszStr)
|
|
|
|
{
|
|
|
|
if (StrChrA(lpszMatch, *lpszStr))
|
|
|
|
return (LPSTR)lpszStr;
|
|
|
|
lpszStr = CharNextA(lpszStr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* StrPBrkW [SHLWAPI.@]
|
|
|
|
*
|
|
|
|
* See StrPBrkA.
|
|
|
|
*/
|
|
|
|
LPWSTR WINAPI StrPBrkW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
|
|
|
|
{
|
2007-08-07 07:27:43 +00:00
|
|
|
if (!lpszStr || !lpszMatch) return NULL;
|
|
|
|
return strpbrkW( lpszStr, lpszMatch );
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* SHLWAPI_StrRChrHelperA
|
|
|
|
*
|
|
|
|
* Internal implementation of StrRChrA/StrRChrIA.
|
|
|
|
*/
|
2007-08-07 07:27:43 +00:00
|
|
|
static LPSTR SHLWAPI_StrRChrHelperA(LPCSTR lpszStr,
|
|
|
|
LPCSTR lpszEnd, WORD ch,
|
|
|
|
BOOL (WINAPI *pChrCmpFn)(WORD,WORD))
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
|
|
|
LPCSTR lpszRet = NULL;
|
|
|
|
|
|
|
|
if (lpszStr)
|
|
|
|
{
|
|
|
|
WORD ch2;
|
|
|
|
|
|
|
|
if (!lpszEnd)
|
|
|
|
lpszEnd = lpszStr + lstrlenA(lpszStr);
|
|
|
|
|
|
|
|
while (*lpszStr && lpszStr <= lpszEnd)
|
|
|
|
{
|
|
|
|
ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr;
|
|
|
|
|
|
|
|
if (!pChrCmpFn(ch, ch2))
|
|
|
|
lpszRet = lpszStr;
|
|
|
|
lpszStr = CharNextA(lpszStr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return (LPSTR)lpszRet;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**************************************************************************
|
|
|
|
* StrRChrA [SHLWAPI.@]
|
|
|
|
*
|
|
|
|
* Find the last occurrence of a character in string.
|
|
|
|
*
|
|
|
|
* PARAMS
|
|
|
|
* lpszStr [I] String to search in
|
|
|
|
* lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
|
|
|
|
* ch [I] Character to search for.
|
|
|
|
*
|
|
|
|
* RETURNS
|
|
|
|
* Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
|
|
|
|
* or NULL if not found.
|
|
|
|
* Failure: NULL, if any arguments are invalid.
|
|
|
|
*/
|
|
|
|
LPSTR WINAPI StrRChrA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch)
|
|
|
|
{
|
|
|
|
TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch);
|
|
|
|
|
|
|
|
return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, SHLWAPI_ChrCmpA);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**************************************************************************
|
|
|
|
* StrRChrW [SHLWAPI.@]
|
|
|
|
*
|
|
|
|
* See StrRChrA.
|
|
|
|
*/
|
2007-08-07 07:27:43 +00:00
|
|
|
LPWSTR WINAPI StrRChrW(LPCWSTR str, LPCWSTR end, WORD ch)
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
2007-08-07 07:27:43 +00:00
|
|
|
WCHAR *ret = NULL;
|
2005-07-31 12:11:56 +00:00
|
|
|
|
2007-08-07 07:27:43 +00:00
|
|
|
if (!str) return NULL;
|
|
|
|
if (!end) end = str + strlenW(str);
|
|
|
|
while (str < end)
|
|
|
|
{
|
|
|
|
if (*str == ch) ret = (WCHAR *)str;
|
|
|
|
str++;
|
|
|
|
}
|
|
|
|
return ret;
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**************************************************************************
|
|
|
|
* StrRChrIA [SHLWAPI.@]
|
|
|
|
*
|
|
|
|
* Find the last occurrence of a character in string, ignoring case.
|
|
|
|
*
|
|
|
|
* PARAMS
|
|
|
|
* lpszStr [I] String to search in
|
|
|
|
* lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
|
|
|
|
* ch [I] Character to search for.
|
|
|
|
*
|
|
|
|
* RETURNS
|
|
|
|
* Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
|
|
|
|
* or NULL if not found.
|
|
|
|
* Failure: NULL, if any arguments are invalid.
|
|
|
|
*/
|
|
|
|
LPSTR WINAPI StrRChrIA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch)
|
|
|
|
{
|
|
|
|
TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch);
|
|
|
|
|
|
|
|
return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, ChrCmpIA);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**************************************************************************
|
|
|
|
* StrRChrIW [SHLWAPI.@]
|
|
|
|
*
|
|
|
|
* See StrRChrIA.
|
|
|
|
*/
|
2007-08-07 07:27:43 +00:00
|
|
|
LPWSTR WINAPI StrRChrIW(LPCWSTR str, LPCWSTR end, WORD ch)
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
2007-08-07 07:27:43 +00:00
|
|
|
WCHAR *ret = NULL;
|
2005-07-31 12:11:56 +00:00
|
|
|
|
2007-08-07 07:27:43 +00:00
|
|
|
if (!str) return NULL;
|
|
|
|
if (!end) end = str + strlenW(str);
|
|
|
|
while (str < end)
|
|
|
|
{
|
|
|
|
if (!ChrCmpIW(*str, ch)) ret = (WCHAR *)str;
|
|
|
|
str++;
|
|
|
|
}
|
|
|
|
return ret;
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* StrCatBuffA [SHLWAPI.@]
|
|
|
|
*
|
|
|
|
* Concatenate two strings together.
|
|
|
|
*
|
|
|
|
* PARAMS
|
|
|
|
* lpszStr [O] String to concatenate to
|
|
|
|
* lpszCat [I] String to add to lpszCat
|
|
|
|
* cchMax [I] Maximum number of characters for the whole string
|
|
|
|
*
|
|
|
|
* RETURNS
|
|
|
|
* lpszStr.
|
|
|
|
*
|
|
|
|
* NOTES
|
|
|
|
* cchMax determines the number of characters in the final length of the
|
|
|
|
* string, not the number appended to lpszStr from lpszCat.
|
|
|
|
*/
|
|
|
|
LPSTR WINAPI StrCatBuffA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax)
|
|
|
|
{
|
|
|
|
INT iLen;
|
|
|
|
|
|
|
|
TRACE("(%p,%s,%d)\n", lpszStr, debugstr_a(lpszCat), cchMax);
|
|
|
|
|
|
|
|
if (!lpszStr)
|
|
|
|
{
|
|
|
|
WARN("Invalid lpszStr would crash under Win32!\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
iLen = strlen(lpszStr);
|
|
|
|
cchMax -= iLen;
|
|
|
|
|
|
|
|
if (cchMax > 0)
|
|
|
|
StrCpyNA(lpszStr + iLen, lpszCat, cchMax);
|
|
|
|
return lpszStr;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* StrCatBuffW [SHLWAPI.@]
|
|
|
|
*
|
|
|
|
* See StrCatBuffA.
|
|
|
|
*/
|
|
|
|
LPWSTR WINAPI StrCatBuffW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax)
|
|
|
|
{
|
|
|
|
INT iLen;
|
|
|
|
|
|
|
|
TRACE("(%p,%s,%d)\n", lpszStr, debugstr_w(lpszCat), cchMax);
|
|
|
|
|
|
|
|
if (!lpszStr)
|
|
|
|
{
|
|
|
|
WARN("Invalid lpszStr would crash under Win32!\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
iLen = strlenW(lpszStr);
|
|
|
|
cchMax -= iLen;
|
|
|
|
|
|
|
|
if (cchMax > 0)
|
|
|
|
StrCpyNW(lpszStr + iLen, lpszCat, cchMax);
|
|
|
|
return lpszStr;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* StrRetToBufA [SHLWAPI.@]
|
|
|
|
*
|
|
|
|
* Convert a STRRET to a normal string.
|
|
|
|
*
|
|
|
|
* PARAMS
|
|
|
|
* lpStrRet [O] STRRET to convert
|
|
|
|
* pIdl [I] ITEMIDLIST for lpStrRet->uType == STRRET_OFFSET
|
|
|
|
* lpszDest [O] Destination for normal string
|
|
|
|
* dwLen [I] Length of lpszDest
|
|
|
|
*
|
|
|
|
* RETURNS
|
|
|
|
* Success: S_OK. lpszDest contains up to dwLen characters of the string.
|
|
|
|
* If lpStrRet is of type STRRET_WSTR, its memory is freed with
|
|
|
|
* CoTaskMemFree() and its type set to STRRET_CSTRA.
|
|
|
|
* Failure: E_FAIL, if any parameters are invalid.
|
|
|
|
*/
|
|
|
|
HRESULT WINAPI StrRetToBufA (LPSTRRET src, const ITEMIDLIST *pidl, LPSTR dest, UINT len)
|
|
|
|
{
|
|
|
|
/* NOTE:
|
|
|
|
* This routine is identical to that in dlls/shell32/shellstring.c.
|
|
|
|
* It was duplicated because not every version of Shlwapi.dll exports
|
|
|
|
* StrRetToBufA. If you change one routine, change them both.
|
|
|
|
*/
|
2012-09-29 13:14:20 +00:00
|
|
|
TRACE("dest=%p len=0x%x strret=%p pidl=%p\n", dest, len, src, pidl);
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
if (!src)
|
|
|
|
{
|
|
|
|
WARN("Invalid lpStrRet would crash under Win32!\n");
|
|
|
|
if (dest)
|
|
|
|
*dest = '\0';
|
|
|
|
return E_FAIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!dest || !len)
|
|
|
|
return E_FAIL;
|
|
|
|
|
|
|
|
*dest = '\0';
|
|
|
|
|
|
|
|
switch (src->uType)
|
|
|
|
{
|
|
|
|
case STRRET_WSTR:
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, dest, len, NULL, NULL);
|
|
|
|
CoTaskMemFree(src->u.pOleStr);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case STRRET_CSTR:
|
2009-01-31 14:48:46 +00:00
|
|
|
lstrcpynA(dest, src->u.cStr, len);
|
2005-07-31 12:11:56 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case STRRET_OFFSET:
|
|
|
|
lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
FIXME("unknown type!\n");
|
2016-11-17 23:06:15 +00:00
|
|
|
return E_NOTIMPL;
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* StrRetToBufW [SHLWAPI.@]
|
|
|
|
*
|
|
|
|
* See StrRetToBufA.
|
|
|
|
*/
|
|
|
|
HRESULT WINAPI StrRetToBufW (LPSTRRET src, const ITEMIDLIST *pidl, LPWSTR dest, UINT len)
|
|
|
|
{
|
2017-06-03 22:39:50 +00:00
|
|
|
TRACE("dest=%p len=0x%x strret=%p pidl=%p\n", dest, len, src, pidl);
|
2005-07-31 12:11:56 +00:00
|
|
|
|
2017-06-03 22:39:50 +00:00
|
|
|
if (!dest || !len)
|
|
|
|
return E_FAIL;
|
2005-07-31 12:11:56 +00:00
|
|
|
|
2017-06-03 22:39:50 +00:00
|
|
|
if (!src)
|
|
|
|
{
|
|
|
|
WARN("Invalid lpStrRet would crash under Win32!\n");
|
|
|
|
if (dest)
|
|
|
|
*dest = '\0';
|
|
|
|
return E_FAIL;
|
|
|
|
}
|
2005-07-31 12:11:56 +00:00
|
|
|
|
2017-06-03 22:39:50 +00:00
|
|
|
*dest = '\0';
|
|
|
|
|
|
|
|
switch (src->uType) {
|
|
|
|
case STRRET_WSTR: {
|
|
|
|
size_t dst_len;
|
|
|
|
if (!src->u.pOleStr)
|
|
|
|
return E_FAIL;
|
|
|
|
dst_len = strlenW(src->u.pOleStr);
|
|
|
|
memcpy(dest, src->u.pOleStr, min(dst_len, len-1) * sizeof(WCHAR));
|
|
|
|
dest[min(dst_len, len-1)] = 0;
|
|
|
|
CoTaskMemFree(src->u.pOleStr);
|
|
|
|
if (len <= dst_len)
|
|
|
|
{
|
|
|
|
dest[0] = 0;
|
|
|
|
return E_NOT_SUFFICIENT_BUFFER;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2005-07-31 12:11:56 +00:00
|
|
|
|
2017-06-03 22:39:50 +00:00
|
|
|
case STRRET_CSTR:
|
|
|
|
if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ))
|
|
|
|
dest[len-1] = 0;
|
|
|
|
break;
|
2005-07-31 12:11:56 +00:00
|
|
|
|
2017-06-03 22:39:50 +00:00
|
|
|
case STRRET_OFFSET:
|
|
|
|
if (pidl)
|
|
|
|
{
|
|
|
|
if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1,
|
|
|
|
dest, len ))
|
|
|
|
dest[len-1] = 0;
|
|
|
|
}
|
|
|
|
break;
|
2005-07-31 12:11:56 +00:00
|
|
|
|
2017-06-03 22:39:50 +00:00
|
|
|
default:
|
|
|
|
FIXME("unknown type!\n");
|
|
|
|
return E_NOTIMPL;
|
|
|
|
}
|
2005-07-31 12:11:56 +00:00
|
|
|
|
2017-06-03 22:39:50 +00:00
|
|
|
return S_OK;
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* StrRetToStrA [SHLWAPI.@]
|
|
|
|
*
|
|
|
|
* Converts a STRRET to a normal string.
|
|
|
|
*
|
|
|
|
* PARAMS
|
|
|
|
* lpStrRet [O] STRRET to convert
|
|
|
|
* pidl [I] ITEMIDLIST for lpStrRet->uType == STRRET_OFFSET
|
|
|
|
* ppszName [O] Destination for converted string
|
|
|
|
*
|
|
|
|
* RETURNS
|
|
|
|
* Success: S_OK. ppszName contains the new string, allocated with CoTaskMemAlloc().
|
|
|
|
* Failure: E_FAIL, if any parameters are invalid.
|
|
|
|
*/
|
|
|
|
HRESULT WINAPI StrRetToStrA(LPSTRRET lpStrRet, const ITEMIDLIST *pidl, LPSTR *ppszName)
|
|
|
|
{
|
|
|
|
HRESULT hRet = E_FAIL;
|
|
|
|
|
|
|
|
switch (lpStrRet->uType)
|
|
|
|
{
|
|
|
|
case STRRET_WSTR:
|
|
|
|
hRet = _SHStrDupAW(lpStrRet->u.pOleStr, ppszName);
|
|
|
|
CoTaskMemFree(lpStrRet->u.pOleStr);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case STRRET_CSTR:
|
|
|
|
hRet = _SHStrDupAA(lpStrRet->u.cStr, ppszName);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case STRRET_OFFSET:
|
|
|
|
hRet = _SHStrDupAA(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, ppszName);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
*ppszName = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return hRet;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* StrRetToStrW [SHLWAPI.@]
|
|
|
|
*
|
|
|
|
* See StrRetToStrA.
|
|
|
|
*/
|
|
|
|
HRESULT WINAPI StrRetToStrW(LPSTRRET lpStrRet, const ITEMIDLIST *pidl, LPWSTR *ppszName)
|
|
|
|
{
|
|
|
|
HRESULT hRet = E_FAIL;
|
|
|
|
|
|
|
|
switch (lpStrRet->uType)
|
|
|
|
{
|
|
|
|
case STRRET_WSTR:
|
|
|
|
hRet = SHStrDupW(lpStrRet->u.pOleStr, ppszName);
|
|
|
|
CoTaskMemFree(lpStrRet->u.pOleStr);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case STRRET_CSTR:
|
|
|
|
hRet = SHStrDupA(lpStrRet->u.cStr, ppszName);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case STRRET_OFFSET:
|
|
|
|
hRet = SHStrDupA(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, ppszName);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
*ppszName = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return hRet;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Create an ASCII string copy using SysAllocString() */
|
|
|
|
static HRESULT _SHStrDupAToBSTR(LPCSTR src, BSTR *pBstrOut)
|
|
|
|
{
|
|
|
|
*pBstrOut = NULL;
|
|
|
|
|
|
|
|
if (src)
|
|
|
|
{
|
|
|
|
INT len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0);
|
|
|
|
WCHAR* szTemp = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
|
|
|
|
|
|
|
|
if (szTemp)
|
|
|
|
{
|
|
|
|
MultiByteToWideChar(CP_ACP, 0, src, -1, szTemp, len);
|
|
|
|
*pBstrOut = SysAllocString(szTemp);
|
|
|
|
HeapFree(GetProcessHeap(), 0, szTemp);
|
|
|
|
|
|
|
|
if (*pBstrOut)
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return E_OUTOFMEMORY;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* StrRetToBSTR [SHLWAPI.@]
|
|
|
|
*
|
|
|
|
* Converts a STRRET to a BSTR.
|
|
|
|
*
|
|
|
|
* PARAMS
|
|
|
|
* lpStrRet [O] STRRET to convert
|
|
|
|
* pidl [I] ITEMIDLIST for lpStrRet->uType = STRRET_OFFSET
|
|
|
|
* pBstrOut [O] Destination for converted BSTR
|
|
|
|
*
|
|
|
|
* RETURNS
|
|
|
|
* Success: S_OK. pBstrOut contains the new string.
|
|
|
|
* Failure: E_FAIL, if any parameters are invalid.
|
|
|
|
*/
|
|
|
|
HRESULT WINAPI StrRetToBSTR(STRRET *lpStrRet, LPCITEMIDLIST pidl, BSTR* pBstrOut)
|
|
|
|
{
|
|
|
|
HRESULT hRet = E_FAIL;
|
|
|
|
|
|
|
|
switch (lpStrRet->uType)
|
|
|
|
{
|
|
|
|
case STRRET_WSTR:
|
|
|
|
*pBstrOut = SysAllocString(lpStrRet->u.pOleStr);
|
|
|
|
if (*pBstrOut)
|
|
|
|
hRet = S_OK;
|
|
|
|
CoTaskMemFree(lpStrRet->u.pOleStr);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case STRRET_CSTR:
|
|
|
|
hRet = _SHStrDupAToBSTR(lpStrRet->u.cStr, pBstrOut);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case STRRET_OFFSET:
|
|
|
|
hRet = _SHStrDupAToBSTR(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, pBstrOut);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
*pBstrOut = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return hRet;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* StrFormatKBSizeA [SHLWAPI.@]
|
|
|
|
*
|
|
|
|
* Create a formatted string containing a byte count in Kilobytes.
|
|
|
|
*
|
|
|
|
* PARAMS
|
|
|
|
* llBytes [I] Byte size to format
|
|
|
|
* lpszDest [I] Destination for formatted string
|
|
|
|
* cchMax [I] Size of lpszDest
|
|
|
|
*
|
|
|
|
* RETURNS
|
|
|
|
* lpszDest.
|
|
|
|
*/
|
|
|
|
LPSTR WINAPI StrFormatKBSizeA(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax)
|
|
|
|
{
|
2007-08-07 07:27:43 +00:00
|
|
|
WCHAR wszBuf[256];
|
2007-11-29 11:15:59 +00:00
|
|
|
|
2007-08-07 07:27:43 +00:00
|
|
|
if (!StrFormatKBSizeW(llBytes, wszBuf, 256))
|
|
|
|
return NULL;
|
|
|
|
if (!WideCharToMultiByte(CP_ACP, 0, wszBuf, -1, lpszDest, cchMax, NULL, NULL))
|
|
|
|
return NULL;
|
2005-07-31 12:11:56 +00:00
|
|
|
return lpszDest;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* StrFormatKBSizeW [SHLWAPI.@]
|
|
|
|
*
|
|
|
|
* See StrFormatKBSizeA.
|
|
|
|
*/
|
|
|
|
LPWSTR WINAPI StrFormatKBSizeW(LONGLONG llBytes, LPWSTR lpszDest, UINT cchMax)
|
|
|
|
{
|
2007-08-07 07:27:43 +00:00
|
|
|
static const WCHAR kb[] = {' ','K','B',0};
|
|
|
|
LONGLONG llKB = (llBytes + 1023) >> 10;
|
|
|
|
int len;
|
2005-07-31 12:11:56 +00:00
|
|
|
|
2007-08-07 07:27:43 +00:00
|
|
|
TRACE("(0x%s,%p,%d)\n", wine_dbgstr_longlong(llBytes), lpszDest, cchMax);
|
2005-07-31 12:11:56 +00:00
|
|
|
|
2007-08-07 07:27:43 +00:00
|
|
|
if (!FormatInt(llKB, lpszDest, cchMax))
|
|
|
|
return NULL;
|
2005-07-31 12:11:56 +00:00
|
|
|
|
2007-08-07 07:27:43 +00:00
|
|
|
len = lstrlenW(lpszDest);
|
|
|
|
if (cchMax - len < 4)
|
|
|
|
return NULL;
|
|
|
|
lstrcatW(lpszDest, kb);
|
2005-07-31 12:11:56 +00:00
|
|
|
return lpszDest;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* StrNCatA [SHLWAPI.@]
|
|
|
|
*
|
|
|
|
* Concatenate two strings together.
|
|
|
|
*
|
|
|
|
* PARAMS
|
|
|
|
* lpszStr [O] String to concatenate to
|
|
|
|
* lpszCat [I] String to add to lpszCat
|
|
|
|
* cchMax [I] Maximum number of characters to concatenate
|
|
|
|
*
|
|
|
|
* RETURNS
|
|
|
|
* lpszStr.
|
|
|
|
*
|
|
|
|
* NOTES
|
|
|
|
* cchMax determines the number of characters that are appended to lpszStr,
|
|
|
|
* not the total length of the string.
|
|
|
|
*/
|
|
|
|
LPSTR WINAPI StrNCatA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax)
|
|
|
|
{
|
|
|
|
LPSTR lpszRet = lpszStr;
|
|
|
|
|
|
|
|
TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszCat), cchMax);
|
|
|
|
|
|
|
|
if (!lpszStr)
|
|
|
|
{
|
|
|
|
WARN("Invalid lpszStr would crash under Win32!\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
StrCpyNA(lpszStr + strlen(lpszStr), lpszCat, cchMax);
|
|
|
|
return lpszRet;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* StrNCatW [SHLWAPI.@]
|
|
|
|
*
|
|
|
|
* See StrNCatA.
|
|
|
|
*/
|
|
|
|
LPWSTR WINAPI StrNCatW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax)
|
|
|
|
{
|
|
|
|
LPWSTR lpszRet = lpszStr;
|
|
|
|
|
|
|
|
TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszCat), cchMax);
|
|
|
|
|
|
|
|
if (!lpszStr)
|
|
|
|
{
|
|
|
|
WARN("Invalid lpszStr would crash under Win32\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
StrCpyNW(lpszStr + strlenW(lpszStr), lpszCat, cchMax);
|
|
|
|
return lpszRet;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* StrTrimA [SHLWAPI.@]
|
|
|
|
*
|
|
|
|
* Remove characters from the start and end of a string.
|
|
|
|
*
|
|
|
|
* PARAMS
|
|
|
|
* lpszStr [O] String to remove characters from
|
|
|
|
* lpszTrim [I] Characters to remove from lpszStr
|
|
|
|
*
|
|
|
|
* RETURNS
|
|
|
|
* TRUE If lpszStr was valid and modified
|
|
|
|
* FALSE Otherwise
|
|
|
|
*/
|
|
|
|
BOOL WINAPI StrTrimA(LPSTR lpszStr, LPCSTR lpszTrim)
|
|
|
|
{
|
|
|
|
DWORD dwLen;
|
|
|
|
LPSTR lpszRead = lpszStr;
|
|
|
|
BOOL bRet = FALSE;
|
|
|
|
|
|
|
|
TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszTrim));
|
|
|
|
|
|
|
|
if (lpszRead && *lpszRead)
|
|
|
|
{
|
|
|
|
while (*lpszRead && StrChrA(lpszTrim, *lpszRead))
|
|
|
|
lpszRead = CharNextA(lpszRead); /* Skip leading matches */
|
|
|
|
|
|
|
|
dwLen = strlen(lpszRead);
|
|
|
|
|
|
|
|
if (lpszRead != lpszStr)
|
|
|
|
{
|
|
|
|
memmove(lpszStr, lpszRead, dwLen + 1);
|
|
|
|
bRet = TRUE;
|
|
|
|
}
|
|
|
|
if (dwLen > 0)
|
|
|
|
{
|
|
|
|
lpszRead = lpszStr + dwLen;
|
|
|
|
while (StrChrA(lpszTrim, lpszRead[-1]))
|
|
|
|
lpszRead = CharPrevA(lpszStr, lpszRead); /* Skip trailing matches */
|
|
|
|
|
|
|
|
if (lpszRead != lpszStr + dwLen)
|
|
|
|
{
|
|
|
|
*lpszRead = '\0';
|
|
|
|
bRet = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return bRet;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* StrTrimW [SHLWAPI.@]
|
|
|
|
*
|
|
|
|
* See StrTrimA.
|
|
|
|
*/
|
|
|
|
BOOL WINAPI StrTrimW(LPWSTR lpszStr, LPCWSTR lpszTrim)
|
|
|
|
{
|
|
|
|
DWORD dwLen;
|
|
|
|
LPWSTR lpszRead = lpszStr;
|
|
|
|
BOOL bRet = FALSE;
|
|
|
|
|
|
|
|
TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszTrim));
|
|
|
|
|
|
|
|
if (lpszRead && *lpszRead)
|
|
|
|
{
|
2007-08-07 07:27:43 +00:00
|
|
|
while (*lpszRead && StrChrW(lpszTrim, *lpszRead)) lpszRead++;
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
dwLen = strlenW(lpszRead);
|
|
|
|
|
|
|
|
if (lpszRead != lpszStr)
|
|
|
|
{
|
|
|
|
memmove(lpszStr, lpszRead, (dwLen + 1) * sizeof(WCHAR));
|
|
|
|
bRet = TRUE;
|
|
|
|
}
|
|
|
|
if (dwLen > 0)
|
|
|
|
{
|
|
|
|
lpszRead = lpszStr + dwLen;
|
|
|
|
while (StrChrW(lpszTrim, lpszRead[-1]))
|
2007-08-07 07:27:43 +00:00
|
|
|
lpszRead--; /* Skip trailing matches */
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
if (lpszRead != lpszStr + dwLen)
|
|
|
|
{
|
|
|
|
*lpszRead = '\0';
|
|
|
|
bRet = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return bRet;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* _SHStrDupAA [INTERNAL]
|
|
|
|
*
|
|
|
|
* Duplicates a ASCII string to ASCII. The destination buffer is allocated.
|
|
|
|
*/
|
2007-08-07 07:27:43 +00:00
|
|
|
static HRESULT _SHStrDupAA(LPCSTR src, LPSTR * dest)
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
|
|
|
HRESULT hr;
|
|
|
|
int len = 0;
|
|
|
|
|
|
|
|
if (src) {
|
|
|
|
len = lstrlenA(src) + 1;
|
|
|
|
*dest = CoTaskMemAlloc(len);
|
|
|
|
} else {
|
|
|
|
*dest = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*dest) {
|
|
|
|
lstrcpynA(*dest,src, len);
|
|
|
|
hr = S_OK;
|
|
|
|
} else {
|
|
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
}
|
|
|
|
|
|
|
|
TRACE("%s->(%p)\n", debugstr_a(src), *dest);
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* SHStrDupA [SHLWAPI.@]
|
|
|
|
*
|
|
|
|
* Return a Unicode copy of a string, in memory allocated by CoTaskMemAlloc().
|
|
|
|
*
|
|
|
|
* PARAMS
|
|
|
|
* lpszStr [I] String to copy
|
|
|
|
* lppszDest [O] Destination for the new string copy
|
|
|
|
*
|
|
|
|
* RETURNS
|
|
|
|
* Success: S_OK. lppszDest contains the new string in Unicode format.
|
|
|
|
* Failure: E_OUTOFMEMORY, If any arguments are invalid or memory allocation
|
|
|
|
* fails.
|
|
|
|
*/
|
|
|
|
HRESULT WINAPI SHStrDupA(LPCSTR lpszStr, LPWSTR * lppszDest)
|
|
|
|
{
|
|
|
|
HRESULT hRet;
|
|
|
|
int len = 0;
|
|
|
|
|
|
|
|
if (lpszStr)
|
|
|
|
{
|
2013-03-24 12:35:51 +00:00
|
|
|
len = MultiByteToWideChar(CP_ACP, 0, lpszStr, -1, NULL, 0) * sizeof(WCHAR);
|
2005-07-31 12:11:56 +00:00
|
|
|
*lppszDest = CoTaskMemAlloc(len);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
*lppszDest = NULL;
|
|
|
|
|
|
|
|
if (*lppszDest)
|
|
|
|
{
|
2013-03-24 12:35:51 +00:00
|
|
|
MultiByteToWideChar(CP_ACP, 0, lpszStr, -1, *lppszDest, len/sizeof(WCHAR));
|
2005-07-31 12:11:56 +00:00
|
|
|
hRet = S_OK;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
hRet = E_OUTOFMEMORY;
|
|
|
|
|
|
|
|
TRACE("%s->(%p)\n", debugstr_a(lpszStr), *lppszDest);
|
|
|
|
return hRet;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* _SHStrDupAW [INTERNAL]
|
|
|
|
*
|
|
|
|
* Duplicates a UNICODE to a ASCII string. The destination buffer is allocated.
|
|
|
|
*/
|
2007-08-07 07:27:43 +00:00
|
|
|
static HRESULT _SHStrDupAW(LPCWSTR src, LPSTR * dest)
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
|
|
|
HRESULT hr;
|
|
|
|
int len = 0;
|
|
|
|
|
|
|
|
if (src) {
|
|
|
|
len = WideCharToMultiByte(CP_ACP, 0, src, -1, NULL, 0, NULL, NULL);
|
|
|
|
*dest = CoTaskMemAlloc(len);
|
|
|
|
} else {
|
|
|
|
*dest = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*dest) {
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, src, -1, *dest, len, NULL, NULL);
|
|
|
|
hr = S_OK;
|
|
|
|
} else {
|
|
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
}
|
|
|
|
|
|
|
|
TRACE("%s->(%p)\n", debugstr_w(src), *dest);
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* SHStrDupW [SHLWAPI.@]
|
|
|
|
*
|
|
|
|
* See SHStrDupA.
|
|
|
|
*/
|
|
|
|
HRESULT WINAPI SHStrDupW(LPCWSTR src, LPWSTR * dest)
|
|
|
|
{
|
|
|
|
HRESULT hr;
|
|
|
|
int len = 0;
|
|
|
|
|
|
|
|
if (src) {
|
|
|
|
len = (lstrlenW(src) + 1) * sizeof(WCHAR);
|
|
|
|
*dest = CoTaskMemAlloc(len);
|
|
|
|
} else {
|
|
|
|
*dest = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*dest) {
|
|
|
|
memcpy(*dest, src, len);
|
|
|
|
hr = S_OK;
|
|
|
|
} else {
|
|
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
}
|
|
|
|
|
|
|
|
TRACE("%s->(%p)\n", debugstr_w(src), *dest);
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* SHLWAPI_WriteReverseNum
|
|
|
|
*
|
|
|
|
* Internal helper for SHLWAPI_WriteTimeClass.
|
|
|
|
*/
|
2007-08-07 07:27:43 +00:00
|
|
|
static inline LPWSTR SHLWAPI_WriteReverseNum(LPWSTR lpszOut, DWORD dwNum)
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
|
|
|
*lpszOut-- = '\0';
|
|
|
|
|
|
|
|
/* Write a decimal number to a string, backwards */
|
|
|
|
do
|
|
|
|
{
|
|
|
|
DWORD dwNextDigit = dwNum % 10;
|
|
|
|
*lpszOut-- = '0' + dwNextDigit;
|
|
|
|
dwNum = (dwNum - dwNextDigit) / 10;
|
|
|
|
} while (dwNum > 0);
|
|
|
|
|
|
|
|
return lpszOut;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* SHLWAPI_FormatSignificant
|
|
|
|
*
|
|
|
|
* Internal helper for SHLWAPI_WriteTimeClass.
|
|
|
|
*/
|
2007-08-07 07:27:43 +00:00
|
|
|
static inline int SHLWAPI_FormatSignificant(LPWSTR lpszNum, int dwDigits)
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
|
|
|
/* Zero non significant digits, return remaining significant digits */
|
|
|
|
while (*lpszNum)
|
|
|
|
{
|
|
|
|
lpszNum++;
|
|
|
|
if (--dwDigits == 0)
|
|
|
|
{
|
|
|
|
while (*lpszNum)
|
|
|
|
*lpszNum++ = '0';
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return dwDigits;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* SHLWAPI_WriteTimeClass
|
|
|
|
*
|
|
|
|
* Internal helper for StrFromTimeIntervalW.
|
|
|
|
*/
|
2007-08-07 07:27:43 +00:00
|
|
|
static int SHLWAPI_WriteTimeClass(LPWSTR lpszOut, DWORD dwValue,
|
|
|
|
UINT uClassStringId, int iDigits)
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
|
|
|
WCHAR szBuff[64], *szOut = szBuff + 32;
|
|
|
|
|
|
|
|
szOut = SHLWAPI_WriteReverseNum(szOut, dwValue);
|
|
|
|
iDigits = SHLWAPI_FormatSignificant(szOut + 1, iDigits);
|
|
|
|
*szOut = ' ';
|
2007-08-07 07:27:43 +00:00
|
|
|
LoadStringW(shlwapi_hInstance, uClassStringId, szBuff + 32, 32);
|
2005-07-31 12:11:56 +00:00
|
|
|
strcatW(lpszOut, szOut);
|
|
|
|
return iDigits;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* StrFromTimeIntervalA [SHLWAPI.@]
|
|
|
|
*
|
|
|
|
* Format a millisecond time interval into a string
|
|
|
|
*
|
|
|
|
* PARAMS
|
|
|
|
* lpszStr [O] Output buffer for formatted time interval
|
|
|
|
* cchMax [I] Size of lpszStr
|
|
|
|
* dwMS [I] Number of milliseconds
|
|
|
|
* iDigits [I] Number of digits to print
|
|
|
|
*
|
|
|
|
* RETURNS
|
|
|
|
* The length of the formatted string, or 0 if any parameter is invalid.
|
|
|
|
*
|
|
|
|
* NOTES
|
|
|
|
* This implementation mimics the Win32 behaviour of always writing a leading
|
|
|
|
* space before the time interval begins.
|
|
|
|
*
|
|
|
|
* iDigits is used to provide approximate times if accuracy is not important.
|
|
|
|
* This number of digits will be written of the first non-zero time class
|
|
|
|
* (hours/minutes/seconds). If this does not complete the time classification,
|
|
|
|
* the remaining digits are changed to zeros (i.e. The time is _not_ rounded).
|
|
|
|
* If there are digits remaining following the writing of a time class, the
|
|
|
|
* next time class will be written.
|
|
|
|
*
|
|
|
|
* For example, given dwMS represents 138 hours,43 minutes and 15 seconds, the
|
|
|
|
* following will result from the given values of iDigits:
|
|
|
|
*
|
|
|
|
*| iDigits 1 2 3 4 5 ...
|
|
|
|
*| lpszStr "100 hr" "130 hr" "138 hr" "138 hr 40 min" "138 hr 43 min" ...
|
|
|
|
*/
|
|
|
|
INT WINAPI StrFromTimeIntervalA(LPSTR lpszStr, UINT cchMax, DWORD dwMS,
|
|
|
|
int iDigits)
|
|
|
|
{
|
|
|
|
INT iRet = 0;
|
|
|
|
|
2007-08-07 07:27:43 +00:00
|
|
|
TRACE("(%p,%d,%d,%d)\n", lpszStr, cchMax, dwMS, iDigits);
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
if (lpszStr && cchMax)
|
|
|
|
{
|
|
|
|
WCHAR szBuff[128];
|
|
|
|
StrFromTimeIntervalW(szBuff, sizeof(szBuff)/sizeof(WCHAR), dwMS, iDigits);
|
|
|
|
WideCharToMultiByte(CP_ACP,0,szBuff,-1,lpszStr,cchMax,0,0);
|
|
|
|
}
|
|
|
|
return iRet;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* StrFromTimeIntervalW [SHLWAPI.@]
|
|
|
|
*
|
|
|
|
* See StrFromTimeIntervalA.
|
|
|
|
*/
|
|
|
|
INT WINAPI StrFromTimeIntervalW(LPWSTR lpszStr, UINT cchMax, DWORD dwMS,
|
|
|
|
int iDigits)
|
|
|
|
{
|
|
|
|
INT iRet = 0;
|
|
|
|
|
2007-08-07 07:27:43 +00:00
|
|
|
TRACE("(%p,%d,%d,%d)\n", lpszStr, cchMax, dwMS, iDigits);
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
if (lpszStr && cchMax)
|
|
|
|
{
|
|
|
|
WCHAR szCopy[128];
|
|
|
|
DWORD dwHours, dwMinutes;
|
|
|
|
|
|
|
|
if (!iDigits || cchMax == 1)
|
|
|
|
{
|
|
|
|
*lpszStr = '\0';
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Calculate the time classes */
|
|
|
|
dwMS = (dwMS + 500) / 1000;
|
|
|
|
dwHours = dwMS / 3600;
|
|
|
|
dwMS -= dwHours * 3600;
|
|
|
|
dwMinutes = dwMS / 60;
|
|
|
|
dwMS -= dwMinutes * 60;
|
|
|
|
|
|
|
|
szCopy[0] = '\0';
|
|
|
|
|
|
|
|
if (dwHours)
|
2007-08-07 07:27:43 +00:00
|
|
|
iDigits = SHLWAPI_WriteTimeClass(szCopy, dwHours, IDS_TIME_INTERVAL_HOURS, iDigits);
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
if (dwMinutes && iDigits)
|
2007-08-07 07:27:43 +00:00
|
|
|
iDigits = SHLWAPI_WriteTimeClass(szCopy, dwMinutes, IDS_TIME_INTERVAL_MINUTES, iDigits);
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
if (iDigits) /* Always write seconds if we have significant digits */
|
2007-08-07 07:27:43 +00:00
|
|
|
SHLWAPI_WriteTimeClass(szCopy, dwMS, IDS_TIME_INTERVAL_SECONDS, iDigits);
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
lstrcpynW(lpszStr, szCopy, cchMax);
|
|
|
|
iRet = strlenW(lpszStr);
|
|
|
|
}
|
|
|
|
return iRet;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* StrIsIntlEqualA [SHLWAPI.@]
|
|
|
|
*
|
|
|
|
* Compare two strings.
|
|
|
|
*
|
|
|
|
* PARAMS
|
|
|
|
* bCase [I] Whether to compare case sensitively
|
|
|
|
* lpszStr [I] First string to compare
|
|
|
|
* lpszComp [I] Second string to compare
|
|
|
|
* iLen [I] Length to compare
|
|
|
|
*
|
|
|
|
* RETURNS
|
|
|
|
* TRUE If the strings are equal.
|
|
|
|
* FALSE Otherwise.
|
|
|
|
*/
|
|
|
|
BOOL WINAPI StrIsIntlEqualA(BOOL bCase, LPCSTR lpszStr, LPCSTR lpszComp,
|
|
|
|
int iLen)
|
|
|
|
{
|
|
|
|
DWORD dwFlags;
|
|
|
|
|
|
|
|
TRACE("(%d,%s,%s,%d)\n", bCase,
|
|
|
|
debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
|
|
|
|
|
|
|
|
/* FIXME: This flag is undocumented and unknown by our CompareString.
|
|
|
|
* We need a define for it.
|
|
|
|
*/
|
|
|
|
dwFlags = 0x10000000;
|
|
|
|
if (!bCase) dwFlags |= NORM_IGNORECASE;
|
|
|
|
|
|
|
|
return (CompareStringA(GetThreadLocale(), dwFlags, lpszStr, iLen, lpszComp, iLen) == CSTR_EQUAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* StrIsIntlEqualW [SHLWAPI.@]
|
|
|
|
*
|
|
|
|
* See StrIsIntlEqualA.
|
|
|
|
*/
|
|
|
|
BOOL WINAPI StrIsIntlEqualW(BOOL bCase, LPCWSTR lpszStr, LPCWSTR lpszComp,
|
|
|
|
int iLen)
|
|
|
|
{
|
|
|
|
DWORD dwFlags;
|
|
|
|
|
|
|
|
TRACE("(%d,%s,%s,%d)\n", bCase,
|
|
|
|
debugstr_w(lpszStr),debugstr_w(lpszComp), iLen);
|
|
|
|
|
|
|
|
/* FIXME: This flag is undocumented and unknown by our CompareString.
|
|
|
|
* We need a define for it.
|
|
|
|
*/
|
|
|
|
dwFlags = 0x10000000;
|
|
|
|
if (!bCase) dwFlags |= NORM_IGNORECASE;
|
|
|
|
|
|
|
|
return (CompareStringW(GetThreadLocale(), dwFlags, lpszStr, iLen, lpszComp, iLen) == CSTR_EQUAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* @ [SHLWAPI.399]
|
|
|
|
*
|
|
|
|
* Copy a string to another string, up to a maximum number of characters.
|
|
|
|
*
|
|
|
|
* PARAMS
|
|
|
|
* lpszDest [O] Destination string
|
|
|
|
* lpszSrc [I] Source string
|
|
|
|
* iLen [I] Maximum number of chars to copy
|
|
|
|
*
|
|
|
|
* RETURNS
|
2007-08-07 07:27:43 +00:00
|
|
|
* Success: A pointer to the last character written to lpszDest.
|
2005-07-31 12:11:56 +00:00
|
|
|
* Failure: lpszDest, if any arguments are invalid.
|
|
|
|
*/
|
|
|
|
LPSTR WINAPI StrCpyNXA(LPSTR lpszDest, LPCSTR lpszSrc, int iLen)
|
|
|
|
{
|
|
|
|
TRACE("(%p,%s,%i)\n", lpszDest, debugstr_a(lpszSrc), iLen);
|
|
|
|
|
|
|
|
if (lpszDest && lpszSrc && iLen > 0)
|
|
|
|
{
|
|
|
|
while ((iLen-- > 1) && *lpszSrc)
|
|
|
|
*lpszDest++ = *lpszSrc++;
|
|
|
|
if (iLen >= 0)
|
|
|
|
*lpszDest = '\0';
|
|
|
|
}
|
|
|
|
return lpszDest;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* @ [SHLWAPI.400]
|
|
|
|
*
|
|
|
|
* Unicode version of StrCpyNXA.
|
|
|
|
*/
|
|
|
|
LPWSTR WINAPI StrCpyNXW(LPWSTR lpszDest, LPCWSTR lpszSrc, int iLen)
|
|
|
|
{
|
|
|
|
TRACE("(%p,%s,%i)\n", lpszDest, debugstr_w(lpszSrc), iLen);
|
|
|
|
|
|
|
|
if (lpszDest && lpszSrc && iLen > 0)
|
|
|
|
{
|
|
|
|
while ((iLen-- > 1) && *lpszSrc)
|
|
|
|
*lpszDest++ = *lpszSrc++;
|
|
|
|
if (iLen >= 0)
|
|
|
|
*lpszDest = '\0';
|
|
|
|
}
|
|
|
|
return lpszDest;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* StrCmpLogicalW [SHLWAPI.@]
|
|
|
|
*
|
|
|
|
* Compare two strings, ignoring case and comparing digits as numbers.
|
|
|
|
*
|
|
|
|
* PARAMS
|
|
|
|
* lpszStr [I] First string to compare
|
|
|
|
* lpszComp [I] Second string to compare
|
|
|
|
* iLen [I] Length to compare
|
|
|
|
*
|
|
|
|
* RETURNS
|
|
|
|
* TRUE If the strings are equal.
|
|
|
|
* FALSE Otherwise.
|
|
|
|
*/
|
|
|
|
INT WINAPI StrCmpLogicalW(LPCWSTR lpszStr, LPCWSTR lpszComp)
|
|
|
|
{
|
|
|
|
INT iDiff;
|
|
|
|
|
|
|
|
TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszComp));
|
|
|
|
|
|
|
|
if (lpszStr && lpszComp)
|
|
|
|
{
|
|
|
|
while (*lpszStr)
|
|
|
|
{
|
|
|
|
if (!*lpszComp)
|
|
|
|
return 1;
|
|
|
|
else if (isdigitW(*lpszStr))
|
|
|
|
{
|
|
|
|
int iStr, iComp;
|
|
|
|
|
|
|
|
if (!isdigitW(*lpszComp))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* Compare the numbers */
|
|
|
|
StrToIntExW(lpszStr, 0, &iStr);
|
|
|
|
StrToIntExW(lpszComp, 0, &iComp);
|
|
|
|
|
|
|
|
if (iStr < iComp)
|
|
|
|
return -1;
|
|
|
|
else if (iStr > iComp)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
/* Skip */
|
|
|
|
while (isdigitW(*lpszStr))
|
|
|
|
lpszStr++;
|
|
|
|
while (isdigitW(*lpszComp))
|
|
|
|
lpszComp++;
|
|
|
|
}
|
|
|
|
else if (isdigitW(*lpszComp))
|
|
|
|
return 1;
|
|
|
|
else
|
|
|
|
{
|
2007-08-07 07:27:43 +00:00
|
|
|
iDiff = ChrCmpIW(*lpszStr,*lpszComp);
|
2005-07-31 12:11:56 +00:00
|
|
|
if (iDiff > 0)
|
|
|
|
return 1;
|
|
|
|
else if (iDiff < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
lpszStr++;
|
|
|
|
lpszComp++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (*lpszComp)
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Structure for formatting byte strings */
|
|
|
|
typedef struct tagSHLWAPI_BYTEFORMATS
|
|
|
|
{
|
|
|
|
LONGLONG dLimit;
|
|
|
|
double dDivisor;
|
|
|
|
double dNormaliser;
|
2007-08-07 07:27:43 +00:00
|
|
|
int nDecimals;
|
2005-07-31 12:11:56 +00:00
|
|
|
WCHAR wPrefix;
|
|
|
|
} SHLWAPI_BYTEFORMATS;
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* StrFormatByteSizeW [SHLWAPI.@]
|
|
|
|
*
|
|
|
|
* Create a string containing an abbreviated byte count of up to 2^63-1.
|
|
|
|
*
|
|
|
|
* PARAMS
|
|
|
|
* llBytes [I] Byte size to format
|
|
|
|
* lpszDest [I] Destination for formatted string
|
|
|
|
* cchMax [I] Size of lpszDest
|
|
|
|
*
|
|
|
|
* RETURNS
|
|
|
|
* lpszDest.
|
|
|
|
*
|
|
|
|
* NOTES
|
|
|
|
* There is no StrFormatByteSize64W function, it is called StrFormatByteSizeW().
|
|
|
|
*/
|
|
|
|
LPWSTR WINAPI StrFormatByteSizeW(LONGLONG llBytes, LPWSTR lpszDest, UINT cchMax)
|
|
|
|
{
|
|
|
|
#define KB ((ULONGLONG)1024)
|
|
|
|
#define MB (KB*KB)
|
|
|
|
#define GB (KB*KB*KB)
|
|
|
|
#define TB (KB*KB*KB*KB)
|
|
|
|
#define PB (KB*KB*KB*KB*KB)
|
|
|
|
|
|
|
|
static const SHLWAPI_BYTEFORMATS bfFormats[] =
|
|
|
|
{
|
2007-08-07 07:27:43 +00:00
|
|
|
{ 10*KB, 10.24, 100.0, 2, 'K' }, /* 10 KB */
|
|
|
|
{ 100*KB, 102.4, 10.0, 1, 'K' }, /* 100 KB */
|
|
|
|
{ 1000*KB, 1024.0, 1.0, 0, 'K' }, /* 1000 KB */
|
|
|
|
{ 10*MB, 10485.76, 100.0, 2, 'M' }, /* 10 MB */
|
|
|
|
{ 100*MB, 104857.6, 10.0, 1, 'M' }, /* 100 MB */
|
|
|
|
{ 1000*MB, 1048576.0, 1.0, 0, 'M' }, /* 1000 MB */
|
|
|
|
{ 10*GB, 10737418.24, 100.0, 2, 'G' }, /* 10 GB */
|
|
|
|
{ 100*GB, 107374182.4, 10.0, 1, 'G' }, /* 100 GB */
|
|
|
|
{ 1000*GB, 1073741824.0, 1.0, 0, 'G' }, /* 1000 GB */
|
|
|
|
{ 10*TB, 10485.76, 100.0, 2, 'T' }, /* 10 TB */
|
|
|
|
{ 100*TB, 104857.6, 10.0, 1, 'T' }, /* 100 TB */
|
|
|
|
{ 1000*TB, 1048576.0, 1.0, 0, 'T' }, /* 1000 TB */
|
|
|
|
{ 10*PB, 10737418.24, 100.00, 2, 'P' }, /* 10 PB */
|
|
|
|
{ 100*PB, 107374182.4, 10.00, 1, 'P' }, /* 100 PB */
|
|
|
|
{ 1000*PB, 1073741824.0, 1.00, 0, 'P' }, /* 1000 PB */
|
|
|
|
{ 0, 10995116277.76, 100.00, 2, 'E' } /* EB's, catch all */
|
2005-07-31 12:11:56 +00:00
|
|
|
};
|
|
|
|
WCHAR wszAdd[] = {' ','?','B',0};
|
|
|
|
double dBytes;
|
|
|
|
UINT i = 0;
|
|
|
|
|
2007-08-07 07:27:43 +00:00
|
|
|
TRACE("(0x%s,%p,%d)\n", wine_dbgstr_longlong(llBytes), lpszDest, cchMax);
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
if (!lpszDest || !cchMax)
|
|
|
|
return lpszDest;
|
|
|
|
|
|
|
|
if (llBytes < 1024) /* 1K */
|
|
|
|
{
|
2007-08-07 07:27:43 +00:00
|
|
|
WCHAR wszBytesFormat[64];
|
|
|
|
LoadStringW(shlwapi_hInstance, IDS_BYTES_FORMAT, wszBytesFormat, 64);
|
2012-09-29 13:14:20 +00:00
|
|
|
snprintfW(lpszDest, cchMax, wszBytesFormat, (int)llBytes);
|
2005-07-31 12:11:56 +00:00
|
|
|
return lpszDest;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Note that if this loop completes without finding a match, i will be
|
|
|
|
* pointing at the last entry, which is a catch all for > 1000 PB
|
|
|
|
*/
|
|
|
|
while (i < sizeof(bfFormats) / sizeof(SHLWAPI_BYTEFORMATS) - 1)
|
|
|
|
{
|
|
|
|
if (llBytes < bfFormats[i].dLimit)
|
|
|
|
break;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
/* Above 1 TB we encounter problems with FP accuracy. So for amounts above
|
|
|
|
* this number we integer shift down by 1 MB first. The table above has
|
|
|
|
* the divisors scaled down from the '< 10 TB' entry onwards, to account
|
|
|
|
* for this. We also add a small fudge factor to get the correct result for
|
|
|
|
* counts that lie exactly on a 1024 byte boundary.
|
|
|
|
*/
|
|
|
|
if (i > 8)
|
2012-09-29 13:14:20 +00:00
|
|
|
dBytes = (double)(llBytes >> 20) + 0.001; /* Scale down by 1 MB */
|
2005-07-31 12:11:56 +00:00
|
|
|
else
|
|
|
|
dBytes = (double)llBytes + 0.00001;
|
|
|
|
|
|
|
|
dBytes = floor(dBytes / bfFormats[i].dDivisor) / bfFormats[i].dNormaliser;
|
|
|
|
|
2007-08-07 07:27:43 +00:00
|
|
|
if (!FormatDouble(dBytes, bfFormats[i].nDecimals, lpszDest, cchMax))
|
|
|
|
return NULL;
|
2005-07-31 12:11:56 +00:00
|
|
|
wszAdd[1] = bfFormats[i].wPrefix;
|
2007-08-07 07:27:43 +00:00
|
|
|
StrCatBuffW(lpszDest, wszAdd, cchMax);
|
2005-07-31 12:11:56 +00:00
|
|
|
return lpszDest;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* StrFormatByteSize64A [SHLWAPI.@]
|
|
|
|
*
|
|
|
|
* See StrFormatByteSizeW.
|
|
|
|
*/
|
|
|
|
LPSTR WINAPI StrFormatByteSize64A(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax)
|
|
|
|
{
|
|
|
|
WCHAR wszBuff[32];
|
|
|
|
|
|
|
|
StrFormatByteSizeW(llBytes, wszBuff, sizeof(wszBuff)/sizeof(WCHAR));
|
|
|
|
|
|
|
|
if (lpszDest)
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, wszBuff, -1, lpszDest, cchMax, 0, 0);
|
|
|
|
return lpszDest;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* StrFormatByteSizeA [SHLWAPI.@]
|
|
|
|
*
|
|
|
|
* Create a string containing an abbreviated byte count of up to 2^31-1.
|
|
|
|
*
|
|
|
|
* PARAMS
|
|
|
|
* dwBytes [I] Byte size to format
|
|
|
|
* lpszDest [I] Destination for formatted string
|
|
|
|
* cchMax [I] Size of lpszDest
|
|
|
|
*
|
|
|
|
* RETURNS
|
|
|
|
* lpszDest.
|
|
|
|
*
|
|
|
|
* NOTES
|
|
|
|
* The Ascii and Unicode versions of this function accept a different
|
|
|
|
* integer type for dwBytes. See StrFormatByteSize64A().
|
|
|
|
*/
|
|
|
|
LPSTR WINAPI StrFormatByteSizeA(DWORD dwBytes, LPSTR lpszDest, UINT cchMax)
|
|
|
|
{
|
2007-08-07 07:27:43 +00:00
|
|
|
TRACE("(%d,%p,%d)\n", dwBytes, lpszDest, cchMax);
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
return StrFormatByteSize64A(dwBytes, lpszDest, cchMax);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* @ [SHLWAPI.162]
|
|
|
|
*
|
|
|
|
* Remove a hanging lead byte from the end of a string, if present.
|
|
|
|
*
|
|
|
|
* PARAMS
|
|
|
|
* lpStr [I] String to check for a hanging lead byte
|
|
|
|
* size [I] Length of lpStr
|
|
|
|
*
|
|
|
|
* RETURNS
|
|
|
|
* Success: The new length of the string. Any hanging lead bytes are removed.
|
|
|
|
* Failure: 0, if any parameters are invalid.
|
|
|
|
*/
|
|
|
|
DWORD WINAPI SHTruncateString(LPSTR lpStr, DWORD size)
|
|
|
|
{
|
|
|
|
if (lpStr && size)
|
|
|
|
{
|
|
|
|
LPSTR lastByte = lpStr + size - 1;
|
|
|
|
|
|
|
|
while(lpStr < lastByte)
|
|
|
|
lpStr += IsDBCSLeadByte(*lpStr) ? 2 : 1;
|
|
|
|
|
|
|
|
if(lpStr == lastByte && IsDBCSLeadByte(*lpStr))
|
|
|
|
{
|
|
|
|
*lpStr = '\0';
|
|
|
|
size--;
|
|
|
|
}
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* @ [SHLWAPI.203]
|
|
|
|
*
|
|
|
|
* Remove a single non-trailing ampersand ('&') from a string.
|
|
|
|
*
|
|
|
|
* PARAMS
|
|
|
|
* lpszStr [I/O] String to remove ampersand from.
|
|
|
|
*
|
|
|
|
* RETURNS
|
|
|
|
* The character after the first ampersand in lpszStr, or the first character
|
|
|
|
* in lpszStr if there is no ampersand in the string.
|
|
|
|
*/
|
|
|
|
char WINAPI SHStripMneumonicA(LPCSTR lpszStr)
|
|
|
|
{
|
|
|
|
LPSTR lpszIter, lpszTmp;
|
|
|
|
char ch;
|
|
|
|
|
|
|
|
TRACE("(%s)\n", debugstr_a(lpszStr));
|
|
|
|
|
|
|
|
ch = *lpszStr;
|
|
|
|
|
|
|
|
if ((lpszIter = StrChrA(lpszStr, '&')))
|
|
|
|
{
|
|
|
|
lpszTmp = CharNextA(lpszIter);
|
2012-09-29 13:14:20 +00:00
|
|
|
if (*lpszTmp)
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
|
|
|
if (*lpszTmp != '&')
|
|
|
|
ch = *lpszTmp;
|
|
|
|
|
2012-09-29 13:14:20 +00:00
|
|
|
memmove( lpszIter, lpszTmp, strlen(lpszTmp) + 1 );
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ch;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* @ [SHLWAPI.225]
|
|
|
|
*
|
|
|
|
* Unicode version of SHStripMneumonicA.
|
|
|
|
*/
|
|
|
|
WCHAR WINAPI SHStripMneumonicW(LPCWSTR lpszStr)
|
|
|
|
{
|
|
|
|
LPWSTR lpszIter, lpszTmp;
|
|
|
|
WCHAR ch;
|
|
|
|
|
|
|
|
TRACE("(%s)\n", debugstr_w(lpszStr));
|
|
|
|
|
|
|
|
ch = *lpszStr;
|
|
|
|
|
|
|
|
if ((lpszIter = StrChrW(lpszStr, '&')))
|
|
|
|
{
|
2007-08-07 07:27:43 +00:00
|
|
|
lpszTmp = lpszIter + 1;
|
2012-09-29 13:14:20 +00:00
|
|
|
if (*lpszTmp)
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
|
|
|
if (*lpszTmp != '&')
|
|
|
|
ch = *lpszTmp;
|
|
|
|
|
2012-09-29 13:14:20 +00:00
|
|
|
memmove( lpszIter, lpszTmp, (strlenW(lpszTmp) + 1) * sizeof(WCHAR) );
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ch;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* @ [SHLWAPI.216]
|
|
|
|
*
|
|
|
|
* Convert an Ascii string to Unicode.
|
|
|
|
*
|
|
|
|
* PARAMS
|
|
|
|
* dwCp [I] Code page for the conversion
|
|
|
|
* lpSrcStr [I] Source Ascii string to convert
|
|
|
|
* lpDstStr [O] Destination for converted Unicode string
|
|
|
|
* iLen [I] Length of lpDstStr
|
|
|
|
*
|
|
|
|
* RETURNS
|
|
|
|
* The return value of the MultiByteToWideChar() function called on lpSrcStr.
|
|
|
|
*/
|
|
|
|
DWORD WINAPI SHAnsiToUnicodeCP(DWORD dwCp, LPCSTR lpSrcStr, LPWSTR lpDstStr, int iLen)
|
|
|
|
{
|
|
|
|
DWORD dwRet;
|
|
|
|
|
|
|
|
dwRet = MultiByteToWideChar(dwCp, 0, lpSrcStr, -1, lpDstStr, iLen);
|
2007-08-07 07:27:43 +00:00
|
|
|
TRACE("%s->%s,ret=%d\n", debugstr_a(lpSrcStr), debugstr_w(lpDstStr), dwRet);
|
2005-07-31 12:11:56 +00:00
|
|
|
return dwRet;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* @ [SHLWAPI.215]
|
|
|
|
*
|
|
|
|
* Convert an Ascii string to Unicode.
|
|
|
|
*
|
|
|
|
* PARAMS
|
|
|
|
* lpSrcStr [I] Source Ascii string to convert
|
|
|
|
* lpDstStr [O] Destination for converted Unicode string
|
|
|
|
* iLen [I] Length of lpDstStr
|
|
|
|
*
|
|
|
|
* RETURNS
|
|
|
|
* The return value of the MultiByteToWideChar() function called on lpSrcStr.
|
|
|
|
*
|
|
|
|
* NOTES
|
|
|
|
* This function simply calls SHAnsiToUnicodeCP with code page CP_ACP.
|
|
|
|
*/
|
|
|
|
DWORD WINAPI SHAnsiToUnicode(LPCSTR lpSrcStr, LPWSTR lpDstStr, int iLen)
|
|
|
|
{
|
|
|
|
return SHAnsiToUnicodeCP(CP_ACP, lpSrcStr, lpDstStr, iLen);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* @ [SHLWAPI.218]
|
|
|
|
*
|
|
|
|
* Convert a Unicode string to Ascii.
|
|
|
|
*
|
|
|
|
* PARAMS
|
|
|
|
* CodePage [I] Code page to use for the conversion
|
|
|
|
* lpSrcStr [I] Source Unicode string to convert
|
|
|
|
* lpDstStr [O] Destination for converted Ascii string
|
2009-07-18 19:25:33 +00:00
|
|
|
* dstlen [I] Length of buffer at lpDstStr
|
2005-07-31 12:11:56 +00:00
|
|
|
*
|
|
|
|
* RETURNS
|
2009-07-18 19:25:33 +00:00
|
|
|
* Success: The length in bytes of the result at lpDstStr (including the terminator)
|
|
|
|
* Failure: When using CP_UTF8, CP_UTF7 or 0xc350 as codePage, 0 is returned and
|
|
|
|
* the result is not nul-terminated.
|
|
|
|
* When using a different codepage, the length in bytes of the truncated
|
|
|
|
* result at lpDstStr (including the terminator) is returned and
|
|
|
|
* lpDstStr is always nul-terminated.
|
|
|
|
*
|
2005-07-31 12:11:56 +00:00
|
|
|
*/
|
2009-07-18 19:25:33 +00:00
|
|
|
DWORD WINAPI SHUnicodeToAnsiCP(UINT CodePage, LPCWSTR lpSrcStr, LPSTR lpDstStr, int dstlen)
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
|
|
|
static const WCHAR emptyW[] = { '\0' };
|
|
|
|
int len , reqLen;
|
|
|
|
LPSTR mem;
|
|
|
|
|
2009-07-18 19:25:33 +00:00
|
|
|
if (!lpDstStr || !dstlen)
|
2005-07-31 12:11:56 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (!lpSrcStr)
|
|
|
|
lpSrcStr = emptyW;
|
|
|
|
|
|
|
|
*lpDstStr = '\0';
|
|
|
|
|
|
|
|
len = strlenW(lpSrcStr) + 1;
|
|
|
|
|
|
|
|
switch (CodePage)
|
|
|
|
{
|
|
|
|
case CP_WINUNICODE:
|
|
|
|
CodePage = CP_UTF8; /* Fall through... */
|
|
|
|
case 0x0000C350: /* FIXME: CP_ #define */
|
|
|
|
case CP_UTF7:
|
|
|
|
case CP_UTF8:
|
|
|
|
{
|
|
|
|
DWORD dwMode = 0;
|
2009-07-18 19:25:33 +00:00
|
|
|
INT lenW = len - 1;
|
|
|
|
INT needed = dstlen - 1;
|
|
|
|
HRESULT hr;
|
2005-07-31 12:11:56 +00:00
|
|
|
|
2009-07-18 19:25:33 +00:00
|
|
|
/* try the user supplied buffer first */
|
|
|
|
hr = ConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &lenW, lpDstStr, &needed);
|
|
|
|
if (hr == S_OK)
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
2009-07-18 19:25:33 +00:00
|
|
|
lpDstStr[needed] = '\0';
|
|
|
|
return needed + 1;
|
|
|
|
}
|
2005-07-31 12:11:56 +00:00
|
|
|
|
2009-07-18 19:25:33 +00:00
|
|
|
/* user buffer too small. exclude termination and copy as much as possible */
|
|
|
|
lenW = len;
|
|
|
|
hr = ConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &lenW, NULL, &needed);
|
|
|
|
needed++;
|
|
|
|
mem = HeapAlloc(GetProcessHeap(), 0, needed);
|
|
|
|
if (!mem)
|
|
|
|
return 0;
|
2005-07-31 12:11:56 +00:00
|
|
|
|
2009-07-18 19:25:33 +00:00
|
|
|
hr = ConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &len, mem, &needed);
|
|
|
|
if (hr == S_OK)
|
|
|
|
{
|
|
|
|
reqLen = SHTruncateString(mem, dstlen);
|
|
|
|
if (reqLen > 0) memcpy(lpDstStr, mem, reqLen-1);
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
2009-07-18 19:25:33 +00:00
|
|
|
HeapFree(GetProcessHeap(), 0, mem);
|
|
|
|
return 0;
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2009-07-18 19:25:33 +00:00
|
|
|
/* try the user supplied buffer first */
|
|
|
|
reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, lpDstStr, dstlen, NULL, NULL);
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
if (!reqLen && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
|
|
|
|
{
|
|
|
|
reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, NULL, 0, NULL, NULL);
|
|
|
|
if (reqLen)
|
|
|
|
{
|
|
|
|
mem = HeapAlloc(GetProcessHeap(), 0, reqLen);
|
|
|
|
if (mem)
|
|
|
|
{
|
2015-07-20 22:57:09 +00:00
|
|
|
WideCharToMultiByte(CodePage, 0, lpSrcStr, len, mem, reqLen, NULL, NULL);
|
2005-07-31 12:11:56 +00:00
|
|
|
|
2009-07-18 19:25:33 +00:00
|
|
|
reqLen = SHTruncateString(mem, dstlen -1);
|
2005-07-31 12:11:56 +00:00
|
|
|
reqLen++;
|
|
|
|
|
2009-07-18 19:25:33 +00:00
|
|
|
lstrcpynA(lpDstStr, mem, reqLen);
|
2005-07-31 12:11:56 +00:00
|
|
|
HeapFree(GetProcessHeap(), 0, mem);
|
2009-07-18 19:25:33 +00:00
|
|
|
lpDstStr[reqLen-1] = '\0';
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return reqLen;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* @ [SHLWAPI.217]
|
|
|
|
*
|
|
|
|
* Convert a Unicode string to Ascii.
|
|
|
|
*
|
|
|
|
* PARAMS
|
|
|
|
* lpSrcStr [I] Source Unicode string to convert
|
|
|
|
* lpDstStr [O] Destination for converted Ascii string
|
|
|
|
* iLen [O] Length of lpDstStr in characters
|
|
|
|
*
|
|
|
|
* RETURNS
|
|
|
|
* See SHUnicodeToAnsiCP
|
|
|
|
|
|
|
|
* NOTES
|
|
|
|
* This function simply calls SHUnicodeToAnsiCP() with CodePage = CP_ACP.
|
|
|
|
*/
|
|
|
|
INT WINAPI SHUnicodeToAnsi(LPCWSTR lpSrcStr, LPSTR lpDstStr, INT iLen)
|
|
|
|
{
|
2009-07-18 19:25:33 +00:00
|
|
|
return SHUnicodeToAnsiCP(CP_ACP, lpSrcStr, lpDstStr, iLen);
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* @ [SHLWAPI.345]
|
|
|
|
*
|
|
|
|
* Copy one string to another.
|
|
|
|
*
|
|
|
|
* PARAMS
|
|
|
|
* lpszSrc [I] Source string to copy
|
|
|
|
* lpszDst [O] Destination for copy
|
|
|
|
* iLen [I] Length of lpszDst in characters
|
|
|
|
*
|
|
|
|
* RETURNS
|
|
|
|
* The length of the copied string, including the terminating NUL. lpszDst
|
|
|
|
* contains iLen characters of lpszSrc.
|
|
|
|
*/
|
|
|
|
DWORD WINAPI SHAnsiToAnsi(LPCSTR lpszSrc, LPSTR lpszDst, int iLen)
|
|
|
|
{
|
|
|
|
LPSTR lpszRet;
|
|
|
|
|
|
|
|
TRACE("(%s,%p,0x%08x)\n", debugstr_a(lpszSrc), lpszDst, iLen);
|
|
|
|
|
|
|
|
lpszRet = StrCpyNXA(lpszDst, lpszSrc, iLen);
|
|
|
|
return lpszRet - lpszDst + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* @ [SHLWAPI.346]
|
|
|
|
*
|
|
|
|
* Unicode version of SSHAnsiToAnsi.
|
|
|
|
*/
|
|
|
|
DWORD WINAPI SHUnicodeToUnicode(LPCWSTR lpszSrc, LPWSTR lpszDst, int iLen)
|
|
|
|
{
|
|
|
|
LPWSTR lpszRet;
|
|
|
|
|
|
|
|
TRACE("(%s,%p,0x%08x)\n", debugstr_w(lpszSrc), lpszDst, iLen);
|
|
|
|
|
|
|
|
lpszRet = StrCpyNXW(lpszDst, lpszSrc, iLen);
|
|
|
|
return lpszRet - lpszDst + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* @ [SHLWAPI.364]
|
|
|
|
*
|
|
|
|
* Determine if an Ascii string converts to Unicode and back identically.
|
|
|
|
*
|
|
|
|
* PARAMS
|
|
|
|
* lpSrcStr [I] Source Unicode string to convert
|
|
|
|
* lpDst [O] Destination for resulting Ascii string
|
|
|
|
* iLen [I] Length of lpDst in characters
|
|
|
|
*
|
|
|
|
* RETURNS
|
|
|
|
* TRUE, since Ascii strings always convert identically.
|
|
|
|
*/
|
|
|
|
BOOL WINAPI DoesStringRoundTripA(LPCSTR lpSrcStr, LPSTR lpDst, INT iLen)
|
|
|
|
{
|
|
|
|
lstrcpynA(lpDst, lpSrcStr, iLen);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* @ [SHLWAPI.365]
|
|
|
|
*
|
|
|
|
* Determine if a Unicode string converts to Ascii and back identically.
|
|
|
|
*
|
|
|
|
* PARAMS
|
|
|
|
* lpSrcStr [I] Source Unicode string to convert
|
|
|
|
* lpDst [O] Destination for resulting Ascii string
|
|
|
|
* iLen [I] Length of lpDst in characters
|
|
|
|
*
|
|
|
|
* RETURNS
|
|
|
|
* TRUE, if lpSrcStr converts to Ascii and back identically,
|
|
|
|
* FALSE otherwise.
|
|
|
|
*/
|
|
|
|
BOOL WINAPI DoesStringRoundTripW(LPCWSTR lpSrcStr, LPSTR lpDst, INT iLen)
|
|
|
|
{
|
|
|
|
WCHAR szBuff[MAX_PATH];
|
|
|
|
|
|
|
|
SHUnicodeToAnsi(lpSrcStr, lpDst, iLen);
|
|
|
|
SHAnsiToUnicode(lpDst, szBuff, MAX_PATH);
|
|
|
|
return !strcmpW(lpSrcStr, szBuff);
|
|
|
|
}
|
2005-09-07 15:52:47 +00:00
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* SHLoadIndirectString [SHLWAPI.@]
|
|
|
|
*
|
2007-08-07 07:27:43 +00:00
|
|
|
* If passed a string that begins with '@', extract the string from the
|
2005-09-07 15:52:47 +00:00
|
|
|
* appropriate resource, otherwise do a straight copy.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
HRESULT WINAPI SHLoadIndirectString(LPCWSTR src, LPWSTR dst, UINT dst_len, void **reserved)
|
|
|
|
{
|
|
|
|
WCHAR *dllname = NULL;
|
|
|
|
HMODULE hmod = NULL;
|
|
|
|
HRESULT hr = E_FAIL;
|
|
|
|
|
|
|
|
TRACE("(%s %p %08x %p)\n", debugstr_w(src), dst, dst_len, reserved);
|
|
|
|
|
|
|
|
if(src[0] == '@')
|
|
|
|
{
|
|
|
|
WCHAR *index_str;
|
|
|
|
int index;
|
|
|
|
|
|
|
|
dst[0] = 0;
|
|
|
|
dllname = StrDupW(src + 1);
|
|
|
|
index_str = strchrW(dllname, ',');
|
|
|
|
|
|
|
|
if(!index_str) goto end;
|
|
|
|
|
|
|
|
*index_str = 0;
|
|
|
|
index_str++;
|
|
|
|
index = atoiW(index_str);
|
2007-11-29 11:15:59 +00:00
|
|
|
|
2005-09-07 15:52:47 +00:00
|
|
|
hmod = LoadLibraryW(dllname);
|
|
|
|
if(!hmod) goto end;
|
|
|
|
|
|
|
|
if(index < 0)
|
|
|
|
{
|
|
|
|
if(LoadStringW(hmod, -index, dst, dst_len))
|
|
|
|
hr = S_OK;
|
|
|
|
}
|
|
|
|
else
|
2007-08-07 07:27:43 +00:00
|
|
|
FIXME("can't handle non-negative indices (%d)\n", index);
|
2005-09-07 15:52:47 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if(dst != src)
|
|
|
|
lstrcpynW(dst, src, dst_len);
|
|
|
|
hr = S_OK;
|
|
|
|
}
|
|
|
|
|
2007-08-07 07:27:43 +00:00
|
|
|
TRACE("returning %s\n", debugstr_w(dst));
|
2005-09-07 15:52:47 +00:00
|
|
|
end:
|
|
|
|
if(hmod) FreeLibrary(hmod);
|
2014-04-24 16:07:14 +00:00
|
|
|
LocalFree(dllname);
|
2005-09-07 15:52:47 +00:00
|
|
|
return hr;
|
|
|
|
}
|
2013-03-24 12:35:51 +00:00
|
|
|
|
|
|
|
BOOL WINAPI IsCharSpaceA(CHAR c)
|
|
|
|
{
|
|
|
|
WORD CharType;
|
|
|
|
return GetStringTypeA(GetSystemDefaultLCID(), CT_CTYPE1, &c, 1, &CharType) && (CharType & C1_SPACE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* @ [SHLWAPI.29]
|
|
|
|
*
|
|
|
|
* Determine if a Unicode character is a space.
|
|
|
|
*
|
|
|
|
* PARAMS
|
|
|
|
* wc [I] Character to check.
|
|
|
|
*
|
|
|
|
* RETURNS
|
|
|
|
* TRUE, if wc is a space,
|
|
|
|
* FALSE otherwise.
|
|
|
|
*/
|
|
|
|
BOOL WINAPI IsCharSpaceW(WCHAR wc)
|
|
|
|
{
|
|
|
|
WORD CharType;
|
|
|
|
|
|
|
|
return GetStringTypeW(CT_CTYPE1, &wc, 1, &CharType) && (CharType & C1_SPACE);
|
|
|
|
}
|