Implement ResetDC and PHYSICALOFFSET[X|Y] devcaps.
[wine] / dlls / quartz / asyncsrc.c
1 /*
2  * Implements Asynchronous File/URL Source.
3  *
4  * FIXME - URL source is not implemented yet.
5  *
6  * Copyright (C) Hidenori TAKESHIMA <hidenori@a2.ctktv.ne.jp>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 #include "config.h"
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "wingdi.h"
28 #include "winuser.h"
29 #include "winerror.h"
30 #include "strmif.h"
31 #include "vfwmsgs.h"
32 #include "uuids.h"
33
34 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
36
37 #include "quartz_private.h"
38 #include "asyncsrc.h"
39 #include "memalloc.h"
40
41
42
43 const WCHAR QUARTZ_wszAsyncFileSourceName[] =
44 {'F','i','l','e',' ','S','o','u','r','c','e',' ','(','A','s','y','n','c','.',')',0};
45 const WCHAR QUARTZ_wszAsyncFileSourcePinName[] =
46 {'O','u','t',0};
47 const WCHAR QUARTZ_wszAsyncURLSourceName[] =
48 {'F','i','l','e',' ','S','o','u','r','c','e',' ','(','U','R','L',')',0};
49 const WCHAR QUARTZ_wszAsyncURLSourcePinName[] =
50 {'O','u','t',0};
51
52
53
54 /***************************************************************************
55  *
56  *      CAsyncReaderImpl internal methods
57  *
58  */
59
60 static
61 AsyncSourceRequest* CAsyncReaderImpl_AllocRequest( CAsyncReaderImpl* This )
62 {
63         AsyncSourceRequest* pReq;
64
65         EnterCriticalSection( &This->m_csFree );
66         pReq = This->m_pFreeFirst;
67         if ( pReq != NULL )
68                 This->m_pFreeFirst = pReq->pNext;
69         LeaveCriticalSection( &This->m_csFree );
70
71         if ( pReq == NULL )
72         {
73                 pReq = (AsyncSourceRequest*)QUARTZ_AllocMem(
74                         sizeof(AsyncSourceRequest) );
75                 if ( pReq == NULL )
76                         return NULL;
77         }
78
79         pReq->pNext = NULL;
80         pReq->llStart = 0;
81         pReq->lLength = 0;
82         pReq->lActual = 0;
83         pReq->pBuf = NULL;
84         pReq->pSample = NULL;
85         pReq->dwContext = 0;
86
87         return pReq;
88 }
89
90 static
91 void CAsyncReaderImpl_FreeRequest( CAsyncReaderImpl* This, AsyncSourceRequest* pReq, BOOL bReleaseMem )
92 {
93         if ( !bReleaseMem )
94         {
95                 EnterCriticalSection( &This->m_csFree );
96                 pReq->pNext = This->m_pFreeFirst;
97                 This->m_pFreeFirst = pReq;
98                 LeaveCriticalSection( &This->m_csFree );
99         }
100         else
101         {
102                 QUARTZ_FreeMem( pReq );
103         }
104 }
105
106 static
107 AsyncSourceRequest* CAsyncReaderImpl_GetRequest( CAsyncReaderImpl* This )
108 {
109         AsyncSourceRequest*     pReq;
110
111         EnterCriticalSection( &This->m_csRequest );
112         pReq = This->m_pRequestFirst;
113         if ( pReq != NULL )
114                 This->m_pRequestFirst = pReq->pNext;
115         LeaveCriticalSection( &This->m_csRequest );
116
117         return pReq;
118 }
119
120 static
121 AsyncSourceRequest* CAsyncReaderImpl_GetReply( CAsyncReaderImpl* This )
122 {
123         AsyncSourceRequest*     pReq;
124
125         EnterCriticalSection( &This->m_csReply );
126         pReq = This->m_pReplyFirst;
127         if ( pReq != NULL )
128                 This->m_pReplyFirst = pReq->pNext;
129         LeaveCriticalSection( &This->m_csReply );
130
131         return pReq;
132 }
133
134 static
135 void CAsyncReaderImpl_PostRequest( CAsyncReaderImpl* This, AsyncSourceRequest* pReq )
136 {
137         /* FIXME - add to tail */
138         EnterCriticalSection( &This->m_csRequest );
139         pReq->pNext = This->m_pRequestFirst;
140         This->m_pRequestFirst = pReq;
141         if ( This->m_hEventReqQueued != (HANDLE)NULL )
142                 SetEvent( This->m_hEventReqQueued );
143         LeaveCriticalSection( &This->m_csRequest );
144 }
145
146 static
147 void CAsyncReaderImpl_PostReply( CAsyncReaderImpl* This, AsyncSourceRequest* pReq )
148 {
149         /* FIXME - add to tail */
150         EnterCriticalSection( &This->m_csReply );
151         pReq->pNext = This->m_pReplyFirst;
152         This->m_pReplyFirst = pReq;
153         if ( This->m_hEventSampQueued != (HANDLE)NULL )
154                 SetEvent( This->m_hEventSampQueued );
155         LeaveCriticalSection( &This->m_csReply );
156 }
157
158 static
159 void CAsyncReaderImpl_ReleaseReqList( CAsyncReaderImpl* This, AsyncSourceRequest** ppReq, BOOL bReleaseMem )
160 {
161         AsyncSourceRequest* pReq;
162         AsyncSourceRequest* pReqNext;
163
164         TRACE("(%p,%p,%d)\n",This,*ppReq,bReleaseMem);
165         pReq = *ppReq; *ppReq = NULL;
166         while ( pReq != NULL )
167         {
168                 pReqNext = pReq->pNext;
169                 CAsyncReaderImpl_FreeRequest(This,pReq,bReleaseMem);
170                 pReq = pReqNext;
171         }
172 }
173
174 static DWORD WINAPI
175 CAsyncReaderImpl_ThreadEntry( LPVOID pv )
176 {
177         CAsyncReaderImpl*       This = (CAsyncReaderImpl*)pv;
178         HANDLE hWaitEvents[2];
179         HRESULT hr;
180         DWORD   dwRes;
181         AsyncSourceRequest*     pReq = NULL;
182
183         SetEvent( This->m_hEventInit );
184
185         hWaitEvents[0] = This->m_hEventReqQueued;
186         hWaitEvents[1] = This->m_hEventCancel;
187
188         TRACE("enter message loop.\n");
189
190         while ( 1 )
191         {
192                 ResetEvent( This->m_hEventReqQueued );
193                 pReq = CAsyncReaderImpl_GetRequest(This);
194                 if ( pReq == NULL )
195                 {
196                         dwRes = WaitForMultipleObjects(2,hWaitEvents,FALSE,INFINITE);
197                         if ( dwRes != WAIT_OBJECT_0 )
198                         {
199                                 if ( This->m_bAbortThread )
200                                         break;
201                         }
202                         continue;
203                 }
204
205                 /* process a queued request */
206                 EnterCriticalSection( &This->m_csReader );
207                 hr = This->pSource->m_pHandler->pRead( This->pSource, pReq->llStart, pReq->lLength, pReq->pBuf, &pReq->lActual, This->m_hEventCancel );
208                 LeaveCriticalSection( &This->m_csReader );
209
210                 if ( FAILED(hr) )
211                 {
212                         /* Notify(ABORT) */
213                         break;
214                 }
215                 if ( hr != S_OK )
216                 {
217                         if ( This->m_bAbortThread )
218                                 break;
219                         ResetEvent( This->m_hEventCancel );
220                 }
221
222                 CAsyncReaderImpl_PostReply( This, pReq );
223                 SetEvent( This->m_hEventSampQueued );
224                 pReq = NULL;
225         }
226
227         if ( pReq != NULL )
228                 CAsyncReaderImpl_PostRequest( This, pReq );
229
230         SetEvent( This->m_hEventSampQueued );
231         return 0;
232 }
233
234 static HRESULT
235 CAsyncReaderImpl_BeginThread( CAsyncReaderImpl* This )
236 {
237         DWORD dwRes;
238         DWORD dwThreadId;
239         HANDLE hEvents[2];
240
241         if ( This->m_hEventInit != (HANDLE)NULL ||
242                  This->m_hEventCancel != (HANDLE)NULL ||
243                  This->m_hEventReqQueued != (HANDLE)NULL ||
244                  This->m_hEventSampQueued != (HANDLE)NULL ||
245                  This->m_hThread != (HANDLE)NULL )
246                 return E_UNEXPECTED;
247         This->m_bAbortThread = FALSE;
248
249         This->m_hEventInit = CreateEventA(NULL,TRUE,FALSE,NULL);
250         if ( This->m_hEventInit == (HANDLE)NULL )
251                 return E_OUTOFMEMORY;
252         This->m_hEventCancel = CreateEventA(NULL,TRUE,FALSE,NULL);
253         if ( This->m_hEventCancel == (HANDLE)NULL )
254                 return E_OUTOFMEMORY;
255         This->m_hEventReqQueued = CreateEventA(NULL,TRUE,FALSE,NULL);
256         if ( This->m_hEventReqQueued == (HANDLE)NULL )
257                 return E_OUTOFMEMORY;
258         This->m_hEventSampQueued = CreateEventA(NULL,TRUE,FALSE,NULL);
259         if ( This->m_hEventSampQueued == (HANDLE)NULL )
260                 return E_OUTOFMEMORY;
261
262         /* create the processing thread. */
263         This->m_hThread = CreateThread(
264                 NULL, 0,
265                 CAsyncReaderImpl_ThreadEntry,
266                 (LPVOID)This,
267                 0, &dwThreadId );
268         if ( This->m_hThread == (HANDLE)NULL )
269                 return E_FAIL;
270
271         hEvents[0] = This->m_hEventInit;
272         hEvents[1] = This->m_hThread;
273
274         dwRes = WaitForMultipleObjects(2,hEvents,FALSE,INFINITE);
275         if ( dwRes != WAIT_OBJECT_0 )
276                 return E_FAIL;
277
278         return NOERROR;
279 }
280
281 static void
282 CAsyncReaderImpl_EndThread( CAsyncReaderImpl* This )
283 {
284         if ( This->m_hThread != (HANDLE)NULL )
285         {
286                 while ( 1 )
287                 {
288                         This->m_bAbortThread = TRUE;
289                         SetEvent( This->m_hEventCancel );
290                         if ( WaitForSingleObject( This->m_hThread, 100 ) == WAIT_OBJECT_0 )
291                                 break;
292                 }
293                 CloseHandle( This->m_hThread );
294                 This->m_hThread = (HANDLE)NULL;
295         }
296         if ( This->m_hEventInit != (HANDLE)NULL )
297         {
298                 CloseHandle( This->m_hEventInit );
299                 This->m_hEventInit = (HANDLE)NULL;
300         }
301         if ( This->m_hEventCancel != (HANDLE)NULL )
302         {
303                 CloseHandle( This->m_hEventCancel );
304                 This->m_hEventCancel = (HANDLE)NULL;
305         }
306         if ( This->m_hEventReqQueued != (HANDLE)NULL )
307         {
308                 CloseHandle( This->m_hEventReqQueued );
309                 This->m_hEventReqQueued = (HANDLE)NULL;
310         }
311         if ( This->m_hEventSampQueued != (HANDLE)NULL )
312         {
313                 CloseHandle( This->m_hEventSampQueued );
314                 This->m_hEventSampQueued = (HANDLE)NULL;
315         }
316 }
317
318 /***************************************************************************
319  *
320  *      CAsyncReaderImpl methods
321  *
322  */
323
324 static HRESULT WINAPI
325 CAsyncReaderImpl_fnQueryInterface(IAsyncReader* iface,REFIID riid,void** ppobj)
326 {
327         ICOM_THIS(CAsyncReaderImpl,iface);
328
329         TRACE("(%p)->()\n",This);
330
331         return IUnknown_QueryInterface(This->punkControl,riid,ppobj);
332 }
333
334 static ULONG WINAPI
335 CAsyncReaderImpl_fnAddRef(IAsyncReader* iface)
336 {
337         ICOM_THIS(CAsyncReaderImpl,iface);
338
339         TRACE("(%p)->()\n",This);
340
341         return IUnknown_AddRef(This->punkControl);
342 }
343
344 static ULONG WINAPI
345 CAsyncReaderImpl_fnRelease(IAsyncReader* iface)
346 {
347         ICOM_THIS(CAsyncReaderImpl,iface);
348
349         TRACE("(%p)->()\n",This);
350
351         return IUnknown_Release(This->punkControl);
352 }
353
354 static HRESULT WINAPI
355 CAsyncReaderImpl_fnRequestAllocator(IAsyncReader* iface,IMemAllocator* pAlloc,ALLOCATOR_PROPERTIES* pProp,IMemAllocator** ppAllocActual)
356 {
357         ICOM_THIS(CAsyncReaderImpl,iface);
358         HRESULT hr;
359         ALLOCATOR_PROPERTIES    propActual;
360         IUnknown* punk = NULL;
361
362         TRACE("(%p)->(%p,%p,%p)\n",This,pAlloc,pProp,ppAllocActual);
363
364         if ( pAlloc == NULL || pProp == NULL || ppAllocActual == NULL )
365                 return E_POINTER;
366
367         IMemAllocator_AddRef(pAlloc);
368         hr = IMemAllocator_SetProperties( pAlloc, pProp, &propActual );
369         if ( SUCCEEDED(hr) )
370         {
371                 *ppAllocActual = pAlloc;
372                 return S_OK;
373         }
374         IMemAllocator_Release(pAlloc);
375
376         hr = QUARTZ_CreateMemoryAllocator(NULL,(void**)&punk);
377         if ( FAILED(hr) )
378                 return hr;
379         hr = IUnknown_QueryInterface( punk, &IID_IMemAllocator, (void**)&pAlloc );
380         IUnknown_Release(punk);
381         if ( FAILED(hr) )
382                 return hr;
383
384         hr = IMemAllocator_SetProperties( pAlloc, pProp, &propActual );
385         if ( SUCCEEDED(hr) )
386         {
387                 *ppAllocActual = pAlloc;
388                 return S_OK;
389         }
390         IMemAllocator_Release(pAlloc);
391
392         return hr;
393 }
394
395 static HRESULT WINAPI
396 CAsyncReaderImpl_fnRequest(IAsyncReader* iface,IMediaSample* pSample,DWORD_PTR dwContext)
397 {
398         ICOM_THIS(CAsyncReaderImpl,iface);
399         HRESULT hr = NOERROR;
400         REFERENCE_TIME  rtStart;
401         REFERENCE_TIME  rtEnd;
402         AsyncSourceRequest*     pReq;
403         BYTE*   pData = NULL;
404
405         TRACE("(%p)->(%p,%u)\n",This,pSample,dwContext);
406
407         hr = IMediaSample_GetPointer(pSample,&pData);
408         if ( SUCCEEDED(hr) )
409                 hr = IMediaSample_GetTime(pSample,&rtStart,&rtEnd);
410         if ( FAILED(hr) )
411                 return hr;
412
413         pReq = CAsyncReaderImpl_AllocRequest(This);
414         if ( pReq == NULL )
415                 return E_OUTOFMEMORY;
416
417         pReq->llStart = rtStart / QUARTZ_TIMEUNITS;
418         pReq->lLength = (LONG)(rtEnd / QUARTZ_TIMEUNITS - rtStart / QUARTZ_TIMEUNITS);
419         pReq->lActual = 0;
420         pReq->pBuf = pData;
421         pReq->pSample = pSample;
422         pReq->dwContext = dwContext;
423         CAsyncReaderImpl_PostRequest( This, pReq );
424
425         return NOERROR;
426 }
427
428 static HRESULT WINAPI
429 CAsyncReaderImpl_fnWaitForNext(IAsyncReader* iface,DWORD dwTimeout,IMediaSample** ppSample,DWORD_PTR* pdwContext)
430 {
431         ICOM_THIS(CAsyncReaderImpl,iface);
432         HRESULT hr = NOERROR;
433         DWORD dwRes;
434         AsyncSourceRequest*     pReq;
435         REFERENCE_TIME  rtStart;
436         REFERENCE_TIME  rtEnd;
437
438         TRACE("(%p)->(%lu,%p,%p)\n",This,dwTimeout,ppSample,pdwContext);
439
440         EnterCriticalSection( &This->m_csRequest );
441         if ( This->m_bInFlushing )
442                 hr = VFW_E_TIMEOUT;
443         LeaveCriticalSection( &This->m_csRequest );
444
445         if ( hr == NOERROR )
446         {
447                 ResetEvent( This->m_hEventSampQueued );
448                 pReq = CAsyncReaderImpl_GetReply(This);
449                 if ( pReq == NULL )
450                 {
451                         dwRes = WaitForSingleObject( This->m_hEventSampQueued, dwTimeout );
452                         if ( dwRes == WAIT_OBJECT_0 )
453                                 pReq = CAsyncReaderImpl_GetReply(This);
454                 }
455                 if ( pReq != NULL )
456                 {
457                         hr = IMediaSample_SetActualDataLength(pReq->pSample,pReq->lActual);
458                         if ( hr == S_OK )
459                         {
460                                 rtStart = pReq->llStart * QUARTZ_TIMEUNITS;
461                                 rtEnd = (pReq->llStart + pReq->lActual) * QUARTZ_TIMEUNITS;
462                                 hr = IMediaSample_SetTime(pReq->pSample,&rtStart,&rtEnd);
463                         }
464                         *ppSample = pReq->pSample;
465                         *pdwContext = pReq->dwContext;
466                         if ( hr == S_OK && pReq->lActual != pReq->lLength )
467                                 hr = S_FALSE;
468                 }
469                 else
470                 {
471                         hr = VFW_E_TIMEOUT;
472                 }
473         }
474
475         return hr;
476 }
477
478 static HRESULT WINAPI
479 CAsyncReaderImpl_fnSyncReadAligned(IAsyncReader* iface,IMediaSample* pSample)
480 {
481         ICOM_THIS(CAsyncReaderImpl,iface);
482         HRESULT hr;
483         REFERENCE_TIME  rtStart;
484         REFERENCE_TIME  rtEnd;
485         BYTE*   pData = NULL;
486         LONGLONG        llStart;
487         LONG    lLength;
488         LONG    lActual;
489
490         TRACE("(%p)->(%p)\n",This,pSample);
491
492         hr = IMediaSample_GetPointer(pSample,&pData);
493         if ( SUCCEEDED(hr) )
494                 hr = IMediaSample_GetTime(pSample,&rtStart,&rtEnd);
495         if ( FAILED(hr) )
496                 return hr;
497
498         llStart = rtStart / QUARTZ_TIMEUNITS;
499         lLength = (LONG)(rtEnd / QUARTZ_TIMEUNITS - rtStart / QUARTZ_TIMEUNITS);
500         lActual = 0;
501
502         EnterCriticalSection( &This->m_csReader );
503         hr = This->pSource->m_pHandler->pRead( This->pSource, llStart, lLength, pData, &lActual, (HANDLE)NULL );
504         LeaveCriticalSection( &This->m_csReader );
505
506         if ( hr == NOERROR )
507         {
508                 hr = IMediaSample_SetActualDataLength(pSample,lActual);
509                 if ( hr == S_OK )
510                 {
511                         rtStart = llStart * QUARTZ_TIMEUNITS;
512                         rtEnd = (llStart + lActual) * QUARTZ_TIMEUNITS;
513                         hr = IMediaSample_SetTime(pSample,&rtStart,&rtEnd);
514                 }
515                 if ( hr == S_OK && lActual != lLength )
516                         hr = S_FALSE;
517         }
518
519         return hr;
520 }
521
522 static HRESULT WINAPI
523 CAsyncReaderImpl_fnSyncRead(IAsyncReader* iface,LONGLONG llPosStart,LONG lLength,BYTE* pbBuf)
524 {
525         ICOM_THIS(CAsyncReaderImpl,iface);
526         HRESULT hr;
527         LONG lActual;
528
529         TRACE("(%p)->()\n",This);
530
531         EnterCriticalSection( &This->m_csReader );
532         hr = This->pSource->m_pHandler->pRead( This->pSource, llPosStart, lLength, pbBuf, &lActual, (HANDLE)NULL );
533         LeaveCriticalSection( &This->m_csReader );
534
535         if ( hr == S_OK && lLength != lActual )
536                 hr = S_FALSE;
537
538         return hr;
539 }
540
541 static HRESULT WINAPI
542 CAsyncReaderImpl_fnLength(IAsyncReader* iface,LONGLONG* pllTotal,LONGLONG* pllAvailable)
543 {
544         ICOM_THIS(CAsyncReaderImpl,iface);
545         HRESULT hr;
546
547         TRACE("(%p)->()\n",This);
548
549         hr = This->pSource->m_pHandler->pGetLength( This->pSource, pllTotal, pllAvailable );
550
551         return hr;
552 }
553
554 static HRESULT WINAPI
555 CAsyncReaderImpl_fnBeginFlush(IAsyncReader* iface)
556 {
557         ICOM_THIS(CAsyncReaderImpl,iface);
558
559         TRACE("(%p)->()\n",This);
560
561         EnterCriticalSection( &This->m_csRequest );
562         This->m_bInFlushing = TRUE;
563         SetEvent( This->m_hEventCancel );
564         CAsyncReaderImpl_ReleaseReqList(This,&This->m_pRequestFirst,FALSE);
565         LeaveCriticalSection( &This->m_csRequest );
566
567         return NOERROR;
568 }
569
570 static HRESULT WINAPI
571 CAsyncReaderImpl_fnEndFlush(IAsyncReader* iface)
572 {
573         ICOM_THIS(CAsyncReaderImpl,iface);
574
575         TRACE("(%p)->()\n",This);
576
577         EnterCriticalSection( &This->m_csRequest );
578         This->m_bInFlushing = FALSE;
579         ResetEvent( This->m_hEventCancel );
580         LeaveCriticalSection( &This->m_csRequest );
581
582         return NOERROR;
583 }
584
585
586 static ICOM_VTABLE(IAsyncReader) iasyncreader =
587 {
588         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
589         /* IUnknown fields */
590         CAsyncReaderImpl_fnQueryInterface,
591         CAsyncReaderImpl_fnAddRef,
592         CAsyncReaderImpl_fnRelease,
593
594         /* IAsyncReader fields */
595         CAsyncReaderImpl_fnRequestAllocator,
596         CAsyncReaderImpl_fnRequest,
597         CAsyncReaderImpl_fnWaitForNext,
598         CAsyncReaderImpl_fnSyncReadAligned,
599         CAsyncReaderImpl_fnSyncRead,
600         CAsyncReaderImpl_fnLength,
601         CAsyncReaderImpl_fnBeginFlush,
602         CAsyncReaderImpl_fnEndFlush,
603 };
604
605 HRESULT CAsyncReaderImpl_InitIAsyncReader(
606         CAsyncReaderImpl* This, IUnknown* punkControl,
607         CAsyncSourceImpl* pSource )
608 {
609         TRACE("(%p,%p)\n",This,punkControl);
610
611         if ( punkControl == NULL )
612         {
613                 ERR( "punkControl must not be NULL\n" );
614                 return E_INVALIDARG;
615         }
616
617         ICOM_VTBL(This) = &iasyncreader;
618         This->punkControl = punkControl;
619         This->pSource = pSource;
620         This->m_bInFlushing = FALSE;
621         This->m_bAbortThread = FALSE;
622         This->m_hEventInit = (HANDLE)NULL;
623         This->m_hEventCancel = (HANDLE)NULL;
624         This->m_hEventReqQueued = (HANDLE)NULL;
625         This->m_hEventSampQueued = (HANDLE)NULL;
626         This->m_hThread = (HANDLE)NULL;
627         This->m_pRequestFirst = NULL;
628         This->m_pReplyFirst = NULL;
629         This->m_pFreeFirst = NULL;
630
631         InitializeCriticalSection( &This->m_csReader );
632         InitializeCriticalSection( &This->m_csRequest );
633         InitializeCriticalSection( &This->m_csReply );
634         InitializeCriticalSection( &This->m_csFree );
635
636         return NOERROR;
637 }
638
639 void CAsyncReaderImpl_UninitIAsyncReader(
640         CAsyncReaderImpl* This )
641 {
642         TRACE("(%p) enter\n",This);
643
644         CAsyncReaderImpl_ReleaseReqList(This,&This->m_pRequestFirst,TRUE);
645         CAsyncReaderImpl_ReleaseReqList(This,&This->m_pReplyFirst,TRUE);
646         CAsyncReaderImpl_ReleaseReqList(This,&This->m_pFreeFirst,TRUE);
647
648         DeleteCriticalSection( &This->m_csReader );
649         DeleteCriticalSection( &This->m_csRequest );
650         DeleteCriticalSection( &This->m_csReply );
651         DeleteCriticalSection( &This->m_csFree );
652
653         TRACE("(%p) leave\n",This);
654 }
655
656 /***************************************************************************
657  *
658  *      CFileSourceFilterImpl
659  *
660  */
661
662 static HRESULT WINAPI
663 CFileSourceFilterImpl_fnQueryInterface(IFileSourceFilter* iface,REFIID riid,void** ppobj)
664 {
665         ICOM_THIS(CFileSourceFilterImpl,iface);
666
667         TRACE("(%p)->()\n",This);
668
669         return IUnknown_QueryInterface(This->punkControl,riid,ppobj);
670 }
671
672 static ULONG WINAPI
673 CFileSourceFilterImpl_fnAddRef(IFileSourceFilter* iface)
674 {
675         ICOM_THIS(CFileSourceFilterImpl,iface);
676
677         TRACE("(%p)->()\n",This);
678
679         return IUnknown_AddRef(This->punkControl);
680 }
681
682 static ULONG WINAPI
683 CFileSourceFilterImpl_fnRelease(IFileSourceFilter* iface)
684 {
685         ICOM_THIS(CFileSourceFilterImpl,iface);
686
687         TRACE("(%p)->()\n",This);
688
689         return IUnknown_Release(This->punkControl);
690 }
691
692 static HRESULT WINAPI
693 CFileSourceFilterImpl_fnLoad(IFileSourceFilter* iface,LPCOLESTR pFileName,const AM_MEDIA_TYPE* pmt)
694 {
695         ICOM_THIS(CFileSourceFilterImpl,iface);
696         HRESULT hr;
697
698         TRACE("(%p)->(%s,%p)\n",This,debugstr_w(pFileName),pmt);
699
700         if ( pFileName == NULL )
701                 return E_POINTER;
702
703         if ( This->m_pwszFileName != NULL )
704                 return E_UNEXPECTED;
705
706         This->m_cbFileName = sizeof(WCHAR)*(lstrlenW(pFileName)+1);
707         This->m_pwszFileName = (WCHAR*)QUARTZ_AllocMem( This->m_cbFileName );
708         if ( This->m_pwszFileName == NULL )
709                 return E_OUTOFMEMORY;
710         memcpy( This->m_pwszFileName, pFileName, This->m_cbFileName );
711
712         if ( pmt != NULL )
713         {
714                 hr = QUARTZ_MediaType_Copy( &This->m_mt, pmt );
715                 if ( FAILED(hr) )
716                         goto err;
717         }
718         else
719         {
720                 ZeroMemory( &This->m_mt, sizeof(AM_MEDIA_TYPE) );
721                 memcpy( &This->m_mt.majortype, &MEDIATYPE_Stream, sizeof(GUID) );
722                 memcpy( &This->m_mt.subtype, &MEDIASUBTYPE_NULL, sizeof(GUID) );
723                 This->m_mt.lSampleSize = 1;
724                 memcpy( &This->m_mt.formattype, &FORMAT_None, sizeof(GUID) );
725         }
726
727         hr = This->pSource->m_pHandler->pLoad( This->pSource, pFileName );
728         if ( FAILED(hr) )
729                 goto err;
730
731         This->pSource->pPin->pin.pmtAcceptTypes = &This->m_mt;
732         This->pSource->pPin->pin.cAcceptTypes = 1;
733
734         return NOERROR;
735 err:;
736         return hr;
737 }
738
739 static HRESULT WINAPI
740 CFileSourceFilterImpl_fnGetCurFile(IFileSourceFilter* iface,LPOLESTR* ppFileName,AM_MEDIA_TYPE* pmt)
741 {
742         ICOM_THIS(CFileSourceFilterImpl,iface);
743         HRESULT hr = E_NOTIMPL;
744
745         TRACE("(%p)->(%p,%p)\n",This,ppFileName,pmt);
746
747         if ( ppFileName == NULL || pmt == NULL )
748                 return E_POINTER;
749
750         if ( This->m_pwszFileName == NULL )
751                 return E_FAIL;
752
753         hr = QUARTZ_MediaType_Copy( pmt, &This->m_mt );
754         if ( FAILED(hr) )
755                 return hr;
756
757         *ppFileName = (WCHAR*)CoTaskMemAlloc( This->m_cbFileName );
758         if ( *ppFileName == NULL )
759         {
760                 QUARTZ_MediaType_Free(pmt);
761                 ZeroMemory( pmt, sizeof(AM_MEDIA_TYPE) );
762                 return E_OUTOFMEMORY;
763         }
764
765         memcpy( *ppFileName, This->m_pwszFileName, This->m_cbFileName );
766
767         return NOERROR;
768 }
769
770 static ICOM_VTABLE(IFileSourceFilter) ifilesource =
771 {
772         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
773         /* IUnknown fields */
774         CFileSourceFilterImpl_fnQueryInterface,
775         CFileSourceFilterImpl_fnAddRef,
776         CFileSourceFilterImpl_fnRelease,
777         /* IFileSourceFilter fields */
778         CFileSourceFilterImpl_fnLoad,
779         CFileSourceFilterImpl_fnGetCurFile,
780 };
781
782 HRESULT CFileSourceFilterImpl_InitIFileSourceFilter(
783         CFileSourceFilterImpl* This, IUnknown* punkControl,
784         CAsyncSourceImpl* pSource,
785         CRITICAL_SECTION* pcsFileSource )
786 {
787         TRACE("(%p,%p)\n",This,punkControl);
788
789         if ( punkControl == NULL )
790         {
791                 ERR( "punkControl must not be NULL\n" );
792                 return E_INVALIDARG;
793         }
794
795         ICOM_VTBL(This) = &ifilesource;
796         This->punkControl = punkControl;
797         This->pSource = pSource;
798         This->pcsFileSource = pcsFileSource;
799         This->m_pwszFileName = NULL;
800         This->m_cbFileName = 0;
801         ZeroMemory( &This->m_mt, sizeof(AM_MEDIA_TYPE) );
802
803         return NOERROR;
804 }
805
806 void CFileSourceFilterImpl_UninitIFileSourceFilter(
807         CFileSourceFilterImpl* This )
808 {
809         TRACE("(%p)\n",This);
810
811         This->pSource->m_pHandler->pCleanup( This->pSource );
812         if ( This->m_pwszFileName != NULL )
813                 QUARTZ_FreeMem( This->m_pwszFileName );
814         QUARTZ_MediaType_Free( &This->m_mt );
815 }
816
817 /***************************************************************************
818  *
819  *      CAsyncSourcePinImpl methods
820  *
821  */
822
823
824 static HRESULT CAsyncSourcePinImpl_OnPreConnect( CPinBaseImpl* pImpl, IPin* pPin )
825 {
826         CAsyncSourcePinImpl_THIS(pImpl,pin);
827
828         TRACE("(%p,%p)\n",This,pPin);
829
830         This->bAsyncReaderQueried = FALSE;
831
832         return NOERROR;
833 }
834
835 static HRESULT CAsyncSourcePinImpl_OnPostConnect( CPinBaseImpl* pImpl, IPin* pPin )
836 {
837         CAsyncSourcePinImpl_THIS(pImpl,pin);
838
839         TRACE("(%p,%p)\n",This,pPin);
840
841         if ( !This->bAsyncReaderQueried )
842                 return E_FAIL;
843
844         return NOERROR;
845 }
846
847 static HRESULT CAsyncSourcePinImpl_OnDisconnect( CPinBaseImpl* pImpl )
848 {
849         CAsyncSourcePinImpl_THIS(pImpl,pin);
850
851         TRACE("(%p)\n",This);
852
853         This->bAsyncReaderQueried = FALSE;
854
855         return NOERROR;
856 }
857
858 static HRESULT CAsyncSourcePinImpl_CheckMediaType( CPinBaseImpl* pImpl, const AM_MEDIA_TYPE* pmt )
859 {
860         CAsyncSourcePinImpl_THIS(pImpl,pin);
861
862         TRACE("(%p,%p)\n",This,pmt);
863         if ( pmt == NULL )
864                 return E_POINTER;
865
866         if ( !IsEqualGUID( &pmt->majortype, &MEDIATYPE_Stream ) )
867                 return E_FAIL;
868
869         return NOERROR;
870 }
871
872 static const CBasePinHandlers outputpinhandlers =
873 {
874         CAsyncSourcePinImpl_OnPreConnect, /* pOnPreConnect */
875         CAsyncSourcePinImpl_OnPostConnect, /* pOnPostConnect */
876         CAsyncSourcePinImpl_OnDisconnect, /* pOnDisconnect */
877         CAsyncSourcePinImpl_CheckMediaType, /* pCheckMediaType */
878         NULL, /* pQualityNotify */
879         NULL, /* pReceive */
880         NULL, /* pReceiveCanBlock */
881         NULL, /* pEndOfStream */
882         NULL, /* pBeginFlush */
883         NULL, /* pEndFlush */
884         NULL, /* pNewSegment */
885 };
886
887 /***************************************************************************
888  *
889  *      CAsyncSourceImpl methods
890  *
891  */
892
893 static HRESULT CAsyncSourceImpl_OnActive( CBaseFilterImpl* pImpl )
894 {
895         CAsyncSourceImpl_THIS(pImpl,basefilter);
896         HRESULT hr;
897
898         TRACE( "(%p)\n", This );
899
900         hr = CAsyncReaderImpl_BeginThread(&This->pPin->async);
901         if ( FAILED(hr) )
902                 return hr;
903
904         return NOERROR;
905 }
906
907 static HRESULT CAsyncSourceImpl_OnInactive( CBaseFilterImpl* pImpl )
908 {
909         CAsyncSourceImpl_THIS(pImpl,basefilter);
910
911         TRACE( "(%p)\n", This );
912
913         CAsyncReaderImpl_EndThread(&This->pPin->async);
914
915         return NOERROR;
916 }
917
918 static const CBaseFilterHandlers filterhandlers =
919 {
920         CAsyncSourceImpl_OnActive, /* pOnActive */
921         CAsyncSourceImpl_OnInactive, /* pOnInactive */
922         NULL, /* pOnStop */
923 };
924
925 /***************************************************************************
926  *
927  *      new/delete CAsyncSourceImpl
928  *
929  */
930
931 /* can I use offsetof safely? - FIXME? */
932 static QUARTZ_IFEntry FilterIFEntries[] =
933 {
934   { &IID_IPersist, offsetof(CAsyncSourceImpl,basefilter)-offsetof(CAsyncSourceImpl,unk) },
935   { &IID_IMediaFilter, offsetof(CAsyncSourceImpl,basefilter)-offsetof(CAsyncSourceImpl,unk) },
936   { &IID_IBaseFilter, offsetof(CAsyncSourceImpl,basefilter)-offsetof(CAsyncSourceImpl,unk) },
937   { &IID_IFileSourceFilter, offsetof(CAsyncSourceImpl,filesrc)-offsetof(CAsyncSourceImpl,unk) },
938 };
939
940 static void QUARTZ_DestroyAsyncSource(IUnknown* punk)
941 {
942         CAsyncSourceImpl_THIS(punk,unk);
943
944         TRACE( "(%p)\n", This );
945
946         if ( This->pPin != NULL )
947         {
948                 IUnknown_Release(This->pPin->unk.punkControl);
949                 This->pPin = NULL;
950         }
951
952         This->m_pHandler->pCleanup( This );
953
954         CFileSourceFilterImpl_UninitIFileSourceFilter(&This->filesrc);
955         CBaseFilterImpl_UninitIBaseFilter(&This->basefilter);
956
957         DeleteCriticalSection( &This->csFilter );
958 }
959
960 HRESULT QUARTZ_CreateAsyncSource(
961         IUnknown* punkOuter,void** ppobj,
962         const CLSID* pclsidAsyncSource,
963         LPCWSTR pwszAsyncSourceName,
964         LPCWSTR pwszOutPinName,
965         const AsyncSourceHandlers* pHandler )
966 {
967         CAsyncSourceImpl*       This = NULL;
968         HRESULT hr;
969
970         TRACE("(%p,%p)\n",punkOuter,ppobj);
971
972         This = (CAsyncSourceImpl*)
973                 QUARTZ_AllocObj( sizeof(CAsyncSourceImpl) );
974         if ( This == NULL )
975                 return E_OUTOFMEMORY;
976
977         This->pPin = NULL;
978         This->m_pHandler = pHandler;
979         This->m_pUserData = NULL;
980
981         QUARTZ_IUnkInit( &This->unk, punkOuter );
982
983         hr = CBaseFilterImpl_InitIBaseFilter(
984                 &This->basefilter,
985                 This->unk.punkControl,
986                 pclsidAsyncSource,
987                 pwszAsyncSourceName,
988                 &filterhandlers );
989         if ( SUCCEEDED(hr) )
990         {
991                 /* construct this class. */
992                 hr = CFileSourceFilterImpl_InitIFileSourceFilter(
993                         &This->filesrc, This->unk.punkControl,
994                         This, &This->csFilter );
995                 if ( FAILED(hr) )
996                 {
997                         CBaseFilterImpl_UninitIBaseFilter(&This->basefilter);
998                 }
999         }
1000
1001         if ( FAILED(hr) )
1002         {
1003                 QUARTZ_FreeObj(This);
1004                 return hr;
1005         }
1006
1007         This->unk.pEntries = FilterIFEntries;
1008         This->unk.dwEntries = sizeof(FilterIFEntries)/sizeof(FilterIFEntries[0]);
1009         This->unk.pOnFinalRelease = QUARTZ_DestroyAsyncSource;
1010         InitializeCriticalSection( &This->csFilter );
1011
1012         /* create the output pin. */
1013         hr = QUARTZ_CreateAsyncSourcePin(
1014                 This, &This->csFilter,
1015                 &This->pPin, pwszOutPinName );
1016         if ( SUCCEEDED(hr) )
1017                 hr = QUARTZ_CompList_AddComp(
1018                         This->basefilter.pOutPins,
1019                         (IUnknown*)&(This->pPin->pin),
1020                         NULL, 0 );
1021
1022         if ( FAILED(hr) )
1023         {
1024                 IUnknown_Release( This->unk.punkControl );
1025                 return hr;
1026         }
1027
1028         *ppobj = (void*)&(This->unk);
1029
1030         return S_OK;
1031 }
1032
1033 /***************************************************************************
1034  *
1035  *      new/delete CAsyncSourcePinImpl
1036  *
1037  */
1038
1039 /* can I use offsetof safely? - FIXME? */
1040 static QUARTZ_IFEntry OutPinIFEntries[] =
1041 {
1042   { &IID_IPin, offsetof(CAsyncSourcePinImpl,pin)-offsetof(CAsyncSourcePinImpl,unk) },
1043   /***{ &IID_IAsyncReader, offsetof(CAsyncSourcePinImpl,async)-offsetof(CAsyncSourcePinImpl,unk) },***/
1044 };
1045
1046 static HRESULT CAsyncSourceImpl_OnQueryInterface(
1047         IUnknown* punk, const IID* piid, void** ppobj )
1048 {
1049         CAsyncSourcePinImpl_THIS(punk,unk);
1050
1051         if ( IsEqualGUID( &IID_IAsyncReader, piid ) )
1052         {
1053                 TRACE("IAsyncReader has been queried.\n");
1054                 *ppobj = (void*)&This->async;
1055                 IUnknown_AddRef(punk);
1056                 This->bAsyncReaderQueried = TRUE;
1057                 return S_OK;
1058         }
1059
1060         return E_NOINTERFACE;
1061 }
1062
1063 static void QUARTZ_DestroyAsyncSourcePin(IUnknown* punk)
1064 {
1065         CAsyncSourcePinImpl_THIS(punk,unk);
1066
1067         TRACE( "(%p)\n", This );
1068
1069         CAsyncReaderImpl_UninitIAsyncReader( &This->async );
1070         CPinBaseImpl_UninitIPin( &This->pin );
1071 }
1072
1073 HRESULT QUARTZ_CreateAsyncSourcePin(
1074         CAsyncSourceImpl* pFilter,
1075         CRITICAL_SECTION* pcsPin,
1076         CAsyncSourcePinImpl** ppPin,
1077         LPCWSTR pwszPinName )
1078 {
1079         CAsyncSourcePinImpl*    This = NULL;
1080         HRESULT hr;
1081
1082         TRACE("(%p,%p,%p)\n",pFilter,pcsPin,ppPin);
1083
1084         This = (CAsyncSourcePinImpl*)
1085                 QUARTZ_AllocObj( sizeof(CAsyncSourcePinImpl) );
1086         if ( This == NULL )
1087                 return E_OUTOFMEMORY;
1088
1089         QUARTZ_IUnkInit( &This->unk, NULL );
1090         This->qiext.pNext = NULL;
1091         This->qiext.pOnQueryInterface = &CAsyncSourceImpl_OnQueryInterface;
1092         QUARTZ_IUnkAddDelegation( &This->unk, &This->qiext );
1093
1094         This->bAsyncReaderQueried = FALSE;
1095         This->pSource = pFilter;
1096
1097         hr = CPinBaseImpl_InitIPin(
1098                 &This->pin,
1099                 This->unk.punkControl,
1100                 pcsPin, NULL,
1101                 &pFilter->basefilter,
1102                 pwszPinName,
1103                 TRUE,
1104                 &outputpinhandlers );
1105
1106         if ( SUCCEEDED(hr) )
1107         {
1108                 hr = CAsyncReaderImpl_InitIAsyncReader(
1109                         &This->async,
1110                         This->unk.punkControl,
1111                         pFilter );
1112                 if ( FAILED(hr) )
1113                 {
1114                         CPinBaseImpl_UninitIPin( &This->pin );
1115                 }
1116         }
1117
1118         if ( FAILED(hr) )
1119         {
1120                 QUARTZ_FreeObj(This);
1121                 return hr;
1122         }
1123
1124         This->unk.pEntries = OutPinIFEntries;
1125         This->unk.dwEntries = sizeof(OutPinIFEntries)/sizeof(OutPinIFEntries[0]);
1126         This->unk.pOnFinalRelease = QUARTZ_DestroyAsyncSourcePin;
1127
1128         *ppPin = This;
1129
1130         TRACE("returned successfully.\n");
1131
1132         return S_OK;
1133 }
1134
1135
1136
1137 /***************************************************************************
1138  *
1139  *      Implements File Source.
1140  *
1141  */
1142
1143 typedef struct AsyncSourceFileImpl
1144 {
1145         HANDLE  hFile;
1146         LONGLONG        llTotal;
1147 } AsyncSourceFileImpl;
1148
1149
1150 static HRESULT AsyncSourceFileImpl_Load( CAsyncSourceImpl* pImpl, LPCWSTR lpwszSourceName )
1151 {
1152         AsyncSourceFileImpl*    This = (AsyncSourceFileImpl*)pImpl->m_pUserData;
1153         DWORD   dwLow;
1154         DWORD   dwHigh;
1155
1156         if ( This != NULL )
1157                 return E_UNEXPECTED;
1158         This = (AsyncSourceFileImpl*)QUARTZ_AllocMem( sizeof(AsyncSourceFileImpl) );
1159         pImpl->m_pUserData = (void*)This;
1160         if ( This == NULL )
1161                 return E_OUTOFMEMORY;
1162         This->hFile = INVALID_HANDLE_VALUE;
1163         This->llTotal = 0;
1164
1165         This->hFile = CreateFileW( lpwszSourceName,
1166                 GENERIC_READ, FILE_SHARE_READ,
1167                 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL );
1168         if ( This->hFile == INVALID_HANDLE_VALUE )
1169                 return E_FAIL;
1170
1171         SetLastError(NO_ERROR);
1172         dwLow = GetFileSize( This->hFile, &dwHigh );
1173         if ( dwLow == 0xffffffff && GetLastError() != NO_ERROR )
1174                 return E_FAIL;
1175
1176         This->llTotal = (LONGLONG)dwLow | ((LONGLONG)dwHigh << 32);
1177
1178         return NOERROR;
1179 }
1180
1181 static HRESULT AsyncSourceFileImpl_Cleanup( CAsyncSourceImpl* pImpl )
1182 {
1183         AsyncSourceFileImpl*    This = (AsyncSourceFileImpl*)pImpl->m_pUserData;
1184
1185         if ( This == NULL )
1186                 return NOERROR;
1187
1188         if ( This->hFile != INVALID_HANDLE_VALUE )
1189                 CloseHandle(This->hFile);
1190
1191         QUARTZ_FreeMem(This);
1192         pImpl->m_pUserData = NULL;
1193
1194         return NOERROR;
1195 }
1196
1197 static HRESULT AsyncSourceFileImpl_GetLength( CAsyncSourceImpl* pImpl, LONGLONG* pllTotal, LONGLONG* pllAvailable )
1198 {
1199         AsyncSourceFileImpl*    This = (AsyncSourceFileImpl*)pImpl->m_pUserData;
1200
1201         if ( This == NULL )
1202                 return E_UNEXPECTED;
1203
1204         *pllTotal = This->llTotal;
1205         *pllAvailable = This->llTotal;
1206
1207         return NOERROR;
1208 }
1209
1210 static HRESULT AsyncSourceFileImpl_Read( CAsyncSourceImpl* pImpl, LONGLONG llOfsStart, LONG lLength, BYTE* pBuf, LONG* plReturned, HANDLE hEventCancel )
1211 {
1212         AsyncSourceFileImpl*    This = (AsyncSourceFileImpl*)pImpl->m_pUserData;
1213         LONG    lReturned;
1214         LONG    lBlock;
1215         LONG    lOfsLow;
1216         LONG    lOfsHigh;
1217         DWORD   dw;
1218         HRESULT hr = S_OK;
1219
1220         if ( This == NULL || This->hFile == INVALID_HANDLE_VALUE )
1221                 return E_UNEXPECTED;
1222
1223         lReturned = 0;
1224
1225         lOfsLow = (LONG)(llOfsStart & 0xffffffff);
1226         lOfsHigh = (LONG)(llOfsStart >> 32);
1227         SetLastError(NO_ERROR);
1228         lOfsLow = SetFilePointer( This->hFile, lOfsLow, &lOfsHigh, FILE_BEGIN );
1229         if ( lOfsLow == (LONG)0xffffffff && GetLastError() != NO_ERROR )
1230                 return E_FAIL;
1231
1232         while ( lLength > 0 )
1233         {
1234                 if ( hEventCancel != (HANDLE)NULL &&
1235                          WaitForSingleObject( hEventCancel, 0 ) == WAIT_OBJECT_0 )
1236                 {
1237                         hr = S_FALSE;
1238                         break;
1239                 }
1240
1241                 lBlock = ( lLength > ASYNCSRC_FILE_BLOCKSIZE ) ?
1242                         ASYNCSRC_FILE_BLOCKSIZE : lLength;
1243
1244                 if ( !ReadFile(This->hFile,pBuf,(DWORD)lBlock,&dw,NULL) )
1245                 {
1246                         hr = E_FAIL;
1247                         break;
1248                 }
1249                 pBuf += dw;
1250                 lReturned += (LONG)dw;
1251                 lLength -= (LONG)dw;
1252                 if ( lBlock > (LONG)dw )
1253                         break;
1254         }
1255
1256         *plReturned = lReturned;
1257
1258         return hr;
1259 }
1260
1261 static const struct AsyncSourceHandlers asyncsrc_file =
1262 {
1263         AsyncSourceFileImpl_Load,
1264         AsyncSourceFileImpl_Cleanup,
1265         AsyncSourceFileImpl_GetLength,
1266         AsyncSourceFileImpl_Read,
1267 };
1268
1269 HRESULT QUARTZ_CreateAsyncReader(IUnknown* punkOuter,void** ppobj)
1270 {
1271         return QUARTZ_CreateAsyncSource(
1272                 punkOuter, ppobj,
1273                 &CLSID_AsyncReader,
1274                 QUARTZ_wszAsyncFileSourceName,
1275                 QUARTZ_wszAsyncFileSourcePinName,
1276                 &asyncsrc_file );
1277 }
1278
1279 /***************************************************************************
1280  *
1281  *      Implements URL Source.
1282  *
1283  */
1284
1285 typedef struct AsyncSourceURLImpl
1286 {
1287         DWORD dwDummy;
1288 } AsyncSourceURLImpl;
1289
1290
1291 static HRESULT AsyncSourceURLImpl_Load( CAsyncSourceImpl* pImpl, LPCWSTR lpwszSourceName )
1292 {
1293         AsyncSourceURLImpl*     This = (AsyncSourceURLImpl*)pImpl->m_pUserData;
1294
1295         FIXME("(%p,%p) stub!\n", pImpl, lpwszSourceName);
1296
1297         if ( This != NULL )
1298                 return E_UNEXPECTED;
1299         This = (AsyncSourceURLImpl*)QUARTZ_AllocMem( sizeof(AsyncSourceURLImpl) );
1300         pImpl->m_pUserData = (void*)This;
1301         if ( This == NULL )
1302                 return E_OUTOFMEMORY;
1303
1304         return E_NOTIMPL;
1305 }
1306
1307 static HRESULT AsyncSourceURLImpl_Cleanup( CAsyncSourceImpl* pImpl )
1308 {
1309         AsyncSourceURLImpl*     This = (AsyncSourceURLImpl*)pImpl->m_pUserData;
1310
1311         FIXME("(%p) stub!\n", This);
1312
1313         if ( This == NULL )
1314                 return NOERROR;
1315
1316         QUARTZ_FreeMem(This);
1317         pImpl->m_pUserData = NULL;
1318
1319         return NOERROR;
1320 }
1321
1322 static HRESULT AsyncSourceURLImpl_GetLength( CAsyncSourceImpl* pImpl, LONGLONG* pllTotal, LONGLONG* pllAvailable )
1323 {
1324         AsyncSourceURLImpl*     This = (AsyncSourceURLImpl*)pImpl->m_pUserData;
1325
1326         FIXME("(%p,%p,%p) stub!\n", This, pllTotal, pllAvailable);
1327
1328         if ( This == NULL )
1329                 return E_UNEXPECTED;
1330
1331         return E_NOTIMPL;
1332 }
1333
1334 static HRESULT AsyncSourceURLImpl_Read( CAsyncSourceImpl* pImpl, LONGLONG llOfsStart, LONG lLength, BYTE* pBuf, LONG* plReturned, HANDLE hEventCancel )
1335 {
1336         AsyncSourceURLImpl*     This = (AsyncSourceURLImpl*)pImpl->m_pUserData;
1337
1338         FIXME("(%p) stub!\n", This);
1339
1340         if ( This == NULL )
1341                 return E_UNEXPECTED;
1342
1343         return E_NOTIMPL;
1344 }
1345
1346 static const struct AsyncSourceHandlers asyncsrc_url =
1347 {
1348         AsyncSourceURLImpl_Load,
1349         AsyncSourceURLImpl_Cleanup,
1350         AsyncSourceURLImpl_GetLength,
1351         AsyncSourceURLImpl_Read,
1352 };
1353
1354
1355 HRESULT QUARTZ_CreateURLReader(IUnknown* punkOuter,void** ppobj)
1356 {
1357         return QUARTZ_CreateAsyncSource(
1358                 punkOuter, ppobj,
1359                 &CLSID_URLReader,
1360                 QUARTZ_wszAsyncURLSourceName,
1361                 QUARTZ_wszAsyncURLSourcePinName,
1362                 &asyncsrc_url );
1363 }