file.c 12.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/*
 * Copyright 2005 Jacek Caban
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * 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 "urlmon_main.h"
20 21 22
#include "winreg.h"
#include "shlwapi.h"

23 24 25 26 27
#include "wine/debug.h"

WINE_DEFAULT_DEBUG_CHANNEL(urlmon);

typedef struct {
28 29
    IInternetProtocolEx IInternetProtocolEx_iface;
    IInternetPriority   IInternetPriority_iface;
30 31

    HANDLE file;
32
    ULONG size;
33
    LONG priority;
34 35 36 37

    LONG ref;
} FileProtocol;

38 39 40 41
static inline FileProtocol *impl_from_IInternetProtocolEx(IInternetProtocolEx *iface)
{
    return CONTAINING_RECORD(iface, FileProtocol, IInternetProtocolEx_iface);
}
42

43 44 45 46
static inline FileProtocol *impl_from_IInternetPriority(IInternetPriority *iface)
{
    return CONTAINING_RECORD(iface, FileProtocol, IInternetPriority_iface);
}
47

48
static HRESULT WINAPI FileProtocol_QueryInterface(IInternetProtocolEx *iface, REFIID riid, void **ppv)
49
{
50
    FileProtocol *This = impl_from_IInternetProtocolEx(iface);
51 52 53 54

    *ppv = NULL;
    if(IsEqualGUID(&IID_IUnknown, riid)) {
        TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
55
        *ppv = &This->IInternetProtocolEx_iface;
56 57
    }else if(IsEqualGUID(&IID_IInternetProtocolRoot, riid)) {
        TRACE("(%p)->(IID_IInternetProtocolRoot %p)\n", This, ppv);
58
        *ppv = &This->IInternetProtocolEx_iface;
59 60
    }else if(IsEqualGUID(&IID_IInternetProtocol, riid)) {
        TRACE("(%p)->(IID_IInternetProtocol %p)\n", This, ppv);
61
        *ppv = &This->IInternetProtocolEx_iface;
62 63
    }else if(IsEqualGUID(&IID_IInternetProtocolEx, riid)) {
        TRACE("(%p)->(IID_IInternetProtocolEx %p)\n", This, ppv);
64
        *ppv = &This->IInternetProtocolEx_iface;
65 66
    }else if(IsEqualGUID(&IID_IInternetPriority, riid)) {
        TRACE("(%p)->(IID_IInternetPriority %p)\n", This, ppv);
67
        *ppv = &This->IInternetPriority_iface;
68 69 70
    }

    if(*ppv) {
71
        IInternetProtocolEx_AddRef(iface);
72 73 74 75 76 77 78
        return S_OK;
    }

    WARN("not supported interface %s\n", debugstr_guid(riid));
    return E_NOINTERFACE;
}

79
static ULONG WINAPI FileProtocol_AddRef(IInternetProtocolEx *iface)
80
{
81
    FileProtocol *This = impl_from_IInternetProtocolEx(iface);
82
    LONG ref = InterlockedIncrement(&This->ref);
83
    TRACE("(%p) ref=%d\n", This, ref);
84 85 86
    return ref;
}

87
static ULONG WINAPI FileProtocol_Release(IInternetProtocolEx *iface)
88
{
89
    FileProtocol *This = impl_from_IInternetProtocolEx(iface);
90 91
    LONG ref = InterlockedDecrement(&This->ref);

92
    TRACE("(%p) ref=%d\n", This, ref);
93 94

    if(!ref) {
95
        if(This->file != INVALID_HANDLE_VALUE)
96
            CloseHandle(This->file);
97
        heap_free(This);
98 99 100 101 102 103 104

        URLMON_UnlockModule();
    }

    return ref;
}

105
static HRESULT WINAPI FileProtocol_Start(IInternetProtocolEx *iface, LPCWSTR szUrl,
106
        IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
107
        DWORD grfPI, HANDLE_PTR dwReserved)
108
{
109
    FileProtocol *This = impl_from_IInternetProtocolEx(iface);
110
    IUri *uri;
111
    HRESULT hres;
112

113
    TRACE("(%p)->(%s %p %p %08x %lx)\n", This, debugstr_w(szUrl), pOIProtSink,
114 115
            pOIBindInfo, grfPI, dwReserved);

116 117
    hres = CreateUri(szUrl, Uri_CREATE_FILE_USE_DOS_PATH, 0, &uri);
    if(FAILED(hres))
118
        return hres;
119

120 121
    hres = IInternetProtocolEx_StartEx(&This->IInternetProtocolEx_iface, uri, pOIProtSink,
            pOIBindInfo, grfPI, (HANDLE*)dwReserved);
122

123 124
    IUri_Release(uri);
    return hres;
125 126
}

127
static HRESULT WINAPI FileProtocol_Continue(IInternetProtocolEx *iface, PROTOCOLDATA *pProtocolData)
128
{
129
    FileProtocol *This = impl_from_IInternetProtocolEx(iface);
130 131 132 133
    FIXME("(%p)->(%p)\n", This, pProtocolData);
    return E_NOTIMPL;
}

134
static HRESULT WINAPI FileProtocol_Abort(IInternetProtocolEx *iface, HRESULT hrReason,
135 136
        DWORD dwOptions)
{
137
    FileProtocol *This = impl_from_IInternetProtocolEx(iface);
138
    FIXME("(%p)->(%08x %08x)\n", This, hrReason, dwOptions);
139 140 141
    return E_NOTIMPL;
}

142
static HRESULT WINAPI FileProtocol_Terminate(IInternetProtocolEx *iface, DWORD dwOptions)
143
{
144
    FileProtocol *This = impl_from_IInternetProtocolEx(iface);
145

146
    TRACE("(%p)->(%08x)\n", This, dwOptions);
147 148 149 150

    return S_OK;
}

151
static HRESULT WINAPI FileProtocol_Suspend(IInternetProtocolEx *iface)
152
{
153
    FileProtocol *This = impl_from_IInternetProtocolEx(iface);
154 155 156 157
    FIXME("(%p)\n", This);
    return E_NOTIMPL;
}

158
static HRESULT WINAPI FileProtocol_Resume(IInternetProtocolEx *iface)
159
{
160
    FileProtocol *This = impl_from_IInternetProtocolEx(iface);
161 162 163 164
    FIXME("(%p)\n", This);
    return E_NOTIMPL;
}

165
static HRESULT WINAPI FileProtocol_Read(IInternetProtocolEx *iface, void *pv,
166 167
        ULONG cb, ULONG *pcbRead)
{
168
    FileProtocol *This = impl_from_IInternetProtocolEx(iface);
169 170
    DWORD read = 0;

171
    TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead);
172

173 174 175
    if (pcbRead)
        *pcbRead = 0;

176
    if(This->file == INVALID_HANDLE_VALUE)
177 178
        return INET_E_DATA_NOT_AVAILABLE;

179 180
    if (!ReadFile(This->file, pv, cb, &read, NULL))
        return INET_E_DOWNLOAD_FAILURE;
181 182 183 184 185 186 187

    if(pcbRead)
        *pcbRead = read;
    
    return cb == read ? S_OK : S_FALSE;
}

188
static HRESULT WINAPI FileProtocol_Seek(IInternetProtocolEx *iface, LARGE_INTEGER dlibMove,
189
        DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
190
{
191
    FileProtocol *This = impl_from_IInternetProtocolEx(iface);
192
    FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
193 194 195
    return E_NOTIMPL;
}

196
static HRESULT WINAPI FileProtocol_LockRequest(IInternetProtocolEx *iface, DWORD dwOptions)
197
{
198
    FileProtocol *This = impl_from_IInternetProtocolEx(iface);
199

200
    TRACE("(%p)->(%08x)\n", This, dwOptions);
201 202 203 204

    return S_OK;
}

205
static HRESULT WINAPI FileProtocol_UnlockRequest(IInternetProtocolEx *iface)
206
{
207
    FileProtocol *This = impl_from_IInternetProtocolEx(iface);
208 209 210 211 212 213

    TRACE("(%p)\n", This);

    return S_OK;
}

214 215 216 217 218 219 220 221 222 223
static inline HRESULT report_result(IInternetProtocolSink *protocol_sink, HRESULT hres, DWORD res)
{
    IInternetProtocolSink_ReportResult(protocol_sink, hres, res, NULL);
    return hres;
}

static HRESULT WINAPI FileProtocol_StartEx(IInternetProtocolEx *iface, IUri *pUri,
        IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
        DWORD grfPI, HANDLE *dwReserved)
{
224
    FileProtocol *This = impl_from_IInternetProtocolEx(iface);
225 226 227
    WCHAR path[MAX_PATH], *ptr;
    LARGE_INTEGER file_size;
    HANDLE file_handle;
228 229
    BINDINFO bindinfo;
    DWORD grfBINDF = 0;
230
    DWORD scheme, size;
231 232
    LPWSTR mime = NULL;
    WCHAR null_char = 0;
233
    BSTR ext;
234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
    HRESULT hres;

    TRACE("(%p)->(%p %p %p %08x %p)\n", This, pUri, pOIProtSink,
            pOIBindInfo, grfPI, dwReserved);

    if(!pUri)
        return E_INVALIDARG;

    scheme = 0;
    hres = IUri_GetScheme(pUri, &scheme);
    if(FAILED(hres))
        return hres;
    if(scheme != URL_SCHEME_FILE)
        return E_INVALIDARG;

    memset(&bindinfo, 0, sizeof(bindinfo));
    bindinfo.cbSize = sizeof(BINDINFO);
    hres = IInternetBindInfo_GetBindInfo(pOIBindInfo, &grfBINDF, &bindinfo);
    if(FAILED(hres)) {
        WARN("GetBindInfo failed: %08x\n", hres);
        return hres;
    }

    ReleaseBindInfo(&bindinfo);

    if(!(grfBINDF & BINDF_FROMURLMON))
        IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_DIRECTBIND, NULL);

    if(This->file != INVALID_HANDLE_VALUE) {
        IInternetProtocolSink_ReportData(pOIProtSink,
                BSCF_FIRSTDATANOTIFICATION|BSCF_LASTDATANOTIFICATION,
                This->size, This->size);
        return S_OK;
    }

    IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_SENDINGREQUEST, &null_char);

271 272
    size = 0;
    hres = CoInternetParseIUri(pUri, PARSE_PATH_FROM_URL, 0, path, sizeof(path)/sizeof(WCHAR), &size, 0);
273
    if(FAILED(hres)) {
274
        WARN("CoInternetParseIUri failed: %08x\n", hres);
275 276 277
        return report_result(pOIProtSink, hres, 0);
    }

278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296
    file_handle = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ, NULL,
            OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if(file_handle == INVALID_HANDLE_VALUE && (ptr = strrchrW(path, '#'))) {
        /* If path contains fragment part, try without it. */
        *ptr = 0;
        file_handle = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ, NULL,
                OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    }
    if(file_handle == INVALID_HANDLE_VALUE)
        return report_result(pOIProtSink, INET_E_RESOURCE_NOT_FOUND, GetLastError());

    if(!GetFileSizeEx(file_handle, &file_size)) {
        CloseHandle(file_handle);
        return report_result(pOIProtSink, INET_E_RESOURCE_NOT_FOUND, GetLastError());
    }

    This->file = file_handle;
    This->size = file_size.u.LowPart;
    IInternetProtocolSink_ReportProgress(pOIProtSink,  BINDSTATUS_CACHEFILENAMEAVAILABLE, path);
