oleaut32: non-dual dispinterfaces should be marshaled via IDispatch.
[wine] / dlls / mshtml / navigate.c
index ecd8333..bcafb6c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2006 Jacek Caban for CodeWeavers
+ * Copyright 2006-2007 Jacek Caban for CodeWeavers
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -37,6 +37,7 @@
 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
 
 #define CONTENT_LENGTH "Content-Length"
+#define UTF16_STR "utf-16"
 
 #define NSINSTREAM(x) ((nsIInputStream*) &(x)->lpInputStreamVtbl)
 
@@ -71,7 +72,7 @@ static nsrefcnt NSAPI nsInputStream_AddRef(nsIInputStream *iface)
     nsProtocolStream *This = NSINSTREAM_THIS(iface);
     LONG ref = InterlockedIncrement(&This->ref);
 
-    TRACE("(%p) ref=%ld\n", This, ref);
+    TRACE("(%p) ref=%d\n", This, ref);
 
     return ref;
 }
@@ -82,7 +83,7 @@ static nsrefcnt NSAPI nsInputStream_Release(nsIInputStream *iface)
     nsProtocolStream *This = NSINSTREAM_THIS(iface);
     LONG ref = InterlockedDecrement(&This->ref);
 
-    TRACE("(%p) ref=%ld\n", This, ref);
+    TRACE("(%p) ref=%d\n", This, ref);
 
     if(!ref)
         mshtml_free(This);
@@ -109,7 +110,7 @@ static nsresult NSAPI nsInputStream_Read(nsIInputStream *iface, char *aBuf, PRUi
 {
     nsProtocolStream *This = NSINSTREAM_THIS(iface);
 
-    TRACE("(%p)->(%p %ld %p)\n", This, aBuf, aCount, _retval);
+    TRACE("(%p)->(%p %d %p)\n", This, aBuf, aCount, _retval);
 
     /* Gecko always calls Read with big enough buffer */
     if(aCount < This->buf_size)
@@ -131,7 +132,7 @@ static nsresult NSAPI nsInputStream_ReadSegments(nsIInputStream *iface,
     PRUint32 written = 0;
     nsresult nsres;
 
-    FIXME("(%p)->(%p %p %ld %p)\n", This, aWriter, aClousure, aCount, _retval);
+    TRACE("(%p)->(%p %p %d %p)\n", This, aWriter, aClousure, aCount, _retval);
 
     if(!This->buf_size)
         return S_OK;
@@ -141,12 +142,13 @@ static nsresult NSAPI nsInputStream_ReadSegments(nsIInputStream *iface,
 
     nsres = aWriter(NSINSTREAM(This), aClousure, This->buf, 0, This->buf_size, &written);
     if(NS_FAILED(nsres))
-        FIXME("aWritter failed: %08lx\n", nsres);
-    if(written != This->buf_size)
-        FIXME("written != buf_size\n");
+        TRACE("aWritter failed: %08x\n", nsres);
+    else if(written != This->buf_size)
+        FIXME("written %d != buf_size %d\n", written, This->buf_size);
 
     This->buf_size -= written; 
 
+    *_retval = written;
     return nsres;
 }
 
@@ -170,7 +172,7 @@ static const nsIInputStreamVtbl nsInputStreamVtbl = {
     nsInputStream_IsNonBlocking
 };
 
-static nsProtocolStream *create_nsprotocol_stream(IStream *stream)
+static nsProtocolStream *create_nsprotocol_stream(void)
 {
     nsProtocolStream *ret = mshtml_alloc(sizeof(nsProtocolStream));
 
@@ -181,6 +183,71 @@ static nsProtocolStream *create_nsprotocol_stream(IStream *stream)
     return ret;
 }
 
+static HRESULT read_stream_data(BSCallback *This, IStream *stream)
+{
+    nsresult nsres;
+    HRESULT hres;
+
+    if(!This->nslistener) {
+        BYTE buf[1024];
+        DWORD read;
+
+        do {
+            read = 0;
+            hres = IStream_Read(stream, buf, sizeof(buf), &read);
+        }while(hres == S_OK && read);
+
+        return S_OK;
+    }
+
+    if(!This->nsstream)
+        This->nsstream = create_nsprotocol_stream();
+
+    do {
+        hres = IStream_Read(stream, This->nsstream->buf, sizeof(This->nsstream->buf),
+                &This->nsstream->buf_size);
+        if(!This->nsstream->buf_size)
+            break;
+
+        if(!This->readed && This->nsstream->buf_size >= 2 && *(WORD*)This->nsstream->buf == 0xfeff) {
+                This->nschannel->charset = mshtml_alloc(sizeof(UTF16_STR));
+                memcpy(This->nschannel->charset, UTF16_STR, sizeof(UTF16_STR));
+        }
+
+        if(!This->readed) {
+            nsres = nsIStreamListener_OnStartRequest(This->nslistener,
+                    (nsIRequest*)NSCHANNEL(This->nschannel), This->nscontext);
+            if(NS_FAILED(nsres))
+                FIXME("OnStartRequest failed: %08x\n", nsres);
+        }
+
+        This->readed += This->nsstream->buf_size;
+
+        nsres = nsIStreamListener_OnDataAvailable(This->nslistener,
+                (nsIRequest*)NSCHANNEL(This->nschannel), This->nscontext,
+                NSINSTREAM(This->nsstream), This->readed-This->nsstream->buf_size,
+                This->nsstream->buf_size);
+        if(NS_FAILED(nsres))
+            ERR("OnDataAvailable failed: %08x\n", nsres);
+
+        if(This->nsstream->buf_size)
+            FIXME("buffer is not empty!\n");
+    }while(hres == S_OK);
+
+    return S_OK;
+}
+
+static void add_nsrequest(BSCallback *This)
+{
+    if(This->nschannel && This->nschannel->load_group) {
+        nsresult nsres = nsILoadGroup_AddRequest(This->nschannel->load_group,
+                (nsIRequest*)NSCHANNEL(This->nschannel), This->nscontext);
+
+        if(NS_FAILED(nsres))
+            ERR("AddRequest failed:%08x\n", nsres);
+    }
+}
+
 #define STATUSCLB_THIS(iface) DEFINE_THIS(BSCallback, BindStatusCallback, iface)
 
 static HRESULT WINAPI BindStatusCallback_QueryInterface(IBindStatusCallback *iface,
@@ -223,7 +290,7 @@ static ULONG WINAPI BindStatusCallback_AddRef(IBindStatusCallback *iface)
     BSCallback *This = STATUSCLB_THIS(iface);
     LONG ref = InterlockedIncrement(&This->ref);
 
-    TRACE("(%p) ref = %ld\n", This, ref);
+    TRACE("(%p) ref = %d\n", This, ref);
 
     return ref;
 }
@@ -233,7 +300,7 @@ static ULONG WINAPI BindStatusCallback_Release(IBindStatusCallback *iface)
     BSCallback *This = STATUSCLB_THIS(iface);
     LONG ref = InterlockedDecrement(&This->ref);
 
-    TRACE("(%p) ref = %ld\n", This, ref);
+    TRACE("(%p) ref = %d\n", This, ref);
 
     if(!ref) {
         if(This->post_data)
@@ -246,6 +313,10 @@ static ULONG WINAPI BindStatusCallback_Release(IBindStatusCallback *iface)
             nsISupports_Release(This->nscontext);
         if(This->nsstream)
             nsIInputStream_Release(NSINSTREAM(This->nsstream));
+        if(This->mon)
+            IMoniker_Release(This->mon);
+        if(This->binding)
+            IBinding_Release(This->binding);
         mshtml_free(This->headers);
         mshtml_free(This);
     }
@@ -257,7 +328,14 @@ static HRESULT WINAPI BindStatusCallback_OnStartBinding(IBindStatusCallback *ifa
         DWORD dwReserved, IBinding *pbind)
 {
     BSCallback *This = STATUSCLB_THIS(iface);
-    FIXME("(%p)->(%ld %p)\n", This, dwReserved, pbind);
+
+    TRACE("(%p)->(%d %p)\n", This, dwReserved, pbind);
+
+    IBinding_AddRef(pbind);
+    This->binding = pbind;
+
+    add_nsrequest(This);
+
     return S_OK;
 }
 
@@ -271,7 +349,7 @@ static HRESULT WINAPI BindStatusCallback_GetPriority(IBindStatusCallback *iface,
 static HRESULT WINAPI BindStatusCallback_OnLowResource(IBindStatusCallback *iface, DWORD reserved)
 {
     BSCallback *This = STATUSCLB_THIS(iface);
-    FIXME("(%p)->(%ld)\n", This, reserved);
+    FIXME("(%p)->(%d)\n", This, reserved);
     return E_NOTIMPL;
 }
 
@@ -280,7 +358,7 @@ static HRESULT WINAPI BindStatusCallback_OnProgress(IBindStatusCallback *iface,
 {
     BSCallback *This = STATUSCLB_THIS(iface);
 
-    TRACE("%p)->(%lu %lu %lu %s)\n", This, ulProgress, ulProgressMax, ulStatusCode,
+    TRACE("%p)->(%u %u %u %s)\n", This, ulProgress, ulProgressMax, ulStatusCode,
             debugstr_w(szStatusText));
 
     switch(ulStatusCode) {
@@ -305,12 +383,41 @@ static HRESULT WINAPI BindStatusCallback_OnStopBinding(IBindStatusCallback *ifac
 {
     BSCallback *This = STATUSCLB_THIS(iface);
 
-    TRACE("(%p)->(%08lx %s)\n", This, hresult, debugstr_w(szError));
+    TRACE("(%p)->(%08x %s)\n", This, hresult, debugstr_w(szError));
 
-    if(This->nslistener)
+    if(This->binding) {
+        IBinding_Release(This->binding);
+        This->binding = NULL;
+    }
+
+    if(This->nslistener) {
         nsIStreamListener_OnStopRequest(This->nslistener, (nsIRequest*)NSCHANNEL(This->nschannel),
                 This->nscontext, NS_OK);
 
+        if(This->nschannel->load_group) {
+            nsresult nsres;
+
+            nsres = nsILoadGroup_RemoveRequest(This->nschannel->load_group,
+                    (nsIRequest*)NSCHANNEL(This->nschannel), NULL, NS_OK);
+            if(NS_FAILED(nsres))
+                ERR("RemoveRequest failed: %08x\n", nsres);
+        }
+    }
+
+    if(This->doc) {
+        task_t *task = mshtml_alloc(sizeof(task_t));
+
+        task->doc = This->doc;
+        task->task_id = TASK_PARSECOMPLETE;
+        task->next = NULL;
+
+        /*
+         * This should be done in the worker thread that parses HTML,
+         * but we don't have such thread (Gecko parses HTML for us).
+         */
+        push_task(task);
+    }
+
     return S_OK;
 }
 
@@ -328,9 +435,9 @@ static HRESULT WINAPI BindStatusCallback_GetBindInfo(IBindStatusCallback *iface,
     memset(pbindinfo, 0, size);
     pbindinfo->cbSize = size;
 
-    pbindinfo->cbStgmedData = This->post_data_len;
+    pbindinfo->cbstgmedData = This->post_data_len;
     pbindinfo->dwCodePage = CP_UTF8;
-    pbindinfo->dwOptions = 0x00020000;
+    pbindinfo->dwOptions = 0x80000;
 
     if(This->post_data) {
         pbindinfo->dwBindVerb = BINDVERB_POST;
@@ -348,40 +455,10 @@ static HRESULT WINAPI BindStatusCallback_OnDataAvailable(IBindStatusCallback *if
         DWORD grfBSCF, DWORD dwSize, FORMATETC *pformatetc, STGMEDIUM *pstgmed)
 {
     BSCallback *This = STATUSCLB_THIS(iface);
-    nsresult nsres;
-    HRESULT hres;
 
-    TRACE("(%p)->(%08lx %ld %p %p)\n", This, grfBSCF, dwSize, pformatetc, pstgmed);
-
-    if(This->nslistener) {
-        if(!This->nsstream) {
-            This->nsstream = create_nsprotocol_stream(pstgmed->u.pstm);
-
-            nsres = nsIStreamListener_OnStartRequest(This->nslistener,
-                    (nsIRequest*)NSCHANNEL(This->nschannel), This->nscontext);
-            if(NS_FAILED(nsres))
-                FIXME("OnStartRequest failed: %08lx\n", nsres);
-        }
-
-        do {
-            hres = IStream_Read(pstgmed->u.pstm, This->nsstream->buf, sizeof(This->nsstream->buf),
-                                &This->nsstream->buf_size);
-            if(This->nsstream->buf_size) {
-                nsres = nsIStreamListener_OnDataAvailable(This->nslistener,
-                        (nsIRequest*)NSCHANNEL(This->nschannel), This->nscontext,
-                        NSINSTREAM(This->nsstream), 0 /* FIXME */, dwSize);
-                if(NS_FAILED(nsres))
-                    FIXME("OnDataAvailable failed: %08lx\n", nsres);
-
-                if(This->nsstream->buf_size)
-                    FIXME("buffer is not empty!\n");
-            }else {
-                break;
-            }
-        }while(hres == S_OK);
-    }
+    TRACE("(%p)->(%08x %d %p %p)\n", This, grfBSCF, dwSize, pformatetc, pstgmed);
 
-    return S_OK;
+    return read_stream_data(This, pstgmed->u.pstm);
 }
 
 static HRESULT WINAPI BindStatusCallback_OnObjectAvailable(IBindStatusCallback *iface,
@@ -435,7 +512,7 @@ static HRESULT WINAPI HttpNegotiate_BeginningTransaction(IHttpNegotiate2 *iface,
     BSCallback *This = HTTPNEG_THIS(iface);
     DWORD size;
 
-    TRACE("(%p)->(%s %s %ld %p)\n", This, debugstr_w(szURL), debugstr_w(szHeaders),
+    TRACE("(%p)->(%s %s %d %p)\n", This, debugstr_w(szURL), debugstr_w(szHeaders),
           dwReserved, pszAdditionalHeaders);
 
     if(!This->headers) {
@@ -454,7 +531,7 @@ static HRESULT WINAPI HttpNegotiate_OnResponse(IHttpNegotiate2 *iface, DWORD dwR
         LPCWSTR szResponseHeaders, LPCWSTR szRequestHeaders, LPWSTR *pszAdditionalRequestHeaders)
 {
     BSCallback *This = HTTPNEG_THIS(iface);
-    FIXME("(%p)->(%ld %s %s %p)\n", This, dwResponseCode, debugstr_w(szResponseHeaders),
+    FIXME("(%p)->(%d %s %s %p)\n", This, dwResponseCode, debugstr_w(szResponseHeaders),
           debugstr_w(szRequestHeaders), pszAdditionalRequestHeaders);
     return E_NOTIMPL;
 }
@@ -511,7 +588,7 @@ static HRESULT WINAPI InternetBindInfo_GetBindString(IInternetBindInfo *iface,
         ULONG ulStringType, LPOLESTR *ppwzStr, ULONG cEl, ULONG *pcElFetched)
 {
     BSCallback *This = BINDINFO_THIS(iface);
-    FIXME("(%p)->(%lu %p %lu %p)\n", This, ulStringType, ppwzStr, cEl, pcElFetched);
+    FIXME("(%p)->(%u %p %u %p)\n", This, ulStringType, ppwzStr, cEl, pcElFetched);
     return E_NOTIMPL;
 }
 
@@ -563,7 +640,7 @@ static const IServiceProviderVtbl ServiceProviderVtbl = {
     BSCServiceProvider_QueryService
 };
 
-BSCallback *create_bscallback(HTMLDocument *doc, LPCOLESTR url)
+BSCallback *create_bscallback(IMoniker *mon)
 {
     BSCallback *ret = mshtml_alloc(sizeof(BSCallback));
 
@@ -575,10 +652,17 @@ BSCallback *create_bscallback(HTMLDocument *doc, LPCOLESTR url)
     ret->post_data = NULL;
     ret->headers = NULL;
     ret->post_data_len = 0;
+    ret->readed = 0;
     ret->nschannel = NULL;
     ret->nslistener = NULL;
     ret->nscontext = NULL;
     ret->nsstream = NULL;
+    ret->binding = NULL;
+    ret->doc = NULL;
+
+    if(mon)
+        IMoniker_AddRef(mon);
+    ret->mon = mon;
 
     return ret;
 }
@@ -661,7 +745,7 @@ void hlink_frame_navigate(HTMLDocument *doc, IHlinkFrame *hlink_frame,
     IMoniker *mon;
     IHlink *hlink;
 
-    callback = create_bscallback(doc, uri);
+    callback = create_bscallback(NULL);
 
     if(post_data_stream) {
         parse_post_data(post_data_stream, &callback->headers, &callback->post_data,
@@ -690,7 +774,7 @@ void hlink_frame_navigate(HTMLDocument *doc, IHlinkFrame *hlink_frame,
 
 }
 
-HRESULT start_binding(BSCallback *bscallback, IMoniker *mon)
+HRESULT start_binding(BSCallback *bscallback)
 {
     IStream *str = NULL;
     IBindCtx *bctx;
@@ -698,19 +782,55 @@ HRESULT start_binding(BSCallback *bscallback, IMoniker *mon)
 
     hres = CreateAsyncBindCtx(0, STATUSCLB(bscallback), NULL, &bctx);
     if(FAILED(hres)) {
-        WARN("CreateAsyncBindCtx failed: %08lx\n", hres);
+        WARN("CreateAsyncBindCtx failed: %08x\n", hres);
         return hres;
     }
 
-    hres = IMoniker_BindToStorage(mon, bctx, NULL, &IID_IStream, (void**)&str);
+    hres = IMoniker_BindToStorage(bscallback->mon, bctx, NULL, &IID_IStream, (void**)&str);
     IBindCtx_Release(bctx);
     if(FAILED(hres)) {
-        WARN("BindToStorage failed: %08lx\n", hres);
+        WARN("BindToStorage failed: %08x\n", hres);
         return hres;
     }
 
     if(str)
         IStream_Release(str);
 
+    IMoniker_Release(bscallback->mon);
+    bscallback->mon = NULL;
     return S_OK;
 }
+
+void set_document_bscallback(HTMLDocument *doc, BSCallback *callback)
+{
+    if(doc->bscallback) {
+        if(doc->bscallback->binding)
+            IBinding_Abort(doc->bscallback->binding);
+        doc->bscallback->doc = NULL;
+        IBindStatusCallback_Release(STATUSCLB(doc->bscallback));
+    }
+
+    doc->bscallback = callback;
+
+    if(callback) {
+        IBindStatusCallback_AddRef(STATUSCLB(callback));
+        callback->doc = doc;
+    }
+}
+
+HRESULT load_stream(BSCallback *bscallback, IStream *stream)
+{
+    HRESULT hres;
+
+    const char text_html[] = "text/html";
+
+    add_nsrequest(bscallback);
+
+    bscallback->nschannel->content = mshtml_alloc(sizeof(text_html));
+    memcpy(bscallback->nschannel->content, text_html, sizeof(text_html));
+
+    hres = read_stream_data(bscallback, stream);
+    IBindStatusCallback_OnStopBinding(STATUSCLB(bscallback), hres, ERROR_SUCCESS);
+
+    return hres;
+}