file.c 10.3 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 20 21 22 23 24
 */

#include "urlmon_main.h"
#include "wine/debug.h"

WINE_DEFAULT_DEBUG_CHANNEL(urlmon);

typedef struct {
25
    const IInternetProtocolVtbl  *lpIInternetProtocolVtbl;
26
    const IInternetPriorityVtbl  *lpInternetPriorityVtbl;
27 28

    HANDLE file;
29
    LONG priority;
30 31 32 33

    LONG ref;
} FileProtocol;

34 35
#define PRIORITY(x)  ((IInternetPriority*)  &(x)->lpInternetPriorityVtbl)

36
#define PROTOCOL_THIS(iface) DEFINE_THIS(FileProtocol, IInternetProtocol, iface)
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51

static HRESULT WINAPI FileProtocol_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv)
{
    FileProtocol *This = PROTOCOL_THIS(iface);

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

    if(*ppv) {
        IInternetProtocol_AddRef(iface);
        return S_OK;
    }

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

static ULONG WINAPI FileProtocol_AddRef(IInternetProtocol *iface)
{
    FileProtocol *This = PROTOCOL_THIS(iface);
    LONG ref = InterlockedIncrement(&This->ref);
70
    TRACE("(%p) ref=%d\n", This, ref);
71 72 73 74 75 76 77 78
    return ref;
}

static ULONG WINAPI FileProtocol_Release(IInternetProtocol *iface)
{
    FileProtocol *This = PROTOCOL_THIS(iface);
    LONG ref = InterlockedDecrement(&This->ref);

79
    TRACE("(%p) ref=%d\n", This, ref);
80 81 82 83

    if(!ref) {
        if(This->file)
            CloseHandle(This->file);
84
        heap_free(This);
85 86 87 88 89 90 91 92 93

        URLMON_UnlockModule();
    }

    return ref;
}

static HRESULT WINAPI FileProtocol_Start(IInternetProtocol *iface, LPCWSTR szUrl,
        IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
94
        DWORD grfPI, HANDLE_PTR dwReserved)
95 96 97 98 99
{
    FileProtocol *This = PROTOCOL_THIS(iface);
    BINDINFO bindinfo;
    DWORD grfBINDF = 0;
    LARGE_INTEGER size;
100
    DWORD len;
101
    LPWSTR url, mime = NULL, file_name;
102
    WCHAR null_char = 0;
103
    BOOL first_call = FALSE;
104
    HRESULT hres;
105 106 107

    static const WCHAR wszFile[]  = {'f','i','l','e',':'};

108
    TRACE("(%p)->(%s %p %p %08x %lx)\n", This, debugstr_w(szUrl), pOIProtSink,
109 110
            pOIBindInfo, grfPI, dwReserved);

111
    if(!szUrl || strlenW(szUrl) < sizeof(wszFile)/sizeof(WCHAR)
112 113 114
            || memcmp(szUrl, wszFile, sizeof(wszFile)))
        return E_INVALIDARG;

115 116
    memset(&bindinfo, 0, sizeof(bindinfo));
    bindinfo.cbSize = sizeof(BINDINFO);
117 118 119 120 121 122 123
    hres = IInternetBindInfo_GetBindInfo(pOIBindInfo, &grfBINDF, &bindinfo);
    if(FAILED(hres)) {
        WARN("GetBindInfo failed: %08x\n", hres);
        return hres;
    }

    ReleaseBindInfo(&bindinfo);
124

125
    len = lstrlenW(szUrl)+16;
126
    url = heap_alloc(len*sizeof(WCHAR));
127 128
    hres = CoInternetParseUrl(szUrl, PARSE_ENCODE, 0, url, len, &len, 0);
    if(FAILED(hres)) {
129
        heap_free(url);
130 131 132
        return hres;
    }

133 134
    if(!(grfBINDF & BINDF_FROMURLMON))
        IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_DIRECTBIND, NULL);
135 136

    if(!This->file) {
137 138
        WCHAR *ptr;

139 140
        first_call = TRUE;

141 142
        IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_SENDINGREQUEST, &null_char);

143
        file_name = url+sizeof(wszFile)/sizeof(WCHAR);
144 145 146 147
        if(file_name[0] == '/' && file_name[1] == '/')
            file_name += 2;
        if(*file_name == '/')
            file_name++;
148

149 150 151 152 153 154 155
        for(ptr = file_name; *ptr; ptr++) {
            if(*ptr == '?' || *ptr == '#') {
                *ptr = 0;
                break;
            }
        }

156 157 158
        if(file_name[1] == '|')
            file_name[1] = ':';

159 160
        This->file = CreateFileW(file_name, GENERIC_READ, FILE_SHARE_READ, NULL,
                                 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
161 162 163 164 165

        if(This->file == INVALID_HANDLE_VALUE) {
            This->file = NULL;
            IInternetProtocolSink_ReportResult(pOIProtSink, INET_E_RESOURCE_NOT_FOUND,
                    GetLastError(), NULL);
166
            heap_free(url);
167 168 169
            return INET_E_RESOURCE_NOT_FOUND;
        }

170 171 172 173 174 175
        IInternetProtocolSink_ReportProgress(pOIProtSink,
                BINDSTATUS_CACHEFILENAMEAVAILABLE, file_name);

        hres = FindMimeFromData(NULL, url, NULL, 0, NULL, 0, &mime, 0);
        if(SUCCEEDED(hres)) {
            IInternetProtocolSink_ReportProgress(pOIProtSink,
176 177 178
                    (grfBINDF & BINDF_FROMURLMON) ?
                    BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE : BINDSTATUS_MIMETYPEAVAILABLE,
                    mime);
179 180
            CoTaskMemFree(mime);
        }
181 182
    }

183
    heap_free(url);
184

185 186 187 188 189
    if(GetFileSizeEx(This->file, &size))
        IInternetProtocolSink_ReportData(pOIProtSink,
                BSCF_FIRSTDATANOTIFICATION|BSCF_LASTDATANOTIFICATION,
                size.u.LowPart, size.u.LowPart);

190 191 192
    if(first_call)
        IInternetProtocolSink_ReportResult(pOIProtSink, S_OK, 0, NULL);

193 194 195 196 197 198 199 200 201 202 203 204 205 206
    return S_OK;
}

