[PATCH 1/3] kernelbase: Add more URL API functions from shlwapi.

Nikolay Sivov nsivov at codeweavers.com
Thu May 23 06:20:20 CDT 2019


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/kernelbase/Makefile.in     |   2 +-
 dlls/kernelbase/kernelbase.spec |  34 +-
 dlls/kernelbase/path.c          | 838 ++++++++++++++++++++++++++++++++
 3 files changed, 856 insertions(+), 18 deletions(-)

diff --git a/dlls/kernelbase/Makefile.in b/dlls/kernelbase/Makefile.in
index dcb03b4fdc..373f79d293 100644
--- a/dlls/kernelbase/Makefile.in
+++ b/dlls/kernelbase/Makefile.in
@@ -1,5 +1,5 @@
 MODULE = kernelbase.dll
-IMPORTS = uuid
+IMPORTS = uuid advapi32
 
 C_SRCS = \
 	main.c \
diff --git a/dlls/kernelbase/kernelbase.spec b/dlls/kernelbase/kernelbase.spec
index f9f9f2487b..e2bee49112 100644
--- a/dlls/kernelbase/kernelbase.spec
+++ b/dlls/kernelbase/kernelbase.spec
@@ -1628,31 +1628,31 @@
 # @ stub UpdatePackageStatus
 # @ stub UpdatePackageStatusForUser
 @ stdcall UpdateProcThreadAttribute(ptr long long ptr long ptr ptr) kernel32.UpdateProcThreadAttribute
-@ stdcall UrlApplySchemeA(str ptr ptr long) shlwapi.UrlApplySchemeA
-@ stdcall UrlApplySchemeW(wstr ptr ptr long) shlwapi.UrlApplySchemeW
+@ stdcall UrlApplySchemeA(str ptr ptr long)
+@ stdcall UrlApplySchemeW(wstr ptr ptr long)
 @ stdcall UrlCanonicalizeA(str ptr ptr long)
 @ stdcall UrlCanonicalizeW(wstr ptr ptr long)
 @ stdcall UrlCombineA(str str ptr ptr long) shlwapi.UrlCombineA
 @ stdcall UrlCombineW(wstr wstr ptr ptr long) shlwapi.UrlCombineW
-@ stdcall UrlCompareA(str str long) shlwapi.UrlCompareA
-@ stdcall UrlCompareW(wstr wstr long) shlwapi.UrlCompareW
-@ stdcall UrlCreateFromPathA(str ptr ptr long) shlwapi.UrlCreateFromPathA
-@ stdcall UrlCreateFromPathW(wstr ptr ptr long) shlwapi.UrlCreateFromPathW
+@ stdcall UrlCompareA(str str long)
+@ stdcall UrlCompareW(wstr wstr long)
+@ stdcall UrlCreateFromPathA(str ptr ptr long)
+@ stdcall UrlCreateFromPathW(wstr ptr ptr long)
 @ stdcall UrlEscapeA(str ptr ptr long)
 @ stdcall UrlEscapeW(wstr ptr ptr long)
-@ stdcall UrlFixupW(wstr wstr long) shlwapi.UrlFixupW
-@ stdcall UrlGetLocationA(str) shlwapi.UrlGetLocationA
-@ stdcall UrlGetLocationW(wstr) shlwapi.UrlGetLocationW
-@ stdcall UrlGetPartA(str ptr ptr long long) shlwapi.UrlGetPartA
-@ stdcall UrlGetPartW(wstr ptr ptr long long) shlwapi.UrlGetPartW
+@ stdcall UrlFixupW(wstr wstr long)
+@ stdcall UrlGetLocationA(str)
+@ stdcall UrlGetLocationW(wstr)
+@ stdcall UrlGetPartA(str ptr ptr long long)
+@ stdcall UrlGetPartW(wstr ptr ptr long long)
 @ stdcall UrlHashA(str ptr long) shlwapi.UrlHashA
 @ stdcall UrlHashW(wstr ptr long) shlwapi.UrlHashW
-@ stdcall UrlIsA(str long) shlwapi.UrlIsA
-@ stdcall UrlIsNoHistoryA(str) shlwapi.UrlIsNoHistoryA
-@ stdcall UrlIsNoHistoryW(wstr) shlwapi.UrlIsNoHistoryW
-@ stdcall UrlIsOpaqueA(str) shlwapi.UrlIsOpaqueA
-@ stdcall UrlIsOpaqueW(wstr) shlwapi.UrlIsOpaqueW
-@ stdcall UrlIsW(wstr long) shlwapi.UrlIsW
+@ stdcall UrlIsA(str long)
+@ stdcall UrlIsNoHistoryA(str)
+@ stdcall UrlIsNoHistoryW(wstr)
+@ stdcall UrlIsOpaqueA(str)
+@ stdcall UrlIsOpaqueW(wstr)
+@ stdcall UrlIsW(wstr long)
 @ stdcall UrlUnescapeA(str ptr ptr long)
 @ stdcall UrlUnescapeW(wstr ptr ptr long)
 @ stdcall VerFindFileA(long str str str ptr ptr ptr ptr) version.VerFindFileA
diff --git a/dlls/kernelbase/path.c b/dlls/kernelbase/path.c
index b81e0bad8c..1a88f20e70 100644
--- a/dlls/kernelbase/path.c
+++ b/dlls/kernelbase/path.c
@@ -36,6 +36,30 @@ WINE_DEFAULT_DEBUG_CHANNEL(path);
 
 static const char hexDigits[] = "0123456789ABCDEF";
 
+struct parsed_url
+{
+    const WCHAR *scheme;   /* [out] start of scheme                     */
+    DWORD scheme_len;      /* [out] size of scheme (until colon)        */
+    const WCHAR *username; /* [out] start of Username                   */
+    DWORD username_len;    /* [out] size of Username (until ":" or "@") */
+    const WCHAR *password; /* [out] start of Password                   */
+    DWORD password_len;    /* [out] size of Password (until "@")        */
+    const WCHAR *hostname; /* [out] start of Hostname                   */
+    DWORD hostname_len;    /* [out] size of Hostname (until ":" or "/") */
+    const WCHAR *port;     /* [out] start of Port                       */
+    DWORD port_len;        /* [out] size of Port (until "/" or eos)     */
+    const WCHAR *query;    /* [out] start of Query                      */
+    DWORD query_len;       /* [out] size of Query (until eos)           */
+};
+
+enum url_scan_type
+{
+    SCHEME,
+    HOST,
+    PORT,
+    USERPASS,
+};
+
 static WCHAR *heap_strdupAtoW(const char *str)
 {
     WCHAR *ret = NULL;
@@ -3724,3 +3748,817 @@ HRESULT WINAPI UrlCanonicalizeW(const WCHAR *src_url, WCHAR *canonicalized, DWOR
 
     return hr;
 }
+
+HRESULT WINAPI UrlApplySchemeA(const char *url, char *out, DWORD *out_len, DWORD flags)
+{
+    LPWSTR inW, outW;
+    HRESULT hr;
+    DWORD len;
+
+    TRACE("%s, %p, %p:out size %d, %#x\n", wine_dbgstr_a(url), out, out_len, out_len ? *out_len : 0, flags);
+
+    if (!url || !out || !out_len)
+        return E_INVALIDARG;
+
+    inW = heap_alloc(2 * INTERNET_MAX_URL_LENGTH * sizeof(WCHAR));
+    outW = inW + INTERNET_MAX_URL_LENGTH;
+
+    MultiByteToWideChar(CP_ACP, 0, url, -1, inW, INTERNET_MAX_URL_LENGTH);
+    len = INTERNET_MAX_URL_LENGTH;
+
+    hr = UrlApplySchemeW(inW, outW, &len, flags);
+    if (hr != S_OK)
+    {
+        heap_free(inW);
+        return hr;
+    }
+
+    len = WideCharToMultiByte(CP_ACP, 0, outW, -1, NULL, 0, NULL, NULL);
+    if (len > *out_len)
+    {
+        hr = E_POINTER;
+        goto cleanup;
+    }
+
+    WideCharToMultiByte(CP_ACP, 0, outW, -1, out, *out_len, NULL, NULL);
+    len--;
+
+cleanup:
+    *out_len = len;
+    heap_free(inW);
+    return hr;
+}
+
+static HRESULT url_guess_scheme(const WCHAR *url, WCHAR *out, DWORD *out_len)
+{
+    WCHAR reg_path[MAX_PATH], value[MAX_PATH], data[MAX_PATH];
+    DWORD value_len, data_len, dwType, i;
+    WCHAR Wxx, Wyy;
+    HKEY newkey;
+    INT index;
+    BOOL j;
+
+    MultiByteToWideChar(CP_ACP, 0,
+            "Software\\Microsoft\\Windows\\CurrentVersion\\URL\\Prefixes", 1, reg_path, MAX_PATH);
+    RegOpenKeyExW(HKEY_LOCAL_MACHINE, reg_path, 0, 1, &newkey);
+    index = 0;
+    while (value_len = data_len = MAX_PATH,
+            RegEnumValueW(newkey, index, value, &value_len, 0, &dwType, (LPVOID)data, &data_len) == 0)
+    {
+        TRACE("guess %d %s is %s\n", index, wine_dbgstr_w(value), wine_dbgstr_w(data));
+
+        j = FALSE;
+        for (i = 0; i < value_len; ++i)
+        {
+            Wxx = url[i];
+            Wyy = value[i];
+            /* remember that TRUE is not-equal */
+            j = ChrCmpIW(Wxx, Wyy);
+            if (j) break;
+        }
+        if ((i == value_len) && !j)
+        {
+            if (strlenW(data) + strlenW(url) + 1 > *out_len)
+            {
+                *out_len = strlenW(data) + strlenW(url) + 1;
+                RegCloseKey(newkey);
+                return E_POINTER;
+            }
+            strcpyW(out, data);
+            strcatW(out, url);
+            *out_len = strlenW(out);
+            TRACE("matched and set to %s\n", wine_dbgstr_w(out));
+            RegCloseKey(newkey);
+            return S_OK;
+        }
+        index++;
+    }
+    RegCloseKey(newkey);
+    return E_FAIL;
+}
+
+static HRESULT url_create_from_path(const WCHAR *path, WCHAR *url, DWORD *url_len)
+{
+    static const WCHAR file_colonW[] = {'f','i','l','e',':',0};
+    static const WCHAR three_slashesW[] = {'/','/','/',0};
+    PARSEDURLW parsed_url;
+    WCHAR *new_url;
+    DWORD needed;
+    HRESULT hr;
+
+    parsed_url.cbSize = sizeof(parsed_url);
+    if (ParseURLW(path, &parsed_url) == S_OK)
+    {
+        if (parsed_url.nScheme != URL_SCHEME_INVALID && parsed_url.cchProtocol > 1)
+        {
+            needed = strlenW(path);
+            if (needed >= *url_len)
+            {
+                *url_len = needed + 1;
+                return E_POINTER;
+            }
+            else
+            {
+                *url_len = needed;
+                return S_FALSE;
+            }
+        }
+    }
+
+    new_url = heap_alloc((strlenW(path) + 9) * sizeof(WCHAR)); /* "file:///" + path length + 1 */
+    strcpyW(new_url, file_colonW);
+    if (isalphaW(path[0]) && path[1] == ':')
+        strcatW(new_url, three_slashesW);
+    strcatW(new_url, path);
+    hr = UrlEscapeW(new_url, url, url_len, URL_ESCAPE_PERCENT);
+    heap_free(new_url);
+    return hr;
+}
+
+static HRESULT url_apply_default_scheme(const WCHAR *url, WCHAR *out, DWORD *length)
+{
+    static const WCHAR prefix_keyW[] =
+        {'S','o','f','t','w','a','r','e',
+         '\\','M','i','c','r','o','s','o','f','t',
+         '\\','W','i','n','d','o','w','s',
+         '\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n',
+         '\\','U','R','L',
+         '\\','D','e','f','a','u','l','t','P','r','e','f','i','x',0};
+    DWORD data_len, dwType;
+    WCHAR data[MAX_PATH];
+    HKEY newkey;
+
+    /* get and prepend default */
+    RegOpenKeyExW(HKEY_LOCAL_MACHINE, prefix_keyW, 0, 1, &newkey);
+    data_len = sizeof(data);
+    RegQueryValueExW(newkey, NULL, 0, &dwType, (BYTE *)data, &data_len);
+    RegCloseKey(newkey);
+    if (strlenW(data) + strlenW(url) + 1 > *length)
+    {
+        *length = strlenW(data) + strlenW(url) + 1;
+        return E_POINTER;
+    }
+    strcpyW(out, data);
+    strcatW(out, url);
+    *length = strlenW(out);
+    TRACE("used default %s\n", wine_dbgstr_w(out));
+    return S_OK;
+}
+
+HRESULT WINAPI UrlApplySchemeW(const WCHAR *url, WCHAR *out, DWORD *length, DWORD flags)
+{
+    PARSEDURLW in_scheme;
+    DWORD res1;
+    HRESULT hr;
+
+    TRACE("%s, %p, %p:out size %d, %#x\n", wine_dbgstr_w(url), out, length, length ? *length : 0, flags);
+
+    if (!url || !out || !length)
+        return E_INVALIDARG;
+
+    if (flags & URL_APPLY_GUESSFILE)
+    {
+        if (*length > 1 && ':' == url[1])
+        {
+            res1 = *length;
+            hr = url_create_from_path(url, out, &res1);
+            if (hr == S_OK || hr == E_POINTER)
+            {
+                *length = res1;
+                return hr;
+            }
+            else if (hr == S_FALSE)
+            {
+                return hr;
+            }
+        }
+    }
+
+    in_scheme.cbSize = sizeof(in_scheme);
+    /* See if the base has a scheme */
+    res1 = ParseURLW(url, &in_scheme);
+    if (res1)
+    {
+        /* no scheme in input, need to see if we need to guess */
+        if (flags & URL_APPLY_GUESSSCHEME)
+        {
+            if ((hr = url_guess_scheme(url, out, length)) != E_FAIL)
+                return hr;
+        }
+    }
+
+    /* If we are here, then either invalid scheme,
+     * or no scheme and can't/failed guess.
+     */
+    if ((((res1 == 0) && (flags & URL_APPLY_FORCEAPPLY)) || ((res1 != 0)) ) && (flags & URL_APPLY_DEFAULT))
+        return url_apply_default_scheme(url, out, length);
+
+    return S_FALSE;
+}
+
+INT WINAPI UrlCompareA(const char *url1, const char *url2, BOOL ignore_slash)
+{
+    INT ret, len, len1, len2;
+
+    if (!ignore_slash)
+        return strcmp(url1, url2);
+    len1 = strlen(url1);
+    if (url1[len1-1] == '/') len1--;
+    len2 = strlen(url2);
+    if (url2[len2-1] == '/') len2--;
+    if (len1 == len2)
+        return strncmp(url1, url2, len1);
+    len = min(len1, len2);
+    ret = strncmp(url1, url2, len);
+    if (ret) return ret;
+    if (len1 > len2) return 1;
+    return -1;
+}
+
+INT WINAPI UrlCompareW(const WCHAR *url1, const WCHAR *url2, BOOL ignore_slash)
+{
+    size_t len, len1, len2;
+    INT ret;
+
+    if (!ignore_slash)
+        return strcmpW(url1, url2);
+    len1 = strlenW(url1);
+    if (url1[len1-1] == '/') len1--;
+    len2 = strlenW(url2);
+    if (url2[len2-1] == '/') len2--;
+    if (len1 == len2)
+        return strncmpW(url1, url2, len1);
+    len = min(len1, len2);
+    ret = strncmpW(url1, url2, len);
+    if (ret) return ret;
+    if (len1 > len2) return 1;
+    return -1;
+}
+
+HRESULT WINAPI UrlFixupW(const WCHAR *url, WCHAR *translatedUrl, DWORD maxChars)
+{
+    DWORD srcLen;
+
+    FIXME("%s, %p, %d stub\n", wine_dbgstr_w(url), translatedUrl, maxChars);
+
+    if (!url)
+        return E_FAIL;
+
+    srcLen = lstrlenW(url) + 1;
+
+    /* For now just copy the URL directly */
+    lstrcpynW(translatedUrl, url, (maxChars < srcLen) ? maxChars : srcLen);
+
+    return S_OK;
+}
+
+const char * WINAPI UrlGetLocationA(const char *url)
+{
+    PARSEDURLA base;
+
+    base.cbSize = sizeof(base);
+    if (ParseURLA(url, &base) != S_OK) return NULL;  /* invalid scheme */
+
+    /* if scheme is file: then never return pointer */
+    if (!strncmp(base.pszProtocol, "file", min(4, base.cchProtocol)) == 0)
+        return NULL;
+
+    /* Look for '#' and return its addr */
+    return strchr(base.pszSuffix, '#');
+}
+
+const WCHAR * WINAPI UrlGetLocationW(const WCHAR *url)
+{
+    static const WCHAR fileW[] = {'f','i','l','e','\0'};
+    PARSEDURLW base;
+
+    base.cbSize = sizeof(base);
+    if (ParseURLW(url, &base) != S_OK) return NULL;  /* invalid scheme */
+
+    /* if scheme is file: then never return pointer */
+    if (!strncmpW(base.pszProtocol, fileW, min(4, base.cchProtocol)))
+        return NULL;
+
+    /* Look for '#' and return its addr */
+    return strchrW(base.pszSuffix, '#');
+}
+
+HRESULT WINAPI UrlGetPartA(const char *url, char *out, DWORD *out_len, DWORD part, DWORD flags)
+{
+    LPWSTR inW, outW;
+    DWORD len, len2;
+    HRESULT hr;
+
+    if (!url || !out || !out_len || !*out_len)
+        return E_INVALIDARG;
+
+    inW = heap_alloc(2 * INTERNET_MAX_URL_LENGTH * sizeof(WCHAR));
+    outW = inW + INTERNET_MAX_URL_LENGTH;
+
+    MultiByteToWideChar(CP_ACP, 0, url, -1, inW, INTERNET_MAX_URL_LENGTH);
+
+    len = INTERNET_MAX_URL_LENGTH;
+    hr = UrlGetPartW(inW, outW, &len, part, flags);
+    if (FAILED(hr))
+    {
+        heap_free(inW);
+        return hr;
+    }
+
+    len2 = WideCharToMultiByte(CP_ACP, 0, outW, len, NULL, 0, NULL, NULL);
+    if (len2 > *out_len)
+    {
+        *out_len = len2 + 1;
+        heap_free(inW);
+        return E_POINTER;
+    }
+    len2 = WideCharToMultiByte(CP_ACP, 0, outW, len + 1, out, *out_len, NULL, NULL);
+    *out_len = len2 - 1;
+    heap_free(inW);
+    return hr;
+}
+
+static const WCHAR * scan_url(const WCHAR *start, DWORD *size, enum url_scan_type type)
+{
+    static DWORD alwayszero = 0;
+    BOOL cont = TRUE;
+
+    *size = 0;
+
+    switch (type)
+    {
+    case SCHEME:
+        while (cont)
+        {
+            if ((islowerW(*start) && isalphaW(*start)) ||
+                    isdigitW(*start) || *start == '+' || *start == '-' || *start == '.')
+            {
+                start++;
+                (*size)++;
+            }
+            else
+                cont = FALSE;
+        }
+        if (*start != ':')
+            *size = 0;
+        break;
+
+    case USERPASS:
+        while (cont)
+        {
+            if (isalphaW(*start) ||
+                    isdigitW(*start) ||
+                    /* user/password only characters */
+                    (*start == ';') ||
+                    (*start == '?') ||
+                    (*start == '&') ||
+                    (*start == '=') ||
+                    /* *extra* characters */
+                    (*start == '!') ||
+                    (*start == '*') ||
+                    (*start == '\'') ||
+                    (*start == '(') ||
+                    (*start == ')') ||
+                    (*start == ',') ||
+                    /* *safe* characters */
+                    (*start == '$') ||
+                    (*start == '_') ||
+                    (*start == '+') ||
+                    (*start == '-') ||
+                    (*start == '.') ||
+                    (*start == ' '))
+            {
+                start++;
+                (*size)++;
+            }
+            else if (*start == '%')
+            {
+                if (isxdigitW(*(start + 1)) && isxdigitW(*(start + 2)))
+                {
+                    start += 3;
+                    *size += 3;
+                }
+                else
+                    cont = FALSE;
+            } else
+                cont = FALSE;
+        }
+        break;
+
+    case PORT:
+        while (cont)
+        {
+            if (isdigitW(*start))
+            {
+                start++;
+                (*size)++;
+            }
+            else
+                cont = FALSE;
+        }
+        break;
+
+    case HOST:
+        while (cont)
+        {
+            if (isalnumW(*start) || *start == '-' || *start == '.' || *start == ' ' || *start == '*')
+            {
+                start++;
+                (*size)++;
+            }
+            else
+                cont = FALSE;
+        }
+        break;
+
+    default:
+        FIXME("unknown type %d\n", type);
+        return (LPWSTR)&alwayszero;
+    }
+
+    return start;
+}
+
+static LONG parse_url(const WCHAR *url, struct parsed_url *pl)
+{
+    const WCHAR *work;
+
+    memset(pl, 0, sizeof(*pl));
+    pl->scheme = url;
+    work = scan_url(pl->scheme, &pl->scheme_len, SCHEME);
+    if (!*work || (*work != ':')) goto ErrorExit;
+    work++;
+    if ((*work != '/') || (*(work+1) != '/')) goto SuccessExit;
+
+    pl->username = work + 2;
+    work = scan_url(pl->username, &pl->username_len, USERPASS);
+    if (*work == ':' )
+    {
+        /* parse password */
+        work++;
+        pl->password = work;
+        work = scan_url(pl->password, &pl->password_len, USERPASS);
+        if (*work != '@')
+        {
+            /* what we just parsed must be the hostname and port
+             * so reset pointers and clear then let it parse */
+            pl->username_len = pl->password_len = 0;
+            work = pl->username - 1;
+            pl->username = pl->password = 0;
+        }
+    }
+    else if (*work == '@')
+    {
+        /* no password */
+        pl->password_len = 0;
+        pl->password = 0;
+    }
+    else if (!*work || *work == '/' || *work == '.')
+    {
+        /* what was parsed was hostname, so reset pointers and let it parse */
+        pl->username_len = pl->password_len = 0;
+        work = pl->username - 1;
+        pl->username = pl->password = 0;
+    }
+    else goto ErrorExit;
+
+    /* now start parsing hostname or hostnumber */
+    work++;
+    pl->hostname = work;
+    work = scan_url(pl->hostname, &pl->hostname_len, HOST);
+    if (*work == ':')
+    {
+        /* parse port */
+        work++;
+        pl->port = work;
+        work = scan_url(pl->port, &pl->port_len, PORT);
+    }
+    if (*work == '/')
+    {
+        /* see if query string */
+        pl->query = strchrW(work, '?');
+        if (pl->query) pl->query_len = strlenW(pl->query);
+    }
+  SuccessExit:
+    TRACE("parse successful: scheme=%p(%d), user=%p(%d), pass=%p(%d), host=%p(%d), port=%p(%d), query=%p(%d)\n",
+            pl->scheme, pl->scheme_len, pl->username, pl->username_len, pl->password, pl->password_len, pl->hostname,
+            pl->hostname_len, pl->port, pl->port_len, pl->query, pl->query_len);
+
+    return S_OK;
+
+  ErrorExit:
+    FIXME("failed to parse %s\n", debugstr_w(url));
+    return E_INVALIDARG;
+}
+
+HRESULT WINAPI UrlGetPartW(const WCHAR *url, WCHAR *out, DWORD *out_len, DWORD part, DWORD flags)
+{
+    DWORD scheme, size, schsize;
+    LPCWSTR addr, schaddr;
+    struct parsed_url pl;
+    HRESULT hr;
+
+    TRACE("%s, %p, %p(%d), %#x, %#x\n", wine_dbgstr_w(url), out, out_len, *out_len, part, flags);
+
+    if (!url || !out || !out_len || !*out_len)
+        return E_INVALIDARG;
+
+    *out = '\0';
+
+    addr = strchrW(url, ':');
+    if (!addr)
+        scheme = URL_SCHEME_UNKNOWN;
+    else
+        scheme = get_scheme_code(url, addr - url);
+
+    hr = parse_url(url, &pl);
+
+    switch (part)
+    {
+    case URL_PART_SCHEME:
+        if (!pl.scheme_len)
+        {
+            *out_len = 0;
+            return S_FALSE;
+        }
+        addr = pl.scheme;
+        size = pl.scheme_len;
+        break;
+
+    case URL_PART_HOSTNAME:
+        switch (scheme)
+        {
+            case URL_SCHEME_FTP:
+            case URL_SCHEME_HTTP:
+            case URL_SCHEME_GOPHER:
+            case URL_SCHEME_TELNET:
+            case URL_SCHEME_FILE:
+            case URL_SCHEME_HTTPS:
+                break;
+            default:
+                *out_len = 0;
+                return E_FAIL;
+        }
+
+        if (scheme == URL_SCHEME_FILE && (!pl.hostname_len || (pl.hostname_len == 1 && *(pl.hostname + 1) == ':')))
+        {
+            *out_len = 0;
+            return S_FALSE;
+        }
+
+        if (!pl.hostname_len)
+        {
+            *out_len = 0;
+            return S_FALSE;
+        }
+        addr = pl.hostname;
+        size = pl.hostname_len;
+        break;
+
+    case URL_PART_USERNAME:
+        if (!pl.username_len)
+        {
+            *out_len = 0;
+            return S_FALSE;
+        }
+        addr = pl.username;
+        size = pl.username_len;
+        break;
+
+    case URL_PART_PASSWORD:
+        if (!pl.password_len)
+        {
+            *out_len = 0;
+            return S_FALSE;
+        }
+        addr = pl.password;
+        size = pl.password_len;
+        break;
+
+    case URL_PART_PORT:
+        if (!pl.port_len)
+        {
+            *out_len = 0;
+            return S_FALSE;
+        }
+        addr = pl.port;
+        size = pl.port_len;
+        break;
+
+    case URL_PART_QUERY:
+        if (!pl.query_len)
+        {
+            *out_len = 0;
+            return S_FALSE;
+        }
+        addr = pl.query;
+        size = pl.query_len;
+        break;
+
+    default:
+        *out_len = 0;
+        return E_INVALIDARG;
+    }
+
+    if (flags == URL_PARTFLAG_KEEPSCHEME)
+    {
+        if (!pl.scheme || !pl.scheme_len)
+        {
+            *out_len = 0;
+            return E_FAIL;
+        }
+        schaddr = pl.scheme;
+        schsize = pl.scheme_len;
+        if (*out_len < schsize + size + 2)
+        {
+            *out_len = schsize + size + 2;
+            return E_POINTER;
+        }
+        memcpy(out, schaddr, schsize*sizeof(WCHAR));
+        out[schsize] = ':';
+        memcpy(out + schsize+1, addr, size*sizeof(WCHAR));
+        out[schsize+1+size] = 0;
+        *out_len = schsize + 1 + size;
+    }
+    else
+    {
+        if (*out_len < size + 1)
+        {
+            *out_len = size + 1;
+            return E_POINTER;
+        }
+        memcpy(out, addr, size*sizeof(WCHAR));
+        out[size] = 0;
+        *out_len = size;
+    }
+    TRACE("len=%d %s\n", *out_len, wine_dbgstr_w(out));
+
+    return hr;
+}
+
+BOOL WINAPI UrlIsA(const char *url, URLIS Urlis)
+{
+    const char *last;
+    PARSEDURLA base;
+
+    TRACE("%s, %d\n", debugstr_a(url), Urlis);
+
+    if (!url)
+        return FALSE;
+
+    switch (Urlis) {
+
+    case URLIS_OPAQUE:
+        base.cbSize = sizeof(base);
+        if (ParseURLA(url, &base) != S_OK) return FALSE;  /* invalid scheme */
+        switch (base.nScheme)
+        {
+        case URL_SCHEME_MAILTO:
+        case URL_SCHEME_SHELL:
+        case URL_SCHEME_JAVASCRIPT:
+        case URL_SCHEME_VBSCRIPT:
+        case URL_SCHEME_ABOUT:
+            return TRUE;
+        }
+        return FALSE;
+
+    case URLIS_FILEURL:
+        return (CompareStringA(LOCALE_INVARIANT, NORM_IGNORECASE, url, 5, "file:", 5) == CSTR_EQUAL);
+
+    case URLIS_DIRECTORY:
+        last = url + strlen(url) - 1;
+        return (last >= url && (*last == '/' || *last == '\\' ));
+
+    case URLIS_URL:
+        return PathIsURLA(url);
+
+    case URLIS_NOHISTORY:
+    case URLIS_APPLIABLE:
+    case URLIS_HASQUERY:
+    default:
+        FIXME("(%s %d): stub\n", debugstr_a(url), Urlis);
+    }
+
+    return FALSE;
+}
+
+BOOL WINAPI UrlIsW(const WCHAR *url, URLIS Urlis)
+{
+    static const WCHAR file_colon[] = {'f','i','l','e',':',0};
+    const WCHAR *last;
+    PARSEDURLW base;
+
+    TRACE("%s, %d\n", debugstr_w(url), Urlis);
+
+    if (!url)
+        return FALSE;
+
+    switch (Urlis)
+    {
+    case URLIS_OPAQUE:
+        base.cbSize = sizeof(base);
+        if (ParseURLW(url, &base) != S_OK) return FALSE;  /* invalid scheme */
+        switch (base.nScheme)
+        {
+        case URL_SCHEME_MAILTO:
+        case URL_SCHEME_SHELL:
+        case URL_SCHEME_JAVASCRIPT:
+        case URL_SCHEME_VBSCRIPT:
+        case URL_SCHEME_ABOUT:
+            return TRUE;
+        }
+        return FALSE;
+
+    case URLIS_FILEURL:
+        return (CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, url, 5, file_colon, 5) == CSTR_EQUAL);
+
+    case URLIS_DIRECTORY:
+        last = url + strlenW(url) - 1;
+        return (last >= url && (*last == '/' || *last == '\\'));
+
+    case URLIS_URL:
+        return PathIsURLW(url);
+
+    case URLIS_NOHISTORY:
+    case URLIS_APPLIABLE:
+    case URLIS_HASQUERY:
+    default:
+        FIXME("(%s %d): stub\n", debugstr_w(url), Urlis);
+    }
+
+    return FALSE;
+}
+
+BOOL WINAPI UrlIsOpaqueA(const char *url)
+{
+    return UrlIsA(url, URLIS_OPAQUE);
+}
+
+BOOL WINAPI UrlIsOpaqueW(const WCHAR *url)
+{
+    return UrlIsW(url, URLIS_OPAQUE);
+}
+
+BOOL WINAPI UrlIsNoHistoryA(const char *url)
+{
+    return UrlIsA(url, URLIS_NOHISTORY);
+}
+
+BOOL WINAPI UrlIsNoHistoryW(const WCHAR *url)
+{
+    return UrlIsW(url, URLIS_NOHISTORY);
+}
+
+HRESULT WINAPI UrlCreateFromPathA(const char *path, char *url, DWORD *url_len, DWORD reserved)
+{
+    WCHAR bufW[INTERNET_MAX_URL_LENGTH];
+    DWORD lenW = ARRAY_SIZE(bufW), lenA;
+    UNICODE_STRING pathW;
+    WCHAR *urlW = bufW;
+    HRESULT hr;
+
+    if (!RtlCreateUnicodeStringFromAsciiz(&pathW, path))
+        return E_INVALIDARG;
+
+    if ((hr = UrlCreateFromPathW(pathW.Buffer, urlW, &lenW, reserved)) == E_POINTER)
+    {
+        urlW = heap_alloc(lenW * sizeof(WCHAR));
+        hr = UrlCreateFromPathW(pathW.Buffer, urlW, &lenW, reserved);
+    }
+
+    if (SUCCEEDED(hr))
+    {
+        RtlUnicodeToMultiByteSize(&lenA, urlW, lenW * sizeof(WCHAR));
+        if (*url_len > lenA)
+        {
+            RtlUnicodeToMultiByteN(url, *url_len - 1, &lenA, urlW, lenW * sizeof(WCHAR));
+            url[lenA] = 0;
+            *url_len = lenA;
+        }
+        else
+        {
+            *url_len = lenA + 1;
+            hr = E_POINTER;
+        }
+    }
+    if (urlW != bufW)
+        heap_free(urlW);
+    RtlFreeUnicodeString(&pathW);
+    return hr;
+}
+
+HRESULT WINAPI UrlCreateFromPathW(const WCHAR *path, WCHAR *url, DWORD *url_len, DWORD reserved)
+{
+    HRESULT hr;
+
+    TRACE("%s, %p, %p, %#x\n", debugstr_w(path), url, url_len, reserved);
+
+    if (reserved || !url || !url_len)
+        return E_INVALIDARG;
+
+    hr = url_create_from_path(path, url, url_len);
+    if (hr == S_FALSE)
+        strcpyW(url, path);
+
+    return hr;
+}
-- 
2.20.1




More information about the wine-devel mailing list