shlwapi: Add implementation for StrCatChainW.
Based on a patch by Huw Campbell.
This commit is contained in:
parent
8dfe0ff251
commit
4b33a339cc
|
@ -86,7 +86,7 @@
|
||||||
@ stdcall SHRegSetUSValueW( wstr wstr long ptr long long) shlwapi.SHRegSetUSValueW
|
@ stdcall SHRegSetUSValueW( wstr wstr long ptr long long) shlwapi.SHRegSetUSValueW
|
||||||
@ stdcall StrCatBuffA(str str long) shlwapi.StrCatBuffA
|
@ stdcall StrCatBuffA(str str long) shlwapi.StrCatBuffA
|
||||||
@ stdcall StrCatBuffW(wstr wstr long) shlwapi.StrCatBuffW
|
@ stdcall StrCatBuffW(wstr wstr long) shlwapi.StrCatBuffW
|
||||||
@ stub StrCatChainW
|
@ stdcall StrCatChainW(ptr long long wstr) shlwapi.StrCatChainW
|
||||||
@ stdcall StrChrA(str long) shlwapi.StrChrA
|
@ stdcall StrChrA(str long) shlwapi.StrChrA
|
||||||
@ stdcall StrChrIA(str long) shlwapi.StrChrIA
|
@ stdcall StrChrIA(str long) shlwapi.StrChrIA
|
||||||
@ stdcall StrChrIW(wstr long) shlwapi.StrChrIW
|
@ stdcall StrChrIW(wstr long) shlwapi.StrChrIW
|
||||||
|
|
|
@ -759,6 +759,7 @@
|
||||||
@ stdcall StrCSpnW (wstr wstr)
|
@ stdcall StrCSpnW (wstr wstr)
|
||||||
@ stdcall StrCatBuffA (str str long)
|
@ stdcall StrCatBuffA (str str long)
|
||||||
@ stdcall StrCatBuffW (wstr wstr long)
|
@ stdcall StrCatBuffW (wstr wstr long)
|
||||||
|
@ stdcall StrCatChainW (ptr long long wstr)
|
||||||
@ stdcall StrCatW (ptr wstr)
|
@ stdcall StrCatW (ptr wstr)
|
||||||
@ stdcall StrChrA (str long)
|
@ stdcall StrChrA (str long)
|
||||||
@ stdcall StrChrIA (str long)
|
@ stdcall StrChrIA (str long)
|
||||||
|
|
|
@ -458,6 +458,47 @@ LPWSTR WINAPI StrCatW(LPWSTR lpszStr, LPCWSTR lpszSrc)
|
||||||
return lpszStr;
|
return lpszStr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* StrCpyW [SHLWAPI.@]
|
* StrCpyW [SHLWAPI.@]
|
||||||
*
|
*
|
||||||
|
|
|
@ -48,6 +48,7 @@ static DWORD (WINAPI *pSHAnsiToAnsi)(LPCSTR,LPSTR,int);
|
||||||
static DWORD (WINAPI *pSHUnicodeToUnicode)(LPCWSTR,LPWSTR,int);
|
static DWORD (WINAPI *pSHUnicodeToUnicode)(LPCWSTR,LPWSTR,int);
|
||||||
static LPSTR (WINAPI *pStrCatBuffA)(LPSTR,LPCSTR,INT);
|
static LPSTR (WINAPI *pStrCatBuffA)(LPSTR,LPCSTR,INT);
|
||||||
static LPWSTR (WINAPI *pStrCatBuffW)(LPWSTR,LPCWSTR,INT);
|
static LPWSTR (WINAPI *pStrCatBuffW)(LPWSTR,LPCWSTR,INT);
|
||||||
|
static DWORD (WINAPI *pStrCatChainW)(LPWSTR,DWORD,DWORD,LPCWSTR);
|
||||||
static LPSTR (WINAPI *pStrCpyNXA)(LPSTR,LPCSTR,int);
|
static LPSTR (WINAPI *pStrCpyNXA)(LPSTR,LPCSTR,int);
|
||||||
static LPWSTR (WINAPI *pStrCpyNXW)(LPWSTR,LPCWSTR,int);
|
static LPWSTR (WINAPI *pStrCpyNXW)(LPWSTR,LPCWSTR,int);
|
||||||
static LPSTR (WINAPI *pStrFormatByteSize64A)(LONGLONG,LPSTR,UINT);
|
static LPSTR (WINAPI *pStrFormatByteSize64A)(LONGLONG,LPSTR,UINT);
|
||||||
|
@ -1481,6 +1482,125 @@ static void test_StrStrNIW(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_StrCatChainW(void)
|
||||||
|
{
|
||||||
|
static const WCHAR deadbeefW[] = {'D','e','A','d','B','e','E','f',0};
|
||||||
|
static const WCHAR deadW[] = {'D','e','A','d',0};
|
||||||
|
static const WCHAR beefW[] = {'B','e','E','f',0};
|
||||||
|
|
||||||
|
WCHAR buf[32 + 1];
|
||||||
|
DWORD ret;
|
||||||
|
|
||||||
|
if (!pStrCatChainW)
|
||||||
|
{
|
||||||
|
win_skip("StrCatChainW is not available\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Test with NULL buffer */
|
||||||
|
ret = pStrCatChainW(NULL, 0, 0, beefW);
|
||||||
|
ok(ret == 0, "Expected StrCatChainW to return 0, got %u\n", ret);
|
||||||
|
|
||||||
|
/* Test with empty buffer */
|
||||||
|
memset(buf, 0x11, sizeof(buf));
|
||||||
|
ret = pStrCatChainW(buf, 0, 0, beefW);
|
||||||
|
ok(ret == 0, "Expected StrCatChainW to return 0, got %u\n", ret);
|
||||||
|
ok(buf[0] == 0x1111, "Expected buf[0] = 0x1111, got %x\n", buf[0]);
|
||||||
|
|
||||||
|
memcpy(buf, deadbeefW, sizeof(deadbeefW));
|
||||||
|
ret = pStrCatChainW(buf, 0, -1, beefW);
|
||||||
|
ok(ret == 8, "Expected StrCatChainW to return 8, got %u\n", ret);
|
||||||
|
ok(!memcmp(buf, deadbeefW, sizeof(deadbeefW)), "Buffer contains wrong data\n");
|
||||||
|
|
||||||
|
/* Append data to existing string with offset = -1 */
|
||||||
|
memset(buf, 0x11, sizeof(buf));
|
||||||
|
ret = pStrCatChainW(buf, 32, 0, deadW);
|
||||||
|
ok(ret == 4, "Expected StrCatChainW to return 4, got %u\n", ret);
|
||||||
|
ok(!memcmp(buf, deadW, sizeof(deadW)), "Buffer contains wrong data\n");
|
||||||
|
|
||||||
|
ret = pStrCatChainW(buf, 32, -1, beefW);
|
||||||
|
ok(ret == 8, "Expected StrCatChainW to return 8, got %u\n", ret);
|
||||||
|
ok(!memcmp(buf, deadbeefW, sizeof(deadbeefW)), "Buffer contains wrong data\n");
|
||||||
|
|
||||||
|
/* Append data at a fixed offset */
|
||||||
|
memset(buf, 0x11, sizeof(buf));
|
||||||
|
ret = pStrCatChainW(buf, 32, 0, deadW);
|
||||||
|
ok(ret == 4, "Expected StrCatChainW to return 4, got %u\n", ret);
|
||||||
|
ok(!memcmp(buf, deadW, sizeof(deadW)), "Buffer contains wrong data\n");
|
||||||
|
|
||||||
|
ret = pStrCatChainW(buf, 32, 4, beefW);
|
||||||
|
ok(ret == 8, "Expected StrCatChainW to return 8, got %u\n", ret);
|
||||||
|
ok(!memcmp(buf, deadbeefW, sizeof(deadbeefW)), "Buffer contains wrong data\n");
|
||||||
|
|
||||||
|
/* Buffer exactly sufficient for string + terminating null */
|
||||||
|
memset(buf, 0x11, sizeof(buf));
|
||||||
|
ret = pStrCatChainW(buf, 5, 0, deadW);
|
||||||
|
ok(ret == 4, "Expected StrCatChainW to return 4, got %u\n", ret);
|
||||||
|
ok(!memcmp(buf, deadW, sizeof(deadW)), "Buffer contains wrong data\n");
|
||||||
|
|
||||||
|
/* Buffer too small, string will be truncated */
|
||||||
|
memset(buf, 0x11, sizeof(buf));
|
||||||
|
ret = pStrCatChainW(buf, 4, 0, deadW);
|
||||||
|
if (ret == 4)
|
||||||
|
{
|
||||||
|
/* Windows 2000 and XP uses a slightly different implementation
|
||||||
|
* for StrCatChainW, which doesn't ensure that strings are null-
|
||||||
|
* terminated. Skip test if we detect such an implementation. */
|
||||||
|
win_skip("Windows2000/XP behaviour detected for StrCatChainW, skipping tests\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ok(ret == 3, "Expected StrCatChainW to return 3, got %u\n", ret);
|
||||||
|
ok(!memcmp(buf, deadW, 3 * sizeof(WCHAR)), "Buffer contains wrong data\n");
|
||||||
|
ok(!buf[3], "String is not nullterminated\n");
|
||||||
|
ok(buf[4] == 0x1111, "Expected buf[4] = 0x1111, got %x\n", buf[4]);
|
||||||
|
|
||||||
|
/* Overwrite part of an existing string */
|
||||||
|
ret = pStrCatChainW(buf, 4, 1, beefW);
|
||||||
|
ok(ret == 3, "Expected StrCatChainW to return 3, got %u\n", ret);
|
||||||
|
ok(buf[0] == 'D', "Expected buf[0] = 'D', got %x\n", buf[0]);
|
||||||
|
ok(buf[1] == 'B', "Expected buf[1] = 'B', got %x\n", buf[1]);
|
||||||
|
ok(buf[2] == 'e', "Expected buf[2] = 'e', got %x\n", buf[2]);
|
||||||
|
ok(!buf[3], "String is not nullterminated\n");
|
||||||
|
ok(buf[4] == 0x1111, "Expected buf[4] = 0x1111, got %x\n", buf[4]);
|
||||||
|
|
||||||
|
/* Test appending to full buffer */
|
||||||
|
memset(buf, 0x11, sizeof(buf));
|
||||||
|
memcpy(buf, deadbeefW, sizeof(deadbeefW));
|
||||||
|
memcpy(buf + 9, deadW, sizeof(deadW));
|
||||||
|
ret = pStrCatChainW(buf, 9, 8, beefW);
|
||||||
|
ok(ret == 8, "Expected StrCatChainW to return 8, got %u\n", ret);
|
||||||
|
ok(!memcmp(buf, deadbeefW, sizeof(deadbeefW)), "Buffer contains wrong data\n");
|
||||||
|
ok(!memcmp(buf + 9, deadW, sizeof(deadW)), "Buffer contains wrong data\n");
|
||||||
|
|
||||||
|
/* Offset points at the end of the buffer */
|
||||||
|
ret = pStrCatChainW(buf, 9, 9, beefW);
|
||||||
|
ok(ret == 8, "Expected StrCatChainW to return 8, got %u\n", ret);
|
||||||
|
ok(!memcmp(buf, deadbeefW, sizeof(deadbeefW)), "Buffer contains wrong data\n");
|
||||||
|
ok(!memcmp(buf + 9, deadW, sizeof(deadW)), "Buffer contains wrong data\n");
|
||||||
|
|
||||||
|
/* Offset points outside of the buffer */
|
||||||
|
ret = pStrCatChainW(buf, 9, 10, beefW);
|
||||||
|
ok(ret == 10, "Expected StrCatChainW to return 10, got %u\n", ret);
|
||||||
|
ok(!memcmp(buf, deadbeefW, sizeof(deadbeefW)), "Buffer contains wrong data\n");
|
||||||
|
ok(!memcmp(buf + 9, deadW, sizeof(deadW)), "Buffer contains wrong data\n");
|
||||||
|
|
||||||
|
/* The same but without nullterminated string */
|
||||||
|
memcpy(buf, deadbeefW, sizeof(deadbeefW));
|
||||||
|
ret = pStrCatChainW(buf, 5, -1, deadW);
|
||||||
|
ok(ret == 8, "Expected StrCatChainW to return 8, got %u\n", ret);
|
||||||
|
ok(!memcmp(buf, deadbeefW, sizeof(deadbeefW)), "Buffer contains wrong data\n");
|
||||||
|
|
||||||
|
ret = pStrCatChainW(buf, 5, 5, deadW);
|
||||||
|
ok(ret == 4, "Expected StrCatChainW to return 4, got %u\n", ret);
|
||||||
|
ok(!memcmp(buf, deadW, sizeof(deadW)), "Buffer contains wrong data\n");
|
||||||
|
ok(buf[5] == 'e', "Expected buf[5] = 'e', got %x\n", buf[5]);
|
||||||
|
|
||||||
|
ret = pStrCatChainW(buf, 5, 6, deadW);
|
||||||
|
ok(ret == 6, "Expected StrCatChainW to return 6, got %u\n", ret);
|
||||||
|
ok(!memcmp(buf, deadW, sizeof(deadW)), "Buffer contains wrong data\n");
|
||||||
|
ok(buf[5] == 'e', "Expected buf[5] = 'e', got %x\n", buf[5]);
|
||||||
|
}
|
||||||
|
|
||||||
START_TEST(string)
|
START_TEST(string)
|
||||||
{
|
{
|
||||||
HMODULE hShlwapi;
|
HMODULE hShlwapi;
|
||||||
|
@ -1500,6 +1620,7 @@ START_TEST(string)
|
||||||
pSHUnicodeToUnicode = (void *)GetProcAddress(hShlwapi, (LPSTR)346);
|
pSHUnicodeToUnicode = (void *)GetProcAddress(hShlwapi, (LPSTR)346);
|
||||||
pStrCatBuffA = (void *)GetProcAddress(hShlwapi, "StrCatBuffA");
|
pStrCatBuffA = (void *)GetProcAddress(hShlwapi, "StrCatBuffA");
|
||||||
pStrCatBuffW = (void *)GetProcAddress(hShlwapi, "StrCatBuffW");
|
pStrCatBuffW = (void *)GetProcAddress(hShlwapi, "StrCatBuffW");
|
||||||
|
pStrCatChainW = (void *)GetProcAddress(hShlwapi, "StrCatChainW");
|
||||||
pStrCpyNXA = (void *)GetProcAddress(hShlwapi, (LPSTR)399);
|
pStrCpyNXA = (void *)GetProcAddress(hShlwapi, (LPSTR)399);
|
||||||
pStrCpyNXW = (void *)GetProcAddress(hShlwapi, (LPSTR)400);
|
pStrCpyNXW = (void *)GetProcAddress(hShlwapi, (LPSTR)400);
|
||||||
pStrChrNW = (void *)GetProcAddress(hShlwapi, "StrChrNW");
|
pStrChrNW = (void *)GetProcAddress(hShlwapi, "StrChrNW");
|
||||||
|
@ -1565,6 +1686,7 @@ START_TEST(string)
|
||||||
test_StrStrIW();
|
test_StrStrIW();
|
||||||
test_StrStrNW();
|
test_StrStrNW();
|
||||||
test_StrStrNIW();
|
test_StrStrNIW();
|
||||||
|
test_StrCatChainW();
|
||||||
|
|
||||||
CoUninitialize();
|
CoUninitialize();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue