widl: Add support for structures.
[wine.git] / dlls / mf / scheme_handler.c
blob7e92748aeb90f091855078e7308f1b0de5d3f824
1 /*
2 * Copyright 2022 Nikolay Sivov for CodeWeavers
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.
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.
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
19 #include <stddef.h>
20 #include <stdarg.h>
22 #define COBJMACROS
23 #include "windef.h"
24 #include "winbase.h"
26 #include "evr.h"
27 #include "mfidl.h"
28 #include "mf_private.h"
30 #include "wine/debug.h"
31 #include "wine/list.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
35 typedef HRESULT (*create_stream_cb)(const WCHAR *url, DWORD flags, IMFByteStream **out);
37 struct scheme_handler_result
39 struct list entry;
40 IMFAsyncResult *result;
41 MF_OBJECT_TYPE obj_type;
42 IUnknown *object;
45 struct scheme_handler
47 IMFSchemeHandler IMFSchemeHandler_iface;
48 IMFAsyncCallback IMFAsyncCallback_iface;
49 LONG refcount;
50 IMFSourceResolver *resolver;
51 struct list results;
52 CRITICAL_SECTION cs;
53 create_stream_cb create_stream;
56 static struct scheme_handler *impl_from_IMFSchemeHandler(IMFSchemeHandler *iface)
58 return CONTAINING_RECORD(iface, struct scheme_handler, IMFSchemeHandler_iface);
61 static struct scheme_handler *impl_from_IMFAsyncCallback(IMFAsyncCallback *iface)
63 return CONTAINING_RECORD(iface, struct scheme_handler, IMFAsyncCallback_iface);
66 static HRESULT WINAPI scheme_handler_QueryInterface(IMFSchemeHandler *iface, REFIID riid, void **obj)
68 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
70 if (IsEqualIID(riid, &IID_IMFSchemeHandler) ||
71 IsEqualIID(riid, &IID_IUnknown))
73 *obj = iface;
74 IMFSchemeHandler_AddRef(iface);
75 return S_OK;
78 WARN("Unsupported %s.\n", debugstr_guid(riid));
79 *obj = NULL;
80 return E_NOINTERFACE;
83 static ULONG WINAPI scheme_handler_AddRef(IMFSchemeHandler *iface)
85 struct scheme_handler *handler = impl_from_IMFSchemeHandler(iface);
86 ULONG refcount = InterlockedIncrement(&handler->refcount);
88 TRACE("%p, refcount %lu.\n", handler, refcount);
90 return refcount;
93 static ULONG WINAPI scheme_handler_Release(IMFSchemeHandler *iface)
95 struct scheme_handler *handler = impl_from_IMFSchemeHandler(iface);
96 ULONG refcount = InterlockedDecrement(&handler->refcount);
97 struct scheme_handler_result *result, *next;
99 TRACE("%p, refcount %lu.\n", iface, refcount);
101 if (!refcount)
103 LIST_FOR_EACH_ENTRY_SAFE(result, next, &handler->results, struct scheme_handler_result, entry)
105 list_remove(&result->entry);
106 IMFAsyncResult_Release(result->result);
107 if (result->object)
108 IUnknown_Release(result->object);
109 free(result);
111 DeleteCriticalSection(&handler->cs);
112 if (handler->resolver)
113 IMFSourceResolver_Release(handler->resolver);
114 free(handler);
117 return refcount;
120 struct create_object_context
122 IUnknown IUnknown_iface;
123 LONG refcount;
125 IPropertyStore *props;
126 WCHAR *url;
127 DWORD flags;
130 static struct create_object_context *impl_from_IUnknown(IUnknown *iface)
132 return CONTAINING_RECORD(iface, struct create_object_context, IUnknown_iface);
135 static HRESULT WINAPI create_object_context_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
137 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
139 if (IsEqualIID(riid, &IID_IUnknown))
141 *obj = iface;
142 IUnknown_AddRef(iface);
143 return S_OK;
146 WARN("Unsupported %s.\n", debugstr_guid(riid));
147 *obj = NULL;
148 return E_NOINTERFACE;
151 static ULONG WINAPI create_object_context_AddRef(IUnknown *iface)
153 struct create_object_context *context = impl_from_IUnknown(iface);
154 ULONG refcount = InterlockedIncrement(&context->refcount);
156 TRACE("%p, refcount %lu.\n", iface, refcount);
158 return refcount;
161 static ULONG WINAPI create_object_context_Release(IUnknown *iface)
163 struct create_object_context *context = impl_from_IUnknown(iface);
164 ULONG refcount = InterlockedDecrement(&context->refcount);
166 TRACE("%p, refcount %lu.\n", iface, refcount);
168 if (!refcount)
170 if (context->props)
171 IPropertyStore_Release(context->props);
172 free(context->url);
173 free(context);
176 return refcount;
179 static const IUnknownVtbl create_object_context_vtbl =
181 create_object_context_QueryInterface,
182 create_object_context_AddRef,
183 create_object_context_Release,
186 static HRESULT WINAPI scheme_handler_BeginCreateObject(IMFSchemeHandler *iface, const WCHAR *url, DWORD flags,
187 IPropertyStore *props, IUnknown **cancel_cookie, IMFAsyncCallback *callback, IUnknown *state)
189 struct scheme_handler *handler = impl_from_IMFSchemeHandler(iface);
190 struct create_object_context *context;
191 IMFAsyncResult *caller, *item;
192 HRESULT hr;
194 TRACE("%p, %s, %#lx, %p, %p, %p, %p.\n", iface, debugstr_w(url), flags, props, cancel_cookie, callback, state);
196 if (cancel_cookie)
197 *cancel_cookie = NULL;
199 if (FAILED(hr = MFCreateAsyncResult(NULL, callback, state, &caller)))
200 return hr;
202 if (!(context = malloc(sizeof(*context))))
204 IMFAsyncResult_Release(caller);
205 return E_OUTOFMEMORY;
208 context->IUnknown_iface.lpVtbl = &create_object_context_vtbl;
209 context->refcount = 1;
210 context->props = props;
211 if (context->props)
212 IPropertyStore_AddRef(context->props);
213 context->flags = flags;
214 context->url = wcsdup(url);
215 if (!context->url)
217 IMFAsyncResult_Release(caller);
218 IUnknown_Release(&context->IUnknown_iface);
219 return E_OUTOFMEMORY;
222 hr = MFCreateAsyncResult(&context->IUnknown_iface, &handler->IMFAsyncCallback_iface, (IUnknown *)caller, &item);
223 IUnknown_Release(&context->IUnknown_iface);
224 if (SUCCEEDED(hr))
226 if (SUCCEEDED(hr = MFPutWorkItemEx(MFASYNC_CALLBACK_QUEUE_IO, item)))
228 if (cancel_cookie)
230 *cancel_cookie = (IUnknown *)caller;
231 IUnknown_AddRef(*cancel_cookie);
235 IMFAsyncResult_Release(item);
237 IMFAsyncResult_Release(caller);
239 return hr;
242 static HRESULT WINAPI scheme_handler_EndCreateObject(IMFSchemeHandler *iface, IMFAsyncResult *result,
243 MF_OBJECT_TYPE *obj_type, IUnknown **object)
245 struct scheme_handler *handler = impl_from_IMFSchemeHandler(iface);
246 struct scheme_handler_result *found = NULL, *cur;
247 HRESULT hr;
249 TRACE("%p, %p, %p, %p.\n", iface, result, obj_type, object);
251 EnterCriticalSection(&handler->cs);
253 LIST_FOR_EACH_ENTRY(cur, &handler->results, struct scheme_handler_result, entry)
255 if (result == cur->result)
257 list_remove(&cur->entry);
258 found = cur;
259 break;
263 LeaveCriticalSection(&handler->cs);
265 if (found)
267 *obj_type = found->obj_type;
268 *object = found->object;
269 hr = IMFAsyncResult_GetStatus(found->result);
270 IMFAsyncResult_Release(found->result);
271 free(found);
273 else
275 *obj_type = MF_OBJECT_INVALID;
276 *object = NULL;
277 hr = MF_E_UNEXPECTED;
280 return hr;
283 static HRESULT WINAPI scheme_handler_CancelObjectCreation(IMFSchemeHandler *iface, IUnknown *cancel_cookie)
285 struct scheme_handler *handler = impl_from_IMFSchemeHandler(iface);
286 struct scheme_handler_result *found = NULL, *cur;
288 TRACE("%p, %p.\n", iface, cancel_cookie);
290 EnterCriticalSection(&handler->cs);
292 LIST_FOR_EACH_ENTRY(cur, &handler->results, struct scheme_handler_result, entry)
294 if (cancel_cookie == (IUnknown *)cur->result)
296 list_remove(&cur->entry);
297 found = cur;
298 break;
302 LeaveCriticalSection(&handler->cs);
304 if (found)
306 IMFAsyncResult_Release(found->result);
307 if (found->object)
308 IUnknown_Release(found->object);
309 free(found);
312 return found ? S_OK : MF_E_UNEXPECTED;
315 static const IMFSchemeHandlerVtbl scheme_handler_vtbl =
317 scheme_handler_QueryInterface,
318 scheme_handler_AddRef,
319 scheme_handler_Release,
320 scheme_handler_BeginCreateObject,
321 scheme_handler_EndCreateObject,
322 scheme_handler_CancelObjectCreation,
325 static HRESULT WINAPI scheme_handler_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj)
327 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
328 IsEqualIID(riid, &IID_IUnknown))
330 *obj = iface;
331 IMFAsyncCallback_AddRef(iface);
332 return S_OK;
335 WARN("Unsupported %s.\n", debugstr_guid(riid));
336 *obj = NULL;
337 return E_NOINTERFACE;
340 static ULONG WINAPI scheme_handler_callback_AddRef(IMFAsyncCallback *iface)
342 struct scheme_handler *handler = impl_from_IMFAsyncCallback(iface);
343 return IMFSchemeHandler_AddRef(&handler->IMFSchemeHandler_iface);
346 static ULONG WINAPI scheme_handler_callback_Release(IMFAsyncCallback *iface)
348 struct scheme_handler *handler = impl_from_IMFAsyncCallback(iface);
349 return IMFSchemeHandler_Release(&handler->IMFSchemeHandler_iface);
352 static HRESULT WINAPI scheme_handler_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue)
354 return E_NOTIMPL;
357 static HRESULT scheme_handler_get_resolver(struct scheme_handler *handler, IMFSourceResolver **resolver)
359 HRESULT hr;
361 if (!handler->resolver)
363 IMFSourceResolver *resolver;
365 if (FAILED(hr = MFCreateSourceResolver(&resolver)))
366 return hr;
368 if (InterlockedCompareExchangePointer((void **)&handler->resolver, resolver, NULL))
369 IMFSourceResolver_Release(resolver);
372 *resolver = handler->resolver;
373 IMFSourceResolver_AddRef(*resolver);
375 return S_OK;
378 static HRESULT WINAPI scheme_handler_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
380 struct scheme_handler *handler = impl_from_IMFAsyncCallback(iface);
381 struct scheme_handler_result *handler_result;
382 MF_OBJECT_TYPE obj_type = MF_OBJECT_INVALID;
383 IUnknown *object = NULL, *context_object;
384 struct create_object_context *context;
385 IMFSourceResolver *resolver;
386 IMFAsyncResult *caller;
387 IMFByteStream *stream;
388 HRESULT hr;
390 caller = (IMFAsyncResult *)IMFAsyncResult_GetStateNoAddRef(result);
392 if (FAILED(hr = IMFAsyncResult_GetObject(result, &context_object)))
394 WARN("Expected context set for callee result.\n");
395 return hr;
398 context = impl_from_IUnknown(context_object);
400 if (SUCCEEDED(hr = handler->create_stream(context->url, context->flags, &stream)))
402 if (context->flags & MF_RESOLUTION_MEDIASOURCE)
404 if (SUCCEEDED(hr = scheme_handler_get_resolver(handler, &resolver)))
406 hr = IMFSourceResolver_CreateObjectFromByteStream(resolver, stream, context->url, context->flags,
407 context->props, &obj_type, &object);
408 IMFSourceResolver_Release(resolver);
409 IMFByteStream_Release(stream);
412 else
414 object = (IUnknown *)stream;
415 obj_type = MF_OBJECT_BYTESTREAM;
419 handler_result = malloc(sizeof(*handler_result));
420 if (handler_result)
422 handler_result->result = caller;
423 IMFAsyncResult_AddRef(handler_result->result);
424 handler_result->obj_type = obj_type;
425 handler_result->object = object;
427 EnterCriticalSection(&handler->cs);
428 list_add_tail(&handler->results, &handler_result->entry);
429 LeaveCriticalSection(&handler->cs);
431 else
433 if (object)
434 IUnknown_Release(object);
435 hr = E_OUTOFMEMORY;
438 IUnknown_Release(&context->IUnknown_iface);
440 IMFAsyncResult_SetStatus(caller, hr);
441 MFInvokeCallback(caller);
443 return S_OK;
446 static const IMFAsyncCallbackVtbl scheme_handler_callback_vtbl =
448 scheme_handler_callback_QueryInterface,
449 scheme_handler_callback_AddRef,
450 scheme_handler_callback_Release,
451 scheme_handler_callback_GetParameters,
452 scheme_handler_callback_Invoke,
455 static HRESULT file_stream_create(const WCHAR *url, DWORD flags, IMFByteStream **out)
457 if (!wcsnicmp(url, L"file://", 7))
458 url += 7;
459 return MFCreateFile(flags & MF_RESOLUTION_WRITE ? MF_ACCESSMODE_READWRITE : MF_ACCESSMODE_READ,
460 MF_OPENMODE_FAIL_IF_NOT_EXIST, MF_FILEFLAGS_NONE, url, out);
463 HRESULT file_scheme_handler_construct(REFIID riid, void **obj)
465 struct scheme_handler *handler;
466 HRESULT hr;
468 TRACE("%s, %p.\n", debugstr_guid(riid), obj);
470 if (!(handler = calloc(1, sizeof(*handler))))
471 return E_OUTOFMEMORY;
473 handler->IMFSchemeHandler_iface.lpVtbl = &scheme_handler_vtbl;
474 handler->IMFAsyncCallback_iface.lpVtbl = &scheme_handler_callback_vtbl;
475 handler->refcount = 1;
476 list_init(&handler->results);
477 InitializeCriticalSection(&handler->cs);
478 handler->create_stream = file_stream_create;
480 hr = IMFSchemeHandler_QueryInterface(&handler->IMFSchemeHandler_iface, riid, obj);
481 IMFSchemeHandler_Release(&handler->IMFSchemeHandler_iface);
483 return hr;
486 static HRESULT urlmon_stream_create(const WCHAR *url, DWORD flags, IMFByteStream **out)
488 IMFAttributes *attributes;
489 IStream *stream;
490 HRESULT hr;
492 if (flags & MF_RESOLUTION_WRITE)
493 return E_INVALIDARG;
495 if (FAILED(hr = URLOpenBlockingStreamW(NULL, url, &stream, 0, NULL)))
497 WARN("Failed to open url %s, hr %#lx\n", debugstr_w(url), hr);
498 return hr;
501 hr = MFCreateMFByteStreamOnStream(stream, out);
502 IStream_Release(stream);
503 if (FAILED(hr))
504 return hr;
506 IMFByteStream_QueryInterface(*out, &IID_IMFAttributes, (void **)&attributes);
507 IMFAttributes_DeleteItem(attributes, &MF_BYTESTREAM_ORIGIN_NAME);
508 IMFAttributes_SetString(attributes, &MF_BYTESTREAM_EFFECTIVE_URL, url);
509 IMFAttributes_SetString(attributes, &MF_BYTESTREAM_CONTENT_TYPE, L"application/octet-stream");
510 IMFAttributes_Release(attributes);
511 return hr;
514 HRESULT urlmon_scheme_handler_construct(REFIID riid, void **obj)
516 struct scheme_handler *handler;
517 HRESULT hr;
519 TRACE("%s, %p.\n", debugstr_guid(riid), obj);
521 if (!(handler = calloc(1, sizeof(*handler))))
522 return E_OUTOFMEMORY;
524 handler->IMFSchemeHandler_iface.lpVtbl = &scheme_handler_vtbl;
525 handler->IMFAsyncCallback_iface.lpVtbl = &scheme_handler_callback_vtbl;
526 handler->refcount = 1;
527 list_init(&handler->results);
528 InitializeCriticalSection(&handler->cs);
529 handler->create_stream = urlmon_stream_create;
531 hr = IMFSchemeHandler_QueryInterface(&handler->IMFSchemeHandler_iface, riid, obj);
532 IMFSchemeHandler_Release(&handler->IMFSchemeHandler_iface);
534 return hr;