Fixed the behavior for SHGetFileInfo when the SHGFI_USEFILEATTRIBUTES
[wine] / dlls / quartz / wavparse.c
1 /*
2  * Implements WAVE/AU/AIFF Parser.
3  *
4  * hidenori@a2.ctktv.ne.jp
5  */
6
7 #include "config.h"
8
9 #include "windef.h"
10 #include "winbase.h"
11 #include "wingdi.h"
12 #include "winuser.h"
13 #include "mmsystem.h"
14 #include "mmreg.h"
15 #include "winerror.h"
16 #include "strmif.h"
17 #include "control.h"
18 #include "vfwmsgs.h"
19 #include "uuids.h"
20
21 #include "debugtools.h"
22 DEFAULT_DEBUG_CHANNEL(quartz);
23
24 #include "quartz_private.h"
25 #include "audioutl.h"
26 #include "parser.h"
27
28
29 static const WCHAR QUARTZ_WaveParser_Name[] =
30 { 'W','a','v','e',' ','P','a','r','s','e','r',0 };
31 static const WCHAR QUARTZ_WaveParserInPin_Name[] =
32 { 'I','n',0 };
33 static const WCHAR QUARTZ_WaveParserOutPin_Name[] =
34 { 'O','u','t',0 };
35
36
37 /****************************************************************************/
38
39 /* S_OK = found, S_FALSE = not found */
40 HRESULT RIFF_GetNext(
41         CParserImpl* pImpl, LONGLONG llOfs,
42         DWORD* pdwCode, DWORD* pdwLength )
43 {
44         BYTE bTemp[8];
45         HRESULT hr;
46
47         hr = IAsyncReader_SyncRead( pImpl->m_pReader, llOfs, 8, bTemp );
48         if ( hr == S_OK )
49         {
50                 *pdwCode = mmioFOURCC(bTemp[0],bTemp[1],bTemp[2],bTemp[3]);
51                 *pdwLength = PARSER_LE_UINT32(&bTemp[4]);
52         }
53         else
54         {
55                 *pdwCode = 0;
56                 *pdwLength = 0;
57         }
58
59         return hr;
60 }
61
62 /* S_OK = found, S_FALSE = not found */
63 HRESULT RIFF_SearchChunk(
64         CParserImpl* pImpl,
65         DWORD dwSearchLengthMax,
66         LONGLONG llOfs, DWORD dwChunk,
67         LONGLONG* pllOfs, DWORD* pdwChunkLength )
68 {
69         HRESULT hr;
70         DWORD dwCurCode;
71         DWORD dwCurLen;
72         LONGLONG llCurLen;
73
74         while ( 1 )
75         {
76                 hr = RIFF_GetNext( pImpl, llOfs, &dwCurCode, &dwCurLen );
77                 if ( hr != S_OK )
78                         break;
79                 TRACE("%c%c%c%c len %lu\n",
80                         (int)(dwCurCode>> 0)&0xff,
81                         (int)(dwCurCode>> 8)&0xff,
82                         (int)(dwCurCode>>16)&0xff,
83                         (int)(dwCurCode>>24)&0xff,
84                         (unsigned long)dwCurLen);
85                 if ( dwChunk == dwCurCode )
86                         break;
87                 llCurLen = 8 + (LONGLONG)((dwCurLen+1)&(~1));
88                 llOfs += llCurLen;
89                 if ( (LONGLONG)dwSearchLengthMax <= llCurLen )
90                         return S_FALSE;
91                 if ( dwSearchLengthMax != (DWORD)0xffffffff )
92                         dwSearchLengthMax -= (DWORD)llCurLen;
93         }
94
95         *pllOfs = llOfs + 8;
96         *pdwChunkLength = dwCurLen;
97
98         return hr;
99 }
100
101 /* S_OK = found, S_FALSE = not found */
102 HRESULT RIFF_SearchList(
103         CParserImpl* pImpl,
104         DWORD dwSearchLengthMax,
105         LONGLONG llOfs, DWORD dwListChunk,
106         LONGLONG* pllOfs, DWORD* pdwChunkLength )
107 {
108         HRESULT hr;
109         DWORD dwCurLen;
110         LONGLONG llCurLen;
111         BYTE bTemp[4];
112
113         while ( 1 )
114         {
115                 hr = RIFF_SearchChunk(
116                         pImpl, dwSearchLengthMax,
117                         llOfs, PARSER_LIST,
118                         &llOfs, &dwCurLen );
119                 if ( hr != S_OK )
120                         break;
121
122                 hr = IAsyncReader_SyncRead( pImpl->m_pReader, llOfs, 4, bTemp );
123                 if ( hr != S_OK )
124                         break;
125
126                 if ( mmioFOURCC(bTemp[0],bTemp[1],bTemp[2],bTemp[3]) == dwListChunk )
127                         break;
128
129                 llCurLen = (LONGLONG)((dwCurLen+1)&(~1));
130                 llOfs += llCurLen;
131                 if ( (LONGLONG)dwSearchLengthMax <= (llCurLen+8) )
132                         return S_FALSE;
133                 if ( dwSearchLengthMax != (DWORD)0xffffffff )
134                         dwSearchLengthMax -= (DWORD)(llCurLen+8);
135         }
136
137         if ( dwCurLen < 12 )
138                 return E_FAIL;
139
140         *pllOfs = llOfs+4;
141         *pdwChunkLength = dwCurLen-4;
142
143         return hr;
144 }
145
146
147
148
149 /****************************************************************************
150  *
151  *      CWavParseImpl
152  */
153
154 typedef enum WavParseFmtType
155 {
156         WaveParse_Native,
157         WaveParse_Signed8,
158         WaveParse_Signed16BE,
159         WaveParse_Unsigned16LE,
160         WaveParse_Unsigned16BE,
161 } WavParseFmtType;
162
163 typedef struct CWavParseImpl
164 {
165         DWORD   cbFmt;
166         WAVEFORMATEX*   pFmt;
167         DWORD   dwBlockSize;
168         LONGLONG        llDataStart;
169         LONGLONG        llBytesTotal;
170         LONGLONG        llBytesProcessed;
171         WavParseFmtType iFmtType;
172 } CWavParseImpl;
173
174
175 static HRESULT CWavParseImpl_InitWAV( CParserImpl* pImpl, CWavParseImpl* This )
176 {
177         HRESULT hr;
178         LONGLONG        llOfs;
179         DWORD   dwChunkLength;
180
181         hr = RIFF_SearchChunk(
182                 pImpl, (DWORD)0xffffffff,
183                 PARSER_RIFF_OfsFirst, PARSER_fmt,
184                 &llOfs, &dwChunkLength );
185         if ( FAILED(hr) )
186                 return hr;
187         if ( hr != S_OK || ( dwChunkLength < (sizeof(WAVEFORMATEX)-2) ) )
188                 return E_FAIL;
189
190         This->cbFmt = dwChunkLength;
191         if ( dwChunkLength < sizeof(WAVEFORMATEX) )
192                 This->cbFmt = sizeof(WAVEFORMATEX);
193         This->pFmt = (WAVEFORMATEX*)QUARTZ_AllocMem( dwChunkLength );
194         if ( This->pFmt == NULL )
195                 return E_OUTOFMEMORY;
196         ZeroMemory( This->pFmt, This->cbFmt );
197
198         hr = IAsyncReader_SyncRead(
199                 pImpl->m_pReader, llOfs, dwChunkLength, (BYTE*)This->pFmt );
200         if ( hr != S_OK )
201         {
202                 if ( SUCCEEDED(hr) )
203                         hr = E_FAIL;
204                 return hr;
205         }
206
207
208         hr = RIFF_SearchChunk(
209                 pImpl, (DWORD)0xffffffff,
210                 PARSER_RIFF_OfsFirst, PARSER_data,
211                 &llOfs, &dwChunkLength );
212         if ( FAILED(hr) )
213                 return hr;
214         if ( hr != S_OK || dwChunkLength == 0 )
215                 return E_FAIL;
216
217         This->llDataStart = llOfs;
218         This->llBytesTotal = (LONGLONG)dwChunkLength;
219
220         return NOERROR;
221 }
222
223 static HRESULT CWavParseImpl_InitAU( CParserImpl* pImpl, CWavParseImpl* This )
224 {
225         BYTE    au_hdr[24];
226         DWORD   dataofs;
227         DWORD   datalen;
228         DWORD   datafmt;
229         DWORD   datarate;
230         DWORD   datachannels;
231         HRESULT hr;
232         WAVEFORMATEX    wfx;
233
234         hr = IAsyncReader_SyncRead( pImpl->m_pReader, 0, 24, au_hdr );
235         if ( FAILED(hr) )
236                 return hr;
237
238         dataofs = PARSER_BE_UINT32(&au_hdr[4]);
239         datalen = PARSER_BE_UINT32(&au_hdr[8]);
240         datafmt = PARSER_BE_UINT32(&au_hdr[12]);
241         datarate = PARSER_BE_UINT32(&au_hdr[16]);
242         datachannels = PARSER_BE_UINT32(&au_hdr[20]);
243
244         if ( dataofs < 24U || datalen == 0U )
245                 return E_FAIL;
246         if ( datachannels != 1 && datachannels != 2 )
247                 return E_FAIL;
248
249         ZeroMemory( &wfx, sizeof(WAVEFORMATEX) );
250         wfx.nChannels = datachannels;
251         wfx.nSamplesPerSec = datarate;
252
253         switch ( datafmt )
254         {
255         case 1:
256                 wfx.wFormatTag = WAVE_FORMAT_MULAW;
257                 wfx.nBlockAlign = datachannels;
258                 wfx.wBitsPerSample = 8;
259                 break;
260         case 2:
261                 wfx.wFormatTag = WAVE_FORMAT_PCM;
262                 wfx.nBlockAlign = datachannels;
263                 wfx.wBitsPerSample = 8;
264                 This->iFmtType = WaveParse_Signed8;
265                 break;
266         case 3:
267                 wfx.wFormatTag = WAVE_FORMAT_PCM;
268                 wfx.nBlockAlign = datachannels;
269                 wfx.wBitsPerSample = 16;
270                 This->iFmtType = WaveParse_Signed16BE;
271                 break;
272         default:
273                 FIXME("audio/basic - unknown format %lu\n", datafmt );
274                 return E_FAIL;
275         }
276         wfx.nAvgBytesPerSec = (datarate * datachannels * (DWORD)wfx.wBitsPerSample) >> 3;
277
278         This->cbFmt = sizeof(WAVEFORMATEX);
279         This->pFmt = (WAVEFORMATEX*)QUARTZ_AllocMem( sizeof(WAVEFORMATEX) );
280         if ( This->pFmt == NULL )
281                 return E_OUTOFMEMORY;
282         memcpy( This->pFmt, &wfx, sizeof(WAVEFORMATEX) );
283
284         This->llDataStart = dataofs;
285         This->llBytesTotal = datalen;
286
287         return NOERROR;
288 }
289
290 static HRESULT CWavParseImpl_InitAIFF( CParserImpl* pImpl, CWavParseImpl* This )
291 {
292         FIXME( "AIFF is not supported now.\n" );
293         return E_FAIL;
294 }
295
296 static HRESULT CWavParseImpl_InitParser( CParserImpl* pImpl, ULONG* pcStreams )
297 {
298         CWavParseImpl*  This = NULL;
299         HRESULT hr;
300         BYTE    header[12];
301
302         TRACE("(%p,%p)\n",pImpl,pcStreams);
303
304         if ( pImpl->m_pReader == NULL )
305                 return E_UNEXPECTED;
306
307         This = (CWavParseImpl*)QUARTZ_AllocMem( sizeof(CWavParseImpl) );
308         if ( This == NULL )
309                 return E_OUTOFMEMORY;
310         pImpl->m_pUserData = This;
311
312         /* construct */
313         This->cbFmt = 0;
314         This->pFmt = NULL;
315         This->dwBlockSize = 0;
316         This->llDataStart = 0;
317         This->llBytesTotal = 0;
318         This->llBytesProcessed = 0;
319         This->iFmtType = WaveParse_Native;
320
321         hr = IAsyncReader_SyncRead( pImpl->m_pReader, 0, 12, header );
322         if ( FAILED(hr) )
323                 return hr;
324         if ( hr != S_OK )
325                 return E_FAIL;
326
327         if ( !memcmp( &header[0], "RIFF", 4 ) &&
328                  !memcmp( &header[8], "WAVE", 4 ) )
329         {
330                 TRACE( "(%p) - it's audio/wav.\n", pImpl );
331                 hr = CWavParseImpl_InitWAV( pImpl, This );
332         }
333         else
334         if ( !memcmp( &header[0], ".snd", 4 ) )
335         {
336                 TRACE( "(%p) - it's audio/basic.\n", pImpl );
337                 hr = CWavParseImpl_InitAU( pImpl, This );
338         }
339         else
340         if ( !memcmp( &header[0], "FORM", 4 ) &&
341                  !memcmp( &header[8], "AIFF", 4 ) )
342         {
343                 TRACE( "(%p) - it's audio/aiff.\n", pImpl );
344                 hr = CWavParseImpl_InitAIFF( pImpl, This );
345         }
346         else
347         {
348                 FIXME( "(%p) - unknown format.\n", pImpl );
349                 hr = E_FAIL;
350         }
351
352         if ( FAILED(hr) )
353         {
354                 return hr;
355         }
356
357         /* initialized successfully. */
358         *pcStreams = 1;
359
360         This->dwBlockSize = (This->pFmt->nAvgBytesPerSec + (DWORD)This->pFmt->nBlockAlign - 1U) / (DWORD)This->pFmt->nBlockAlign;
361
362         TRACE( "(%p) returned successfully.\n", pImpl );
363
364         return NOERROR;
365 }
366
367 static HRESULT CWavParseImpl_UninitParser( CParserImpl* pImpl )
368 {
369         CWavParseImpl*  This = (CWavParseImpl*)pImpl->m_pUserData;
370
371         TRACE("(%p)\n",This);
372
373         if ( This == NULL )
374                 return NOERROR;
375
376         /* destruct */
377         if ( This->pFmt != NULL ) QUARTZ_FreeMem(This->pFmt);
378
379         QUARTZ_FreeMem( This );
380         pImpl->m_pUserData = NULL;
381
382         return NOERROR;
383 }
384
385 static LPCWSTR CWavParseImpl_GetOutPinName( CParserImpl* pImpl, ULONG nStreamIndex )
386 {
387         CWavParseImpl*  This = (CWavParseImpl*)pImpl->m_pUserData;
388
389         TRACE("(%p)\n",This);
390
391         return QUARTZ_WaveParserOutPin_Name;
392 }
393
394 static HRESULT CWavParseImpl_GetStreamType( CParserImpl* pImpl, ULONG nStreamIndex, AM_MEDIA_TYPE* pmt )
395 {
396         CWavParseImpl*  This = (CWavParseImpl*)pImpl->m_pUserData;
397
398         TRACE("(%p)\n",This);
399
400         if ( This == NULL || This->pFmt == NULL )
401                 return E_UNEXPECTED;
402
403         ZeroMemory( pmt, sizeof(AM_MEDIA_TYPE) );
404         memcpy( &pmt->majortype, &MEDIATYPE_Audio, sizeof(GUID) );
405         QUARTZ_MediaSubType_FromFourCC( &pmt->subtype, (DWORD)This->pFmt->wFormatTag );
406         pmt->bFixedSizeSamples = 1;
407         pmt->bTemporalCompression = 0;
408         pmt->lSampleSize = This->pFmt->nBlockAlign;
409         memcpy( &pmt->formattype, &FORMAT_WaveFormatEx, sizeof(GUID) );
410         pmt->pUnk = NULL;
411
412         pmt->pbFormat = (BYTE*)CoTaskMemAlloc( This->cbFmt );
413         if ( pmt->pbFormat == NULL )
414                 return E_OUTOFMEMORY;
415         pmt->cbFormat = This->cbFmt;
416         memcpy( pmt->pbFormat, This->pFmt, This->cbFmt );
417
418         return NOERROR;
419 }
420
421 static HRESULT CWavParseImpl_CheckStreamType( CParserImpl* pImpl, ULONG nStreamIndex, const AM_MEDIA_TYPE* pmt )
422 {
423         if ( !IsEqualGUID( &pmt->majortype, &MEDIATYPE_Audio ) ||
424                  !IsEqualGUID( &pmt->formattype, &FORMAT_WaveFormatEx ) )
425                 return E_FAIL;
426         if ( pmt->pbFormat == NULL || pmt->cbFormat < sizeof(WAVEFORMATEX) )
427                 return E_FAIL;
428
429         return NOERROR;
430 }
431
432 static HRESULT CWavParseImpl_GetAllocProp( CParserImpl* pImpl, ALLOCATOR_PROPERTIES* pReqProp )
433 {
434         CWavParseImpl*  This = (CWavParseImpl*)pImpl->m_pUserData;
435
436         TRACE("(%p)\n",This);
437
438         if ( This == NULL || This->pFmt == NULL )
439                 return E_UNEXPECTED;
440
441         ZeroMemory( pReqProp, sizeof(ALLOCATOR_PROPERTIES) );
442         pReqProp->cBuffers = 1;
443         pReqProp->cbBuffer = This->dwBlockSize;
444
445         return NOERROR;
446 }
447
448 static HRESULT CWavParseImpl_GetNextRequest( CParserImpl* pImpl, ULONG* pnStreamIndex, LONGLONG* pllStart, LONG* plLength, REFERENCE_TIME* prtStart, REFERENCE_TIME* prtStop )
449 {
450         CWavParseImpl*  This = (CWavParseImpl*)pImpl->m_pUserData;
451         LONGLONG        llAvail;
452         LONGLONG        llStart;
453         LONGLONG        llEnd;
454
455         TRACE("(%p)\n",This);
456
457         if ( This == NULL || This->pFmt == NULL )
458                 return E_UNEXPECTED;
459
460         llAvail = This->llBytesTotal - This->llBytesProcessed;
461         if ( llAvail > (LONGLONG)This->dwBlockSize )
462                 llAvail = (LONGLONG)This->dwBlockSize;
463         llStart = This->llBytesProcessed;
464         llEnd = llStart + llAvail;
465         This->llBytesProcessed = llEnd;
466
467         *pllStart = This->llBytesProcessed;
468         *plLength = (LONG)llAvail;
469         *prtStart = llStart * QUARTZ_TIMEUNITS / (LONGLONG)This->pFmt->nAvgBytesPerSec;
470         *prtStop = llEnd * QUARTZ_TIMEUNITS / (LONGLONG)This->pFmt->nAvgBytesPerSec;
471
472         return NOERROR;
473 }
474
475 static HRESULT CWavParseImpl_ProcessSample( CParserImpl* pImpl, ULONG nStreamIndex, LONGLONG llStart, LONG lLength, IMediaSample* pSample )
476 {
477         CWavParseImpl*  This = (CWavParseImpl*)pImpl->m_pUserData;
478         BYTE*   pData;
479         LONG    lActLen;
480         HRESULT hr;
481
482         TRACE("(%p)\n",This);
483
484         hr = IMediaSample_GetPointer(pSample,&pData);
485         if ( FAILED(hr) )
486                 return hr;
487         lActLen = (LONG)IMediaSample_GetActualDataLength(pSample);
488         if ( lActLen != lLength )
489                 return E_FAIL;
490
491         switch ( This->iFmtType )
492         {
493         case WaveParse_Native:
494                 break;
495         case WaveParse_Signed8:
496                 AUDIOUTL_ChangeSign8(pData,lActLen);
497                 break;
498         case WaveParse_Signed16BE:
499                 AUDIOUTL_ByteSwap(pData,lActLen);
500                 break;
501         case WaveParse_Unsigned16LE:
502                 AUDIOUTL_ChangeSign16LE(pData,lActLen);
503                 break;
504         case WaveParse_Unsigned16BE:
505                 AUDIOUTL_ChangeSign16BE(pData,lActLen);
506                 AUDIOUTL_ByteSwap(pData,lActLen);
507                 break;
508         default:
509                 FIXME("(%p) - %d not implemented\n", This, This->iFmtType );
510                 return E_FAIL;
511         }
512
513         return NOERROR;
514 }
515
516
517 static const struct ParserHandlers CWavParseImpl_Handlers =
518 {
519         CWavParseImpl_InitParser,
520         CWavParseImpl_UninitParser,
521         CWavParseImpl_GetOutPinName,
522         CWavParseImpl_GetStreamType,
523         CWavParseImpl_CheckStreamType,
524         CWavParseImpl_GetAllocProp,
525         CWavParseImpl_GetNextRequest,
526         CWavParseImpl_ProcessSample,
527
528         /* for IQualityControl */
529         NULL, /* pQualityNotify */
530
531         /* for seeking */
532         NULL, /* pGetSeekingCaps */
533         NULL, /* pIsTimeFormatSupported */
534         NULL, /* pGetCurPos */
535         NULL, /* pSetCurPos */
536         NULL, /* pGetDuration */
537         NULL, /* pSetDuration */
538         NULL, /* pGetStopPos */
539         NULL, /* pSetStopPos */
540         NULL, /* pGetPreroll */
541         NULL, /* pSetPreroll */
542 };
543
544 HRESULT QUARTZ_CreateWaveParser(IUnknown* punkOuter,void** ppobj)
545 {
546         return QUARTZ_CreateParser(
547                 punkOuter,ppobj,
548                 &CLSID_quartzWaveParser,
549                 QUARTZ_WaveParser_Name,
550                 QUARTZ_WaveParserInPin_Name,
551                 &CWavParseImpl_Handlers );
552 }
553
554