crypt32: NULL ptr could leak into function (Coverity).
[wine] / dlls / mshtml / htmllocation.c
1 /*
2  * Copyright 2008 Jacek Caban for CodeWeavers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #include <stdarg.h>
20
21 #define COBJMACROS
22
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winuser.h"
26 #include "winreg.h"
27 #include "ole2.h"
28 #include "wininet.h"
29 #include "shlwapi.h"
30
31 #include "wine/debug.h"
32
33 #include "mshtml_private.h"
34 #include "resource.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
37
38 static HRESULT get_url(HTMLLocation *This, const WCHAR **ret)
39 {
40     if(!This->window || !This->window->url) {
41         FIXME("No current URL\n");
42         return E_NOTIMPL;
43     }
44
45     *ret = This->window->url;
46     return S_OK;
47 }
48
49 static HRESULT get_url_components(HTMLLocation *This, URL_COMPONENTSW *url)
50 {
51     const WCHAR *doc_url;
52     HRESULT hres;
53
54     hres = get_url(This, &doc_url);
55     if(FAILED(hres))
56         return hres;
57
58     if(!InternetCrackUrlW(doc_url, 0, 0, url)) {
59         FIXME("InternetCrackUrlW failed: 0x%08x\n", GetLastError());
60         SetLastError(0);
61         return E_FAIL;
62     }
63
64     return S_OK;
65 }
66
67 #define HTMLLOCATION_THIS(iface) DEFINE_THIS(HTMLLocation, HTMLLocation, iface)
68
69 static HRESULT WINAPI HTMLLocation_QueryInterface(IHTMLLocation *iface, REFIID riid, void **ppv)
70 {
71     HTMLLocation *This = HTMLLOCATION_THIS(iface);
72
73     *ppv = NULL;
74
75     if(IsEqualGUID(&IID_IUnknown, riid)) {
76         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
77         *ppv = HTMLLOCATION(This);
78     }else if(IsEqualGUID(&IID_IHTMLLocation, riid)) {
79         TRACE("(%p)->(IID_IHTMLLocation %p)\n", This, ppv);
80         *ppv = HTMLLOCATION(This);
81     }else if(dispex_query_interface(&This->dispex, riid, ppv)) {
82         return *ppv ? S_OK : E_NOINTERFACE;
83     }
84
85     if(*ppv) {
86         IUnknown_AddRef((IUnknown*)*ppv);
87         return S_OK;
88     }
89
90     WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
91     return E_NOINTERFACE;
92 }
93
94 static ULONG WINAPI HTMLLocation_AddRef(IHTMLLocation *iface)
95 {
96     HTMLLocation *This = HTMLLOCATION_THIS(iface);
97     LONG ref = InterlockedIncrement(&This->ref);
98
99     TRACE("(%p) ref=%d\n", This, ref);
100
101     return ref;
102 }
103
104 static ULONG WINAPI HTMLLocation_Release(IHTMLLocation *iface)
105 {
106     HTMLLocation *This = HTMLLOCATION_THIS(iface);
107     LONG ref = InterlockedDecrement(&This->ref);
108
109     TRACE("(%p) ref=%d\n", This, ref);
110
111     if(!ref) {
112         if(This->window)
113             This->window->location = NULL;
114         release_dispex(&This->dispex);
115         heap_free(This);
116     }
117
118     return ref;
119 }
120
121 static HRESULT WINAPI HTMLLocation_GetTypeInfoCount(IHTMLLocation *iface, UINT *pctinfo)
122 {
123     HTMLLocation *This = HTMLLOCATION_THIS(iface);
124     return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
125 }
126
127 static HRESULT WINAPI HTMLLocation_GetTypeInfo(IHTMLLocation *iface, UINT iTInfo,
128                                               LCID lcid, ITypeInfo **ppTInfo)
129 {
130     HTMLLocation *This = HTMLLOCATION_THIS(iface);
131     return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
132 }
133
134 static HRESULT WINAPI HTMLLocation_GetIDsOfNames(IHTMLLocation *iface, REFIID riid,
135                                                 LPOLESTR *rgszNames, UINT cNames,
136                                                 LCID lcid, DISPID *rgDispId)
137 {
138     HTMLLocation *This = HTMLLOCATION_THIS(iface);
139     return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, riid, rgszNames, cNames,
140             lcid, rgDispId);
141 }
142
143 static HRESULT WINAPI HTMLLocation_Invoke(IHTMLLocation *iface, DISPID dispIdMember,
144                             REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
145                             VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
146 {
147     HTMLLocation *This = HTMLLOCATION_THIS(iface);
148     return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface, dispIdMember, riid, lcid,
149             wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
150 }
151
152 static HRESULT WINAPI HTMLLocation_put_href(IHTMLLocation *iface, BSTR v)
153 {
154     HTMLLocation *This = HTMLLOCATION_THIS(iface);
155
156     TRACE("(%p)->(%s)\n", This, debugstr_w(v));
157
158     if(!This->window) {
159         FIXME("No window available\n");
160         return E_FAIL;
161     }
162
163     return navigate_url(This->window, v, This->window->url);
164 }
165
166 static HRESULT WINAPI HTMLLocation_get_href(IHTMLLocation *iface, BSTR *p)
167 {
168     HTMLLocation *This = HTMLLOCATION_THIS(iface);
169     URL_COMPONENTSW url = {sizeof(URL_COMPONENTSW)};
170     WCHAR *buf = NULL, *url_path = NULL;
171     HRESULT hres, ret;
172     DWORD len = 0;
173     int i;
174
175     TRACE("(%p)->(%p)\n", This, p);
176
177     if(!p)
178         return E_POINTER;
179
180     url.dwSchemeLength = 1;
181     url.dwHostNameLength = 1;
182     url.dwUrlPathLength = 1;
183     url.dwExtraInfoLength = 1;
184     hres = get_url_components(This, &url);
185     if(FAILED(hres))
186         return hres;
187
188     switch(url.nScheme) {
189     case INTERNET_SCHEME_FILE:
190         {
191             /* prepend a slash */
192             url_path = HeapAlloc(GetProcessHeap(), 0, (url.dwUrlPathLength + 1) * sizeof(WCHAR));
193             if(!url_path)
194                 return E_OUTOFMEMORY;
195             url_path[0] = '/';
196             memcpy(url_path + 1, url.lpszUrlPath, url.dwUrlPathLength * sizeof(WCHAR));
197             url.lpszUrlPath = url_path;
198             url.dwUrlPathLength = url.dwUrlPathLength + 1;
199         }
200         break;
201
202     case INTERNET_SCHEME_HTTP:
203     case INTERNET_SCHEME_HTTPS:
204     case INTERNET_SCHEME_FTP:
205         if(!url.dwUrlPathLength) {
206             /* add a slash if it's blank */
207             url_path = url.lpszUrlPath = HeapAlloc(GetProcessHeap(), 0, 1 * sizeof(WCHAR));
208             if(!url.lpszUrlPath)
209                 return E_OUTOFMEMORY;
210             url.lpszUrlPath[0] = '/';
211             url.dwUrlPathLength = 1;
212         }
213         break;
214
215     default:
216         break;
217     }
218
219     /* replace \ with / */
220     for(i = 0; i < url.dwUrlPathLength; ++i)
221         if(url.lpszUrlPath[i] == '\\')
222             url.lpszUrlPath[i] = '/';
223
224     if(InternetCreateUrlW(&url, ICU_ESCAPE, NULL, &len)) {
225         FIXME("InternetCreateUrl succeeded with NULL buffer?\n");
226         ret = E_FAIL;
227         goto cleanup;
228     }
229
230     if(GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
231         FIXME("InternetCreateUrl failed with error: %08x\n", GetLastError());
232         SetLastError(0);
233         ret = E_FAIL;
234         goto cleanup;
235     }
236     SetLastError(0);
237
238     buf = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
239     if(!buf) {
240         ret = E_OUTOFMEMORY;
241         goto cleanup;
242     }
243
244     if(!InternetCreateUrlW(&url, ICU_ESCAPE, buf, &len)) {
245         FIXME("InternetCreateUrl failed with error: %08x\n", GetLastError());
246         SetLastError(0);
247         ret = E_FAIL;
248         goto cleanup;
249     }
250
251     *p = SysAllocStringLen(buf, len);
252     if(!*p) {
253         ret = E_OUTOFMEMORY;
254         goto cleanup;
255     }
256
257     ret = S_OK;
258
259 cleanup:
260     HeapFree(GetProcessHeap(), 0, buf);
261     HeapFree(GetProcessHeap(), 0, url_path);
262
263     return ret;
264 }
265
266 static HRESULT WINAPI HTMLLocation_put_protocol(IHTMLLocation *iface, BSTR v)
267 {
268     HTMLLocation *This = HTMLLOCATION_THIS(iface);
269     FIXME("(%p)->(%s)\n", This, debugstr_w(v));
270     return E_NOTIMPL;
271 }
272
273 static HRESULT WINAPI HTMLLocation_get_protocol(IHTMLLocation *iface, BSTR *p)
274 {
275     HTMLLocation *This = HTMLLOCATION_THIS(iface);
276     URL_COMPONENTSW url = {sizeof(URL_COMPONENTSW)};
277     HRESULT hres;
278
279     TRACE("(%p)->(%p)\n", This, p);
280
281     if(!p)
282         return E_POINTER;
283
284     url.dwSchemeLength = 1;
285     hres = get_url_components(This, &url);
286     if(FAILED(hres))
287         return hres;
288
289     if(!url.dwSchemeLength) {
290         FIXME("Unexpected blank protocol\n");
291         return E_NOTIMPL;
292     }else {
293         WCHAR buf[url.dwSchemeLength + 1];
294         memcpy(buf, url.lpszScheme, url.dwSchemeLength * sizeof(WCHAR));
295         buf[url.dwSchemeLength] = ':';
296         *p = SysAllocStringLen(buf, url.dwSchemeLength + 1);
297     }
298     if(!*p)
299         return E_OUTOFMEMORY;
300     return S_OK;
301 }
302
303 static HRESULT WINAPI HTMLLocation_put_host(IHTMLLocation *iface, BSTR v)
304 {
305     HTMLLocation *This = HTMLLOCATION_THIS(iface);
306     FIXME("(%p)->(%s)\n", This, debugstr_w(v));
307     return E_NOTIMPL;
308 }
309
310 static HRESULT WINAPI HTMLLocation_get_host(IHTMLLocation *iface, BSTR *p)
311 {
312     HTMLLocation *This = HTMLLOCATION_THIS(iface);
313     URL_COMPONENTSW url = {sizeof(URL_COMPONENTSW)};
314     HRESULT hres;
315
316     TRACE("(%p)->(%p)\n", This, p);
317
318     if(!p)
319         return E_POINTER;
320
321     url.dwHostNameLength = 1;
322     hres = get_url_components(This, &url);
323     if(FAILED(hres))
324         return hres;
325
326     if(!url.dwHostNameLength){
327         *p = NULL;
328         return S_OK;
329     }
330
331     if(url.nPort) {
332         /* <hostname>:<port> */
333         const WCHAR format[] = {'%','d',0};
334         DWORD len = url.dwHostNameLength + 1 + 5 + 1;
335         WCHAR buf[len];
336
337         memcpy(buf, url.lpszHostName, url.dwHostNameLength * sizeof(WCHAR));
338         buf[url.dwHostNameLength] = ':';
339         snprintfW(buf + url.dwHostNameLength + 1, 6, format, url.nPort);
340         *p = SysAllocString(buf);
341     }else
342         *p = SysAllocStringLen(url.lpszHostName, url.dwHostNameLength);
343
344     if(!*p)
345         return E_OUTOFMEMORY;
346     return S_OK;
347 }
348
349 static HRESULT WINAPI HTMLLocation_put_hostname(IHTMLLocation *iface, BSTR v)
350 {
351     HTMLLocation *This = HTMLLOCATION_THIS(iface);
352     FIXME("(%p)->(%s)\n", This, debugstr_w(v));
353     return E_NOTIMPL;
354 }
355
356 static HRESULT WINAPI HTMLLocation_get_hostname(IHTMLLocation *iface, BSTR *p)
357 {
358     HTMLLocation *This = HTMLLOCATION_THIS(iface);
359     URL_COMPONENTSW url = {sizeof(URL_COMPONENTSW)};
360     HRESULT hres;
361
362     TRACE("(%p)->(%p)\n", This, p);
363
364     if(!p)
365         return E_POINTER;
366
367     url.dwHostNameLength = 1;
368     hres = get_url_components(This, &url);
369     if(FAILED(hres))
370         return hres;
371
372     if(!url.dwHostNameLength){
373         *p = NULL;
374         return S_OK;
375     }
376
377     *p = SysAllocStringLen(url.lpszHostName, url.dwHostNameLength);
378     if(!*p)
379         return E_OUTOFMEMORY;
380     return S_OK;
381 }
382
383 static HRESULT WINAPI HTMLLocation_put_port(IHTMLLocation *iface, BSTR v)
384 {
385     HTMLLocation *This = HTMLLOCATION_THIS(iface);
386     FIXME("(%p)->(%s)\n", This, debugstr_w(v));
387     return E_NOTIMPL;
388 }
389
390 static HRESULT WINAPI HTMLLocation_get_port(IHTMLLocation *iface, BSTR *p)
391 {
392     HTMLLocation *This = HTMLLOCATION_THIS(iface);
393     URL_COMPONENTSW url = {sizeof(URL_COMPONENTSW)};
394     HRESULT hres;
395
396     TRACE("(%p)->(%p)\n", This, p);
397
398     if(!p)
399         return E_POINTER;
400
401     hres = get_url_components(This, &url);
402     if(FAILED(hres))
403         return hres;
404
405     if(url.nPort) {
406         const WCHAR format[] = {'%','d',0};
407         WCHAR buf[6];
408         snprintfW(buf, 6, format, url.nPort);
409         *p = SysAllocString(buf);
410     }else {
411         const WCHAR empty[] = {0};
412         *p = SysAllocString(empty);
413     }
414
415     if(!*p)
416         return E_OUTOFMEMORY;
417     return S_OK;
418 }
419
420 static HRESULT WINAPI HTMLLocation_put_pathname(IHTMLLocation *iface, BSTR v)
421 {
422     HTMLLocation *This = HTMLLOCATION_THIS(iface);
423     FIXME("(%p)->(%s)\n", This, debugstr_w(v));
424     return E_NOTIMPL;
425 }
426
427 static HRESULT WINAPI HTMLLocation_get_pathname(IHTMLLocation *iface, BSTR *p)
428 {
429     HTMLLocation *This = HTMLLOCATION_THIS(iface);
430     URL_COMPONENTSW url = {sizeof(URL_COMPONENTSW)};
431     HRESULT hres;
432
433     TRACE("(%p)->(%p)\n", This, p);
434
435     if(!p)
436         return E_POINTER;
437
438     url.dwUrlPathLength = 1;
439     url.dwExtraInfoLength = 1;
440     hres = get_url_components(This, &url);
441     if(FAILED(hres))
442         return hres;
443
444     if(url.dwUrlPathLength && url.lpszUrlPath[0] == '/')
445         *p = SysAllocStringLen(url.lpszUrlPath + 1, url.dwUrlPathLength - 1);
446     else
447         *p = SysAllocStringLen(url.lpszUrlPath, url.dwUrlPathLength);
448
449     if(!*p)
450         return E_OUTOFMEMORY;
451     return S_OK;
452 }
453
454 static HRESULT WINAPI HTMLLocation_put_search(IHTMLLocation *iface, BSTR v)
455 {
456     HTMLLocation *This = HTMLLOCATION_THIS(iface);
457     FIXME("(%p)->(%s)\n", This, debugstr_w(v));
458     return E_NOTIMPL;
459 }
460
461 static HRESULT WINAPI HTMLLocation_get_search(IHTMLLocation *iface, BSTR *p)
462 {
463     HTMLLocation *This = HTMLLOCATION_THIS(iface);
464     URL_COMPONENTSW url = {sizeof(URL_COMPONENTSW)};
465     HRESULT hres;
466     const WCHAR hash[] = {'#',0};
467
468     TRACE("(%p)->(%p)\n", This, p);
469
470     if(!p)
471         return E_POINTER;
472
473     url.dwExtraInfoLength = 1;
474     hres = get_url_components(This, &url);
475     if(FAILED(hres))
476         return hres;
477
478     if(!url.dwExtraInfoLength){
479         *p = NULL;
480         return S_OK;
481     }
482
483     url.dwExtraInfoLength = strcspnW(url.lpszExtraInfo, hash);
484
485     *p = SysAllocStringLen(url.lpszExtraInfo, url.dwExtraInfoLength);
486
487     if(!*p)
488         return E_OUTOFMEMORY;
489     return S_OK;
490 }
491
492 static HRESULT WINAPI HTMLLocation_put_hash(IHTMLLocation *iface, BSTR v)
493 {
494     HTMLLocation *This = HTMLLOCATION_THIS(iface);
495     FIXME("(%p)->(%s)\n", This, debugstr_w(v));
496     return E_NOTIMPL;
497 }
498
499 static HRESULT WINAPI HTMLLocation_get_hash(IHTMLLocation *iface, BSTR *p)
500 {
501     HTMLLocation *This = HTMLLOCATION_THIS(iface);
502     URL_COMPONENTSW url = {sizeof(URL_COMPONENTSW)};
503     const WCHAR hash[] = {'#',0};
504     DWORD hash_pos = 0;
505     HRESULT hres;
506
507     TRACE("(%p)->(%p)\n", This, p);
508
509     if(!p)
510         return E_POINTER;
511
512     url.dwExtraInfoLength = 1;
513     hres = get_url_components(This, &url);
514     if(FAILED(hres))
515         return hres;
516
517     if(!url.dwExtraInfoLength){
518         *p = NULL;
519         return S_OK;
520     }
521
522     hash_pos = strcspnW(url.lpszExtraInfo, hash);
523     url.dwExtraInfoLength -= hash_pos;
524
525     *p = SysAllocStringLen(url.lpszExtraInfo + hash_pos, url.dwExtraInfoLength);
526
527     if(!*p)
528         return E_OUTOFMEMORY;
529     return S_OK;
530 }
531
532 static HRESULT WINAPI HTMLLocation_reload(IHTMLLocation *iface, VARIANT_BOOL flag)
533 {
534     HTMLLocation *This = HTMLLOCATION_THIS(iface);
535     FIXME("(%p)->(%x)\n", This, flag);
536     return E_NOTIMPL;
537 }
538
539 static HRESULT WINAPI HTMLLocation_replace(IHTMLLocation *iface, BSTR bstr)
540 {
541     HTMLLocation *This = HTMLLOCATION_THIS(iface);
542     FIXME("(%p)->(%s)\n", This, debugstr_w(bstr));
543     return E_NOTIMPL;
544 }
545
546 static HRESULT WINAPI HTMLLocation_assign(IHTMLLocation *iface, BSTR bstr)
547 {
548     HTMLLocation *This = HTMLLOCATION_THIS(iface);
549     FIXME("(%p)->(%s)\n", This, debugstr_w(bstr));
550     return E_NOTIMPL;
551 }
552
553 static HRESULT WINAPI HTMLLocation_toString(IHTMLLocation *iface, BSTR *String)
554 {
555     HTMLLocation *This = HTMLLOCATION_THIS(iface);
556     FIXME("(%p)->(%p)\n", This, String);
557     return E_NOTIMPL;
558 }
559
560 #undef HTMLLOCATION_THIS
561
562 static const IHTMLLocationVtbl HTMLLocationVtbl = {
563     HTMLLocation_QueryInterface,
564     HTMLLocation_AddRef,
565     HTMLLocation_Release,
566     HTMLLocation_GetTypeInfoCount,
567     HTMLLocation_GetTypeInfo,
568     HTMLLocation_GetIDsOfNames,
569     HTMLLocation_Invoke,
570     HTMLLocation_put_href,
571     HTMLLocation_get_href,
572     HTMLLocation_put_protocol,
573     HTMLLocation_get_protocol,
574     HTMLLocation_put_host,
575     HTMLLocation_get_host,
576     HTMLLocation_put_hostname,
577     HTMLLocation_get_hostname,
578     HTMLLocation_put_port,
579     HTMLLocation_get_port,
580     HTMLLocation_put_pathname,
581     HTMLLocation_get_pathname,
582     HTMLLocation_put_search,
583     HTMLLocation_get_search,
584     HTMLLocation_put_hash,
585     HTMLLocation_get_hash,
586     HTMLLocation_reload,
587     HTMLLocation_replace,
588     HTMLLocation_assign,
589     HTMLLocation_toString
590 };
591
592 static const tid_t HTMLLocation_iface_tids[] = {
593     IHTMLLocation_tid,
594     0
595 };
596 static dispex_static_data_t HTMLLocation_dispex = {
597     NULL,
598     DispHTMLLocation_tid,
599     NULL,
600     HTMLLocation_iface_tids
601 };
602
603
604 HRESULT HTMLLocation_Create(HTMLWindow *window, HTMLLocation **ret)
605 {
606     HTMLLocation *location;
607
608     location = heap_alloc(sizeof(*location));
609     if(!location)
610         return E_OUTOFMEMORY;
611
612     location->lpHTMLLocationVtbl = &HTMLLocationVtbl;
613     location->ref = 1;
614     location->window = window;
615
616     init_dispex(&location->dispex, (IUnknown*)HTMLLOCATION(location),  &HTMLLocation_dispex);
617
618     *ret = location;
619     return S_OK;
620 }