static HRESULT WINAPI FileProtocol_Continue(IInternetProtocol *iface, PROTOCOLDATA *pProtocolData)
{
    FileProtocol *This = PROTOCOL_THIS(iface);
    FIXME("(%p)->(%p)\n", This, pProtocolData);
    return E_NOTIMPL;
}

static HRESULT WINAPI FileProtocol_Abort(IInternetProtocol *iface, HRESULT hrReason,
        DWORD dwOptions)
{
    FileProtocol *This = PROTOCOL_THIS(iface);
207
    FIXME("(%p)->(%08x %08x)\n", This, hrReason, dwOptions);
208 209 210 211 212 213 214
    return E_NOTIMPL;
}

static HRESULT WINAPI FileProtocol_Terminate(IInternetProtocol *iface, DWORD dwOptions)
{
    FileProtocol *This = PROTOCOL_THIS(iface);

215
    TRACE("(%p)->(%08x)\n", This, dwOptions);
216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239

    return S_OK;
}

static HRESULT WINAPI FileProtocol_Suspend(IInternetProtocol *iface)
{
    FileProtocol *This = PROTOCOL_THIS(iface);
    FIXME("(%p)\n", This);
    return E_NOTIMPL;
}

static HRESULT WINAPI FileProtocol_Resume(IInternetProtocol *iface)
{
    FileProtocol *This = PROTOCOL_THIS(iface);
    FIXME("(%p)\n", This);
    return E_NOTIMPL;
}

static HRESULT WINAPI FileProtocol_Read(IInternetProtocol *iface, void *pv,
        ULONG cb, ULONG *pcbRead)
{
    FileProtocol *This = PROTOCOL_THIS(iface);
    DWORD read = 0;

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

242 243 244
    if (pcbRead)
        *pcbRead = 0;

245 246 247
    if(!This->file)
        return INET_E_DATA_NOT_AVAILABLE;

248 249
    if (!ReadFile(This->file, pv, cb, &read, NULL))
        return INET_E_DOWNLOAD_FAILURE;
250 251 252 253 254 255 256 257

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

static HRESULT WINAPI FileProtocol_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove,
258
        DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
259 260
{
    FileProtocol *This = PROTOCOL_THIS(iface);
261
    FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
262 263 264 265 266 267 268
    return E_NOTIMPL;
}

static HRESULT WINAPI FileProtocol_LockRequest(IInternetProtocol *iface, DWORD dwOptions)
{
    FileProtocol *This = PROTOCOL_THIS(iface);

269
    TRACE("(%p)->(%08x)\n", This, dwOptions);
270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300

    return S_OK;
}

static HRESULT WINAPI FileProtocol_UnlockRequest(IInternetProtocol *iface)
{
    FileProtocol *This = PROTOCOL_THIS(iface);

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

    return S_OK;
}

#undef PROTOCOL_THIS

static const IInternetProtocolVtbl FileProtocolVtbl = {
    FileProtocol_QueryInterface,
    FileProtocol_AddRef,
    FileProtocol_Release,
    FileProtocol_Start,
    FileProtocol_Continue,
    FileProtocol_Abort,
    FileProtocol_Terminate,
    FileProtocol_Suspend,
    FileProtocol_Resume,
    FileProtocol_Read,
    FileProtocol_Seek,
    FileProtocol_LockRequest,
    FileProtocol_UnlockRequest
};

301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325
#define PRIORITY_THIS(iface) DEFINE_THIS(FileProtocol, InternetPriority, iface)

static HRESULT WINAPI FilePriority_QueryInterface(IInternetPriority *iface,
                                                  REFIID riid, void **ppv)
{
    FileProtocol *This = PRIORITY_THIS(iface);
    return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv);
}

static ULONG WINAPI FilePriority_AddRef(IInternetPriority *iface)
{
    FileProtocol *This = PRIORITY_THIS(iface);
    return IInternetProtocol_AddRef(PROTOCOL(This));
}

static ULONG WINAPI FilePriority_Release(IInternetPriority *iface)
{
    FileProtocol *This = PRIORITY_THIS(iface);
    return IInternetProtocol_Release(PROTOCOL(This));
}

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

326
    TRACE("(%p)->(%d)\n", This, nPriority);
327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351

    This->priority = nPriority;
    return S_OK;
}

static HRESULT WINAPI FilePriority_GetPriority(IInternetPriority *iface, LONG *pnPriority)
{
    FileProtocol *This = PRIORITY_THIS(iface);

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

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

#undef PRIORITY_THIS

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

352 353 354 355 356 357 358 359
HRESULT FileProtocol_Construct(IUnknown *pUnkOuter, LPVOID *ppobj)
{
    FileProtocol *ret;

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

    URLMON_LockModule();

360
    ret = heap_alloc(sizeof(FileProtocol));
361

362
    ret->lpIInternetProtocolVtbl = &FileProtocolVtbl;
363
    ret->lpInternetPriorityVtbl = &FilePriorityVtbl;
364
    ret->file = NULL;
365
    ret->priority = 0;
366 367 368 369 370 371
    ret->ref = 1;

    *ppobj = PROTOCOL(ret);
    
    return S_OK;
}