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