Added mappings for a few messages.
[wine] / dlls / avifil32 / iafile.c
1 /*
2  * Copyright 1999 Marcus Meissner
3  * Copyright 2001 Hidenori TAKESHIMA <hidenori@a2.ctktv.ne.jp>
4  *
5  * FIXME - implements editing/writing.
6  */
7
8 #include <string.h>
9 #include <stdio.h>
10 #include <assert.h>
11
12 #include "winbase.h"
13 #include "winnls.h"
14 #include "mmsystem.h"
15 #include "winerror.h"
16 #include "vfw.h"
17 #include "debugtools.h"
18 #include "avifile_private.h"
19
20 DEFAULT_DEBUG_CHANNEL(avifile);
21
22 #define AVIFILE_STREAMS_MAX     4
23
24
25 static HRESULT WINAPI IAVIFile_fnQueryInterface(IAVIFile* iface,REFIID refiid,LPVOID *obj);
26 static ULONG WINAPI IAVIFile_fnAddRef(IAVIFile* iface);
27 static ULONG WINAPI IAVIFile_fnRelease(IAVIFile* iface);
28 static HRESULT WINAPI IAVIFile_fnInfo(IAVIFile*iface,AVIFILEINFOW*afi,LONG size);
29 static HRESULT WINAPI IAVIFile_fnGetStream(IAVIFile*iface,PAVISTREAM*avis,DWORD fccType,LONG lParam);
30 static HRESULT WINAPI IAVIFile_fnCreateStream(IAVIFile*iface,PAVISTREAM*avis,AVISTREAMINFOW*asi);
31 static HRESULT WINAPI IAVIFile_fnWriteData(IAVIFile*iface,DWORD ckid,LPVOID lpData,LONG size);
32 static HRESULT WINAPI IAVIFile_fnReadData(IAVIFile*iface,DWORD ckid,LPVOID lpData,LONG *size);
33 static HRESULT WINAPI IAVIFile_fnEndRecord(IAVIFile*iface);
34 static HRESULT WINAPI IAVIFile_fnDeleteStream(IAVIFile*iface,DWORD fccType,LONG lParam);
35
36 struct ICOM_VTABLE(IAVIFile) iavift = {
37     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
38     IAVIFile_fnQueryInterface,
39     IAVIFile_fnAddRef,
40     IAVIFile_fnRelease,
41     IAVIFile_fnInfo,
42     IAVIFile_fnGetStream,
43     IAVIFile_fnCreateStream,
44     IAVIFile_fnWriteData,
45     IAVIFile_fnReadData,
46     IAVIFile_fnEndRecord,
47     IAVIFile_fnDeleteStream,
48     /* IAVIFILE_fnOpen */ /* FIXME? */
49 };
50
51
52 typedef struct IAVIFileImpl
53 {
54         ICOM_VFIELD(IAVIFile);
55         /* IUnknown stuff */
56         DWORD                   ref;
57         /* IAVIFile stuff */
58         HANDLE                  hf;
59         DWORD                   dwAVIFileCaps;
60         DWORD                   dwAVIFileScale;
61         DWORD                   dwAVIFileRate;
62         DWORD                   dwAVIFileLength;
63         DWORD                   dwAVIFileEditCount;
64         MainAVIHeader           hdr;
65         IAVIStream*             pStreams[AVIFILE_STREAMS_MAX];
66         AVIStreamHeader         strhdrs[AVIFILE_STREAMS_MAX];
67         DWORD                   dwMoviTop;
68         DWORD                   dwCountOfIndexEntry;
69         AVIINDEXENTRY*          pIndexEntry;
70         AVIINDEXENTRY*          pStreamIndexEntry[AVIFILE_STREAMS_MAX+1];
71 } IAVIFileImpl;
72
73
74 /****************************************************************************
75  * AVI file parser.
76  */
77
78 static HRESULT AVIFILE_IAVIFile_ReadNextChunkHeader(
79                 IAVIFileImpl* This, FOURCC* pfcc, DWORD* pdwSize )
80 {
81         BYTE    buf[8];
82         DWORD   dwRead;
83
84         if ( ( !ReadFile( This->hf, buf, 8, &dwRead, NULL ) ) ||
85              ( 8 != dwRead ) )
86                 return AVIERR_FILEREAD;
87         *pfcc = mmioFOURCC(buf[0],buf[1],buf[2],buf[3]);
88         *pdwSize = ( ((DWORD)buf[4])       ) |
89                    ( ((DWORD)buf[5]) <<  8 ) |
90                    ( ((DWORD)buf[6]) << 16 ) |
91                    ( ((DWORD)buf[7]) << 24 );
92
93         return S_OK;
94 }
95
96 static HRESULT AVIFILE_IAVIFile_SkipChunkData(
97                 IAVIFileImpl* This, DWORD dwChunkSize )
98 {
99         LONG    lHigh = 0;
100         DWORD   dwRes;
101
102         if ( dwChunkSize == 0 )
103                 return S_OK;
104
105         SetLastError(NO_ERROR);
106         dwRes = SetFilePointer( This->hf, (LONG)dwChunkSize,
107                                 &lHigh, FILE_CURRENT );
108         if ( dwRes == (DWORD)0xffffffff && GetLastError() != NO_ERROR )
109                 return AVIERR_FILEREAD;
110
111         return S_OK;
112 }
113
114 static HRESULT AVIFILE_IAVIFile_ReadChunkData(
115                 IAVIFileImpl* This, DWORD dwChunkSize,
116                 LPVOID lpvBuf, DWORD dwBufSize, LPDWORD lpdwRead )
117 {
118         if ( dwBufSize > dwChunkSize )
119                 dwBufSize = dwChunkSize;
120         if ( ( !ReadFile( This->hf, lpvBuf, dwBufSize, lpdwRead, NULL ) ) ||
121              ( dwBufSize != *lpdwRead ) )
122                 return AVIERR_FILEREAD;
123
124         return AVIFILE_IAVIFile_SkipChunkData( This, dwChunkSize - dwBufSize );
125 }
126
127 static HRESULT AVIFILE_IAVIFile_SeekToSpecifiedChunk(
128                 IAVIFileImpl* This, FOURCC fccType, DWORD* pdwLen )
129 {
130         HRESULT hr;
131         FOURCC  fcc;
132         BYTE    buf[4];
133         DWORD   dwRead;
134
135         while ( 1 )
136         {
137                 hr = AVIFILE_IAVIFile_ReadNextChunkHeader(
138                                 This, &fcc, pdwLen );
139                 if ( hr != S_OK )
140                         return hr;
141                 if ( fcc == fccType )
142                         return S_OK;
143
144                 if ( fcc == FOURCC_LIST )
145                 {
146                     if ( ( !ReadFile( This->hf, buf, 4, &dwRead, NULL ) ) ||
147                          ( 4 != dwRead ) )
148                         return AVIERR_FILEREAD;
149                 }
150                 else
151                 {
152                     hr = AVIFILE_IAVIFile_SkipChunkData(
153                                         This, *pdwLen );
154                     if ( hr != S_OK )
155                         return hr;
156                 }
157         }
158 }
159
160
161 WINE_AVISTREAM_DATA* AVIFILE_Alloc_IAVIStreamData( DWORD dwFmtLen )
162 {
163         WINE_AVISTREAM_DATA*    pData;
164
165         pData = (WINE_AVISTREAM_DATA*)
166                 HeapAlloc( AVIFILE_data.hHeap,HEAP_ZERO_MEMORY,
167                            sizeof(WINE_AVISTREAM_DATA) );
168         if ( pData == NULL )
169                 return NULL;
170         if ( dwFmtLen > 0 )
171         {
172                 pData->pbFmt = (BYTE*)
173                         HeapAlloc( AVIFILE_data.hHeap,HEAP_ZERO_MEMORY,
174                                    sizeof(BYTE)*dwFmtLen );
175                 if ( pData->pbFmt == NULL )
176                 {
177                         AVIFILE_Free_IAVIStreamData( pData );
178                         return NULL;
179                 }
180         }
181         pData->dwFmtLen = dwFmtLen;
182
183         return pData;
184 }
185
186 void AVIFILE_Free_IAVIStreamData( WINE_AVISTREAM_DATA* pData )
187 {
188         if ( pData != NULL )
189         {
190                 if ( pData->pbFmt != NULL )
191                         HeapFree( AVIFILE_data.hHeap,0,pData->pbFmt );
192                 HeapFree( AVIFILE_data.hHeap,0,pData );
193         }
194 }
195
196 static void AVIFILE_IAVIFile_InitIndexTable(
197                 IAVIFileImpl* This,
198                 AVIINDEXENTRY* pIndexBuf,
199                 AVIINDEXENTRY* pIndexData,
200                 DWORD dwCountOfIndexEntry )
201 {
202         DWORD   dwStreamIndex;
203         DWORD   dwIndex;
204         FOURCC  ckid;
205
206         dwStreamIndex = 0;
207         for ( ; dwStreamIndex < (AVIFILE_STREAMS_MAX+1); dwStreamIndex ++ )
208                 This->pStreamIndexEntry[dwStreamIndex] = NULL;
209
210         dwStreamIndex = 0;
211         for ( ; dwStreamIndex < This->hdr.dwStreams; dwStreamIndex ++ )
212         {
213                 ckid = mmioFOURCC('0','0'+dwStreamIndex,0,0);
214                 TRACE( "testing ckid %c%c%c%c\n",
215                         (int)(ckid>> 0)&0xff,
216                         (int)(ckid>> 8)&0xff,
217                         (int)(ckid>>16)&0xff,
218                         (int)(ckid>>24)&0xff );
219                 This->pStreamIndexEntry[dwStreamIndex] = pIndexBuf;
220                 FIXME( "pIndexBuf = %p\n", pIndexBuf );
221                 for ( dwIndex = 0; dwIndex < dwCountOfIndexEntry; dwIndex++ )
222                 {
223                     TRACE( "ckid %c%c%c%c\n",
224                             (int)(pIndexData[dwIndex].ckid>> 0)&0xff,
225                             (int)(pIndexData[dwIndex].ckid>> 8)&0xff,
226                             (int)(pIndexData[dwIndex].ckid>>16)&0xff,
227                             (int)(pIndexData[dwIndex].ckid>>24)&0xff );
228                             
229                     if ( (pIndexData[dwIndex].ckid & mmioFOURCC(0xff,0xff,0,0))
230                                                                 == ckid )
231                     {
232                         memcpy( pIndexBuf, &pIndexData[dwIndex],
233                                 sizeof(AVIINDEXENTRY) );
234                         pIndexBuf ++;
235                     }
236                 }
237                 FIXME( "pIndexBuf = %p\n", pIndexBuf );
238         }
239         This->pStreamIndexEntry[This->hdr.dwStreams] = pIndexBuf;
240 }
241
242
243 /****************************************************************************
244  * Create an IAVIFile object.
245  */
246
247 static HRESULT AVIFILE_IAVIFile_Construct( IAVIFileImpl* This );
248 static void AVIFILE_IAVIFile_Destruct( IAVIFileImpl* This );
249
250 HRESULT AVIFILE_CreateIAVIFile(void** ppobj)
251 {
252         IAVIFileImpl    *This;
253         HRESULT         hr;
254
255         TRACE("(%p)\n",ppobj);
256         *ppobj = NULL;
257         This = (IAVIFileImpl*)HeapAlloc(AVIFILE_data.hHeap,HEAP_ZERO_MEMORY,
258                                         sizeof(IAVIFileImpl));
259         if ( This == NULL )
260                 return AVIERR_MEMORY;
261         This->ref = 1;
262         ICOM_VTBL(This) = &iavift;
263         hr = AVIFILE_IAVIFile_Construct( This );
264         if ( hr != S_OK )
265         {
266                 AVIFILE_IAVIFile_Destruct( This );
267                 return hr;
268         }
269
270         TRACE("new -> %p\n",This);
271         *ppobj = (LPVOID)This;
272
273         return S_OK;
274 }
275
276 /****************************************************************************
277  * IUnknown interface
278  */
279
280 static HRESULT WINAPI IAVIFile_fnQueryInterface(IAVIFile* iface,REFIID refiid,LPVOID *obj) {
281         ICOM_THIS(IAVIFileImpl,iface);
282
283         TRACE("(%p)->QueryInterface(%s,%p)\n",This,debugstr_guid(refiid),obj);
284         if ( IsEqualGUID(&IID_IUnknown,refiid) ||
285              IsEqualGUID(&IID_IAVIFile,refiid) )
286         {
287                 *obj = iface;
288                 IAVIFile_AddRef(iface);
289                 return S_OK;
290         }
291         return OLE_E_ENUM_NOMORE;
292 }
293
294 static ULONG WINAPI IAVIFile_fnAddRef(IAVIFile* iface) {
295         ICOM_THIS(IAVIFileImpl,iface);
296
297         TRACE("(%p)->AddRef()\n",iface);
298         return ++(This->ref);
299 }
300
301 static ULONG WINAPI IAVIFile_fnRelease(IAVIFile* iface) {
302         ICOM_THIS(IAVIFileImpl,iface);
303
304         TRACE("(%p)->Release()\n",iface);
305         if ( (--(This->ref)) > 0 )
306                 return This->ref;
307
308         AVIFILE_IAVIFile_Destruct(This);
309         HeapFree(AVIFILE_data.hHeap,0,iface);
310         return 0;
311 }
312
313 /****************************************************************************
314  * IAVIFile interface
315  */
316
317 static HRESULT AVIFILE_IAVIFile_Construct( IAVIFileImpl* This )
318 {
319         DWORD   dwIndex;
320
321         This->hf = INVALID_HANDLE_VALUE;
322         This->dwAVIFileCaps = 0;
323         This->dwAVIFileScale = 0;
324         This->dwAVIFileRate = 0;
325         This->dwAVIFileLength = 0;
326         This->dwAVIFileEditCount = 0;
327         for ( dwIndex = 0; dwIndex < AVIFILE_STREAMS_MAX; dwIndex++ )
328                 This->pStreams[dwIndex] = NULL;
329         This->dwCountOfIndexEntry = 0;
330         This->pIndexEntry = NULL;
331
332         AVIFILE_data.dwClassObjRef ++;
333
334         return S_OK;
335 }
336
337 static void AVIFILE_IAVIFile_Destruct( IAVIFileImpl* This )
338 {
339         DWORD   dwIndex;
340
341         if ( This->pIndexEntry != NULL )
342         {
343                 HeapFree(AVIFILE_data.hHeap,0,This->pIndexEntry);
344                 This->pIndexEntry = NULL;
345         }
346
347         for ( dwIndex = 0; dwIndex < AVIFILE_STREAMS_MAX; dwIndex++ )
348         {
349                 if ( This->pStreams[dwIndex] != NULL )
350                 {
351                         IAVIStream_Release( This->pStreams[dwIndex] );
352                         This->pStreams[dwIndex] = NULL;
353                 }
354         }
355
356         if ( This->hf != INVALID_HANDLE_VALUE )
357                 CloseHandle( This->hf );
358
359         AVIFILE_data.dwClassObjRef --;
360 }
361
362 static HRESULT WINAPI IAVIFile_fnInfo(IAVIFile*iface,AVIFILEINFOW*afi,LONG size)
363 {
364         ICOM_THIS(IAVIFileImpl,iface);
365         AVIFILEINFOW    fiw;
366
367         FIXME("(%p)->Info(%p,%ld)\n",iface,afi,size);
368
369         memset( &fiw, 0, sizeof(fiw) );
370         fiw.dwMaxBytesPerSec = This->hdr.dwMaxBytesPerSec;
371         fiw.dwFlags = This->hdr.dwFlags;
372         fiw.dwCaps = This->dwAVIFileCaps;
373         fiw.dwStreams = This->hdr.dwStreams;
374         fiw.dwSuggestedBufferSize = This->hdr.dwSuggestedBufferSize;
375         fiw.dwWidth = This->hdr.dwWidth;
376         fiw.dwHeight = This->hdr.dwHeight;
377         fiw.dwScale = This->dwAVIFileScale; /* FIXME */
378         fiw.dwRate = This->dwAVIFileRate; /* FIXME */
379         fiw.dwLength = This->dwAVIFileLength; /* FIXME */
380         fiw.dwEditCount = This->dwAVIFileEditCount; /* FIXME */
381         /* fiw.szFileType[64]; */
382
383         if ( size > sizeof(AVIFILEINFOW) )
384                 size = sizeof(AVIFILEINFOW);
385         memcpy( afi, &fiw, size );
386
387         return S_OK;
388 }
389
390 static HRESULT WINAPI IAVIFile_fnGetStream(IAVIFile*iface,PAVISTREAM*avis,DWORD fccType,LONG lParam)
391 {
392         ICOM_THIS(IAVIFileImpl,iface);
393
394         FIXME("(%p)->GetStream(%p,0x%08lx,%ld)\n",iface,avis,fccType,lParam);
395         if ( fccType != 0 )
396                 return E_FAIL;
397         if ( lParam < 0 || lParam >= This->hdr.dwStreams )
398                 return E_FAIL;
399         *avis = This->pStreams[lParam];
400         IAVIStream_AddRef( *avis );
401
402         return S_OK;
403 }
404
405 static HRESULT WINAPI IAVIFile_fnCreateStream(IAVIFile*iface,PAVISTREAM*avis,AVISTREAMINFOW*asi)
406 {
407         ICOM_THIS(IAVIFileImpl,iface);
408
409         FIXME("(%p,%p,%p)\n",This,avis,asi);
410         return E_FAIL;
411 }
412
413 static HRESULT WINAPI IAVIFile_fnWriteData(IAVIFile*iface,DWORD ckid,LPVOID lpData,LONG size)
414 {
415         ICOM_THIS(IAVIFileImpl,iface);
416
417         FIXME("(%p)->WriteData(0x%08lx,%p,%ld)\n",This,ckid,lpData,size);
418         /* FIXME: write data to file */
419         return E_FAIL;
420 }
421
422 static HRESULT WINAPI IAVIFile_fnReadData(IAVIFile*iface,DWORD ckid,LPVOID lpData,LONG *size)
423 {
424         ICOM_THIS(IAVIFileImpl,iface);
425
426         FIXME("(%p)->ReadData(0x%08lx,%p,%p)\n",This,ckid,lpData,size);
427         /* FIXME: read at most size bytes from file */
428
429         return E_FAIL;
430 }
431
432 static HRESULT WINAPI IAVIFile_fnEndRecord(IAVIFile*iface)
433 {
434         ICOM_THIS(IAVIFileImpl,iface);
435
436         FIXME("(%p)->EndRecord()\n",This);
437         /* FIXME: end record? */
438         return E_FAIL;
439 }
440
441 static HRESULT WINAPI IAVIFile_fnDeleteStream(IAVIFile*iface,DWORD fccType,LONG lParam)
442 {
443         ICOM_THIS(IAVIFileImpl,iface);
444
445         FIXME("(%p)->DeleteStream(0x%08lx,%ld)\n",This,fccType,lParam);
446         /* FIXME: delete stream? */
447         return E_FAIL;
448 }
449
450 /*****************************************************************************
451  *      AVIFILE_IAVIFile_Open (internal)
452  */
453 HRESULT AVIFILE_IAVIFile_Open( PAVIFILE paf, LPCWSTR szFile, UINT uMode )
454 {
455         ICOM_THIS(IAVIFileImpl,paf);
456         HRESULT         hr;
457         DWORD           dwAcc;
458         DWORD           dwShared;
459         DWORD           dwCreate;
460         BYTE            buf[12];
461         DWORD           dwRead;
462         FOURCC          fccFileType;
463         DWORD           dwLen;
464         DWORD           dwIndex;
465
466         FIXME("(%p)->Open(%p,%u)\n",This,szFile,uMode);
467
468         if ( This->hf != INVALID_HANDLE_VALUE )
469         {
470                 CloseHandle( This->hf );
471                 This->hf = INVALID_HANDLE_VALUE;
472         }
473
474         switch ( uMode & 0x3 )
475         {
476         case OF_READ: /* 0x0 */
477                 dwAcc = GENERIC_READ;
478                 dwCreate = OPEN_EXISTING;
479                 This->dwAVIFileCaps = AVIFILECAPS_CANREAD;
480                 break;
481         case OF_WRITE: /* 0x1 */
482                 dwAcc = GENERIC_WRITE;
483                 dwCreate = OPEN_ALWAYS;
484                 This->dwAVIFileCaps = AVIFILECAPS_CANWRITE;
485                 break;
486         case OF_READWRITE: /* 0x2 */
487                 dwAcc = GENERIC_READ|GENERIC_WRITE;
488                 dwCreate = OPEN_ALWAYS;
489                 This->dwAVIFileCaps = AVIFILECAPS_CANREAD|AVIFILECAPS_CANWRITE;
490                 break;
491         default:
492                 return E_FAIL;
493         }
494
495         if ( This->dwAVIFileCaps & AVIFILECAPS_CANWRITE )
496         {
497                 FIXME( "editing AVI is currently not supported!\n" );
498                 return E_FAIL;
499         }
500
501         switch ( uMode & 0x70 )
502         {
503         case OF_SHARE_COMPAT: /* 0x00 */
504                 dwShared = FILE_SHARE_READ|FILE_SHARE_WRITE;
505                 break;
506         case OF_SHARE_EXCLUSIVE: /* 0x10 */
507                 dwShared = 0;
508                 break;
509         case OF_SHARE_DENY_WRITE: /* 0x20 */
510                 dwShared = FILE_SHARE_READ;
511                 break;
512         case OF_SHARE_DENY_READ: /* 0x30 */
513                 dwShared = FILE_SHARE_WRITE;
514                 break;
515         case OF_SHARE_DENY_NONE: /* 0x40 */
516                 dwShared = FILE_SHARE_READ|FILE_SHARE_WRITE;
517                 break;
518         default:
519                 return E_FAIL;
520         }
521         if ( uMode & OF_CREATE )
522                 dwCreate = CREATE_ALWAYS;
523
524         This->hf = CreateFileW( szFile, dwAcc, dwShared, NULL,
525                                 dwCreate, FILE_ATTRIBUTE_NORMAL,
526                                 (HANDLE)NULL );
527         if ( This->hf == INVALID_HANDLE_VALUE )
528                 return AVIERR_FILEOPEN;
529
530         if ( dwAcc & GENERIC_READ )
531         {
532             if ( !ReadFile( This->hf, buf, 12, &dwRead, NULL ) )
533                 return AVIERR_FILEREAD;
534             if ( dwRead == 12 )
535             {
536                 if ( mmioFOURCC(buf[0],buf[1],buf[2],buf[3]) != FOURCC_RIFF )
537                         return AVIERR_BADFORMAT;
538
539                 fccFileType = mmioFOURCC(buf[8],buf[9],buf[10],buf[11]);
540                 if ( fccFileType != formtypeAVI )
541                         return AVIERR_BADFORMAT;
542
543                 /* get AVI main header. */
544                 hr = AVIFILE_IAVIFile_SeekToSpecifiedChunk(
545                                 This, ckidAVIMAINHDR, &dwLen );
546                 if ( hr != S_OK )
547                         return hr;
548                 if ( dwLen < (sizeof(DWORD)*10) )
549                         return AVIERR_BADFORMAT;
550                 hr = AVIFILE_IAVIFile_ReadChunkData(
551                                 This, dwLen,
552                                 &(This->hdr), sizeof(MainAVIHeader), &dwLen );
553                 if ( This->hdr.dwStreams == 0 ||
554                      This->hdr.dwStreams > AVIFILE_STREAMS_MAX )
555                         return AVIERR_BADFORMAT;
556
557                 /* get stream headers. */
558                 dwIndex = 0;
559                 while ( dwIndex < This->hdr.dwStreams )
560                 {
561                         WINE_AVISTREAM_DATA*    pData;
562
563                         hr = AVIFILE_IAVIFile_SeekToSpecifiedChunk(
564                                         This, ckidSTREAMHEADER, &dwLen );
565                         if ( hr != S_OK )
566                                 return hr;
567                         if ( dwLen < (sizeof(DWORD)*12) )
568                                 return AVIERR_BADFORMAT;
569                         hr = AVIFILE_IAVIFile_ReadChunkData(
570                                 This, dwLen,
571                                 &This->strhdrs[dwIndex],
572                                 sizeof(AVIStreamHeader), &dwLen );
573
574                         hr = AVIFILE_IAVIFile_SeekToSpecifiedChunk(
575                                         This, ckidSTREAMFORMAT, &dwLen );
576                         if ( hr != S_OK )
577                                 return hr;
578                         pData = AVIFILE_Alloc_IAVIStreamData( dwLen );
579                         if ( pData == NULL )
580                                 return AVIERR_MEMORY;
581                         hr = AVIFILE_IAVIFile_ReadChunkData(
582                                 This, dwLen,
583                                 pData->pbFmt, dwLen, &dwLen );
584                         if ( hr != S_OK )
585                         {
586                                 AVIFILE_Free_IAVIStreamData( pData );
587                                 return hr;
588                         }
589                         pData->dwStreamIndex = dwIndex;
590                         pData->pstrhdr = &This->strhdrs[dwIndex];
591
592                         hr = AVIStreamCreate(&This->pStreams[dwIndex],
593                                              (LONG)paf, (LONG)(pData), NULL );
594                         if ( hr != S_OK )
595                         {
596                                 AVIFILE_Free_IAVIStreamData( pData );
597                                 return hr;
598                         }
599
600                         if ( (This->strhdrs[dwIndex].fccType
601                                         == mmioFOURCC('v','i','d','s')) ||
602                              (This->strhdrs[dwIndex].fccType
603                                         == mmioFOURCC('V','I','D','S')) )
604                         {
605                                 This->dwAVIFileScale =
606                                         This->strhdrs[dwIndex].dwScale;
607                                 This->dwAVIFileRate =
608                                         This->strhdrs[dwIndex].dwRate;
609                                 This->dwAVIFileLength =
610                                         This->strhdrs[dwIndex].dwLength;
611                         }
612                         else
613                         if ( This->dwAVIFileScale == 0 )
614                         {
615                                 This->dwAVIFileScale =
616                                         This->strhdrs[dwIndex].dwScale;
617                                 This->dwAVIFileRate =
618                                         This->strhdrs[dwIndex].dwRate;
619                                 This->dwAVIFileLength =
620                                         This->strhdrs[dwIndex].dwLength;
621                         }
622
623                         dwIndex ++;
624                 }
625
626                 /* skip movi. */
627                 while ( 1 )
628                 {
629                         hr = AVIFILE_IAVIFile_SeekToSpecifiedChunk(
630                                         This, FOURCC_LIST, &dwLen );
631                         if ( hr != S_OK )
632                                 return hr;
633                         if ( dwLen < 4 )
634                                 return AVIERR_BADFORMAT;
635
636                         This->dwMoviTop = SetFilePointer( This->hf,0,NULL,FILE_CURRENT );
637                         if ( This->dwMoviTop == 0xffffffff )
638                                 return AVIERR_BADFORMAT;
639
640                         if ( ( !ReadFile(This->hf, buf, 4, &dwRead, NULL) ) ||
641                              ( dwRead != 4 ) )
642                                 return AVIERR_FILEREAD;
643
644                         hr = AVIFILE_IAVIFile_SkipChunkData(
645                                         This, dwLen - 4 );
646                         if ( hr != S_OK )
647                                 return hr;
648                         if ( mmioFOURCC(buf[0],buf[1],buf[2],buf[3])
649                                 == mmioFOURCC('m', 'o', 'v', 'i') )
650                                 break;
651                 }
652
653                 /* get idx1. */
654                 hr = AVIFILE_IAVIFile_SeekToSpecifiedChunk(
655                                 This, ckidAVINEWINDEX, &dwLen );
656                 if ( hr != S_OK )
657                         return hr;
658
659                 This->dwCountOfIndexEntry = dwLen / sizeof(AVIINDEXENTRY);
660                 This->pIndexEntry = (AVIINDEXENTRY*)
661                         HeapAlloc(AVIFILE_data.hHeap,HEAP_ZERO_MEMORY,
662                                   sizeof(AVIINDEXENTRY) *
663                                   This->dwCountOfIndexEntry * 2 );
664                 if ( This->pIndexEntry == NULL )
665                         return AVIERR_MEMORY;
666                 hr = AVIFILE_IAVIFile_ReadChunkData(
667                                 This, dwLen,
668                                 This->pIndexEntry + This->dwCountOfIndexEntry,
669                                 sizeof(AVIINDEXENTRY) *
670                                 This->dwCountOfIndexEntry, &dwLen );
671                 if ( hr != S_OK )
672                         return hr;
673                 AVIFILE_IAVIFile_InitIndexTable(
674                                 This, This->pIndexEntry,
675                                 This->pIndexEntry + This->dwCountOfIndexEntry,
676                                 This->dwCountOfIndexEntry );
677             }
678             else
679             {
680                 /* FIXME - create the handle has GENERIC_WRITE access. */
681                 return AVIERR_FILEREAD;
682             }
683         }
684         else
685         {
686             return AVIERR_FILEOPEN; /* FIXME */
687         }
688
689         return S_OK;
690 }
691
692 /*****************************************************************************
693  *      AVIFILE_IAVIFile_GetIndexTable (internal)
694  */
695 HRESULT AVIFILE_IAVIFile_GetIndexTable( PAVIFILE paf, DWORD dwStreamIndex,
696                                         AVIINDEXENTRY** ppIndexEntry,
697                                         DWORD* pdwCountOfIndexEntry )
698 {
699         ICOM_THIS(IAVIFileImpl,paf);
700
701         if ( dwStreamIndex < 0 || dwStreamIndex >= This->hdr.dwStreams )
702         {
703                 FIXME( "invalid stream index %lu\n", dwStreamIndex );
704                 return E_FAIL;
705         }
706         FIXME( "cur %p, next %p\n",
707                 This->pStreamIndexEntry[dwStreamIndex],
708                 This->pStreamIndexEntry[dwStreamIndex+1] );
709         *ppIndexEntry = This->pStreamIndexEntry[dwStreamIndex];
710         *pdwCountOfIndexEntry =
711                 This->pStreamIndexEntry[dwStreamIndex+1] -
712                         This->pStreamIndexEntry[dwStreamIndex];
713
714         return S_OK;
715 }
716
717 /*****************************************************************************
718  *      AVIFILE_IAVIFile_ReadMovieData (internal)
719  */
720 HRESULT AVIFILE_IAVIFile_ReadMovieData( PAVIFILE paf, DWORD dwOffset,
721                                         DWORD dwLength, LPVOID lpvBuf )
722 {
723         ICOM_THIS(IAVIFileImpl,paf);
724         LONG    lHigh = 0;
725         DWORD   dwRes;
726
727         if ( dwLength == 0 )
728                 return S_OK;
729         SetLastError(NO_ERROR);
730         dwRes = SetFilePointer( This->hf, (LONG)(dwOffset+This->dwMoviTop),
731                                 &lHigh, FILE_BEGIN );
732         if ( dwRes == (DWORD)0xffffffff && GetLastError() != NO_ERROR )
733                 return AVIERR_FILEREAD;
734
735         if ( ( !ReadFile(This->hf, lpvBuf, dwLength, &dwRes, NULL) ) ||
736              ( dwLength != dwRes ) )
737         {
738                 FIXME( "error in ReadFile()\n" );
739                 return AVIERR_FILEREAD;
740         }
741
742         return S_OK;
743 }
744