⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mmio.c

📁 这是一个开放源代码的与WINNT/WIN2K/WIN2003兼容的操作系统
💻 C
📖 第 1 页 / 共 3 页
字号:
/*
 * MMIO functions
 *
 * Copyright 1998 Andrew Taylor
 * Copyright 1998 Ove K鍁en
 * Copyright 2000,2002 Eric Pouech
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

/* Still to be done:
 * 	+ correct handling of global/local IOProcs (and temporary IOProcs)
 *	+ mode of mmio objects is not used (read vs write vs readwrite)
 *	+ thread safeness
 *      + 32 A <=> W message mapping
 */


#include <ctype.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <assert.h>

#include "windef.h"
#include "winbase.h"
#include "winnls.h"
#include "mmsystem.h"
#include "winemm.h"

#include "wine/debug.h"

WINE_DEFAULT_DEBUG_CHANNEL(mmio);

LRESULT         (*pFnMmioCallback16)(DWORD,LPMMIOINFO,UINT,LPARAM,LPARAM) /* = NULL */;

/**************************************************************************
 *               	mmioDosIOProc           		[internal]
 */
static LRESULT CALLBACK mmioDosIOProc(LPMMIOINFO lpmmioinfo, UINT uMessage,
				      LPARAM lParam1, LPARAM lParam2)
{
    LRESULT	ret = MMSYSERR_NOERROR;

    TRACE("(%p, %X, 0x%lx, 0x%lx);\n", lpmmioinfo, uMessage, lParam1, lParam2);

    switch (uMessage) {
    case MMIOM_OPEN:
	{
	    /* Parameters:
	     * lParam1 = szFileName parameter from mmioOpen
	     * lParam2 = reserved
	     * Returns: zero on success, error code on error
	     * NOTE: lDiskOffset automatically set to zero
	     */
	    LPCSTR      szFileName = (LPCSTR)lParam1;

	    if (lpmmioinfo->dwFlags & MMIO_GETTEMP) {
		FIXME("MMIO_GETTEMP not implemented\n");
		return MMIOERR_CANNOTOPEN;
	    }

	    /* if filename NULL, assume open file handle in adwInfo[0] */
	    if (szFileName) {
                OFSTRUCT    ofs;
                lpmmioinfo->adwInfo[0] = (DWORD)OpenFile(szFileName, &ofs, lpmmioinfo->dwFlags & 0xFFFF);
            }
	    if (lpmmioinfo->adwInfo[0] == (DWORD)HFILE_ERROR)
		ret = MMIOERR_CANNOTOPEN;
	}
	break;

    case MMIOM_CLOSE:
	/* Parameters:
	 * lParam1 = wFlags parameter from mmioClose
	 * lParam2 = unused
	 * Returns: zero on success, error code on error
	 */
	if (!(lParam1 & MMIO_FHOPEN))
	    _lclose((HFILE)lpmmioinfo->adwInfo[0]);
	break;

    case MMIOM_READ:
	/* Parameters:
	 * lParam1 = huge pointer to read buffer
	 * lParam2 = number of bytes to read
	 * Returns: number of bytes read, 0 for EOF, -1 for error (error code
	 *	   in wErrorRet)
	 */
	ret = _lread((HFILE)lpmmioinfo->adwInfo[0], (HPSTR)lParam1, (LONG)lParam2);
	if (ret != -1)
	    lpmmioinfo->lDiskOffset += ret;

	break;

    case MMIOM_WRITE:
    case MMIOM_WRITEFLUSH:
	/* no internal buffering, so WRITEFLUSH handled same as WRITE */

	/* Parameters:
	 * lParam1 = huge pointer to write buffer
	 * lParam2 = number of bytes to write
	 * Returns: number of bytes written, -1 for error (error code in
	 *		wErrorRet)
	 */
	ret = _hwrite((HFILE)lpmmioinfo->adwInfo[0], (HPSTR)lParam1, (LONG)lParam2);
	if (ret != -1)
	    lpmmioinfo->lDiskOffset += ret;
	break;

    case MMIOM_SEEK:
	/* Parameters:
	 * lParam1 = new position
	 * lParam2 = from whence to seek (SEEK_SET, SEEK_CUR, SEEK_END)
	 * Returns: new file postion, -1 on error
	 */
	ret = _llseek((HFILE)lpmmioinfo->adwInfo[0], (LONG)lParam1, (LONG)lParam2);
	if (ret != -1)
	    lpmmioinfo->lDiskOffset = ret;
	return ret;

    case MMIOM_RENAME:
	/* Parameters:
	 * lParam1 = old name
	 * lParam2 = new name
	 * Returns: zero on success, non-zero on failure
	 */
 	 if (!MoveFileA((const char*)lParam1, (const char*)lParam2))
	     ret = MMIOERR_FILENOTFOUND;
	 break;

    default:
	FIXME("unexpected message %u\n", uMessage);
	return 0;
    }

    return ret;
}

/**************************************************************************
 *               	mmioMemIOProc           		[internal]
 */
static LRESULT CALLBACK mmioMemIOProc(LPMMIOINFO lpmmioinfo, UINT uMessage,
				      LPARAM lParam1, LPARAM lParam2)
{
    TRACE("(%p,0x%04x,0x%08lx,0x%08lx)\n", lpmmioinfo, uMessage, lParam1, lParam2);

    switch (uMessage) {

    case MMIOM_OPEN:
	/* Parameters:
	 * lParam1 = filename (must be NULL)
	 * lParam2 = reserved
	 * Returns: zero on success, error code on error
	 * NOTE: lDiskOffset automatically set to zero
	 */
	/* FIXME: io proc shouldn't change it */
	if (!(lpmmioinfo->dwFlags & MMIO_CREATE))
	    lpmmioinfo->pchEndRead = lpmmioinfo->pchEndWrite;
        lpmmioinfo->adwInfo[0] = HFILE_ERROR;
	return 0;

    case MMIOM_CLOSE:
	/* Parameters:
	 * lParam1 = wFlags parameter from mmioClose
	 * lParam2 = unused
	 * Returns: zero on success, error code on error
	 */
	return 0;

    case MMIOM_READ:
	/* Parameters:
	 * lParam1 = huge pointer to read buffer
	 * lParam2 = number of bytes to read
	 * Returns: number of bytes read, 0 for EOF, -1 for error (error code
	 *	   in wErrorRet)
	 * NOTE: lDiskOffset should be updated
	 */
	FIXME("MMIOM_READ on memory files should not occur, buffer may be lost!\n");
	return 0;

    case MMIOM_WRITE:
    case MMIOM_WRITEFLUSH:
	/* no internal buffering, so WRITEFLUSH handled same as WRITE */

	/* Parameters:
	 * lParam1 = huge pointer to write buffer
	 * lParam2 = number of bytes to write
	 * Returns: number of bytes written, -1 for error (error code in
	 *		wErrorRet)
	 * NOTE: lDiskOffset should be updated
	 */
	FIXME("MMIOM_WRITE on memory files should not occur, buffer may be lost!\n");
	return 0;

    case MMIOM_SEEK:
	/* Parameters:
	 * lParam1 = new position
	 * lParam2 = from whence to seek (SEEK_SET, SEEK_CUR, SEEK_END)
	 * Returns: new file postion, -1 on error
	 * NOTE: lDiskOffset should be updated
	 */
	FIXME("MMIOM_SEEK on memory files should not occur, buffer may be lost!\n");
	return -1;

    default:
	FIXME("unexpected message %u\n", uMessage);
	return 0;
    }
}

/* This array will be the entire list for most apps 
 * Note that temporary ioProcs will be stored with a 0 fourCC code
 */

