Release 1.5.29.
[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 static BOOL create_test_file(char *temp_file)
672 {
673     char temp_path[MAX_PATH];
674     DWORD ret, written;
675     HANDLE h;
676
677     ret = GetTempPath(sizeof(temp_path), temp_path);
678     ok(ret, "Failed to get a temp path, err %d\n", GetLastError());
679     if (!ret)
680         return FALSE;
681
682     ret = GetTempFileName(temp_path, "mmio", 0, temp_file);
683     ok(ret, "Failed to get a temp name, err %d\n", GetLastError());
684     if (!ret)
685         return FALSE;
686
687     h = CreateFileA(temp_file, GENERIC_WRITE, 0, NULL,
688                     CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
689     ok(h != INVALID_HANDLE_VALUE, "Failed to create a file, err %d\n", GetLastError());
690     if (h == INVALID_HANDLE_VALUE) return FALSE;
691
692     ret = WriteFile(h, RIFF_buf, sizeof(RIFF_buf), &written, NULL);
693     ok(ret, "Failed to write a file, err %d\n", GetLastError());
694     CloseHandle(h);
695     if (!ret) DeleteFileA(temp_file);
696     return ret;
697 }
698
699 static void test_mmioSeek(void)
700 {
701     HMMIO hmmio;
702     MMIOINFO mmio;
703     LONG end, pos;
704     const LONG size = sizeof(RIFF_buf), offset = 16;
705     char test_file[MAX_PATH];
706     MMRESULT res;
707     HFILE hfile;
708     OFSTRUCT ofs;
709
710     /* test memory file */
711     memset(&mmio, 0, sizeof(mmio));
712     mmio.fccIOProc = FOURCC_MEM;
713     mmio.pchBuffer = (char*)&RIFF_buf;
714     mmio.cchBuffer = sizeof(RIFF_buf);
715     hmmio = mmioOpen(NULL, &mmio, MMIO_READ);
716     ok(hmmio != NULL, "mmioOpen error %u\n", mmio.wErrorRet);
717     if (hmmio != NULL) {
718         /* seek to the end */
719         end = mmioSeek(hmmio, 0, SEEK_END);
720         todo_wine ok(end == size, "expected %d, got %d\n", size, end);
721
722         /* seek backward from the end */
723         pos = mmioSeek(hmmio, offset, SEEK_END);
724         ok(pos == size-offset, "expected %d, got %d\n", size-offset, pos);
725
726         mmioClose(hmmio, 0);
727     }
728
729     if (!create_test_file(test_file)) return;
730
731     /* test standard file without buffering */
732     hmmio = NULL;
733     memset(&mmio, 0, sizeof(mmio));
734     mmio.fccIOProc = FOURCC_DOS;
735     mmio.pchBuffer = 0;
736     mmio.cchBuffer = 0;
737     hmmio = mmioOpen(test_file, &mmio, MMIO_READ);
738     ok(hmmio != NULL, "mmioOpen error %u\n", mmio.wErrorRet);
739     if (hmmio != NULL) {
740         /* seek to the end */
741         end = mmioSeek(hmmio, 0, SEEK_END);
742         ok(end == size, "expected %d, got %d\n", size, end);
743
744         /* test MMIOINFO values */
745         res = mmioGetInfo(hmmio, &mmio, 0);
746         ok(res == MMSYSERR_NOERROR, "expected 0, got %d\n", res);
747         ok(mmio.pchNext == mmio.pchBuffer, "expected %p, got %p\n", mmio.pchBuffer, mmio.pchNext);
748         ok(mmio.pchEndRead == mmio.pchBuffer, "expected %p, got %p\n", mmio.pchBuffer, mmio.pchEndRead);
749         ok(mmio.pchEndWrite == mmio.pchBuffer + mmio.cchBuffer, "expected %p + %d, got %p\n", mmio.pchBuffer, mmio.cchBuffer, mmio.pchEndWrite);
750         todo_wine ok(mmio.lBufOffset == size, "expected %d, got %d\n", size, mmio.lBufOffset);
751         ok(mmio.lDiskOffset == size, "expected %d, got %d\n", size, mmio.lDiskOffset);
752
753         /* seek backward from the end */
754         pos = mmioSeek(hmmio, offset, SEEK_END);
755         ok(pos == size-offset, "expected %d, got %d\n", size-offset, pos);
756
757         mmioClose(hmmio, 0);
758     }
759
760     /* test standard file with buffering */
761     hmmio = NULL;
762     memset(&mmio, 0, sizeof(mmio));
763     mmio.fccIOProc = FOURCC_DOS;
764     mmio.pchBuffer = 0;
765     mmio.cchBuffer = 0;
766     hmmio = mmioOpen(test_file, &mmio, MMIO_READ | MMIO_ALLOCBUF);
767     ok(hmmio != NULL, "mmioOpen error %u\n", mmio.wErrorRet);
768     if (hmmio != NULL) {
769         /* seek to the end */
770         end = mmioSeek(hmmio, 0, SEEK_END);
771         ok(end == size, "expected %d, got %d\n", size, end);
772
773         /* test MMIOINFO values */
774         res = mmioGetInfo(hmmio, &mmio, 0);
775         ok(res == MMSYSERR_NOERROR, "expected 0, got %d\n", res);
776         ok(mmio.pchNext == mmio.pchBuffer, "expected %p, got %p\n", mmio.pchBuffer, mmio.pchNext);
777         ok(mmio.pchEndRead == mmio.pchBuffer, "expected %p, got %p\n", mmio.pchBuffer, mmio.pchEndRead);
778         ok(mmio.pchEndWrite == mmio.pchBuffer + mmio.cchBuffer, "expected %p + %d, got %p\n", mmio.pchBuffer, mmio.cchBuffer, mmio.pchEndWrite);
779         ok(mmio.lBufOffset == end, "expected %d, got %d\n", end, mmio.lBufOffset);
780         ok(mmio.lDiskOffset == size, "expected %d, got %d\n", size, mmio.lDiskOffset);
781
782         /* seek backward from the end */
783         pos = mmioSeek(hmmio, offset, SEEK_END);
784         ok(pos == size-offset, "expected %d, got %d\n", size-offset, pos);
785
786         mmioClose(hmmio, 0);
787     }
788
789     /* test seek position inheritance from standard file handle */
790     hfile = OpenFile(test_file, &ofs, OF_READ);
791     ok(hfile != HFILE_ERROR, "Failed to open the file, err %d\n", GetLastError());
792     if (hfile != HFILE_ERROR) {
793         pos = _llseek(hfile, offset, SEEK_SET);
794         ok(pos != HFILE_ERROR, "Failed to seek, err %d\n", GetLastError());
795         memset(&mmio, 0, sizeof(mmio));
796         mmio.fccIOProc = FOURCC_DOS;
797         mmio.adwInfo[0] = (DWORD)hfile;
798         hmmio = mmioOpen(NULL, &mmio, MMIO_READ | MMIO_DENYWRITE | MMIO_ALLOCBUF);
799         ok(hmmio != NULL, "mmioOpen error %u\n", mmio.wErrorRet);
800         if (hmmio != NULL) {
801             pos = mmioSeek(hmmio, 0, SEEK_CUR);
802             ok(pos == offset, "expected %d, got %d\n", offset, pos);
803             mmioClose(hmmio, 0);
804         }
805     }
806
807     DeleteFileA(test_file);
808 }
809
810 static void test_mmio_end_of_file(void)
811 {
812     char test_file[MAX_PATH], buffer[128], data[16];
813     MMIOINFO mmio;
814     HMMIO hmmio;
815     LONG ret;
816     MMRESULT res;
817
818     if (!create_test_file(test_file)) return;
819
820     memset(&mmio, 0, sizeof(mmio));
821     mmio.fccIOProc = FOURCC_DOS;
822     mmio.pchBuffer = buffer;
823     mmio.cchBuffer = sizeof(buffer);
824     hmmio = mmioOpen(test_file, &mmio, MMIO_READ);
825     ok(hmmio != NULL, "mmioOpen error %u\n", mmio.wErrorRet);
826     if (hmmio == NULL) {
827         DeleteFileA(test_file);
828         return;
829     }
830
831     ret = mmioSeek(hmmio, 0, SEEK_END);
832     ok(sizeof(RIFF_buf) == ret, "got %d\n", ret);
833
834     ret = mmioRead(hmmio, data, sizeof(data));
835     ok(ret == 0, "expected %d, got %d\n", 0, ret);
836
837     res = mmioGetInfo(hmmio, &mmio, 0);
838     ok(res == MMSYSERR_NOERROR, "expected 0, got %d\n", res);
839
840     res = mmioAdvance(hmmio, &mmio, MMIO_READ);
841     ok(res == MMSYSERR_NOERROR, "expected 0, got %d\n", res);
842     ok(mmio.pchNext == mmio.pchEndRead, "expected %p, got %p\n", mmio.pchEndRead, mmio.pchNext);
843
844     mmioClose(hmmio, 0);
845     DeleteFileA(test_file);
846 }
847
848 static void test_mmio_buffer_pointer(void)
849 {
850     char test_file[MAX_PATH];
851     char buffer[5], data[16];
852     MMIOINFO mmio;
853     HMMIO hmmio;
854     LONG size, pos;
855     MMRESULT res;
856
857     if (!create_test_file(test_file)) return;
858
859     memset(&mmio, 0, sizeof(mmio));
860     mmio.fccIOProc = FOURCC_DOS;
861     mmio.pchBuffer = buffer;
862     mmio.cchBuffer = sizeof(buffer);
863     hmmio = mmioOpen(test_file, &mmio, MMIO_READ);
864     ok(hmmio != NULL, "mmioOpen error %u\n", mmio.wErrorRet);
865     if (hmmio == NULL) {
866         DeleteFileA(test_file);
867         return;
868     }
869
870     /* the buffer is empty */
871     size = mmioRead(hmmio, data, 0);
872     ok(size == 0, "expected 0, got %d\n", size);
873     res = mmioGetInfo(hmmio, &mmio, 0);
874     ok(res == MMSYSERR_NOERROR, "expected 0, got %d\n", res);
875     ok(mmio.pchEndRead == mmio.pchBuffer, "expected %p, got %p\n", mmio.pchBuffer, mmio.pchEndRead);
876
877     /* fill the buffer */
878     size = mmioAdvance(hmmio, &mmio, MMIO_READ);
879     ok(mmio.pchEndRead-mmio.pchBuffer == sizeof(buffer), "got %d\n", (int)(mmio.pchEndRead-mmio.pchBuffer));
880
881     /* seeking to the same buffer chunk, the buffer is kept */
882     size = sizeof(buffer)/2;
883     pos = mmioSeek(hmmio, size, SEEK_SET);
884     ok(pos == size, "failed to seek, expected %d, got %d\n", size, pos);
885     res = mmioGetInfo(hmmio, &mmio, 0);
886     ok(res == MMSYSERR_NOERROR, "expected 0, got %d\n", res);
887     ok(mmio.lBufOffset == 0, "expected 0, got %d\n", mmio.lBufOffset);
888     ok(mmio.pchNext-mmio.pchBuffer == size, "expected %d, got %d\n", size, (int)(mmio.pchNext-mmio.pchBuffer));
889     ok(mmio.pchEndRead-mmio.pchBuffer == sizeof(buffer), "got %d\n", (int)(mmio.pchEndRead-mmio.pchBuffer));
890
891     /* seeking to another buffer chunk, the buffer is empty */
892     size = sizeof(buffer) * 3 + sizeof(buffer) / 2;
893     pos = mmioSeek(hmmio, size, SEEK_SET);
894     ok(pos == size, "failed to seek, got %d\n", pos);
895     res = mmioGetInfo(hmmio, &mmio, 0);
896     ok(res == MMSYSERR_NOERROR, "expected 0, got %d\n", res);
897     ok(mmio.lBufOffset == size, "expected %d, got %d\n", size, mmio.lBufOffset);
898     ok(mmio.pchNext == mmio.pchBuffer, "expected %p, got %p\n", mmio.pchBuffer, mmio.pchNext);
899     ok(mmio.pchEndRead == mmio.pchBuffer, "expected %p, got %p\n", mmio.pchBuffer, mmio.pchEndRead);
900
901     /* reading a lot (as sizeof(data) > mmio.cchBuffer), the buffer is empty */
902     size = mmioRead(hmmio, data, sizeof(data));
903     ok(size == sizeof(data), "failed to read, got %d\n", size);
904     res = mmioGetInfo(hmmio, &mmio, 0);
905     ok(res == MMSYSERR_NOERROR, "expected 0, got %d\n", res);
906     ok(mmio.lBufOffset == pos+size, "expected %d, got %d\n", pos+size, mmio.lBufOffset);
907     ok(mmio.pchNext == mmio.pchBuffer, "expected %p, got %p\n", mmio.pchBuffer, mmio.pchNext);
908     ok(mmio.pchEndRead == mmio.pchBuffer, "expected %p, got %p\n", mmio.pchBuffer, mmio.pchEndRead);
909
910     mmioClose(hmmio, 0);
911     DeleteFileA(test_file);
912 }
913
914 START_TEST(mmio)
915 {
916     /* Make it possible to run the tests against a specific AVI file in
917      * addition to the builtin test data. This is mostly meant as a
918      * debugging aid and is not part of the standard tests.
919      */
920     char fname[] = "msrle.avi";
921
922     test_mmioDescend(NULL);
923     test_mmioDescend(fname);
924     test_mmioOpen(NULL);
925     test_mmioOpen(fname);
926     test_mmioSetBuffer(NULL);
927     test_mmioSetBuffer(fname);
928     test_mmioOpen_fourcc();
929     test_mmioSeek();
930     test_mmio_end_of_file();
931     test_mmio_buffer_pointer();
932 }