297

298 299 300
    hres = IUri_GetExtension(pUri, &ext);
    if(SUCCEEDED(hres)) {
        if(hres == S_OK && *ext) {
301 302
            if((ptr = strchrW(ext, '#')))
                *ptr = 0;
303 304 305 306 307 308 309 310
            hres = find_mime_from_ext(ext, &mime);
            if(SUCCEEDED(hres)) {
                IInternetProtocolSink_ReportProgress(pOIProtSink,
                        (grfBINDF & BINDF_FROMURLMON) ?
                        BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE : BINDSTATUS_MIMETYPEAVAILABLE,
                        mime);
                CoTaskMemFree(mime);
            }
311
        }
312
        SysFreeString(ext);
313 314 315 316 317 318 319 320 321 322
    }

    IInternetProtocolSink_ReportData(pOIProtSink,
            BSCF_FIRSTDATANOTIFICATION|BSCF_LASTDATANOTIFICATION,
            This->size, This->size);

    return report_result(pOIProtSink, S_OK, 0);
}

static const IInternetProtocolExVtbl FileProtocolExVtbl = {
323 324 325 326 327 328 329 330 331 332 333 334
    FileProtocol_QueryInterface,
    FileProtocol_AddRef,
    FileProtocol_Release,
    FileProtocol_Start,
    FileProtocol_Continue,
    FileProtocol_Abort,
    FileProtocol_Terminate,
    FileProtocol_Suspend,
    FileProtocol_Resume,
    FileProtocol_Read,
    FileProtocol_Seek,
    FileProtocol_LockRequest,
335 336
    FileProtocol_UnlockRequest,
    FileProtocol_StartEx
337 338
};

339 340 341
static HRESULT WINAPI FilePriority_QueryInterface(IInternetPriority *iface,
                                                  REFIID riid, void **ppv)
{
342 343
    FileProtocol *This = impl_from_IInternetPriority(iface);
    return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv);
344 345 346 347
}

static ULONG WINAPI FilePriority_AddRef(IInternetPriority *iface)
{
348 349
    FileProtocol *This = impl_from_IInternetPriority(iface);
    return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
350 351 352 353
}

static ULONG WINAPI FilePriority_Release(IInternetPriority *iface)
{
354 355
    FileProtocol *This = impl_from_IInternetPriority(iface);
    return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
356 357 358 359
}

static HRESULT WINAPI FilePriority_SetPriority(IInternetPriority *iface, LONG nPriority)
{
360
    FileProtocol *This = impl_from_IInternetPriority(iface);
361

362
    TRACE("(%p)->(%d)\n", This, nPriority);
363 364 365 366 367 368 369

    This->priority = nPriority;
    return S_OK;
}

static HRESULT WINAPI FilePriority_GetPriority(IInternetPriority *iface, LONG *pnPriority)
{
370
    FileProtocol *This = impl_from_IInternetPriority(iface);
371 372 373 374 375 376 377 378 379 380 381 382 383 384 385

    TRACE("(%p)->(%p)\n", This, pnPriority);

    *pnPriority = This->priority;
    return S_OK;
}

static const IInternetPriorityVtbl FilePriorityVtbl = {
    FilePriority_QueryInterface,
    FilePriority_AddRef,
    FilePriority_Release,
    FilePriority_SetPriority,
    FilePriority_GetPriority
};

386 387 388 389 390 391 392 393
HRESULT FileProtocol_Construct(IUnknown *pUnkOuter, LPVOID *ppobj)
{
    FileProtocol *ret;

    TRACE("(%p %p)\n", pUnkOuter, ppobj);

    URLMON_LockModule();

394
    ret = heap_alloc(sizeof(FileProtocol));
395

396 397
    ret->IInternetProtocolEx_iface.lpVtbl = &FileProtocolExVtbl;
    ret->IInternetPriority_iface.lpVtbl = &FilePriorityVtbl;
398
    ret->file = INVALID_HANDLE_VALUE;
399
    ret->priority = 0;
400 401
    ret->ref = 1;

402
    *ppobj = &ret->IInternetProtocolEx_iface;
403 404
    return S_OK;
}