winmm: Mark headers WHDR_DONE at the last possible time.
[wine] / dlls / winmm / tests / mmio.c
1 /*
2  * Unit tests for mmio APIs
3  *
4  * Copyright 2005 Dmitry Timoshkov
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 #include <stdarg.h>
22
23 #include "windef.h"
24 #include "winbase.h"
25 #include "wingdi.h"
26 #include "mmsystem.h"
27 #include "vfw.h"
28 #include "wine/test.h"
29
30 static DWORD RIFF_buf[] =
31 {
32     FOURCC_RIFF, 32*sizeof(DWORD), mmioFOURCC('A','V','I',' '),
33     FOURCC_LIST, 29*sizeof(DWORD), listtypeAVIHEADER, ckidAVIMAINHDR,
34     sizeof(MainAVIHeader), 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
35     0xdeadbeef, 0xdeadbeef, 0xdeadbeef,0xdeadbeef,
36     0xdeadbeef, 0xdeadbeef, 0xdeadbeef,0xdeadbeef,
37     0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
38     FOURCC_LIST, 10*sizeof(DWORD),listtypeSTREAMHEADER, ckidSTREAMHEADER,
39     7*sizeof(DWORD), streamtypeVIDEO, 0xdeadbeef, 0xdeadbeef,
40     0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
41     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
42     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
43     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
44     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
45 };
46
47 static void expect_buf_offset_dbg(HMMIO hmmio, LONG off, int line)
48 {
49     MMIOINFO mmio;
50     LONG ret;
51
52     memset(&mmio, 0, sizeof(mmio));
53     ret = mmioGetInfo(hmmio, &mmio, 0);
54     ok_(__FILE__, line)(ret == MMSYSERR_NOERROR, "mmioGetInfo error %u\n", ret);
55     ok_(__FILE__, line)(mmio.lBufOffset == 0, "expected 0, got %d\n", mmio.lBufOffset);
56     ret = mmioSeek(hmmio, 0, SEEK_CUR);
57     ok_(__FILE__, line)(ret == off, "expected %d, got %d\n", off, ret);
58 }
59
60 #define expect_buf_offset(a1, a2) expect_buf_offset_dbg(a1, a2, __LINE__)
61
62 static void test_mmioDescend(char *fname)
63 {
64     MMRESULT ret;
65     HMMIO hmmio;
66     MMIOINFO mmio;
67     MMCKINFO ckRiff, ckList, ck, ckList2;
68
69     memset(&mmio, 0, sizeof(mmio));
70     mmio.fccIOProc = fname ? FOURCC_DOS : FOURCC_MEM;
71     mmio.cchBuffer = sizeof(RIFF_buf);
72     mmio.pchBuffer = (char *)RIFF_buf;
73     hmmio = mmioOpen(fname, &mmio, MMIO_READ);
74     if (fname && !hmmio)
75     {
76         trace("No optional %s file. Skipping the test\n", fname);
77         return;
78     }
79     ok(hmmio != 0, "mmioOpen error %u\n", mmio.wErrorRet);
80
81     expect_buf_offset(hmmio, 0);
82
83     /* first normal RIFF AVI parsing */
84     ret = mmioDescend(hmmio, &ckRiff, NULL, 0);
85     ok(ret == MMSYSERR_NOERROR, "mmioDescend error %u\n", ret);
86     ok(ckRiff.ckid == FOURCC_RIFF, "wrong ckid: %04x\n", ckRiff.ckid);
87     ok(ckRiff.fccType == formtypeAVI, "wrong fccType: %04x\n", ckRiff.fccType);
88     ok(ckRiff.dwDataOffset == 8, "expected 8 got %u\n", ckRiff.dwDataOffset);
89     trace("ckid %4.4s cksize %04x fccType %4.4s off %04x flags %04x\n",
90           (LPCSTR)&ckRiff.ckid, ckRiff.cksize, (LPCSTR)&ckRiff.fccType,
91           ckRiff.dwDataOffset, ckRiff.dwFlags);
92
93     expect_buf_offset(hmmio, 12);
94
95     ret = mmioDescend(hmmio, &ckList, &ckRiff, 0);
96     ok(ret == MMSYSERR_NOERROR, "mmioDescend error %u\n", ret);
97     ok(ckList.ckid == FOURCC_LIST, "wrong ckid: %04x\n", ckList.ckid);
98     ok(ckList.fccType == listtypeAVIHEADER, "wrong fccType: %04x\n", ckList.fccType);
99     ok(ckList.dwDataOffset == 20, "expected 20 got %u\n", ckList.dwDataOffset);
100     trace("ckid %4.4s cksize %04x fccType %4.4s off %04x flags %04x\n",
101           (LPCSTR)&ckList.ckid, ckList.cksize, (LPCSTR)&ckList.fccType,
102           ckList.dwDataOffset, ckList.dwFlags);
103
104     expect_buf_offset(hmmio, 24);
105
106     ret = mmioDescend(hmmio, &ck, &ckList, 0);
107     ok(ret == MMSYSERR_NOERROR, "mmioDescend error %u\n", ret);
108     ok(ck.ckid == ckidAVIMAINHDR, "wrong ckid: %04x\n", ck.ckid);
109     ok(ck.fccType == 0, "wrong fccType: %04x\n", ck.fccType);
110     trace("ckid %4.4s cksize %04x fccType %4.4s off %04x flags %04x\n",
111           (LPCSTR)&ck.ckid, ck.cksize, (LPCSTR)&ck.fccType,
112           ck.dwDataOffset, ck.dwFlags);
113
114     expect_buf_offset(hmmio, 32);
115
116     /* Skip chunk data */
117     ret = mmioSeek(hmmio, ck.cksize, SEEK_CUR);
118     ok(ret == 0x58, "expected 0x58, got %#x\n", ret);
119
120     ret = mmioDescend(hmmio, &ckList2, &ckList, 0);
121     ok(ret == MMSYSERR_NOERROR, "mmioDescend error %u\n", ret);
122     ok(ckList2.ckid == FOURCC_LIST, "wrong ckid: %04x\n", ckList2.ckid);
123     ok(ckList2.fccType == listtypeSTREAMHEADER, "wrong fccType: %04x\n", ckList2.fccType);
124     trace("ckid %4.4s cksize %04x fccType %4.4s off %04x flags %04x\n",
125           (LPCSTR)&ckList2.ckid, ckList2.cksize, (LPCSTR)&ckList2.fccType,
126           ckList2.dwDataOffset, ckList2.dwFlags);
127
128     expect_buf_offset(hmmio, 100);
129
130     ret = mmioDescend(hmmio, &ck, &ckList2, 0);
131     ok(ret == MMSYSERR_NOERROR, "mmioDescend error %u\n", ret);
132     ok(ck.ckid == ckidSTREAMHEADER, "wrong ckid: %04x\n", ck.ckid);
133     ok(ck.fccType == 0, "wrong fccType: %04x\n", ck.fccType);
134     trace("ckid %4.4s cksize %04x fccType %4.4s off %04x flags %04x\n",
135           (LPCSTR)&ck.ckid, ck.cksize, (LPCSTR)&ck.fccType,
136           ck.dwDataOffset, ck.dwFlags);
137
138     expect_buf_offset(hmmio, 108);
139
140     /* test various mmioDescend flags */
141
142     mmioSeek(hmmio, 0, SEEK_SET);
143     memset(&ck, 0x66, sizeof(ck));
144     ret = mmioDescend(hmmio, &ck, NULL, MMIO_FINDRIFF);
145     ok(ret == MMIOERR_CHUNKNOTFOUND ||
146        ret == MMIOERR_INVALIDFILE, "mmioDescend returned %u\n", ret);
147
148     mmioSeek(hmmio, 0, SEEK_SET);
149     memset(&ck, 0x66, sizeof(ck));
150     ck.ckid = 0;
151     ret = mmioDescend(hmmio, &ck, NULL, MMIO_FINDRIFF);
152     ok(ret == MMIOERR_CHUNKNOTFOUND ||
153        ret == MMIOERR_INVALIDFILE, "mmioDescend returned %u\n", ret);
154
155     mmioSeek(hmmio, 0, SEEK_SET);
156     memset(&ck, 0x66, sizeof(ck));
157     ck.fccType = 0;
158     ret = mmioDescend(hmmio, &ck, NULL, MMIO_FINDRIFF);
159     ok(ret == MMSYSERR_NOERROR, "mmioDescend error %u\n", ret);
160     ok(ck.ckid == FOURCC_RIFF, "wrong ckid: %04x\n", ck.ckid);
161     ok(ck.fccType == formtypeAVI, "wrong fccType: %04x\n", ck.fccType);
162
163     mmioSeek(hmmio, 0, SEEK_SET);
164     memset(&ck, 0x66, sizeof(ck));
165     ret = mmioDescend(hmmio, &ck, NULL, 0);
166     ok(ret == MMSYSERR_NOERROR, "mmioDescend error %u\n", ret);
167     ok(ck.ckid == FOURCC_RIFF, "wrong ckid: %04x\n", ck.ckid);
168     ok(ck.fccType == formtypeAVI, "wrong fccType: %04x\n", ck.fccType);
169
170     /* do NOT seek, use current file position */
171     memset(&ck, 0x66, sizeof(ck));
172     ck.fccType = 0;
173     ret = mmioDescend(hmmio, &ck, NULL, MMIO_FINDLIST);
174     ok(ret == MMSYSERR_NOERROR, "mmioDescend error %u\n", ret);
175     ok(ck.ckid == FOURCC_LIST, "wrong ckid: %04x\n", ck.ckid);
176     ok(ck.fccType == listtypeAVIHEADER, "wrong fccType: %04x\n", ck.fccType);
177
178     mmioSeek(hmmio, 0, SEEK_SET);
179     memset(&ck, 0x66, sizeof(ck));
180     ck.ckid = 0;
181     ck.fccType = listtypeAVIHEADER;
182     ret = mmioDescend(hmmio, &ck, NULL, MMIO_FINDCHUNK);
183     ok(ret == MMSYSERR_NOERROR, "mmioDescend error %u\n", ret);
184     ok(ck.ckid == FOURCC_RIFF, "wrong ckid: %04x\n", ck.ckid);
185     ok(ck.fccType == formtypeAVI, "wrong fccType: %04x\n", ck.fccType);
186
187     /* do NOT seek, use current file position */
188     memset(&ck, 0x66, sizeof(ck));
189     ck.ckid = FOURCC_LIST;
190     ret = mmioDescend(hmmio, &ck, NULL, MMIO_FINDCHUNK);
191     ok(ret == MMSYSERR_NOERROR, "mmioDescend error %u\n", ret);
192     ok(ck.ckid == FOURCC_LIST, "wrong ckid: %04x\n", ck.ckid);
193     ok(ck.fccType == listtypeAVIHEADER, "wrong fccType: %04x\n", ck.fccType);
194
195     mmioSeek(hmmio, 0, SEEK_SET);
196     memset(&ck, 0x66, sizeof(ck));
197     ck.ckid = FOURCC_RIFF;
198     ret = mmioDescend(hmmio, &ck, NULL, MMIO_FINDCHUNK);
199     ok(ret == MMSYSERR_NOERROR, "mmioDescend error %u\n", ret);
200     ok(ck.ckid == FOURCC_RIFF, "wrong ckid: %04x\n", ck.ckid);
201     ok(ck.fccType == formtypeAVI, "wrong fccType: %04x\n", ck.fccType);
202
203     /* do NOT seek, use current file position */
204     memset(&ckList, 0x66, sizeof(ckList));
205     ckList.ckid = 0;
206     ret = mmioDescend(hmmio, &ckList, &ck, MMIO_FINDCHUNK);
207     ok(ret == MMSYSERR_NOERROR, "mmioDescend error %u\n", ret);
208     ok(ckList.ckid == FOURCC_LIST, "wrong ckid: %04x\n", ckList.ckid);
209     ok(ckList.fccType == listtypeAVIHEADER, "wrong fccType: %04x\n", ckList.fccType);
210
211     mmioSeek(hmmio, 0, SEEK_SET);
212     memset(&ck, 0x66, sizeof(ck));
213     ret = mmioDescend(hmmio, &ck, NULL, MMIO_FINDCHUNK);
214     ok(ret == MMIOERR_CHUNKNOTFOUND ||
215        ret == MMIOERR_INVALIDFILE, "mmioDescend returned %u\n", ret);
216     ok(ck.ckid != 0x66666666, "wrong ckid: %04x\n", ck.ckid);
217     ok(ck.fccType != 0x66666666, "wrong fccType: %04x\n", ck.fccType);
218     ok(ck.dwDataOffset != 0x66666666, "wrong dwDataOffset: %04x\n", ck.dwDataOffset);
219
220     mmioSeek(hmmio, 0, SEEK_SET);
221     memset(&ck, 0x66, sizeof(ck));
222     ret = mmioDescend(hmmio, &ck, NULL, MMIO_FINDRIFF);
223     ok(ret == MMIOERR_CHUNKNOTFOUND ||
224        ret == MMIOERR_INVALIDFILE, "mmioDescend returned %u\n", ret);
225
226     mmioClose(hmmio, 0);
227 }
228
229 static void test_mmioOpen(char *fname)
230 {
231     char buf[MMIO_DEFAULTBUFFER];
232     MMRESULT ret;
233     HMMIO hmmio;
234     MMIOINFO mmio;
235
236     memset(&mmio, 0, sizeof(mmio));
237     mmio.fccIOProc = fname ? FOURCC_DOS : FOURCC_MEM;
238     mmio.cchBuffer = sizeof(buf);
239     mmio.pchBuffer = buf;
240     hmmio = mmioOpen(fname, &mmio, MMIO_READ);
241     if (fname && !hmmio)
242     {
243         trace("No optional %s file. Skipping the test\n", fname);
244         return;
245     }
246     ok(hmmio != 0, "mmioOpen error %u\n", mmio.wErrorRet);
247
248     memset(&mmio, 0, sizeof(mmio));
249     ret = mmioGetInfo(hmmio, &mmio, 0);
250     ok(ret == MMSYSERR_NOERROR, "mmioGetInfo error %u\n", ret);
251     ok(mmio.dwFlags == MMIO_READ, "expected MMIO_READ, got %x\n", mmio.dwFlags);
252     ok(mmio.wErrorRet == MMSYSERR_NOERROR, "expected MMSYSERR_NOERROR, got %u\n", mmio.wErrorRet);
253     ok(mmio.fccIOProc == (fname ? FOURCC_DOS : FOURCC_MEM), "got %4.4s\n", (LPCSTR)&mmio.fccIOProc);
254     ok(mmio.cchBuffer == sizeof(buf), "got %u\n", mmio.cchBuffer);
255     ok(mmio.pchBuffer == buf, "expected %p, got %p\n", buf, mmio.pchBuffer);
256     ok(mmio.pchNext == mmio.pchBuffer, "expected %p, got %p\n", mmio.pchBuffer, mmio.pchNext);
257     if (mmio.fccIOProc == FOURCC_DOS)
258         ok(mmio.pchEndRead == mmio.pchBuffer, "expected %p, got %p\n", mmio.pchBuffer, mmio.pchEndRead);
259     else
260         ok(mmio.pchEndRead == mmio.pchBuffer + mmio.cchBuffer, "expected %p + %d, got %p\n", mmio.pchBuffer, mmio.cchBuffer, mmio.pchEndRead);
261     ok(mmio.pchEndWrite == mmio.pchBuffer + mmio.cchBuffer, "expected %p + %d, got %p\n", mmio.pchBuffer, mmio.cchBuffer, mmio.pchEndWrite);
262     ok(mmio.lBufOffset == 0, "expected 0, got %d\n", mmio.lBufOffset);
263     ok(mmio.lDiskOffset == 0, "expected 0, got %d\n", mmio.lDiskOffset);
264
265     ret = mmioSeek(hmmio, 0, SEEK_CUR);
266     ok(ret == 0, "expected 0, got %d\n", ret);
267
268     mmioClose(hmmio, 0);
269
270     memset(&mmio, 0, sizeof(mmio));
271     mmio.fccIOProc = fname ? FOURCC_DOS : FOURCC_MEM;
272     mmio.cchBuffer = 0;
273     mmio.pchBuffer = buf;
274     hmmio = mmioOpen(fname, &mmio, MMIO_READ);
275     ok(hmmio != 0, "mmioOpen error %u\n", mmio.wErrorRet);
276
277     memset(&mmio, 0, sizeof(mmio));
278     ret = mmioGetInfo(hmmio, &mmio, 0);
279     ok(ret == MMSYSERR_NOERROR, "mmioGetInfo error %u\n", ret);
280     ok(mmio.dwFlags == MMIO_READ, "expected MMIO_READ, got %x\n", mmio.dwFlags);
281     ok(mmio.wErrorRet == MMSYSERR_NOERROR, "expected MMSYSERR_NOERROR, got %u\n", mmio.wErrorRet);
282     ok(mmio.fccIOProc == (fname ? FOURCC_DOS : FOURCC_MEM), "got %4.4s\n", (LPCSTR)&mmio.fccIOProc);
283     ok(mmio.cchBuffer == 0, "expected 0, got %u\n", mmio.cchBuffer);
284     ok(mmio.pchBuffer == buf, "expected %p, got %p\n", buf, mmio.pchBuffer);
285     ok(mmio.pchNext == mmio.pchBuffer, "expected %p, got %p\n", mmio.pchBuffer, mmio.pchNext);
286     ok(mmio.pchEndRead == mmio.pchBuffer, "expected %p, got %p\n", mmio.pchBuffer, mmio.pchEndRead);
287     ok(mmio.pchEndWrite == mmio.pchBuffer, "expected %p, got %p\n", mmio.pchBuffer, mmio.pchEndWrite);
288     ok(mmio.lBufOffset == 0, "expected 0, got %d\n", mmio.lBufOffset);
289     ok(mmio.lDiskOffset == 0, "expected 0, got %d\n", mmio.lDiskOffset);
290
291     ret = mmioSeek(hmmio, 0, SEEK_CUR);
292     ok(ret == 0, "expected 0, got %d\n", ret);
293
294     mmioClose(hmmio, 0);
295
296     memset(&mmio, 0, sizeof(mmio));
297     mmio.fccIOProc = fname ? FOURCC_DOS : FOURCC_MEM;
298     mmio.cchBuffer = 0;
299     mmio.pchBuffer = NULL;
300     hmmio = mmioOpen(fname, &mmio, MMIO_READ);
301     ok(hmmio != 0, "mmioOpen error %u\n", mmio.wErrorRet);
302
303     memset(&mmio, 0, sizeof(mmio));
304     ret = mmioGetInfo(hmmio, &mmio, 0);
305     ok(ret == MMSYSERR_NOERROR, "mmioGetInfo error %u\n", ret);
306     ok(mmio.dwFlags == MMIO_READ, "expected MMIO_READ, got %x\n", mmio.dwFlags);
307     ok(mmio.wErrorRet == MMSYSERR_NOERROR, "expected MMSYSERR_NOERROR, got %u\n", mmio.wErrorRet);
308     ok(mmio.fccIOProc == (fname ? FOURCC_DOS : FOURCC_MEM), "got %4.4s\n", (LPCSTR)&mmio.fccIOProc);
309     ok(mmio.cchBuffer == 0, "expected 0, got %u\n", mmio.cchBuffer);
310     ok(mmio.pchBuffer == NULL, "expected NULL\n");
311     ok(mmio.pchNext == NULL, "expected NULL\n");
312     ok(mmio.pchEndRead == NULL, "expected NULL\n");
313     ok(mmio.pchEndWrite == NULL, "expected NULL\n");
314     ok(mmio.lBufOffset == 0, "expected 0, got %d\n", mmio.lBufOffset);
315     ok(mmio.lDiskOffset == 0, "expected 0, got %d\n", mmio.lDiskOffset);
316
317 #if 0 /* remove once passes under Wine */
318     ret = mmioSeek(hmmio, 0, SEEK_CUR);
319     ok(ret == 0, "expected 0, got %d\n", ret);
320 #endif
321
322     mmioClose(hmmio, 0);
323
324     memset(&mmio, 0, sizeof(mmio));
325     mmio.fccIOProc = fname ? FOURCC_DOS : FOURCC_MEM;
326     mmio.cchBuffer = 256;
327     mmio.pchBuffer = NULL;
328     hmmio = mmioOpen(fname, &mmio, MMIO_READ);
329     ok(hmmio != 0, "mmioOpen error %u\n", mmio.wErrorRet);
330
331     memset(&mmio, 0, sizeof(mmio));
332     ret = mmioGetInfo(hmmio, &mmio, 0);
333     ok(ret == MMSYSERR_NOERROR, "mmioGetInfo error %u\n", ret);
334     ok(mmio.dwFlags == (MMIO_READ|MMIO_ALLOCBUF), "expected MMIO_READ|MMIO_ALLOCBUF, got %x\n", mmio.dwFlags);
335     ok(mmio.wErrorRet == MMSYSERR_NOERROR, "expected MMSYSERR_NOERROR, got %u\n", mmio.wErrorRet);
336     ok(mmio.fccIOProc == (fname ? FOURCC_DOS : FOURCC_MEM), "got %4.4s\n", (LPCSTR)&mmio.fccIOProc);
337     ok(mmio.cchBuffer == 256, "expected 256, got %u\n", mmio.cchBuffer);
338     ok(mmio.pchBuffer != NULL, "expected not NULL\n");
339     ok(mmio.pchNext == mmio.pchBuffer, "expected %p, got %p\n", mmio.pchBuffer, mmio.pchNext);
340     if (mmio.fccIOProc == FOURCC_DOS)
341         ok(mmio.pchEndRead == mmio.pchBuffer, "expected %p, got %p\n", mmio.pchBuffer, mmio.pchEndRead);
342     else
343         ok(mmio.pchEndRead == mmio.pchBuffer + mmio.cchBuffer, "expected %p + %d, got %p\n", mmio.pchBuffer, mmio.cchBuffer, mmio.pchEndRead);
344     ok(mmio.pchEndWrite == mmio.pchBuffer + mmio.cchBuffer, "expected %p + %d, got %p\n", mmio.pchBuffer, mmio.cchBuffer, mmio.pchEndWrite);
345     ok(mmio.lBufOffset == 0, "expected 0, got %d\n", mmio.lBufOffset);
346     ok(mmio.lDiskOffset == 0, "expected 0, got %d\n", mmio.lDiskOffset);
347
348 #if 0 /* remove once passes under Wine */
349     ret = mmioSeek(hmmio, 0, SEEK_CUR);
350     ok(ret == 0, "expected 0, got %d\n", ret);
351 #endif
352
353     mmioClose(hmmio, 0);
354
355     memset(&mmio, 0, sizeof(mmio));
356     mmio.fccIOProc = fname ? FOURCC_DOS : FOURCC_MEM;
357     mmio.cchBuffer = sizeof(buf);
358     mmio.pchBuffer = buf;
359     hmmio = mmioOpen(fname, &mmio, MMIO_READ | MMIO_ALLOCBUF);
360     ok(hmmio != 0, "mmioOpen error %u\n", mmio.wErrorRet);
361
362     memset(&mmio, 0, sizeof(mmio));
363     ret = mmioGetInfo(hmmio, &mmio, 0);
364     ok(ret == MMSYSERR_NOERROR, "mmioGetInfo error %u\n", ret);
365     ok(mmio.dwFlags == MMIO_READ, "expected MMIO_READ, got %x\n", mmio.dwFlags);
366     ok(mmio.wErrorRet == MMSYSERR_NOERROR, "expected MMSYSERR_NOERROR, got %u\n", mmio.wErrorRet);
367     ok(mmio.fccIOProc == (fname ? FOURCC_DOS : FOURCC_MEM), "got %4.4s\n", (LPCSTR)&mmio.fccIOProc);
368     ok(mmio.cchBuffer == sizeof(buf), "got %u\n", mmio.cchBuffer);
369     ok(mmio.pchBuffer == buf, "expected %p, got %p\n", buf, mmio.pchBuffer);
370     ok(mmio.pchNext == mmio.pchBuffer, "expected %p, got %p\n", mmio.pchBuffer, mmio.pchNext);
371     if (mmio.fccIOProc == FOURCC_DOS)
372         ok(mmio.pchEndRead == mmio.pchBuffer, "expected %p, got %p\n", mmio.pchBuffer, mmio.pchEndRead);
373     else
374         ok(mmio.pchEndRead == mmio.pchBuffer + mmio.cchBuffer, "expected %p + %d, got %p\n", mmio.pchBuffer, mmio.cchBuffer, mmio.pchEndRead);
375     ok(mmio.pchEndWrite == mmio.pchBuffer + mmio.cchBuffer, "expected %p + %d, got %p\n", mmio.pchBuffer, mmio.cchBuffer, mmio.pchEndWrite);
376     ok(mmio.lBufOffset == 0, "expected 0, got %d\n", mmio.lBufOffset);
377     ok(mmio.lDiskOffset == 0, "expected 0, got %d\n", mmio.lDiskOffset);
378
379     ret = mmioSeek(hmmio, 0, SEEK_CUR);
380     ok(ret == 0, "expected 0, got %d\n", ret);
381
382     mmioClose(hmmio, 0);
383
384     memset(&mmio, 0, sizeof(mmio));
385     mmio.fccIOProc = fname ? FOURCC_DOS : FOURCC_MEM;
386     mmio.cchBuffer = 0;
387     mmio.pchBuffer = NULL;
388     hmmio = mmioOpen(fname, &mmio, MMIO_READ | MMIO_ALLOCBUF);
389     ok(hmmio != 0, "mmioOpen error %u\n", mmio.wErrorRet);
390
391     memset(&mmio, 0, sizeof(mmio));
392     ret = mmioGetInfo(hmmio, &mmio, 0);
393     ok(ret == MMSYSERR_NOERROR, "mmioGetInfo error %u\n", ret);
394     ok(mmio.dwFlags == (MMIO_READ|MMIO_ALLOCBUF), "expected MMIO_READ|MMIO_ALLOCBUF, got %x\n", mmio.dwFlags);
395     ok(mmio.wErrorRet == MMSYSERR_NOERROR, "expected MMSYSERR_NOERROR, got %u\n", mmio.wErrorRet);
396     ok(mmio.fccIOProc == (fname ? FOURCC_DOS : FOURCC_MEM), "got %4.4s\n", (LPCSTR)&mmio.fccIOProc);
397     ok(mmio.cchBuffer == MMIO_DEFAULTBUFFER, "expected MMIO_DEFAULTBUFFER, got %u\n", mmio.cchBuffer);
398     ok(mmio.pchBuffer != NULL, "expected not NULL\n");
399     ok(mmio.pchNext == mmio.pchBuffer, "expected %p, got %p\n", mmio.pchBuffer, mmio.pchNext);
400     if (mmio.fccIOProc == FOURCC_DOS)
401         ok(mmio.pchEndRead == mmio.pchBuffer, "expected %p, got %p\n", mmio.pchBuffer, mmio.pchEndRead);
402     else
403         ok(mmio.pchEndRead == mmio.pchBuffer + mmio.cchBuffer, "expected %p + %d, got %p\n", mmio.pchBuffer, mmio.cchBuffer, mmio.pchEndRead);
404     ok(mmio.pchEndWrite == mmio.pchBuffer + mmio.cchBuffer, "expected %p + %d, got %p\n", mmio.pchBuffer, mmio.cchBuffer, mmio.pchEndWrite);
405     ok(mmio.lBufOffset == 0, "expected 0, got %d\n", mmio.lBufOffset);
406     ok(mmio.lDiskOffset == 0, "expected 0, got %d\n", mmio.lDiskOffset);
407
408 #if 0 /* remove once passes under Wine */
409     ret = mmioSeek(hmmio, 0, SEEK_CUR);
410     ok(ret == 0, "expected 0, got %d\n", ret);
411 #endif
412
413     mmioClose(hmmio, 0);
414
415     memset(&mmio, 0, sizeof(mmio));
416     mmio.fccIOProc = fname ? FOURCC_DOS : FOURCC_MEM;
417     mmio.cchBuffer = 256;
418     mmio.pchBuffer = NULL;
419     hmmio = mmioOpen(fname, &mmio, MMIO_READ | MMIO_ALLOCBUF);
420     ok(hmmio != 0, "mmioOpen error %u\n", mmio.wErrorRet);
421
422     memset(&mmio, 0, sizeof(mmio));
423     ret = mmioGetInfo(hmmio, &mmio, 0);
424     ok(ret == MMSYSERR_NOERROR, "mmioGetInfo error %u\n", ret);
425     ok(mmio.dwFlags == (MMIO_READ|MMIO_ALLOCBUF), "expected MMIO_READ|MMIO_ALLOCBUF, got %x\n", mmio.dwFlags);
426     ok(mmio.wErrorRet == MMSYSERR_NOERROR, "expected MMSYSERR_NOERROR, got %u\n", mmio.wErrorRet);
427     ok(mmio.fccIOProc == (fname ? FOURCC_DOS : FOURCC_MEM), "got %4.4s\n", (LPCSTR)&mmio.fccIOProc);
428     ok(mmio.cchBuffer == 256, "expected 256, got %u\n", mmio.cchBuffer);
429     ok(mmio.pchBuffer != NULL, "expected not NULL\n");
430     ok(mmio.pchNext == mmio.pchBuffer, "expected %p, got %p\n", mmio.pchBuffer, mmio.pchNext);
431     if (mmio.fccIOProc == FOURCC_DOS)
432         ok(mmio.pchEndRead == mmio.pchBuffer, "expected %p, got %p\n", mmio.pchBuffer, mmio.pchEndRead);
433     else
434         ok(mmio.pchEndRead == mmio.pchBuffer + mmio.cchBuffer, "expected %p + %d, got %p\n", mmio.pchBuffer, mmio.cchBuffer, mmio.pchEndRead);
435     ok(mmio.pchEndWrite == mmio.pchBuffer + mmio.cchBuffer, "expected %p + %d, got %p\n", mmio.pchBuffer, mmio.cchBuffer, mmio.pchEndWrite);
436     ok(mmio.lBufOffset == 0, "expected 0, got %d\n", mmio.lBufOffset);
437     ok(mmio.lDiskOffset == 0, "expected 0, got %d\n", mmio.lDiskOffset);
438
439 #if 0 /* remove once passes under Wine */
440     ret = mmioSeek(hmmio, 0, SEEK_CUR);
441     ok(ret == 0, "expected 0, got %d\n", ret);
442 #endif
443
444     mmioClose(hmmio, 0);
445
446     memset(&mmio, 0, sizeof(mmio));
447     mmio.fccIOProc = fname ? FOURCC_DOS : FOURCC_MEM;
448     mmio.cchBuffer = 0;
449     mmio.pchBuffer = buf;
450     hmmio = mmioOpen(fname, &mmio, MMIO_READ | MMIO_ALLOCBUF);
451     if (!hmmio && mmio.wErrorRet == ERROR_BAD_FORMAT)
452     {
453         /* Seen on Win9x, WinMe but also XP-SP1 */
454         skip("Some Windows versions don't like a 0 size and a given buffer\n");
455         return;
456     }
457     ok(hmmio != 0, "mmioOpen error %u\n", mmio.wErrorRet);
458
459     memset(&mmio, 0, sizeof(mmio));
460     ret = mmioGetInfo(hmmio, &mmio, 0);
461     ok(ret == MMSYSERR_NOERROR, "mmioGetInfo error %u\n", ret);
462     ok(mmio.dwFlags == MMIO_READ, "expected MMIO_READ, got %x\n", mmio.dwFlags);
463     ok(mmio.wErrorRet == MMSYSERR_NOERROR, "expected MMSYSERR_NOERROR, got %u\n", mmio.wErrorRet);
464     ok(mmio.fccIOProc == (fname ? FOURCC_DOS : FOURCC_MEM), "got %4.4s\n", (LPCSTR)&mmio.fccIOProc);
465     ok(mmio.cchBuffer == MMIO_DEFAULTBUFFER, "expected MMIO_DEFAULTBUFFER, got %u\n", mmio.cchBuffer);
466     ok(mmio.pchBuffer == buf, "expected %p, got %p\n", buf, mmio.pchBuffer);
467     ok(mmio.pchNext == mmio.pchBuffer, "expected %p, got %p\n", mmio.pchBuffer, mmio.pchNext);
468     if (mmio.fccIOProc == FOURCC_DOS)
469         ok(mmio.pchEndRead == mmio.pchBuffer, "expected %p, got %p\n", mmio.pchBuffer, mmio.pchEndRead);
470     else
471         ok(mmio.pchEndRead == mmio.pchBuffer + mmio.cchBuffer, "expected %p + %d, got %p\n", mmio.pchBuffer, mmio.cchBuffer, mmio.pchEndRead);
472     ok(mmio.pchEndWrite == mmio.pchBuffer + mmio.cchBuffer, "expected %p + %d, got %p\n", mmio.pchBuffer, mmio.cchBuffer, mmio.pchEndWrite);
473     ok(mmio.lBufOffset == 0, "expected 0, got %d\n", mmio.lBufOffset);
474     ok(mmio.lDiskOffset == 0, "expected 0, got %d\n", mmio.lDiskOffset);
475
476     ret = mmioSeek(hmmio, 0, SEEK_CUR);
477     ok(ret == 0, "expected 0, got %d\n", ret);
478
479     mmioClose(hmmio, 0);
480 }
481
482 static void test_mmioSetBuffer(char *fname)
483 {
484     char buf[256];
485     MMRESULT ret;
486     HMMIO hmmio;
487     MMIOINFO mmio;
488
489     memset(&mmio, 0, sizeof(mmio));
490     mmio.fccIOProc = fname ? FOURCC_DOS : FOURCC_MEM;
491     mmio.cchBuffer = sizeof(buf);
492     mmio.pchBuffer = buf;
493     hmmio = mmioOpen(fname, &mmio, MMIO_READ);
494     if (fname && !hmmio)
495     {
496         trace("No optional %s file. Skipping the test\n", fname);
497         return;
498     }
499     ok(hmmio != 0, "mmioOpen error %u\n", mmio.wErrorRet);
500
501     memset(&mmio, 0, sizeof(mmio));
502     ret = mmioGetInfo(hmmio, &mmio, 0);
503     ok(ret == MMSYSERR_NOERROR, "mmioGetInfo error %u\n", ret);
504     ok(mmio.dwFlags == MMIO_READ, "expected MMIO_READ, got %x\n", mmio.dwFlags);
505     ok(mmio.wErrorRet == MMSYSERR_NOERROR, "expected MMSYSERR_NOERROR, got %u\n", mmio.wErrorRet);
506     ok(mmio.fccIOProc == (fname ? FOURCC_DOS : FOURCC_MEM), "got %4.4s\n", (LPCSTR)&mmio.fccIOProc);
507     ok(mmio.cchBuffer == sizeof(buf), "got %u\n", mmio.cchBuffer);
508     ok(mmio.pchBuffer == buf, "expected %p, got %p\n", buf, mmio.pchBuffer);
509     ok(mmio.pchNext == mmio.pchBuffer, "expected %p, got %p\n", mmio.pchBuffer, mmio.pchNext);
510     if (mmio.fccIOProc == FOURCC_DOS)
511         ok(mmio.pchEndRead == mmio.pchBuffer, "expected %p, got %p\n", mmio.pchBuffer, mmio.pchEndRead);
512     else
513         ok(mmio.pchEndRead == mmio.pchBuffer + mmio.cchBuffer, "expected %p + %d, got %p\n", mmio.pchBuffer, mmio.cchBuffer, mmio.pchEndRead);
514     ok(mmio.pchEndWrite == mmio.pchBuffer + mmio.cchBuffer, "expected %p + %d, got %p\n", mmio.pchBuffer, mmio.cchBuffer, mmio.pchEndWrite);
515     ok(mmio.lBufOffset == 0, "expected 0, got %d\n", mmio.lBufOffset);
516     ok(mmio.lDiskOffset == 0, "expected 0, got %d\n", mmio.lDiskOffset);
517
518     ret = mmioSeek(hmmio, 0, SEEK_CUR);
519     ok(ret == 0, "expected 0, got %d\n", ret);
520
521     ret = mmioSetBuffer(hmmio, NULL, 0, 0);
522     ok(ret == MMSYSERR_NOERROR, "mmioSetBuffer error %u\n", ret);
523
524     memset(&mmio, 0, sizeof(mmio));
525     ret = mmioGetInfo(hmmio, &mmio, 0);
526     ok(ret == MMSYSERR_NOERROR, "mmioGetInfo error %u\n", ret);
527     ok(mmio.dwFlags == MMIO_READ, "expected MMIO_READ, got %x\n", mmio.dwFlags);
528     ok(mmio.wErrorRet == MMSYSERR_NOERROR, "expected MMSYSERR_NOERROR, got %u\n", mmio.wErrorRet);
529     ok(mmio.fccIOProc == (fname ? FOURCC_DOS : FOURCC_MEM), "got %4.4s\n", (LPCSTR)&mmio.fccIOProc);
530     ok(mmio.cchBuffer == 0, "got not 0\n");
531     ok(mmio.pchBuffer == NULL, "got not NULL buf\n");
532     ok(mmio.pchNext == mmio.pchBuffer, "expected %p, got %p\n", mmio.pchBuffer, mmio.pchNext);
533     ok(mmio.pchEndRead == mmio.pchBuffer, "expected %p, got %p\n", mmio.pchBuffer, mmio.pchEndRead);
534     ok(mmio.pchEndWrite == mmio.pchBuffer, "expected %p, got %p\n", mmio.pchBuffer, mmio.pchEndWrite);
535 #if 0 /* remove once passes under Wine */
536     ok(mmio.lBufOffset == 0, "expected 0, got %d\n", mmio.lBufOffset);
537     ok(mmio.lDiskOffset == 0, "expected 0, got %d\n", mmio.lDiskOffset);
538 #endif
539
540 #if 0 /* remove once passes under Wine */
541     ret = mmioSeek(hmmio, 0, SEEK_CUR);
542     ok(ret == 0, "expected 0, got %d\n", ret);
543 #endif
544
545     ret = mmioSetBuffer(hmmio, NULL, 0, MMIO_ALLOCBUF);
546     ok(ret == MMSYSERR_NOERROR, "mmioSetBuffer error %u\n", ret);
547
548     memset(&mmio, 0, sizeof(mmio));
549     ret = mmioGetInfo(hmmio, &mmio, 0);
550     ok(ret == MMSYSERR_NOERROR, "mmioGetInfo error %u\n", ret);
551     ok(mmio.dwFlags == MMIO_READ, "expected MMIO_READ, got %x\n", mmio.dwFlags);
552     ok(mmio.wErrorRet == MMSYSERR_NOERROR, "expected MMSYSERR_NOERROR, got %u\n", mmio.wErrorRet);
553     ok(mmio.fccIOProc == (fname ? FOURCC_DOS : FOURCC_MEM), "got %4.4s\n", (LPCSTR)&mmio.fccIOProc);
554     ok(mmio.cchBuffer == 0, "got not 0\n");
555     ok(mmio.pchBuffer == NULL, "got not NULL buf\n");
556     ok(mmio.pchNext == mmio.pchBuffer, "expected %p, got %p\n", mmio.pchBuffer, mmio.pchNext);
557     ok(mmio.pchEndRead == mmio.pchBuffer, "expected %p, got %p\n", mmio.pchBuffer, mmio.pchEndRead);
558     ok(mmio.pchEndWrite == mmio.pchBuffer, "expected %p, got %p\n", mmio.pchBuffer, mmio.pchEndWrite);
559 #if 0 /* remove once passes under Wine */
560     ok(mmio.lBufOffset == 0, "expected 0, got %d\n", mmio.lBufOffset);
561     ok(mmio.lDiskOffset == 0, "expected 0, got %d\n", mmio.lDiskOffset);
562 #endif
563
564 #if 0 /* remove once passes under Wine */
565     ret = mmioSeek(hmmio, 0, SEEK_CUR);
566     ok(ret == 0, "expected 0, got %d\n", ret);
567 #endif
568
569     ret = mmioSetBuffer(hmmio, buf, 0, MMIO_ALLOCBUF);
570     ok(ret == MMSYSERR_NOERROR, "mmioSetBuffer error %u\n", ret);
571
572     memset(&mmio, 0, sizeof(mmio));
573     ret = mmioGetInfo(hmmio, &mmio, 0);
574     ok(ret == MMSYSERR_NOERROR, "mmioGetInfo error %u\n", ret);
575     ok(mmio.dwFlags == MMIO_READ, "expected MMIO_READ, got %x\n", mmio.dwFlags);
576     ok(mmio.wErrorRet == MMSYSERR_NOERROR, "expected MMSYSERR_NOERROR, got %u\n", mmio.wErrorRet);
577     ok(mmio.fccIOProc == (fname ? FOURCC_DOS : FOURCC_MEM), "got %4.4s\n", (LPCSTR)&mmio.fccIOProc);
578     ok(mmio.cchBuffer == 0, "got not 0\n");
579     ok(mmio.pchBuffer == buf, "expected %p, got %p\n", buf, mmio.pchBuffer);
580     ok(mmio.pchNext == mmio.pchBuffer, "expected %p, got %p\n", mmio.pchBuffer, mmio.pchNext);
581     ok(mmio.pchEndRead == mmio.pchBuffer, "expected %p, got %p\n", mmio.pchBuffer, mmio.pchEndRead);
582     ok(mmio.pchEndWrite == mmio.pchBuffer, "expected %p, got %p\n", mmio.pchBuffer, mmio.pchEndWrite);
583 #if 0 /* remove once passes under Wine */
584     ok(mmio.lBufOffset == 0, "expected 0, got %d\n", mmio.lBufOffset);
585     ok(mmio.lDiskOffset == 0, "expected 0, got %d\n", mmio.lDiskOffset);
586 #endif
587
588 #if 0 /* remove once passes under Wine */
589     ret = mmioSeek(hmmio, 0, SEEK_CUR);
590     ok(ret == 0, "expected 0, got %d\n", ret);
591 #endif
592
593     ret = mmioSetBuffer(hmmio, NULL, 256, MMIO_WRITE|MMIO_ALLOCBUF);
594     ok(ret == MMSYSERR_NOERROR, "mmioSetBuffer error %u\n", ret);
595
596     memset(&mmio, 0, sizeof(mmio));
597     ret = mmioGetInfo(hmmio, &mmio, 0);
598     ok(ret == MMSYSERR_NOERROR, "mmioGetInfo error %u\n", ret);
599     ok(mmio.dwFlags == (MMIO_READ|MMIO_ALLOCBUF), "expected MMIO_READ|MMIO_ALLOCBUF, got %x\n", mmio.dwFlags);
600     ok(mmio.wErrorRet == MMSYSERR_NOERROR, "expected MMSYSERR_NOERROR, got %u\n", mmio.wErrorRet);
601     ok(mmio.fccIOProc == (fname ? FOURCC_DOS : FOURCC_MEM), "got %4.4s\n", (LPCSTR)&mmio.fccIOProc);
602     ok(mmio.cchBuffer == 256, "got %u\n", mmio.cchBuffer);
603     ok(mmio.pchBuffer != NULL, "expected not NULL\n");
604     ok(mmio.pchBuffer != buf, "expected != buf\n");
605     ok(mmio.pchNext == mmio.pchBuffer, "expected %p, got %p\n", mmio.pchBuffer, mmio.pchNext);
606     ok(mmio.pchEndRead == mmio.pchBuffer, "expected %p, got %p\n", buf, mmio.pchEndRead);
607     ok(mmio.pchEndWrite == mmio.pchBuffer + mmio.cchBuffer, "expected %p + %d, got %p\n", mmio.pchBuffer, mmio.cchBuffer, mmio.pchEndWrite);
608 #if 0 /* remove once passes under Wine */
609     ok(mmio.lBufOffset == 0, "expected 0, got %d\n", mmio.lBufOffset);
610     ok(mmio.lDiskOffset == 0, "expected 0, got %d\n", mmio.lDiskOffset);
611 #endif
612
613 #if 0 /* remove once passes under Wine */
614     ret = mmioSeek(hmmio, 0, SEEK_CUR);
615     ok(ret == 0, "expected 0, got %d\n", ret);
616 #endif
617
618     mmioClose(hmmio, 0);
619 }
620
621 #define FOURCC_XYZ mmioFOURCC('X', 'Y', 'Z', ' ')
622
623 static LRESULT CALLBACK mmio_test_IOProc(LPSTR lpMMIOInfo, UINT uMessage, LPARAM lParam1, LPARAM lParam2)
624 {
625     LPMMIOINFO lpInfo = (LPMMIOINFO) lpMMIOInfo;
626
627     switch (uMessage)
628     {
629     case MMIOM_OPEN:
630         if (lpInfo->fccIOProc == FOURCC_DOS)
631             lpInfo->fccIOProc = mmioFOURCC('F', 'A', 'I', 'L');
632         return MMSYSERR_NOERROR;
633     case MMIOM_CLOSE:
634         return MMSYSERR_NOERROR;
635     default:
636         return 0;
637     }
638 }
639
640 static void test_mmioOpen_fourcc(void)
641 {
642     char fname[] = "file+name.xyz+one.two";
643
644     LPMMIOPROC lpProc;
645     HMMIO hmmio;
646     MMIOINFO mmio;
647
648     lpProc = mmioInstallIOProc(FOURCC_DOS, mmio_test_IOProc, MMIO_INSTALLPROC);
649     ok(lpProc == mmio_test_IOProc, "mmioInstallIOProc error\n");
650
651     lpProc = mmioInstallIOProc(FOURCC_XYZ, mmio_test_IOProc, MMIO_INSTALLPROC);
652     ok(lpProc == mmio_test_IOProc, "mmioInstallIOProc error\n");
653
654     memset(&mmio, 0, sizeof(mmio));
655     hmmio = mmioOpen(fname, &mmio, MMIO_READ);
656     mmioGetInfo(hmmio, &mmio, 0);
657     ok(hmmio != NULL && mmio.fccIOProc == FOURCC_XYZ, "mmioOpen error %u, got %4.4s\n", mmio.wErrorRet, (LPCSTR)&mmio.fccIOProc);
658     mmioClose(hmmio, 0);
659
660     mmioInstallIOProc(FOURCC_XYZ, NULL, MMIO_REMOVEPROC);
661
662     memset(&mmio, 0, sizeof(mmio));
663     hmmio = mmioOpen(fname, &mmio, MMIO_READ);
664     mmioGetInfo(hmmio, &mmio, 0);
665     ok(hmmio == NULL && mmio.wErrorRet == MMIOERR_FILENOTFOUND, "mmioOpen error %u, got %4.4s\n", mmio.wErrorRet, (LPCSTR)&mmio.fccIOProc);
666     mmioClose(hmmio, 0);
667
668     mmioInstallIOProc(FOURCC_DOS, NULL, MMIO_REMOVEPROC);
669 }
670
671 START_TEST(mmio)
672 {
673     /* Make it possible to run the tests against a specific AVI file in
674      * addition to the builtin test data. This is mostly meant as a
675      * debugging aid and is not part of the standard tests.
676      */
677     char fname[] = "msrle.avi";
678
679     test_mmioDescend(NULL);
680     test_mmioDescend(fname);
681     test_mmioOpen(NULL);
682     test_mmioOpen(fname);
683     test_mmioSetBuffer(NULL);
684     test_mmioSetBuffer(fname);
685     test_mmioOpen_fourcc();
686 }