wined3d: Move shader caps setting into the arb and glsl shader backends.
[wine] / dlls / quartz / filesource.c
1 /*
2  * File Source Filter
3  *
4  * Copyright 2003 Robert Shearman
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #define NONAMELESSUNION
22 #define NONAMELESSSTRUCT
23
24 #include "quartz_private.h"
25
26 #include "wine/debug.h"
27 #include "wine/unicode.h"
28 #include "pin.h"
29 #include "uuids.h"
30 #include "vfwmsgs.h"
31 #include "winbase.h"
32 #include "winreg.h"
33 #include "shlwapi.h"
34 #include <assert.h>
35
36 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
37
38 static const WCHAR wszOutputPinName[] = { 'O','u','t','p','u','t',0 };
39
40 typedef struct AsyncReader
41 {
42     const IBaseFilterVtbl * lpVtbl;
43     const IFileSourceFilterVtbl * lpVtblFSF;
44
45     LONG refCount;
46     FILTER_INFO filterInfo;
47     FILTER_STATE state;
48     CRITICAL_SECTION csFilter;
49
50     IPin * pOutputPin;
51     LPOLESTR pszFileName;
52     AM_MEDIA_TYPE * pmt;
53 } AsyncReader;
54
55 static const IBaseFilterVtbl AsyncReader_Vtbl;
56 static const IFileSourceFilterVtbl FileSource_Vtbl;
57 static const IAsyncReaderVtbl FileAsyncReader_Vtbl;
58
59 static HRESULT FileAsyncReader_Construct(HANDLE hFile, IBaseFilter * pBaseFilter, LPCRITICAL_SECTION pCritSec, IPin ** ppPin);
60
61 static inline AsyncReader *impl_from_IFileSourceFilter( IFileSourceFilter *iface )
62 {
63     return (AsyncReader *)((char*)iface - FIELD_OFFSET(AsyncReader, lpVtblFSF));
64 }
65
66 static WCHAR const mediatype_name[11] = {
67     'M', 'e', 'd', 'i', 'a', ' ', 'T', 'y', 'p', 'e', 0 };
68 static WCHAR const subtype_name[8] = {
69     'S', 'u', 'b', 't', 'y', 'p', 'e', 0 };
70
71 static HRESULT process_extensions(HKEY hkeyExtensions, LPCOLESTR pszFileName, GUID * majorType, GUID * minorType)
72 {
73     WCHAR *extension;
74     LONG l;
75     HKEY hsub;
76     WCHAR keying[39];
77     DWORD size;
78
79     if (!pszFileName)
80         return E_POINTER;
81
82     /* Get the part of the name that matters */
83     extension = PathFindExtensionW(pszFileName);
84     if (*extension != '.')
85         return E_FAIL;
86
87     l = RegOpenKeyExW(hkeyExtensions, extension, 0, KEY_READ, &hsub);
88     if (l)
89         return E_FAIL;
90
91     size = sizeof(keying);
92     l = RegQueryValueExW(hsub, mediatype_name, NULL, NULL, (LPBYTE)keying, &size);
93     if (!l)
94         CLSIDFromString(keying, majorType);
95
96     size = sizeof(keying);
97     if (!l)
98         l = RegQueryValueExW(hsub, subtype_name, NULL, NULL, (LPBYTE)keying, &size);
99     if (!l)
100         CLSIDFromString(keying, minorType);
101
102     RegCloseKey(hsub);
103
104     if (!l)
105         return S_OK;
106     return E_FAIL;
107 }
108
109 static unsigned char byte_from_hex_char(WCHAR wHex)
110 {
111     switch (tolowerW(wHex))
112     {
113     case '0':
114     case '1':
115     case '2':
116     case '3':
117     case '4':
118     case '5':
119     case '6':
120     case '7':
121     case '8':
122     case '9':
123         return (wHex - '0') & 0xf;
124     case 'a':
125     case 'b':
126     case 'c':
127     case 'd':
128     case 'e':
129     case 'f':
130         return (wHex - 'a' + 10) & 0xf;
131     default:
132         return 0;
133     }
134 }
135
136 static HRESULT process_pattern_string(LPCWSTR wszPatternString, IAsyncReader * pReader)
137 {
138     ULONG ulOffset;
139     ULONG ulBytes;
140     BYTE * pbMask;
141     BYTE * pbValue;
142     BYTE * pbFile;
143     HRESULT hr = S_OK;
144     ULONG strpos;
145
146     TRACE("\t\tPattern string: %s\n", debugstr_w(wszPatternString));
147     
148     /* format: "offset, bytestocompare, mask, value" */
149
150     ulOffset = strtolW(wszPatternString, NULL, 10);
151
152     if (!(wszPatternString = strchrW(wszPatternString, ',')))
153         return E_INVALIDARG;
154
155     wszPatternString++; /* skip ',' */
156
157     ulBytes = strtolW(wszPatternString, NULL, 10);
158
159     pbMask = HeapAlloc(GetProcessHeap(), 0, ulBytes);
160     pbValue = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ulBytes);
161     pbFile = HeapAlloc(GetProcessHeap(), 0, ulBytes);
162
163     /* default mask is match everything */
164     memset(pbMask, 0xFF, ulBytes);
165
166     if (!(wszPatternString = strchrW(wszPatternString, ',')))
167         hr = E_INVALIDARG;
168
169     wszPatternString++; /* skip ',' */
170
171     if (hr == S_OK)
172     {
173         for ( ; !isxdigitW(*wszPatternString) && (*wszPatternString != ','); wszPatternString++)
174             ;
175
176         for (strpos = 0; isxdigitW(*wszPatternString) && (strpos/2 < ulBytes); wszPatternString++, strpos++)
177         {
178             if ((strpos % 2) == 1) /* odd numbered position */
179                 pbMask[strpos / 2] |= byte_from_hex_char(*wszPatternString);
180             else
181                 pbMask[strpos / 2] = byte_from_hex_char(*wszPatternString) << 4;
182         }
183
184         if (!(wszPatternString = strchrW(wszPatternString, ',')))
185             hr = E_INVALIDARG;
186     
187         wszPatternString++; /* skip ',' */
188     }
189
190     if (hr == S_OK)
191     {
192         for ( ; !isxdigitW(*wszPatternString) && (*wszPatternString != ','); wszPatternString++)
193             ;
194
195         for (strpos = 0; isxdigitW(*wszPatternString) && (strpos/2 < ulBytes); wszPatternString++, strpos++)
196         {
197             if ((strpos % 2) == 1) /* odd numbered position */
198                 pbValue[strpos / 2] |= byte_from_hex_char(*wszPatternString);
199             else
200                 pbValue[strpos / 2] = byte_from_hex_char(*wszPatternString) << 4;
201         }
202     }
203
204     if (hr == S_OK)
205         hr = IAsyncReader_SyncRead(pReader, ulOffset, ulBytes, pbFile);
206
207     if (hr == S_OK)
208     {
209         ULONG i;
210         for (i = 0; i < ulBytes; i++)
211             if ((pbFile[i] & pbMask[i]) != pbValue[i])
212             {
213                 hr = S_FALSE;
214                 break;
215             }
216     }
217
218     HeapFree(GetProcessHeap(), 0, pbMask);
219     HeapFree(GetProcessHeap(), 0, pbValue);
220     HeapFree(GetProcessHeap(), 0, pbFile);
221
222     /* if we encountered no errors with this string, and there is a following tuple, then we
223      * have to match that as well to succeed */
224     if ((hr == S_OK) && (wszPatternString = strchrW(wszPatternString, ',')))
225         return process_pattern_string(wszPatternString + 1, pReader);
226     else
227         return hr;
228 }
229
230 static HRESULT GetClassMediaFile(IAsyncReader * pReader, LPCOLESTR pszFileName, GUID * majorType, GUID * minorType)
231 {
232     HKEY hkeyMediaType = NULL;
233     LONG lRet;
234     HRESULT hr = S_OK;
235     BOOL bFound = FALSE;
236     static const WCHAR wszMediaType[] = {'M','e','d','i','a',' ','T','y','p','e',0};
237
238     TRACE("(%p, %s, %p, %p)\n", pReader, debugstr_w(pszFileName), majorType, minorType);
239
240     CopyMemory(majorType, &GUID_NULL, sizeof(*majorType));
241     CopyMemory(minorType, &GUID_NULL, sizeof(*minorType));
242
243     lRet = RegOpenKeyExW(HKEY_CLASSES_ROOT, wszMediaType, 0, KEY_READ, &hkeyMediaType);
244     hr = HRESULT_FROM_WIN32(lRet);
245
246     if (SUCCEEDED(hr))
247     {
248         DWORD indexMajor;
249
250         for (indexMajor = 0; !bFound; indexMajor++)
251         {
252             HKEY hkeyMajor;
253             WCHAR wszMajorKeyName[CHARS_IN_GUID];
254             DWORD dwKeyNameLength = sizeof(wszMajorKeyName) / sizeof(wszMajorKeyName[0]);
255             static const WCHAR wszExtensions[] = {'E','x','t','e','n','s','i','o','n','s',0};
256
257             if (RegEnumKeyExW(hkeyMediaType, indexMajor, wszMajorKeyName, &dwKeyNameLength, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
258                 break;
259             if (RegOpenKeyExW(hkeyMediaType, wszMajorKeyName, 0, KEY_READ, &hkeyMajor) != ERROR_SUCCESS)
260                 break;
261             TRACE("%s\n", debugstr_w(wszMajorKeyName));
262             if (!strcmpW(wszExtensions, wszMajorKeyName))
263             {
264                 if (process_extensions(hkeyMajor, pszFileName, majorType, minorType) == S_OK)
265                     bFound = TRUE;
266             }
267             else
268             {
269                 DWORD indexMinor;
270
271                 for (indexMinor = 0; !bFound; indexMinor++)
272                 {
273                     HKEY hkeyMinor;
274                     WCHAR wszMinorKeyName[CHARS_IN_GUID];
275                     DWORD dwMinorKeyNameLen = sizeof(wszMinorKeyName) / sizeof(wszMinorKeyName[0]);
276                     DWORD maxValueLen;
277                     DWORD indexValue;
278
279                     if (RegEnumKeyExW(hkeyMajor, indexMinor, wszMinorKeyName, &dwMinorKeyNameLen, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
280                         break;
281
282                     if (RegOpenKeyExW(hkeyMajor, wszMinorKeyName, 0, KEY_READ, &hkeyMinor) != ERROR_SUCCESS)
283                         break;
284
285                     TRACE("\t%s\n", debugstr_w(wszMinorKeyName));
286         
287                     if (RegQueryInfoKeyW(hkeyMinor, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &maxValueLen, NULL, NULL) != ERROR_SUCCESS)
288                         break;
289
290                     for (indexValue = 0; !bFound; indexValue++)
291                     {
292                         DWORD dwType;
293                         WCHAR wszValueName[14]; /* longest name we should encounter will be "Source Filter" */
294                         LPWSTR wszPatternString = HeapAlloc(GetProcessHeap(), 0, maxValueLen);
295                         DWORD dwValueNameLen = sizeof(wszValueName) / sizeof(wszValueName[0]); /* remember this is in chars */
296                         DWORD dwDataLen = maxValueLen; /* remember this is in bytes */
297                         static const WCHAR wszSourceFilter[] = {'S','o','u','r','c','e',' ','F','i','l','t','e','r',0};
298                         LONG temp;
299
300                         if ((temp = RegEnumValueW(hkeyMinor, indexValue, wszValueName, &dwValueNameLen, NULL, &dwType, (LPBYTE)wszPatternString, &dwDataLen)) != ERROR_SUCCESS)
301                         {
302                             HeapFree(GetProcessHeap(), 0, wszPatternString);
303                             break;
304                         }
305
306                         /* if it is not the source filter value */
307                         if (strcmpW(wszValueName, wszSourceFilter))
308                         {
309                             if (process_pattern_string(wszPatternString, pReader) == S_OK)
310                             {
311                                 if (SUCCEEDED(CLSIDFromString(wszMajorKeyName, majorType)) &&
312                                     SUCCEEDED(CLSIDFromString(wszMinorKeyName, minorType)))
313                                     bFound = TRUE;
314                             }
315                         }
316                         HeapFree(GetProcessHeap(), 0, wszPatternString);
317                     }
318                     CloseHandle(hkeyMinor);
319                 }
320             }
321             CloseHandle(hkeyMajor);
322         }
323     }
324     CloseHandle(hkeyMediaType);
325
326     if (SUCCEEDED(hr) && !bFound)
327     {
328         ERR("Media class not found\n");
329         hr = E_FAIL;
330     }
331     else if (bFound)
332         TRACE("Found file's class: major = %s, subtype = %s\n", qzdebugstr_guid(majorType), qzdebugstr_guid(minorType));
333
334     return hr;
335 }
336
337 HRESULT AsyncReader_create(IUnknown * pUnkOuter, LPVOID * ppv)
338 {
339     AsyncReader *pAsyncRead;
340     
341     if( pUnkOuter )
342         return CLASS_E_NOAGGREGATION;
343     
344     pAsyncRead = CoTaskMemAlloc(sizeof(AsyncReader));
345
346     if (!pAsyncRead)
347         return E_OUTOFMEMORY;
348
349     pAsyncRead->lpVtbl = &AsyncReader_Vtbl;
350     pAsyncRead->lpVtblFSF = &FileSource_Vtbl;
351     pAsyncRead->refCount = 1;
352     pAsyncRead->filterInfo.achName[0] = '\0';
353     pAsyncRead->filterInfo.pGraph = NULL;
354     pAsyncRead->pOutputPin = NULL;
355
356     InitializeCriticalSection(&pAsyncRead->csFilter);
357     pAsyncRead->csFilter.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": AsyncReader.csFilter");
358
359     pAsyncRead->pszFileName = NULL;
360     pAsyncRead->pmt = NULL;
361
362     *ppv = (LPVOID)pAsyncRead;
363
364     TRACE("-- created at %p\n", pAsyncRead);
365
366     return S_OK;
367 }
368
369 /** IUnknown methods **/
370
371 static HRESULT WINAPI AsyncReader_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
372 {
373     AsyncReader *This = (AsyncReader *)iface;
374
375     TRACE("(%s, %p)\n", qzdebugstr_guid(riid), ppv);
376
377     *ppv = NULL;
378
379     if (IsEqualIID(riid, &IID_IUnknown))
380         *ppv = (LPVOID)This;
381     else if (IsEqualIID(riid, &IID_IPersist))
382         *ppv = (LPVOID)This;
383     else if (IsEqualIID(riid, &IID_IMediaFilter))
384         *ppv = (LPVOID)This;
385     else if (IsEqualIID(riid, &IID_IBaseFilter))
386         *ppv = (LPVOID)This;
387     else if (IsEqualIID(riid, &IID_IFileSourceFilter))
388         *ppv = (LPVOID)(&This->lpVtblFSF);
389
390     if (*ppv)
391     {
392         IUnknown_AddRef((IUnknown *)(*ppv));
393         return S_OK;
394     }
395
396     if (!IsEqualIID(riid, &IID_IPin) && !IsEqualIID(riid, &IID_IMediaSeeking))
397         FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
398
399     return E_NOINTERFACE;
400 }
401
402 static ULONG WINAPI AsyncReader_AddRef(IBaseFilter * iface)
403 {
404     AsyncReader *This = (AsyncReader *)iface;
405     ULONG refCount = InterlockedIncrement(&This->refCount);
406     
407     TRACE("(%p)->() AddRef from %d\n", This, refCount - 1);
408     
409     return refCount;
410 }
411
412 static ULONG WINAPI AsyncReader_Release(IBaseFilter * iface)
413 {
414     AsyncReader *This = (AsyncReader *)iface;
415     ULONG refCount = InterlockedDecrement(&This->refCount);
416     
417     TRACE("(%p)->() Release from %d\n", This, refCount + 1);
418     
419     if (!refCount)
420     {
421         if (This->pOutputPin)
422         {
423             IPin *pConnectedTo;
424             if(SUCCEEDED(IPin_ConnectedTo(This->pOutputPin, &pConnectedTo)))
425             {
426                 IPin_Disconnect(pConnectedTo);
427                 IPin_Release(pConnectedTo);
428             }
429             IPin_Disconnect(This->pOutputPin);
430             IPin_Release(This->pOutputPin);
431         }
432         This->csFilter.DebugInfo->Spare[0] = 0;
433         DeleteCriticalSection(&This->csFilter);
434         This->lpVtbl = NULL;
435         CoTaskMemFree(This);
436         return 0;
437     }
438     else
439         return refCount;
440 }
441
442 /** IPersist methods **/
443
444 static HRESULT WINAPI AsyncReader_GetClassID(IBaseFilter * iface, CLSID * pClsid)
445 {
446     TRACE("(%p)\n", pClsid);
447
448     *pClsid = CLSID_AsyncReader;
449
450     return S_OK;
451 }
452
453 /** IMediaFilter methods **/
454
455 static HRESULT WINAPI AsyncReader_Stop(IBaseFilter * iface)
456 {
457     AsyncReader *This = (AsyncReader *)iface;
458
459     TRACE("()\n");
460
461     This->state = State_Stopped;
462     
463     return S_OK;
464 }
465
466 static HRESULT WINAPI AsyncReader_Pause(IBaseFilter * iface)
467 {
468     AsyncReader *This = (AsyncReader *)iface;
469
470     TRACE("()\n");
471
472     This->state = State_Paused;
473
474     return S_OK;
475 }
476
477 static HRESULT WINAPI AsyncReader_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
478 {
479     AsyncReader *This = (AsyncReader *)iface;
480
481     TRACE("(%x%08x)\n", (ULONG)(tStart >> 32), (ULONG)tStart);
482
483     This->state = State_Running;
484
485     return S_OK;
486 }
487
488 static HRESULT WINAPI AsyncReader_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState)
489 {
490     AsyncReader *This = (AsyncReader *)iface;
491
492     TRACE("(%u, %p)\n", dwMilliSecsTimeout, pState);
493
494     *pState = This->state;
495     
496     return S_OK;
497 }
498
499 static HRESULT WINAPI AsyncReader_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock)
500 {
501 /*    AsyncReader *This = (AsyncReader *)iface;*/
502
503     TRACE("(%p)\n", pClock);
504
505     return S_OK;
506 }
507
508 static HRESULT WINAPI AsyncReader_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClock)
509 {
510 /*    AsyncReader *This = (AsyncReader *)iface;*/
511
512     TRACE("(%p)\n", ppClock);
513
514     return S_OK;
515 }
516
517 /** IBaseFilter methods **/
518
519 static HRESULT WINAPI AsyncReader_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum)
520 {
521     ENUMPINDETAILS epd;
522     AsyncReader *This = (AsyncReader *)iface;
523
524     TRACE("(%p)\n", ppEnum);
525
526     epd.cPins = This->pOutputPin ? 1 : 0;
527     epd.ppPins = &This->pOutputPin;
528     return IEnumPinsImpl_Construct(&epd, ppEnum);
529 }
530
531 static HRESULT WINAPI AsyncReader_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin)
532 {
533     FIXME("(%s, %p)\n", debugstr_w(Id), ppPin);
534
535     return E_NOTIMPL;
536 }
537
538 static HRESULT WINAPI AsyncReader_QueryFilterInfo(IBaseFilter * iface, FILTER_INFO *pInfo)
539 {
540     AsyncReader *This = (AsyncReader *)iface;
541
542     TRACE("(%p)\n", pInfo);
543
544     strcpyW(pInfo->achName, This->filterInfo.achName);
545     pInfo->pGraph = This->filterInfo.pGraph;
546
547     if (pInfo->pGraph)
548         IFilterGraph_AddRef(pInfo->pGraph);
549     
550     return S_OK;
551 }
552
553 static HRESULT WINAPI AsyncReader_JoinFilterGraph(IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName)
554 {
555     AsyncReader *This = (AsyncReader *)iface;
556
557     TRACE("(%p, %s)\n", pGraph, debugstr_w(pName));
558
559     if (pName)
560         strcpyW(This->filterInfo.achName, pName);
561     else
562         *This->filterInfo.achName = 0;
563     This->filterInfo.pGraph = pGraph; /* NOTE: do NOT increase ref. count */
564
565     return S_OK;
566 }
567
568 static HRESULT WINAPI AsyncReader_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo)
569 {
570     FIXME("(%p)\n", pVendorInfo);
571
572     return E_NOTIMPL;
573 }
574
575 static const IBaseFilterVtbl AsyncReader_Vtbl =
576 {
577     AsyncReader_QueryInterface,
578     AsyncReader_AddRef,
579     AsyncReader_Release,
580     AsyncReader_GetClassID,
581     AsyncReader_Stop,
582     AsyncReader_Pause,
583     AsyncReader_Run,
584     AsyncReader_GetState,
585     AsyncReader_SetSyncSource,
586     AsyncReader_GetSyncSource,
587     AsyncReader_EnumPins,
588     AsyncReader_FindPin,
589     AsyncReader_QueryFilterInfo,
590     AsyncReader_JoinFilterGraph,
591     AsyncReader_QueryVendorInfo
592 };
593
594 static HRESULT WINAPI FileSource_QueryInterface(IFileSourceFilter * iface, REFIID riid, LPVOID * ppv)
595 {
596     AsyncReader *This = impl_from_IFileSourceFilter(iface);
597
598     return IBaseFilter_QueryInterface((IFileSourceFilter*)&This->lpVtbl, riid, ppv);
599 }
600
601 static ULONG WINAPI FileSource_AddRef(IFileSourceFilter * iface)
602 {
603     AsyncReader *This = impl_from_IFileSourceFilter(iface);
604
605     return IBaseFilter_AddRef((IFileSourceFilter*)&This->lpVtbl);
606 }
607
608 static ULONG WINAPI FileSource_Release(IFileSourceFilter * iface)
609 {
610     AsyncReader *This = impl_from_IFileSourceFilter(iface);
611
612     return IBaseFilter_Release((IFileSourceFilter*)&This->lpVtbl);
613 }
614
615 static HRESULT WINAPI FileSource_Load(IFileSourceFilter * iface, LPCOLESTR pszFileName, const AM_MEDIA_TYPE * pmt)
616 {
617     HRESULT hr;
618     HANDLE hFile;
619     IAsyncReader * pReader = NULL;
620     AsyncReader *This = impl_from_IFileSourceFilter(iface);
621
622     TRACE("(%s, %p)\n", debugstr_w(pszFileName), pmt);
623
624     /* open file */
625     /* FIXME: check the sharing values that native uses */
626     hFile = CreateFileW(pszFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
627
628     if (hFile == INVALID_HANDLE_VALUE)
629     {
630         return HRESULT_FROM_WIN32(GetLastError());
631     }
632
633     /* create pin */
634     hr = FileAsyncReader_Construct(hFile, (IBaseFilter *)&This->lpVtbl, &This->csFilter, &This->pOutputPin);
635
636     if (SUCCEEDED(hr))
637         hr = IPin_QueryInterface(This->pOutputPin, &IID_IAsyncReader, (LPVOID *)&pReader);
638
639     /* store file name & media type */
640     if (SUCCEEDED(hr))
641     {
642         This->pszFileName = CoTaskMemAlloc((strlenW(pszFileName) + 1) * sizeof(WCHAR));
643         strcpyW(This->pszFileName, pszFileName);
644         This->pmt = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
645         if (!pmt)
646         {
647             This->pmt->bFixedSizeSamples = TRUE;
648             This->pmt->bTemporalCompression = FALSE;
649             This->pmt->cbFormat = 0;
650             This->pmt->pbFormat = NULL;
651             This->pmt->pUnk = NULL;
652             This->pmt->lSampleSize = 0;
653             This->pmt->formattype = FORMAT_None;
654             hr = GetClassMediaFile(pReader, pszFileName, &This->pmt->majortype, &This->pmt->subtype);
655             if (FAILED(hr))
656             {
657                 CoTaskMemFree(This->pmt);
658                 This->pmt = NULL;
659             }
660         }
661         else
662             CopyMediaType(This->pmt, pmt);
663     }
664
665     if (pReader)
666         IAsyncReader_Release(pReader);
667
668     if (FAILED(hr))
669     {
670         if (This->pOutputPin)
671         {
672             IPin_Release(This->pOutputPin);
673             This->pOutputPin = NULL;
674         }
675
676         CoTaskMemFree(This->pszFileName);
677         This->pszFileName = NULL;
678
679         CloseHandle(hFile);
680     }
681
682     /* FIXME: check return codes */
683     return hr;
684 }
685
686 static HRESULT WINAPI FileSource_GetCurFile(IFileSourceFilter * iface, LPOLESTR * ppszFileName, AM_MEDIA_TYPE * pmt)
687 {
688     AsyncReader *This = impl_from_IFileSourceFilter(iface);
689     
690     TRACE("(%p, %p)\n", ppszFileName, pmt);
691
692     if (!ppszFileName)
693         return E_POINTER;
694
695     /* copy file name & media type if available, otherwise clear the outputs */
696     if (This->pszFileName)
697     {
698         *ppszFileName = CoTaskMemAlloc((strlenW(This->pszFileName) + 1) * sizeof(WCHAR));
699         strcpyW(*ppszFileName, This->pszFileName);
700     }
701     else
702         *ppszFileName = NULL;
703
704     if (pmt)
705     {
706         if (This->pmt)
707             CopyMediaType(pmt, This->pmt);
708         else
709             ZeroMemory(pmt, sizeof(*pmt));
710     }
711
712     return S_OK;
713 }
714
715 static const IFileSourceFilterVtbl FileSource_Vtbl = 
716 {
717     FileSource_QueryInterface,
718     FileSource_AddRef,
719     FileSource_Release,
720     FileSource_Load,
721     FileSource_GetCurFile
722 };
723
724
725 /* the dwUserData passed back to user */
726 typedef struct DATAREQUEST
727 {
728     IMediaSample * pSample; /* sample passed to us by user */
729     DWORD_PTR dwUserData; /* user data passed to us */
730     OVERLAPPED ovl; /* our overlapped structure */
731
732     struct DATAREQUEST * pNext; /* next data request in list */
733 } DATAREQUEST;
734
735 static void queue(DATAREQUEST * pHead, DATAREQUEST * pItem)
736 {
737     DATAREQUEST * pCurrent;
738     for (pCurrent = pHead; pCurrent->pNext; pCurrent = pCurrent->pNext)
739         ;
740     pCurrent->pNext = pItem;
741 }
742
743 typedef struct FileAsyncReader
744 {
745     OutputPin pin;
746     const struct IAsyncReaderVtbl * lpVtblAR;
747
748     HANDLE hFile;
749     HANDLE hEvent;
750     BOOL bFlushing;
751     DATAREQUEST * pHead; /* head of data request list */
752     CRITICAL_SECTION csList; /* critical section to protect operations on list */
753 } FileAsyncReader;
754
755 static inline FileAsyncReader *impl_from_IAsyncReader( IAsyncReader *iface )
756 {
757     return (FileAsyncReader *)((char*)iface - FIELD_OFFSET(FileAsyncReader, lpVtblAR));
758 }
759
760 static HRESULT AcceptProcAFR(LPVOID iface, const AM_MEDIA_TYPE *pmt)
761 {
762     AsyncReader *This = (AsyncReader *)iface;
763     
764     FIXME("(%p, %p)\n", iface, pmt);
765
766     if (IsEqualGUID(&pmt->majortype, &This->pmt->majortype) &&
767         IsEqualGUID(&pmt->subtype, &This->pmt->subtype) &&
768         IsEqualGUID(&pmt->formattype, &FORMAT_None))
769         return S_OK;
770     
771     return S_FALSE;
772 }
773
774 /* overriden pin functions */
775
776 static HRESULT WINAPI FileAsyncReaderPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv)
777 {
778     FileAsyncReader *This = (FileAsyncReader *)iface;
779     TRACE("(%s, %p)\n", qzdebugstr_guid(riid), ppv);
780
781     *ppv = NULL;
782
783     if (IsEqualIID(riid, &IID_IUnknown))
784         *ppv = (LPVOID)This;
785     else if (IsEqualIID(riid, &IID_IPin))
786         *ppv = (LPVOID)This;
787     else if (IsEqualIID(riid, &IID_IAsyncReader))
788         *ppv = (LPVOID)&This->lpVtblAR;
789
790     if (*ppv)
791     {
792         IUnknown_AddRef((IUnknown *)(*ppv));
793         return S_OK;
794     }
795
796     if (!IsEqualIID(riid, &IID_IPin) && !IsEqualIID(riid, &IID_IMediaSeeking))
797         FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
798
799     return E_NOINTERFACE;
800 }
801
802 static ULONG WINAPI FileAsyncReaderPin_Release(IPin * iface)
803 {
804     FileAsyncReader *This = (FileAsyncReader *)iface;
805     ULONG refCount = InterlockedDecrement(&This->pin.pin.refCount);
806     
807     TRACE("(%p)->() Release from %d\n", This, refCount + 1);
808     
809     if (!refCount)
810     {
811         DATAREQUEST * pCurrent;
812         DATAREQUEST * pNext;
813         for (pCurrent = This->pHead; pCurrent; pCurrent = pNext)
814         {
815             pNext = pCurrent->pNext;
816             CoTaskMemFree(pCurrent);
817         }
818         CloseHandle(This->hFile);
819         CloseHandle(This->hEvent);
820         This->csList.DebugInfo->Spare[0] = 0;
821         DeleteCriticalSection(&This->csList);
822         CoTaskMemFree(This);
823         return 0;
824     }
825     return refCount;
826 }
827
828 static HRESULT WINAPI FileAsyncReaderPin_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum)
829 {
830     ENUMMEDIADETAILS emd;
831     FileAsyncReader *This = (FileAsyncReader *)iface;
832
833     TRACE("(%p)\n", ppEnum);
834
835     emd.cMediaTypes = 1;
836     emd.pMediaTypes = ((AsyncReader *)This->pin.pin.pinInfo.pFilter)->pmt;
837
838     return IEnumMediaTypesImpl_Construct(&emd, ppEnum);
839 }
840
841 static const IPinVtbl FileAsyncReaderPin_Vtbl = 
842 {
843     FileAsyncReaderPin_QueryInterface,
844     IPinImpl_AddRef,
845     FileAsyncReaderPin_Release,
846     OutputPin_Connect,
847     OutputPin_ReceiveConnection,
848     IPinImpl_Disconnect,
849     IPinImpl_ConnectedTo,
850     IPinImpl_ConnectionMediaType,
851     IPinImpl_QueryPinInfo,
852     IPinImpl_QueryDirection,
853     IPinImpl_QueryId,
854     IPinImpl_QueryAccept,
855     FileAsyncReaderPin_EnumMediaTypes,
856     IPinImpl_QueryInternalConnections,
857     OutputPin_EndOfStream,
858     OutputPin_BeginFlush,
859     OutputPin_EndFlush,
860     OutputPin_NewSegment
861 };
862
863 /* Function called as a helper to IPin_Connect */
864 /* specific AM_MEDIA_TYPE - it cannot be NULL */
865 /* this differs from standard OutputPin_ConnectSpecific only in that it
866  * doesn't need the IMemInputPin interface on the receiving pin */
867 static HRESULT FileAsyncReaderPin_ConnectSpecific(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
868 {
869     OutputPin *This = (OutputPin *)iface;
870     HRESULT hr;
871
872     TRACE("(%p, %p)\n", pReceivePin, pmt);
873     dump_AM_MEDIA_TYPE(pmt);
874
875     /* FIXME: call queryacceptproc */
876
877     This->pin.pConnectedTo = pReceivePin;
878     IPin_AddRef(pReceivePin);
879     CopyMediaType(&This->pin.mtCurrent, pmt);
880
881     hr = IPin_ReceiveConnection(pReceivePin, iface, pmt);
882
883     if (FAILED(hr))
884     {
885         IPin_Release(This->pin.pConnectedTo);
886         This->pin.pConnectedTo = NULL;
887         FreeMediaType(&This->pin.mtCurrent);
888     }
889
890     TRACE(" -- %x\n", hr);
891     return hr;
892 }
893
894 static HRESULT FileAsyncReader_Construct(HANDLE hFile, IBaseFilter * pBaseFilter, LPCRITICAL_SECTION pCritSec, IPin ** ppPin)
895 {
896     FileAsyncReader * pPinImpl;
897     PIN_INFO piOutput;
898
899     *ppPin = NULL;
900
901     pPinImpl = CoTaskMemAlloc(sizeof(*pPinImpl));
902
903     if (!pPinImpl)
904         return E_OUTOFMEMORY;
905
906     piOutput.dir = PINDIR_OUTPUT;
907     piOutput.pFilter = pBaseFilter;
908     strcpyW(piOutput.achName, wszOutputPinName);
909
910     if (SUCCEEDED(OutputPin_Init(&piOutput, NULL, pBaseFilter, AcceptProcAFR, pCritSec, &pPinImpl->pin)))
911     {
912         pPinImpl->pin.pin.lpVtbl = &FileAsyncReaderPin_Vtbl;
913         pPinImpl->lpVtblAR = &FileAsyncReader_Vtbl;
914         pPinImpl->hFile = hFile;
915         pPinImpl->hEvent = CreateEventW(NULL, 0, 0, NULL);
916         pPinImpl->bFlushing = FALSE;
917         pPinImpl->pHead = NULL;
918         pPinImpl->pin.pConnectSpecific = FileAsyncReaderPin_ConnectSpecific;
919         InitializeCriticalSection(&pPinImpl->csList);
920         pPinImpl->csList.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": FileAsyncReader.csList");
921
922         *ppPin = (IPin *)(&pPinImpl->pin.pin.lpVtbl);
923         return S_OK;
924     }
925
926     CoTaskMemFree(pPinImpl);
927     return E_FAIL;
928 }
929
930 /* IAsyncReader */
931
932 static HRESULT WINAPI FileAsyncReader_QueryInterface(IAsyncReader * iface, REFIID riid, LPVOID * ppv)
933 {
934     FileAsyncReader *This = impl_from_IAsyncReader(iface);
935
936     return IPin_QueryInterface((IPin *)This, riid, ppv);
937 }
938
939 static ULONG WINAPI FileAsyncReader_AddRef(IAsyncReader * iface)
940 {
941     FileAsyncReader *This = impl_from_IAsyncReader(iface);
942
943     return IPin_AddRef((IPin *)This);
944 }
945
946 static ULONG WINAPI FileAsyncReader_Release(IAsyncReader * iface)
947 {
948     FileAsyncReader *This = impl_from_IAsyncReader(iface);
949
950     return IPin_Release((IPin *)This);
951 }
952
953 #define DEF_ALIGNMENT 1
954
955 static HRESULT WINAPI FileAsyncReader_RequestAllocator(IAsyncReader * iface, IMemAllocator * pPreferred, ALLOCATOR_PROPERTIES * pProps, IMemAllocator ** ppActual)
956 {
957     HRESULT hr = S_OK;
958
959     TRACE("(%p, %p, %p)\n", pPreferred, pProps, ppActual);
960
961     if (!pProps->cbAlign || (pProps->cbAlign % DEF_ALIGNMENT) != 0)
962         pProps->cbAlign = DEF_ALIGNMENT;
963
964     if (pPreferred)
965     {
966         ALLOCATOR_PROPERTIES PropsActual;
967         hr = IMemAllocator_SetProperties(pPreferred, pProps, &PropsActual);
968         /* FIXME: check we are still aligned */
969         if (SUCCEEDED(hr))
970         {
971             IMemAllocator_AddRef(pPreferred);
972             *ppActual = pPreferred;
973             TRACE("FileAsyncReader_RequestAllocator -- %x\n", hr);
974             return S_OK;
975         }
976     }
977
978     pPreferred = NULL;
979
980     hr = CoCreateInstance(&CLSID_MemoryAllocator, NULL, CLSCTX_INPROC, &IID_IMemAllocator, (LPVOID *)&pPreferred);
981
982     if (SUCCEEDED(hr))
983     {
984         ALLOCATOR_PROPERTIES PropsActual;
985         hr = IMemAllocator_SetProperties(pPreferred, pProps, &PropsActual);
986         /* FIXME: check we are still aligned */
987         if (SUCCEEDED(hr))
988         {
989             *ppActual = pPreferred;
990             TRACE("FileAsyncReader_RequestAllocator -- %x\n", hr);
991             return S_OK;
992         }
993     }
994
995     if (FAILED(hr))
996     {
997         *ppActual = NULL;
998         if (pPreferred)
999             IMemAllocator_Release(pPreferred);
1000     }
1001
1002     TRACE("-- %x\n", hr);
1003     return hr;
1004 }
1005
1006 /* we could improve the Request/WaitForNext mechanism by allowing out of order samples.
1007  * however, this would be quite complicated to do and may be a bit error prone */
1008 static HRESULT WINAPI FileAsyncReader_Request(IAsyncReader * iface, IMediaSample * pSample, DWORD_PTR dwUser)
1009 {
1010     REFERENCE_TIME Start;
1011     REFERENCE_TIME Stop;
1012     DATAREQUEST * pDataRq;
1013     BYTE * pBuffer;
1014     HRESULT hr = S_OK;
1015     FileAsyncReader *This = impl_from_IAsyncReader(iface);
1016
1017     TRACE("(%p, %lx)\n", pSample, dwUser);
1018
1019     /* check flushing state */
1020     if (This->bFlushing)
1021         return VFW_E_WRONG_STATE;
1022
1023     if (!(pDataRq = CoTaskMemAlloc(sizeof(*pDataRq))))
1024         hr = E_OUTOFMEMORY;
1025
1026     /* get start and stop positions in bytes */
1027     if (SUCCEEDED(hr))
1028         hr = IMediaSample_GetTime(pSample, &Start, &Stop);
1029
1030     if (SUCCEEDED(hr))
1031         hr = IMediaSample_GetPointer(pSample, &pBuffer);
1032
1033     if (SUCCEEDED(hr))
1034     {
1035         DWORD dwLength = (DWORD) BYTES_FROM_MEDIATIME(Stop - Start);
1036
1037         pDataRq->ovl.u.s.Offset = (DWORD) BYTES_FROM_MEDIATIME(Start);
1038         pDataRq->ovl.u.s.OffsetHigh = (DWORD)(BYTES_FROM_MEDIATIME(Start) >> (sizeof(DWORD) * 8));
1039         pDataRq->ovl.hEvent = This->hEvent;
1040         pDataRq->dwUserData = dwUser;
1041         pDataRq->pNext = NULL;
1042         /* we violate traditional COM rules here by maintaining
1043          * a reference to the sample, but not calling AddRef, but
1044          * that's what MSDN says to do */
1045         pDataRq->pSample = pSample;
1046
1047         EnterCriticalSection(&This->csList);
1048         {
1049             if (This->pHead)
1050                 /* adds data request to end of list */
1051                 queue(This->pHead, pDataRq);
1052             else
1053                 This->pHead = pDataRq;
1054         }
1055         LeaveCriticalSection(&This->csList);
1056
1057         /* this is definitely not how it is implemented on Win9x
1058          * as they do not support async reads on files, but it is
1059          * sooo much easier to use this than messing around with threads!
1060          */
1061         if (!ReadFile(This->hFile, pBuffer, dwLength, NULL, &pDataRq->ovl))
1062             hr = HRESULT_FROM_WIN32(GetLastError());
1063
1064         /* ERROR_IO_PENDING is not actually an error since this is what we want! */
1065         if (hr == HRESULT_FROM_WIN32(ERROR_IO_PENDING))
1066             hr = S_OK;
1067     }
1068
1069     if (FAILED(hr) && pDataRq)
1070     {
1071         EnterCriticalSection(&This->csList);
1072         {
1073             DATAREQUEST * pCurrent;
1074             for (pCurrent = This->pHead; pCurrent && pCurrent->pNext; pCurrent = pCurrent->pNext)
1075                 if (pCurrent->pNext == pDataRq)
1076                 {
1077                     pCurrent->pNext = pDataRq->pNext;
1078                     break;
1079                 }
1080         }
1081         LeaveCriticalSection(&This->csList);
1082         CoTaskMemFree(pDataRq);
1083     }
1084
1085     TRACE("-- %x\n", hr);
1086     return hr;
1087 }
1088
1089 static HRESULT WINAPI FileAsyncReader_WaitForNext(IAsyncReader * iface, DWORD dwTimeout, IMediaSample ** ppSample, DWORD_PTR * pdwUser)
1090 {
1091     HRESULT hr = S_OK;
1092     DWORD dwBytes = 0;
1093     DATAREQUEST * pDataRq = NULL;
1094     FileAsyncReader *This = impl_from_IAsyncReader(iface);
1095
1096     TRACE("(%u, %p, %p)\n", dwTimeout, ppSample, pdwUser);
1097
1098     /* FIXME: we could do with improving this by waiting for an array of event handles
1099      * and then determining which one finished and removing that from the list, otherwise
1100      * we will end up waiting for longer than we should do, if a later request finishes
1101      * before an earlier one */
1102
1103     *ppSample = NULL;
1104     *pdwUser = 0;
1105
1106     /* we return immediately if flushing */
1107     if (This->bFlushing)
1108         hr = VFW_E_WRONG_STATE;
1109
1110     if (SUCCEEDED(hr))
1111     {
1112         /* wait for the read to finish or timeout */
1113         if (WaitForSingleObject(This->hEvent, dwTimeout) == WAIT_TIMEOUT)
1114             hr = VFW_E_TIMEOUT;
1115     }
1116     if (SUCCEEDED(hr))
1117     {
1118         EnterCriticalSection(&This->csList);
1119         {
1120             pDataRq = This->pHead;
1121             if (pDataRq == NULL)
1122                 hr = E_FAIL;
1123             else
1124                 This->pHead = pDataRq->pNext;
1125         }
1126         LeaveCriticalSection(&This->csList);
1127     }
1128
1129     if (SUCCEEDED(hr))
1130     {
1131         /* get any errors */
1132         if (!GetOverlappedResult(This->hFile, &pDataRq->ovl, &dwBytes, FALSE))
1133             hr = HRESULT_FROM_WIN32(GetLastError());
1134     }
1135
1136     if (SUCCEEDED(hr))
1137     {
1138         IMediaSample_SetActualDataLength(pDataRq->pSample, dwBytes);
1139         *ppSample = pDataRq->pSample;
1140         *pdwUser = pDataRq->dwUserData;
1141     }
1142
1143     /* no need to close event handle since we will close it when the pin is destroyed */
1144     CoTaskMemFree(pDataRq);
1145     
1146     TRACE("-- %x\n", hr);
1147     return hr;
1148 }
1149
1150 static HRESULT WINAPI FileAsyncReader_SyncRead(IAsyncReader * iface, LONGLONG llPosition, LONG lLength, BYTE * pBuffer);
1151
1152 static HRESULT WINAPI FileAsyncReader_SyncReadAligned(IAsyncReader * iface, IMediaSample * pSample)
1153 {
1154     BYTE * pBuffer;
1155     REFERENCE_TIME tStart;
1156     REFERENCE_TIME tStop;
1157     HRESULT hr;
1158
1159     TRACE("(%p)\n", pSample);
1160
1161     hr = IMediaSample_GetTime(pSample, &tStart, &tStop);
1162
1163     if (SUCCEEDED(hr))
1164         hr = IMediaSample_GetPointer(pSample, &pBuffer);
1165
1166     if (SUCCEEDED(hr))
1167         hr = FileAsyncReader_SyncRead(iface, 
1168             BYTES_FROM_MEDIATIME(tStart),
1169             (LONG) BYTES_FROM_MEDIATIME(tStop - tStart),
1170             pBuffer);
1171
1172     TRACE("-- %x\n", hr);
1173     return hr;
1174 }
1175
1176 static HRESULT WINAPI FileAsyncReader_SyncRead(IAsyncReader * iface, LONGLONG llPosition, LONG lLength, BYTE * pBuffer)
1177 {
1178     OVERLAPPED ovl;
1179     HRESULT hr = S_OK;
1180     FileAsyncReader *This = impl_from_IAsyncReader(iface);
1181
1182     TRACE("(%x%08x, %d, %p)\n", (ULONG)(llPosition >> 32), (ULONG)llPosition, lLength, pBuffer);
1183
1184     ZeroMemory(&ovl, sizeof(ovl));
1185
1186     ovl.hEvent = CreateEventW(NULL, 0, 0, NULL);
1187     /* NOTE: llPosition is the actual byte position to start reading from */
1188     ovl.u.s.Offset = (DWORD) llPosition;
1189     ovl.u.s.OffsetHigh = (DWORD) (llPosition >> (sizeof(DWORD) * 8));
1190
1191     if (!ReadFile(This->hFile, pBuffer, lLength, NULL, &ovl))
1192         hr = HRESULT_FROM_WIN32(GetLastError());
1193
1194     if (hr == HRESULT_FROM_WIN32(ERROR_IO_PENDING))
1195         hr = S_OK;
1196
1197     if (SUCCEEDED(hr))
1198     {
1199         DWORD dwBytesRead;
1200
1201         if (!GetOverlappedResult(This->hFile, &ovl, &dwBytesRead, TRUE))
1202             hr = HRESULT_FROM_WIN32(GetLastError());
1203     }
1204
1205     CloseHandle(ovl.hEvent);
1206
1207     TRACE("-- %x\n", hr);
1208     return hr;
1209 }
1210
1211 static HRESULT WINAPI FileAsyncReader_Length(IAsyncReader * iface, LONGLONG * pTotal, LONGLONG * pAvailable)
1212 {
1213     DWORD dwSizeLow;
1214     DWORD dwSizeHigh;
1215     FileAsyncReader *This = impl_from_IAsyncReader(iface);
1216
1217     TRACE("(%p, %p)\n", pTotal, pAvailable);
1218
1219     if (((dwSizeLow = GetFileSize(This->hFile, &dwSizeHigh)) == -1) &&
1220         (GetLastError() != NO_ERROR))
1221         return HRESULT_FROM_WIN32(GetLastError());
1222
1223     *pTotal = (LONGLONG)dwSizeLow | (LONGLONG)dwSizeHigh << (sizeof(DWORD) * 8);
1224
1225     *pAvailable = *pTotal;
1226
1227     return S_OK;
1228 }
1229
1230 static HRESULT WINAPI FileAsyncReader_BeginFlush(IAsyncReader * iface)
1231 {
1232     FileAsyncReader *This = impl_from_IAsyncReader(iface);
1233
1234     TRACE("()\n");
1235
1236     This->bFlushing = TRUE;
1237     CancelIo(This->hFile);
1238     SetEvent(This->hEvent);
1239     
1240     /* FIXME: free list */
1241
1242     return S_OK;
1243 }
1244
1245 static HRESULT WINAPI FileAsyncReader_EndFlush(IAsyncReader * iface)
1246 {
1247     FileAsyncReader *This = impl_from_IAsyncReader(iface);
1248
1249     TRACE("()\n");
1250
1251     This->bFlushing = FALSE;
1252
1253     return S_OK;
1254 }
1255
1256 static const IAsyncReaderVtbl FileAsyncReader_Vtbl = 
1257 {
1258     FileAsyncReader_QueryInterface,
1259     FileAsyncReader_AddRef,
1260     FileAsyncReader_Release,
1261     FileAsyncReader_RequestAllocator,
1262     FileAsyncReader_Request,
1263     FileAsyncReader_WaitForNext,
1264     FileAsyncReader_SyncReadAligned,
1265     FileAsyncReader_SyncRead,
1266     FileAsyncReader_Length,
1267     FileAsyncReader_BeginFlush,
1268     FileAsyncReader_EndFlush,
1269 };