Fixes buffer overrun problems with GetDIBits.
[wine.git] / multimedia / mmio.c
blob57bcbc2ed30993c01f9bcf7428b5a5dddcf39297
1 /*
2 * MMIO functions
4 * Copyright 1998 Andrew Taylor
5 * Copyright 1998 Ove Kåven
7 */
10 #include <stdlib.h>
11 #include <string.h>
12 #include <errno.h>
13 #include "wintypes.h"
14 #include "wine/winbase16.h"
15 #include "heap.h"
16 #include "file.h"
17 #include "mmsystem.h"
18 #include "debug.h"
19 #include "xmalloc.h"
21 /**************************************************************************
22 * mmioDosIOProc [internal]
24 static LRESULT mmioDosIOProc(LPMMIOINFO16 lpmmioinfo, UINT16 uMessage, LPARAM lParam1, LPARAM lParam2) {
25 TRACE(mmio, "(%p, %X, %ld, %ld);\n", lpmmioinfo, uMessage, lParam1, lParam2);
27 switch (uMessage) {
29 case MMIOM_OPEN: {
30 /* Parameters:
31 * lParam1 = szFileName parameter from mmioOpen
32 * lParam2 = reserved (we use it for 16-bitness)
33 * Returns: zero on success, error code on error
34 * NOTE: lDiskOffset automatically set to zero
37 OFSTRUCT ofs;
38 LPSTR szFileName = (LPSTR) lParam1;
40 if (lpmmioinfo->dwFlags & MMIO_GETTEMP) {
41 FIXME(mmio, "MMIO_GETTEMP not implemented\n");
42 return MMIOERR_CANNOTOPEN;
45 /* if filename NULL, assume open file handle in adwInfo[0] */
46 if (!szFileName) {
47 if (lParam2) lpmmioinfo->adwInfo[0] =
48 FILE_GetHandle32(lpmmioinfo->adwInfo[0]);
49 return 0;
52 lpmmioinfo->adwInfo[0] =
53 (DWORD) OpenFile32(szFileName, &ofs, lpmmioinfo->dwFlags);
54 if (lpmmioinfo->adwInfo[0] == -1)
55 return MMIOERR_CANNOTOPEN;
57 return 0;
60 case MMIOM_CLOSE: {
61 /* Parameters:
62 * lParam1 = wFlags parameter from mmioClose
63 * lParam2 = unused
64 * Returns: zero on success, error code on error
67 UINT16 uFlags = (UINT16) lParam1;
69 if (uFlags & MMIO_FHOPEN)
70 return 0;
72 _lclose32((HFILE32)lpmmioinfo->adwInfo[0]);
73 return 0;
77 case MMIOM_READ: {
78 /* Parameters:
79 * lParam1 = huge pointer to read buffer
80 * lParam2 = number of bytes to read
81 * Returns: number of bytes read, 0 for EOF, -1 for error (error code
82 * in wErrorRet)
83 * NOTE: lDiskOffset should be updated
86 HPSTR pch = (HPSTR) lParam1;
87 LONG cch = (LONG) lParam2;
88 LONG count;
90 count = _lread32((HFILE32)lpmmioinfo->adwInfo[0], pch, cch);
91 if (count != -1)
92 lpmmioinfo->lDiskOffset += count;
94 return count;
97 case MMIOM_WRITE:
98 case MMIOM_WRITEFLUSH: {
99 /* no internal buffering, so WRITEFLUSH handled same as WRITE */
101 /* Parameters:
102 * lParam1 = huge pointer to write buffer
103 * lParam2 = number of bytes to write
104 * Returns: number of bytes written, -1 for error (error code in
105 * wErrorRet)
106 * NOTE: lDiskOffset should be updated
109 HPSTR pch = (HPSTR) lParam1;
110 LONG cch = (LONG) lParam2;
111 LONG count;
113 count = _hwrite32((HFILE32)lpmmioinfo->adwInfo[0], pch, cch);
114 if (count != -1)
115 lpmmioinfo->lDiskOffset += count;
117 return count;
120 case MMIOM_SEEK: {
121 /* Parameters:
122 * lParam1 = new position
123 * lParam2 = from whence to seek (SEEK_SET, SEEK_CUR, SEEK_END)
124 * Returns: new file postion, -1 on error
125 * NOTE: lDiskOffset should be updated
128 LONG Offset = (LONG) lParam1;
129 LONG Whence = (LONG) lParam2;
130 LONG pos;
132 pos = _llseek32((HFILE32)lpmmioinfo->adwInfo[0], Offset, Whence);
133 if (pos != -1)
134 lpmmioinfo->lDiskOffset = pos;
136 return pos;
139 case MMIOM_RENAME: {
140 /* Parameters:
141 * lParam1 = old name
142 * lParam2 = new name
143 * Returns: zero on success, non-zero on failure
146 FIXME(mmio, "MMIOM_RENAME unimplemented\n");
147 return MMIOERR_FILENOTFOUND;
150 default:
151 FIXME(mmio, "unexpected message %u\n", uMessage);
152 return 0;
155 return 0;
158 /**************************************************************************
159 * mmioMemIOProc [internal]
161 static LRESULT mmioMemIOProc(LPMMIOINFO16 lpmmioinfo, UINT16 uMessage, LPARAM lParam1, LPARAM lParam2) {
162 TRACE(mmio,"(%p,0x%04x,0x%08lx,0x%08lx)\n",lpmmioinfo,uMessage,lParam1,lParam2);
163 switch (uMessage) {
165 case MMIOM_OPEN: {
166 /* Parameters:
167 * lParam1 = filename (must be NULL)
168 * lParam2 = reserved (we use it for 16-bitness)
169 * Returns: zero on success, error code on error
170 * NOTE: lDiskOffset automatically set to zero
173 if (!(lpmmioinfo->dwFlags & MMIO_CREATE))
174 lpmmioinfo->pchEndRead = lpmmioinfo->pchEndWrite;
176 return 0;
179 case MMIOM_CLOSE: {
180 /* Parameters:
181 * lParam1 = wFlags parameter from mmioClose
182 * lParam2 = unused
183 * Returns: zero on success, error code on error
186 return 0;
190 case MMIOM_READ: {
191 /* Parameters:
192 * lParam1 = huge pointer to read buffer
193 * lParam2 = number of bytes to read
194 * Returns: number of bytes read, 0 for EOF, -1 for error (error code
195 * in wErrorRet)
196 * NOTE: lDiskOffset should be updated
199 /* HPSTR pch = (HPSTR) lParam1; */
200 /* LONG cch = (LONG) lParam2; */
202 FIXME(mmio,"MMIOM_READ on memory files should not occur, buffer may be lost!\n");
203 return 0;
206 case MMIOM_WRITE:
207 case MMIOM_WRITEFLUSH: {
208 /* no internal buffering, so WRITEFLUSH handled same as WRITE */
210 /* Parameters:
211 * lParam1 = huge pointer to write buffer
212 * lParam2 = number of bytes to write
213 * Returns: number of bytes written, -1 for error (error code in
214 * wErrorRet)
215 * NOTE: lDiskOffset should be updated
218 /* HPSTR pch = (HPSTR) lParam1; */
219 /* LONG cch = (LONG) lParam2; */
221 FIXME(mmio,"MMIOM_WRITE on memory files should not occur, buffer may be lost!\n");
222 return 0;
225 case MMIOM_SEEK: {
226 /* Parameters:
227 * lParam1 = new position
228 * lParam2 = from whence to seek (SEEK_SET, SEEK_CUR, SEEK_END)
229 * Returns: new file postion, -1 on error
230 * NOTE: lDiskOffset should be updated
233 /* LONG Offset = (LONG) lParam1; */
234 /* LONG Whence = (LONG) lParam2; */
236 FIXME(mmio,"MMIOM_SEEK on memory files should not occur, buffer may be lost!\n");
237 return -1;
240 default:
241 FIXME(mmio, "unexpected message %u\n", uMessage);
242 return 0;
245 return 0;
248 /**************************************************************************
249 * MMIO_Open [internal]
251 static HMMIO16 MMIO_Open(LPSTR szFileName, MMIOINFO16 * lpmmioinfo,
252 DWORD dwOpenFlags, int use16)
254 LPMMIOINFO16 lpmminfo;
255 HMMIO16 hmmio;
256 UINT16 result;
258 TRACE(mmio, "('%s', %p, %08lX);\n", szFileName, lpmmioinfo, dwOpenFlags);
260 hmmio = GlobalAlloc16(GHND, sizeof(MMIOINFO16));
261 lpmminfo = (LPMMIOINFO16)GlobalLock16(hmmio);
262 if (lpmminfo == NULL)
263 return 0;
264 memset(lpmminfo, 0, sizeof(MMIOINFO16));
266 /* assume DOS file if not otherwise specified */
267 if (!lpmmioinfo ||
268 (lpmmioinfo->fccIOProc == 0 && lpmmioinfo->pIOProc == NULL)) {
270 lpmminfo->fccIOProc = FOURCC_DOS;
271 lpmminfo->pIOProc = (LPMMIOPROC16) mmioDosIOProc;
273 /* if just the four character code is present, look up IO proc */
274 else if (lpmmioinfo->pIOProc == NULL) {
276 lpmminfo->fccIOProc = lpmmioinfo->fccIOProc;
277 lpmminfo->pIOProc = mmioInstallIOProc16(lpmmioinfo->fccIOProc, NULL, MMIO_FINDPROC);
280 /* if IO proc specified, use it and specified four character code */
281 else {
283 lpmminfo->fccIOProc = lpmmioinfo->fccIOProc;
284 lpmminfo->pIOProc = lpmmioinfo->pIOProc;
287 if (dwOpenFlags & MMIO_ALLOCBUF) {
288 if ((result = mmioSetBuffer16(hmmio, NULL, MMIO_DEFAULTBUFFER, 0))) {
289 if (lpmmioinfo)
290 lpmmioinfo->wErrorRet = result;
291 return 0;
293 } else
294 if (lpmminfo->fccIOProc == FOURCC_MEM) {
295 if ((result = mmioSetBuffer16(hmmio, lpmmioinfo->pchBuffer, lpmmioinfo->cchBuffer, 0))) {
296 if (lpmmioinfo)
297 lpmmioinfo->wErrorRet = result;
298 return 0;
302 lpmminfo->dwFlags = dwOpenFlags;
303 lpmminfo->hmmio = hmmio;
305 /* call IO proc to actually open file */
306 result = (UINT16) mmioSendMessage(hmmio, MMIOM_OPEN, (LPARAM) szFileName, (LPARAM) use16);
308 GlobalUnlock16(hmmio);
310 if (result != 0) {
311 GlobalFree16(hmmio);
312 return 0;
315 return hmmio;
318 /**************************************************************************
319 * mmioOpenW [WINMM.123]
321 HMMIO32 WINAPI mmioOpen32W(LPWSTR szFileName, MMIOINFO32 * lpmmioinfo,
322 DWORD dwOpenFlags)
324 LPSTR szFn = HEAP_strdupWtoA(GetProcessHeap(),0,szFileName);
325 HMMIO32 ret = MMIO_Open(szFn,(LPMMIOINFO16)lpmmioinfo,dwOpenFlags,FALSE);
327 HeapFree(GetProcessHeap(),0,szFn);
328 return ret;
331 /**************************************************************************
332 * mmioOpenA [WINMM.122]
334 HMMIO32 WINAPI mmioOpen32A(LPSTR szFileName, MMIOINFO32 * lpmmioinfo,
335 DWORD dwOpenFlags)
337 return MMIO_Open(szFileName,(LPMMIOINFO16)lpmmioinfo,dwOpenFlags,FALSE);
340 /**************************************************************************
341 * mmioOpen [MMSYSTEM.1210]
343 HMMIO16 WINAPI mmioOpen16(LPSTR szFileName, MMIOINFO16 * lpmmioinfo,
344 DWORD dwOpenFlags)
346 return MMIO_Open(szFileName,(LPMMIOINFO16)lpmmioinfo,dwOpenFlags,TRUE);
350 /**************************************************************************
351 * mmioClose [WINMM.114]
353 MMRESULT32 WINAPI mmioClose32(HMMIO32 hmmio, UINT32 uFlags)
355 LPMMIOINFO16 lpmminfo;
356 MMRESULT32 result;
358 TRACE(mmio, "(%04X, %04X);\n", hmmio, uFlags);
360 lpmminfo = (LPMMIOINFO16) GlobalLock16(hmmio);
361 if (lpmminfo == NULL)
362 return 0;
364 /* flush the file - if error reported, ignore */
365 if (mmioFlush32(hmmio, MMIO_EMPTYBUF) != 0)
366 lpmminfo->dwFlags &= ~MMIO_DIRTY;
368 result = mmioSendMessage(hmmio,MMIOM_CLOSE,(LPARAM)uFlags,(LPARAM)0);
370 mmioSetBuffer16(hmmio, NULL, 0, 0);
372 GlobalUnlock16(hmmio);
373 GlobalFree16(hmmio);
375 return result;
379 /**************************************************************************
380 * mmioClose [MMSYSTEM.1211]
382 MMRESULT16 WINAPI mmioClose16(HMMIO16 hmmio, UINT16 uFlags)
384 return mmioClose32(hmmio,uFlags);
389 /**************************************************************************
390 * mmioRead [WINMM.124]
392 LONG WINAPI mmioRead32(HMMIO32 hmmio, HPSTR pch, LONG cch)
394 LONG count;
395 LPMMIOINFO16 lpmminfo;
397 TRACE(mmio, "(%04X, %p, %ld);\n", hmmio, pch, cch);
399 lpmminfo = (LPMMIOINFO16)GlobalLock16(hmmio);
400 if (lpmminfo == NULL)
401 return -1;
403 if (lpmminfo->pchNext != lpmminfo->pchEndRead) {
404 count = lpmminfo->pchEndRead - lpmminfo->pchNext;
405 if (count > cch || count < 0) count = cch;
406 memcpy(pch, lpmminfo->pchNext, count);
407 lpmminfo->pchNext += count;
408 pch += count;
409 cch -= count;
410 } else
411 count = 0;
413 if (cch&&(lpmminfo->fccIOProc!=FOURCC_MEM)) {
414 if (lpmminfo->cchBuffer) {
415 mmioFlush32(hmmio, MMIO_EMPTYBUF);
417 while (cch) {
418 LONG size;
419 lpmminfo->lBufOffset = lpmminfo->lDiskOffset;
420 lpmminfo->pchNext = lpmminfo->pchBuffer;
421 lpmminfo->pchEndRead = lpmminfo->pchBuffer;
422 size = mmioSendMessage(hmmio, MMIOM_READ,
423 (LPARAM) lpmminfo->pchBuffer,
424 (LPARAM) lpmminfo->cchBuffer);
425 if (size<=0) break;
426 lpmminfo->pchEndRead = lpmminfo->pchBuffer + size;
427 if (size > cch) size = cch;
428 memcpy(pch, lpmminfo->pchNext, size);
429 lpmminfo->pchNext += size;
430 pch += size;
431 cch -= size;
432 count += size;
434 } else {
435 count += mmioSendMessage(hmmio, MMIOM_READ, (LPARAM) pch, (LPARAM) cch);
436 if (count>0) lpmminfo->lBufOffset += count;
440 GlobalUnlock16(hmmio);
441 TRACE(mmio, "count=%ld\n", count);
442 return count;
445 /**************************************************************************
446 * mmioRead [MMSYSTEM.1212]
448 LONG WINAPI mmioRead16(HMMIO16 hmmio, HPSTR pch, LONG cch)
450 return mmioRead32(hmmio,pch,cch);
453 /**************************************************************************
454 * mmioWrite [WINMM.133]
456 LONG WINAPI mmioWrite32(HMMIO32 hmmio, HPCSTR pch, LONG cch)
458 LONG count;
459 LPMMIOINFO16 lpmminfo;
461 TRACE(mmio, "(%04X, %p, %ld);\n", hmmio, pch, cch);
463 lpmminfo = (LPMMIOINFO16)GlobalLock16(hmmio);
464 if (lpmminfo == NULL)
465 return -1;
467 if (lpmminfo->cchBuffer) {
468 count = 0;
469 while (cch) {
470 if (lpmminfo->pchNext != lpmminfo->pchEndWrite) {
471 count = lpmminfo->pchEndWrite - lpmminfo->pchNext;
472 if (count > cch || count < 0) count = cch;
473 memcpy(lpmminfo->pchNext, pch, count);
474 lpmminfo->pchNext += count;
475 pch += count;
476 cch -= count;
477 lpmminfo->dwFlags |= MMIO_DIRTY;
478 } else
479 if (lpmminfo->fccIOProc==FOURCC_MEM) {
480 if (lpmminfo->adwInfo[0]) {
481 /* from where would we get the memory handle? */
482 FIXME(mmio, "memory file expansion not implemented!\n");
483 } else break;
486 if (lpmminfo->pchNext == lpmminfo->pchEndWrite
487 && mmioFlush32(hmmio, MMIO_EMPTYBUF)) break;
489 } else {
490 count = mmioSendMessage(hmmio, MMIOM_WRITE, (LPARAM) pch, (LPARAM) cch);
491 lpmminfo->lBufOffset = lpmminfo->lDiskOffset;
494 GlobalUnlock16(hmmio);
495 TRACE(mmio, "count=%ld\n", count);
496 return count;
499 /**************************************************************************
500 * mmioWrite [MMSYSTEM.1213]
502 LONG WINAPI mmioWrite16(HMMIO16 hmmio, HPCSTR pch, LONG cch)
504 return mmioWrite32(hmmio,pch,cch);
507 /**************************************************************************
508 * mmioSeek [MMSYSTEM.1214]
510 LONG WINAPI mmioSeek32(HMMIO32 hmmio, LONG lOffset, INT32 iOrigin)
512 int offset;
513 LPMMIOINFO16 lpmminfo;
515 TRACE(mmio, "(%04X, %08lX, %d);\n", hmmio, lOffset, iOrigin);
517 lpmminfo = (LPMMIOINFO16)GlobalLock16(hmmio);
518 if (lpmminfo == NULL)
519 return -1;
521 offset = (iOrigin==SEEK_SET)?(lOffset - lpmminfo->lBufOffset):
522 (iOrigin==SEEK_CUR)?(lOffset +
523 (lpmminfo->pchNext - lpmminfo->pchBuffer)):-1;
525 if ((lpmminfo->cchBuffer<0)||
526 ((offset>=0)&&(offset<=(lpmminfo->pchEndRead-lpmminfo->pchBuffer)))) {
527 lpmminfo->pchNext = lpmminfo->pchBuffer + offset;
528 GlobalUnlock16(hmmio);
529 return lpmminfo->lBufOffset + offset;
532 if ((lpmminfo->fccIOProc==FOURCC_MEM)||mmioFlush32(hmmio, MMIO_EMPTYBUF)) {
533 GlobalUnlock16(hmmio);
534 return -1;
537 offset = mmioSendMessage(hmmio, MMIOM_SEEK, (LPARAM) lOffset, (LPARAM) iOrigin);
538 lpmminfo->lBufOffset = lpmminfo->lDiskOffset;
540 GlobalUnlock16(hmmio);
541 return offset;
544 /**************************************************************************
545 * mmioSeek [MMSYSTEM.1214]
547 LONG WINAPI mmioSeek16(HMMIO16 hmmio, LONG lOffset, INT16 iOrigin)
549 return mmioSeek32(hmmio,lOffset,iOrigin);
552 /**************************************************************************
553 * mmioGetInfo [MMSYSTEM.1215]
555 UINT16 WINAPI mmioGetInfo16(HMMIO16 hmmio, MMIOINFO16 * lpmmioinfo, UINT16 uFlags)
557 LPMMIOINFO16 lpmminfo;
558 TRACE(mmio, "mmioGetInfo\n");
559 lpmminfo = (LPMMIOINFO16)GlobalLock16(hmmio);
560 if (lpmminfo == NULL) return 0;
561 memcpy(lpmmioinfo, lpmminfo, sizeof(MMIOINFO16));
562 GlobalUnlock16(hmmio);
563 return 0;
566 /**************************************************************************
567 * mmioGetInfo [WINMM.118]
569 UINT32 WINAPI mmioGetInfo32(HMMIO32 hmmio, MMIOINFO32*lpmmioinfo, UINT32 uFlags)
571 MMIOINFO16 mmioinfo;
572 LPMMIOINFO16 lpmminfo=&mmioinfo;
573 UINT16 ret;
575 TRACE(mmio, "(0x%04x,%p,0x%08x)\n",hmmio,lpmmioinfo,uFlags);
576 ret = mmioGetInfo16(hmmio,&mmioinfo,uFlags);
577 if (!ret)
578 return 0;
579 lpmmioinfo->dwFlags = lpmminfo->dwFlags;
580 lpmmioinfo->fccIOProc = lpmminfo->fccIOProc;
581 lpmmioinfo->pIOProc = (LPMMIOPROC32)lpmminfo->pIOProc;
582 lpmmioinfo->wErrorRet = lpmminfo->wErrorRet;
583 lpmmioinfo->htask = lpmminfo->htask;
584 lpmmioinfo->cchBuffer = lpmminfo->cchBuffer;
585 lpmmioinfo->pchBuffer = lpmminfo->pchBuffer;
586 lpmmioinfo->pchNext = lpmminfo->pchNext;
587 lpmmioinfo->pchEndRead = lpmminfo->pchEndRead;
588 lpmmioinfo->pchEndWrite = lpmminfo->pchEndWrite;
589 lpmmioinfo->lBufOffset = lpmminfo->lBufOffset;
590 lpmmioinfo->lDiskOffset = lpmminfo->lDiskOffset;
591 memcpy(lpmmioinfo->adwInfo,lpmminfo->adwInfo,sizeof(lpmminfo->adwInfo));
592 lpmmioinfo->dwReserved1 = lpmminfo->dwReserved1;
593 lpmmioinfo->dwReserved2 = lpmminfo->dwReserved2;
594 lpmmioinfo->hmmio = lpmminfo->hmmio;
595 return 0;
598 /**************************************************************************
599 * mmioSetInfo [MMSYSTEM.1216]
601 UINT16 WINAPI mmioSetInfo16(HMMIO16 hmmio, const MMIOINFO16 * lpmmioinfo, UINT16 uFlags)
603 LPMMIOINFO16 lpmminfo;
604 TRACE(mmio, "mmioSetInfo\n");
605 lpmminfo = (LPMMIOINFO16)GlobalLock16(hmmio);
606 if (lpmminfo == NULL) return 0;
607 lpmminfo->pchNext = lpmmioinfo->pchNext;
608 lpmminfo->pchEndRead = lpmmioinfo->pchEndRead;
609 GlobalUnlock16(hmmio);
610 return 0;
613 /**************************************************************************
614 * mmioSetInfo [WINMM.130]
616 UINT32 WINAPI mmioSetInfo32(HMMIO32 hmmio, const MMIOINFO32 * lpmmioinfo, UINT32 uFlags)
618 LPMMIOINFO16 lpmminfo;
619 TRACE(mmio, "mmioSetInfo\n");
620 lpmminfo = (LPMMIOINFO16)GlobalLock16(hmmio);
621 if (lpmminfo == NULL) return 0;
622 lpmminfo->pchNext = lpmmioinfo->pchNext;
623 lpmminfo->pchEndRead = lpmmioinfo->pchEndRead;
624 GlobalUnlock16(hmmio);
625 return 0;
628 /**************************************************************************
629 * mmioSetBuffer [WINMM.129]
631 UINT32 WINAPI mmioSetBuffer32(HMMIO32 hmmio, LPSTR pchBuffer,
632 LONG cchBuffer, UINT32 uFlags)
634 LPMMIOINFO16 lpmminfo;
636 if (mmioFlush32(hmmio, MMIO_EMPTYBUF) != 0)
637 return MMIOERR_CANNOTWRITE;
639 TRACE(mmio, "(hmmio=%04x, pchBuf=%p, cchBuf=%ld, uFlags=%#08x)\n",
640 hmmio, pchBuffer, cchBuffer, uFlags);
642 lpmminfo = (LPMMIOINFO16)GlobalLock16(hmmio);
643 if (lpmminfo == NULL) return 0;
644 if ((!cchBuffer || pchBuffer) && lpmminfo->dwFlags&MMIO_ALLOCBUF) {
645 GlobalUnlock16(lpmminfo->dwReserved1);
646 GlobalFree16(lpmminfo->dwReserved1);
647 lpmminfo->dwFlags &= ~MMIO_ALLOCBUF;
649 if (pchBuffer) {
650 lpmminfo->pchBuffer = pchBuffer;
651 } else if (lpmminfo->dwFlags&MMIO_ALLOCBUF) {
652 HGLOBAL16 hNewBuf;
653 GlobalUnlock16(lpmminfo->dwReserved1);
654 hNewBuf = GlobalReAlloc16(lpmminfo->dwReserved1, cchBuffer, 0);
655 if (!hNewBuf) {
656 /* FIXME: this assumes the memory block didn't move */
657 GlobalLock16(lpmminfo->dwReserved1);
658 GlobalUnlock16(hmmio);
659 return MMIOERR_OUTOFMEMORY;
661 lpmminfo->dwReserved1 = hNewBuf;
662 lpmminfo->pchBuffer = GlobalLock16(hNewBuf);
663 } else if (cchBuffer) {
664 HGLOBAL16 hNewBuf = GlobalAlloc16(GMEM_MOVEABLE, cchBuffer);
665 if (!hNewBuf) {
666 GlobalUnlock16(hmmio);
667 return MMIOERR_OUTOFMEMORY;
669 lpmminfo->dwReserved1 = hNewBuf;
670 lpmminfo->pchBuffer = GlobalLock16(hNewBuf);
671 lpmminfo->dwFlags |= MMIO_ALLOCBUF;
672 } else
673 lpmminfo->pchBuffer = NULL;
674 lpmminfo->cchBuffer = cchBuffer;
675 lpmminfo->pchNext = lpmminfo->pchBuffer;
676 lpmminfo->pchEndRead = lpmminfo->pchBuffer;
677 lpmminfo->pchEndWrite = lpmminfo->pchBuffer + cchBuffer;
678 lpmminfo->lBufOffset = 0;
680 GlobalUnlock16(hmmio);
681 return (UINT16) 0;
684 /**************************************************************************
685 * mmioSetBuffer [MMSYSTEM.1217]
687 UINT16 WINAPI mmioSetBuffer16(HMMIO16 hmmio, LPSTR pchBuffer,
688 LONG cchBuffer, UINT16 uFlags)
690 return mmioSetBuffer32(hmmio, pchBuffer, cchBuffer, uFlags);
693 /**************************************************************************
694 * mmioFlush [WINMM.117]
696 UINT32 WINAPI mmioFlush32(HMMIO32 hmmio, UINT32 uFlags)
698 LPMMIOINFO16 lpmminfo;
699 TRACE(mmio, "(%04X, %04X)\n", hmmio, uFlags);
700 lpmminfo = (LPMMIOINFO16)GlobalLock16(hmmio);
701 if (lpmminfo == NULL) return 0;
703 if ((!lpmminfo->cchBuffer)||(lpmminfo->fccIOProc==FOURCC_MEM)) {
704 GlobalUnlock16(hmmio);
705 return 0;
707 /* not quite sure what to do here, but I'll guess */
708 if (lpmminfo->dwFlags & MMIO_DIRTY) {
709 mmioSendMessage(hmmio, MMIOM_SEEK,
710 (LPARAM) lpmminfo->lBufOffset,
711 (LPARAM) SEEK_SET);
712 mmioSendMessage(hmmio, MMIOM_WRITE,
713 (LPARAM) lpmminfo->pchBuffer,
714 (LPARAM) (lpmminfo->pchNext - lpmminfo->pchBuffer) );
715 lpmminfo->dwFlags &= ~MMIO_DIRTY;
717 if (uFlags & MMIO_EMPTYBUF) {
718 /* seems Windows doesn't do any seeking here, hopefully this
719 won't matter, otherwise a slight rewrite is necessary */
720 mmioSendMessage(hmmio, MMIOM_SEEK,
721 (LPARAM) (lpmminfo->lBufOffset +
722 (lpmminfo->pchNext - lpmminfo->pchBuffer)),
723 (LPARAM) SEEK_SET);
724 lpmminfo->pchNext = lpmminfo->pchBuffer;
725 lpmminfo->pchEndRead = lpmminfo->pchBuffer;
726 lpmminfo->lBufOffset = lpmminfo->lDiskOffset;
729 GlobalUnlock16(hmmio);
730 return 0;
733 /**************************************************************************
734 * mmioFlush [MMSYSTEM.1218]
736 UINT16 WINAPI mmioFlush16(HMMIO16 hmmio, UINT16 uFlags)
738 return mmioFlush32(hmmio,uFlags);
741 /**************************************************************************
742 * mmioAdvance [MMSYSTEM.1219]
744 UINT32 WINAPI mmioAdvance32(HMMIO32 hmmio,MMIOINFO32*lpmmioinfo,UINT32 uFlags)
746 LPMMIOINFO16 lpmminfo;
747 TRACE(mmio, "mmioAdvance\n");
748 lpmminfo = (LPMMIOINFO16)GlobalLock16(hmmio);
749 if (lpmminfo == NULL) return 0;
750 if (!lpmminfo->cchBuffer) {
751 GlobalUnlock16(hmmio);
752 return MMIOERR_UNBUFFERED;
754 lpmminfo->pchNext = lpmmioinfo->pchNext;
755 if (mmioFlush32(hmmio, MMIO_EMPTYBUF)) {
756 GlobalUnlock16(hmmio);
757 return MMIOERR_CANNOTWRITE;
759 if (uFlags == MMIO_READ)
760 lpmmioinfo->pchEndRead = lpmmioinfo->pchBuffer +
761 mmioSendMessage(hmmio, MMIOM_READ,
762 (LPARAM) lpmmioinfo->pchBuffer,
763 (LPARAM) lpmmioinfo->cchBuffer);
764 #if 0 /* mmioFlush32 already did the writing */
765 if (uFlags == MMIO_WRITE)
766 mmioSendMessage(hmmio, MMIOM_WRITE,
767 (LPARAM) lpmmioinfo->pchBuffer,
768 (LPARAM) lpmmioinfo->cchBuffer);
769 #endif
770 lpmmioinfo->pchNext = lpmmioinfo->pchBuffer;
771 GlobalUnlock16(hmmio);
772 return 0;
775 /**************************************************************************
776 * mmioAdvance [MMSYSTEM.1219]
778 UINT16 WINAPI mmioAdvance16(HMMIO16 hmmio,MMIOINFO16*lpmmioinfo,UINT16 uFlags)
780 LPMMIOINFO16 lpmminfo;
781 TRACE(mmio, "mmioAdvance\n");
782 lpmminfo = (LPMMIOINFO16)GlobalLock16(hmmio);
783 if (lpmminfo == NULL) return 0;
784 if (!lpmminfo->cchBuffer) {
785 GlobalUnlock16(hmmio);
786 return MMIOERR_UNBUFFERED;
788 lpmminfo->pchNext = lpmmioinfo->pchNext;
789 if (mmioFlush32(hmmio, MMIO_EMPTYBUF)) {
790 GlobalUnlock16(hmmio);
791 return MMIOERR_CANNOTWRITE;
793 if (uFlags == MMIO_READ)
794 lpmmioinfo->pchEndRead = lpmmioinfo->pchBuffer +
795 mmioSendMessage(hmmio, MMIOM_READ,
796 (LPARAM) lpmmioinfo->pchBuffer,
797 (LPARAM) lpmmioinfo->cchBuffer);
798 #if 0 /* mmioFlush32 already did the writing */
799 if (uFlags == MMIO_WRITE)
800 mmioSendMessage(hmmio, MMIOM_WRITE,
801 (LPARAM) lpmmioinfo->pchBuffer,
802 (LPARAM) lpmmioinfo->cchBuffer);
803 #endif
804 lpmmioinfo->pchNext = lpmmioinfo->pchBuffer;
805 GlobalUnlock16(hmmio);
806 return 0;
809 /**************************************************************************
810 * mmioStringToFOURCCA [WINMM.131]
812 FOURCC WINAPI mmioStringToFOURCC32A(LPCSTR sz, UINT32 uFlags)
814 return mmioStringToFOURCC16(sz,uFlags);
817 /**************************************************************************
818 * mmioStringToFOURCCW [WINMM.132]
820 FOURCC WINAPI mmioStringToFOURCC32W(LPCWSTR sz, UINT32 uFlags)
822 LPSTR szA = HEAP_strdupWtoA(GetProcessHeap(),0,sz);
823 FOURCC ret = mmioStringToFOURCC32A(szA,uFlags);
825 HeapFree(GetProcessHeap(),0,szA);
826 return ret;
829 /**************************************************************************
830 * mmioStringToFOURCC [MMSYSTEM.1220]
832 FOURCC WINAPI mmioStringToFOURCC16(LPCSTR sz, UINT16 uFlags)
834 return mmioFOURCC(sz[0],sz[1],sz[2],sz[3]);
837 /**************************************************************************
838 * mmioInstallIOProc16 [MMSYSTEM.1221]
840 LPMMIOPROC16 WINAPI mmioInstallIOProc16(FOURCC fccIOProc,
841 LPMMIOPROC16 pIOProc, DWORD dwFlags)
843 TRACE(mmio, "(%ld, %p, %08lX)\n",
844 fccIOProc, pIOProc, dwFlags);
846 if (dwFlags & MMIO_GLOBALPROC) {
847 FIXME(mmio, " global procedures not implemented\n");
850 /* just handle the known procedures for now */
851 switch(dwFlags & (MMIO_INSTALLPROC|MMIO_REMOVEPROC|MMIO_FINDPROC)) {
852 case MMIO_INSTALLPROC:
853 return NULL;
854 case MMIO_REMOVEPROC:
855 return NULL;
856 case MMIO_FINDPROC:
857 if (fccIOProc == FOURCC_DOS)
858 return (LPMMIOPROC16) mmioDosIOProc;
859 else if (fccIOProc == FOURCC_MEM)
860 return (LPMMIOPROC16) mmioMemIOProc;
861 else
862 return NULL;
863 default:
864 return NULL;
868 /**************************************************************************
869 * mmioInstallIOProc32A [WINMM.120]
871 LPMMIOPROC32 WINAPI mmioInstallIOProc32A(FOURCC fccIOProc,
872 LPMMIOPROC32 pIOProc, DWORD dwFlags)
874 FIXME(mmio, "(%c%c%c%c,%p,0x%08lx) -- empty stub \n",
875 (char)((fccIOProc&0xff000000)>>24),
876 (char)((fccIOProc&0x00ff0000)>>16),
877 (char)((fccIOProc&0x0000ff00)>> 8),
878 (char)(fccIOProc&0x000000ff),
879 pIOProc, dwFlags );
880 return 0;
883 /**************************************************************************
884 * mmioSendMessage [MMSYSTEM.1222]
886 LRESULT WINAPI mmioSendMessage(HMMIO16 hmmio, UINT16 uMessage,
887 LPARAM lParam1, LPARAM lParam2)
889 LPMMIOINFO16 lpmminfo;
890 LRESULT result;
891 const char *msg = NULL;
893 #ifdef DEBUG_RUNTIME
894 switch (uMessage) {
895 #define msgname(x) case x: msg = #x; break;
896 msgname(MMIOM_OPEN);
897 msgname(MMIOM_CLOSE);
898 msgname(MMIOM_READ);
899 msgname(MMIOM_WRITE);
900 msgname(MMIOM_WRITEFLUSH);
901 msgname(MMIOM_SEEK);
902 msgname(MMIOM_RENAME);
903 #undef msgname
905 #endif
907 if (msg)
908 TRACE(mmio, "(%04X, %s, %ld, %ld)\n",
909 hmmio, msg, lParam1, lParam2);
910 else
911 TRACE(mmio, "(%04X, %u, %ld, %ld)\n",
912 hmmio, uMessage, lParam1, lParam2);
914 lpmminfo = (LPMMIOINFO16)GlobalLock16(hmmio);
916 if (lpmminfo && lpmminfo->pIOProc)
917 result = (*lpmminfo->pIOProc)((LPSTR)lpmminfo, uMessage, lParam1, lParam2);
918 else
919 result = MMSYSERR_INVALPARAM;
921 GlobalUnlock16(hmmio);
923 return result;
926 /**************************************************************************
927 * mmioDescend [MMSYSTEM.1223]
929 UINT16 WINAPI mmioDescend(HMMIO16 hmmio, MMCKINFO * lpck,
930 const MMCKINFO * lpckParent, UINT16 uFlags)
932 DWORD dwOldPos;
933 MMCKINFO searchcki;
934 char ckid[5],fcc[5];
936 TRACE(mmio,"(%04X, %p, %p, %04X);\n",hmmio,lpck,lpckParent,uFlags);
938 if (lpck == NULL)
939 return 0;
940 dwOldPos = mmioSeek32(hmmio, 0, SEEK_CUR);
941 TRACE(mmio, "dwOldPos=%ld\n", dwOldPos);
943 if (lpckParent != NULL) {
944 TRACE(mmio, "seek inside parent at %ld !\n", lpckParent->dwDataOffset);
945 dwOldPos = mmioSeek32(hmmio,lpckParent->dwDataOffset,SEEK_SET);
948 /* The SDK docu says 'ckid' is used for all cases. Real World
949 * examples disagree -Marcus,990216.
952 searchcki.fccType = 0;
953 /* find_chunk looks for 'ckid' */
954 if (uFlags & MMIO_FINDCHUNK)
955 searchcki.ckid = lpck->ckid;
956 /* find_riff and find_list look for 'fccType' */
957 if (uFlags & MMIO_FINDLIST) {
958 searchcki.ckid = FOURCC_LIST;
959 searchcki.fccType = lpck->fccType;
961 if (uFlags & MMIO_FINDRIFF) {
962 searchcki.ckid = FOURCC_RIFF;
963 searchcki.fccType = lpck->fccType;
965 memcpy(&fcc,&(searchcki.fccType),4);fcc[4]=0;
966 memcpy(&ckid,&(searchcki.ckid),4);ckid[4]=0;
967 TRACE(mmio,"searching for %s.%s\n",ckid,searchcki.fccType?fcc:"<any>");
969 if (uFlags & (MMIO_FINDCHUNK|MMIO_FINDLIST|MMIO_FINDRIFF)) {
970 while (TRUE) {
971 LONG ix;
973 ix = mmioRead32(hmmio, (LPSTR)lpck, 3 * sizeof(DWORD));
974 if (ix < 2*sizeof(DWORD)) {
975 mmioSeek32(hmmio, dwOldPos, SEEK_SET);
976 WARN(mmio, "return ChunkNotFound\n");
977 return MMIOERR_CHUNKNOTFOUND;
979 lpck->dwDataOffset = dwOldPos + 2 * sizeof(DWORD);
980 if (ix < lpck->dwDataOffset - dwOldPos) {
981 mmioSeek32(hmmio, dwOldPos, SEEK_SET);
982 WARN(mmio, "return ChunkNotFound\n");
983 return MMIOERR_CHUNKNOTFOUND;
985 memcpy(ckid,&lpck->ckid,4);
986 memcpy(fcc,&lpck->fccType,4);
987 TRACE(mmio, "ckid=%s fcc=%s cksize=%08lX !\n",
988 ckid, searchcki.fccType?fcc:"<unused>",
989 lpck->cksize
991 if ((searchcki.ckid == lpck->ckid) &&
992 (!searchcki.fccType ||
993 (searchcki.fccType == lpck->fccType)
996 break;
998 dwOldPos = lpck->dwDataOffset + lpck->cksize;
999 mmioSeek32(hmmio, dwOldPos, SEEK_SET);
1001 /* If we were looking for RIFF/LIST chunks, the final dataptr
1002 * is after the chunkid. If we were just looking for the chunk
1003 * it is after the cksize. So add 4 in RIFF/LIST case.
1005 if (uFlags & (MMIO_FINDLIST|MMIO_FINDRIFF))
1006 lpck->dwDataOffset+=sizeof(DWORD);
1007 } else {
1008 /* FIXME: unverified, does it do this? */
1009 if (mmioRead32(hmmio, (LPSTR)lpck, sizeof(MMCKINFO)) < sizeof(MMCKINFO)) {
1010 mmioSeek32(hmmio, dwOldPos, SEEK_SET);
1011 WARN(mmio, "return ChunkNotFound 2nd\n");
1012 return MMIOERR_CHUNKNOTFOUND;
1014 lpck->dwDataOffset = dwOldPos + 2 * sizeof(DWORD);
1015 if (lpck->ckid == FOURCC_RIFF || lpck->ckid == FOURCC_LIST)
1016 lpck->dwDataOffset += sizeof(DWORD);
1018 mmioSeek32(hmmio, lpck->dwDataOffset, SEEK_SET);
1019 memcpy(ckid,&(lpck->ckid),4);
1020 TRACE(mmio, "lpck->ckid=%s lpck->cksize=%ld !\n", ckid, lpck->cksize);
1021 memcpy(fcc,&(lpck->fccType),4);
1022 TRACE(mmio, "lpck->fccType=%08lX (%s)!\n", lpck->fccType,searchcki.fccType?fcc:"");
1023 return 0;
1026 /**************************************************************************
1027 * mmioAscend [WINMM.113]
1029 UINT32 WINAPI mmioAscend32(HMMIO32 hmmio, MMCKINFO * lpck, UINT32 uFlags)
1031 TRACE(mmio, "(%04X, %p, %04X);\n",
1032 hmmio, lpck, uFlags);
1033 if (lpck->dwFlags&MMIO_DIRTY) {
1034 DWORD dwOldPos, dwNewSize, dwSizePos;
1036 TRACE(mmio, "chunk is marked MMIO_DIRTY, correcting chunk size\n");
1037 dwOldPos = mmioSeek32(hmmio, 0, SEEK_CUR);
1038 TRACE(mmio, "dwOldPos=%ld\n", dwOldPos);
1039 dwNewSize = dwOldPos - lpck->dwDataOffset;
1040 if (dwNewSize != lpck->cksize) {
1041 TRACE(mmio, "dwNewSize=%ld\n", dwNewSize);
1042 lpck->cksize = dwNewSize;
1044 dwSizePos = lpck->dwDataOffset - sizeof(DWORD);
1045 if (lpck->ckid == FOURCC_RIFF || lpck->ckid == FOURCC_LIST)
1046 dwSizePos -= sizeof(DWORD);
1047 TRACE(mmio, "dwSizePos=%ld\n", dwSizePos);
1049 mmioSeek32(hmmio, dwSizePos, SEEK_SET);
1050 mmioWrite32(hmmio, (LPSTR)&dwNewSize, sizeof(DWORD));
1053 mmioSeek32(hmmio,lpck->dwDataOffset+lpck->cksize,SEEK_SET);
1055 return 0;
1058 /**************************************************************************
1059 * mmioAscend [MMSYSTEM.1224]
1061 UINT16 WINAPI mmioAscend16(HMMIO16 hmmio, MMCKINFO * lpck, UINT16 uFlags)
1063 return mmioAscend32(hmmio,lpck,uFlags);
1066 /**************************************************************************
1067 * mmioCreateChunk [MMSYSTEM.1225]
1069 UINT16 WINAPI mmioCreateChunk16(HMMIO16 hmmio, MMCKINFO * lpck, UINT16 uFlags)
1071 DWORD dwOldPos;
1072 LONG ix;
1074 TRACE(mmio, "(%04X, %p, %04X);\n",
1075 hmmio, lpck, uFlags);
1077 dwOldPos = mmioSeek32(hmmio, 0, SEEK_CUR);
1078 TRACE(mmio, "dwOldPos=%ld\n", dwOldPos);
1080 if (uFlags == MMIO_CREATELIST)
1081 lpck->ckid = FOURCC_LIST;
1082 else if (uFlags == MMIO_CREATERIFF)
1083 lpck->ckid = FOURCC_RIFF;
1085 TRACE(mmio, "ckid=%08lX\n", lpck->ckid);
1087 lpck->dwDataOffset = dwOldPos + 2 * sizeof(DWORD);
1088 if (lpck->ckid == FOURCC_RIFF || lpck->ckid == FOURCC_LIST)
1089 lpck->dwDataOffset += sizeof(DWORD);
1090 lpck->dwFlags = MMIO_DIRTY;
1092 ix = mmioWrite32(hmmio, (LPSTR)lpck, lpck->dwDataOffset - dwOldPos);
1093 TRACE(mmio, "after _lwrite32 ix = %ld req = %ld, errno = %d\n",ix,lpck->dwDataOffset - dwOldPos,errno);
1094 if (ix < lpck->dwDataOffset - dwOldPos) {
1096 mmioSeek32(hmmio, dwOldPos, SEEK_SET);
1097 WARN(mmio, "return CannotWrite\n");
1098 return MMIOERR_CANNOTWRITE;
1101 return 0;
1104 /**************************************************************************
1105 * mmioCreateChunk [WINMM.115]
1107 UINT32 WINAPI mmioCreateChunk32(HMMIO32 hmmio, MMCKINFO * lpck, UINT32 uFlags)
1109 return mmioCreateChunk16(hmmio, lpck, uFlags);
1112 /**************************************************************************
1113 * mmioRename [MMSYSTEM.1226]
1115 UINT16 WINAPI mmioRename16(LPCSTR szFileName, LPCSTR szNewFileName,
1116 MMIOINFO16 * lpmmioinfo, DWORD dwRenameFlags)
1118 UINT16 result;
1119 LPMMIOINFO16 lpmminfo;
1120 HMMIO16 hmmio;
1122 TRACE(mmio, "('%s', '%s', %p, %08lX);\n",
1123 szFileName, szNewFileName, lpmmioinfo, dwRenameFlags);
1125 hmmio = GlobalAlloc16(GHND, sizeof(MMIOINFO16));
1126 lpmminfo = (LPMMIOINFO16) GlobalLock16(hmmio);
1128 if (lpmmioinfo)
1129 memcpy(lpmminfo, lpmmioinfo, sizeof(MMIOINFO16));
1131 /* assume DOS file if not otherwise specified */
1132 if (lpmminfo->fccIOProc == 0 && lpmminfo->pIOProc == NULL) {
1134 lpmminfo->fccIOProc = mmioFOURCC('D', 'O', 'S', ' ');
1135 lpmminfo->pIOProc = (LPMMIOPROC16) mmioDosIOProc;
1138 /* if just the four character code is present, look up IO proc */
1139 else if (lpmminfo->pIOProc == NULL) {
1141 lpmminfo->pIOProc = mmioInstallIOProc16(lpmminfo->fccIOProc, NULL, MMIO_FINDPROC);
1144 /* (if IO proc specified, use it and specified four character code) */
1146 result = (UINT16) mmioSendMessage(hmmio, MMIOM_RENAME, (LPARAM) szFileName, (LPARAM) szNewFileName);
1148 GlobalUnlock16(hmmio);
1149 GlobalFree16(hmmio);
1151 return result;
1154 /**************************************************************************
1155 * mmioRenameA [WINMM.125]
1157 UINT32 WINAPI mmioRename32A(LPCSTR szFileName, LPCSTR szNewFileName,
1158 MMIOINFO32* lpmmioinfo, DWORD dwRenameFlags)
1160 FIXME(mmio, "This may fail\n");
1161 return mmioRename16(szFileName, szNewFileName, (MMIOINFO16*)lpmmioinfo, dwRenameFlags);
1164 /**************************************************************************
1165 * mmioRenameW [WINMM.126]
1167 UINT32 WINAPI mmioRename32W(LPCWSTR szFileName, LPCWSTR szNewFileName,
1168 MMIOINFO32* lpmmioinfo, DWORD dwRenameFlags)
1170 LPSTR szFn = HEAP_strdupWtoA(GetProcessHeap(), 0, szFileName);
1171 LPSTR sznFn = HEAP_strdupWtoA(GetProcessHeap(), 0, szNewFileName);
1172 UINT32 ret = mmioRename32A(szFn, sznFn, lpmmioinfo, dwRenameFlags);
1174 HeapFree(GetProcessHeap(),0,szFn);
1175 HeapFree(GetProcessHeap(),0,sznFn);
1176 return ret;