From 811ed515ab8791c67bc2edc6118f550b01d163e1 Mon Sep 17 00:00:00 2001 From: Thomas Mullaly Date: Sun, 6 Jun 2010 23:39:46 -0400 Subject: [PATCH] urlmon: Added a scheme name parser for the IUri interface. --- dlls/urlmon/tests/uri.c | 7 ++ dlls/urlmon/uri.c | 156 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 162 insertions(+), 1 deletion(-) diff --git a/dlls/urlmon/tests/uri.c b/dlls/urlmon/tests/uri.c index a89e5c64709..ddd35d878d9 100644 --- a/dlls/urlmon/tests/uri.c +++ b/dlls/urlmon/tests/uri.c @@ -522,12 +522,19 @@ static void test_CreateUri_InvalidArgs(void) { HRESULT hr; IUri *uri = (void*) 0xdeadbeef; + const WCHAR invalidW[] = {'i','n','v','a','l','i','d',0}; + hr = pCreateUri(http_urlW, 0, 0, NULL); ok(hr == E_INVALIDARG, "Error: CreateUri returned 0x%08x, expected 0x%08x\n", hr, E_INVALIDARG); hr = pCreateUri(NULL, 0, 0, &uri); ok(hr == E_INVALIDARG, "Error: CreateUri returned 0x%08x, expected 0x%08x\n", hr, E_INVALIDARG); ok(uri == NULL, "Error: Expected the IUri to be NULL, but it was %p instead\n", uri); + + uri = (void*) 0xdeadbeef; + hr = pCreateUri(invalidW, 0, 0, &uri); + ok(hr == E_INVALIDARG, "Error: CreateUri returned 0x%08x, expected 0x%08x.\n", hr, E_INVALIDARG); + ok(uri == NULL, "Error: Expected the IUri to be NULL, but it was %p instead\n", uri); } static void test_IUri_GetPropertyBSTR(void) { diff --git a/dlls/urlmon/uri.c b/dlls/urlmon/uri.c index 732ec44a4b0..246eacccbc3 100644 --- a/dlls/urlmon/uri.c +++ b/dlls/urlmon/uri.c @@ -20,6 +20,9 @@ #include "urlmon_main.h" #include "wine/debug.h" +#define NO_SHLWAPI_REG +#include "shlwapi.h" + WINE_DEFAULT_DEBUG_CHANNEL(urlmon); typedef struct { @@ -34,6 +37,146 @@ typedef struct { LONG ref; } UriBuilder; +typedef struct { + BSTR uri; + + + BOOL is_relative; + + const WCHAR *scheme; + DWORD scheme_len; +} parse_data; + +static inline BOOL is_alpha(WCHAR val) { + return ((val >= 'a' && val <= 'z') || (val >= 'A' && val <= 'Z')); +} + +static inline BOOL is_num(WCHAR val) { + return (val >= '0' && val <= '9'); +} + +/* A URI is implicitly a file path if it begins with + * a drive letter (eg X:) or starts with "\\" (UNC path). + */ +static inline BOOL is_implicit_file_path(const WCHAR *str) { + if(is_alpha(str[0]) && str[1] == ':') + return TRUE; + else if(str[0] == '\\' && str[1] == '\\') + return TRUE; + + return FALSE; +} + +/* Tries to parse the scheme name of the URI. + * + * scheme = ALPHA *(ALPHA | NUM | '+' | '-' | '.') as defined by RFC 3896. + * NOTE: Windows accepts a number as the first character of a scheme. + */ +static BOOL parse_scheme_name(const WCHAR **ptr, parse_data *data) { + const WCHAR *start = *ptr; + + data->scheme = NULL; + data->scheme_len = 0; + + while(**ptr) { + if(!is_num(**ptr) && !is_alpha(**ptr) && **ptr != '+' && + **ptr != '-' && **ptr != '.') + break; + + (*ptr)++; + } + + if(*ptr == start) + return FALSE; + + /* Schemes must end with a ':' */ + if(**ptr != ':') { + *ptr = start; + return FALSE; + } + + data->scheme = start; + data->scheme_len = *ptr - start; + + ++(*ptr); + return TRUE; +} + +/* Tries to parse (or deduce) the scheme_name of a URI. If it can't + * parse a scheme from the URI it will try to deduce the scheme_name and scheme_type + * using the flags specified in 'flags' (if any). Flags that affect how this function + * operates are the Uri_CREATE_ALLOW_* flags. + * + * All parsed/deduced information will be stored in 'data' when the function returns. + * + * Returns TRUE if it was able to successfully parse the information. + */ +static BOOL parse_scheme(const WCHAR **ptr, parse_data *data, DWORD flags) { + static const WCHAR fileW[] = {'f','i','l','e',0}; + static const WCHAR wildcardW[] = {'*',0}; + + /* First check to see if the uri could implicitly be a file path. */ + if(is_implicit_file_path(*ptr)) { + if(flags & Uri_CREATE_ALLOW_IMPLICIT_FILE_SCHEME) { + data->scheme = fileW; + data->scheme_len = lstrlenW(fileW); + TRACE("(%p %p %x): URI is an implicit file path.\n", ptr, data, flags); + } else { + /* Window's does not consider anything that can implicitly be a file + * path to be a valid URI if the ALLOW_IMPLICIT_FILE_SCHEME flag is not set... + */ + TRACE("(%p %p %x): URI is implicitly a file path, but, the ALLOW_IMPLICIT_FILE_SCHEME flag wasn't set.\n", + ptr, data, flags); + return FALSE; + } + } else if(!parse_scheme_name(ptr, data)) { + /* No Scheme was found, this means it could be: + * a) an implicit Wildcard scheme + * b) a relative URI + * c) a invalid URI. + */ + if(flags & Uri_CREATE_ALLOW_IMPLICIT_WILDCARD_SCHEME) { + data->scheme = wildcardW; + data->scheme_len = lstrlenW(wildcardW); + + TRACE("(%p %p %x): URI is an implicit wildcard scheme.\n", ptr, data, flags); + } else if (flags & Uri_CREATE_ALLOW_RELATIVE) { + data->is_relative = TRUE; + TRACE("(%p %p %x): URI is relative.\n", ptr, data, flags); + } else { + TRACE("(%p %p %x): Malformed URI found. Unable to deduce scheme name.\n", ptr, data, flags); + return FALSE; + } + } + + if(!data->is_relative) + TRACE("(%p %p %x): Found scheme=%s scheme_len=%d\n", ptr, data, flags, + debugstr_wn(data->scheme, data->scheme_len), data->scheme_len); + + return TRUE; +} + +/* Parses and validates the components of the specified by data->uri + * and stores the information it parses into 'data'. + * + * Returns TRUE if it successfully parsed the URI. False otherwise. + */ +static BOOL parse_uri(parse_data *data, DWORD flags) { + const WCHAR *ptr; + const WCHAR **pptr; + + ptr = data->uri; + pptr = &ptr; + + TRACE("(%p %x): BEGINNING TO PARSE URI %s.\n", data, flags, debugstr_w(data->uri)); + + if(!parse_scheme(pptr, data, flags)) + return FALSE; + + TRACE("(%p %x): FINISHED PARSING URI.\n", data, flags); + return TRUE; +} + #define URI(x) ((IUri*) &(x)->lpIUriVtbl) #define URIBUILDER(x) ((IUriBuilder*) &(x)->lpIUriBuilderVtbl) @@ -475,6 +618,7 @@ static const IUriVtbl UriVtbl = { HRESULT WINAPI CreateUri(LPCWSTR pwzURI, DWORD dwFlags, DWORD_PTR dwReserved, IUri **ppURI) { Uri *ret; + parse_data data; TRACE("(%s %x %x %p)\n", debugstr_w(pwzURI), dwFlags, (DWORD)dwReserved, ppURI); @@ -495,12 +639,22 @@ HRESULT WINAPI CreateUri(LPCWSTR pwzURI, DWORD dwFlags, DWORD_PTR dwReserved, IU /* Create a copy of pwzURI and store it as the raw_uri. */ ret->raw_uri = SysAllocString(pwzURI); - if(!ret->raw_uri) { heap_free(ret); return E_OUTOFMEMORY; } + memset(&data, 0, sizeof(parse_data)); + data.uri = ret->raw_uri; + + if(!parse_uri(&data, dwFlags)) { + /* Encountered an unsupported or invalid URI */ + SysFreeString(ret->raw_uri); + heap_free(ret); + *ppURI = NULL; + return E_INVALIDARG; + } + *ppURI = URI(ret); return S_OK; }