📄 mmio.c
字号:
EnterCriticalSection(&WINMM_IData.cs);
/* lookup next unallocated WORD handle, with a non NULL value */
while (++MMIO_counter == 0 || MMIO_Get((HMMIO)(ULONG_PTR)MMIO_counter));
wm->info.hmmio = (HMMIO)(ULONG_PTR)MMIO_counter;
wm->lpNext = WINMM_IData.lpMMIO;
WINMM_IData.lpMMIO = wm;
LeaveCriticalSection(&WINMM_IData.cs);
}
return wm;
}
/**************************************************************************
* MMIO_Destroy [internal]
*-
* Destroys an internal representation for a mmio instance
*/
static BOOL MMIO_Destroy(LPWINE_MMIO wm)
{
LPWINE_MMIO* m;
EnterCriticalSection(&WINMM_IData.cs);
/* search for the matching one... */
m = &(WINMM_IData.lpMMIO);
while (*m && *m != wm) m = &(*m)->lpNext;
/* ...and destroy */
if (*m) {
*m = (*m)->lpNext;
HeapFree(GetProcessHeap(), 0, wm);
wm = NULL;
}
LeaveCriticalSection(&WINMM_IData.cs);
return wm ? FALSE : TRUE;
}
/****************************************************************
* MMIO_Flush [INTERNAL]
*/
static MMRESULT MMIO_Flush(WINE_MMIO* wm, UINT uFlags)
{
if (wm->info.cchBuffer && (wm->info.fccIOProc != FOURCC_MEM)) {
/* not quite sure what to do here, but I'll guess */
if (wm->info.dwFlags & MMIO_DIRTY) {
/* FIXME: error handling */
send_message(wm->ioProc, &wm->info, MMIOM_SEEK,
wm->info.lBufOffset, SEEK_SET, MMIO_PROC_32A);
send_message(wm->ioProc, &wm->info, MMIOM_WRITE,
(LPARAM)wm->info.pchBuffer,
wm->info.pchNext - wm->info.pchBuffer, MMIO_PROC_32A);
}
if (uFlags & MMIO_EMPTYBUF)
wm->info.pchNext = wm->info.pchEndRead = wm->info.pchBuffer;
}
wm->info.dwFlags &= ~MMIO_DIRTY;
return MMSYSERR_NOERROR;
}
/***************************************************************************
* MMIO_GrabNextBuffer [INTERNAL]
*/
static LONG MMIO_GrabNextBuffer(LPWINE_MMIO wm, int for_read)
{
LONG size = wm->info.cchBuffer;
TRACE("bo=%lx do=%lx of=%lx\n",
wm->info.lBufOffset, wm->info.lDiskOffset,
send_message(wm->ioProc, &wm->info, MMIOM_SEEK, 0, SEEK_CUR, MMIO_PROC_32A));
wm->info.lBufOffset = wm->info.lDiskOffset;
wm->info.pchNext = wm->info.pchBuffer;
wm->info.pchEndRead = wm->info.pchBuffer;
wm->info.pchEndWrite = wm->info.pchBuffer + wm->info.cchBuffer;
wm->bBufferLoaded = TRUE;
if (for_read) {
size = send_message(wm->ioProc, &wm->info, MMIOM_READ,
(LPARAM)wm->info.pchBuffer, size, MMIO_PROC_32A);
if (size > 0)
wm->info.pchEndRead += size;
else
wm->bBufferLoaded = FALSE;
}
return size;
}
/***************************************************************************
* MMIO_SetBuffer [INTERNAL]
*/
static MMRESULT MMIO_SetBuffer(WINE_MMIO* wm, void* pchBuffer, LONG cchBuffer,
UINT uFlags)
{
TRACE("(%p %p %ld %u)\n", wm, pchBuffer, cchBuffer, uFlags);
if (uFlags) return MMSYSERR_INVALPARAM;
if (cchBuffer > 0xFFFF)
WARN("Untested handling of huge mmio buffers (%ld >= 64k)\n", cchBuffer);
if (MMIO_Flush(wm, 0) != MMSYSERR_NOERROR)
return MMIOERR_CANNOTWRITE;
/* free previous buffer if allocated */
if (wm->info.dwFlags & MMIO_ALLOCBUF) {
HeapFree(GetProcessHeap(), 0, wm->info.pchBuffer);
wm->info.pchBuffer = NULL;
wm->info.dwFlags &= ~MMIO_ALLOCBUF;
}
if (pchBuffer) {
wm->info.pchBuffer = pchBuffer;
} else if (cchBuffer) {
if (!(wm->info.pchBuffer = HeapAlloc(GetProcessHeap(), 0, cchBuffer)))
return MMIOERR_OUTOFMEMORY;
wm->info.dwFlags |= MMIO_ALLOCBUF;
} else {
wm->info.pchBuffer = NULL;
}
wm->info.cchBuffer = cchBuffer;
wm->info.pchNext = wm->info.pchBuffer;
wm->info.pchEndRead = wm->info.pchBuffer;
wm->info.pchEndWrite = wm->info.pchBuffer + cchBuffer;
wm->info.lBufOffset = 0;
wm->bBufferLoaded = FALSE;
return MMSYSERR_NOERROR;
}
/**************************************************************************
* MMIO_Open [internal]
*/
HMMIO MMIO_Open(LPSTR szFileName, MMIOINFO* refmminfo, DWORD dwOpenFlags,
enum mmioProcType type)
{
LPWINE_MMIO wm;
MMIOINFO mmioinfo;
TRACE("('%s', %p, %08lX, %d);\n", szFileName, refmminfo, dwOpenFlags, type);
if (!refmminfo) {
refmminfo = &mmioinfo;
mmioinfo.fccIOProc = 0;
mmioinfo.pIOProc = NULL;
mmioinfo.pchBuffer = NULL;
mmioinfo.cchBuffer = 0;
type = MMIO_PROC_32A;
}
if (dwOpenFlags & (MMIO_PARSE|MMIO_EXIST)) {
char buffer[MAX_PATH];
if (GetFullPathNameA(szFileName, sizeof(buffer), buffer, NULL) >= sizeof(buffer))
return (HMMIO)FALSE;
if ((dwOpenFlags & MMIO_EXIST) && (GetFileAttributesA(buffer) == INVALID_FILE_ATTRIBUTES))
return (HMMIO)FALSE;
strcpy(szFileName, buffer);
return (HMMIO)TRUE;
}
if ((wm = MMIO_Create()) == NULL)
return 0;
/* If both params are NULL, then parse the file name if available */
if (refmminfo->fccIOProc == 0 && refmminfo->pIOProc == NULL) {
wm->info.fccIOProc = MMIO_ParseExtA(szFileName);
/* Handle any unhandled/error case. Assume DOS file */
if (wm->info.fccIOProc == 0)
wm->info.fccIOProc = FOURCC_DOS;
if (!(wm->ioProc = MMIO_FindProcNode(wm->info.fccIOProc))) {
/* If not found, retry with FOURCC_DOS */
wm->info.fccIOProc = FOURCC_DOS;
if (!(wm->ioProc = MMIO_FindProcNode(wm->info.fccIOProc)))
goto error2;
}
wm->bTmpIOProc = FALSE;
}
/* if just the four character code is present, look up IO proc */
else if (refmminfo->pIOProc == NULL) {
wm->info.fccIOProc = refmminfo->fccIOProc;
if (!(wm->ioProc = MMIO_FindProcNode(wm->info.fccIOProc))) goto error2;
wm->bTmpIOProc = FALSE;
}
/* if IO proc specified, use it and specified four character code */
else {
wm->info.fccIOProc = refmminfo->fccIOProc;
MMIO_InstallIOProc(wm->info.fccIOProc, refmminfo->pIOProc,
MMIO_INSTALLPROC, type);
if (!(wm->ioProc = MMIO_FindProcNode(wm->info.fccIOProc))) goto error2;
assert(wm->ioProc->pIOProc == refmminfo->pIOProc);
wm->bTmpIOProc = TRUE;
}
wm->bBufferLoaded = FALSE;
wm->ioProc->count++;
if (dwOpenFlags & MMIO_ALLOCBUF) {
if ((refmminfo->wErrorRet = MMIO_SetBuffer(wm, NULL, MMIO_DEFAULTBUFFER, 0)))
goto error1;
} else if (wm->info.fccIOProc == FOURCC_MEM) {
refmminfo->wErrorRet = MMIO_SetBuffer(wm, refmminfo->pchBuffer, refmminfo->cchBuffer, 0);
if (refmminfo->wErrorRet != MMSYSERR_NOERROR)
goto error1;
wm->bBufferLoaded = TRUE;
} /* else => unbuffered, wm->info.pchBuffer == NULL */
/* see mmioDosIOProc for that one */
wm->info.adwInfo[0] = refmminfo->adwInfo[0];
wm->info.dwFlags = dwOpenFlags;
/* call IO proc to actually open file */
refmminfo->wErrorRet = send_message(wm->ioProc, &wm->info, MMIOM_OPEN,
(LPARAM)szFileName, 0, MMIO_PROC_32A);
/* grab file size, when possible */
wm->dwFileSize = GetFileSize((HANDLE)wm->info.adwInfo[0], NULL);
if (refmminfo->wErrorRet == 0)
return wm->info.hmmio;
error1:
if (wm->ioProc) wm->ioProc->count--;
error2:
MMIO_Destroy(wm);
return 0;
}
/**************************************************************************
* mmioOpenW [WINMM.@]
*/
HMMIO WINAPI mmioOpenW(LPWSTR szFileName, MMIOINFO* lpmmioinfo,
DWORD dwOpenFlags)
{
HMMIO ret;
LPSTR szFn = NULL;
if (szFileName)
{
INT len = WideCharToMultiByte( CP_ACP, 0, szFileName, -1, NULL, 0, NULL, NULL );
szFn = HeapAlloc( GetProcessHeap(), 0, len );
if (!szFn) return NULL;
WideCharToMultiByte( CP_ACP, 0, szFileName, -1, szFn, len, NULL, NULL );
}
ret = MMIO_Open(szFn, lpmmioinfo, dwOpenFlags, MMIO_PROC_32W);
HeapFree(GetProcessHeap(), 0, szFn);
return ret;
}
/**************************************************************************
* mmioOpenA [WINMM.@]
*/
HMMIO WINAPI mmioOpenA(LPSTR szFileName, MMIOINFO* lpmmioinfo,
DWORD dwOpenFlags)
{
return MMIO_Open(szFileName, lpmmioinfo, dwOpenFlags, MMIO_PROC_32A);
}
/**************************************************************************
* mmioClose [WINMM.@]
*/
MMRESULT WINAPI mmioClose(HMMIO hmmio, UINT uFlags)
{
LPWINE_MMIO wm;
MMRESULT result;
TRACE("(%p, %04X);\n", hmmio, uFlags);
if ((wm = MMIO_Get(hmmio)) == NULL)
return MMSYSERR_INVALHANDLE;
if ((result = MMIO_Flush(wm, 0)) != MMSYSERR_NOERROR)
return result;
result = send_message(wm->ioProc, &wm->info, MMIOM_CLOSE,
uFlags, 0, MMIO_PROC_32A);
MMIO_SetBuffer(wm, NULL, 0, 0);
wm->ioProc->count--;
if (wm->bTmpIOProc)
MMIO_InstallIOProc(wm->info.fccIOProc, wm->ioProc->pIOProc,
MMIO_REMOVEPROC, wm->ioProc->type);
MMIO_Destroy(wm);
return result;
}
/**************************************************************************
* mmioRead [WINMM.@]
*/
LONG WINAPI mmioRead(HMMIO hmmio, HPSTR pch, LONG cch)
{
LPWINE_MMIO wm;
LONG count;
TRACE("(%p, %p, %ld);\n", hmmio, pch, cch);
if ((wm = MMIO_Get(hmmio)) == NULL)
return -1;
/* unbuffered case first */
if (!wm->info.pchBuffer)
return send_message(wm->ioProc, &wm->info, MMIOM_READ,
(LPARAM)pch, cch, MMIO_PROC_32A);
/* first try from current buffer */
if (wm->info.pchNext != wm->info.pchEndRead) {
count = wm->info.pchEndRead - wm->info.pchNext;
if (count > cch || count < 0) count = cch;
memcpy(pch, wm->info.pchNext, count);
wm->info.pchNext += count;
pch += count;
cch -= count;
} else
count = 0;
if (cch && (wm->info.fccIOProc != FOURCC_MEM)) {
assert(wm->info.cchBuffer);
while (cch) {
LONG size;
size = MMIO_GrabNextBuffer(wm, TRUE);
if (size <= 0) break;
if (size > cch) size = cch;
memcpy(pch, wm->info.pchBuffer, size);
wm->info.pchNext += size;
pch += size;
cch -= size;
count += size;
}
}
TRACE("count=%ld\n", count);
return count;
}
/**************************************************************************
* mmioWrite [WINMM.@]
*/
LONG WINAPI mmioWrite(HMMIO hmmio, HPCSTR pch, LONG cch)
{
LPWINE_MMIO wm;
LONG count;
TRACE("(%p, %p, %ld);\n", hmmio, pch, cch);
if ((wm = MMIO_Get(hmmio)) == NULL)
return -1;
if (wm->info.cchBuffer) {
LONG bytesW = 0;
count = 0;
while (cch) {
if (wm->info.pchNext != wm->info.pchEndWrite) {
count = wm->info.pchEndWrite - wm->info.pchNext;
if (count > cch || count < 0) count = cch;
memcpy(wm->info.pchNext, pch, count);
wm->info.pchNext += count;
pch += count;
cch -= count;
bytesW += count;
wm->info.dwFlags |= MMIO_DIRTY;
} else {
if (wm->info.fccIOProc == FOURCC_MEM) {
if (wm->info.adwInfo[0]) {
/* from where would we get the memory handle? */
FIXME("memory file expansion not implemented!\n");
break;
} else break;
}
}
if (wm->info.pchNext == wm->info.pchEndWrite)
{
MMIO_Flush(wm, MMIO_EMPTYBUF);
MMIO_GrabNextBuffer(wm, FALSE);
}
else break;
}
count = bytesW;
} else {
count = send_message(wm->ioProc, &wm->info, MMIOM_WRITE,
(LPARAM)pch, cch, MMIO_PROC_32A);
wm->info.lBufOffset = wm->info.lDiskOffset;
}
TRACE("bytes written=%ld\n", count);
return count;
}
/**************************************************************************
* mmioSeek [WINMM.@]
*/
LONG WINAPI mmioSeek(HMMIO hmmio, LONG lOffset, INT iOrigin)
{
LPWINE_MMIO wm;
LONG offset;
TRACE("(%p, %08lX, %d);\n", hmmio, lOffset, iOrigin);
if ((wm = MMIO_Get(hmmio)) == NULL)
return MMSYSERR_INVALHANDLE;
/* not buffered, direct seek on file */
if (!wm->info.pchBuffer)
return send_message(wm->ioProc, &wm->info, MMIOM_SEEK,
lOffset, iOrigin, MMIO_PROC_32A);
switch (iOrigin) {
case SEEK_SET:
offset = lOffset;
break;
case SEEK_CUR:
offset = wm->info.lBufOffset + (wm->info.pchNext - wm->info.pchBuffer) + lOffset;
break;
case SEEK_END:
offset = ((wm->info.fccIOProc == FOURCC_MEM)? wm->info.cchBuffer : wm->dwFileSize) - lOffset;
break;
default:
return -1;
}
if (offset && offset >= wm->dwFileSize && wm->info.fccIOProc != FOURCC_MEM) {
/* should check that write mode exists */
if (MMIO_Flush(wm, 0) != MMSYSERR_NOERROR)
return -1;
wm->info.lBufOffset = offset;
wm->info.pchEndRead = wm->info.pchBuffer;
wm->info.pchEndWrite = wm->info.pchBuffer + wm->info.cchBuffer;
if ((wm->info.dwFlags & MMIO_RWMODE) == MMIO_READ) {
wm->info.lDiskOffset = wm->dwFileSize;
}
} else if ((wm->info.cchBuffer > 0) &&
((offset < wm->info.lBufOffset) ||
(offset >= wm->info.lBufOffset + wm->info.cchBuffer) ||
!wm->bBufferLoaded)) {
/* stay in same buffer ? */
/* some memory mapped buffers are defined with -1 as a size */
/* condition to change buffer */
if ((wm->info.fccIOProc == FOURCC_MEM) ||
MMIO_Flush(wm, 0) != MMSYSERR_NOERROR ||
/* this also sets the wm->info.lDiskOffset field */
send_message(wm->ioProc, &wm->info, MMIOM_SEEK,
(offset / wm->info.cchBuffer) * wm->info.cchBuffer,
SEEK_SET, MMIO_PROC_32A) == -1)
return -1;
MMIO_GrabNextBuffer(wm, TRUE);
}
wm->info.pchNext = wm->info.pchBuffer + (offset - wm->info.lBufOffset);
TRACE("=> %ld\n", offset);
return offset;
}
/**************************************************************************
* mmioGetInfo [WINMM.@]
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -