C++程序  |  851行  |  25.89 KB

/*----------------------------------------------------------------------------
 *
 * File: 
 * eas_xmf.c
 *  5 
 * Contents and purpose:
 * XMF File Parser
 *
 * Copyright Sonic Network Inc. 2005

 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 *----------------------------------------------------------------------------
 * Revision Control:
 *   $Revision: 501 $
 *   $Date: 2006-12-11 17:53:36 -0800 (Mon, 11 Dec 2006) $
 *----------------------------------------------------------------------------
*/

#include "eas_data.h"
#include "eas_miditypes.h"
#include "eas_parser.h"
#include "eas_report.h"
#include "eas_host.h"
#include "eas_midi.h"
#include "eas_xmf.h"
#include "eas_xmfdata.h"
#include "eas_config.h"
#include "eas_vm_protos.h"
#include "eas_mdls.h"
#include "eas_smf.h"


/* XMF header file type */
#define XMF_IDENTIFIER		 	0x584d465f
#define XMF_VERSION_2_00		0x322e3030
#define XMF_FILE_TYPE			0x00000002
#define XMF_SPEC_LEVEL			0x00000001
#define XMF_RIFF_CHUNK			0x52494646
#define XMF_RIFF_DLS			0x444c5320
#define XMF_SMF_CHUNK			0x4d546864

/* local prototypes */
static EAS_RESULT XMF_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset);
static EAS_RESULT XMF_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData);
static EAS_RESULT XMF_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime);
static EAS_RESULT XMF_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode);
static EAS_RESULT XMF_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_STATE *pState);
static EAS_RESULT XMF_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData);
static EAS_RESULT XMF_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData);
static EAS_RESULT XMF_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData);
static EAS_RESULT XMF_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData);
static EAS_RESULT XMF_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value);
static EAS_RESULT XMF_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue);
static EAS_RESULT XMF_FindFileContents (EAS_HW_DATA_HANDLE hwInstData, S_XMF_DATA *pXMFData);
static EAS_RESULT XMF_ReadNode (EAS_HW_DATA_HANDLE hwInstData, S_XMF_DATA *pXMFData, EAS_I32 nodeOffset, EAS_I32 *pLength);
static EAS_RESULT XMF_ReadVLQ (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE fileHandle, EAS_I32 *value);


/*----------------------------------------------------------------------------
 *
 * XMF_Parser
 *
 * This structure contains the functional interface for the XMF parser 
 *----------------------------------------------------------------------------
*/
const S_FILE_PARSER_INTERFACE EAS_XMF_Parser =
{
	XMF_CheckFileType,
	XMF_Prepare,
	XMF_Time,
	XMF_Event,
	XMF_State,
	XMF_Close,
	XMF_Reset,
	XMF_Pause,
	XMF_Resume,
	NULL,
	XMF_SetData,
	XMF_GetData,
	NULL
};

/*----------------------------------------------------------------------------
 * XMF_CheckFileType()
 *----------------------------------------------------------------------------
 * Purpose: 
 * Check the file type to see if we can parse it
 *
 * Inputs:
 * pEASData			- pointer to overall EAS data structure
 * handle			- pointer to file handle
 *		
 * Outputs:
 * 
 *
 * Side Effects:
 *
 *----------------------------------------------------------------------------
*/
static EAS_RESULT XMF_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset)
{
	S_XMF_DATA *pXMFData;
	EAS_RESULT result;
	EAS_U32 temp;
	
	/* assume we don't recognize it initially */
	*ppHandle = NULL;

	/* read the file identifier */
	if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &temp, EAS_TRUE))  != EAS_SUCCESS)
		return result;
	if (temp != XMF_IDENTIFIER)
		return EAS_SUCCESS;

	/* read the version */
	if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &temp, EAS_TRUE))  != EAS_SUCCESS)
		return result;
	if (temp != XMF_VERSION_2_00)
	{
		{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "XMF file version was 0x%08x, expected 0x%08x\n", temp, XMF_VERSION_2_00); */ }
		return EAS_SUCCESS;
	}

	/* read the file type */
	if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &temp, EAS_TRUE))  != EAS_SUCCESS)
		return result;
	if (temp != XMF_FILE_TYPE)
	{
		{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "XMF file type was 0x%08x, expected 0x%08x\n", temp, XMF_FILE_TYPE); */ }
		return EAS_SUCCESS;
	}

	/* read the spec level */
	if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &temp, EAS_TRUE))  != EAS_SUCCESS)
		return result;
	if (temp != XMF_SPEC_LEVEL)
	{
		{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "XMF file spec was 0x%08x, expected 0x%08x\n", temp, XMF_SPEC_LEVEL); */ }
		return EAS_SUCCESS;
	}

	/* check for static memory allocation */
	if (pEASData->staticMemoryModel)
		pXMFData = EAS_CMEnumData(EAS_CM_XMF_DATA);
	else
		pXMFData = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_XMF_DATA));
	if (!pXMFData)
		return EAS_ERROR_MALLOC_FAILED;
	
	/* zero the memory to insure complete initialization */
	EAS_HWMemSet((void *)pXMFData,0, sizeof(S_XMF_DATA));
	
	pXMFData->fileHandle = fileHandle;
	pXMFData->fileOffset = offset;
	*ppHandle = pXMFData;

	/* locate the SMF and DLS contents */
	if ((result = XMF_FindFileContents(pEASData->hwInstData, pXMFData)) != EAS_SUCCESS)
	{
		{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "No SMF data found in XMF file\n"); */ }
		return result;
	}

	/* let the SMF parser take over */
	if ((result = EAS_HWFileSeek(pEASData->hwInstData, fileHandle, pXMFData->midiOffset)) != EAS_SUCCESS)
		return result;
	return SMF_CheckFileType(pEASData, fileHandle, &pXMFData->pSMFData, pXMFData->midiOffset);	
}

/*----------------------------------------------------------------------------
 * XMF_Prepare()
 *----------------------------------------------------------------------------
 * Purpose: 
 * Prepare to parse the file. Allocates instance data (or uses static allocation for
 * static memory model). 
 *
 * Inputs:
 * pEASData			- pointer to overall EAS data structure
 * handle			- pointer to file handle
 *		
 * Outputs:
 * 
 *
 * Side Effects:
 *
 *----------------------------------------------------------------------------
*/
static EAS_RESULT XMF_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
{
	S_XMF_DATA* pXMFData;
	EAS_RESULT result;

	/* parse DLS collection */
	pXMFData = (S_XMF_DATA*) pInstData;
	if (pXMFData->dlsOffset != 0)
	{
		if ((result = DLSParser(pEASData->hwInstData, pXMFData->fileHandle, pXMFData->dlsOffset, &pXMFData->pDLS)) != EAS_SUCCESS)
		{
			{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Error converting XMF DLS data\n"); */ }
			return result;
		}
	}

	/* Prepare the SMF parser */
	if ((result = SMF_Prepare(pEASData, pXMFData->pSMFData)) != EAS_SUCCESS)
		return result;

	/* if no DLS file, skip this step */
	if (pXMFData->pDLS == NULL)
		return EAS_SUCCESS;
	
	/* tell the synth to use the DLS collection */
	result = VMSetDLSLib(((S_SMF_DATA*) pXMFData->pSMFData)->pSynth, pXMFData->pDLS);
	if (result == EAS_SUCCESS)
	{
		DLSAddRef(pXMFData->pDLS);
		VMInitializeAllChannels(pEASData->pVoiceMgr, ((S_SMF_DATA*) pXMFData->pSMFData)->pSynth);
	}
	return result;
}

/*----------------------------------------------------------------------------
 * XMF_Time()
 *----------------------------------------------------------------------------
 * Purpose: 
 * Returns the time of the next event in msecs
 *
 * Inputs:
 * pEASData			- pointer to overall EAS data structure
 * handle			- pointer to file handle
 * pTime			- pointer to variable to hold time of next event (in msecs)
 *		
 * Outputs:
 * 
 *
 * Side Effects:
 *
 *----------------------------------------------------------------------------
*/
static EAS_RESULT XMF_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime)
{
	return SMF_Time(pEASData, ((S_XMF_DATA*) pInstData)->pSMFData, pTime);
}

/*----------------------------------------------------------------------------
 * XMF_Event()
 *----------------------------------------------------------------------------
 * Purpose: 
 * Parse the next event in the file
 *
 * Inputs:
 * pEASData			- pointer to overall EAS data structure
 * handle			- pointer to file handle
 *		
 * Outputs:
 * 
 *
 * Side Effects:
 *
 *----------------------------------------------------------------------------
*/
static EAS_RESULT XMF_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode)
{
	return SMF_Event(pEASData, ((S_XMF_DATA*) pInstData)->pSMFData, parserMode);
}

/*----------------------------------------------------------------------------
 * XMF_State()
 *----------------------------------------------------------------------------
 * Purpose: 
 * Returns the current state of the stream
 *
 * Inputs:
 * pEASData			- pointer to overall EAS data structure
 * handle			- pointer to file handle
 * pState			- pointer to variable to store state
 *		
 * Outputs:
 * 
 *
 * Side Effects:
 *
 *----------------------------------------------------------------------------
*/
static EAS_RESULT XMF_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 *pState)
{
	return SMF_State(pEASData, ((S_XMF_DATA*) pInstData)->pSMFData, pState);
}

/*----------------------------------------------------------------------------
 * XMF_Close()
 *----------------------------------------------------------------------------
 * Purpose: 
 * Close the file and clean up
 *
 * Inputs:
 * pEASData			- pointer to overall EAS data structure
 * handle			- pointer to file handle
 *		
 * Outputs:
 * 
 *
 * Side Effects:
 *
 *----------------------------------------------------------------------------
*/
static EAS_RESULT XMF_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
{
	S_XMF_DATA* pXMFData;
	EAS_RESULT result;

	pXMFData = (S_XMF_DATA *)pInstData;

	/* close the SMF stream, it will close the file handle */
	if ((result = SMF_Close(pEASData, pXMFData->pSMFData)) != EAS_SUCCESS)
		return result;

	if (pXMFData->pDLS)
		DLSCleanup(pEASData->hwInstData, pXMFData->pDLS);

	/* if using dynamic memory, free it */
	if (!pEASData->staticMemoryModel)
	{
		/* free the instance data */			
		EAS_HWFree(pEASData->hwInstData, pXMFData);
	}

	return EAS_SUCCESS;
}

/*----------------------------------------------------------------------------
 * XMF_Reset()
 *----------------------------------------------------------------------------
 * Purpose: 
 * Reset the sequencer. Used for locating backwards in the file.
 *
 * Inputs:
 * pEASData			- pointer to overall EAS data structure
 * handle			- pointer to file handle
 *		
 * Outputs:
 * 
 *
 * Side Effects:
 *
 *----------------------------------------------------------------------------
*/
static EAS_RESULT XMF_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
{
	return SMF_Reset(pEASData, ((S_XMF_DATA*) pInstData)->pSMFData);
}

/*----------------------------------------------------------------------------
 * XMF_Pause()
 *----------------------------------------------------------------------------
 * Purpose: 
 * Pauses the sequencer. Mutes all voices and sets state to pause.
 *
 * Inputs:
 * pEASData			- pointer to overall EAS data structure
 * handle			- pointer to file handle
 *		
 * Outputs:
 * 
 *
 * Side Effects:
 *
 *----------------------------------------------------------------------------
*/
static EAS_RESULT XMF_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
{
	return SMF_Pause(pEASData, ((S_XMF_DATA*) pInstData)->pSMFData);
}

/*----------------------------------------------------------------------------
 * XMF_Resume()
 *----------------------------------------------------------------------------
 * Purpose: 
 * Resume playing after a pause, sets state back to playing.
 *
 * Inputs:
 * pEASData			- pointer to overall EAS data structure
 * handle			- pointer to file handle
 *		
 * Outputs:
 * 
 *
 * Side Effects:
 *
 *----------------------------------------------------------------------------
*/
static EAS_RESULT XMF_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
{
	return SMF_Resume(pEASData, ((S_XMF_DATA*) pInstData)->pSMFData);
}

/*----------------------------------------------------------------------------
 * XMF_SetData()
 *----------------------------------------------------------------------------
 * Purpose: 
 * Sets the playback rate of the underlying SMF file
 *
 * Inputs:
 * pEASData			- pointer to overall EAS data structure
 * handle			- pointer to file handle
 * rate				- rate (28-bit fraction)
 *		
 * Outputs:
 * 
 *
 * Side Effects:
 *
 *----------------------------------------------------------------------------
*/
static EAS_RESULT XMF_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value)
{
	return SMF_SetData(pEASData, ((S_XMF_DATA*) pInstData)->pSMFData, param, value);
}

/*----------------------------------------------------------------------------
 * XMF_GetData()
 *----------------------------------------------------------------------------
 * Purpose: 
 * Gets the file type
 *
 * Inputs:
 * pEASData			- pointer to overall EAS data structure
 * handle			- pointer to file handle
 * rate				- rate (28-bit fraction)
 *		
 * Outputs:
 * 
 *
 * Side Effects:
 *
 *----------------------------------------------------------------------------
*/
static EAS_RESULT XMF_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue)
{
	EAS_RESULT result;

	/* call SMF parser to get value */
	if ((result = SMF_GetData(pEASData, ((S_XMF_DATA*) pInstData)->pSMFData, param, pValue)) != EAS_SUCCESS)
		return result;

	/* special case for file type */
	if (param == PARSER_DATA_FILE_TYPE)
	{
		if (*pValue == EAS_FILE_SMF0)
			*pValue = EAS_FILE_XMF0;
		else if (*pValue == EAS_FILE_SMF1)
			*pValue = EAS_FILE_XMF1;
	}

	return EAS_SUCCESS;
}

/*----------------------------------------------------------------------------
 * XMF_FindFileContents()
 *----------------------------------------------------------------------------
 * Purpose: 
 * Finds SMF data and DLS data in XMF file, and remembers offset for each.
 * If more than one is found, uses the first one found of each.
 * Makes assumptions about the format of a mobile XMF file
 *
 * Inputs:
 * pEASData			- pointer to overall EAS data structure
 * pXMFData			- pointer to XMF parser instance data
 * handle			- pointer to file handle
 *		
 * Outputs:
 * 
 *
 * Side Effects:
 *
 *----------------------------------------------------------------------------
*/
static EAS_RESULT XMF_FindFileContents (EAS_HW_DATA_HANDLE hwInstData, S_XMF_DATA *pXMFData)
{
	EAS_RESULT result;
	EAS_I32 value;
	EAS_I32 length;

	/* initialize offsets */
	pXMFData->dlsOffset = pXMFData->midiOffset = 0;

	/* read file length, ignore it for now */
	if ((result = XMF_ReadVLQ(hwInstData, pXMFData->fileHandle, &value)) != EAS_SUCCESS)
		return result;

	/* read MetaDataTypesTable length and skip over it */
	if ((result = XMF_ReadVLQ(hwInstData, pXMFData->fileHandle, &value)) != EAS_SUCCESS)
		return result;
	if ((result = EAS_HWFileSeekOfs(hwInstData, pXMFData->fileHandle, value)) != EAS_SUCCESS)
		return result;

	/* get TreeStart offset and jump to it */
	if ((result = XMF_ReadVLQ(hwInstData, pXMFData->fileHandle, &value)) != EAS_SUCCESS)
		return result;
	if ((result = XMF_ReadNode(hwInstData, pXMFData, value, &length)) != EAS_SUCCESS)
		return result;

	/* check for SMF data */
	if (pXMFData->midiOffset == 0)
	{
		{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "No SMF data found in XMF file\n"); */ }
		return EAS_ERROR_FILE_FORMAT;
	}

	/* check for SFM in wrong order */
	if ((pXMFData->dlsOffset > 0) && (pXMFData->midiOffset < pXMFData->dlsOffset))
		{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "DLS data must precede SMF data in Mobile XMF file\n"); */ }

	return EAS_SUCCESS;
}

/*----------------------------------------------------------------------------
 * XMF_ReadNode()
 *----------------------------------------------------------------------------
 * Purpose: 
 *
 * Inputs:
 *		
 * Outputs:
 * 
 *
 * Side Effects:
 *
 *----------------------------------------------------------------------------
*/
static EAS_RESULT XMF_ReadNode (EAS_HW_DATA_HANDLE hwInstData, S_XMF_DATA *pXMFData, EAS_I32 nodeOffset, EAS_I32 *pLength)
{
	EAS_RESULT result;
	EAS_I32 refType;
	EAS_I32 numItems;
	EAS_I32 offset;
	EAS_I32 length;
	EAS_I32 headerLength;
	EAS_U32 chunkType;

	/* seek to start of node */
	if ((result = EAS_HWFileSeek(hwInstData, pXMFData->fileHandle, nodeOffset)) != EAS_SUCCESS)
		return result;
	
	/* get node length */
	if ((result = XMF_ReadVLQ(hwInstData, pXMFData->fileHandle, pLength)) != EAS_SUCCESS)
		return result;

	/* get number of contained items */
	if ((result = XMF_ReadVLQ(hwInstData, pXMFData->fileHandle, &numItems)) != EAS_SUCCESS)
		return result;

	/* get node header length */
	if ((result = XMF_ReadVLQ(hwInstData, pXMFData->fileHandle, &headerLength)) != EAS_SUCCESS)
		return result;

	/* get metadata length */
	if ((result = XMF_ReadVLQ(hwInstData, pXMFData->fileHandle, &length)) != EAS_SUCCESS)
		return result;

	/* get the current location */
	if ((result = EAS_HWFilePos(hwInstData, pXMFData->fileHandle, &offset)) != EAS_SUCCESS)
		return result;

	/* skip to node contents */
	if ((result = EAS_HWFileSeek(hwInstData, pXMFData->fileHandle, nodeOffset + headerLength)) != EAS_SUCCESS)
		return result;

	/* get reference type */
	if ((result = XMF_ReadVLQ(hwInstData, pXMFData->fileHandle, &refType)) != EAS_SUCCESS)
		return result;

	/* get the current location */
	if ((result = EAS_HWFilePos(hwInstData, pXMFData->fileHandle, &offset)) != EAS_SUCCESS)
		return result;

	/* process file node */
	if (numItems == 0)

	{
		/* if in-file resource, find out where it is and jump to it */
		if (refType == 2)
		{
			if ((result = XMF_ReadVLQ(hwInstData, pXMFData->fileHandle, &offset)) != EAS_SUCCESS)
				return result;
			offset += pXMFData->fileOffset;
			if ((result = EAS_HWFileSeek(hwInstData, pXMFData->fileHandle, offset)) != EAS_SUCCESS)
				return result;
		}

		/* or else it must be an inline resource */
		else if (refType != 1)
		{
			{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Unexpected reference type %d\n", refType); */ }
			return EAS_ERROR_FILE_FORMAT;
		}

		/* get the chunk type */
		if ((result = EAS_HWGetDWord(hwInstData, pXMFData->fileHandle, &chunkType, EAS_TRUE)) != EAS_SUCCESS)
			return result;

		/* found a RIFF chunk, check for DLS type */
		if (chunkType == XMF_RIFF_CHUNK)
		{
			/* skip length */
			if ((result = EAS_HWFileSeekOfs(hwInstData, pXMFData->fileHandle, sizeof(EAS_I32))) != EAS_SUCCESS)
				return result;

			/* get RIFF file type */
			if ((result = EAS_HWGetDWord(hwInstData, pXMFData->fileHandle, &chunkType, EAS_TRUE)) != EAS_SUCCESS)
				return result;
			if (chunkType == XMF_RIFF_DLS)
				pXMFData->dlsOffset = offset;
		}

		/* found an SMF chunk */
		else if (chunkType == XMF_SMF_CHUNK)
			pXMFData->midiOffset = offset;
	}

	/* folder node, process the items in the list */
	else
	{
		for ( ; numItems > 0; numItems--)
		{
			/* process this item */
			if ((result = XMF_ReadNode(hwInstData, pXMFData, offset, &length)) != EAS_SUCCESS)
				return result;

			/* seek to start of next item */
			offset += length;
			if ((result = EAS_HWFileSeek(hwInstData, pXMFData->fileHandle, offset)) != EAS_SUCCESS)
				return result;
		}
	}
	
	return EAS_SUCCESS;
}

#if 0
/*----------------------------------------------------------------------------
 * XMF_FindFileContents()
 *----------------------------------------------------------------------------
 * Purpose: 
 * Finds SMF data and DLS data in XMF file, and remembers offset for each.
 * If more than one is found, uses the first one found of each.
 * Makes assumptions about the format of a mobile XMF file
 *
 * Inputs:
 * pEASData			- pointer to overall EAS data structure
 * pXMFData			- pointer to XMF parser instance data
 * handle			- pointer to file handle
 *		
 * Outputs:
 * 
 *
 * Side Effects:
 *
 *----------------------------------------------------------------------------
*/
static EAS_RESULT XMF_FindFileContents(S_EAS_DATA *pEASData, S_XMF_DATA *pXMFData, EAS_FILE_HANDLE fileHandle)
{
	EAS_RESULT result;
	EAS_I32 offset;
	EAS_I32 value;
	EAS_I32 numItems;
	EAS_I32 length;
	EAS_CHAR id[4];
	EAS_I32 location;

	/* init dls offset, so that we know we haven't found a dls chunk yet */
	pXMFData->dlsOffset = 0;

	/* read file length, ignore it for now */
	if ((result = XMF_ReadVLQ(pEASData, fileHandle, &value)) != EAS_SUCCESS)
		return result;

	/* read MetaDataTypesTable length and skip over it */
	if ((result = XMF_ReadVLQ(pEASData, fileHandle, &value)) != EAS_SUCCESS)
		return result;
	if ((result = EAS_HWFileSeekOfs(pEASData, fileHandle, value)) != EAS_SUCCESS)
		return result;

	/* get TreeStart offset and jump to it */
	if ((result = XMF_ReadVLQ(pEASData, fileHandle, &offset)) != EAS_SUCCESS)
		return result;
	if ((result = EAS_HWFileSeek(pEASData->hwInstData, fileHandle, offset)) != EAS_SUCCESS)
		return result;
	
	/* read node length, ignore it for now */
	if ((result = XMF_ReadVLQ(pEASData, fileHandle, &value)) != EAS_SUCCESS)
		return result;

	/* read number of contained items */
	if ((result = XMF_ReadVLQ(pEASData, fileHandle, &numItems)) != EAS_SUCCESS)
		return result;

	/*read node header length */
	if ((result = XMF_ReadVLQ(pEASData, fileHandle, &value)) != EAS_SUCCESS)
		return result;

	/*go to the node offset */
	if ((result = EAS_HWFileSeek(pEASData->hwInstData, fileHandle, offset + value)) != EAS_SUCCESS)
		return result;

	/* read Reference Type */
	if ((result = XMF_ReadVLQ(pEASData, fileHandle, &value)) != EAS_SUCCESS)
		return result;

	/* make sure it is an in-line resource, for now */
	if (value != 1)
	{
		{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Problem parsing XMF file tree\n"); */ }
		return EAS_FAILURE;
	}

	/* parse through the list of items */
	while (numItems > 0)
	{
		/*get current offset */
		if ((result = EAS_HWFilePos(pEASData->hwInstData, fileHandle, &offset)) != EAS_SUCCESS)
			return result;

		/*read node length */
		if ((result = XMF_ReadVLQ(pEASData, fileHandle, &length)) != EAS_SUCCESS)
			return result;

		/* read number of items */
		if ((result = XMF_ReadVLQ(pEASData, fileHandle, &value)) != EAS_SUCCESS)
			return result;

		/* make sure not a folder */
		if (value != 0)
		{
			{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Problem parsing XMF file node\n"); */ }
			return EAS_FAILURE;
		}

		/* read offset to resource and jump to it */
		if ((result = XMF_ReadVLQ(pEASData, fileHandle, &value)) != EAS_SUCCESS)
			return result;
		if ((result = EAS_HWFileSeek(pEASData->hwInstData, fileHandle, offset + value)) != EAS_SUCCESS)
			return result;

		/* read Reference Type */
		if ((result = XMF_ReadVLQ(pEASData, fileHandle, &value)) != EAS_SUCCESS)
			return result;

		/* make sure it is an in-line resource */
		if (value != 1)
		{
			{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Problem parsing XMF file node\n"); */ }
			return EAS_FAILURE;
		}

		/* get current offset as a possible location for SMF file or DLS file */
		if ((result = EAS_HWFilePos(pEASData->hwInstData, fileHandle, &location)) != EAS_SUCCESS)
			return result;

		/* read four bytes */
		if ((result = EAS_HWReadFile(pEASData->hwInstData, fileHandle, id, sizeof(id), &value)) != EAS_SUCCESS)
			return result;

		/* check if DLS */
		if (pXMFData->dlsOffset == 0 && id[0] == 'R' && id[1] == 'I' && id[2] == 'F' && id[3] == 'F')
		{
			//remember offset
			pXMFData->dlsOffset = location;
		}
		
		/* else check if SMF */
		else if (id[0] == 'M' && id[1] == 'T' && id[2] == 'h' && id[3] == 'd')
		{
			//remember offset
			pXMFData->midiOffset = location;

			//we are done
			return EAS_SUCCESS;
		}

		//one less item
		numItems--;

		//if more data, go to the next item
		if (numItems >0)
		{
			if ((result = EAS_HWFileSeek(pEASData->hwInstData, fileHandle, offset + length)) != EAS_SUCCESS)
				return result;
		}
	}

	return EAS_FAILURE;

}
#endif

/*----------------------------------------------------------------------------
 * XMF_ReadVLQ()
 *----------------------------------------------------------------------------
 * Purpose:
 * Reads a VLQ encoded value from the file referenced by fileHandle
 *
 * Inputs:
 * pEASData			- pointer to overall EAS data structure
 * fileHandle		- pointer to file handle
 *		
 * Outputs:
 * value			- pointer to the value decoded from the VLQ data
 * 
 *
 * Side Effects:
 *
 *----------------------------------------------------------------------------
*/
static EAS_RESULT XMF_ReadVLQ (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE fileHandle, EAS_I32 *value)
{
	EAS_RESULT result;
	EAS_U8 c;

	*value = 0;

	if ((result = EAS_HWGetByte(hwInstData, fileHandle, &c)) != EAS_SUCCESS)
		return result;

	while (c > 0x7F)
	{
		/*lint -e{703} shift for performance */
		*value = (*value << 7) | (c & 0x7F);

		if ((result = EAS_HWGetByte(hwInstData, fileHandle, &c)) != EAS_SUCCESS)
			return result;
	}

	/*lint -e{703} shift for performance */
	*value = (*value << 7) | c;

	return EAS_SUCCESS;
}