From: Zhiyi Zhang <zzhang@codeweavers.com> And use it for CoInternetCombineIUri() and CoInternetCombineUrlEx(). PrivateCoInternetCombineIUri() is an exported function of iertutil. However, its behavior could be different due to its undocumented nature. --- dlls/iertutil/iertutil.spec | 1 + dlls/iertutil/uri.c | 347 +++++++++++++++++++++++++ dlls/urlmon/uri.c | 504 +----------------------------------- 3 files changed, 353 insertions(+), 499 deletions(-) diff --git a/dlls/iertutil/iertutil.spec b/dlls/iertutil/iertutil.spec index ccfc966d117..e6742cfacca 100644 --- a/dlls/iertutil/iertutil.spec +++ b/dlls/iertutil/iertutil.spec @@ -4,3 +4,4 @@ @ stdcall -private DllCanUnloadNow() @ stdcall -private DllGetActivationFactory(ptr ptr) @ stdcall -private DllGetClassObject(ptr ptr ptr) +@ stdcall PrivateCoInternetCombineIUri(ptr ptr long ptr long) diff --git a/dlls/iertutil/uri.c b/dlls/iertutil/uri.c index b5d5cd01d10..2f06071a23e 100644 --- a/dlls/iertutil/uri.c +++ b/dlls/iertutil/uri.c @@ -6087,3 +6087,350 @@ HRESULT WINAPI CreateIUriBuilder(IUri *pIUri, DWORD dwFlags, DWORD_PTR dwReserve *ppIUriBuilder = &ret->IUriBuilder_iface; return S_OK; } + +/* Merges the base path with the relative path and stores the resulting path + * and path len in 'result' and 'result_len'. + */ +static HRESULT merge_paths(parse_data *data, const WCHAR *base, DWORD base_len, const WCHAR *relative, + DWORD relative_len, WCHAR **result, DWORD *result_len, DWORD flags) +{ + const WCHAR *end = NULL; + DWORD base_copy_len = 0; + WCHAR *ptr; + + if(base_len) { + if(data->scheme_type == URL_SCHEME_MK && *relative == '/') { + /* Find '::' segment */ + for(end = base; end < base+base_len-1; end++) { + if(end[0] == ':' && end[1] == ':') { + end++; + break; + } + } + + /* If not found, try finding the end of @xxx: */ + if(end == base+base_len-1) + end = *base == '@' ? wmemchr(base, ':', base_len) : NULL; + }else { + /* Find the characters that will be copied over from the base path. */ + for (end = base + base_len - 1; end >= base; end--) if (*end == '/') break; + if(end < base && data->scheme_type == URL_SCHEME_FILE) + /* Try looking for a '\\'. */ + for (end = base + base_len - 1; end >= base; end--) if (*end == '\\') break; + } + } + + if (end) base_copy_len = (end+1)-base; + *result = malloc((base_copy_len + relative_len + 1) * sizeof(WCHAR)); + + if(!(*result)) { + *result_len = 0; + return E_OUTOFMEMORY; + } + + ptr = *result; + memcpy(ptr, base, base_copy_len*sizeof(WCHAR)); + ptr += base_copy_len; + + memcpy(ptr, relative, relative_len*sizeof(WCHAR)); + ptr += relative_len; + *ptr = '\0'; + + *result_len = (ptr-*result); + TRACE("ret %s\n", debugstr_wn(*result, *result_len)); + return S_OK; +} + +static HRESULT combine_uri(Uri *base, Uri *relative, DWORD flags, IUri **result, DWORD extras) { + Uri *ret; + HRESULT hr; + parse_data data; + Uri *proc_uri = base; + DWORD create_flags = 0, len = 0; + + memset(&data, 0, sizeof(parse_data)); + + /* Base case is when the relative Uri has a scheme name, + * if it does, then 'result' will contain the same data + * as the relative Uri. + */ + if(relative->scheme_start > -1) { + data.uri = SysAllocString(relative->raw_uri); + if(!data.uri) { + *result = NULL; + return E_OUTOFMEMORY; + } + + parse_uri(&data, Uri_CREATE_ALLOW_IMPLICIT_FILE_SCHEME); + + hr = Uri_Construct(NULL, (void**)&ret); + if(FAILED(hr)) { + *result = NULL; + return hr; + } + + if(extras & COMBINE_URI_FORCE_FLAG_USE) { + if(flags & URL_DONT_SIMPLIFY) + create_flags |= Uri_CREATE_NO_CANONICALIZE; + if(flags & URL_DONT_UNESCAPE_EXTRA_INFO) + create_flags |= Uri_CREATE_NO_DECODE_EXTRA_INFO; + } + + ret->raw_uri = data.uri; + hr = canonicalize_uri(&data, ret, create_flags); + if(FAILED(hr)) { + IUri_Release(&ret->IUri_iface); + *result = NULL; + return hr; + } + + apply_default_flags(&create_flags); + ret->create_flags = create_flags; + + *result = &ret->IUri_iface; + } else { + WCHAR *path = NULL; + DWORD raw_flags = 0; + + if(base->scheme_start > -1) { + data.scheme = base->canon_uri+base->scheme_start; + data.scheme_len = base->scheme_len; + data.scheme_type = base->scheme_type; + } else { + data.is_relative = TRUE; + data.scheme_type = URL_SCHEME_UNKNOWN; + create_flags |= Uri_CREATE_ALLOW_RELATIVE; + } + + if(relative->authority_start > -1) + proc_uri = relative; + + if(proc_uri->authority_start > -1) { + if(proc_uri->userinfo_start > -1 && proc_uri->userinfo_split != 0) { + data.username = proc_uri->canon_uri+proc_uri->userinfo_start; + data.username_len = (proc_uri->userinfo_split > -1) ? proc_uri->userinfo_split : proc_uri->userinfo_len; + } + + if(proc_uri->userinfo_split > -1) { + data.password = proc_uri->canon_uri+proc_uri->userinfo_start+proc_uri->userinfo_split+1; + data.password_len = proc_uri->userinfo_len-proc_uri->userinfo_split-1; + } + + if(proc_uri->host_start > -1) { + const WCHAR *host = proc_uri->canon_uri+proc_uri->host_start; + parse_host(&host, &data, 0); + } + + if(proc_uri->has_port) { + data.has_port = TRUE; + data.port_value = proc_uri->port; + } + } else if(base->scheme_type != URL_SCHEME_FILE) + data.is_opaque = TRUE; + + if(proc_uri == relative || relative->path_start == -1 || !relative->path_len) { + if(proc_uri->path_start > -1) { + data.path = proc_uri->canon_uri+proc_uri->path_start; + data.path_len = proc_uri->path_len; + } else if(!data.is_opaque) { + /* Just set the path as a '/' if the base didn't have + * one and if it's a hierarchical URI. + */ + data.path = L"/"; + data.path_len = 1; + } + + if(relative->query_start > -1) + proc_uri = relative; + + if(proc_uri->query_start > -1) { + data.query = proc_uri->canon_uri+proc_uri->query_start; + data.query_len = proc_uri->query_len; + } + } else { + const WCHAR *ptr, **pptr; + DWORD path_offset = 0, path_len = 0; + + /* There's two possibilities on what will happen to the path component + * of the result IUri. First, if the relative path begins with a '/' + * then the resulting path will just be the relative path. Second, if + * relative path doesn't begin with a '/' then the base path and relative + * path are merged together. + */ + if(relative->path_len && *(relative->canon_uri+relative->path_start) == '/' && data.scheme_type != URL_SCHEME_MK) { + WCHAR *tmp = NULL; + BOOL copy_drive_path = FALSE; + + /* If the relative IUri's path starts with a '/', then we + * don't use the base IUri's path. Unless the base IUri + * is a file URI, in which case it uses the drive path of + * the base IUri (if it has any) in the new path. + */ + if(base->scheme_type == URL_SCHEME_FILE) { + if(base->path_len > 3 && *(base->canon_uri+base->path_start) == '/' && + is_drive_path(base->canon_uri+base->path_start+1)) { + path_len += 3; + copy_drive_path = TRUE; + } + } + + path_len += relative->path_len; + + path = malloc((path_len + 1) * sizeof(WCHAR)); + if(!path) { + *result = NULL; + return E_OUTOFMEMORY; + } + + tmp = path; + + /* Copy the base paths, drive path over. */ + if(copy_drive_path) { + memcpy(tmp, base->canon_uri+base->path_start, 3*sizeof(WCHAR)); + tmp += 3; + } + + memcpy(tmp, relative->canon_uri+relative->path_start, relative->path_len*sizeof(WCHAR)); + path[path_len] = '\0'; + } else { + /* Merge the base path with the relative path. */ + hr = merge_paths(&data, base->canon_uri+base->path_start, base->path_len, + relative->canon_uri+relative->path_start, relative->path_len, + &path, &path_len, flags); + if(FAILED(hr)) { + *result = NULL; + return hr; + } + + /* If the resulting IUri is a file URI, the drive path isn't + * reduced out when the dot segments are removed. + */ + if(path_len >= 3 && data.scheme_type == URL_SCHEME_FILE && !data.host) { + if(*path == '/' && is_drive_path(path+1)) + path_offset = 2; + else if(is_drive_path(path)) + path_offset = 1; + } + } + + /* Check if the dot segments need to be removed from the path. */ + if(!(flags & URL_DONT_SIMPLIFY) && !data.is_opaque) { + DWORD offset = (path_offset > 0) ? path_offset+1 : 0; + DWORD new_len = remove_dot_segments(path+offset,path_len-offset); + + if(new_len != path_len) { + WCHAR *tmp = realloc(path, (offset + new_len + 1) * sizeof(WCHAR)); + if(!tmp) { + free(path); + *result = NULL; + return E_OUTOFMEMORY; + } + + tmp[new_len+offset] = '\0'; + path = tmp; + path_len = new_len+offset; + } + } + + if(relative->query_start > -1) { + data.query = relative->canon_uri+relative->query_start; + data.query_len = relative->query_len; + } + + /* Make sure the path component is valid. */ + ptr = path; + pptr = &ptr; + if((data.is_opaque && !parse_path_opaque(pptr, &data, 0)) || + (!data.is_opaque && !parse_path_hierarchical(pptr, &data, 0))) { + free(path); + *result = NULL; + return E_INVALIDARG; + } + } + + if(relative->fragment_start > -1) { + data.fragment = relative->canon_uri+relative->fragment_start; + data.fragment_len = relative->fragment_len; + } + + if(flags & URL_DONT_SIMPLIFY) + raw_flags |= RAW_URI_FORCE_PORT_DISP; + if(flags & URL_FILE_USE_PATHURL) + raw_flags |= RAW_URI_CONVERT_TO_DOS_PATH; + + len = generate_raw_uri(&data, data.uri, raw_flags); + data.uri = SysAllocStringLen(NULL, len); + if(!data.uri) { + free(path); + *result = NULL; + return E_OUTOFMEMORY; + } + + generate_raw_uri(&data, data.uri, raw_flags); + + hr = Uri_Construct(NULL, (void**)&ret); + if(FAILED(hr)) { + SysFreeString(data.uri); + free(path); + *result = NULL; + return hr; + } + + if(flags & URL_DONT_SIMPLIFY) + create_flags |= Uri_CREATE_NO_CANONICALIZE; + if(flags & URL_FILE_USE_PATHURL) + create_flags |= Uri_CREATE_FILE_USE_DOS_PATH; + + ret->raw_uri = data.uri; + hr = canonicalize_uri(&data, ret, create_flags); + if(FAILED(hr)) { + IUri_Release(&ret->IUri_iface); + *result = NULL; + return hr; + } + + if(flags & URL_DONT_SIMPLIFY) + ret->display_modifiers |= URI_DISPLAY_NO_DEFAULT_PORT_AUTH; + + apply_default_flags(&create_flags); + ret->create_flags = create_flags; + *result = &ret->IUri_iface; + + free(path); + } + + return S_OK; +} + +/*********************************************************************** + * PrivateCoInternetCombineIUri (iertutil.@) + */ +HRESULT WINAPI PrivateCoInternetCombineIUri(IUri *pBaseUri, IUri *pRelativeUri, + DWORD dwCombineFlags, IUri **ppCombinedUri, + DWORD_PTR dwReserved) +{ + Uri *relative, *base; + + TRACE("(%p %p %lx %p %Ix)\n", pBaseUri, pRelativeUri, dwCombineFlags, ppCombinedUri, dwReserved); + + if (!ppCombinedUri) + return E_INVALIDARG; + + if (!pBaseUri || !pRelativeUri) + { + *ppCombinedUri = NULL; + return E_INVALIDARG; + } + + relative = get_uri_obj(pRelativeUri); + base = get_uri_obj(pBaseUri); + if (!relative || !base) + { + *ppCombinedUri = NULL; + FIXME("(%p %p %lx %p %Ix) Unknown IUri types not supported yet.\n", pBaseUri, pRelativeUri, + dwCombineFlags, ppCombinedUri, dwReserved); + return E_NOTIMPL; + } + + return combine_uri(base, relative, dwCombineFlags, ppCombinedUri, dwReserved); +} diff --git a/dlls/urlmon/uri.c b/dlls/urlmon/uri.c index 97721649565..935d429b7b5 100644 --- a/dlls/urlmon/uri.c +++ b/dlls/urlmon/uri.c @@ -49,6 +49,9 @@ WINE_DEFAULT_DEBUG_CHANNEL(urlmon); +HRESULT WINAPI PrivateCoInternetCombineIUri(IUri *pBaseUri, IUri *pRelativeUri, DWORD dwCombineFlags, + IUri **ppCombinedUri, DWORD_PTR dwReserved); + static const IID IID_IUriObj = {0x4b364760,0x9f51,0x11df,{0x98,0x1c,0x08,0x00,0x20,0x0c,0x9a,0x66}}; typedef struct { @@ -365,22 +368,6 @@ static inline BOOL is_hierarchical_scheme(URL_SCHEME type) { type == URL_SCHEME_RES); } -/* Applies each default Uri_CREATE flags to 'flags' if it - * doesn't cause a flag conflict. - */ -static void apply_default_flags(DWORD *flags) { - if(!(*flags & Uri_CREATE_NO_CANONICALIZE)) - *flags |= Uri_CREATE_CANONICALIZE; - if(!(*flags & Uri_CREATE_NO_DECODE_EXTRA_INFO)) - *flags |= Uri_CREATE_DECODE_EXTRA_INFO; - if(!(*flags & Uri_CREATE_NO_CRACK_UNKNOWN_SCHEMES)) - *flags |= Uri_CREATE_CRACK_UNKNOWN_SCHEMES; - if(!(*flags & Uri_CREATE_NO_PRE_PROCESS_HTML_URI)) - *flags |= Uri_CREATE_PRE_PROCESS_HTML_URI; - if(!(*flags & Uri_CREATE_IE_SETTINGS)) - *flags |= Uri_CREATE_NO_IE_SETTINGS; -} - /* Determines if the URI is hierarchical using the information already parsed into * data and using the current location of parsing in the URI string. * @@ -3136,173 +3123,6 @@ static HRESULT compare_uris(const Uri *a, const Uri *b, BOOL *ret) { return S_OK; } -static void convert_to_dos_path(const WCHAR *path, DWORD path_len, - WCHAR *output, DWORD *output_len) -{ - const WCHAR *ptr = path; - - if(path_len > 3 && *ptr == '/' && is_drive_path(path+1)) - /* Skip over the leading / before the drive path. */ - ++ptr; - - for(; ptr < path+path_len; ++ptr) { - if(*ptr == '/') { - if(output) - *output++ = '\\'; - (*output_len)++; - } else { - if(output) - *output++ = *ptr; - (*output_len)++; - } - } -} - -/* Generates a raw uri string using the parse_data. */ -static DWORD generate_raw_uri(const parse_data *data, BSTR uri, DWORD flags) { - DWORD length = 0; - - if(data->scheme) { - if(uri) { - memcpy(uri, data->scheme, data->scheme_len*sizeof(WCHAR)); - uri[data->scheme_len] = ':'; - } - length += data->scheme_len+1; - } - - if(!data->is_opaque) { - /* For the "//" which appears before the authority component. */ - if(uri) { - uri[length] = '/'; - uri[length+1] = '/'; - } - length += 2; - - /* Check if we need to add the "\\" before the host name - * of a UNC server name in a DOS path. - */ - if(flags & RAW_URI_CONVERT_TO_DOS_PATH && - data->scheme_type == URL_SCHEME_FILE && data->host) { - if(uri) { - uri[length] = '\\'; - uri[length+1] = '\\'; - } - length += 2; - } - } - - if(data->username) { - if(uri) - memcpy(uri+length, data->username, data->username_len*sizeof(WCHAR)); - length += data->username_len; - } - - if(data->password) { - if(uri) { - uri[length] = ':'; - memcpy(uri+length+1, data->password, data->password_len*sizeof(WCHAR)); - } - length += data->password_len+1; - } - - if(data->password || data->username) { - if(uri) - uri[length] = '@'; - ++length; - } - - if(data->host) { - /* IPv6 addresses get the brackets added around them if they don't already - * have them. - */ - const BOOL add_brackets = data->host_type == Uri_HOST_IPV6 && *(data->host) != '['; - if(add_brackets) { - if(uri) - uri[length] = '['; - ++length; - } - - if(uri) - memcpy(uri+length, data->host, data->host_len*sizeof(WCHAR)); - length += data->host_len; - - if(add_brackets) { - if(uri) - uri[length] = ']'; - length++; - } - } - - if(data->has_port) { - /* The port isn't included in the raw uri if it's the default - * port for the scheme type. - */ - DWORD i; - BOOL is_default = FALSE; - - for(i = 0; i < ARRAY_SIZE(default_ports); ++i) { - if(data->scheme_type == default_ports[i].scheme && - data->port_value == default_ports[i].port) - is_default = TRUE; - } - - if(!is_default || flags & RAW_URI_FORCE_PORT_DISP) { - if(uri) - uri[length] = ':'; - ++length; - - if(uri) - length += ui2str(uri+length, data->port_value); - else - length += ui2str(NULL, data->port_value); - } - } - - /* Check if a '/' should be added before the path for hierarchical URIs. */ - if(!data->is_opaque && data->path && *(data->path) != '/') { - if(uri) - uri[length] = '/'; - ++length; - } - - if(data->path) { - if(!data->is_opaque && data->scheme_type == URL_SCHEME_FILE && - flags & RAW_URI_CONVERT_TO_DOS_PATH) { - DWORD len = 0; - - if(uri) - convert_to_dos_path(data->path, data->path_len, uri+length, &len); - else - convert_to_dos_path(data->path, data->path_len, NULL, &len); - - length += len; - } else { - if(uri) - memcpy(uri+length, data->path, data->path_len*sizeof(WCHAR)); - length += data->path_len; - } - } - - if(data->query) { - if(uri) - memcpy(uri+length, data->query, data->query_len*sizeof(WCHAR)); - length += data->query_len; - } - - if(data->fragment) { - if(uri) - memcpy(uri+length, data->fragment, data->fragment_len*sizeof(WCHAR)); - length += data->fragment_len; - } - - if(uri) - TRACE("(%p %p): Generated raw uri=%s len=%ld\n", data, uri, debugstr_wn(uri, length), length); - else - TRACE("(%p %p): Computed raw uri len=%ld\n", data, uri, length); - - return length; -} - static inline Uri* impl_from_IUri(IUri *iface) { return CONTAINING_RECORD(iface, Uri, IUri_iface); @@ -4852,320 +4672,6 @@ HRESULT Uri_Construct(IUnknown *pUnkOuter, LPVOID *ppobj) return S_OK; } -/* Merges the base path with the relative path and stores the resulting path - * and path len in 'result' and 'result_len'. - */ -static HRESULT merge_paths(parse_data *data, const WCHAR *base, DWORD base_len, const WCHAR *relative, - DWORD relative_len, WCHAR **result, DWORD *result_len, DWORD flags) -{ - const WCHAR *end = NULL; - DWORD base_copy_len = 0; - WCHAR *ptr; - - if(base_len) { - if(data->scheme_type == URL_SCHEME_MK && *relative == '/') { - /* Find '::' segment */ - for(end = base; end < base+base_len-1; end++) { - if(end[0] == ':' && end[1] == ':') { - end++; - break; - } - } - - /* If not found, try finding the end of @xxx: */ - if(end == base+base_len-1) - end = *base == '@' ? wmemchr(base, ':', base_len) : NULL; - }else { - /* Find the characters that will be copied over from the base path. */ - for (end = base + base_len - 1; end >= base; end--) if (*end == '/') break; - if(end < base && data->scheme_type == URL_SCHEME_FILE) - /* Try looking for a '\\'. */ - for (end = base + base_len - 1; end >= base; end--) if (*end == '\\') break; - } - } - - if (end) base_copy_len = (end+1)-base; - *result = malloc((base_copy_len + relative_len + 1) * sizeof(WCHAR)); - - if(!(*result)) { - *result_len = 0; - return E_OUTOFMEMORY; - } - - ptr = *result; - memcpy(ptr, base, base_copy_len*sizeof(WCHAR)); - ptr += base_copy_len; - - memcpy(ptr, relative, relative_len*sizeof(WCHAR)); - ptr += relative_len; - *ptr = '\0'; - - *result_len = (ptr-*result); - TRACE("ret %s\n", debugstr_wn(*result, *result_len)); - return S_OK; -} - -static HRESULT combine_uri(Uri *base, Uri *relative, DWORD flags, IUri **result, DWORD extras) { - Uri *ret; - HRESULT hr; - parse_data data; - Uri *proc_uri = base; - DWORD create_flags = 0, len = 0; - - memset(&data, 0, sizeof(parse_data)); - - /* Base case is when the relative Uri has a scheme name, - * if it does, then 'result' will contain the same data - * as the relative Uri. - */ - if(relative->scheme_start > -1) { - data.uri = SysAllocString(relative->raw_uri); - if(!data.uri) { - *result = NULL; - return E_OUTOFMEMORY; - } - - parse_uri(&data, Uri_CREATE_ALLOW_IMPLICIT_FILE_SCHEME); - - hr = Uri_Construct(NULL, (void**)&ret); - if(FAILED(hr)) { - *result = NULL; - return hr; - } - - if(extras & COMBINE_URI_FORCE_FLAG_USE) { - if(flags & URL_DONT_SIMPLIFY) - create_flags |= Uri_CREATE_NO_CANONICALIZE; - if(flags & URL_DONT_UNESCAPE_EXTRA_INFO) - create_flags |= Uri_CREATE_NO_DECODE_EXTRA_INFO; - } - - ret->raw_uri = data.uri; - hr = canonicalize_uri(&data, ret, create_flags); - if(FAILED(hr)) { - IUri_Release(&ret->IUri_iface); - *result = NULL; - return hr; - } - - apply_default_flags(&create_flags); - ret->create_flags = create_flags; - - *result = &ret->IUri_iface; - } else { - WCHAR *path = NULL; - DWORD raw_flags = 0; - - if(base->scheme_start > -1) { - data.scheme = base->canon_uri+base->scheme_start; - data.scheme_len = base->scheme_len; - data.scheme_type = base->scheme_type; - } else { - data.is_relative = TRUE; - data.scheme_type = URL_SCHEME_UNKNOWN; - create_flags |= Uri_CREATE_ALLOW_RELATIVE; - } - - if(relative->authority_start > -1) - proc_uri = relative; - - if(proc_uri->authority_start > -1) { - if(proc_uri->userinfo_start > -1 && proc_uri->userinfo_split != 0) { - data.username = proc_uri->canon_uri+proc_uri->userinfo_start; - data.username_len = (proc_uri->userinfo_split > -1) ? proc_uri->userinfo_split : proc_uri->userinfo_len; - } - - if(proc_uri->userinfo_split > -1) { - data.password = proc_uri->canon_uri+proc_uri->userinfo_start+proc_uri->userinfo_split+1; - data.password_len = proc_uri->userinfo_len-proc_uri->userinfo_split-1; - } - - if(proc_uri->host_start > -1) { - const WCHAR *host = proc_uri->canon_uri+proc_uri->host_start; - parse_host(&host, &data, 0); - } - - if(proc_uri->has_port) { - data.has_port = TRUE; - data.port_value = proc_uri->port; - } - } else if(base->scheme_type != URL_SCHEME_FILE) - data.is_opaque = TRUE; - - if(proc_uri == relative || relative->path_start == -1 || !relative->path_len) { - if(proc_uri->path_start > -1) { - data.path = proc_uri->canon_uri+proc_uri->path_start; - data.path_len = proc_uri->path_len; - } else if(!data.is_opaque) { - /* Just set the path as a '/' if the base didn't have - * one and if it's a hierarchical URI. - */ - data.path = L"/"; - data.path_len = 1; - } - - if(relative->query_start > -1) - proc_uri = relative; - - if(proc_uri->query_start > -1) { - data.query = proc_uri->canon_uri+proc_uri->query_start; - data.query_len = proc_uri->query_len; - } - } else { - const WCHAR *ptr, **pptr; - DWORD path_offset = 0, path_len = 0; - - /* There's two possibilities on what will happen to the path component - * of the result IUri. First, if the relative path begins with a '/' - * then the resulting path will just be the relative path. Second, if - * relative path doesn't begin with a '/' then the base path and relative - * path are merged together. - */ - if(relative->path_len && *(relative->canon_uri+relative->path_start) == '/' && data.scheme_type != URL_SCHEME_MK) { - WCHAR *tmp = NULL; - BOOL copy_drive_path = FALSE; - - /* If the relative IUri's path starts with a '/', then we - * don't use the base IUri's path. Unless the base IUri - * is a file URI, in which case it uses the drive path of - * the base IUri (if it has any) in the new path. - */ - if(base->scheme_type == URL_SCHEME_FILE) { - if(base->path_len > 3 && *(base->canon_uri+base->path_start) == '/' && - is_drive_path(base->canon_uri+base->path_start+1)) { - path_len += 3; - copy_drive_path = TRUE; - } - } - - path_len += relative->path_len; - - path = malloc((path_len + 1) * sizeof(WCHAR)); - if(!path) { - *result = NULL; - return E_OUTOFMEMORY; - } - - tmp = path; - - /* Copy the base paths, drive path over. */ - if(copy_drive_path) { - memcpy(tmp, base->canon_uri+base->path_start, 3*sizeof(WCHAR)); - tmp += 3; - } - - memcpy(tmp, relative->canon_uri+relative->path_start, relative->path_len*sizeof(WCHAR)); - path[path_len] = '\0'; - } else { - /* Merge the base path with the relative path. */ - hr = merge_paths(&data, base->canon_uri+base->path_start, base->path_len, - relative->canon_uri+relative->path_start, relative->path_len, - &path, &path_len, flags); - if(FAILED(hr)) { - *result = NULL; - return hr; - } - - /* If the resulting IUri is a file URI, the drive path isn't - * reduced out when the dot segments are removed. - */ - if(path_len >= 3 && data.scheme_type == URL_SCHEME_FILE && !data.host) { - if(*path == '/' && is_drive_path(path+1)) - path_offset = 2; - else if(is_drive_path(path)) - path_offset = 1; - } - } - - /* Check if the dot segments need to be removed from the path. */ - if(!(flags & URL_DONT_SIMPLIFY) && !data.is_opaque) { - DWORD offset = (path_offset > 0) ? path_offset+1 : 0; - DWORD new_len = remove_dot_segments(path+offset,path_len-offset); - - if(new_len != path_len) { - WCHAR *tmp = realloc(path, (offset + new_len + 1) * sizeof(WCHAR)); - if(!tmp) { - free(path); - *result = NULL; - return E_OUTOFMEMORY; - } - - tmp[new_len+offset] = '\0'; - path = tmp; - path_len = new_len+offset; - } - } - - if(relative->query_start > -1) { - data.query = relative->canon_uri+relative->query_start; - data.query_len = relative->query_len; - } - - /* Make sure the path component is valid. */ - ptr = path; - pptr = &ptr; - if((data.is_opaque && !parse_path_opaque(pptr, &data, 0)) || - (!data.is_opaque && !parse_path_hierarchical(pptr, &data, 0))) { - free(path); - *result = NULL; - return E_INVALIDARG; - } - } - - if(relative->fragment_start > -1) { - data.fragment = relative->canon_uri+relative->fragment_start; - data.fragment_len = relative->fragment_len; - } - - if(flags & URL_DONT_SIMPLIFY) - raw_flags |= RAW_URI_FORCE_PORT_DISP; - if(flags & URL_FILE_USE_PATHURL) - raw_flags |= RAW_URI_CONVERT_TO_DOS_PATH; - - len = generate_raw_uri(&data, data.uri, raw_flags); - data.uri = SysAllocStringLen(NULL, len); - if(!data.uri) { - free(path); - *result = NULL; - return E_OUTOFMEMORY; - } - - generate_raw_uri(&data, data.uri, raw_flags); - - hr = Uri_Construct(NULL, (void**)&ret); - if(FAILED(hr)) { - SysFreeString(data.uri); - free(path); - *result = NULL; - return hr; - } - - if(flags & URL_DONT_SIMPLIFY) - create_flags |= Uri_CREATE_NO_CANONICALIZE; - if(flags & URL_FILE_USE_PATHURL) - create_flags |= Uri_CREATE_FILE_USE_DOS_PATH; - - ret->raw_uri = data.uri; - hr = canonicalize_uri(&data, ret, create_flags); - if(FAILED(hr)) { - IUri_Release(&ret->IUri_iface); - *result = NULL; - return hr; - } - - if(flags & URL_DONT_SIMPLIFY) - ret->display_modifiers |= URI_DISPLAY_NO_DEFAULT_PORT_AUTH; - - apply_default_flags(&create_flags); - ret->create_flags = create_flags; - *result = &ret->IUri_iface; - - free(path); - } - - return S_OK; -} - /*********************************************************************** * CoInternetCombineIUri (urlmon.@) */ @@ -5209,7 +4715,7 @@ HRESULT WINAPI CoInternetCombineIUri(IUri *pBaseUri, IUri *pRelativeUri, DWORD d } } - return combine_uri(base, relative, dwCombineFlags, ppCombinedUri, 0); + return PrivateCoInternetCombineIUri(pBaseUri, pRelativeUri, dwCombineFlags, ppCombinedUri, 0); } /*********************************************************************** @@ -5268,7 +4774,7 @@ HRESULT WINAPI CoInternetCombineUrlEx(IUri *pBaseUri, LPCWSTR pwzRelativeUrl, DW return hr; } - hr = combine_uri(base, get_uri_obj(relative), dwCombineFlags, ppCombinedUri, COMBINE_URI_FORCE_FLAG_USE); + hr = PrivateCoInternetCombineIUri(pBaseUri, relative, dwCombineFlags, ppCombinedUri, COMBINE_URI_FORCE_FLAG_USE); IUri_Release(relative); return hr; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9131