windows-nt/Source/XPSP1/NT/multimedia/directx/dinput/dx8/dll/diriff.c
2020-09-26 16:20:57 +08:00

662 lines
19 KiB
C

/****************************************************************************
MODULE: RIFF.CPP
Tab settings: Every 4 spaces
Copyright 1996, Microsoft Corporation, All Rights Reserved.
PURPOSE: Classes for reading and writing RIFF files
CLASSES:
CRIFFFile Encapsulates common RIFF file functionality
Author(s): Name:
---------- ----------------
DMS Daniel M. Sangster
Revision History:
-----------------
Version Date Author Comments
1.0 25-Jul-96 DMS Created
COMMENTS:
****************************************************************************/
#include "dinputpr.h"
#define sqfl sqflDev
/*
* This function converts MMIO errors to HRESULTS
*/
HRESULT INLINE hresMMIO(UINT mmioErr)
{
switch(mmioErr)
{
case 0x0: return S_OK;
case MMIOERR_FILENOTFOUND: return hresLe(ERROR_FILE_NOT_FOUND);/* file not found */
case MMIOERR_OUTOFMEMORY: return hresLe(ERROR_OUTOFMEMORY); /* out of memory */
case MMIOERR_CANNOTOPEN: return hresLe(ERROR_OPEN_FAILED); /* cannot open */
case MMIOERR_CANNOTCLOSE: return S_FALSE; /* cannot close */
case MMIOERR_CANNOTREAD: return hresLe(ERROR_READ_FAULT); /* cannot read */
case MMIOERR_CANNOTWRITE: return hresLe(ERROR_WRITE_FAULT); /* cannot write */
case MMIOERR_CANNOTSEEK: return hresLe(ERROR_SEEK); /* cannot seek */
case MMIOERR_CANNOTEXPAND: return hresLe(ERROR_SEEK); /* cannot expand file */
case MMIOERR_CHUNKNOTFOUND: return hresLe(ERROR_SECTOR_NOT_FOUND); /* chunk not found */
case MMIOERR_UNBUFFERED: return E_FAIL;
case MMIOERR_PATHNOTFOUND: return hresLe(ERROR_PATH_NOT_FOUND);/* path incorrect */
case MMIOERR_ACCESSDENIED: return hresLe(ERROR_ACCESS_DENIED); /* file was protected */
case MMIOERR_SHARINGVIOLATION: return hresLe(ERROR_SHARING_VIOLATION); /* file in use */
case MMIOERR_NETWORKERROR: return hresLe(ERROR_UNEXP_NET_ERR); /* network not responding */
case MMIOERR_TOOMANYOPENFILES: return hresLe(ERROR_TOO_MANY_OPEN_FILES); /* no more file handles */
case MMIOERR_INVALIDFILE: return hresLe(ERROR_BAD_FORMAT); /* default error file error */
default: return E_FAIL;
}
}
HRESULT INLINE RIFF_Ascend(HMMIO hmmio, LPMMCKINFO lpmmckinfo)
{
return hresMMIO( mmioAscend(hmmio, lpmmckinfo, 0) );
}
HRESULT INLINE RIFF_Descend(HMMIO hmmio, LPMMCKINFO lpmmckinfo, LPMMCKINFO lpmmckinfoParent, UINT nFlags)
{
return hresMMIO(mmioDescend(hmmio, lpmmckinfo, lpmmckinfoParent, nFlags));
}
HRESULT INLINE RIFF_CreateChunk(HMMIO hmmio, LPMMCKINFO lpmmckinfo, UINT nFlags)
{
// set cksize to zero to overcome a bug in release version of mmioAscend
// which does not correctly write back the size of the chunk
lpmmckinfo->cksize = 0;
return hresMMIO(mmioCreateChunk(hmmio, lpmmckinfo, nFlags));
}
HRESULT INLINE RIFF_Read(HMMIO hmmio, LPVOID pBuf, LONG nCount)
{
return (nCount == mmioRead(hmmio, (char*)pBuf, nCount)) ? S_OK: hresLe(ERROR_READ_FAULT);
}
HRESULT INLINE RIFF_Write(HMMIO hmmio, const LPVOID pBuf, LONG nCount)
{
return ( nCount == mmioWrite(hmmio, (char*)pBuf, nCount)) ? S_OK : hresLe(ERROR_WRITE_FAULT);
}
HRESULT RIFF_Close(HMMIO hmmio, UINT nFlags)
{
return hresMMIO(mmioClose(hmmio, nFlags));
}
/*
* Opens a RIFF file for read / write
* Reads/Writes a GUID that servers as our signature
*/
HRESULT RIFF_Open
(
LPCSTR lpszFilename,
UINT nOpenFlags,
PHANDLE phmmio,
LPMMCKINFO lpmmck,
PDWORD pdwEffectSz
)
{
HRESULT hres = S_OK;
MMIOINFO mmInfo;
HMMIO hmmio;
LPSTR lpszFile = (LPSTR)lpszFilename;
ZeroX(mmInfo);
//There is a problem in mmio that causes somewhat unpredictable behaviour under certain conditions --
//in particular, if using drag-n-drop, it may happen so that mmioOpenA() opens 1 file for reading
//and completely different file for writing, if only the file name is specified.
//So we need to check whether we have only the file name or the path (path will contain a \).
if (strchr(lpszFilename, '\\') == NULL)
{
//Put the current directory before the file name to give the absolute path.
//Apparently mmio doesn't have a problem if given absolute path.
CHAR szFullPath[MAX_PATH];
DWORD dwWritten = GetFullPathNameA(lpszFilename, MAX_PATH, (LPSTR)&szFullPath, NULL);
if (( dwWritten != 0) && (dwWritten <= MAX_PATH))
{
lpszFile = (LPSTR)&szFullPath;
}
}
//There is a problem in mmioOpenA() that makes it leak when the file specified to open for reading
//doesn't exist.
//To avoid the leak, we need to check overselves whether we're opening for reading and
//whether the file exists.
if( nOpenFlags == ( MMIO_READ | MMIO_ALLOCBUF) )
{
HANDLE h = CreateFileA(lpszFile,
GENERIC_READ,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (h == INVALID_HANDLE_VALUE)
{
//set the error code
hres = hresLe(GetLastError());
goto done;
}
else
{
//the file is there; close handle
CloseHandle(h);
}
}
// go ahead and open the file, if we can
hmmio = mmioOpenA(lpszFile, &mmInfo, nOpenFlags);
if(mmInfo.wErrorRet)
{
hres = hresMMIO(mmInfo.wErrorRet);
AssertF(FAILED(hres));
}
// if( nOpenFlags & ( MMIO_READ | MMIO_ALLOCBUF) )
if( nOpenFlags == ( MMIO_READ | MMIO_ALLOCBUF) )
{
if(SUCCEEDED(hres))
{
// locate and descend into FORC RIFF chunk
lpmmck->fccType = FCC_FORCE_EFFECT_RIFF;
hres = RIFF_Descend(hmmio, lpmmck, NULL, MMIO_FINDRIFF);
}
if(SUCCEEDED(hres))
{
GUID GUIDVersion;
//read the guid
hres = RIFF_Read(hmmio, &GUIDVersion, sizeof(GUID));
if(SUCCEEDED(hres))
{
if(IsEqualGUID(&GUIDVersion, &GUID_INTERNALFILEEFFECT))
{
} else
{
hres = hresLe(ERROR_BAD_FORMAT);
}
}
}
}
//else if( nOpenFlags & ( MMIO_WRITE | MMIO_ALLOCBUF) )
else if( nOpenFlags & ( MMIO_WRITE) )
{
// create the FORC RIFF chunk
lpmmck->fccType = FCC_FORCE_EFFECT_RIFF;
hres = RIFF_CreateChunk(hmmio, lpmmck, MMIO_CREATERIFF);
if(SUCCEEDED(hres))
{
//write the version GUID
hres = RIFF_Write(hmmio, (PV)&GUID_INTERNALFILEEFFECT, sizeof(GUID));
}
} else
{
hres = E_FAIL;
}
*phmmio = hmmio;
done:;
return hres;
}
/*****************************************************************************
*
* internal
* RIFF_ReadEffect
*
* Reads a single Effect from a RIFF file
*
* The callee bears the responsibility to free the TypeSpecificParameterBlock
* for the effect.
*
*
*****************************************************************************/
#ifdef _M_IA64
//This is hack to read 32 bit files on ia64, since someone decided to write
//pointers to file.
//Copied from dinput.h and modified.
typedef struct DIEFFECT_FILE32 {
DWORD dwSize; /* sizeof(DIEFFECT) */
DWORD dwFlags; /* DIEFF_* */
DWORD dwDuration; /* Microseconds */
DWORD dwSamplePeriod; /* Microseconds */
DWORD dwGain;
DWORD dwTriggerButton; /* or DIEB_NOTRIGGER */
DWORD dwTriggerRepeatInterval; /* Microseconds */
DWORD cAxes; /* Number of axes */
/*Make sure size is same on both 1386 and ia64.
LPDWORD rgdwAxes;
LPLONG rglDirection;
LPDIENVELOPE lpEnvelope;
*/ DWORD rgdwAxes; /* Array of axes */
DWORD rglDirection; /* Array of directions */
DWORD lpEnvelope; /* Optional */
DWORD cbTypeSpecificParams; /* Size of params */
/*Make sure size is same on both 1386 and ia64.
LPVOID lpvTypeSpecificParams;
*/ DWORD lpvTypeSpecificParams; /* Pointer to params */
//#if(DIRECTINPUT_VERSION >= 0x0600)//Out since file format does not change.
DWORD dwStartDelay; /* Microseconds */
//#endif /* DIRECTINPUT_VERSION >= 0x0600 *///Out since file format does not change.
} DIEFFECT_FILE32, *LPDIEFFECT_FILE32;
#endif /*_M_IA64*/
HRESULT
RIFF_ReadEffect
(
HMMIO hmmio,
LPDIFILEEFFECT lpDiFileEf
)
{
HRESULT hres = E_FAIL;
MMCKINFO mmckinfoEffectLIST;
MMCKINFO mmckinfoDataCHUNK;
LPDIEFFECT peff = (LPDIEFFECT)lpDiFileEf->lpDiEffect;
// descend into the effect list
mmckinfoEffectLIST.fccType = FCC_EFFECT_LIST;
hres = RIFF_Descend(hmmio, &mmckinfoEffectLIST, NULL, MMIO_FINDLIST);
if(SUCCEEDED(hres))
{
//read the name
hres = RIFF_Read(hmmio, lpDiFileEf->szFriendlyName, MAX_SIZE_SNAME);
}
if(SUCCEEDED(hres))
{
#ifdef _M_IA64
DIEFFECT_FILE32 eff32;
//read the effect structure
hres = RIFF_Read(hmmio, &eff32, sizeof(eff32));
AssertF( eff32.dwSize == sizeof(eff32) );
if( eff32.dwSize != sizeof(eff32) )
{
hres = ERROR_BAD_FORMAT;
}
else
{
peff->dwSize=sizeof(*peff);
peff->dwFlags=eff32.dwFlags;
peff->dwDuration=eff32.dwDuration;
peff->dwSamplePeriod=eff32.dwSamplePeriod;
peff->dwGain=eff32.dwGain;
peff->dwTriggerButton=eff32.dwTriggerButton;
peff->dwTriggerRepeatInterval=eff32.dwTriggerRepeatInterval;
peff->cAxes=eff32.cAxes;
peff->cbTypeSpecificParams=eff32.cbTypeSpecificParams;
peff->lpvTypeSpecificParams=(LPVOID)(DWORD_PTR)eff32.lpvTypeSpecificParams;
peff->dwStartDelay=eff32.dwStartDelay;
}
#else /*_M_IA64*/
// Reading the effect structure will zap out the following,
// so we make a copy before the read.
LPDIENVELOPE lpEnvelope = peff->lpEnvelope;
LPDWORD rgdwAxes = peff->rgdwAxes;
LPLONG rglDirection= peff->rglDirection;
//read the effect structure
hres = RIFF_Read(hmmio, peff, sizeof(DIEFFECT));
AssertF( peff->dwSize == sizeof(DIEFFECT) );
if( peff->dwSize != sizeof(DIEFFECT) )
{
hres = ERROR_BAD_FORMAT;
}
else
{
if(peff->lpEnvelope) peff->lpEnvelope = lpEnvelope;
if(peff->rgdwAxes) peff->rgdwAxes = rgdwAxes;
if(peff->rglDirection) peff->rglDirection = rglDirection;
}
#endif /*_M_IA64*/
if(SUCCEEDED(hres))
{
AssertF(peff->cAxes < DIEFFECT_MAXAXES);
if(peff->cAxes >= DIEFFECT_MAXAXES)
{
hres = ERROR_BAD_FORMAT;
}
}
}
if(SUCCEEDED(hres))
{
// read the Effect GUID
hres = RIFF_Read(hmmio, &lpDiFileEf->GuidEffect, sizeof(GUID));
}
if(SUCCEEDED(hres))
{
UINT nRepeatCount;
//read in the repeat count
hres = RIFF_Read(hmmio, &nRepeatCount, sizeof(nRepeatCount));
}
if(SUCCEEDED(hres) && peff->rgdwAxes)
{
// descend the data chunk
mmckinfoDataCHUNK.ckid = FCC_DATA_CHUNK;
hres = RIFF_Descend(hmmio, &mmckinfoDataCHUNK, NULL, MMIO_FINDCHUNK);
if(SUCCEEDED(hres))
{
//read the axes
hres = RIFF_Read(hmmio, peff->rgdwAxes, cbX(*peff->rgdwAxes)*(peff->cAxes));
hres = RIFF_Ascend(hmmio, &mmckinfoDataCHUNK);
}
}
if(SUCCEEDED(hres) && peff->rglDirection)
{
//descend the data chunk
mmckinfoDataCHUNK.ckid = FCC_DATA_CHUNK;
hres = RIFF_Descend(hmmio, &mmckinfoDataCHUNK, NULL, MMIO_FINDCHUNK);
if(SUCCEEDED(hres))
{
//read the direction
hres = RIFF_Read(hmmio, peff->rglDirection, cbX(*peff->rglDirection)*(peff->cAxes));
hres = RIFF_Ascend(hmmio, &mmckinfoDataCHUNK);
}
}
if(SUCCEEDED(hres) && peff->lpEnvelope )
{
//descend the data chunk
mmckinfoDataCHUNK.ckid = FCC_DATA_CHUNK;
hres = RIFF_Descend(hmmio, &mmckinfoDataCHUNK, NULL, MMIO_FINDCHUNK);
if(SUCCEEDED(hres))
{
hres = RIFF_Read(hmmio, peff->lpEnvelope, sizeof(DIENVELOPE));
hres = RIFF_Ascend(hmmio, &mmckinfoDataCHUNK);
}
}
if(SUCCEEDED(hres) && (peff->cbTypeSpecificParams > 0))
{
// get the param structure, if any
hres = AllocCbPpv( peff->cbTypeSpecificParams, &peff->lpvTypeSpecificParams );
if( SUCCEEDED( hres ) )
{
//descend the data chunk
mmckinfoDataCHUNK.ckid = FCC_DATA_CHUNK;
hres = RIFF_Descend(hmmio, &mmckinfoDataCHUNK, NULL, MMIO_FINDCHUNK);
if(SUCCEEDED(hres))
{
hres = RIFF_Read(hmmio, peff->lpvTypeSpecificParams, peff->cbTypeSpecificParams);
hres = RIFF_Ascend(hmmio, &mmckinfoDataCHUNK);
}
}
}
if(SUCCEEDED(hres))
{
// ascend the effect chunk
hres = RIFF_Ascend(hmmio, &mmckinfoEffectLIST);
}
return hres;
}
/*
* RIFF_WriteEffect
*
* Writes a single Effect structure to a RIFF file
*
* The effect structure is quite complex. It contains pointers
* to a number of other structures. This function checks for
* valid data before it writes out the effect structure
*/
HRESULT RIFF_WriteEffect
(HMMIO hmmio,
LPDIFILEEFFECT lpDiFileEf
)
{
HRESULT hres = E_FAIL;
LPDIEFFECT peff = (LPDIEFFECT)lpDiFileEf->lpDiEffect;
MMCKINFO mmckinfoEffectLIST;
MMCKINFO mmckinfoDataCHUNK;
LPDWORD rgdwAxes = NULL;
LPLONG rglDirection = NULL;
LPDIENVELOPE lpEnvelope = NULL;
LPVOID lpvTypeSpecPar = NULL;
EnterProcI(RIFF_WriteEffect, (_ "xx", hmmio, lpDiFileEf));
// create the effect LIST
mmckinfoEffectLIST.fccType = FCC_EFFECT_LIST;
hres = RIFF_CreateChunk(hmmio, &mmckinfoEffectLIST, MMIO_CREATELIST);
//save the effect ptrs and write flags to the file, instead of ptrs
if (peff->rgdwAxes)
{
rgdwAxes = peff->rgdwAxes;
peff->rgdwAxes = (LPDWORD)DIEP_AXES;
}
if (peff->rglDirection)
{
rglDirection = peff->rglDirection;
peff->rglDirection = (LPLONG)DIEP_DIRECTION;
}
if (peff->lpEnvelope)
{
lpEnvelope = peff->lpEnvelope;
peff->lpEnvelope = (LPDIENVELOPE)DIEP_ENVELOPE;
}
if ((peff->cbTypeSpecificParams > 0) && (peff->lpvTypeSpecificParams != NULL))
{
lpvTypeSpecPar = peff->lpvTypeSpecificParams;
peff->lpvTypeSpecificParams = (LPVOID)DIEP_TYPESPECIFICPARAMS;
}
if(SUCCEEDED(hres))
{
hres = hresFullValidReadStrA(lpDiFileEf->szFriendlyName, MAX_JOYSTRING,1);
if(SUCCEEDED(hres))
{
//write the name, only MAX_SIZE_SNAME characters
hres = RIFF_Write(hmmio, lpDiFileEf->szFriendlyName, MAX_SIZE_SNAME);
}
}
if(SUCCEEDED(hres))
{
hres = (peff && IsBadReadPtr(peff, cbX(DIEFFECT_DX5))) ? E_POINTER : S_OK;
if(SUCCEEDED(hres))
{
hres = (peff && IsBadReadPtr(peff, peff->dwSize)) ? E_POINTER : S_OK;
}
if(SUCCEEDED(hres))
{
//write the effect structure
#ifdef _M_IA64
DIEFFECT_FILE32 eff32;
ZeroMemory(&eff32,sizeof(eff32));
eff32.dwSize=sizeof(eff32);
eff32.dwFlags=peff->dwFlags;
eff32.dwDuration=peff->dwDuration;
eff32.dwSamplePeriod=peff->dwSamplePeriod;
eff32.dwGain=peff->dwGain;
eff32.dwTriggerButton=peff->dwTriggerButton;
eff32.dwTriggerRepeatInterval=peff->dwTriggerRepeatInterval;
eff32.cAxes=peff->cAxes;
eff32.cbTypeSpecificParams=peff->cbTypeSpecificParams;
eff32.lpvTypeSpecificParams=(DWORD)(DWORD_PTR)peff->lpvTypeSpecificParams;
eff32.dwStartDelay=peff->dwStartDelay;
hres = RIFF_Write(hmmio, &eff32, eff32.dwSize);
#else /*_M_IA64*/
hres = RIFF_Write(hmmio, peff, peff->dwSize);
#endif /*_M_IA64*/
}
}
//restore the ptrs
if (rgdwAxes != NULL)
{
peff->rgdwAxes = rgdwAxes;
}
if (rglDirection != NULL)
{
peff->rglDirection = rglDirection;
}
if (lpEnvelope != NULL)
{
peff->lpEnvelope = lpEnvelope;
}
if (lpvTypeSpecPar != NULL)
{
peff->lpvTypeSpecificParams = lpvTypeSpecPar;
}
if(SUCCEEDED(hres))
{
// write the Effect GUID
hres = RIFF_Write(hmmio, &lpDiFileEf->GuidEffect, sizeof(GUID));
}
//write 1 as the repeat count
if(SUCCEEDED(hres))
{
UINT nRepeatCount = 1;
hres = RIFF_Write(hmmio, &nRepeatCount, sizeof(DWORD));
}
if(SUCCEEDED(hres) && rgdwAxes )
{
hres = (IsBadReadPtr(rgdwAxes, (*rgdwAxes)*cbX(peff->cAxes))) ? E_POINTER : S_OK;
if(SUCCEEDED(hres))
{
// create the data CHUNK
mmckinfoDataCHUNK.ckid = FCC_DATA_CHUNK;
hres = RIFF_CreateChunk(hmmio, &mmckinfoDataCHUNK, 0);
//write the axes
if(SUCCEEDED(hres))
{
hres = RIFF_Write(hmmio, rgdwAxes, sizeof(*rgdwAxes)*(peff->cAxes));
hres = RIFF_Ascend(hmmio, &mmckinfoDataCHUNK);
}
}
}
if(SUCCEEDED(hres) && rglDirection)
{
hres = (IsBadReadPtr(rglDirection, cbX(*rglDirection)*(peff->cAxes))) ? E_POINTER : S_OK;
if(SUCCEEDED(hres))
{
// create the data CHUNK
mmckinfoDataCHUNK.ckid = FCC_DATA_CHUNK;
hres = RIFF_CreateChunk(hmmio, &mmckinfoDataCHUNK, 0);
if(SUCCEEDED(hres))
{
//write the direction
hres = RIFF_Write(hmmio, rglDirection, sizeof(*rglDirection)*(peff->cAxes));
hres = RIFF_Ascend(hmmio, &mmckinfoDataCHUNK);
}
}
}
//write the envelope, if one is present
if(SUCCEEDED(hres) &&
(lpEnvelope != NULL) )
{
hres = (IsBadReadPtr(lpEnvelope, cbX(*lpEnvelope))) ? E_POINTER : S_OK;
if(SUCCEEDED(hres))
{
// create the data CHUNK
mmckinfoDataCHUNK.ckid = FCC_DATA_CHUNK;
hres = RIFF_CreateChunk(hmmio, &mmckinfoDataCHUNK, 0);
//write the envelope
if(SUCCEEDED(hres))
{
hres = RIFF_Write(hmmio, lpEnvelope, lpEnvelope->dwSize);
hres = RIFF_Ascend(hmmio, &mmckinfoDataCHUNK);
}
}
}
//write the type-specific
if(SUCCEEDED(hres) &&
(peff->cbTypeSpecificParams > 0) &&
(peff->lpvTypeSpecificParams != NULL) )
{
hres = (IsBadReadPtr(lpvTypeSpecPar, peff->cbTypeSpecificParams)) ? E_POINTER : S_OK;
if(SUCCEEDED(hres))
{
// create the data CHUNK
mmckinfoDataCHUNK.ckid = FCC_DATA_CHUNK;
hres = RIFF_CreateChunk(hmmio, &mmckinfoDataCHUNK, 0);
//write the params
if(SUCCEEDED(hres))
{
hres = RIFF_Write(hmmio, lpvTypeSpecPar, peff->cbTypeSpecificParams);
hres = RIFF_Ascend(hmmio, &mmckinfoDataCHUNK);
}
}
}
if(SUCCEEDED(hres))
{
// ascend the effect chunk
hres = RIFF_Ascend(hmmio, &mmckinfoEffectLIST);
}
ExitOleProc();
return hres;
}