Commit 7513b583 authored by Nikolay Sivov's avatar Nikolay Sivov Committed by Alexandre Julliard

shlwapi: Implement PathUnExpandEnvStrings.

parent c1a5b06d
......@@ -58,6 +58,21 @@ static fnpIsNetDrive pIsNetDrive;
HRESULT WINAPI SHGetWebFolderFilePathW(LPCWSTR,LPWSTR,DWORD);
static inline WCHAR* heap_strdupAtoW(LPCSTR str)
{
WCHAR *ret = NULL;
if (str)
{
DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
ret = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
if (ret)
MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
}
return ret;
}
/*************************************************************************
* PathAppendA [SHLWAPI.@]
*
......@@ -4040,18 +4055,61 @@ VOID WINAPI PathUndecorateW(LPWSTR lpszPath)
* strings.
*
* PARAMS
* pszPath [I] Buffer containing the path to unexpand.
* pszBuf [O] Buffer to receive the unexpanded path.
* cchBuf [I] Size of pszBuf in characters.
* path [I] Buffer containing the path to unexpand.
* buffer [O] Buffer to receive the unexpanded path.
* buf_len [I] Size of pszBuf in characters.
*
* RETURNS
* Success: TRUE
* Failure: FALSE
*/
BOOL WINAPI PathUnExpandEnvStringsA(LPCSTR pszPath, LPSTR pszBuf, UINT cchBuf)
BOOL WINAPI PathUnExpandEnvStringsA(LPCSTR path, LPSTR buffer, UINT buf_len)
{
FIXME("(%s,%s,0x%08x)\n", debugstr_a(pszPath), debugstr_a(pszBuf), cchBuf);
return FALSE;
WCHAR bufferW[MAX_PATH], *pathW;
DWORD len;
BOOL ret;
TRACE("(%s, %p, %d)\n", debugstr_a(path), buffer, buf_len);
pathW = heap_strdupAtoW(path);
if (!pathW) return FALSE;
ret = PathUnExpandEnvStringsW(pathW, bufferW, MAX_PATH);
HeapFree(GetProcessHeap(), 0, pathW);
if (!ret) return FALSE;
len = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
if (buf_len < len + 1) return FALSE;
WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, buf_len, NULL, NULL);
return TRUE;
}
static const WCHAR allusersprofileW[] = {'%','A','L','L','U','S','E','R','S','P','R','O','F','I','L','E','%',0};
static const WCHAR appdataW[] = {'%','A','P','P','D','A','T','A','%',0};
static const WCHAR computernameW[] = {'%','C','O','M','P','U','T','E','R','N','A','M','E','%',0};
static const WCHAR programfilesW[] = {'%','P','r','o','g','r','a','m','F','i','l','e','s','%',0};
static const WCHAR systemrootW[] = {'%','S','y','s','t','e','m','R','o','o','t','%',0};
static const WCHAR systemdriveW[] = {'%','S','y','s','t','e','m','D','r','i','v','e','%',0};
static const WCHAR userprofileW[] = {'%','U','S','E','R','P','R','O','F','I','L','E','%',0};
struct envvars_map
{
const WCHAR *var;
UINT varlen;
WCHAR path[MAX_PATH];
DWORD len;
};
static void init_envvars_map(struct envvars_map *map)
{
while (map->var)
{
map->len = ExpandEnvironmentStringsW(map->var, map->path, sizeof(map->path)/sizeof(WCHAR));
/* exclude null from length */
if (map->len) map->len--;
map++;
}
}
/*************************************************************************
......@@ -4059,10 +4117,51 @@ BOOL WINAPI PathUnExpandEnvStringsA(LPCSTR pszPath, LPSTR pszBuf, UINT cchBuf)
*
* Unicode version of PathUnExpandEnvStringsA.
*/
BOOL WINAPI PathUnExpandEnvStringsW(LPCWSTR pszPath, LPWSTR pszBuf, UINT cchBuf)
BOOL WINAPI PathUnExpandEnvStringsW(LPCWSTR path, LPWSTR buffer, UINT buf_len)
{
FIXME("(%s,%s,0x%08x)\n", debugstr_w(pszPath), debugstr_w(pszBuf), cchBuf);
return FALSE;
static struct envvars_map null_var = {NULL, 0, {0}, 0};
struct envvars_map *match = &null_var, *cur;
struct envvars_map envvars[] = {
{ allusersprofileW, sizeof(allusersprofileW)/sizeof(WCHAR) },
{ appdataW, sizeof(appdataW)/sizeof(WCHAR) },
{ computernameW, sizeof(computernameW)/sizeof(WCHAR) },
{ programfilesW, sizeof(programfilesW)/sizeof(WCHAR) },
{ systemrootW, sizeof(systemrootW)/sizeof(WCHAR) },
{ systemdriveW, sizeof(systemdriveW)/sizeof(WCHAR) },
{ userprofileW, sizeof(userprofileW)/sizeof(WCHAR) },
{ NULL }
};
DWORD pathlen;
UINT needed;
TRACE("(%s, %p, %d)\n", debugstr_w(path), buffer, buf_len);
pathlen = strlenW(path);
init_envvars_map(envvars);
cur = envvars;
while (cur->var)
{
/* path can't contain expanded value or value wasn't retrieved */
if (cur->len == 0 || cur->len > pathlen || strncmpiW(cur->path, path, cur->len))
{
cur++;
continue;
}
if (cur->len > match->len)
match = cur;
cur++;
}
/* 'varlen' includes NULL termination char */
needed = match->varlen + pathlen - match->len;
if (match->len == 0 || needed > buf_len) return FALSE;
strcpyW(buffer, match->var);
strcatW(buffer, &path[match->len]);
TRACE("ret %s\n", debugstr_w(buffer));
return TRUE;
}
/*************************************************************************
......
......@@ -34,6 +34,8 @@ static HRESULT (WINAPI *pPathCreateFromUrlA)(LPCSTR, LPSTR, LPDWORD, DWORD);
static HRESULT (WINAPI *pPathCreateFromUrlW)(LPCWSTR, LPWSTR, LPDWORD, DWORD);
static HRESULT (WINAPI *pPathCreateFromUrlAlloc)(LPCWSTR, LPWSTR*, DWORD);
static BOOL (WINAPI *pPathAppendA)(LPSTR, LPCSTR);
static BOOL (WINAPI *pPathUnExpandEnvStringsA)(LPCSTR, LPSTR, UINT);
static BOOL (WINAPI *pPathUnExpandEnvStringsW)(LPCWSTR, LPWSTR, UINT);
/* ################ */
......@@ -1452,7 +1454,136 @@ static void test_PathGetDriveNumber(void)
ok(ret == -1, "got %d\n", ret);
}
/* ################ */
static void test_PathUnExpandEnvStrings(void)
{
static const WCHAR sysrootW[] = {'%','S','y','s','t','e','m','R','o','o','t','%',0};
static const WCHAR sysdriveW[] = {'%','S','y','s','t','e','m','D','r','i','v','e','%',0};
static const WCHAR nonpathW[] = {'p','a','t','h',0};
static const char sysrootA[] = "%SystemRoot%";
static const char sysdriveA[] = "%SystemDrive%";
WCHAR pathW[MAX_PATH], buffW[MAX_PATH], sysdrvW[3];
char path[MAX_PATH], buff[MAX_PATH], sysdrvA[3], envvarA[10];
BOOL ret;
UINT len;
if (!pPathUnExpandEnvStringsA || !pPathUnExpandEnvStringsW)
{
win_skip("PathUnExpandEnvStrings not available\n");
return;
}
/* something that can't be represented with env var */
strcpy(path, "somepath_name");
strcpy(buff, "xx");
SetLastError(0xdeadbeef);
ret = pPathUnExpandEnvStringsA(path, buff, sizeof(buff));
ok(!ret && GetLastError() == 0xdeadbeef, "got %d, error %d\n", ret, GetLastError());
ok(buff[0] == 'x', "wrong return string %s\n", buff);
len = GetSystemDirectoryA(path, MAX_PATH);
ok(len > 0, "failed to get sysdir\n");
sysdrvA[0] = path[0];
strcpy(&sysdrvA[1], ":");
/* buffer size is not enough */
strcpy(buff, "xx");
SetLastError(0xdeadbeef);
ret = pPathUnExpandEnvStringsA(path, buff, 5);
ok(!ret && GetLastError() == 0xdeadbeef, "got %d\n", ret);
ok(buff[0] == 'x', "wrong return string %s\n", buff);
/* buffer size is enough to hold variable name only */
strcpy(buff, "xx");
SetLastError(0xdeadbeef);
ret = pPathUnExpandEnvStringsA(path, buff, sizeof(sysrootA));
ok(!ret && GetLastError() == 0xdeadbeef, "got %d, error %d\n", ret, GetLastError());
ok(buff[0] == 'x', "wrong return string %s\n", buff);
/* enough size */
buff[0] = 0;
ret = pPathUnExpandEnvStringsA(path, buff, sizeof(buff));
ok(ret, "got %d\n", ret);
ok(!strncmp(buff, sysrootA, sizeof(sysrootA)-1), "wrong return string %s\n", buff);
/* expanded value occurs multiple times */
/* for drive C: it's unexpands it like 'C:C:' -> '%SystemDrive%C:' */
buff[0] = 0;
strcpy(path, sysdrvA);
strcat(path, sysdrvA);
ret = pPathUnExpandEnvStringsA(path, buff, sizeof(buff));
ok(ret, "got %d\n", ret);
/* expected string */
strcpy(path, sysdriveA);
strcat(path, sysdrvA);
ok(!strcmp(buff, path), "wrong unexpanded string %s, expected %s\n", buff, path);
/* now with altered variable */
ret = GetEnvironmentVariableA("SystemDrive", envvarA, sizeof(envvarA));
ok(ret, "got %d\n", ret);
ret = SetEnvironmentVariableA("SystemDrive", "WW");
ok(ret, "got %d\n", ret);
/* variables are not cached */
strcpy(path, sysdrvA);
strcat(path, sysdrvA);
SetLastError(0xdeadbeef);
ret = pPathUnExpandEnvStringsA(path, buff, sizeof(buff));
ok(!ret && GetLastError() == 0xdeadbeef, "got %d, error %d\n", ret, GetLastError());
ret = SetEnvironmentVariableA("SystemDrive", envvarA);
ok(ret, "got %d\n", ret);
/* PathUnExpandEnvStringsW */
/* something that can't be represented with env var */
lstrcpyW(pathW, nonpathW);
buffW[0] = 'x'; buffW[1] = 0;
SetLastError(0xdeadbeef);
ret = pPathUnExpandEnvStringsW(pathW, buffW, sizeof(buffW)/sizeof(WCHAR));
ok(!ret && GetLastError() == 0xdeadbeef, "got %d, error %d\n", ret, GetLastError());
ok(buffW[0] == 'x', "wrong return string %s\n", wine_dbgstr_w(buffW));
len = GetSystemDirectoryW(pathW, MAX_PATH);
ok(len > 0, "failed to get sysdir\n");
sysdrvW[0] = pathW[0];
sysdrvW[1] = ':';
sysdrvW[2] = 0;
/* buffer size is not enough */
buffW[0] = 'x'; buffW[1] = 0;
SetLastError(0xdeadbeef);
ret = pPathUnExpandEnvStringsW(pathW, buffW, 5);
ok(!ret && GetLastError() == 0xdeadbeef, "got %d, error %d\n", ret, GetLastError());
ok(buffW[0] == 'x', "wrong return string %s\n", wine_dbgstr_w(buffW));
/* buffer size is enough to hold variable name only */
buffW[0] = 'x'; buffW[1] = 0;
SetLastError(0xdeadbeef);
ret = pPathUnExpandEnvStringsW(pathW, buffW, sizeof(sysrootW)/sizeof(WCHAR));
ok(!ret && GetLastError() == 0xdeadbeef, "got %d, error %d\n", ret, GetLastError());
ok(buffW[0] == 'x', "wrong return string %s\n", wine_dbgstr_w(buffW));
/* enough size */
buffW[0] = 0;
ret = pPathUnExpandEnvStringsW(pathW, buffW, sizeof(buffW)/sizeof(WCHAR));
ok(ret, "got %d\n", ret);
ok(!memcmp(buffW, sysrootW, sizeof(sysrootW) - sizeof(WCHAR)), "wrong return string %s\n", wine_dbgstr_w(buffW));
/* expanded value occurs multiple times */
/* for drive C: it's unexpands it like 'C:C:' -> '%SystemDrive%C:' */
buffW[0] = 0;
lstrcpyW(pathW, sysdrvW);
lstrcatW(pathW, sysdrvW);
ret = pPathUnExpandEnvStringsW(pathW, buffW, sizeof(buff)/sizeof(WCHAR));
ok(ret, "got %d\n", ret);
/* expected string */
lstrcpyW(pathW, sysdriveW);
lstrcatW(pathW, sysdrvW);
ok(!lstrcmpW(buffW, pathW), "wrong unexpanded string %s, expected %s\n", wine_dbgstr_w(buffW), wine_dbgstr_w(pathW));
}
START_TEST(path)
{
......@@ -1471,6 +1602,8 @@ START_TEST(path)
pPathIsValidCharA = (void*)GetProcAddress(hShlwapi, (LPSTR)455);
pPathIsValidCharW = (void*)GetProcAddress(hShlwapi, (LPSTR)456);
pPathAppendA = (void*)GetProcAddress(hShlwapi, "PathAppendA");
pPathUnExpandEnvStringsA = (void*)GetProcAddress(hShlwapi, "PathUnExpandEnvStringsA");
pPathUnExpandEnvStringsW = (void*)GetProcAddress(hShlwapi, "PathUnExpandEnvStringsW");
test_PathSearchAndQualify();
test_PathCreateFromUrl();
......@@ -1492,4 +1625,5 @@ START_TEST(path)
test_PathCommonPrefixA();
test_PathUnquoteSpaces();
test_PathGetDriveNumber();
test_PathUnExpandEnvStrings();
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment