urlmon: Set BINDF_NEEDFILE flag for all not urlmon protocols.
[wine] / dlls / urlmon / umstream.c
1 /*
2  * Based on ../shell32/memorystream.c
3  *
4  * Copyright 1999 Juergen Schmied
5  * Copyright 2003 Mike McCormack for CodeWeavers
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include <stdarg.h>
23
24 #define COBJMACROS
25
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winreg.h"
29 #include "winternl.h"
30 #include "winuser.h"
31 #include "objbase.h"
32 #include "wine/debug.h"
33 #include "wine/unicode.h"
34 #include "ole2.h"
35 #include "urlmon.h"
36 #include "wininet.h"
37 #include "shlwapi.h"
38 #include "urlmon_main.h"
39
40 WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
41
42 static const IStreamVtbl stvt;
43
44 HRESULT UMCreateStreamOnCacheFile(LPCWSTR pszURL,
45                                   DWORD dwSize,
46                                   LPWSTR pszFileName,
47                                   HANDLE *phfile,
48                                   IUMCacheStream **ppstr)
49 {
50     IUMCacheStream* ucstr;
51     HANDLE handle;
52     LPWSTR ext;
53     LPCWSTR c;
54     LPCWSTR eloc = 0;
55     HRESULT hr;
56
57     for (c = pszURL; *c && *c != '#' && *c != '?'; ++c)
58     {
59         if (*c == '.')
60            eloc = c + 1;
61         else if (*c == '/' || *c == '\\')
62            eloc = 0;
63     }
64
65     if (!eloc)
66        eloc = c;
67
68     ext = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * (c - eloc + 1));
69     memcpy(ext, eloc, sizeof(WCHAR) * (c - eloc));
70     ext[c - eloc] = 0;
71
72     if(!CreateUrlCacheEntryW(pszURL, dwSize, ext, pszFileName, 0))
73        hr = HRESULT_FROM_WIN32(GetLastError());
74     else
75        hr = 0;
76
77     HeapFree(GetProcessHeap(), 0, ext);
78
79     if (hr)
80        return hr;
81
82     TRACE("Opening %s\n", debugstr_w(pszFileName) );
83
84     handle = CreateFileW( pszFileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, NULL );
85     if( handle == INVALID_HANDLE_VALUE )
86        return HRESULT_FROM_WIN32(GetLastError());
87
88     if (phfile)
89     {
90        /* Call CreateFileW again because we need a handle with its own file pointer, and DuplicateHandle will return
91         * a handle that shares its file pointer with the original.
92         */
93            *phfile = CreateFileW( pszFileName, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL );
94
95        if (*phfile == (HANDLE) HFILE_ERROR)
96        {
97            DWORD dwError = GetLastError();
98
99            CloseHandle(handle);
100            return HRESULT_FROM_WIN32(dwError);
101        }
102     }
103
104     ucstr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,sizeof(IUMCacheStream));
105     if(ucstr )
106     {
107        ucstr->pszURL = HeapAlloc(GetProcessHeap(),
108                                  HEAP_ZERO_MEMORY,
109                                  sizeof(WCHAR) * (lstrlenW(pszURL) + 1));
110        if (ucstr->pszURL)
111        {
112             ucstr->pszFileName = HeapAlloc(GetProcessHeap(),
113                                            HEAP_ZERO_MEMORY,
114                                            sizeof(WCHAR) * (lstrlenW(pszFileName) + 1));
115            if (ucstr->pszFileName)
116            {
117               ucstr->lpVtbl=&stvt;
118               ucstr->ref = 1;
119               ucstr->handle = handle;
120               ucstr->closed = 0;
121               lstrcpyW(ucstr->pszURL, pszURL);
122               lstrcpyW(ucstr->pszFileName, pszFileName);
123
124               *ppstr = ucstr;
125
126               return S_OK;
127            }
128            HeapFree(GetProcessHeap(), 0, ucstr->pszURL);
129        }
130        HeapFree(GetProcessHeap(), 0, ucstr);
131     }
132     CloseHandle(handle);
133     if (phfile)
134        CloseHandle(*phfile);
135     return E_OUTOFMEMORY;
136 }
137
138 void UMCloseCacheFileStream(IUMCacheStream *This)
139 {
140     if (!This->closed)
141     {
142        FILETIME ftZero;
143
144        ftZero.dwLowDateTime = ftZero.dwHighDateTime = 0;
145
146        This->closed = 1;
147        CommitUrlCacheEntryW(This->pszURL,
148                             This->pszFileName,
149                             ftZero,
150                             ftZero,
151                             NORMAL_CACHE_ENTRY,
152                             0,
153                             0,
154                             0,
155                             0);
156     }
157 }
158
159 /**************************************************************************
160 *  IStream_fnQueryInterface
161 */
162 static HRESULT WINAPI IStream_fnQueryInterface(IStream *iface,
163                                                REFIID riid,
164                                                LPVOID *ppvObj)
165 {
166     IUMCacheStream *This = (IUMCacheStream *)iface;
167
168     TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvObj);
169
170     *ppvObj = NULL;
171
172     if(IsEqualIID(riid, &IID_IUnknown) ||
173        IsEqualIID(riid, &IID_IStream))
174     {
175       *ppvObj = This;
176     }
177
178     if(*ppvObj)
179     {
180       IStream_AddRef((IStream*)*ppvObj);
181       TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
182       return S_OK;
183     }
184     TRACE("-- Interface: E_NOINTERFACE\n");
185     return E_NOINTERFACE;
186 }
187
188 /**************************************************************************
189 *  IStream_fnAddRef
190 */
191 static ULONG WINAPI IStream_fnAddRef(IStream *iface)
192 {
193     IUMCacheStream *This = (IUMCacheStream *)iface;
194     ULONG refCount = InterlockedIncrement(&This->ref);
195
196     TRACE("(%p)->(count=%u)\n", This, refCount - 1);
197
198     return refCount;
199 }
200
201 /**************************************************************************
202 *  IStream_fnRelease
203 */
204 static ULONG WINAPI IStream_fnRelease(IStream *iface)
205 {
206     IUMCacheStream *This = (IUMCacheStream *)iface;
207     ULONG refCount = InterlockedDecrement(&This->ref);
208
209     TRACE("(%p)->(count=%u)\n", This, refCount + 1);
210
211     if (!refCount)
212     {
213        TRACE(" destroying UMCacheStream (%p)\n",This);
214        UMCloseCacheFileStream(This);
215        CloseHandle(This->handle);
216        HeapFree(GetProcessHeap(), 0, This->pszFileName);
217        HeapFree(GetProcessHeap(), 0, This->pszURL);
218        HeapFree(GetProcessHeap(),0,This);
219     }
220     return refCount;
221 }
222
223 static HRESULT WINAPI IStream_fnRead (IStream * iface, 
224                                       void* pv,
225                                       ULONG cb,
226                                       ULONG* pcbRead)
227 {
228     ULONG dwBytesRead;
229     IUMCacheStream *This = (IUMCacheStream *)iface;
230
231     TRACE("(%p)->(%p,0x%08x,%p)\n",This, pv, cb, pcbRead);
232
233     if ( !pv )
234        return STG_E_INVALIDPOINTER;
235
236     if ( !pcbRead)
237         pcbRead = &dwBytesRead;
238
239     if ( ! ReadFile( This->handle, pv, cb, (LPDWORD)pcbRead, NULL ) )
240        return S_FALSE;
241
242     if (!*pcbRead)
243         return This->closed ? S_FALSE : E_PENDING;
244     return S_OK;
245 }
246
247 static HRESULT WINAPI IStream_fnWrite (IStream * iface,
248                                        const void* pv,
249                                        ULONG cb,
250                                        ULONG* pcbWritten)
251 {
252     return E_NOTIMPL;
253 }
254
255 static HRESULT WINAPI IStream_fnSeek (IStream * iface,
256                                    LARGE_INTEGER dlibMove,
257                                    DWORD dwOrigin,
258                                    ULARGE_INTEGER* plibNewPosition)
259 {
260     LARGE_INTEGER newpos;
261     IUMCacheStream *This = (IUMCacheStream *)iface;
262
263     TRACE("(%p)\n",This);
264
265     if (!SetFilePointerEx( This->handle, dlibMove, &newpos, dwOrigin ))
266        return E_FAIL;
267
268     if (plibNewPosition)
269         plibNewPosition->QuadPart = newpos.QuadPart;
270
271     return S_OK;
272 }
273
274 static HRESULT WINAPI IStream_fnSetSize (IStream * iface,
275                                          ULARGE_INTEGER libNewSize)
276 {
277     LARGE_INTEGER newpos;
278     IUMCacheStream *This = (IUMCacheStream *)iface;
279
280     TRACE("(%p)\n",This);
281
282     newpos.QuadPart = libNewSize.QuadPart;
283     if( ! SetFilePointerEx( This->handle, newpos, NULL, FILE_BEGIN ) )
284        return E_FAIL;
285
286     if( ! SetEndOfFile( This->handle ) )
287        return E_FAIL;
288
289     return S_OK;
290 }
291
292 static HRESULT WINAPI IStream_fnCopyTo (IStream * iface,
293                                    IStream* pstm,
294                                    ULARGE_INTEGER cb,
295                                    ULARGE_INTEGER* pcbRead,
296                                    ULARGE_INTEGER* pcbWritten)
297 {
298     IUMCacheStream *This = (IUMCacheStream *)iface;
299
300     TRACE("(%p)\n",This);
301
302     return E_NOTIMPL;
303 }
304
305 static HRESULT WINAPI IStream_fnCommit (IStream * iface,
306                                    DWORD grfCommitFlags)
307 {
308     IUMCacheStream *This = (IUMCacheStream *)iface;
309
310     TRACE("(%p)\n",This);
311
312     return E_NOTIMPL;
313 }
314
315 static HRESULT WINAPI IStream_fnRevert (IStream * iface)
316 {
317     IUMCacheStream *This = (IUMCacheStream *)iface;
318
319     TRACE("(%p)\n",This);
320
321     return E_NOTIMPL;
322 }
323 static HRESULT WINAPI IStream_fnLockRegion (IStream * iface,
324                                             ULARGE_INTEGER libOffset,
325                                             ULARGE_INTEGER cb,
326                                             DWORD dwLockType)
327 {
328     IUMCacheStream *This = (IUMCacheStream *)iface;
329
330     TRACE("(%p)\n",This);
331
332     return E_NOTIMPL;
333 }
334 static HRESULT WINAPI IStream_fnUnlockRegion (IStream * iface,
335                                               ULARGE_INTEGER libOffset,
336                                               ULARGE_INTEGER cb,
337                                               DWORD dwLockType)
338 {
339     IUMCacheStream *This = (IUMCacheStream *)iface;
340
341     TRACE("(%p)\n",This);
342
343     return E_NOTIMPL;
344 }
345 static HRESULT WINAPI IStream_fnStat (IStream * iface,
346                                       STATSTG*   pstatstg,
347                                       DWORD grfStatFlag)
348 {
349     IUMCacheStream *This = (IUMCacheStream *)iface;
350
351     TRACE("(%p)\n",This);
352
353     return E_NOTIMPL;
354 }
355 static HRESULT WINAPI IStream_fnClone (IStream * iface,
356                                        IStream** ppstm)
357 {
358     IUMCacheStream *This = (IUMCacheStream *)iface;
359
360     TRACE("(%p)\n",This);
361
362     return E_NOTIMPL;
363 }
364
365 static const IStreamVtbl stvt =
366 {
367     IStream_fnQueryInterface,
368     IStream_fnAddRef,
369     IStream_fnRelease,
370     IStream_fnRead,
371     IStream_fnWrite,
372     IStream_fnSeek,
373     IStream_fnSetSize,
374     IStream_fnCopyTo,
375     IStream_fnCommit,
376     IStream_fnRevert,
377     IStream_fnLockRegion,
378     IStream_fnUnlockRegion,
379     IStream_fnStat,
380     IStream_fnClone
381
382 };