static struct IOProcList defaultProcs[] = {
    {&defaultProcs[1], FOURCC_DOS, (LPMMIOPROC)mmioDosIOProc, MMIO_PROC_32A, 0},
    {NULL,             FOURCC_MEM, (LPMMIOPROC)mmioMemIOProc, MMIO_PROC_32A, 0},
};

static struct IOProcList*	pIOProcListAnchor = &defaultProcs[0];

/****************************************************************
 *       	MMIO_FindProcNode 			[INTERNAL]
 *
 * Finds the ProcList node associated with a given FOURCC code.
 */
static struct IOProcList*	MMIO_FindProcNode(FOURCC fccIOProc)
{
    struct IOProcList*	pListNode;

    for (pListNode = pIOProcListAnchor; pListNode; pListNode = pListNode->pNext) {
	if (pListNode->fourCC == fccIOProc) {
	    return pListNode;
	}
    }
    return NULL;
}

/****************************************************************
 *       	MMIO_InstallIOProc 			[INTERNAL]
 */
LPMMIOPROC MMIO_InstallIOProc(FOURCC fccIOProc, LPMMIOPROC pIOProc,
                              DWORD dwFlags, enum mmioProcType type)
{
    LPMMIOPROC	        lpProc = NULL;
    struct IOProcList*  pListNode;
    struct IOProcList** ppListNode;

    TRACE("(%08lx, %p, %08lX, %i)\n", fccIOProc, pIOProc, dwFlags, type);

    if (dwFlags & MMIO_GLOBALPROC)
	FIXME("Global procedures not implemented\n");

    /* just handle the known procedures for now */
    switch (dwFlags & (MMIO_INSTALLPROC|MMIO_REMOVEPROC|MMIO_FINDPROC)) {
    case MMIO_INSTALLPROC:
	/* Create new entry for the IOProc list */
	pListNode = HeapAlloc(GetProcessHeap(), 0, sizeof(*pListNode));
	if (pListNode) {
	    /* Fill in this node */
	    pListNode->fourCC = fccIOProc;
	    pListNode->pIOProc = pIOProc;
	    pListNode->type = type;
	    pListNode->count = 0;

	    /* Stick it on the end of the list */
	    pListNode->pNext = pIOProcListAnchor;
	    pIOProcListAnchor = pListNode;

	    /* Return this IOProc - that's how the caller knows we succeeded */
	    lpProc = pIOProc;
	}
	break;

    case MMIO_REMOVEPROC:
	/*
	 * Search for the node that we're trying to remove
         * We search for a matching fourCC code if it's non null, or the proc
         * address otherwise
         * note that this method won't find the first item on the list, but
	 * since the first two items on this list are ones we won't
	 * let the user delete anyway, that's okay
	 */
	ppListNode = &pIOProcListAnchor;
	while ((*ppListNode) && 
               ((fccIOProc != 0) ? 
                (*ppListNode)->fourCC != fccIOProc : 
                (*ppListNode)->pIOProc != pIOProc))
	    ppListNode = &((*ppListNode)->pNext);

	if (*ppListNode) { /* found it */
	    /* FIXME: what should be done if an open mmio object uses this proc ?
	     * shall we return an error, nuke the mmio object ?
	     */
	    if ((*ppListNode)->count) {
		ERR("Cannot remove a mmIOProc while in use\n");
		break;
	    }
	    /* remove it, but only if it isn't builtin */
	    if ((*ppListNode) >= defaultProcs &&
		(*ppListNode) < defaultProcs + sizeof(defaultProcs)) {
		WARN("Tried to remove built-in mmio proc. Skipping\n");
	    } else {
		/* Okay, nuke it */
		struct IOProcList*  ptmpNode = *ppListNode;
		lpProc = (*ppListNode)->pIOProc;
		*ppListNode = (*ppListNode)->pNext;
		HeapFree(GetProcessHeap(), 0, ptmpNode);
	    }
	}
	break;

    case MMIO_FINDPROC:
	if ((pListNode = MMIO_FindProcNode(fccIOProc))) {
	    lpProc = pListNode->pIOProc;
	}
	break;
    }

    return lpProc;
}

