1c2c66affSColin Finck /*
2c2c66affSColin Finck * Url functions
3c2c66affSColin Finck *
4c2c66affSColin Finck * Copyright 2000 Huw D M Davies for CodeWeavers.
5c2c66affSColin Finck *
6c2c66affSColin Finck * This library is free software; you can redistribute it and/or
7c2c66affSColin Finck * modify it under the terms of the GNU Lesser General Public
8c2c66affSColin Finck * License as published by the Free Software Foundation; either
9c2c66affSColin Finck * version 2.1 of the License, or (at your option) any later version.
10c2c66affSColin Finck *
11c2c66affSColin Finck * This library is distributed in the hope that it will be useful,
12c2c66affSColin Finck * but WITHOUT ANY WARRANTY; without even the implied warranty of
13c2c66affSColin Finck * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14c2c66affSColin Finck * Lesser General Public License for more details.
15c2c66affSColin Finck *
16c2c66affSColin Finck * You should have received a copy of the GNU Lesser General Public
17c2c66affSColin Finck * License along with this library; if not, write to the Free Software
18c2c66affSColin Finck * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19c2c66affSColin Finck */
20c2c66affSColin Finck
21d3fd5bddSAmine Khaldi #include "config.h"
22d3fd5bddSAmine Khaldi #include "wine/port.h"
23d3fd5bddSAmine Khaldi #include <stdarg.h>
24d3fd5bddSAmine Khaldi #include <string.h>
25d3fd5bddSAmine Khaldi #include <stdlib.h>
26d3fd5bddSAmine Khaldi #include "windef.h"
27d3fd5bddSAmine Khaldi #include "winbase.h"
28d3fd5bddSAmine Khaldi #include "winnls.h"
29d3fd5bddSAmine Khaldi #include "winerror.h"
30d3fd5bddSAmine Khaldi #include "wine/unicode.h"
31d3fd5bddSAmine Khaldi #include "wininet.h"
32d3fd5bddSAmine Khaldi #include "winreg.h"
33d3fd5bddSAmine Khaldi #include "winternl.h"
34d3fd5bddSAmine Khaldi #define NO_SHLWAPI_STREAM
35d3fd5bddSAmine Khaldi #include "shlwapi.h"
36d3fd5bddSAmine Khaldi #include "intshcut.h"
37d3fd5bddSAmine Khaldi #include "wine/debug.h"
38c2c66affSColin Finck
39c2c66affSColin Finck HMODULE WINAPI MLLoadLibraryW(LPCWSTR,HMODULE,DWORD);
40c2c66affSColin Finck BOOL WINAPI MLFreeLibrary(HMODULE);
41c2c66affSColin Finck HRESULT WINAPI MLBuildResURLW(LPCWSTR,HMODULE,DWORD,LPCWSTR,LPWSTR,DWORD);
42c2c66affSColin Finck
43d3fd5bddSAmine Khaldi WINE_DEFAULT_DEBUG_CHANNEL(shell);
44d3fd5bddSAmine Khaldi
heap_strdupAtoW(const char * str)45c2c66affSColin Finck static inline WCHAR *heap_strdupAtoW(const char *str)
46c2c66affSColin Finck {
47c2c66affSColin Finck LPWSTR ret = NULL;
48c2c66affSColin Finck
49c2c66affSColin Finck if(str) {
50c2c66affSColin Finck DWORD len;
51c2c66affSColin Finck
52c2c66affSColin Finck len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
53c2c66affSColin Finck ret = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
54c2c66affSColin Finck MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
55c2c66affSColin Finck }
56c2c66affSColin Finck
57c2c66affSColin Finck return ret;
58c2c66affSColin Finck }
59c2c66affSColin Finck
60c2c66affSColin Finck /* The following schemes were identified in the native version of
61c2c66affSColin Finck * SHLWAPI.DLL version 5.50
62c2c66affSColin Finck */
63c2c66affSColin Finck static const struct {
64c2c66affSColin Finck URL_SCHEME scheme_number;
65c2c66affSColin Finck WCHAR scheme_name[12];
66c2c66affSColin Finck } shlwapi_schemes[] = {
67c2c66affSColin Finck {URL_SCHEME_FTP, {'f','t','p',0}},
68c2c66affSColin Finck {URL_SCHEME_HTTP, {'h','t','t','p',0}},
69c2c66affSColin Finck {URL_SCHEME_GOPHER, {'g','o','p','h','e','r',0}},
70c2c66affSColin Finck {URL_SCHEME_MAILTO, {'m','a','i','l','t','o',0}},
71c2c66affSColin Finck {URL_SCHEME_NEWS, {'n','e','w','s',0}},
72c2c66affSColin Finck {URL_SCHEME_NNTP, {'n','n','t','p',0}},
73c2c66affSColin Finck {URL_SCHEME_TELNET, {'t','e','l','n','e','t',0}},
74c2c66affSColin Finck {URL_SCHEME_WAIS, {'w','a','i','s',0}},
75c2c66affSColin Finck {URL_SCHEME_FILE, {'f','i','l','e',0}},
76c2c66affSColin Finck {URL_SCHEME_MK, {'m','k',0}},
77c2c66affSColin Finck {URL_SCHEME_HTTPS, {'h','t','t','p','s',0}},
78c2c66affSColin Finck {URL_SCHEME_SHELL, {'s','h','e','l','l',0}},
79c2c66affSColin Finck {URL_SCHEME_SNEWS, {'s','n','e','w','s',0}},
80c2c66affSColin Finck {URL_SCHEME_LOCAL, {'l','o','c','a','l',0}},
81c2c66affSColin Finck {URL_SCHEME_JAVASCRIPT, {'j','a','v','a','s','c','r','i','p','t',0}},
82c2c66affSColin Finck {URL_SCHEME_VBSCRIPT, {'v','b','s','c','r','i','p','t',0}},
83c2c66affSColin Finck {URL_SCHEME_ABOUT, {'a','b','o','u','t',0}},
84c2c66affSColin Finck {URL_SCHEME_RES, {'r','e','s',0}},
85c2c66affSColin Finck };
86c2c66affSColin Finck
87c2c66affSColin Finck typedef struct {
88c2c66affSColin Finck LPCWSTR pScheme; /* [out] start of scheme */
89c2c66affSColin Finck DWORD szScheme; /* [out] size of scheme (until colon) */
90c2c66affSColin Finck LPCWSTR pUserName; /* [out] start of Username */
91c2c66affSColin Finck DWORD szUserName; /* [out] size of Username (until ":" or "@") */
92c2c66affSColin Finck LPCWSTR pPassword; /* [out] start of Password */
93c2c66affSColin Finck DWORD szPassword; /* [out] size of Password (until "@") */
94c2c66affSColin Finck LPCWSTR pHostName; /* [out] start of Hostname */
95c2c66affSColin Finck DWORD szHostName; /* [out] size of Hostname (until ":" or "/") */
96c2c66affSColin Finck LPCWSTR pPort; /* [out] start of Port */
97c2c66affSColin Finck DWORD szPort; /* [out] size of Port (until "/" or eos) */
98c2c66affSColin Finck LPCWSTR pQuery; /* [out] start of Query */
99c2c66affSColin Finck DWORD szQuery; /* [out] size of Query (until eos) */
100c2c66affSColin Finck } WINE_PARSE_URL;
101c2c66affSColin Finck
102c2c66affSColin Finck typedef enum {
103c2c66affSColin Finck SCHEME,
104c2c66affSColin Finck HOST,
105c2c66affSColin Finck PORT,
106c2c66affSColin Finck USERPASS,
107c2c66affSColin Finck } WINE_URL_SCAN_TYPE;
108c2c66affSColin Finck
109c2c66affSColin Finck static const CHAR hexDigits[] = "0123456789ABCDEF";
110c2c66affSColin Finck
111c2c66affSColin Finck static const WCHAR fileW[] = {'f','i','l','e','\0'};
112c2c66affSColin Finck
113c2c66affSColin Finck static const unsigned char HashDataLookup[256] = {
114c2c66affSColin Finck 0x01, 0x0E, 0x6E, 0x19, 0x61, 0xAE, 0x84, 0x77, 0x8A, 0xAA, 0x7D, 0x76, 0x1B,
115c2c66affSColin Finck 0xE9, 0x8C, 0x33, 0x57, 0xC5, 0xB1, 0x6B, 0xEA, 0xA9, 0x38, 0x44, 0x1E, 0x07,
116c2c66affSColin Finck 0xAD, 0x49, 0xBC, 0x28, 0x24, 0x41, 0x31, 0xD5, 0x68, 0xBE, 0x39, 0xD3, 0x94,
117c2c66affSColin Finck 0xDF, 0x30, 0x73, 0x0F, 0x02, 0x43, 0xBA, 0xD2, 0x1C, 0x0C, 0xB5, 0x67, 0x46,
118c2c66affSColin Finck 0x16, 0x3A, 0x4B, 0x4E, 0xB7, 0xA7, 0xEE, 0x9D, 0x7C, 0x93, 0xAC, 0x90, 0xB0,
119c2c66affSColin Finck 0xA1, 0x8D, 0x56, 0x3C, 0x42, 0x80, 0x53, 0x9C, 0xF1, 0x4F, 0x2E, 0xA8, 0xC6,
120c2c66affSColin Finck 0x29, 0xFE, 0xB2, 0x55, 0xFD, 0xED, 0xFA, 0x9A, 0x85, 0x58, 0x23, 0xCE, 0x5F,
121c2c66affSColin Finck 0x74, 0xFC, 0xC0, 0x36, 0xDD, 0x66, 0xDA, 0xFF, 0xF0, 0x52, 0x6A, 0x9E, 0xC9,
122c2c66affSColin Finck 0x3D, 0x03, 0x59, 0x09, 0x2A, 0x9B, 0x9F, 0x5D, 0xA6, 0x50, 0x32, 0x22, 0xAF,
123c2c66affSColin Finck 0xC3, 0x64, 0x63, 0x1A, 0x96, 0x10, 0x91, 0x04, 0x21, 0x08, 0xBD, 0x79, 0x40,
124c2c66affSColin Finck 0x4D, 0x48, 0xD0, 0xF5, 0x82, 0x7A, 0x8F, 0x37, 0x69, 0x86, 0x1D, 0xA4, 0xB9,
125c2c66affSColin Finck 0xC2, 0xC1, 0xEF, 0x65, 0xF2, 0x05, 0xAB, 0x7E, 0x0B, 0x4A, 0x3B, 0x89, 0xE4,
126c2c66affSColin Finck 0x6C, 0xBF, 0xE8, 0x8B, 0x06, 0x18, 0x51, 0x14, 0x7F, 0x11, 0x5B, 0x5C, 0xFB,
127c2c66affSColin Finck 0x97, 0xE1, 0xCF, 0x15, 0x62, 0x71, 0x70, 0x54, 0xE2, 0x12, 0xD6, 0xC7, 0xBB,
128c2c66affSColin Finck 0x0D, 0x20, 0x5E, 0xDC, 0xE0, 0xD4, 0xF7, 0xCC, 0xC4, 0x2B, 0xF9, 0xEC, 0x2D,
129c2c66affSColin Finck 0xF4, 0x6F, 0xB6, 0x99, 0x88, 0x81, 0x5A, 0xD9, 0xCA, 0x13, 0xA5, 0xE7, 0x47,
130c2c66affSColin Finck 0xE6, 0x8E, 0x60, 0xE3, 0x3E, 0xB3, 0xF6, 0x72, 0xA2, 0x35, 0xA0, 0xD7, 0xCD,
131c2c66affSColin Finck 0xB4, 0x2F, 0x6D, 0x2C, 0x26, 0x1F, 0x95, 0x87, 0x00, 0xD8, 0x34, 0x3F, 0x17,
132c2c66affSColin Finck 0x25, 0x45, 0x27, 0x75, 0x92, 0xB8, 0xA3, 0xC8, 0xDE, 0xEB, 0xF8, 0xF3, 0xDB,
133c2c66affSColin Finck 0x0A, 0x98, 0x83, 0x7B, 0xE5, 0xCB, 0x4C, 0x78, 0xD1 };
134c2c66affSColin Finck
get_scheme_code(LPCWSTR scheme,DWORD scheme_len)135c2c66affSColin Finck static DWORD get_scheme_code(LPCWSTR scheme, DWORD scheme_len)
136c2c66affSColin Finck {
137c2c66affSColin Finck unsigned int i;
138c2c66affSColin Finck
139c2c66affSColin Finck for(i=0; i < sizeof(shlwapi_schemes)/sizeof(shlwapi_schemes[0]); i++) {
140c2c66affSColin Finck if(scheme_len == strlenW(shlwapi_schemes[i].scheme_name)
141c2c66affSColin Finck && !memicmpW(scheme, shlwapi_schemes[i].scheme_name, scheme_len))
142c2c66affSColin Finck return shlwapi_schemes[i].scheme_number;
143c2c66affSColin Finck }
144c2c66affSColin Finck
145c2c66affSColin Finck return URL_SCHEME_UNKNOWN;
146c2c66affSColin Finck }
147c2c66affSColin Finck
148c2c66affSColin Finck /*************************************************************************
149c2c66affSColin Finck * @ [SHLWAPI.1]
150c2c66affSColin Finck *
151c2c66affSColin Finck * Parse a Url into its constituent parts.
152c2c66affSColin Finck *
153c2c66affSColin Finck * PARAMS
154c2c66affSColin Finck * x [I] Url to parse
155c2c66affSColin Finck * y [O] Undocumented structure holding the parsed information
156c2c66affSColin Finck *
157c2c66affSColin Finck * RETURNS
158c2c66affSColin Finck * Success: S_OK. y contains the parsed Url details.
159c2c66affSColin Finck * Failure: An HRESULT error code.
160c2c66affSColin Finck */
ParseURLA(LPCSTR x,PARSEDURLA * y)161c2c66affSColin Finck HRESULT WINAPI ParseURLA(LPCSTR x, PARSEDURLA *y)
162c2c66affSColin Finck {
163c2c66affSColin Finck WCHAR scheme[INTERNET_MAX_SCHEME_LENGTH];
164c2c66affSColin Finck const char *ptr = x;
165c2c66affSColin Finck int len;
166c2c66affSColin Finck
167c2c66affSColin Finck TRACE("%s %p\n", debugstr_a(x), y);
168c2c66affSColin Finck
169c2c66affSColin Finck if(y->cbSize != sizeof(*y))
170c2c66affSColin Finck return E_INVALIDARG;
171c2c66affSColin Finck
172b7250325SAmine Khaldi while(*ptr && (isalnum(*ptr) || *ptr == '-' || *ptr == '+' || *ptr == '.'))
173c2c66affSColin Finck ptr++;
174c2c66affSColin Finck
175c2c66affSColin Finck if (*ptr != ':' || ptr <= x+1) {
176c2c66affSColin Finck y->pszProtocol = NULL;
177c2c66affSColin Finck return URL_E_INVALID_SYNTAX;
178c2c66affSColin Finck }
179c2c66affSColin Finck
180c2c66affSColin Finck y->pszProtocol = x;
181c2c66affSColin Finck y->cchProtocol = ptr-x;
182c2c66affSColin Finck y->pszSuffix = ptr+1;
183c2c66affSColin Finck y->cchSuffix = strlen(y->pszSuffix);
184c2c66affSColin Finck
185c2c66affSColin Finck len = MultiByteToWideChar(CP_ACP, 0, x, ptr-x,
186c2c66affSColin Finck scheme, sizeof(scheme)/sizeof(WCHAR));
187c2c66affSColin Finck y->nScheme = get_scheme_code(scheme, len);
188c2c66affSColin Finck
189c2c66affSColin Finck return S_OK;
190c2c66affSColin Finck }
191c2c66affSColin Finck
192c2c66affSColin Finck /*************************************************************************
193c2c66affSColin Finck * @ [SHLWAPI.2]
194c2c66affSColin Finck *
195c2c66affSColin Finck * Unicode version of ParseURLA.
196c2c66affSColin Finck */
ParseURLW(LPCWSTR x,PARSEDURLW * y)197c2c66affSColin Finck HRESULT WINAPI ParseURLW(LPCWSTR x, PARSEDURLW *y)
198c2c66affSColin Finck {
199c2c66affSColin Finck const WCHAR *ptr = x;
200c2c66affSColin Finck
201c2c66affSColin Finck TRACE("%s %p\n", debugstr_w(x), y);
202c2c66affSColin Finck
203c2c66affSColin Finck if(y->cbSize != sizeof(*y))
204c2c66affSColin Finck return E_INVALIDARG;
205c2c66affSColin Finck
206b7250325SAmine Khaldi while(*ptr && (isalnumW(*ptr) || *ptr == '-' || *ptr == '+' || *ptr == '.'))
207c2c66affSColin Finck ptr++;
208c2c66affSColin Finck
209c2c66affSColin Finck if (*ptr != ':' || ptr <= x+1) {
210c2c66affSColin Finck y->pszProtocol = NULL;
211c2c66affSColin Finck return URL_E_INVALID_SYNTAX;
212c2c66affSColin Finck }
213c2c66affSColin Finck
214c2c66affSColin Finck y->pszProtocol = x;
215c2c66affSColin Finck y->cchProtocol = ptr-x;
216c2c66affSColin Finck y->pszSuffix = ptr+1;
217c2c66affSColin Finck y->cchSuffix = strlenW(y->pszSuffix);
218c2c66affSColin Finck y->nScheme = get_scheme_code(x, ptr-x);
219c2c66affSColin Finck
220c2c66affSColin Finck return S_OK;
221c2c66affSColin Finck }
222c2c66affSColin Finck
223c2c66affSColin Finck /*************************************************************************
224c2c66affSColin Finck * UrlCanonicalizeA [SHLWAPI.@]
225c2c66affSColin Finck *
226c2c66affSColin Finck * Canonicalize a Url.
227c2c66affSColin Finck *
228c2c66affSColin Finck * PARAMS
229c2c66affSColin Finck * pszUrl [I] Url to cCanonicalize
230c2c66affSColin Finck * pszCanonicalized [O] Destination for converted Url.
231c2c66affSColin Finck * pcchCanonicalized [I/O] Length of pszUrl, destination for length of pszCanonicalized
232c2c66affSColin Finck * dwFlags [I] Flags controlling the conversion.
233c2c66affSColin Finck *
234c2c66affSColin Finck * RETURNS
235c2c66affSColin Finck * Success: S_OK. The pszCanonicalized contains the converted Url.
236c2c66affSColin Finck * Failure: E_POINTER, if *pcchCanonicalized is too small.
237c2c66affSColin Finck *
238c2c66affSColin Finck * MSDN incorrectly describes the flags for this function. They should be:
239c2c66affSColin Finck *| URL_DONT_ESCAPE_EXTRA_INFO 0x02000000
240c2c66affSColin Finck *| URL_ESCAPE_SPACES_ONLY 0x04000000
241c2c66affSColin Finck *| URL_ESCAPE_PERCENT 0x00001000
242c2c66affSColin Finck *| URL_ESCAPE_UNSAFE 0x10000000
243c2c66affSColin Finck *| URL_UNESCAPE 0x10000000
244c2c66affSColin Finck *| URL_DONT_SIMPLIFY 0x08000000
245c2c66affSColin Finck *| URL_ESCAPE_SEGMENT_ONLY 0x00002000
246c2c66affSColin Finck */
UrlCanonicalizeA(LPCSTR pszUrl,LPSTR pszCanonicalized,LPDWORD pcchCanonicalized,DWORD dwFlags)247c2c66affSColin Finck HRESULT WINAPI UrlCanonicalizeA(LPCSTR pszUrl, LPSTR pszCanonicalized,
248c2c66affSColin Finck LPDWORD pcchCanonicalized, DWORD dwFlags)
249c2c66affSColin Finck {
250c2c66affSColin Finck LPWSTR url, canonical;
251c2c66affSColin Finck HRESULT ret;
252c2c66affSColin Finck
253c2c66affSColin Finck TRACE("(%s, %p, %p, 0x%08x) *pcchCanonicalized: %d\n", debugstr_a(pszUrl), pszCanonicalized,
254c2c66affSColin Finck pcchCanonicalized, dwFlags, pcchCanonicalized ? *pcchCanonicalized : -1);
255c2c66affSColin Finck
256c2c66affSColin Finck if(!pszUrl || !pszCanonicalized || !pcchCanonicalized || !*pcchCanonicalized)
257c2c66affSColin Finck return E_INVALIDARG;
258c2c66affSColin Finck
259c2c66affSColin Finck url = heap_strdupAtoW(pszUrl);
260c2c66affSColin Finck canonical = HeapAlloc(GetProcessHeap(), 0, *pcchCanonicalized*sizeof(WCHAR));
261c2c66affSColin Finck if(!url || !canonical) {
262c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, url);
263c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, canonical);
264c2c66affSColin Finck return E_OUTOFMEMORY;
265c2c66affSColin Finck }
266c2c66affSColin Finck
267c2c66affSColin Finck ret = UrlCanonicalizeW(url, canonical, pcchCanonicalized, dwFlags);
268c2c66affSColin Finck if(ret == S_OK)
269c2c66affSColin Finck WideCharToMultiByte(CP_ACP, 0, canonical, -1, pszCanonicalized,
270c2c66affSColin Finck *pcchCanonicalized+1, NULL, NULL);
271c2c66affSColin Finck
272c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, url);
273c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, canonical);
274c2c66affSColin Finck return ret;
275c2c66affSColin Finck }
276c2c66affSColin Finck
277c2c66affSColin Finck /*************************************************************************
278c2c66affSColin Finck * UrlCanonicalizeW [SHLWAPI.@]
279c2c66affSColin Finck *
280c2c66affSColin Finck * See UrlCanonicalizeA.
281c2c66affSColin Finck */
UrlCanonicalizeW(LPCWSTR pszUrl,LPWSTR pszCanonicalized,LPDWORD pcchCanonicalized,DWORD dwFlags)282c2c66affSColin Finck HRESULT WINAPI UrlCanonicalizeW(LPCWSTR pszUrl, LPWSTR pszCanonicalized,
283c2c66affSColin Finck LPDWORD pcchCanonicalized, DWORD dwFlags)
284c2c66affSColin Finck {
285c2c66affSColin Finck HRESULT hr = S_OK;
286c2c66affSColin Finck DWORD EscapeFlags;
287c2c66affSColin Finck LPCWSTR wk1, root;
288c2c66affSColin Finck LPWSTR lpszUrlCpy, url, wk2, mp, mp2;
289c2c66affSColin Finck INT state;
290c2c66affSColin Finck DWORD nByteLen, nLen, nWkLen;
291c2c66affSColin Finck BOOL is_file_url;
292c2c66affSColin Finck WCHAR slash = '\0';
293c2c66affSColin Finck
294c2c66affSColin Finck static const WCHAR wszFile[] = {'f','i','l','e',':'};
295c2c66affSColin Finck static const WCHAR wszRes[] = {'r','e','s',':'};
296c2c66affSColin Finck static const WCHAR wszHttp[] = {'h','t','t','p',':'};
297c2c66affSColin Finck static const WCHAR wszLocalhost[] = {'l','o','c','a','l','h','o','s','t'};
298c2c66affSColin Finck static const WCHAR wszFilePrefix[] = {'f','i','l','e',':','/','/','/'};
299c2c66affSColin Finck
300c2c66affSColin Finck TRACE("(%s, %p, %p, 0x%08x) *pcchCanonicalized: %d\n", debugstr_w(pszUrl), pszCanonicalized,
301c2c66affSColin Finck pcchCanonicalized, dwFlags, pcchCanonicalized ? *pcchCanonicalized : -1);
302c2c66affSColin Finck
303c2c66affSColin Finck if(!pszUrl || !pszCanonicalized || !pcchCanonicalized || !*pcchCanonicalized)
304c2c66affSColin Finck return E_INVALIDARG;
305c2c66affSColin Finck
306c2c66affSColin Finck if(!*pszUrl) {
307c2c66affSColin Finck *pszCanonicalized = 0;
308c2c66affSColin Finck return S_OK;
309c2c66affSColin Finck }
310c2c66affSColin Finck
311c2c66affSColin Finck /* Remove '\t' characters from URL */
312c2c66affSColin Finck nByteLen = (strlenW(pszUrl) + 1) * sizeof(WCHAR); /* length in bytes */
313c2c66affSColin Finck url = HeapAlloc(GetProcessHeap(), 0, nByteLen);
314c2c66affSColin Finck if(!url)
315c2c66affSColin Finck return E_OUTOFMEMORY;
316c2c66affSColin Finck
317c2c66affSColin Finck wk1 = pszUrl;
318c2c66affSColin Finck wk2 = url;
319c2c66affSColin Finck do {
320c2c66affSColin Finck while(*wk1 == '\t')
321c2c66affSColin Finck wk1++;
322c2c66affSColin Finck *wk2++ = *wk1;
323c2c66affSColin Finck } while(*wk1++);
324c2c66affSColin Finck
325c2c66affSColin Finck /* Allocate memory for simplified URL (before escaping) */
326c2c66affSColin Finck nByteLen = (wk2-url)*sizeof(WCHAR);
327c2c66affSColin Finck lpszUrlCpy = HeapAlloc(GetProcessHeap(), 0,
328c2c66affSColin Finck nByteLen+sizeof(wszFilePrefix)+sizeof(WCHAR));
329c2c66affSColin Finck if(!lpszUrlCpy) {
330c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, url);
331c2c66affSColin Finck return E_OUTOFMEMORY;
332c2c66affSColin Finck }
333c2c66affSColin Finck
334c2c66affSColin Finck is_file_url = !strncmpW(wszFile, url, sizeof(wszFile)/sizeof(WCHAR));
335c2c66affSColin Finck
336c2c66affSColin Finck if ((nByteLen >= sizeof(wszHttp) &&
337c2c66affSColin Finck !memcmp(wszHttp, url, sizeof(wszHttp))) || is_file_url)
338c2c66affSColin Finck slash = '/';
339c2c66affSColin Finck
340c2c66affSColin Finck if((dwFlags & (URL_FILE_USE_PATHURL | URL_WININET_COMPATIBILITY)) && is_file_url)
341c2c66affSColin Finck slash = '\\';
342c2c66affSColin Finck
343c2c66affSColin Finck if(nByteLen >= sizeof(wszRes) && !memcmp(wszRes, url, sizeof(wszRes))) {
344c2c66affSColin Finck dwFlags &= ~URL_FILE_USE_PATHURL;
345c2c66affSColin Finck slash = '\0';
346c2c66affSColin Finck }
347c2c66affSColin Finck
348c2c66affSColin Finck /*
349c2c66affSColin Finck * state =
350c2c66affSColin Finck * 0 initial 1,3
351c2c66affSColin Finck * 1 have 2[+] alnum 2,3
352c2c66affSColin Finck * 2 have scheme (found :) 4,6,3
353c2c66affSColin Finck * 3 failed (no location)
354c2c66affSColin Finck * 4 have // 5,3
355c2c66affSColin Finck * 5 have 1[+] alnum 6,3
356c2c66affSColin Finck * 6 have location (found /) save root location
357c2c66affSColin Finck */
358c2c66affSColin Finck
359c2c66affSColin Finck wk1 = url;
360c2c66affSColin Finck wk2 = lpszUrlCpy;
361c2c66affSColin Finck state = 0;
362c2c66affSColin Finck
363c2c66affSColin Finck if(url[1] == ':') { /* Assume path */
364c2c66affSColin Finck memcpy(wk2, wszFilePrefix, sizeof(wszFilePrefix));
365c2c66affSColin Finck wk2 += sizeof(wszFilePrefix)/sizeof(WCHAR);
366c2c66affSColin Finck if (dwFlags & (URL_FILE_USE_PATHURL | URL_WININET_COMPATIBILITY))
367c2c66affSColin Finck {
368c2c66affSColin Finck slash = '\\';
369c2c66affSColin Finck --wk2;
370c2c66affSColin Finck }
371c2c66affSColin Finck else
372c2c66affSColin Finck dwFlags |= URL_ESCAPE_UNSAFE;
373c2c66affSColin Finck state = 5;
374c2c66affSColin Finck is_file_url = TRUE;
375c2c66affSColin Finck } else if(url[0] == '/') {
376c2c66affSColin Finck state = 5;
377c2c66affSColin Finck is_file_url = TRUE;
378c2c66affSColin Finck }
379c2c66affSColin Finck
380c2c66affSColin Finck while (*wk1) {
381c2c66affSColin Finck switch (state) {
382c2c66affSColin Finck case 0:
383c2c66affSColin Finck if (!isalnumW(*wk1)) {state = 3; break;}
384c2c66affSColin Finck *wk2++ = *wk1++;
385c2c66affSColin Finck if (!isalnumW(*wk1)) {state = 3; break;}
386c2c66affSColin Finck *wk2++ = *wk1++;
387c2c66affSColin Finck state = 1;
388c2c66affSColin Finck break;
389c2c66affSColin Finck case 1:
390c2c66affSColin Finck *wk2++ = *wk1;
391c2c66affSColin Finck if (*wk1++ == ':') state = 2;
392c2c66affSColin Finck break;
393c2c66affSColin Finck case 2:
394c2c66affSColin Finck *wk2++ = *wk1++;
395c2c66affSColin Finck if (*wk1 != '/') {state = 6; break;}
396c2c66affSColin Finck *wk2++ = *wk1++;
397c2c66affSColin Finck if((dwFlags & URL_FILE_USE_PATHURL) && nByteLen >= sizeof(wszLocalhost)
398c2c66affSColin Finck && is_file_url
399c2c66affSColin Finck && !memcmp(wszLocalhost, wk1, sizeof(wszLocalhost))){
400c2c66affSColin Finck wk1 += sizeof(wszLocalhost)/sizeof(WCHAR);
401c2c66affSColin Finck while(*wk1 == '\\' && (dwFlags & URL_FILE_USE_PATHURL))
402c2c66affSColin Finck wk1++;
403c2c66affSColin Finck }
404c2c66affSColin Finck
405c2c66affSColin Finck if(*wk1 == '/' && (dwFlags & URL_FILE_USE_PATHURL)){
406c2c66affSColin Finck wk1++;
407c2c66affSColin Finck }else if(is_file_url){
408c2c66affSColin Finck const WCHAR *body = wk1;
409c2c66affSColin Finck
410c2c66affSColin Finck while(*body == '/')
411c2c66affSColin Finck ++body;
412c2c66affSColin Finck
413c2c66affSColin Finck if(isalnumW(*body) && *(body+1) == ':'){
414c2c66affSColin Finck if(!(dwFlags & (URL_WININET_COMPATIBILITY | URL_FILE_USE_PATHURL))){
415c2c66affSColin Finck if(slash)
416c2c66affSColin Finck *wk2++ = slash;
417c2c66affSColin Finck else
418c2c66affSColin Finck *wk2++ = '/';
419c2c66affSColin Finck }
420c2c66affSColin Finck }else{
421c2c66affSColin Finck if(dwFlags & URL_WININET_COMPATIBILITY){
422c2c66affSColin Finck if(*wk1 == '/' && *(wk1+1) != '/'){
423c2c66affSColin Finck *wk2++ = '\\';
424c2c66affSColin Finck }else{
425c2c66affSColin Finck *wk2++ = '\\';
426c2c66affSColin Finck *wk2++ = '\\';
427c2c66affSColin Finck }
428c2c66affSColin Finck }else{
429c2c66affSColin Finck if(*wk1 == '/' && *(wk1+1) != '/'){
430c2c66affSColin Finck if(slash)
431c2c66affSColin Finck *wk2++ = slash;
432c2c66affSColin Finck else
433c2c66affSColin Finck *wk2++ = '/';
434c2c66affSColin Finck }
435c2c66affSColin Finck }
436c2c66affSColin Finck }
437c2c66affSColin Finck wk1 = body;
438c2c66affSColin Finck }
439c2c66affSColin Finck state = 4;
440c2c66affSColin Finck break;
441c2c66affSColin Finck case 3:
442c2c66affSColin Finck nWkLen = strlenW(wk1);
443c2c66affSColin Finck memcpy(wk2, wk1, (nWkLen + 1) * sizeof(WCHAR));
444c2c66affSColin Finck mp = wk2;
445c2c66affSColin Finck wk1 += nWkLen;
446c2c66affSColin Finck wk2 += nWkLen;
447c2c66affSColin Finck
448c2c66affSColin Finck if(slash) {
449c2c66affSColin Finck while(mp < wk2) {
450c2c66affSColin Finck if(*mp == '/' || *mp == '\\')
451c2c66affSColin Finck *mp = slash;
452c2c66affSColin Finck mp++;
453c2c66affSColin Finck }
454c2c66affSColin Finck }
455c2c66affSColin Finck break;
456c2c66affSColin Finck case 4:
457c2c66affSColin Finck if (!isalnumW(*wk1) && (*wk1 != '-') && (*wk1 != '.') && (*wk1 != ':'))
458c2c66affSColin Finck {state = 3; break;}
459c2c66affSColin Finck while(isalnumW(*wk1) || (*wk1 == '-') || (*wk1 == '.') || (*wk1 == ':'))
460c2c66affSColin Finck *wk2++ = *wk1++;
461c2c66affSColin Finck state = 5;
462c2c66affSColin Finck if (!*wk1) {
463c2c66affSColin Finck if(slash)
464c2c66affSColin Finck *wk2++ = slash;
465c2c66affSColin Finck else
466c2c66affSColin Finck *wk2++ = '/';
467c2c66affSColin Finck }
468c2c66affSColin Finck break;
469c2c66affSColin Finck case 5:
470c2c66affSColin Finck if (*wk1 != '/' && *wk1 != '\\') {state = 3; break;}
471c2c66affSColin Finck while(*wk1 == '/' || *wk1 == '\\') {
472c2c66affSColin Finck if(slash)
473c2c66affSColin Finck *wk2++ = slash;
474c2c66affSColin Finck else
475c2c66affSColin Finck *wk2++ = *wk1;
476c2c66affSColin Finck wk1++;
477c2c66affSColin Finck }
478c2c66affSColin Finck state = 6;
479c2c66affSColin Finck break;
480c2c66affSColin Finck case 6:
481c2c66affSColin Finck if(dwFlags & URL_DONT_SIMPLIFY) {
482c2c66affSColin Finck state = 3;
483c2c66affSColin Finck break;
484c2c66affSColin Finck }
485c2c66affSColin Finck
486c2c66affSColin Finck /* Now at root location, cannot back up any more. */
487c2c66affSColin Finck /* "root" will point at the '/' */
488c2c66affSColin Finck
489c2c66affSColin Finck root = wk2-1;
490c2c66affSColin Finck while (*wk1) {
491c2c66affSColin Finck mp = strchrW(wk1, '/');
492c2c66affSColin Finck mp2 = strchrW(wk1, '\\');
493c2c66affSColin Finck if(mp2 && (!mp || mp2 < mp))
494c2c66affSColin Finck mp = mp2;
495c2c66affSColin Finck if (!mp) {
496c2c66affSColin Finck nWkLen = strlenW(wk1);
497c2c66affSColin Finck memcpy(wk2, wk1, (nWkLen + 1) * sizeof(WCHAR));
498c2c66affSColin Finck wk1 += nWkLen;
499c2c66affSColin Finck wk2 += nWkLen;
500c2c66affSColin Finck continue;
501c2c66affSColin Finck }
502c2c66affSColin Finck nLen = mp - wk1;
503c2c66affSColin Finck if(nLen) {
504c2c66affSColin Finck memcpy(wk2, wk1, nLen * sizeof(WCHAR));
505c2c66affSColin Finck wk2 += nLen;
506c2c66affSColin Finck wk1 += nLen;
507c2c66affSColin Finck }
508c2c66affSColin Finck if(slash)
509c2c66affSColin Finck *wk2++ = slash;
510c2c66affSColin Finck else
511c2c66affSColin Finck *wk2++ = *wk1;
512c2c66affSColin Finck wk1++;
513c2c66affSColin Finck
514c2c66affSColin Finck while (*wk1 == '.') {
515c2c66affSColin Finck TRACE("found '/.'\n");
516c2c66affSColin Finck if (wk1[1] == '/' || wk1[1] == '\\') {
517c2c66affSColin Finck /* case of /./ -> skip the ./ */
518c2c66affSColin Finck wk1 += 2;
519c2c66affSColin Finck }
520c2c66affSColin Finck else if (wk1[1] == '.' && (wk1[2] == '/'
521c2c66affSColin Finck || wk1[2] == '\\' || wk1[2] == '?'
522c2c66affSColin Finck || wk1[2] == '#' || !wk1[2])) {
523c2c66affSColin Finck /* case /../ -> need to backup wk2 */
524c2c66affSColin Finck TRACE("found '/../'\n");
525c2c66affSColin Finck *(wk2-1) = '\0'; /* set end of string */
526c2c66affSColin Finck mp = strrchrW(root, '/');
527c2c66affSColin Finck mp2 = strrchrW(root, '\\');
528c2c66affSColin Finck if(mp2 && (!mp || mp2 < mp))
529c2c66affSColin Finck mp = mp2;
530c2c66affSColin Finck if (mp && (mp >= root)) {
531c2c66affSColin Finck /* found valid backup point */
532c2c66affSColin Finck wk2 = mp + 1;
533c2c66affSColin Finck if(wk1[2] != '/' && wk1[2] != '\\')
534c2c66affSColin Finck wk1 += 2;
535c2c66affSColin Finck else
536c2c66affSColin Finck wk1 += 3;
537c2c66affSColin Finck }
538c2c66affSColin Finck else {
539c2c66affSColin Finck /* did not find point, restore '/' */
540c2c66affSColin Finck *(wk2-1) = slash;
541c2c66affSColin Finck break;
542c2c66affSColin Finck }
543c2c66affSColin Finck }
544c2c66affSColin Finck else
545c2c66affSColin Finck break;
546c2c66affSColin Finck }
547c2c66affSColin Finck }
548c2c66affSColin Finck *wk2 = '\0';
549c2c66affSColin Finck break;
550c2c66affSColin Finck default:
551c2c66affSColin Finck FIXME("how did we get here - state=%d\n", state);
552c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, lpszUrlCpy);
553c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, url);
554c2c66affSColin Finck return E_INVALIDARG;
555c2c66affSColin Finck }
556c2c66affSColin Finck *wk2 = '\0';
557c2c66affSColin Finck TRACE("Simplified, orig <%s>, simple <%s>\n",
558c2c66affSColin Finck debugstr_w(pszUrl), debugstr_w(lpszUrlCpy));
559c2c66affSColin Finck }
560c2c66affSColin Finck nLen = lstrlenW(lpszUrlCpy);
561c2c66affSColin Finck while ((nLen > 0) && ((lpszUrlCpy[nLen-1] <= ' ')))
562c2c66affSColin Finck lpszUrlCpy[--nLen]=0;
563c2c66affSColin Finck
564c2c66affSColin Finck if((dwFlags & URL_UNESCAPE) ||
565c2c66affSColin Finck ((dwFlags & URL_FILE_USE_PATHURL) && nByteLen >= sizeof(wszFile)
566c2c66affSColin Finck && !memcmp(wszFile, url, sizeof(wszFile))))
567c2c66affSColin Finck UrlUnescapeW(lpszUrlCpy, NULL, &nLen, URL_UNESCAPE_INPLACE);
568c2c66affSColin Finck
569c2c66affSColin Finck if((EscapeFlags = dwFlags & (URL_ESCAPE_UNSAFE |
570c2c66affSColin Finck URL_ESCAPE_SPACES_ONLY |
571c2c66affSColin Finck URL_ESCAPE_PERCENT |
572c2c66affSColin Finck URL_DONT_ESCAPE_EXTRA_INFO |
573c2c66affSColin Finck URL_ESCAPE_SEGMENT_ONLY ))) {
574c2c66affSColin Finck EscapeFlags &= ~URL_ESCAPE_UNSAFE;
575c2c66affSColin Finck hr = UrlEscapeW(lpszUrlCpy, pszCanonicalized, pcchCanonicalized,
576c2c66affSColin Finck EscapeFlags);
577c2c66affSColin Finck } else { /* No escaping needed, just copy the string */
578c2c66affSColin Finck nLen = lstrlenW(lpszUrlCpy);
579c2c66affSColin Finck if(nLen < *pcchCanonicalized)
580c2c66affSColin Finck memcpy(pszCanonicalized, lpszUrlCpy, (nLen + 1)*sizeof(WCHAR));
581c2c66affSColin Finck else {
582c2c66affSColin Finck hr = E_POINTER;
583c2c66affSColin Finck nLen++;
584c2c66affSColin Finck }
585c2c66affSColin Finck *pcchCanonicalized = nLen;
586c2c66affSColin Finck }
587c2c66affSColin Finck
588c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, lpszUrlCpy);
589c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, url);
590c2c66affSColin Finck
591c2c66affSColin Finck if (hr == S_OK)
592c2c66affSColin Finck TRACE("result %s\n", debugstr_w(pszCanonicalized));
593c2c66affSColin Finck
594c2c66affSColin Finck return hr;
595c2c66affSColin Finck }
596c2c66affSColin Finck
597c2c66affSColin Finck /*************************************************************************
598c2c66affSColin Finck * UrlCombineA [SHLWAPI.@]
599c2c66affSColin Finck *
600c2c66affSColin Finck * Combine two Urls.
601c2c66affSColin Finck *
602c2c66affSColin Finck * PARAMS
603c2c66affSColin Finck * pszBase [I] Base Url
604c2c66affSColin Finck * pszRelative [I] Url to combine with pszBase
605c2c66affSColin Finck * pszCombined [O] Destination for combined Url
606c2c66affSColin Finck * pcchCombined [O] Destination for length of pszCombined
607c2c66affSColin Finck * dwFlags [I] URL_ flags from "shlwapi.h"
608c2c66affSColin Finck *
609c2c66affSColin Finck * RETURNS
610c2c66affSColin Finck * Success: S_OK. pszCombined contains the combined Url, pcchCombined
611c2c66affSColin Finck * contains its length.
612c2c66affSColin Finck * Failure: An HRESULT error code indicating the error.
613c2c66affSColin Finck */
UrlCombineA(LPCSTR pszBase,LPCSTR pszRelative,LPSTR pszCombined,LPDWORD pcchCombined,DWORD dwFlags)614c2c66affSColin Finck HRESULT WINAPI UrlCombineA(LPCSTR pszBase, LPCSTR pszRelative,
615c2c66affSColin Finck LPSTR pszCombined, LPDWORD pcchCombined,
616c2c66affSColin Finck DWORD dwFlags)
617c2c66affSColin Finck {
618c2c66affSColin Finck LPWSTR base, relative, combined;
619c2c66affSColin Finck DWORD ret, len, len2;
620c2c66affSColin Finck
621c2c66affSColin Finck TRACE("(base %s, Relative %s, Combine size %d, flags %08x) using W version\n",
622c2c66affSColin Finck debugstr_a(pszBase),debugstr_a(pszRelative),
623c2c66affSColin Finck pcchCombined?*pcchCombined:0,dwFlags);
624c2c66affSColin Finck
625c2c66affSColin Finck if(!pszBase || !pszRelative || !pcchCombined)
626c2c66affSColin Finck return E_INVALIDARG;
627c2c66affSColin Finck
628c2c66affSColin Finck base = HeapAlloc(GetProcessHeap(), 0,
629c2c66affSColin Finck (3*INTERNET_MAX_URL_LENGTH) * sizeof(WCHAR));
630c2c66affSColin Finck relative = base + INTERNET_MAX_URL_LENGTH;
631c2c66affSColin Finck combined = relative + INTERNET_MAX_URL_LENGTH;
632c2c66affSColin Finck
633c2c66affSColin Finck MultiByteToWideChar(CP_ACP, 0, pszBase, -1, base, INTERNET_MAX_URL_LENGTH);
634c2c66affSColin Finck MultiByteToWideChar(CP_ACP, 0, pszRelative, -1, relative, INTERNET_MAX_URL_LENGTH);
635c2c66affSColin Finck len = *pcchCombined;
636c2c66affSColin Finck
637c2c66affSColin Finck ret = UrlCombineW(base, relative, pszCombined?combined:NULL, &len, dwFlags);
638c2c66affSColin Finck if (ret != S_OK) {
639c2c66affSColin Finck *pcchCombined = len;
640c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, base);
641c2c66affSColin Finck return ret;
642c2c66affSColin Finck }
643c2c66affSColin Finck
644c2c66affSColin Finck len2 = WideCharToMultiByte(CP_ACP, 0, combined, len, NULL, 0, NULL, NULL);
645c2c66affSColin Finck if (len2 > *pcchCombined) {
646c2c66affSColin Finck *pcchCombined = len2;
647c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, base);
648c2c66affSColin Finck return E_POINTER;
649c2c66affSColin Finck }
650c2c66affSColin Finck WideCharToMultiByte(CP_ACP, 0, combined, len+1, pszCombined, (*pcchCombined)+1,
651c2c66affSColin Finck NULL, NULL);
652c2c66affSColin Finck *pcchCombined = len2;
653c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, base);
654c2c66affSColin Finck return S_OK;
655c2c66affSColin Finck }
656c2c66affSColin Finck
657c2c66affSColin Finck /*************************************************************************
658c2c66affSColin Finck * UrlCombineW [SHLWAPI.@]
659c2c66affSColin Finck *
660c2c66affSColin Finck * See UrlCombineA.
661c2c66affSColin Finck */
UrlCombineW(LPCWSTR pszBase,LPCWSTR pszRelative,LPWSTR pszCombined,LPDWORD pcchCombined,DWORD dwFlags)662c2c66affSColin Finck HRESULT WINAPI UrlCombineW(LPCWSTR pszBase, LPCWSTR pszRelative,
663c2c66affSColin Finck LPWSTR pszCombined, LPDWORD pcchCombined,
664c2c66affSColin Finck DWORD dwFlags)
665c2c66affSColin Finck {
666c2c66affSColin Finck PARSEDURLW base, relative;
667c2c66affSColin Finck DWORD myflags, sizeloc = 0;
668c2c66affSColin Finck DWORD i, len, res1, res2, process_case = 0;
669c2c66affSColin Finck LPWSTR work, preliminary, mbase, mrelative;
670c2c66affSColin Finck static const WCHAR myfilestr[] = {'f','i','l','e',':','/','/','/','\0'};
671c2c66affSColin Finck static const WCHAR fragquerystr[] = {'#','?',0};
672c2c66affSColin Finck HRESULT ret;
673c2c66affSColin Finck
674c2c66affSColin Finck TRACE("(base %s, Relative %s, Combine size %d, flags %08x)\n",
675c2c66affSColin Finck debugstr_w(pszBase),debugstr_w(pszRelative),
676c2c66affSColin Finck pcchCombined?*pcchCombined:0,dwFlags);
677c2c66affSColin Finck
678c2c66affSColin Finck if(!pszBase || !pszRelative || !pcchCombined)
679c2c66affSColin Finck return E_INVALIDARG;
680c2c66affSColin Finck
681c2c66affSColin Finck base.cbSize = sizeof(base);
682c2c66affSColin Finck relative.cbSize = sizeof(relative);
683c2c66affSColin Finck
684c2c66affSColin Finck /* Get space for duplicates of the input and the output */
685c2c66affSColin Finck preliminary = HeapAlloc(GetProcessHeap(), 0, (3*INTERNET_MAX_URL_LENGTH) *
686c2c66affSColin Finck sizeof(WCHAR));
687c2c66affSColin Finck mbase = preliminary + INTERNET_MAX_URL_LENGTH;
688c2c66affSColin Finck mrelative = mbase + INTERNET_MAX_URL_LENGTH;
689c2c66affSColin Finck *preliminary = '\0';
690c2c66affSColin Finck
691c2c66affSColin Finck /* Canonicalize the base input prior to looking for the scheme */
692c2c66affSColin Finck myflags = dwFlags & (URL_DONT_SIMPLIFY | URL_UNESCAPE);
693c2c66affSColin Finck len = INTERNET_MAX_URL_LENGTH;
694c2c66affSColin Finck UrlCanonicalizeW(pszBase, mbase, &len, myflags);
695c2c66affSColin Finck
696c2c66affSColin Finck /* Canonicalize the relative input prior to looking for the scheme */
697c2c66affSColin Finck len = INTERNET_MAX_URL_LENGTH;
698c2c66affSColin Finck UrlCanonicalizeW(pszRelative, mrelative, &len, myflags);
699c2c66affSColin Finck
700c2c66affSColin Finck /* See if the base has a scheme */
701c2c66affSColin Finck res1 = ParseURLW(mbase, &base);
702c2c66affSColin Finck if (res1) {
703c2c66affSColin Finck /* if pszBase has no scheme, then return pszRelative */
704c2c66affSColin Finck TRACE("no scheme detected in Base\n");
705c2c66affSColin Finck process_case = 1;
706c2c66affSColin Finck }
707c2c66affSColin Finck else do {
708c2c66affSColin Finck BOOL manual_search = FALSE;
709c2c66affSColin Finck
710c2c66affSColin Finck work = (LPWSTR)base.pszProtocol;
711c2c66affSColin Finck for(i=0; i<base.cchProtocol; i++)
712c2c66affSColin Finck work[i] = tolowerW(work[i]);
713c2c66affSColin Finck
714c2c66affSColin Finck /* mk is a special case */
715c2c66affSColin Finck if(base.nScheme == URL_SCHEME_MK) {
716c2c66affSColin Finck static const WCHAR wsz[] = {':',':',0};
717c2c66affSColin Finck
718c2c66affSColin Finck WCHAR *ptr = strstrW(base.pszSuffix, wsz);
719c2c66affSColin Finck if(ptr) {
720c2c66affSColin Finck int delta;
721c2c66affSColin Finck
722c2c66affSColin Finck ptr += 2;
723c2c66affSColin Finck delta = ptr-base.pszSuffix;
724c2c66affSColin Finck base.cchProtocol += delta;
725c2c66affSColin Finck base.pszSuffix += delta;
726c2c66affSColin Finck base.cchSuffix -= delta;
727c2c66affSColin Finck }
728c2c66affSColin Finck }else {
729c2c66affSColin Finck /* get size of location field (if it exists) */
730c2c66affSColin Finck work = (LPWSTR)base.pszSuffix;
731c2c66affSColin Finck sizeloc = 0;
732c2c66affSColin Finck if (*work++ == '/') {
733c2c66affSColin Finck if (*work++ == '/') {
734c2c66affSColin Finck /* At this point have start of location and
735c2c66affSColin Finck * it ends at next '/' or end of string.
736c2c66affSColin Finck */
737c2c66affSColin Finck while(*work && (*work != '/')) work++;
738c2c66affSColin Finck sizeloc = (DWORD)(work - base.pszSuffix);
739c2c66affSColin Finck }
740c2c66affSColin Finck }
741c2c66affSColin Finck }
742c2c66affSColin Finck
743c2c66affSColin Finck /* If there is a '?', then the remaining part can only contain a
744c2c66affSColin Finck * query string or fragment, so start looking for the last leaf
745c2c66affSColin Finck * from the '?'. Otherwise, if there is a '#' and the characters
746c2c66affSColin Finck * immediately preceding it are ".htm[l]", then begin looking for
747c2c66affSColin Finck * the last leaf starting from the '#'. Otherwise the '#' is not
748c2c66affSColin Finck * meaningful and just start looking from the end. */
749c2c66affSColin Finck if ((work = strpbrkW(base.pszSuffix + sizeloc, fragquerystr))) {
750c2c66affSColin Finck const WCHAR htmlW[] = {'.','h','t','m','l',0};
751c2c66affSColin Finck const int len_htmlW = 5;
752c2c66affSColin Finck const WCHAR htmW[] = {'.','h','t','m',0};
753c2c66affSColin Finck const int len_htmW = 4;
754c2c66affSColin Finck
755c2c66affSColin Finck if (*work == '?' || base.nScheme == URL_SCHEME_HTTP || base.nScheme == URL_SCHEME_HTTPS)
756c2c66affSColin Finck manual_search = TRUE;
757c2c66affSColin Finck else if (work - base.pszSuffix > len_htmW) {
758c2c66affSColin Finck work -= len_htmW;
759c2c66affSColin Finck if (strncmpiW(work, htmW, len_htmW) == 0)
760c2c66affSColin Finck manual_search = TRUE;
761c2c66affSColin Finck work += len_htmW;
762c2c66affSColin Finck }
763c2c66affSColin Finck
764c2c66affSColin Finck if (!manual_search &&
765c2c66affSColin Finck work - base.pszSuffix > len_htmlW) {
766c2c66affSColin Finck work -= len_htmlW;
767c2c66affSColin Finck if (strncmpiW(work, htmlW, len_htmlW) == 0)
768c2c66affSColin Finck manual_search = TRUE;
769c2c66affSColin Finck work += len_htmlW;
770c2c66affSColin Finck }
771c2c66affSColin Finck }
772c2c66affSColin Finck
773c2c66affSColin Finck if (manual_search) {
774c2c66affSColin Finck /* search backwards starting from the current position */
775c2c66affSColin Finck while (*work != '/' && work > base.pszSuffix + sizeloc)
776c2c66affSColin Finck --work;
777c2c66affSColin Finck base.cchSuffix = work - base.pszSuffix + 1;
778c2c66affSColin Finck }else {
779c2c66affSColin Finck /* search backwards starting from the end of the string */
780c2c66affSColin Finck work = strrchrW((base.pszSuffix+sizeloc), '/');
781c2c66affSColin Finck if (work) {
782c2c66affSColin Finck len = (DWORD)(work - base.pszSuffix + 1);
783c2c66affSColin Finck base.cchSuffix = len;
784c2c66affSColin Finck }else
785c2c66affSColin Finck base.cchSuffix = sizeloc;
786c2c66affSColin Finck }
787c2c66affSColin Finck
788c2c66affSColin Finck /*
789c2c66affSColin Finck * At this point:
790c2c66affSColin Finck * .pszSuffix points to location (starting with '//')
791c2c66affSColin Finck * .cchSuffix length of location (above) and rest less the last
792c2c66affSColin Finck * leaf (if any)
793c2c66affSColin Finck * sizeloc length of location (above) up to but not including
794c2c66affSColin Finck * the last '/'
795c2c66affSColin Finck */
796c2c66affSColin Finck
797c2c66affSColin Finck res2 = ParseURLW(mrelative, &relative);
798c2c66affSColin Finck if (res2) {
799c2c66affSColin Finck /* no scheme in pszRelative */
800c2c66affSColin Finck TRACE("no scheme detected in Relative\n");
801c2c66affSColin Finck relative.pszSuffix = mrelative; /* case 3,4,5 depends on this */
802c2c66affSColin Finck relative.cchSuffix = strlenW(mrelative);
803c2c66affSColin Finck if (*pszRelative == ':') {
804c2c66affSColin Finck /* case that is either left alone or uses pszBase */
805c2c66affSColin Finck if (dwFlags & URL_PLUGGABLE_PROTOCOL) {
806c2c66affSColin Finck process_case = 5;
807c2c66affSColin Finck break;
808c2c66affSColin Finck }
809c2c66affSColin Finck process_case = 1;
810c2c66affSColin Finck break;
811c2c66affSColin Finck }
812c2c66affSColin Finck if (isalnumW(*mrelative) && (*(mrelative + 1) == ':')) {
813c2c66affSColin Finck /* case that becomes "file:///" */
814c2c66affSColin Finck strcpyW(preliminary, myfilestr);
815c2c66affSColin Finck process_case = 1;
816c2c66affSColin Finck break;
817c2c66affSColin Finck }
818c2c66affSColin Finck if ((*mrelative == '/') && (*(mrelative+1) == '/')) {
819c2c66affSColin Finck /* pszRelative has location and rest */
820c2c66affSColin Finck process_case = 3;
821c2c66affSColin Finck break;
822c2c66affSColin Finck }
823c2c66affSColin Finck if (*mrelative == '/') {
824c2c66affSColin Finck /* case where pszRelative is root to location */
825c2c66affSColin Finck process_case = 4;
826c2c66affSColin Finck break;
827c2c66affSColin Finck }
828c2c66affSColin Finck if (*mrelative == '#') {
829c2c66affSColin Finck if(!(work = strchrW(base.pszSuffix+base.cchSuffix, '#')))
830c2c66affSColin Finck work = (LPWSTR)base.pszSuffix + strlenW(base.pszSuffix);
831c2c66affSColin Finck
832c2c66affSColin Finck memcpy(preliminary, base.pszProtocol, (work-base.pszProtocol)*sizeof(WCHAR));
833c2c66affSColin Finck preliminary[work-base.pszProtocol] = '\0';
834c2c66affSColin Finck process_case = 1;
835c2c66affSColin Finck break;
836c2c66affSColin Finck }
837c2c66affSColin Finck process_case = (*base.pszSuffix == '/' || base.nScheme == URL_SCHEME_MK) ? 5 : 3;
838c2c66affSColin Finck break;
839c2c66affSColin Finck }else {
840c2c66affSColin Finck work = (LPWSTR)relative.pszProtocol;
841c2c66affSColin Finck for(i=0; i<relative.cchProtocol; i++)
842c2c66affSColin Finck work[i] = tolowerW(work[i]);
843c2c66affSColin Finck }
844c2c66affSColin Finck
845c2c66affSColin Finck /* handle cases where pszRelative has scheme */
846c2c66affSColin Finck if ((base.cchProtocol == relative.cchProtocol) &&
847c2c66affSColin Finck (strncmpW(base.pszProtocol, relative.pszProtocol, base.cchProtocol) == 0)) {
848c2c66affSColin Finck
849c2c66affSColin Finck /* since the schemes are the same */
850c2c66affSColin Finck if ((*relative.pszSuffix == '/') && (*(relative.pszSuffix+1) == '/')) {
851c2c66affSColin Finck /* case where pszRelative replaces location and following */
852c2c66affSColin Finck process_case = 3;
853c2c66affSColin Finck break;
854c2c66affSColin Finck }
855c2c66affSColin Finck if (*relative.pszSuffix == '/') {
856c2c66affSColin Finck /* case where pszRelative is root to location */
857c2c66affSColin Finck process_case = 4;
858c2c66affSColin Finck break;
859c2c66affSColin Finck }
860c2c66affSColin Finck /* replace either just location if base's location starts with a
861c2c66affSColin Finck * slash or otherwise everything */
862c2c66affSColin Finck process_case = (*base.pszSuffix == '/') ? 5 : 1;
863c2c66affSColin Finck break;
864c2c66affSColin Finck }
865c2c66affSColin Finck if ((*relative.pszSuffix == '/') && (*(relative.pszSuffix+1) == '/')) {
866c2c66affSColin Finck /* case where pszRelative replaces scheme, location,
867c2c66affSColin Finck * and following and handles PLUGGABLE
868c2c66affSColin Finck */
869c2c66affSColin Finck process_case = 2;
870c2c66affSColin Finck break;
871c2c66affSColin Finck }
872c2c66affSColin Finck process_case = 1;
873c2c66affSColin Finck break;
874c2c66affSColin Finck } while(FALSE); /* a little trick to allow easy exit from nested if's */
875c2c66affSColin Finck
876c2c66affSColin Finck ret = S_OK;
877c2c66affSColin Finck switch (process_case) {
878c2c66affSColin Finck
879c2c66affSColin Finck case 1: /*
880c2c66affSColin Finck * Return pszRelative appended to what ever is in pszCombined,
881c2c66affSColin Finck * (which may the string "file:///"
882c2c66affSColin Finck */
883c2c66affSColin Finck strcatW(preliminary, mrelative);
884c2c66affSColin Finck break;
885c2c66affSColin Finck
886c2c66affSColin Finck case 2: /* case where pszRelative replaces scheme, and location */
887c2c66affSColin Finck strcpyW(preliminary, mrelative);
888c2c66affSColin Finck break;
889c2c66affSColin Finck
890c2c66affSColin Finck case 3: /*
891c2c66affSColin Finck * Return the pszBase scheme with pszRelative. Basically
892c2c66affSColin Finck * keeps the scheme and replaces the domain and following.
893c2c66affSColin Finck */
894c2c66affSColin Finck memcpy(preliminary, base.pszProtocol, (base.cchProtocol + 1)*sizeof(WCHAR));
895c2c66affSColin Finck work = preliminary + base.cchProtocol + 1;
896c2c66affSColin Finck strcpyW(work, relative.pszSuffix);
897c2c66affSColin Finck break;
898c2c66affSColin Finck
899c2c66affSColin Finck case 4: /*
900c2c66affSColin Finck * Return the pszBase scheme and location but everything
901c2c66affSColin Finck * after the location is pszRelative. (Replace document
902c2c66affSColin Finck * from root on.)
903c2c66affSColin Finck */
904c2c66affSColin Finck memcpy(preliminary, base.pszProtocol, (base.cchProtocol+1+sizeloc)*sizeof(WCHAR));
905c2c66affSColin Finck work = preliminary + base.cchProtocol + 1 + sizeloc;
906c2c66affSColin Finck if (dwFlags & URL_PLUGGABLE_PROTOCOL)
907c2c66affSColin Finck *(work++) = '/';
908c2c66affSColin Finck strcpyW(work, relative.pszSuffix);
909c2c66affSColin Finck break;
910c2c66affSColin Finck
911c2c66affSColin Finck case 5: /*
912c2c66affSColin Finck * Return the pszBase without its document (if any) and
913c2c66affSColin Finck * append pszRelative after its scheme.
914c2c66affSColin Finck */
915c2c66affSColin Finck memcpy(preliminary, base.pszProtocol,
916c2c66affSColin Finck (base.cchProtocol+1+base.cchSuffix)*sizeof(WCHAR));
917c2c66affSColin Finck work = preliminary + base.cchProtocol+1+base.cchSuffix - 1;
918c2c66affSColin Finck if (*work++ != '/')
919c2c66affSColin Finck *(work++) = '/';
920d3fd5bddSAmine Khaldi if (relative.pszSuffix[0] == '.' && relative.pszSuffix[1] == 0)
921d3fd5bddSAmine Khaldi *work = 0;
922d3fd5bddSAmine Khaldi else
923c2c66affSColin Finck strcpyW(work, relative.pszSuffix);
924c2c66affSColin Finck break;
925c2c66affSColin Finck
926c2c66affSColin Finck default:
927c2c66affSColin Finck FIXME("How did we get here????? process_case=%d\n", process_case);
928c2c66affSColin Finck ret = E_INVALIDARG;
929c2c66affSColin Finck }
930c2c66affSColin Finck
931c2c66affSColin Finck if (ret == S_OK) {
932c2c66affSColin Finck /* Reuse mrelative as temp storage as it's already allocated and not needed anymore */
933c2c66affSColin Finck if(*pcchCombined == 0)
934c2c66affSColin Finck *pcchCombined = 1;
935c2c66affSColin Finck ret = UrlCanonicalizeW(preliminary, mrelative, pcchCombined, (dwFlags & ~URL_FILE_USE_PATHURL));
936c2c66affSColin Finck if(SUCCEEDED(ret) && pszCombined) {
937c2c66affSColin Finck lstrcpyW(pszCombined, mrelative);
938c2c66affSColin Finck }
939c2c66affSColin Finck TRACE("return-%d len=%d, %s\n",
940c2c66affSColin Finck process_case, *pcchCombined, debugstr_w(pszCombined));
941c2c66affSColin Finck }
942c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, preliminary);
943c2c66affSColin Finck return ret;
944c2c66affSColin Finck }
945c2c66affSColin Finck
946c2c66affSColin Finck /*************************************************************************
947c2c66affSColin Finck * UrlEscapeA [SHLWAPI.@]
948c2c66affSColin Finck */
949c2c66affSColin Finck
UrlEscapeA(LPCSTR pszUrl,LPSTR pszEscaped,LPDWORD pcchEscaped,DWORD dwFlags)950c2c66affSColin Finck HRESULT WINAPI UrlEscapeA(
951c2c66affSColin Finck LPCSTR pszUrl,
952c2c66affSColin Finck LPSTR pszEscaped,
953c2c66affSColin Finck LPDWORD pcchEscaped,
954c2c66affSColin Finck DWORD dwFlags)
955c2c66affSColin Finck {
956c2c66affSColin Finck WCHAR bufW[INTERNET_MAX_URL_LENGTH];
957c2c66affSColin Finck WCHAR *escapedW = bufW;
958c2c66affSColin Finck UNICODE_STRING urlW;
959c2c66affSColin Finck HRESULT ret;
960c2c66affSColin Finck DWORD lenW = sizeof(bufW)/sizeof(WCHAR), lenA;
961c2c66affSColin Finck
962c2c66affSColin Finck if (!pszEscaped || !pcchEscaped || !*pcchEscaped)
963c2c66affSColin Finck return E_INVALIDARG;
964c2c66affSColin Finck
965c2c66affSColin Finck if(!RtlCreateUnicodeStringFromAsciiz(&urlW, pszUrl))
966c2c66affSColin Finck return E_INVALIDARG;
967c2c66affSColin Finck if(dwFlags & URL_ESCAPE_AS_UTF8) {
968c2c66affSColin Finck RtlFreeUnicodeString(&urlW);
969c2c66affSColin Finck return E_NOTIMPL;
970c2c66affSColin Finck }
971c2c66affSColin Finck if((ret = UrlEscapeW(urlW.Buffer, escapedW, &lenW, dwFlags)) == E_POINTER) {
972c2c66affSColin Finck escapedW = HeapAlloc(GetProcessHeap(), 0, lenW * sizeof(WCHAR));
973c2c66affSColin Finck ret = UrlEscapeW(urlW.Buffer, escapedW, &lenW, dwFlags);
974c2c66affSColin Finck }
975c2c66affSColin Finck if(ret == S_OK) {
976c2c66affSColin Finck RtlUnicodeToMultiByteSize(&lenA, escapedW, lenW * sizeof(WCHAR));
977c2c66affSColin Finck if(*pcchEscaped > lenA) {
978c2c66affSColin Finck RtlUnicodeToMultiByteN(pszEscaped, *pcchEscaped - 1, &lenA, escapedW, lenW * sizeof(WCHAR));
979c2c66affSColin Finck pszEscaped[lenA] = 0;
980c2c66affSColin Finck *pcchEscaped = lenA;
981c2c66affSColin Finck } else {
982c2c66affSColin Finck *pcchEscaped = lenA + 1;
983c2c66affSColin Finck ret = E_POINTER;
984c2c66affSColin Finck }
985c2c66affSColin Finck }
986c2c66affSColin Finck if(escapedW != bufW) HeapFree(GetProcessHeap(), 0, escapedW);
987c2c66affSColin Finck RtlFreeUnicodeString(&urlW);
988c2c66affSColin Finck return ret;
989c2c66affSColin Finck }
990c2c66affSColin Finck
991c2c66affSColin Finck #define WINE_URL_BASH_AS_SLASH 0x01
992c2c66affSColin Finck #define WINE_URL_COLLAPSE_SLASHES 0x02
993c2c66affSColin Finck #define WINE_URL_ESCAPE_SLASH 0x04
994c2c66affSColin Finck #define WINE_URL_ESCAPE_HASH 0x08
995c2c66affSColin Finck #define WINE_URL_ESCAPE_QUESTION 0x10
996c2c66affSColin Finck #define WINE_URL_STOP_ON_HASH 0x20
997c2c66affSColin Finck #define WINE_URL_STOP_ON_QUESTION 0x40
998c2c66affSColin Finck
URL_NeedEscapeW(WCHAR ch,DWORD flags,DWORD int_flags)999c2c66affSColin Finck static inline BOOL URL_NeedEscapeW(WCHAR ch, DWORD flags, DWORD int_flags)
1000c2c66affSColin Finck {
1001c2c66affSColin Finck if (flags & URL_ESCAPE_SPACES_ONLY)
1002c2c66affSColin Finck return ch == ' ';
1003c2c66affSColin Finck
1004c2c66affSColin Finck if ((flags & URL_ESCAPE_PERCENT) && (ch == '%'))
1005c2c66affSColin Finck return TRUE;
1006c2c66affSColin Finck
1007c2c66affSColin Finck if ((flags & URL_ESCAPE_AS_UTF8) && (ch >= 0x80))
1008c2c66affSColin Finck return TRUE;
1009c2c66affSColin Finck
1010c2c66affSColin Finck if (ch <= 31 || (ch >= 127 && ch <= 255) )
1011c2c66affSColin Finck return TRUE;
1012c2c66affSColin Finck
1013c2c66affSColin Finck if (isalnumW(ch))
1014c2c66affSColin Finck return FALSE;
1015c2c66affSColin Finck
1016c2c66affSColin Finck switch (ch) {
1017c2c66affSColin Finck case ' ':
1018c2c66affSColin Finck case '<':
1019c2c66affSColin Finck case '>':
1020c2c66affSColin Finck case '\"':
1021c2c66affSColin Finck case '{':
1022c2c66affSColin Finck case '}':
1023c2c66affSColin Finck case '|':
1024c2c66affSColin Finck case '\\':
1025c2c66affSColin Finck case '^':
1026c2c66affSColin Finck case ']':
1027c2c66affSColin Finck case '[':
1028c2c66affSColin Finck case '`':
1029c2c66affSColin Finck case '&':
1030c2c66affSColin Finck return TRUE;
1031c2c66affSColin Finck case '/':
1032c2c66affSColin Finck return !!(int_flags & WINE_URL_ESCAPE_SLASH);
1033c2c66affSColin Finck case '?':
1034c2c66affSColin Finck return !!(int_flags & WINE_URL_ESCAPE_QUESTION);
1035c2c66affSColin Finck case '#':
1036c2c66affSColin Finck return !!(int_flags & WINE_URL_ESCAPE_HASH);
1037c2c66affSColin Finck default:
1038c2c66affSColin Finck return FALSE;
1039c2c66affSColin Finck }
1040c2c66affSColin Finck }
1041c2c66affSColin Finck
1042c2c66affSColin Finck
1043c2c66affSColin Finck /*************************************************************************
1044c2c66affSColin Finck * UrlEscapeW [SHLWAPI.@]
1045c2c66affSColin Finck *
1046c2c66affSColin Finck * Converts unsafe characters in a Url into escape sequences.
1047c2c66affSColin Finck *
1048c2c66affSColin Finck * PARAMS
1049c2c66affSColin Finck * pszUrl [I] Url to modify
1050c2c66affSColin Finck * pszEscaped [O] Destination for modified Url
1051c2c66affSColin Finck * pcchEscaped [I/O] Length of pszUrl, destination for length of pszEscaped
1052c2c66affSColin Finck * dwFlags [I] URL_ flags from "shlwapi.h"
1053c2c66affSColin Finck *
1054c2c66affSColin Finck * RETURNS
1055c2c66affSColin Finck * Success: S_OK. pszEscaped contains the escaped Url, pcchEscaped
1056c2c66affSColin Finck * contains its length.
1057c2c66affSColin Finck * Failure: E_POINTER, if pszEscaped is not large enough. In this case
1058c2c66affSColin Finck * pcchEscaped is set to the required length.
1059c2c66affSColin Finck *
1060c2c66affSColin Finck * Converts unsafe characters into their escape sequences.
1061c2c66affSColin Finck *
1062c2c66affSColin Finck * NOTES
1063c2c66affSColin Finck * - By default this function stops converting at the first '?' or
1064c2c66affSColin Finck * '#' character.
1065c2c66affSColin Finck * - If dwFlags contains URL_ESCAPE_SPACES_ONLY then only spaces are
1066c2c66affSColin Finck * converted, but the conversion continues past a '?' or '#'.
1067c2c66affSColin Finck * - Note that this function did not work well (or at all) in shlwapi version 4.
1068c2c66affSColin Finck *
1069c2c66affSColin Finck * BUGS
1070c2c66affSColin Finck * Only the following flags are implemented:
1071c2c66affSColin Finck *| URL_ESCAPE_SPACES_ONLY
1072c2c66affSColin Finck *| URL_DONT_ESCAPE_EXTRA_INFO
1073c2c66affSColin Finck *| URL_ESCAPE_SEGMENT_ONLY
1074c2c66affSColin Finck *| URL_ESCAPE_PERCENT
1075c2c66affSColin Finck */
UrlEscapeW(LPCWSTR pszUrl,LPWSTR pszEscaped,LPDWORD pcchEscaped,DWORD dwFlags)1076c2c66affSColin Finck HRESULT WINAPI UrlEscapeW(
1077c2c66affSColin Finck LPCWSTR pszUrl,
1078c2c66affSColin Finck LPWSTR pszEscaped,
1079c2c66affSColin Finck LPDWORD pcchEscaped,
1080c2c66affSColin Finck DWORD dwFlags)
1081c2c66affSColin Finck {
1082c2c66affSColin Finck LPCWSTR src;
1083c2c66affSColin Finck DWORD needed = 0, ret;
1084c2c66affSColin Finck BOOL stop_escaping = FALSE;
1085c2c66affSColin Finck WCHAR next[12], *dst, *dst_ptr;
1086c2c66affSColin Finck INT i, len;
1087c2c66affSColin Finck PARSEDURLW parsed_url;
1088c2c66affSColin Finck DWORD int_flags;
1089c2c66affSColin Finck DWORD slashes = 0;
1090c2c66affSColin Finck static const WCHAR localhost[] = {'l','o','c','a','l','h','o','s','t',0};
1091c2c66affSColin Finck
1092c2c66affSColin Finck TRACE("(%p(%s) %p %p 0x%08x)\n", pszUrl, debugstr_w(pszUrl),
1093c2c66affSColin Finck pszEscaped, pcchEscaped, dwFlags);
1094c2c66affSColin Finck
1095c2c66affSColin Finck if(!pszUrl || !pcchEscaped || !pszEscaped || *pcchEscaped == 0)
1096c2c66affSColin Finck return E_INVALIDARG;
1097c2c66affSColin Finck
1098c2c66affSColin Finck if(dwFlags & ~(URL_ESCAPE_SPACES_ONLY |
1099c2c66affSColin Finck URL_ESCAPE_SEGMENT_ONLY |
1100c2c66affSColin Finck URL_DONT_ESCAPE_EXTRA_INFO |
1101c2c66affSColin Finck URL_ESCAPE_PERCENT |
1102c2c66affSColin Finck URL_ESCAPE_AS_UTF8))
1103c2c66affSColin Finck FIXME("Unimplemented flags: %08x\n", dwFlags);
1104c2c66affSColin Finck
1105c2c66affSColin Finck dst_ptr = dst = HeapAlloc(GetProcessHeap(), 0, *pcchEscaped*sizeof(WCHAR));
1106c2c66affSColin Finck if(!dst_ptr)
1107c2c66affSColin Finck return E_OUTOFMEMORY;
1108c2c66affSColin Finck
1109c2c66affSColin Finck /* fix up flags */
1110c2c66affSColin Finck if (dwFlags & URL_ESCAPE_SPACES_ONLY)
1111c2c66affSColin Finck /* if SPACES_ONLY specified, reset the other controls */
1112c2c66affSColin Finck dwFlags &= ~(URL_DONT_ESCAPE_EXTRA_INFO |
1113c2c66affSColin Finck URL_ESCAPE_PERCENT |
1114c2c66affSColin Finck URL_ESCAPE_SEGMENT_ONLY);
1115c2c66affSColin Finck
1116c2c66affSColin Finck else
1117c2c66affSColin Finck /* if SPACES_ONLY *not* specified the assume DONT_ESCAPE_EXTRA_INFO */
1118c2c66affSColin Finck dwFlags |= URL_DONT_ESCAPE_EXTRA_INFO;
1119c2c66affSColin Finck
1120c2c66affSColin Finck
1121c2c66affSColin Finck int_flags = 0;
1122c2c66affSColin Finck if(dwFlags & URL_ESCAPE_SEGMENT_ONLY) {
1123c2c66affSColin Finck int_flags = WINE_URL_ESCAPE_QUESTION | WINE_URL_ESCAPE_HASH | WINE_URL_ESCAPE_SLASH;
1124c2c66affSColin Finck } else {
1125c2c66affSColin Finck parsed_url.cbSize = sizeof(parsed_url);
1126c2c66affSColin Finck if(ParseURLW(pszUrl, &parsed_url) != S_OK)
1127c2c66affSColin Finck parsed_url.nScheme = URL_SCHEME_INVALID;
1128c2c66affSColin Finck
1129c2c66affSColin Finck TRACE("scheme = %d (%s)\n", parsed_url.nScheme, debugstr_wn(parsed_url.pszProtocol, parsed_url.cchProtocol));
1130c2c66affSColin Finck
1131c2c66affSColin Finck if(dwFlags & URL_DONT_ESCAPE_EXTRA_INFO)
1132c2c66affSColin Finck int_flags = WINE_URL_STOP_ON_HASH | WINE_URL_STOP_ON_QUESTION;
1133c2c66affSColin Finck
1134c2c66affSColin Finck switch(parsed_url.nScheme) {
1135c2c66affSColin Finck case URL_SCHEME_FILE:
1136c2c66affSColin Finck int_flags |= WINE_URL_BASH_AS_SLASH | WINE_URL_COLLAPSE_SLASHES | WINE_URL_ESCAPE_HASH;
1137c2c66affSColin Finck int_flags &= ~WINE_URL_STOP_ON_HASH;
1138c2c66affSColin Finck break;
1139c2c66affSColin Finck
1140c2c66affSColin Finck case URL_SCHEME_HTTP:
1141c2c66affSColin Finck case URL_SCHEME_HTTPS:
1142c2c66affSColin Finck int_flags |= WINE_URL_BASH_AS_SLASH;
1143c2c66affSColin Finck if(parsed_url.pszSuffix[0] != '/' && parsed_url.pszSuffix[0] != '\\')
1144c2c66affSColin Finck int_flags |= WINE_URL_ESCAPE_SLASH;
1145c2c66affSColin Finck break;
1146c2c66affSColin Finck
1147c2c66affSColin Finck case URL_SCHEME_MAILTO:
1148c2c66affSColin Finck int_flags |= WINE_URL_ESCAPE_SLASH | WINE_URL_ESCAPE_QUESTION | WINE_URL_ESCAPE_HASH;
1149c2c66affSColin Finck int_flags &= ~(WINE_URL_STOP_ON_QUESTION | WINE_URL_STOP_ON_HASH);
1150c2c66affSColin Finck break;
1151c2c66affSColin Finck
1152c2c66affSColin Finck case URL_SCHEME_INVALID:
1153c2c66affSColin Finck break;
1154c2c66affSColin Finck
1155c2c66affSColin Finck case URL_SCHEME_FTP:
1156c2c66affSColin Finck default:
1157c2c66affSColin Finck if(parsed_url.pszSuffix[0] != '/')
1158c2c66affSColin Finck int_flags |= WINE_URL_ESCAPE_SLASH;
1159c2c66affSColin Finck break;
1160c2c66affSColin Finck }
1161c2c66affSColin Finck }
1162c2c66affSColin Finck
1163c2c66affSColin Finck for(src = pszUrl; *src; ) {
1164c2c66affSColin Finck WCHAR cur = *src;
1165c2c66affSColin Finck len = 0;
1166c2c66affSColin Finck
1167c2c66affSColin Finck if((int_flags & WINE_URL_COLLAPSE_SLASHES) && src == pszUrl + parsed_url.cchProtocol + 1) {
1168c2c66affSColin Finck int localhost_len = sizeof(localhost)/sizeof(WCHAR) - 1;
1169c2c66affSColin Finck while(cur == '/' || cur == '\\') {
1170c2c66affSColin Finck slashes++;
1171c2c66affSColin Finck cur = *++src;
1172c2c66affSColin Finck }
1173c2c66affSColin Finck if(slashes == 2 && !strncmpiW(src, localhost, localhost_len)) { /* file://localhost/ -> file:/// */
1174c2c66affSColin Finck if(*(src + localhost_len) == '/' || *(src + localhost_len) == '\\')
1175c2c66affSColin Finck src += localhost_len + 1;
1176c2c66affSColin Finck slashes = 3;
1177c2c66affSColin Finck }
1178c2c66affSColin Finck
1179c2c66affSColin Finck switch(slashes) {
1180c2c66affSColin Finck case 1:
1181c2c66affSColin Finck case 3:
1182c2c66affSColin Finck next[0] = next[1] = next[2] = '/';
1183c2c66affSColin Finck len = 3;
1184c2c66affSColin Finck break;
1185c2c66affSColin Finck case 0:
1186c2c66affSColin Finck len = 0;
1187c2c66affSColin Finck break;
1188c2c66affSColin Finck default:
1189c2c66affSColin Finck next[0] = next[1] = '/';
1190c2c66affSColin Finck len = 2;
1191c2c66affSColin Finck break;
1192c2c66affSColin Finck }
1193c2c66affSColin Finck }
1194c2c66affSColin Finck if(len == 0) {
1195c2c66affSColin Finck
1196c2c66affSColin Finck if(cur == '#' && (int_flags & WINE_URL_STOP_ON_HASH))
1197c2c66affSColin Finck stop_escaping = TRUE;
1198c2c66affSColin Finck
1199c2c66affSColin Finck if(cur == '?' && (int_flags & WINE_URL_STOP_ON_QUESTION))
1200c2c66affSColin Finck stop_escaping = TRUE;
1201c2c66affSColin Finck
1202c2c66affSColin Finck if(cur == '\\' && (int_flags & WINE_URL_BASH_AS_SLASH) && !stop_escaping) cur = '/';
1203c2c66affSColin Finck
1204c2c66affSColin Finck if(URL_NeedEscapeW(cur, dwFlags, int_flags) && stop_escaping == FALSE) {
1205c2c66affSColin Finck if(dwFlags & URL_ESCAPE_AS_UTF8) {
1206c2c66affSColin Finck char utf[16];
1207c2c66affSColin Finck
1208c2c66affSColin Finck if ((cur >= 0xd800 && cur <= 0xdfff) &&
1209c2c66affSColin Finck (src[1] >= 0xdc00 && src[1] <= 0xdfff))
1210c2c66affSColin Finck {
1211c2c66affSColin Finck #ifdef __REACTOS__
1212c2c66affSColin Finck len = WideCharToMultiByte( CP_UTF8, 0, src, 2,
1213c2c66affSColin Finck utf, sizeof(utf), NULL, NULL );
1214c2c66affSColin Finck #else
1215c2c66affSColin Finck len = WideCharToMultiByte( CP_UTF8, WC_ERR_INVALID_CHARS, src, 2,
1216c2c66affSColin Finck utf, sizeof(utf), NULL, NULL );
1217c2c66affSColin Finck #endif
1218c2c66affSColin Finck src++;
1219c2c66affSColin Finck }
1220c2c66affSColin Finck else
1221c2c66affSColin Finck #ifdef __REACTOS__
1222c2c66affSColin Finck len = WideCharToMultiByte( CP_UTF8, 0, &cur, 1,
1223c2c66affSColin Finck utf, sizeof(utf), NULL, NULL );
1224c2c66affSColin Finck #else
1225c2c66affSColin Finck len = WideCharToMultiByte( CP_UTF8, WC_ERR_INVALID_CHARS, &cur, 1,
1226c2c66affSColin Finck utf, sizeof(utf), NULL, NULL );
1227c2c66affSColin Finck #endif
1228c2c66affSColin Finck
1229c2c66affSColin Finck if (!len) {
1230c2c66affSColin Finck utf[0] = 0xef;
1231c2c66affSColin Finck utf[1] = 0xbf;
1232c2c66affSColin Finck utf[2] = 0xbd;
1233c2c66affSColin Finck len = 3;
1234c2c66affSColin Finck }
1235c2c66affSColin Finck
1236c2c66affSColin Finck for(i = 0; i < len; i++) {
1237c2c66affSColin Finck next[i*3+0] = '%';
1238c2c66affSColin Finck next[i*3+1] = hexDigits[(utf[i] >> 4) & 0xf];
1239c2c66affSColin Finck next[i*3+2] = hexDigits[utf[i] & 0xf];
1240c2c66affSColin Finck }
1241c2c66affSColin Finck len *= 3;
1242c2c66affSColin Finck } else {
1243c2c66affSColin Finck next[0] = '%';
1244c2c66affSColin Finck next[1] = hexDigits[(cur >> 4) & 0xf];
1245c2c66affSColin Finck next[2] = hexDigits[cur & 0xf];
1246c2c66affSColin Finck len = 3;
1247c2c66affSColin Finck }
1248c2c66affSColin Finck } else {
1249c2c66affSColin Finck next[0] = cur;
1250c2c66affSColin Finck len = 1;
1251c2c66affSColin Finck }
1252c2c66affSColin Finck src++;
1253c2c66affSColin Finck }
1254c2c66affSColin Finck
1255c2c66affSColin Finck if(needed + len <= *pcchEscaped) {
1256c2c66affSColin Finck memcpy(dst, next, len*sizeof(WCHAR));
1257c2c66affSColin Finck dst += len;
1258c2c66affSColin Finck }
1259c2c66affSColin Finck needed += len;
1260c2c66affSColin Finck }
1261c2c66affSColin Finck
1262c2c66affSColin Finck if(needed < *pcchEscaped) {
1263c2c66affSColin Finck *dst = '\0';
1264c2c66affSColin Finck memcpy(pszEscaped, dst_ptr, (needed+1)*sizeof(WCHAR));
1265c2c66affSColin Finck
1266c2c66affSColin Finck ret = S_OK;
1267c2c66affSColin Finck } else {
1268c2c66affSColin Finck needed++; /* add one for the '\0' */
1269c2c66affSColin Finck ret = E_POINTER;
1270c2c66affSColin Finck }
1271c2c66affSColin Finck *pcchEscaped = needed;
1272c2c66affSColin Finck
1273c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, dst_ptr);
1274c2c66affSColin Finck return ret;
1275c2c66affSColin Finck }
1276c2c66affSColin Finck
1277c2c66affSColin Finck
1278c2c66affSColin Finck /*************************************************************************
1279c2c66affSColin Finck * UrlUnescapeA [SHLWAPI.@]
1280c2c66affSColin Finck *
1281c2c66affSColin Finck * Converts Url escape sequences back to ordinary characters.
1282c2c66affSColin Finck *
1283c2c66affSColin Finck * PARAMS
1284c2c66affSColin Finck * pszUrl [I/O] Url to convert
1285c2c66affSColin Finck * pszUnescaped [O] Destination for converted Url
1286c2c66affSColin Finck * pcchUnescaped [I/O] Size of output string
1287c2c66affSColin Finck * dwFlags [I] URL_ESCAPE_ Flags from "shlwapi.h"
1288c2c66affSColin Finck *
1289c2c66affSColin Finck * RETURNS
1290c2c66affSColin Finck * Success: S_OK. The converted value is in pszUnescaped, or in pszUrl if
1291c2c66affSColin Finck * dwFlags includes URL_ESCAPE_INPLACE.
1292c2c66affSColin Finck * Failure: E_POINTER if the converted Url is bigger than pcchUnescaped. In
1293c2c66affSColin Finck * this case pcchUnescaped is set to the size required.
1294c2c66affSColin Finck * NOTES
1295c2c66affSColin Finck * If dwFlags includes URL_DONT_ESCAPE_EXTRA_INFO, the conversion stops at
1296c2c66affSColin Finck * the first occurrence of either a '?' or '#' character.
1297c2c66affSColin Finck */
UrlUnescapeA(LPSTR pszUrl,LPSTR pszUnescaped,LPDWORD pcchUnescaped,DWORD dwFlags)1298c2c66affSColin Finck HRESULT WINAPI UrlUnescapeA(
1299c2c66affSColin Finck LPSTR pszUrl,
1300c2c66affSColin Finck LPSTR pszUnescaped,
1301c2c66affSColin Finck LPDWORD pcchUnescaped,
1302c2c66affSColin Finck DWORD dwFlags)
1303c2c66affSColin Finck {
1304c2c66affSColin Finck char *dst, next;
1305c2c66affSColin Finck LPCSTR src;
1306c2c66affSColin Finck HRESULT ret;
1307c2c66affSColin Finck DWORD needed;
1308c2c66affSColin Finck BOOL stop_unescaping = FALSE;
1309c2c66affSColin Finck
1310c2c66affSColin Finck TRACE("(%s, %p, %p, 0x%08x)\n", debugstr_a(pszUrl), pszUnescaped,
1311c2c66affSColin Finck pcchUnescaped, dwFlags);
1312c2c66affSColin Finck
1313c2c66affSColin Finck if (!pszUrl) return E_INVALIDARG;
1314c2c66affSColin Finck
1315c2c66affSColin Finck if(dwFlags & URL_UNESCAPE_INPLACE)
1316c2c66affSColin Finck dst = pszUrl;
1317c2c66affSColin Finck else
1318c2c66affSColin Finck {
1319c2c66affSColin Finck if (!pszUnescaped || !pcchUnescaped) return E_INVALIDARG;
1320c2c66affSColin Finck dst = pszUnescaped;
1321c2c66affSColin Finck }
1322c2c66affSColin Finck
1323c2c66affSColin Finck for(src = pszUrl, needed = 0; *src; src++, needed++) {
1324c2c66affSColin Finck if(dwFlags & URL_DONT_UNESCAPE_EXTRA_INFO &&
1325c2c66affSColin Finck (*src == '#' || *src == '?')) {
1326c2c66affSColin Finck stop_unescaping = TRUE;
1327c2c66affSColin Finck next = *src;
1328c2c66affSColin Finck } else if(*src == '%' && isxdigit(*(src + 1)) && isxdigit(*(src + 2))
1329c2c66affSColin Finck && stop_unescaping == FALSE) {
1330c2c66affSColin Finck INT ih;
1331c2c66affSColin Finck char buf[3];
1332c2c66affSColin Finck memcpy(buf, src + 1, 2);
1333c2c66affSColin Finck buf[2] = '\0';
1334c2c66affSColin Finck ih = strtol(buf, NULL, 16);
1335c2c66affSColin Finck next = (CHAR) ih;
1336c2c66affSColin Finck src += 2; /* Advance to end of escape */
1337c2c66affSColin Finck } else
1338c2c66affSColin Finck next = *src;
1339c2c66affSColin Finck
1340c2c66affSColin Finck if(dwFlags & URL_UNESCAPE_INPLACE || needed < *pcchUnescaped)
1341c2c66affSColin Finck *dst++ = next;
1342c2c66affSColin Finck }
1343c2c66affSColin Finck
1344c2c66affSColin Finck if(dwFlags & URL_UNESCAPE_INPLACE || needed < *pcchUnescaped) {
1345c2c66affSColin Finck *dst = '\0';
1346c2c66affSColin Finck ret = S_OK;
1347c2c66affSColin Finck } else {
1348c2c66affSColin Finck needed++; /* add one for the '\0' */
1349c2c66affSColin Finck ret = E_POINTER;
1350c2c66affSColin Finck }
1351c2c66affSColin Finck if(!(dwFlags & URL_UNESCAPE_INPLACE))
1352c2c66affSColin Finck *pcchUnescaped = needed;
1353c2c66affSColin Finck
1354c2c66affSColin Finck if (ret == S_OK) {
1355c2c66affSColin Finck TRACE("result %s\n", (dwFlags & URL_UNESCAPE_INPLACE) ?
1356c2c66affSColin Finck debugstr_a(pszUrl) : debugstr_a(pszUnescaped));
1357c2c66affSColin Finck }
1358c2c66affSColin Finck
1359c2c66affSColin Finck return ret;
1360c2c66affSColin Finck }
1361c2c66affSColin Finck
1362c2c66affSColin Finck /*************************************************************************
1363c2c66affSColin Finck * UrlUnescapeW [SHLWAPI.@]
1364c2c66affSColin Finck *
1365c2c66affSColin Finck * See UrlUnescapeA.
1366c2c66affSColin Finck */
UrlUnescapeW(LPWSTR pszUrl,LPWSTR pszUnescaped,LPDWORD pcchUnescaped,DWORD dwFlags)1367c2c66affSColin Finck HRESULT WINAPI UrlUnescapeW(
1368c2c66affSColin Finck LPWSTR pszUrl,
1369c2c66affSColin Finck LPWSTR pszUnescaped,
1370c2c66affSColin Finck LPDWORD pcchUnescaped,
1371c2c66affSColin Finck DWORD dwFlags)
1372c2c66affSColin Finck {
1373c2c66affSColin Finck WCHAR *dst, next;
1374c2c66affSColin Finck LPCWSTR src;
1375c2c66affSColin Finck HRESULT ret;
1376c2c66affSColin Finck DWORD needed;
1377c2c66affSColin Finck BOOL stop_unescaping = FALSE;
1378c2c66affSColin Finck
1379c2c66affSColin Finck TRACE("(%s, %p, %p, 0x%08x)\n", debugstr_w(pszUrl), pszUnescaped,
1380c2c66affSColin Finck pcchUnescaped, dwFlags);
1381c2c66affSColin Finck
1382c2c66affSColin Finck if(!pszUrl) return E_INVALIDARG;
1383c2c66affSColin Finck
1384c2c66affSColin Finck if(dwFlags & URL_UNESCAPE_INPLACE)
1385c2c66affSColin Finck dst = pszUrl;
1386c2c66affSColin Finck else
1387c2c66affSColin Finck {
1388c2c66affSColin Finck if (!pszUnescaped || !pcchUnescaped) return E_INVALIDARG;
1389c2c66affSColin Finck dst = pszUnescaped;
1390c2c66affSColin Finck }
1391c2c66affSColin Finck
1392c2c66affSColin Finck for(src = pszUrl, needed = 0; *src; src++, needed++) {
1393c2c66affSColin Finck if(dwFlags & URL_DONT_UNESCAPE_EXTRA_INFO &&
1394c2c66affSColin Finck (*src == '#' || *src == '?')) {
1395c2c66affSColin Finck stop_unescaping = TRUE;
1396c2c66affSColin Finck next = *src;
1397c2c66affSColin Finck } else if(*src == '%' && isxdigitW(*(src + 1)) && isxdigitW(*(src + 2))
1398c2c66affSColin Finck && stop_unescaping == FALSE) {
1399c2c66affSColin Finck INT ih;
1400c2c66affSColin Finck WCHAR buf[5] = {'0','x',0};
1401c2c66affSColin Finck memcpy(buf + 2, src + 1, 2*sizeof(WCHAR));
1402c2c66affSColin Finck buf[4] = 0;
1403c2c66affSColin Finck StrToIntExW(buf, STIF_SUPPORT_HEX, &ih);
1404c2c66affSColin Finck next = (WCHAR) ih;
1405c2c66affSColin Finck src += 2; /* Advance to end of escape */
1406c2c66affSColin Finck } else
1407c2c66affSColin Finck next = *src;
1408c2c66affSColin Finck
1409c2c66affSColin Finck if(dwFlags & URL_UNESCAPE_INPLACE || needed < *pcchUnescaped)
1410c2c66affSColin Finck *dst++ = next;
1411c2c66affSColin Finck }
1412c2c66affSColin Finck
1413c2c66affSColin Finck if(dwFlags & URL_UNESCAPE_INPLACE || needed < *pcchUnescaped) {
1414c2c66affSColin Finck *dst = '\0';
1415c2c66affSColin Finck ret = S_OK;
1416c2c66affSColin Finck } else {
1417c2c66affSColin Finck needed++; /* add one for the '\0' */
1418c2c66affSColin Finck ret = E_POINTER;
1419c2c66affSColin Finck }
1420c2c66affSColin Finck if(!(dwFlags & URL_UNESCAPE_INPLACE))
1421c2c66affSColin Finck *pcchUnescaped = needed;
1422c2c66affSColin Finck
1423c2c66affSColin Finck if (ret == S_OK) {
1424c2c66affSColin Finck TRACE("result %s\n", (dwFlags & URL_UNESCAPE_INPLACE) ?
1425c2c66affSColin Finck debugstr_w(pszUrl) : debugstr_w(pszUnescaped));
1426c2c66affSColin Finck }
1427c2c66affSColin Finck
1428c2c66affSColin Finck return ret;
1429c2c66affSColin Finck }
1430c2c66affSColin Finck
1431c2c66affSColin Finck /*************************************************************************
1432c2c66affSColin Finck * UrlGetLocationA [SHLWAPI.@]
1433c2c66affSColin Finck *
1434c2c66affSColin Finck * Get the location from a Url.
1435c2c66affSColin Finck *
1436c2c66affSColin Finck * PARAMS
1437c2c66affSColin Finck * pszUrl [I] Url to get the location from
1438c2c66affSColin Finck *
1439c2c66affSColin Finck * RETURNS
1440c2c66affSColin Finck * A pointer to the start of the location in pszUrl, or NULL if there is
1441c2c66affSColin Finck * no location.
1442c2c66affSColin Finck *
1443c2c66affSColin Finck * NOTES
1444c2c66affSColin Finck * - MSDN erroneously states that "The location is the segment of the Url
1445c2c66affSColin Finck * starting with a '?' or '#' character". Neither V4 nor V5 of shlwapi.dll
1446c2c66affSColin Finck * stop at '?' and always return a NULL in this case.
1447c2c66affSColin Finck * - MSDN also erroneously states that "If a file URL has a query string,
1448c2c66affSColin Finck * the returned string is the query string". In all tested cases, if the
1449c2c66affSColin Finck * Url starts with "fi" then a NULL is returned. V5 gives the following results:
1450c2c66affSColin Finck *| Result Url
1451c2c66affSColin Finck *| ------ ---
1452c2c66affSColin Finck *| NULL file://aa/b/cd#hohoh
1453c2c66affSColin Finck *| #hohoh http://aa/b/cd#hohoh
1454c2c66affSColin Finck *| NULL fi://aa/b/cd#hohoh
1455c2c66affSColin Finck *| #hohoh ff://aa/b/cd#hohoh
1456c2c66affSColin Finck */
UrlGetLocationA(LPCSTR pszUrl)1457c2c66affSColin Finck LPCSTR WINAPI UrlGetLocationA(
1458c2c66affSColin Finck LPCSTR pszUrl)
1459c2c66affSColin Finck {
1460c2c66affSColin Finck PARSEDURLA base;
1461c2c66affSColin Finck DWORD res1;
1462c2c66affSColin Finck
1463c2c66affSColin Finck base.cbSize = sizeof(base);
1464c2c66affSColin Finck res1 = ParseURLA(pszUrl, &base);
1465c2c66affSColin Finck if (res1) return NULL; /* invalid scheme */
1466c2c66affSColin Finck
1467c2c66affSColin Finck /* if scheme is file: then never return pointer */
1468c2c66affSColin Finck if (strncmp(base.pszProtocol, "file", min(4,base.cchProtocol)) == 0) return NULL;
1469c2c66affSColin Finck
1470c2c66affSColin Finck /* Look for '#' and return its addr */
1471c2c66affSColin Finck return strchr(base.pszSuffix, '#');
1472c2c66affSColin Finck }
1473c2c66affSColin Finck
1474c2c66affSColin Finck /*************************************************************************
1475c2c66affSColin Finck * UrlGetLocationW [SHLWAPI.@]
1476c2c66affSColin Finck *
1477c2c66affSColin Finck * See UrlGetLocationA.
1478c2c66affSColin Finck */
UrlGetLocationW(LPCWSTR pszUrl)1479c2c66affSColin Finck LPCWSTR WINAPI UrlGetLocationW(
1480c2c66affSColin Finck LPCWSTR pszUrl)
1481c2c66affSColin Finck {
1482c2c66affSColin Finck PARSEDURLW base;
1483c2c66affSColin Finck DWORD res1;
1484c2c66affSColin Finck
1485c2c66affSColin Finck base.cbSize = sizeof(base);
1486c2c66affSColin Finck res1 = ParseURLW(pszUrl, &base);
1487c2c66affSColin Finck if (res1) return NULL; /* invalid scheme */
1488c2c66affSColin Finck
1489c2c66affSColin Finck /* if scheme is file: then never return pointer */
1490c2c66affSColin Finck if (strncmpW(base.pszProtocol, fileW, min(4,base.cchProtocol)) == 0) return NULL;
1491c2c66affSColin Finck
1492c2c66affSColin Finck /* Look for '#' and return its addr */
1493c2c66affSColin Finck return strchrW(base.pszSuffix, '#');
1494c2c66affSColin Finck }
1495c2c66affSColin Finck
1496c2c66affSColin Finck /*************************************************************************
1497c2c66affSColin Finck * UrlCompareA [SHLWAPI.@]
1498c2c66affSColin Finck *
1499c2c66affSColin Finck * Compare two Urls.
1500c2c66affSColin Finck *
1501c2c66affSColin Finck * PARAMS
1502c2c66affSColin Finck * pszUrl1 [I] First Url to compare
1503c2c66affSColin Finck * pszUrl2 [I] Url to compare to pszUrl1
1504c2c66affSColin Finck * fIgnoreSlash [I] TRUE = compare only up to a final slash
1505c2c66affSColin Finck *
1506c2c66affSColin Finck * RETURNS
1507c2c66affSColin Finck * less than zero, zero, or greater than zero indicating pszUrl2 is greater
1508c2c66affSColin Finck * than, equal to, or less than pszUrl1 respectively.
1509c2c66affSColin Finck */
UrlCompareA(LPCSTR pszUrl1,LPCSTR pszUrl2,BOOL fIgnoreSlash)1510c2c66affSColin Finck INT WINAPI UrlCompareA(
1511c2c66affSColin Finck LPCSTR pszUrl1,
1512c2c66affSColin Finck LPCSTR pszUrl2,
1513c2c66affSColin Finck BOOL fIgnoreSlash)
1514c2c66affSColin Finck {
1515c2c66affSColin Finck INT ret, len, len1, len2;
1516c2c66affSColin Finck
1517c2c66affSColin Finck if (!fIgnoreSlash)
1518c2c66affSColin Finck return strcmp(pszUrl1, pszUrl2);
1519c2c66affSColin Finck len1 = strlen(pszUrl1);
1520c2c66affSColin Finck if (pszUrl1[len1-1] == '/') len1--;
1521c2c66affSColin Finck len2 = strlen(pszUrl2);
1522c2c66affSColin Finck if (pszUrl2[len2-1] == '/') len2--;
1523c2c66affSColin Finck if (len1 == len2)
1524c2c66affSColin Finck return strncmp(pszUrl1, pszUrl2, len1);
1525c2c66affSColin Finck len = min(len1, len2);
1526c2c66affSColin Finck ret = strncmp(pszUrl1, pszUrl2, len);
1527c2c66affSColin Finck if (ret) return ret;
1528c2c66affSColin Finck if (len1 > len2) return 1;
1529c2c66affSColin Finck return -1;
1530c2c66affSColin Finck }
1531c2c66affSColin Finck
1532c2c66affSColin Finck /*************************************************************************
1533c2c66affSColin Finck * UrlCompareW [SHLWAPI.@]
1534c2c66affSColin Finck *
1535c2c66affSColin Finck * See UrlCompareA.
1536c2c66affSColin Finck */
UrlCompareW(LPCWSTR pszUrl1,LPCWSTR pszUrl2,BOOL fIgnoreSlash)1537c2c66affSColin Finck INT WINAPI UrlCompareW(
1538c2c66affSColin Finck LPCWSTR pszUrl1,
1539c2c66affSColin Finck LPCWSTR pszUrl2,
1540c2c66affSColin Finck BOOL fIgnoreSlash)
1541c2c66affSColin Finck {
1542c2c66affSColin Finck INT ret;
1543c2c66affSColin Finck size_t len, len1, len2;
1544c2c66affSColin Finck
1545c2c66affSColin Finck if (!fIgnoreSlash)
1546c2c66affSColin Finck return strcmpW(pszUrl1, pszUrl2);
1547c2c66affSColin Finck len1 = strlenW(pszUrl1);
1548c2c66affSColin Finck if (pszUrl1[len1-1] == '/') len1--;
1549c2c66affSColin Finck len2 = strlenW(pszUrl2);
1550c2c66affSColin Finck if (pszUrl2[len2-1] == '/') len2--;
1551c2c66affSColin Finck if (len1 == len2)
1552c2c66affSColin Finck return strncmpW(pszUrl1, pszUrl2, len1);
1553c2c66affSColin Finck len = min(len1, len2);
1554c2c66affSColin Finck ret = strncmpW(pszUrl1, pszUrl2, len);
1555c2c66affSColin Finck if (ret) return ret;
1556c2c66affSColin Finck if (len1 > len2) return 1;
1557c2c66affSColin Finck return -1;
1558c2c66affSColin Finck }
1559c2c66affSColin Finck
1560c2c66affSColin Finck /*************************************************************************
1561c2c66affSColin Finck * HashData [SHLWAPI.@]
1562c2c66affSColin Finck *
1563c2c66affSColin Finck * Hash an input block into a variable sized digest.
1564c2c66affSColin Finck *
1565c2c66affSColin Finck * PARAMS
1566c2c66affSColin Finck * lpSrc [I] Input block
1567c2c66affSColin Finck * nSrcLen [I] Length of lpSrc
1568c2c66affSColin Finck * lpDest [I] Output for hash digest
1569c2c66affSColin Finck * nDestLen [I] Length of lpDest
1570c2c66affSColin Finck *
1571c2c66affSColin Finck * RETURNS
1572c2c66affSColin Finck * Success: TRUE. lpDest is filled with the computed hash value.
1573c2c66affSColin Finck * Failure: FALSE, if any argument is invalid.
1574c2c66affSColin Finck */
HashData(const unsigned char * lpSrc,DWORD nSrcLen,unsigned char * lpDest,DWORD nDestLen)1575c2c66affSColin Finck HRESULT WINAPI HashData(const unsigned char *lpSrc, DWORD nSrcLen,
1576c2c66affSColin Finck unsigned char *lpDest, DWORD nDestLen)
1577c2c66affSColin Finck {
1578c2c66affSColin Finck INT srcCount = nSrcLen - 1, destCount = nDestLen - 1;
1579c2c66affSColin Finck
1580c2c66affSColin Finck if (!lpSrc || !lpDest)
1581c2c66affSColin Finck return E_INVALIDARG;
1582c2c66affSColin Finck
1583c2c66affSColin Finck while (destCount >= 0)
1584c2c66affSColin Finck {
1585c2c66affSColin Finck lpDest[destCount] = (destCount & 0xff);
1586c2c66affSColin Finck destCount--;
1587c2c66affSColin Finck }
1588c2c66affSColin Finck
1589c2c66affSColin Finck while (srcCount >= 0)
1590c2c66affSColin Finck {
1591c2c66affSColin Finck destCount = nDestLen - 1;
1592c2c66affSColin Finck while (destCount >= 0)
1593c2c66affSColin Finck {
1594c2c66affSColin Finck lpDest[destCount] = HashDataLookup[lpSrc[srcCount] ^ lpDest[destCount]];
1595c2c66affSColin Finck destCount--;
1596c2c66affSColin Finck }
1597c2c66affSColin Finck srcCount--;
1598c2c66affSColin Finck }
1599c2c66affSColin Finck return S_OK;
1600c2c66affSColin Finck }
1601c2c66affSColin Finck
1602c2c66affSColin Finck /*************************************************************************
1603c2c66affSColin Finck * UrlHashA [SHLWAPI.@]
1604c2c66affSColin Finck *
1605c2c66affSColin Finck * Produce a Hash from a Url.
1606c2c66affSColin Finck *
1607c2c66affSColin Finck * PARAMS
1608c2c66affSColin Finck * pszUrl [I] Url to hash
1609c2c66affSColin Finck * lpDest [O] Destinationh for hash
1610c2c66affSColin Finck * nDestLen [I] Length of lpDest
1611c2c66affSColin Finck *
1612c2c66affSColin Finck * RETURNS
1613c2c66affSColin Finck * Success: S_OK. lpDest is filled with the computed hash value.
1614c2c66affSColin Finck * Failure: E_INVALIDARG, if any argument is invalid.
1615c2c66affSColin Finck */
UrlHashA(LPCSTR pszUrl,unsigned char * lpDest,DWORD nDestLen)1616c2c66affSColin Finck HRESULT WINAPI UrlHashA(LPCSTR pszUrl, unsigned char *lpDest, DWORD nDestLen)
1617c2c66affSColin Finck {
1618c2c66affSColin Finck if (IsBadStringPtrA(pszUrl, -1) || IsBadWritePtr(lpDest, nDestLen))
1619c2c66affSColin Finck return E_INVALIDARG;
1620c2c66affSColin Finck
1621c2c66affSColin Finck HashData((const BYTE*)pszUrl, (int)strlen(pszUrl), lpDest, nDestLen);
1622c2c66affSColin Finck return S_OK;
1623c2c66affSColin Finck }
1624c2c66affSColin Finck
1625c2c66affSColin Finck /*************************************************************************
1626c2c66affSColin Finck * UrlHashW [SHLWAPI.@]
1627c2c66affSColin Finck *
1628c2c66affSColin Finck * See UrlHashA.
1629c2c66affSColin Finck */
UrlHashW(LPCWSTR pszUrl,unsigned char * lpDest,DWORD nDestLen)1630c2c66affSColin Finck HRESULT WINAPI UrlHashW(LPCWSTR pszUrl, unsigned char *lpDest, DWORD nDestLen)
1631c2c66affSColin Finck {
1632c2c66affSColin Finck char szUrl[MAX_PATH];
1633c2c66affSColin Finck
1634c2c66affSColin Finck TRACE("(%s,%p,%d)\n",debugstr_w(pszUrl), lpDest, nDestLen);
1635c2c66affSColin Finck
1636c2c66affSColin Finck if (IsBadStringPtrW(pszUrl, -1) || IsBadWritePtr(lpDest, nDestLen))
1637c2c66affSColin Finck return E_INVALIDARG;
1638c2c66affSColin Finck
1639c2c66affSColin Finck /* Win32 hashes the data as an ASCII string, presumably so that both A+W
1640c2c66affSColin Finck * return the same digests for the same URL.
1641c2c66affSColin Finck */
1642c2c66affSColin Finck WideCharToMultiByte(CP_ACP, 0, pszUrl, -1, szUrl, MAX_PATH, NULL, NULL);
1643c2c66affSColin Finck HashData((const BYTE*)szUrl, (int)strlen(szUrl), lpDest, nDestLen);
1644c2c66affSColin Finck return S_OK;
1645c2c66affSColin Finck }
1646c2c66affSColin Finck
1647c2c66affSColin Finck /*************************************************************************
1648c2c66affSColin Finck * UrlApplySchemeA [SHLWAPI.@]
1649c2c66affSColin Finck *
1650c2c66affSColin Finck * Apply a scheme to a Url.
1651c2c66affSColin Finck *
1652c2c66affSColin Finck * PARAMS
1653c2c66affSColin Finck * pszIn [I] Url to apply scheme to
1654c2c66affSColin Finck * pszOut [O] Destination for modified Url
1655c2c66affSColin Finck * pcchOut [I/O] Length of pszOut/destination for length of pszOut
1656c2c66affSColin Finck * dwFlags [I] URL_ flags from "shlwapi.h"
1657c2c66affSColin Finck *
1658c2c66affSColin Finck * RETURNS
1659c2c66affSColin Finck * Success: S_OK: pszOut contains the modified Url, pcchOut contains its length.
1660c2c66affSColin Finck * Failure: An HRESULT error code describing the error.
1661c2c66affSColin Finck */
UrlApplySchemeA(LPCSTR pszIn,LPSTR pszOut,LPDWORD pcchOut,DWORD dwFlags)1662c2c66affSColin Finck HRESULT WINAPI UrlApplySchemeA(LPCSTR pszIn, LPSTR pszOut, LPDWORD pcchOut, DWORD dwFlags)
1663c2c66affSColin Finck {
1664c2c66affSColin Finck LPWSTR in, out;
1665c2c66affSColin Finck HRESULT ret;
1666c2c66affSColin Finck DWORD len;
1667c2c66affSColin Finck
1668c2c66affSColin Finck TRACE("(%s, %p, %p:out size %d, 0x%08x)\n", debugstr_a(pszIn),
1669c2c66affSColin Finck pszOut, pcchOut, pcchOut ? *pcchOut : 0, dwFlags);
1670c2c66affSColin Finck
1671c2c66affSColin Finck if (!pszIn || !pszOut || !pcchOut) return E_INVALIDARG;
1672c2c66affSColin Finck
1673c2c66affSColin Finck in = HeapAlloc(GetProcessHeap(), 0,
1674c2c66affSColin Finck (2*INTERNET_MAX_URL_LENGTH) * sizeof(WCHAR));
1675c2c66affSColin Finck out = in + INTERNET_MAX_URL_LENGTH;
1676c2c66affSColin Finck
1677c2c66affSColin Finck MultiByteToWideChar(CP_ACP, 0, pszIn, -1, in, INTERNET_MAX_URL_LENGTH);
1678c2c66affSColin Finck len = INTERNET_MAX_URL_LENGTH;
1679c2c66affSColin Finck
1680c2c66affSColin Finck ret = UrlApplySchemeW(in, out, &len, dwFlags);
1681c2c66affSColin Finck if (ret != S_OK) {
1682c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, in);
1683c2c66affSColin Finck return ret;
1684c2c66affSColin Finck }
1685c2c66affSColin Finck
1686c2c66affSColin Finck len = WideCharToMultiByte(CP_ACP, 0, out, -1, NULL, 0, NULL, NULL);
1687c2c66affSColin Finck if (len > *pcchOut) {
1688c2c66affSColin Finck ret = E_POINTER;
1689c2c66affSColin Finck goto cleanup;
1690c2c66affSColin Finck }
1691c2c66affSColin Finck
1692c2c66affSColin Finck WideCharToMultiByte(CP_ACP, 0, out, -1, pszOut, *pcchOut, NULL, NULL);
1693c2c66affSColin Finck len--;
1694c2c66affSColin Finck
1695c2c66affSColin Finck cleanup:
1696c2c66affSColin Finck *pcchOut = len;
1697c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, in);
1698c2c66affSColin Finck return ret;
1699c2c66affSColin Finck }
1700c2c66affSColin Finck
URL_GuessScheme(LPCWSTR pszIn,LPWSTR pszOut,LPDWORD pcchOut)1701c2c66affSColin Finck static HRESULT URL_GuessScheme(LPCWSTR pszIn, LPWSTR pszOut, LPDWORD pcchOut)
1702c2c66affSColin Finck {
1703c2c66affSColin Finck HKEY newkey;
1704c2c66affSColin Finck BOOL j;
1705c2c66affSColin Finck INT index;
1706c2c66affSColin Finck DWORD value_len, data_len, dwType, i;
1707c2c66affSColin Finck WCHAR reg_path[MAX_PATH];
1708c2c66affSColin Finck WCHAR value[MAX_PATH], data[MAX_PATH];
1709c2c66affSColin Finck WCHAR Wxx, Wyy;
1710c2c66affSColin Finck
1711c2c66affSColin Finck MultiByteToWideChar(CP_ACP, 0,
1712c2c66affSColin Finck "Software\\Microsoft\\Windows\\CurrentVersion\\URL\\Prefixes",
1713c2c66affSColin Finck -1, reg_path, MAX_PATH);
1714c2c66affSColin Finck RegOpenKeyExW(HKEY_LOCAL_MACHINE, reg_path, 0, 1, &newkey);
1715c2c66affSColin Finck index = 0;
1716c2c66affSColin Finck while(value_len = data_len = MAX_PATH,
1717c2c66affSColin Finck RegEnumValueW(newkey, index, value, &value_len,
1718c2c66affSColin Finck 0, &dwType, (LPVOID)data, &data_len) == 0) {
1719c2c66affSColin Finck TRACE("guess %d %s is %s\n",
1720c2c66affSColin Finck index, debugstr_w(value), debugstr_w(data));
1721c2c66affSColin Finck
1722c2c66affSColin Finck j = FALSE;
1723c2c66affSColin Finck for(i=0; i<value_len; i++) {
1724c2c66affSColin Finck Wxx = pszIn[i];
1725c2c66affSColin Finck Wyy = value[i];
1726c2c66affSColin Finck /* remember that TRUE is not-equal */
1727c2c66affSColin Finck j = ChrCmpIW(Wxx, Wyy);
1728c2c66affSColin Finck if (j) break;
1729c2c66affSColin Finck }
1730c2c66affSColin Finck if ((i == value_len) && !j) {
1731c2c66affSColin Finck if (strlenW(data) + strlenW(pszIn) + 1 > *pcchOut) {
1732c2c66affSColin Finck *pcchOut = strlenW(data) + strlenW(pszIn) + 1;
1733c2c66affSColin Finck RegCloseKey(newkey);
1734c2c66affSColin Finck return E_POINTER;
1735c2c66affSColin Finck }
1736c2c66affSColin Finck strcpyW(pszOut, data);
1737c2c66affSColin Finck strcatW(pszOut, pszIn);
1738c2c66affSColin Finck *pcchOut = strlenW(pszOut);
1739c2c66affSColin Finck TRACE("matched and set to %s\n", debugstr_w(pszOut));
1740c2c66affSColin Finck RegCloseKey(newkey);
1741c2c66affSColin Finck return S_OK;
1742c2c66affSColin Finck }
1743c2c66affSColin Finck index++;
1744c2c66affSColin Finck }
1745c2c66affSColin Finck RegCloseKey(newkey);
1746c2c66affSColin Finck return E_FAIL;
1747c2c66affSColin Finck }
1748c2c66affSColin Finck
URL_CreateFromPath(LPCWSTR pszPath,LPWSTR pszUrl,LPDWORD pcchUrl)1749c2c66affSColin Finck static HRESULT URL_CreateFromPath(LPCWSTR pszPath, LPWSTR pszUrl, LPDWORD pcchUrl)
1750c2c66affSColin Finck {
1751c2c66affSColin Finck DWORD needed;
1752c2c66affSColin Finck HRESULT ret = S_OK;
1753c2c66affSColin Finck WCHAR *pszNewUrl;
1754c2c66affSColin Finck WCHAR file_colonW[] = {'f','i','l','e',':',0};
1755c2c66affSColin Finck WCHAR three_slashesW[] = {'/','/','/',0};
1756c2c66affSColin Finck PARSEDURLW parsed_url;
1757c2c66affSColin Finck
1758c2c66affSColin Finck parsed_url.cbSize = sizeof(parsed_url);
1759c2c66affSColin Finck if(ParseURLW(pszPath, &parsed_url) == S_OK) {
1760c2c66affSColin Finck if(parsed_url.nScheme != URL_SCHEME_INVALID && parsed_url.cchProtocol > 1) {
1761c2c66affSColin Finck needed = strlenW(pszPath);
1762c2c66affSColin Finck if (needed >= *pcchUrl) {
1763c2c66affSColin Finck *pcchUrl = needed + 1;
1764c2c66affSColin Finck return E_POINTER;
1765c2c66affSColin Finck } else {
1766c2c66affSColin Finck *pcchUrl = needed;
1767c2c66affSColin Finck return S_FALSE;
1768c2c66affSColin Finck }
1769c2c66affSColin Finck }
1770c2c66affSColin Finck }
1771c2c66affSColin Finck
1772c2c66affSColin Finck pszNewUrl = HeapAlloc(GetProcessHeap(), 0, (strlenW(pszPath) + 9) * sizeof(WCHAR)); /* "file:///" + pszPath_len + 1 */
1773c2c66affSColin Finck strcpyW(pszNewUrl, file_colonW);
1774c2c66affSColin Finck if(isalphaW(pszPath[0]) && pszPath[1] == ':')
1775c2c66affSColin Finck strcatW(pszNewUrl, three_slashesW);
1776c2c66affSColin Finck strcatW(pszNewUrl, pszPath);
1777c2c66affSColin Finck ret = UrlEscapeW(pszNewUrl, pszUrl, pcchUrl, URL_ESCAPE_PERCENT);
1778c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, pszNewUrl);
1779c2c66affSColin Finck return ret;
1780c2c66affSColin Finck }
1781c2c66affSColin Finck
URL_ApplyDefault(LPCWSTR pszIn,LPWSTR pszOut,LPDWORD pcchOut)1782c2c66affSColin Finck static HRESULT URL_ApplyDefault(LPCWSTR pszIn, LPWSTR pszOut, LPDWORD pcchOut)
1783c2c66affSColin Finck {
1784c2c66affSColin Finck HKEY newkey;
1785c2c66affSColin Finck DWORD data_len, dwType;
1786c2c66affSColin Finck WCHAR data[MAX_PATH];
1787c2c66affSColin Finck
1788c2c66affSColin Finck static const WCHAR prefix_keyW[] =
1789c2c66affSColin Finck {'S','o','f','t','w','a','r','e',
1790c2c66affSColin Finck '\\','M','i','c','r','o','s','o','f','t',
1791c2c66affSColin Finck '\\','W','i','n','d','o','w','s',
1792c2c66affSColin Finck '\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n',
1793c2c66affSColin Finck '\\','U','R','L',
1794c2c66affSColin Finck '\\','D','e','f','a','u','l','t','P','r','e','f','i','x',0};
1795c2c66affSColin Finck
1796c2c66affSColin Finck /* get and prepend default */
1797c2c66affSColin Finck RegOpenKeyExW(HKEY_LOCAL_MACHINE, prefix_keyW, 0, 1, &newkey);
1798c2c66affSColin Finck data_len = sizeof(data);
1799c2c66affSColin Finck RegQueryValueExW(newkey, NULL, 0, &dwType, (LPBYTE)data, &data_len);
1800c2c66affSColin Finck RegCloseKey(newkey);
1801c2c66affSColin Finck if (strlenW(data) + strlenW(pszIn) + 1 > *pcchOut) {
1802c2c66affSColin Finck *pcchOut = strlenW(data) + strlenW(pszIn) + 1;
1803c2c66affSColin Finck return E_POINTER;
1804c2c66affSColin Finck }
1805c2c66affSColin Finck strcpyW(pszOut, data);
1806c2c66affSColin Finck strcatW(pszOut, pszIn);
1807c2c66affSColin Finck *pcchOut = strlenW(pszOut);
1808c2c66affSColin Finck TRACE("used default %s\n", debugstr_w(pszOut));
1809c2c66affSColin Finck return S_OK;
1810c2c66affSColin Finck }
1811c2c66affSColin Finck
1812c2c66affSColin Finck /*************************************************************************
1813c2c66affSColin Finck * UrlApplySchemeW [SHLWAPI.@]
1814c2c66affSColin Finck *
1815c2c66affSColin Finck * See UrlApplySchemeA.
1816c2c66affSColin Finck */
UrlApplySchemeW(LPCWSTR pszIn,LPWSTR pszOut,LPDWORD pcchOut,DWORD dwFlags)1817c2c66affSColin Finck HRESULT WINAPI UrlApplySchemeW(LPCWSTR pszIn, LPWSTR pszOut, LPDWORD pcchOut, DWORD dwFlags)
1818c2c66affSColin Finck {
1819c2c66affSColin Finck PARSEDURLW in_scheme;
1820c2c66affSColin Finck DWORD res1;
1821c2c66affSColin Finck HRESULT ret;
1822c2c66affSColin Finck
1823c2c66affSColin Finck TRACE("(%s, %p, %p:out size %d, 0x%08x)\n", debugstr_w(pszIn),
1824c2c66affSColin Finck pszOut, pcchOut, pcchOut ? *pcchOut : 0, dwFlags);
1825c2c66affSColin Finck
1826c2c66affSColin Finck if (!pszIn || !pszOut || !pcchOut) return E_INVALIDARG;
1827c2c66affSColin Finck
1828c2c66affSColin Finck if (dwFlags & URL_APPLY_GUESSFILE) {
1829c2c66affSColin Finck if (*pcchOut > 1 && ':' == pszIn[1]) {
1830c2c66affSColin Finck res1 = *pcchOut;
1831c2c66affSColin Finck ret = URL_CreateFromPath(pszIn, pszOut, &res1);
1832c2c66affSColin Finck if (ret == S_OK || ret == E_POINTER){
1833c2c66affSColin Finck *pcchOut = res1;
1834c2c66affSColin Finck return ret;
1835c2c66affSColin Finck }
1836c2c66affSColin Finck else if (ret == S_FALSE)
1837c2c66affSColin Finck {
1838c2c66affSColin Finck return ret;
1839c2c66affSColin Finck }
1840c2c66affSColin Finck }
1841c2c66affSColin Finck }
1842c2c66affSColin Finck
1843c2c66affSColin Finck in_scheme.cbSize = sizeof(in_scheme);
1844c2c66affSColin Finck /* See if the base has a scheme */
1845c2c66affSColin Finck res1 = ParseURLW(pszIn, &in_scheme);
1846c2c66affSColin Finck if (res1) {
1847c2c66affSColin Finck /* no scheme in input, need to see if we need to guess */
1848c2c66affSColin Finck if (dwFlags & URL_APPLY_GUESSSCHEME) {
1849c2c66affSColin Finck if ((ret = URL_GuessScheme(pszIn, pszOut, pcchOut)) != E_FAIL)
1850c2c66affSColin Finck return ret;
1851c2c66affSColin Finck }
1852c2c66affSColin Finck }
1853c2c66affSColin Finck
1854c2c66affSColin Finck /* If we are here, then either invalid scheme,
1855c2c66affSColin Finck * or no scheme and can't/failed guess.
1856c2c66affSColin Finck */
1857c2c66affSColin Finck if ( ( ((res1 == 0) && (dwFlags & URL_APPLY_FORCEAPPLY)) ||
1858c2c66affSColin Finck ((res1 != 0)) ) &&
1859c2c66affSColin Finck (dwFlags & URL_APPLY_DEFAULT)) {
1860c2c66affSColin Finck /* find and apply default scheme */
1861c2c66affSColin Finck return URL_ApplyDefault(pszIn, pszOut, pcchOut);
1862c2c66affSColin Finck }
1863c2c66affSColin Finck
1864c2c66affSColin Finck return S_FALSE;
1865c2c66affSColin Finck }
1866c2c66affSColin Finck
1867c2c66affSColin Finck /*************************************************************************
1868c2c66affSColin Finck * UrlIsA [SHLWAPI.@]
1869c2c66affSColin Finck *
1870c2c66affSColin Finck * Determine if a Url is of a certain class.
1871c2c66affSColin Finck *
1872c2c66affSColin Finck * PARAMS
1873c2c66affSColin Finck * pszUrl [I] Url to check
1874c2c66affSColin Finck * Urlis [I] URLIS_ constant from "shlwapi.h"
1875c2c66affSColin Finck *
1876c2c66affSColin Finck * RETURNS
1877c2c66affSColin Finck * TRUE if pszUrl belongs to the class type in Urlis.
1878c2c66affSColin Finck * FALSE Otherwise.
1879c2c66affSColin Finck */
UrlIsA(LPCSTR pszUrl,URLIS Urlis)1880c2c66affSColin Finck BOOL WINAPI UrlIsA(LPCSTR pszUrl, URLIS Urlis)
1881c2c66affSColin Finck {
1882c2c66affSColin Finck PARSEDURLA base;
1883c2c66affSColin Finck DWORD res1;
1884c2c66affSColin Finck LPCSTR last;
1885c2c66affSColin Finck
1886c2c66affSColin Finck TRACE("(%s %d)\n", debugstr_a(pszUrl), Urlis);
1887c2c66affSColin Finck
1888c2c66affSColin Finck if(!pszUrl)
1889c2c66affSColin Finck return FALSE;
1890c2c66affSColin Finck
1891c2c66affSColin Finck switch (Urlis) {
1892c2c66affSColin Finck
1893c2c66affSColin Finck case URLIS_OPAQUE:
1894c2c66affSColin Finck base.cbSize = sizeof(base);
1895c2c66affSColin Finck res1 = ParseURLA(pszUrl, &base);
1896c2c66affSColin Finck if (res1) return FALSE; /* invalid scheme */
1897c2c66affSColin Finck switch (base.nScheme)
1898c2c66affSColin Finck {
1899c2c66affSColin Finck case URL_SCHEME_MAILTO:
1900c2c66affSColin Finck case URL_SCHEME_SHELL:
1901c2c66affSColin Finck case URL_SCHEME_JAVASCRIPT:
1902c2c66affSColin Finck case URL_SCHEME_VBSCRIPT:
1903c2c66affSColin Finck case URL_SCHEME_ABOUT:
1904c2c66affSColin Finck return TRUE;
1905c2c66affSColin Finck }
1906c2c66affSColin Finck return FALSE;
1907c2c66affSColin Finck
1908c2c66affSColin Finck case URLIS_FILEURL:
1909c2c66affSColin Finck return (CompareStringA(LOCALE_INVARIANT, NORM_IGNORECASE, pszUrl, 5,
1910c2c66affSColin Finck "file:", 5) == CSTR_EQUAL);
1911c2c66affSColin Finck
1912c2c66affSColin Finck case URLIS_DIRECTORY:
1913c2c66affSColin Finck last = pszUrl + strlen(pszUrl) - 1;
1914c2c66affSColin Finck return (last >= pszUrl && (*last == '/' || *last == '\\' ));
1915c2c66affSColin Finck
1916c2c66affSColin Finck case URLIS_URL:
1917c2c66affSColin Finck return PathIsURLA(pszUrl);
1918c2c66affSColin Finck
1919c2c66affSColin Finck case URLIS_NOHISTORY:
1920c2c66affSColin Finck case URLIS_APPLIABLE:
1921c2c66affSColin Finck case URLIS_HASQUERY:
1922c2c66affSColin Finck default:
1923c2c66affSColin Finck FIXME("(%s %d): stub\n", debugstr_a(pszUrl), Urlis);
1924c2c66affSColin Finck }
1925c2c66affSColin Finck return FALSE;
1926c2c66affSColin Finck }
1927c2c66affSColin Finck
1928c2c66affSColin Finck /*************************************************************************
1929c2c66affSColin Finck * UrlIsW [SHLWAPI.@]
1930c2c66affSColin Finck *
1931c2c66affSColin Finck * See UrlIsA.
1932c2c66affSColin Finck */
UrlIsW(LPCWSTR pszUrl,URLIS Urlis)1933c2c66affSColin Finck BOOL WINAPI UrlIsW(LPCWSTR pszUrl, URLIS Urlis)
1934c2c66affSColin Finck {
1935c2c66affSColin Finck static const WCHAR file_colon[] = { 'f','i','l','e',':',0 };
1936c2c66affSColin Finck PARSEDURLW base;
1937c2c66affSColin Finck DWORD res1;
1938c2c66affSColin Finck LPCWSTR last;
1939c2c66affSColin Finck
1940c2c66affSColin Finck TRACE("(%s %d)\n", debugstr_w(pszUrl), Urlis);
1941c2c66affSColin Finck
1942c2c66affSColin Finck if(!pszUrl)
1943c2c66affSColin Finck return FALSE;
1944c2c66affSColin Finck
1945c2c66affSColin Finck switch (Urlis) {
1946c2c66affSColin Finck
1947c2c66affSColin Finck case URLIS_OPAQUE:
1948c2c66affSColin Finck base.cbSize = sizeof(base);
1949c2c66affSColin Finck res1 = ParseURLW(pszUrl, &base);
1950c2c66affSColin Finck if (res1) return FALSE; /* invalid scheme */
1951c2c66affSColin Finck switch (base.nScheme)
1952c2c66affSColin Finck {
1953c2c66affSColin Finck case URL_SCHEME_MAILTO:
1954c2c66affSColin Finck case URL_SCHEME_SHELL:
1955c2c66affSColin Finck case URL_SCHEME_JAVASCRIPT:
1956c2c66affSColin Finck case URL_SCHEME_VBSCRIPT:
1957c2c66affSColin Finck case URL_SCHEME_ABOUT:
1958c2c66affSColin Finck return TRUE;
1959c2c66affSColin Finck }
1960c2c66affSColin Finck return FALSE;
1961c2c66affSColin Finck
1962c2c66affSColin Finck case URLIS_FILEURL:
1963c2c66affSColin Finck return (CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, pszUrl, 5,
1964c2c66affSColin Finck file_colon, 5) == CSTR_EQUAL);
1965c2c66affSColin Finck
1966c2c66affSColin Finck case URLIS_DIRECTORY:
1967c2c66affSColin Finck last = pszUrl + strlenW(pszUrl) - 1;
1968c2c66affSColin Finck return (last >= pszUrl && (*last == '/' || *last == '\\'));
1969c2c66affSColin Finck
1970c2c66affSColin Finck case URLIS_URL:
1971c2c66affSColin Finck return PathIsURLW(pszUrl);
1972c2c66affSColin Finck
1973c2c66affSColin Finck case URLIS_NOHISTORY:
1974c2c66affSColin Finck case URLIS_APPLIABLE:
1975c2c66affSColin Finck case URLIS_HASQUERY:
1976c2c66affSColin Finck default:
1977c2c66affSColin Finck FIXME("(%s %d): stub\n", debugstr_w(pszUrl), Urlis);
1978c2c66affSColin Finck }
1979c2c66affSColin Finck return FALSE;
1980c2c66affSColin Finck }
1981c2c66affSColin Finck
1982c2c66affSColin Finck /*************************************************************************
1983c2c66affSColin Finck * UrlIsNoHistoryA [SHLWAPI.@]
1984c2c66affSColin Finck *
1985c2c66affSColin Finck * Determine if a Url should not be stored in the users history list.
1986c2c66affSColin Finck *
1987c2c66affSColin Finck * PARAMS
1988c2c66affSColin Finck * pszUrl [I] Url to check
1989c2c66affSColin Finck *
1990c2c66affSColin Finck * RETURNS
1991c2c66affSColin Finck * TRUE, if pszUrl should be excluded from the history list,
1992c2c66affSColin Finck * FALSE otherwise.
1993c2c66affSColin Finck */
UrlIsNoHistoryA(LPCSTR pszUrl)1994c2c66affSColin Finck BOOL WINAPI UrlIsNoHistoryA(LPCSTR pszUrl)
1995c2c66affSColin Finck {
1996c2c66affSColin Finck return UrlIsA(pszUrl, URLIS_NOHISTORY);
1997c2c66affSColin Finck }
1998c2c66affSColin Finck
1999c2c66affSColin Finck /*************************************************************************
2000c2c66affSColin Finck * UrlIsNoHistoryW [SHLWAPI.@]
2001c2c66affSColin Finck *
2002c2c66affSColin Finck * See UrlIsNoHistoryA.
2003c2c66affSColin Finck */
UrlIsNoHistoryW(LPCWSTR pszUrl)2004c2c66affSColin Finck BOOL WINAPI UrlIsNoHistoryW(LPCWSTR pszUrl)
2005c2c66affSColin Finck {
2006c2c66affSColin Finck return UrlIsW(pszUrl, URLIS_NOHISTORY);
2007c2c66affSColin Finck }
2008c2c66affSColin Finck
2009c2c66affSColin Finck /*************************************************************************
2010c2c66affSColin Finck * UrlIsOpaqueA [SHLWAPI.@]
2011c2c66affSColin Finck *
2012c2c66affSColin Finck * Determine if a Url is opaque.
2013c2c66affSColin Finck *
2014c2c66affSColin Finck * PARAMS
2015c2c66affSColin Finck * pszUrl [I] Url to check
2016c2c66affSColin Finck *
2017c2c66affSColin Finck * RETURNS
2018c2c66affSColin Finck * TRUE if pszUrl is opaque,
2019c2c66affSColin Finck * FALSE Otherwise.
2020c2c66affSColin Finck *
2021c2c66affSColin Finck * NOTES
2022c2c66affSColin Finck * An opaque Url is one that does not start with "<protocol>://".
2023c2c66affSColin Finck */
UrlIsOpaqueA(LPCSTR pszUrl)2024c2c66affSColin Finck BOOL WINAPI UrlIsOpaqueA(LPCSTR pszUrl)
2025c2c66affSColin Finck {
2026c2c66affSColin Finck return UrlIsA(pszUrl, URLIS_OPAQUE);
2027c2c66affSColin Finck }
2028c2c66affSColin Finck
2029c2c66affSColin Finck /*************************************************************************
2030c2c66affSColin Finck * UrlIsOpaqueW [SHLWAPI.@]
2031c2c66affSColin Finck *
2032c2c66affSColin Finck * See UrlIsOpaqueA.
2033c2c66affSColin Finck */
UrlIsOpaqueW(LPCWSTR pszUrl)2034c2c66affSColin Finck BOOL WINAPI UrlIsOpaqueW(LPCWSTR pszUrl)
2035c2c66affSColin Finck {
2036c2c66affSColin Finck return UrlIsW(pszUrl, URLIS_OPAQUE);
2037c2c66affSColin Finck }
2038c2c66affSColin Finck
2039c2c66affSColin Finck /*************************************************************************
2040c2c66affSColin Finck * Scans for characters of type "type" and when not matching found,
2041c2c66affSColin Finck * returns pointer to it and length in size.
2042c2c66affSColin Finck *
2043c2c66affSColin Finck * Characters tested based on RFC 1738
2044c2c66affSColin Finck */
URL_ScanID(LPCWSTR start,LPDWORD size,WINE_URL_SCAN_TYPE type)2045c2c66affSColin Finck static LPCWSTR URL_ScanID(LPCWSTR start, LPDWORD size, WINE_URL_SCAN_TYPE type)
2046c2c66affSColin Finck {
2047c2c66affSColin Finck static DWORD alwayszero = 0;
2048c2c66affSColin Finck BOOL cont = TRUE;
2049c2c66affSColin Finck
2050c2c66affSColin Finck *size = 0;
2051c2c66affSColin Finck
2052c2c66affSColin Finck switch(type){
2053c2c66affSColin Finck
2054c2c66affSColin Finck case SCHEME:
2055c2c66affSColin Finck while (cont) {
2056c2c66affSColin Finck if ( (islowerW(*start) && isalphaW(*start)) ||
2057c2c66affSColin Finck isdigitW(*start) ||
2058c2c66affSColin Finck (*start == '+') ||
2059c2c66affSColin Finck (*start == '-') ||
2060c2c66affSColin Finck (*start == '.')) {
2061c2c66affSColin Finck start++;
2062c2c66affSColin Finck (*size)++;
2063c2c66affSColin Finck }
2064c2c66affSColin Finck else
2065c2c66affSColin Finck cont = FALSE;
2066c2c66affSColin Finck }
2067c2c66affSColin Finck
2068c2c66affSColin Finck if(*start != ':')
2069c2c66affSColin Finck *size = 0;
2070c2c66affSColin Finck
2071c2c66affSColin Finck break;
2072c2c66affSColin Finck
2073c2c66affSColin Finck case USERPASS:
2074c2c66affSColin Finck while (cont) {
2075c2c66affSColin Finck if ( isalphaW(*start) ||
2076c2c66affSColin Finck isdigitW(*start) ||
2077c2c66affSColin Finck /* user/password only characters */
2078c2c66affSColin Finck (*start == ';') ||
2079c2c66affSColin Finck (*start == '?') ||
2080c2c66affSColin Finck (*start == '&') ||
2081c2c66affSColin Finck (*start == '=') ||
2082c2c66affSColin Finck /* *extra* characters */
2083c2c66affSColin Finck (*start == '!') ||
2084c2c66affSColin Finck (*start == '*') ||
2085c2c66affSColin Finck (*start == '\'') ||
2086c2c66affSColin Finck (*start == '(') ||
2087c2c66affSColin Finck (*start == ')') ||
2088c2c66affSColin Finck (*start == ',') ||
2089c2c66affSColin Finck /* *safe* characters */
2090c2c66affSColin Finck (*start == '$') ||
2091c2c66affSColin Finck (*start == '_') ||
2092c2c66affSColin Finck (*start == '+') ||
2093c2c66affSColin Finck (*start == '-') ||
2094c2c66affSColin Finck (*start == '.') ||
2095c2c66affSColin Finck (*start == ' ')) {
2096c2c66affSColin Finck start++;
2097c2c66affSColin Finck (*size)++;
2098c2c66affSColin Finck } else if (*start == '%') {
2099c2c66affSColin Finck if (isxdigitW(*(start+1)) &&
2100c2c66affSColin Finck isxdigitW(*(start+2))) {
2101c2c66affSColin Finck start += 3;
2102c2c66affSColin Finck *size += 3;
2103c2c66affSColin Finck } else
2104c2c66affSColin Finck cont = FALSE;
2105c2c66affSColin Finck } else
2106c2c66affSColin Finck cont = FALSE;
2107c2c66affSColin Finck }
2108c2c66affSColin Finck break;
2109c2c66affSColin Finck
2110c2c66affSColin Finck case PORT:
2111c2c66affSColin Finck while (cont) {
2112c2c66affSColin Finck if (isdigitW(*start)) {
2113c2c66affSColin Finck start++;
2114c2c66affSColin Finck (*size)++;
2115c2c66affSColin Finck }
2116c2c66affSColin Finck else
2117c2c66affSColin Finck cont = FALSE;
2118c2c66affSColin Finck }
2119c2c66affSColin Finck break;
2120c2c66affSColin Finck
2121c2c66affSColin Finck case HOST:
2122c2c66affSColin Finck while (cont) {
2123c2c66affSColin Finck if (isalnumW(*start) ||
2124c2c66affSColin Finck (*start == '-') ||
2125c2c66affSColin Finck (*start == '.') ||
2126c2c66affSColin Finck (*start == ' ') ||
2127c2c66affSColin Finck (*start == '*') ) {
2128c2c66affSColin Finck start++;
2129c2c66affSColin Finck (*size)++;
2130c2c66affSColin Finck }
2131c2c66affSColin Finck else
2132c2c66affSColin Finck cont = FALSE;
2133c2c66affSColin Finck }
2134c2c66affSColin Finck break;
2135c2c66affSColin Finck default:
2136c2c66affSColin Finck FIXME("unknown type %d\n", type);
2137c2c66affSColin Finck return (LPWSTR)&alwayszero;
2138c2c66affSColin Finck }
2139c2c66affSColin Finck /* TRACE("scanned %d characters next char %p<%c>\n",
2140c2c66affSColin Finck *size, start, *start); */
2141c2c66affSColin Finck return start;
2142c2c66affSColin Finck }
2143c2c66affSColin Finck
2144c2c66affSColin Finck /*************************************************************************
2145c2c66affSColin Finck * Attempt to parse URL into pieces.
2146c2c66affSColin Finck */
URL_ParseUrl(LPCWSTR pszUrl,WINE_PARSE_URL * pl)2147c2c66affSColin Finck static LONG URL_ParseUrl(LPCWSTR pszUrl, WINE_PARSE_URL *pl)
2148c2c66affSColin Finck {
2149c2c66affSColin Finck LPCWSTR work;
2150c2c66affSColin Finck
2151c2c66affSColin Finck memset(pl, 0, sizeof(WINE_PARSE_URL));
2152c2c66affSColin Finck pl->pScheme = pszUrl;
2153c2c66affSColin Finck work = URL_ScanID(pl->pScheme, &pl->szScheme, SCHEME);
2154c2c66affSColin Finck if (!*work || (*work != ':')) goto ErrorExit;
2155c2c66affSColin Finck work++;
2156c2c66affSColin Finck if ((*work != '/') || (*(work+1) != '/')) goto SuccessExit;
2157c2c66affSColin Finck pl->pUserName = work + 2;
2158c2c66affSColin Finck work = URL_ScanID(pl->pUserName, &pl->szUserName, USERPASS);
2159c2c66affSColin Finck if (*work == ':' ) {
2160c2c66affSColin Finck /* parse password */
2161c2c66affSColin Finck work++;
2162c2c66affSColin Finck pl->pPassword = work;
2163c2c66affSColin Finck work = URL_ScanID(pl->pPassword, &pl->szPassword, USERPASS);
2164c2c66affSColin Finck if (*work != '@') {
2165c2c66affSColin Finck /* what we just parsed must be the hostname and port
2166c2c66affSColin Finck * so reset pointers and clear then let it parse */
2167c2c66affSColin Finck pl->szUserName = pl->szPassword = 0;
2168c2c66affSColin Finck work = pl->pUserName - 1;
2169c2c66affSColin Finck pl->pUserName = pl->pPassword = 0;
2170c2c66affSColin Finck }
2171c2c66affSColin Finck } else if (*work == '@') {
2172c2c66affSColin Finck /* no password */
2173c2c66affSColin Finck pl->szPassword = 0;
2174c2c66affSColin Finck pl->pPassword = 0;
2175c2c66affSColin Finck } else if (!*work || (*work == '/') || (*work == '.')) {
2176c2c66affSColin Finck /* what was parsed was hostname, so reset pointers and let it parse */
2177c2c66affSColin Finck pl->szUserName = pl->szPassword = 0;
2178c2c66affSColin Finck work = pl->pUserName - 1;
2179c2c66affSColin Finck pl->pUserName = pl->pPassword = 0;
2180c2c66affSColin Finck } else goto ErrorExit;
2181c2c66affSColin Finck
2182c2c66affSColin Finck /* now start parsing hostname or hostnumber */
2183c2c66affSColin Finck work++;
2184c2c66affSColin Finck pl->pHostName = work;
2185c2c66affSColin Finck work = URL_ScanID(pl->pHostName, &pl->szHostName, HOST);
2186c2c66affSColin Finck if (*work == ':') {
2187c2c66affSColin Finck /* parse port */
2188c2c66affSColin Finck work++;
2189c2c66affSColin Finck pl->pPort = work;
2190c2c66affSColin Finck work = URL_ScanID(pl->pPort, &pl->szPort, PORT);
2191c2c66affSColin Finck }
2192c2c66affSColin Finck if (*work == '/') {
2193c2c66affSColin Finck /* see if query string */
2194c2c66affSColin Finck pl->pQuery = strchrW(work, '?');
2195c2c66affSColin Finck if (pl->pQuery) pl->szQuery = strlenW(pl->pQuery);
2196c2c66affSColin Finck }
2197c2c66affSColin Finck SuccessExit:
2198c2c66affSColin Finck TRACE("parse successful: scheme=%p(%d), user=%p(%d), pass=%p(%d), host=%p(%d), port=%p(%d), query=%p(%d)\n",
2199c2c66affSColin Finck pl->pScheme, pl->szScheme,
2200c2c66affSColin Finck pl->pUserName, pl->szUserName,
2201c2c66affSColin Finck pl->pPassword, pl->szPassword,
2202c2c66affSColin Finck pl->pHostName, pl->szHostName,
2203c2c66affSColin Finck pl->pPort, pl->szPort,
2204c2c66affSColin Finck pl->pQuery, pl->szQuery);
2205c2c66affSColin Finck return S_OK;
2206c2c66affSColin Finck ErrorExit:
2207c2c66affSColin Finck FIXME("failed to parse %s\n", debugstr_w(pszUrl));
2208c2c66affSColin Finck return E_INVALIDARG;
2209c2c66affSColin Finck }
2210c2c66affSColin Finck
2211c2c66affSColin Finck /*************************************************************************
2212c2c66affSColin Finck * UrlGetPartA [SHLWAPI.@]
2213c2c66affSColin Finck *
2214c2c66affSColin Finck * Retrieve part of a Url.
2215c2c66affSColin Finck *
2216c2c66affSColin Finck * PARAMS
2217c2c66affSColin Finck * pszIn [I] Url to parse
2218c2c66affSColin Finck * pszOut [O] Destination for part of pszIn requested
2219c2c66affSColin Finck * pcchOut [I] Size of pszOut
2220c2c66affSColin Finck * [O] length of pszOut string EXCLUDING '\0' if S_OK, otherwise
2221c2c66affSColin Finck * needed size of pszOut INCLUDING '\0'.
2222c2c66affSColin Finck * dwPart [I] URL_PART_ enum from "shlwapi.h"
2223c2c66affSColin Finck * dwFlags [I] URL_ flags from "shlwapi.h"
2224c2c66affSColin Finck *
2225c2c66affSColin Finck * RETURNS
2226c2c66affSColin Finck * Success: S_OK. pszOut contains the part requested, pcchOut contains its length.
2227c2c66affSColin Finck * Failure: An HRESULT error code describing the error.
2228c2c66affSColin Finck */
UrlGetPartA(LPCSTR pszIn,LPSTR pszOut,LPDWORD pcchOut,DWORD dwPart,DWORD dwFlags)2229c2c66affSColin Finck HRESULT WINAPI UrlGetPartA(LPCSTR pszIn, LPSTR pszOut, LPDWORD pcchOut,
2230c2c66affSColin Finck DWORD dwPart, DWORD dwFlags)
2231c2c66affSColin Finck {
2232c2c66affSColin Finck LPWSTR in, out;
2233c2c66affSColin Finck DWORD ret, len, len2;
2234c2c66affSColin Finck
2235c2c66affSColin Finck if(!pszIn || !pszOut || !pcchOut || *pcchOut <= 0)
2236c2c66affSColin Finck return E_INVALIDARG;
2237c2c66affSColin Finck
2238c2c66affSColin Finck in = HeapAlloc(GetProcessHeap(), 0,
2239c2c66affSColin Finck (2*INTERNET_MAX_URL_LENGTH) * sizeof(WCHAR));
2240c2c66affSColin Finck out = in + INTERNET_MAX_URL_LENGTH;
2241c2c66affSColin Finck
2242c2c66affSColin Finck MultiByteToWideChar(CP_ACP, 0, pszIn, -1, in, INTERNET_MAX_URL_LENGTH);
2243c2c66affSColin Finck
2244c2c66affSColin Finck len = INTERNET_MAX_URL_LENGTH;
2245c2c66affSColin Finck ret = UrlGetPartW(in, out, &len, dwPart, dwFlags);
2246c2c66affSColin Finck
2247c2c66affSColin Finck if (FAILED(ret)) {
2248c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, in);
2249c2c66affSColin Finck return ret;
2250c2c66affSColin Finck }
2251c2c66affSColin Finck
2252c2c66affSColin Finck len2 = WideCharToMultiByte(CP_ACP, 0, out, len, NULL, 0, NULL, NULL);
2253c2c66affSColin Finck if (len2 > *pcchOut) {
2254c2c66affSColin Finck *pcchOut = len2+1;
2255c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, in);
2256c2c66affSColin Finck return E_POINTER;
2257c2c66affSColin Finck }
2258c2c66affSColin Finck len2 = WideCharToMultiByte(CP_ACP, 0, out, len+1, pszOut, *pcchOut, NULL, NULL);
2259c2c66affSColin Finck *pcchOut = len2-1;
2260c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, in);
2261c2c66affSColin Finck return ret;
2262c2c66affSColin Finck }
2263c2c66affSColin Finck
2264c2c66affSColin Finck /*************************************************************************
2265c2c66affSColin Finck * UrlGetPartW [SHLWAPI.@]
2266c2c66affSColin Finck *
2267c2c66affSColin Finck * See UrlGetPartA.
2268c2c66affSColin Finck */
UrlGetPartW(LPCWSTR pszIn,LPWSTR pszOut,LPDWORD pcchOut,DWORD dwPart,DWORD dwFlags)2269c2c66affSColin Finck HRESULT WINAPI UrlGetPartW(LPCWSTR pszIn, LPWSTR pszOut, LPDWORD pcchOut,
2270c2c66affSColin Finck DWORD dwPart, DWORD dwFlags)
2271c2c66affSColin Finck {
2272c2c66affSColin Finck WINE_PARSE_URL pl;
2273c2c66affSColin Finck HRESULT ret;
2274c2c66affSColin Finck DWORD scheme, size, schsize;
2275c2c66affSColin Finck LPCWSTR addr, schaddr;
2276c2c66affSColin Finck
2277c2c66affSColin Finck TRACE("(%s %p %p(%d) %08x %08x)\n",
2278c2c66affSColin Finck debugstr_w(pszIn), pszOut, pcchOut, *pcchOut, dwPart, dwFlags);
2279c2c66affSColin Finck
2280c2c66affSColin Finck if(!pszIn || !pszOut || !pcchOut || *pcchOut <= 0)
2281c2c66affSColin Finck return E_INVALIDARG;
2282c2c66affSColin Finck
2283c2c66affSColin Finck *pszOut = '\0';
2284c2c66affSColin Finck
2285c2c66affSColin Finck addr = strchrW(pszIn, ':');
2286c2c66affSColin Finck if(!addr)
2287c2c66affSColin Finck scheme = URL_SCHEME_UNKNOWN;
2288c2c66affSColin Finck else
2289c2c66affSColin Finck scheme = get_scheme_code(pszIn, addr-pszIn);
2290c2c66affSColin Finck
2291c2c66affSColin Finck ret = URL_ParseUrl(pszIn, &pl);
2292c2c66affSColin Finck
2293c2c66affSColin Finck switch (dwPart) {
2294c2c66affSColin Finck case URL_PART_SCHEME:
2295c2c66affSColin Finck if (!pl.szScheme) {
2296c2c66affSColin Finck *pcchOut = 0;
2297c2c66affSColin Finck return S_FALSE;
2298c2c66affSColin Finck }
2299c2c66affSColin Finck addr = pl.pScheme;
2300c2c66affSColin Finck size = pl.szScheme;
2301c2c66affSColin Finck break;
2302c2c66affSColin Finck
2303c2c66affSColin Finck case URL_PART_HOSTNAME:
2304c2c66affSColin Finck switch(scheme) {
2305c2c66affSColin Finck case URL_SCHEME_FTP:
2306c2c66affSColin Finck case URL_SCHEME_HTTP:
2307c2c66affSColin Finck case URL_SCHEME_GOPHER:
2308c2c66affSColin Finck case URL_SCHEME_TELNET:
2309c2c66affSColin Finck case URL_SCHEME_FILE:
2310c2c66affSColin Finck case URL_SCHEME_HTTPS:
2311c2c66affSColin Finck break;
2312c2c66affSColin Finck default:
2313c2c66affSColin Finck *pcchOut = 0;
2314c2c66affSColin Finck return E_FAIL;
2315c2c66affSColin Finck }
2316c2c66affSColin Finck
2317c2c66affSColin Finck if(scheme==URL_SCHEME_FILE && (!pl.szHostName ||
2318c2c66affSColin Finck (pl.szHostName==1 && *(pl.pHostName+1)==':'))) {
2319c2c66affSColin Finck *pcchOut = 0;
2320c2c66affSColin Finck return S_FALSE;
2321c2c66affSColin Finck }
2322c2c66affSColin Finck
2323c2c66affSColin Finck if (!pl.szHostName) {
2324c2c66affSColin Finck *pcchOut = 0;
2325c2c66affSColin Finck return S_FALSE;
2326c2c66affSColin Finck }
2327c2c66affSColin Finck addr = pl.pHostName;
2328c2c66affSColin Finck size = pl.szHostName;
2329c2c66affSColin Finck break;
2330c2c66affSColin Finck
2331c2c66affSColin Finck case URL_PART_USERNAME:
2332c2c66affSColin Finck if (!pl.szUserName) {
2333c2c66affSColin Finck *pcchOut = 0;
2334c2c66affSColin Finck return S_FALSE;
2335c2c66affSColin Finck }
2336c2c66affSColin Finck addr = pl.pUserName;
2337c2c66affSColin Finck size = pl.szUserName;
2338c2c66affSColin Finck break;
2339c2c66affSColin Finck
2340c2c66affSColin Finck case URL_PART_PASSWORD:
2341c2c66affSColin Finck if (!pl.szPassword) {
2342c2c66affSColin Finck *pcchOut = 0;
2343c2c66affSColin Finck return S_FALSE;
2344c2c66affSColin Finck }
2345c2c66affSColin Finck addr = pl.pPassword;
2346c2c66affSColin Finck size = pl.szPassword;
2347c2c66affSColin Finck break;
2348c2c66affSColin Finck
2349c2c66affSColin Finck case URL_PART_PORT:
2350c2c66affSColin Finck if (!pl.szPort) {
2351c2c66affSColin Finck *pcchOut = 0;
2352c2c66affSColin Finck return S_FALSE;
2353c2c66affSColin Finck }
2354c2c66affSColin Finck addr = pl.pPort;
2355c2c66affSColin Finck size = pl.szPort;
2356c2c66affSColin Finck break;
2357c2c66affSColin Finck
2358c2c66affSColin Finck case URL_PART_QUERY:
2359c2c66affSColin Finck if (!pl.szQuery) {
2360c2c66affSColin Finck *pcchOut = 0;
2361c2c66affSColin Finck return S_FALSE;
2362c2c66affSColin Finck }
2363c2c66affSColin Finck addr = pl.pQuery;
2364c2c66affSColin Finck size = pl.szQuery;
2365c2c66affSColin Finck break;
2366c2c66affSColin Finck
2367c2c66affSColin Finck default:
2368c2c66affSColin Finck *pcchOut = 0;
2369c2c66affSColin Finck return E_INVALIDARG;
2370c2c66affSColin Finck }
2371c2c66affSColin Finck
2372c2c66affSColin Finck if (dwFlags == URL_PARTFLAG_KEEPSCHEME) {
2373c2c66affSColin Finck if(!pl.pScheme || !pl.szScheme) {
2374c2c66affSColin Finck *pcchOut = 0;
2375c2c66affSColin Finck return E_FAIL;
2376c2c66affSColin Finck }
2377c2c66affSColin Finck schaddr = pl.pScheme;
2378c2c66affSColin Finck schsize = pl.szScheme;
2379c2c66affSColin Finck if (*pcchOut < schsize + size + 2) {
2380c2c66affSColin Finck *pcchOut = schsize + size + 2;
2381c2c66affSColin Finck return E_POINTER;
2382c2c66affSColin Finck }
2383c2c66affSColin Finck memcpy(pszOut, schaddr, schsize*sizeof(WCHAR));
2384c2c66affSColin Finck pszOut[schsize] = ':';
2385c2c66affSColin Finck memcpy(pszOut+schsize+1, addr, size*sizeof(WCHAR));
2386c2c66affSColin Finck pszOut[schsize+1+size] = 0;
2387c2c66affSColin Finck *pcchOut = schsize + 1 + size;
2388c2c66affSColin Finck }
2389c2c66affSColin Finck else {
2390c2c66affSColin Finck if (*pcchOut < size + 1) {*pcchOut = size+1; return E_POINTER;}
2391c2c66affSColin Finck memcpy(pszOut, addr, size*sizeof(WCHAR));
2392c2c66affSColin Finck pszOut[size] = 0;
2393c2c66affSColin Finck *pcchOut = size;
2394c2c66affSColin Finck }
2395c2c66affSColin Finck TRACE("len=%d %s\n", *pcchOut, debugstr_w(pszOut));
2396c2c66affSColin Finck
2397c2c66affSColin Finck return ret;
2398c2c66affSColin Finck }
2399c2c66affSColin Finck
2400c2c66affSColin Finck /*************************************************************************
2401c2c66affSColin Finck * PathIsURLA [SHLWAPI.@]
2402c2c66affSColin Finck *
2403c2c66affSColin Finck * Check if the given path is a Url.
2404c2c66affSColin Finck *
2405c2c66affSColin Finck * PARAMS
2406c2c66affSColin Finck * lpszPath [I] Path to check.
2407c2c66affSColin Finck *
2408c2c66affSColin Finck * RETURNS
2409c2c66affSColin Finck * TRUE if lpszPath is a Url.
2410c2c66affSColin Finck * FALSE if lpszPath is NULL or not a Url.
2411c2c66affSColin Finck */
PathIsURLA(LPCSTR lpstrPath)2412c2c66affSColin Finck BOOL WINAPI PathIsURLA(LPCSTR lpstrPath)
2413c2c66affSColin Finck {
2414c2c66affSColin Finck PARSEDURLA base;
2415c2c66affSColin Finck HRESULT hres;
2416c2c66affSColin Finck
2417c2c66affSColin Finck TRACE("%s\n", debugstr_a(lpstrPath));
2418c2c66affSColin Finck
2419c2c66affSColin Finck if (!lpstrPath || !*lpstrPath) return FALSE;
2420c2c66affSColin Finck
2421c2c66affSColin Finck /* get protocol */
2422c2c66affSColin Finck base.cbSize = sizeof(base);
2423c2c66affSColin Finck hres = ParseURLA(lpstrPath, &base);
2424c2c66affSColin Finck return hres == S_OK && (base.nScheme != URL_SCHEME_INVALID);
2425c2c66affSColin Finck }
2426c2c66affSColin Finck
2427c2c66affSColin Finck /*************************************************************************
2428c2c66affSColin Finck * PathIsURLW [SHLWAPI.@]
2429c2c66affSColin Finck *
2430c2c66affSColin Finck * See PathIsURLA.
2431c2c66affSColin Finck */
PathIsURLW(LPCWSTR lpstrPath)2432c2c66affSColin Finck BOOL WINAPI PathIsURLW(LPCWSTR lpstrPath)
2433c2c66affSColin Finck {
2434c2c66affSColin Finck PARSEDURLW base;
2435c2c66affSColin Finck HRESULT hres;
2436c2c66affSColin Finck
2437c2c66affSColin Finck TRACE("%s\n", debugstr_w(lpstrPath));
2438c2c66affSColin Finck
2439c2c66affSColin Finck if (!lpstrPath || !*lpstrPath) return FALSE;
2440c2c66affSColin Finck
2441c2c66affSColin Finck /* get protocol */
2442c2c66affSColin Finck base.cbSize = sizeof(base);
2443c2c66affSColin Finck hres = ParseURLW(lpstrPath, &base);
2444c2c66affSColin Finck return hres == S_OK && (base.nScheme != URL_SCHEME_INVALID);
2445c2c66affSColin Finck }
2446c2c66affSColin Finck
2447c2c66affSColin Finck /*************************************************************************
2448c2c66affSColin Finck * UrlCreateFromPathA [SHLWAPI.@]
2449c2c66affSColin Finck *
2450c2c66affSColin Finck * See UrlCreateFromPathW
2451c2c66affSColin Finck */
UrlCreateFromPathA(LPCSTR pszPath,LPSTR pszUrl,LPDWORD pcchUrl,DWORD dwReserved)2452c2c66affSColin Finck HRESULT WINAPI UrlCreateFromPathA(LPCSTR pszPath, LPSTR pszUrl, LPDWORD pcchUrl, DWORD dwReserved)
2453c2c66affSColin Finck {
2454c2c66affSColin Finck WCHAR bufW[INTERNET_MAX_URL_LENGTH];
2455c2c66affSColin Finck WCHAR *urlW = bufW;
2456c2c66affSColin Finck UNICODE_STRING pathW;
2457c2c66affSColin Finck HRESULT ret;
2458c2c66affSColin Finck DWORD lenW = sizeof(bufW)/sizeof(WCHAR), lenA;
2459c2c66affSColin Finck
2460c2c66affSColin Finck if(!RtlCreateUnicodeStringFromAsciiz(&pathW, pszPath))
2461c2c66affSColin Finck return E_INVALIDARG;
2462c2c66affSColin Finck if((ret = UrlCreateFromPathW(pathW.Buffer, urlW, &lenW, dwReserved)) == E_POINTER) {
2463c2c66affSColin Finck urlW = HeapAlloc(GetProcessHeap(), 0, lenW * sizeof(WCHAR));
2464c2c66affSColin Finck ret = UrlCreateFromPathW(pathW.Buffer, urlW, &lenW, dwReserved);
2465c2c66affSColin Finck }
2466c2c66affSColin Finck if(ret == S_OK || ret == S_FALSE) {
2467c2c66affSColin Finck RtlUnicodeToMultiByteSize(&lenA, urlW, lenW * sizeof(WCHAR));
2468c2c66affSColin Finck if(*pcchUrl > lenA) {
2469c2c66affSColin Finck RtlUnicodeToMultiByteN(pszUrl, *pcchUrl - 1, &lenA, urlW, lenW * sizeof(WCHAR));
2470c2c66affSColin Finck pszUrl[lenA] = 0;
2471c2c66affSColin Finck *pcchUrl = lenA;
2472c2c66affSColin Finck } else {
2473c2c66affSColin Finck *pcchUrl = lenA + 1;
2474c2c66affSColin Finck ret = E_POINTER;
2475c2c66affSColin Finck }
2476c2c66affSColin Finck }
2477c2c66affSColin Finck if(urlW != bufW) HeapFree(GetProcessHeap(), 0, urlW);
2478c2c66affSColin Finck RtlFreeUnicodeString(&pathW);
2479c2c66affSColin Finck return ret;
2480c2c66affSColin Finck }
2481c2c66affSColin Finck
2482c2c66affSColin Finck /*************************************************************************
2483c2c66affSColin Finck * UrlCreateFromPathW [SHLWAPI.@]
2484c2c66affSColin Finck *
2485c2c66affSColin Finck * Create a Url from a file path.
2486c2c66affSColin Finck *
2487c2c66affSColin Finck * PARAMS
2488c2c66affSColin Finck * pszPath [I] Path to convert
2489c2c66affSColin Finck * pszUrl [O] Destination for the converted Url
2490c2c66affSColin Finck * pcchUrl [I/O] Length of pszUrl
2491c2c66affSColin Finck * dwReserved [I] Reserved, must be 0
2492c2c66affSColin Finck *
2493c2c66affSColin Finck * RETURNS
2494c2c66affSColin Finck * Success: S_OK pszUrl contains the converted path, S_FALSE if the path is already a Url
2495c2c66affSColin Finck * Failure: An HRESULT error code.
2496c2c66affSColin Finck */
UrlCreateFromPathW(LPCWSTR pszPath,LPWSTR pszUrl,LPDWORD pcchUrl,DWORD dwReserved)2497c2c66affSColin Finck HRESULT WINAPI UrlCreateFromPathW(LPCWSTR pszPath, LPWSTR pszUrl, LPDWORD pcchUrl, DWORD dwReserved)
2498c2c66affSColin Finck {
2499c2c66affSColin Finck HRESULT ret;
2500c2c66affSColin Finck
2501c2c66affSColin Finck TRACE("(%s, %p, %p, 0x%08x)\n", debugstr_w(pszPath), pszUrl, pcchUrl, dwReserved);
2502c2c66affSColin Finck
2503c2c66affSColin Finck /* Validate arguments */
2504c2c66affSColin Finck if (dwReserved != 0)
2505c2c66affSColin Finck return E_INVALIDARG;
2506c2c66affSColin Finck if (!pszUrl || !pcchUrl)
2507c2c66affSColin Finck return E_INVALIDARG;
2508c2c66affSColin Finck
2509c2c66affSColin Finck ret = URL_CreateFromPath(pszPath, pszUrl, pcchUrl);
2510c2c66affSColin Finck
2511c2c66affSColin Finck if (S_FALSE == ret)
2512c2c66affSColin Finck strcpyW(pszUrl, pszPath);
2513c2c66affSColin Finck
2514c2c66affSColin Finck return ret;
2515c2c66affSColin Finck }
2516c2c66affSColin Finck
2517*f496a5fcSKatayama Hirofumi MZ #ifndef __REACTOS__
2518c2c66affSColin Finck /*************************************************************************
2519c2c66affSColin Finck * SHAutoComplete [SHLWAPI.@]
2520c2c66affSColin Finck *
2521c2c66affSColin Finck * Enable auto-completion for an edit control.
2522c2c66affSColin Finck *
2523c2c66affSColin Finck * PARAMS
2524c2c66affSColin Finck * hwndEdit [I] Handle of control to enable auto-completion for
2525c2c66affSColin Finck * dwFlags [I] SHACF_ flags from "shlwapi.h"
2526c2c66affSColin Finck *
2527c2c66affSColin Finck * RETURNS
2528c2c66affSColin Finck * Success: S_OK. Auto-completion is enabled for the control.
2529c2c66affSColin Finck * Failure: An HRESULT error code indicating the error.
2530c2c66affSColin Finck */
SHAutoComplete(HWND hwndEdit,DWORD dwFlags)2531c2c66affSColin Finck HRESULT WINAPI SHAutoComplete(HWND hwndEdit, DWORD dwFlags)
2532c2c66affSColin Finck {
2533c2c66affSColin Finck FIXME("stub\n");
2534c2c66affSColin Finck return S_FALSE;
2535c2c66affSColin Finck }
2536*f496a5fcSKatayama Hirofumi MZ #endif
2537c2c66affSColin Finck
2538c2c66affSColin Finck /*************************************************************************
2539c2c66affSColin Finck * MLBuildResURLA [SHLWAPI.405]
2540c2c66affSColin Finck *
2541c2c66affSColin Finck * Create a Url pointing to a resource in a module.
2542c2c66affSColin Finck *
2543c2c66affSColin Finck * PARAMS
2544c2c66affSColin Finck * lpszLibName [I] Name of the module containing the resource
2545c2c66affSColin Finck * hMod [I] Callers module handle
2546c2c66affSColin Finck * dwFlags [I] Undocumented flags for loading the module
2547c2c66affSColin Finck * lpszRes [I] Resource name
2548c2c66affSColin Finck * lpszDest [O] Destination for resulting Url
2549c2c66affSColin Finck * dwDestLen [I] Length of lpszDest
2550c2c66affSColin Finck *
2551c2c66affSColin Finck * RETURNS
2552c2c66affSColin Finck * Success: S_OK. lpszDest contains the resource Url.
2553c2c66affSColin Finck * Failure: E_INVALIDARG, if any argument is invalid, or
2554c2c66affSColin Finck * E_FAIL if dwDestLen is too small.
2555c2c66affSColin Finck */
MLBuildResURLA(LPCSTR lpszLibName,HMODULE hMod,DWORD dwFlags,LPCSTR lpszRes,LPSTR lpszDest,DWORD dwDestLen)2556c2c66affSColin Finck HRESULT WINAPI MLBuildResURLA(LPCSTR lpszLibName, HMODULE hMod, DWORD dwFlags,
2557c2c66affSColin Finck LPCSTR lpszRes, LPSTR lpszDest, DWORD dwDestLen)
2558c2c66affSColin Finck {
2559c2c66affSColin Finck WCHAR szLibName[MAX_PATH], szRes[MAX_PATH], szDest[MAX_PATH];
2560c2c66affSColin Finck HRESULT hRet;
2561c2c66affSColin Finck
2562c2c66affSColin Finck if (lpszLibName)
2563c2c66affSColin Finck MultiByteToWideChar(CP_ACP, 0, lpszLibName, -1, szLibName, sizeof(szLibName)/sizeof(WCHAR));
2564c2c66affSColin Finck
2565c2c66affSColin Finck if (lpszRes)
2566c2c66affSColin Finck MultiByteToWideChar(CP_ACP, 0, lpszRes, -1, szRes, sizeof(szRes)/sizeof(WCHAR));
2567c2c66affSColin Finck
2568c2c66affSColin Finck if (dwDestLen > sizeof(szLibName)/sizeof(WCHAR))
2569c2c66affSColin Finck dwDestLen = sizeof(szLibName)/sizeof(WCHAR);
2570c2c66affSColin Finck
2571c2c66affSColin Finck hRet = MLBuildResURLW(lpszLibName ? szLibName : NULL, hMod, dwFlags,
2572c2c66affSColin Finck lpszRes ? szRes : NULL, lpszDest ? szDest : NULL, dwDestLen);
2573c2c66affSColin Finck if (SUCCEEDED(hRet) && lpszDest)
2574c2c66affSColin Finck WideCharToMultiByte(CP_ACP, 0, szDest, -1, lpszDest, dwDestLen, NULL, NULL);
2575c2c66affSColin Finck
2576c2c66affSColin Finck return hRet;
2577c2c66affSColin Finck }
2578c2c66affSColin Finck
2579c2c66affSColin Finck /*************************************************************************
2580c2c66affSColin Finck * MLBuildResURLA [SHLWAPI.406]
2581c2c66affSColin Finck *
2582c2c66affSColin Finck * See MLBuildResURLA.
2583c2c66affSColin Finck */
MLBuildResURLW(LPCWSTR lpszLibName,HMODULE hMod,DWORD dwFlags,LPCWSTR lpszRes,LPWSTR lpszDest,DWORD dwDestLen)2584c2c66affSColin Finck HRESULT WINAPI MLBuildResURLW(LPCWSTR lpszLibName, HMODULE hMod, DWORD dwFlags,
2585c2c66affSColin Finck LPCWSTR lpszRes, LPWSTR lpszDest, DWORD dwDestLen)
2586c2c66affSColin Finck {
2587c2c66affSColin Finck static const WCHAR szRes[] = { 'r','e','s',':','/','/','\0' };
2588c2c66affSColin Finck #define szResLen ((sizeof(szRes) - sizeof(WCHAR))/sizeof(WCHAR))
2589c2c66affSColin Finck HRESULT hRet = E_FAIL;
2590c2c66affSColin Finck
2591c2c66affSColin Finck TRACE("(%s,%p,0x%08x,%s,%p,%d)\n", debugstr_w(lpszLibName), hMod, dwFlags,
2592c2c66affSColin Finck debugstr_w(lpszRes), lpszDest, dwDestLen);
2593c2c66affSColin Finck
2594c2c66affSColin Finck if (!lpszLibName || !hMod || hMod == INVALID_HANDLE_VALUE || !lpszRes ||
2595c2c66affSColin Finck !lpszDest || (dwFlags && dwFlags != 2))
2596c2c66affSColin Finck return E_INVALIDARG;
2597c2c66affSColin Finck
2598c2c66affSColin Finck if (dwDestLen >= szResLen + 1)
2599c2c66affSColin Finck {
2600c2c66affSColin Finck dwDestLen -= (szResLen + 1);
2601c2c66affSColin Finck memcpy(lpszDest, szRes, sizeof(szRes));
2602c2c66affSColin Finck
2603c2c66affSColin Finck hMod = MLLoadLibraryW(lpszLibName, hMod, dwFlags);
2604c2c66affSColin Finck
2605c2c66affSColin Finck if (hMod)
2606c2c66affSColin Finck {
2607c2c66affSColin Finck WCHAR szBuff[MAX_PATH];
2608c2c66affSColin Finck DWORD len;
2609c2c66affSColin Finck
2610c2c66affSColin Finck len = GetModuleFileNameW(hMod, szBuff, sizeof(szBuff)/sizeof(WCHAR));
2611c2c66affSColin Finck if (len && len < sizeof(szBuff)/sizeof(WCHAR))
2612c2c66affSColin Finck {
2613c2c66affSColin Finck DWORD dwPathLen = strlenW(szBuff) + 1;
2614c2c66affSColin Finck
2615c2c66affSColin Finck if (dwDestLen >= dwPathLen)
2616c2c66affSColin Finck {
2617c2c66affSColin Finck DWORD dwResLen;
2618c2c66affSColin Finck
2619c2c66affSColin Finck dwDestLen -= dwPathLen;
2620c2c66affSColin Finck memcpy(lpszDest + szResLen, szBuff, dwPathLen * sizeof(WCHAR));
2621c2c66affSColin Finck
2622c2c66affSColin Finck dwResLen = strlenW(lpszRes) + 1;
2623c2c66affSColin Finck if (dwDestLen >= dwResLen + 1)
2624c2c66affSColin Finck {
2625c2c66affSColin Finck lpszDest[szResLen + dwPathLen-1] = '/';
2626c2c66affSColin Finck memcpy(lpszDest + szResLen + dwPathLen, lpszRes, dwResLen * sizeof(WCHAR));
2627c2c66affSColin Finck hRet = S_OK;
2628c2c66affSColin Finck }
2629c2c66affSColin Finck }
2630c2c66affSColin Finck }
2631c2c66affSColin Finck MLFreeLibrary(hMod);
2632c2c66affSColin Finck }
2633c2c66affSColin Finck }
2634c2c66affSColin Finck return hRet;
2635c2c66affSColin Finck }
2636c2c66affSColin Finck
2637c2c66affSColin Finck /***********************************************************************
2638c2c66affSColin Finck * UrlFixupW [SHLWAPI.462]
2639c2c66affSColin Finck *
2640c2c66affSColin Finck * Checks the scheme part of a URL and attempts to correct misspellings.
2641c2c66affSColin Finck *
2642c2c66affSColin Finck * PARAMS
2643c2c66affSColin Finck * lpszUrl [I] Pointer to the URL to be corrected
2644c2c66affSColin Finck * lpszTranslatedUrl [O] Pointer to a buffer to store corrected URL
2645c2c66affSColin Finck * dwMaxChars [I] Maximum size of corrected URL
2646c2c66affSColin Finck *
2647c2c66affSColin Finck * RETURNS
2648c2c66affSColin Finck * success: S_OK if URL corrected or already correct
2649c2c66affSColin Finck * failure: S_FALSE if unable to correct / COM error code if other error
2650c2c66affSColin Finck *
2651c2c66affSColin Finck */
UrlFixupW(LPCWSTR url,LPWSTR translatedUrl,DWORD maxChars)2652c2c66affSColin Finck HRESULT WINAPI UrlFixupW(LPCWSTR url, LPWSTR translatedUrl, DWORD maxChars)
2653c2c66affSColin Finck {
2654c2c66affSColin Finck DWORD srcLen;
2655c2c66affSColin Finck
2656c2c66affSColin Finck FIXME("(%s,%p,%d) STUB\n", debugstr_w(url), translatedUrl, maxChars);
2657c2c66affSColin Finck
2658c2c66affSColin Finck if (!url)
2659c2c66affSColin Finck return E_FAIL;
2660c2c66affSColin Finck
2661c2c66affSColin Finck srcLen = lstrlenW(url) + 1;
2662c2c66affSColin Finck
2663c2c66affSColin Finck /* For now just copy the URL directly */
2664c2c66affSColin Finck lstrcpynW(translatedUrl, url, (maxChars < srcLen) ? maxChars : srcLen);
2665c2c66affSColin Finck
2666c2c66affSColin Finck return S_OK;
2667c2c66affSColin Finck }
2668c2c66affSColin Finck
2669c2c66affSColin Finck /*************************************************************************
2670c2c66affSColin Finck * IsInternetESCEnabled [SHLWAPI.@]
2671c2c66affSColin Finck */
IsInternetESCEnabled(void)2672c2c66affSColin Finck BOOL WINAPI IsInternetESCEnabled(void)
2673c2c66affSColin Finck {
2674c2c66affSColin Finck FIXME(": stub\n");
2675c2c66affSColin Finck return FALSE;
2676c2c66affSColin Finck }
2677