/****************************************************************
 *       	send_message    			[INTERNAL]
 */
static LRESULT	send_message(struct IOProcList* ioProc, LPMMIOINFO mmioinfo,
                             DWORD wMsg, LPARAM lParam1,
                             LPARAM lParam2, enum mmioProcType type)
{
    LRESULT 		result = MMSYSERR_ERROR;
    LPARAM		lp1 = lParam1, lp2 = lParam2;

    if (!ioProc) {
	ERR("brrr\n");
	result = MMSYSERR_INVALPARAM;
    }

    switch (ioProc->type) {
    case MMIO_PROC_16:
        if (pFnMmioCallback16)
            result = pFnMmioCallback16((DWORD)ioProc->pIOProc,
                                       mmioinfo, wMsg, lp1, lp2);
        break;
    case MMIO_PROC_32A:
    case MMIO_PROC_32W:
	if (ioProc->type != type) {
	    /* map (lParam1, lParam2) into (lp1, lp2) 32 A<=>W */
	    FIXME("NIY 32 A<=>W mapping\n");
	}
	result = (ioProc->pIOProc)((LPSTR)mmioinfo, wMsg, lp1, lp2);

#if 0
	if (ioProc->type != type) {
	    /* unmap (lParam1, lParam2) into (lp1, lp2) 32 A<=>W */
	}
#endif
	break;
    default:
	FIXME("Internal error\n");
    }

    return result;
}

/**************************************************************************
 *      			MMIO_ParseExtA 		        [internal]
 *
 * Parses a filename for the extension.
 *
 * RETURNS
 *  The FOURCC code for the extension if found, else 0.
 */
static FOURCC MMIO_ParseExtA(LPCSTR szFileName)
{
    /* Filenames are of the form file.ext{+ABC}
       For now, we take the last '+' if present */

    FOURCC ret = 0;

    /* Note that ext{Start,End} point to the . and + respectively */
    LPSTR extEnd;
    LPSTR extStart;

    TRACE("(%s)\n", debugstr_a(szFileName));

    if (!szFileName)
	return ret;

    /* Find the last '.' */
    extStart = strrchr(szFileName,'.');

    if (!extStart) {
         ERR("No . in szFileName: %s\n", debugstr_a(szFileName));
    } else {
        CHAR ext[5];

        /* Find the '+' afterwards */
        extEnd = strchr(extStart,'+');
        if (extEnd) {

            if (extEnd - extStart - 1 > 4)
                WARN("Extension length > 4\n");
            lstrcpynA(ext, extStart + 1, min(extEnd-extStart,5));

        } else {
            /* No + so just an extension */
            if (strlen(extStart) > 4) {
                WARN("Extension length > 4\n");
            }
            lstrcpynA(ext, extStart + 1, 5);
        }
        TRACE("Got extension: %s\n", debugstr_a(ext));

        /* FOURCC codes identifying file-extensions must be uppercase */
        ret = mmioStringToFOURCCA(ext, MMIO_TOUPPER);
    }
    return ret;
}

/**************************************************************************
 *				MMIO_Get			[internal]
 *
 * Retrieves the mmio object from current process
 */
LPWINE_MMIO	MMIO_Get(HMMIO h)
{
    LPWINE_MMIO		wm = NULL;

    EnterCriticalSection(&WINMM_IData.cs);
    for (wm = WINMM_IData.lpMMIO; wm; wm = wm->lpNext) {
	if (wm->info.hmmio == h)
	    break;
    }
    LeaveCriticalSection(&WINMM_IData.cs);
    return wm;
}

/**************************************************************************
 *				MMIO_Create			[internal]
 *
 * Creates an internal representation for a mmio instance
 */
static	LPWINE_MMIO		MMIO_Create(void)
{
    static	WORD	MMIO_counter = 0;
    LPWINE_MMIO		wm;

    wm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WINE_MMIO));
    if (wm) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -