/* ***** BEGIN LICENSE BLOCK *****
 * Source last modified: $Id: smlrendr.cpp,v 1.7.2.1 2004/07/09 01:58:02 hubbe Exp $
 * 
 * Portions Copyright (c) 1995-2004 RealNetworks, Inc. All Rights Reserved.
 * 
 * The contents of this file, and the files included with this file,
 * are subject to the current version of the RealNetworks Public
 * Source License (the "RPSL") available at
 * http://www.helixcommunity.org/content/rpsl unless you have licensed
 * the file under the current version of the RealNetworks Community
 * Source License (the "RCSL") available at
 * http://www.helixcommunity.org/content/rcsl, in which case the RCSL
 * will apply. You may also obtain the license terms directly from
 * RealNetworks.  You may not use this file except in compliance with
 * the RPSL or, if you have a valid RCSL with RealNetworks applicable
 * to this file, the RCSL.  Please see the applicable RPSL or RCSL for
 * the rights, obligations and limitations governing use of the
 * contents of the file.
 * 
 * Alternatively, the contents of this file may be used under the
 * terms of the GNU General Public License Version 2 or later (the
 * "GPL") in which case the provisions of the GPL are applicable
 * instead of those above. If you wish to allow use of your version of
 * this file only under the terms of the GPL, and not to allow others
 * to use your version of this file under the terms of either the RPSL
 * or RCSL, indicate your decision by deleting the provisions above
 * and replace them with the notice and other provisions required by
 * the GPL. If you do not delete the provisions above, a recipient may
 * use your version of this file under the terms of any one of the
 * RPSL, the RCSL or the GPL.
 * 
 * This file is part of the Helix DNA Technology. RealNetworks is the
 * developer of the Original Code and owns the copyrights in the
 * portions it created.
 * 
 * This file, and the files included with this file, is distributed
 * and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
 * KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
 * ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
 * ENJOYMENT OR NON-INFRINGEMENT.
 * 
 * Technology Compatibility Kit Test Suite(s) Location:
 *    http://www.helixcommunity.org/content/tck
 * 
 * Contributor(s):
 * 
 * ***** END LICENSE BLOCK ***** */

#if defined (_AIX)
#include <X11/Xlib.h>
#endif
// system
#include <time.h>
// include
#include "hxtypes.h"
#include "hxwintyp.h"
#include "smiltype.h"
#include "hxcom.h"
#include "hxcomm.h"
#include "ihxpckts.h"
#include "hxcore.h"
#include "hxrendr.h"
#include "hxplugn.h"
#include "hxwin.h"
#include "hxgroup.h"
#include "hxsite2.h"
#include "hxupgrd.h"
#include "hxmon.h"
#include "hxver.h"
#include "hxvport.h"
#include "hxclsnk.h"
#include "hxprefs.h"
#include "hxmmrkr.h" // smldoc.h   dependency
#include "hxinter.h" // smldoc.h   dependency
#include "hxsm2sm.h"
#include "hxerror.h"
// cont
#include "hxstring.h"
#include "chxpckts.h"
#include "smlpkt.h"
// misc
#include "hxurl.h"
#include "hxstrutl.h" /* for SafeS---() */
#include "smlelem.h"
#include "smlutil.h"
// smlrendr
#include "evnthook.h"
#include "siteuser.h"
#include "passivsw.h"
#include "layout.h"
#include "smldoc.h"
#include "smlerror.h"
#include "smlrmlog.h"
#include "smlrendr.h"
#include "smlrendr.ver"
// debug
#include "debugout.h"
#include "hxheap.h"
#ifdef _DEBUG
#undef HX_THIS_FILE		
static const char HX_THIS_FILE[] = __FILE__;
#endif

/* We should really define it in a common header file */
#if defined (_WINDOWS ) || defined (WIN32)
#define OS_SEPARATOR_CHAR	'\\'
#define OS_SEPARATOR_STRING	"\\"
#elif defined (_UNIX)
#define OS_SEPARATOR_CHAR	'/'
#define OS_SEPARATOR_STRING	"/"
#elif defined (_MACINTOSH)
#define OS_SEPARATOR_CHAR	':'
#define OS_SEPARATOR_STRING	":"
#endif // defined (_WINDOWS ) || defined (WIN32)


#ifdef _WINDOWS
extern HINSTANCE g_hInstance;
#endif

static const UINT32 INITIAL_GRANULARITY = 67; // XXXMEH - increased interval to help animation CPU

#define SMIL20_AND_UP_STREAM_MIME_TYPE "application/smil"

const char* const CSmilRenderer::zm_pName	      = "SMIL";
const char* const CSmilRenderer::zm_pDescription    = "RealNetworks RMA Driver Renderer Plugin";
const char* const CSmilRenderer::zm_pCopyright      = HXVER_COPYRIGHT;
const char* const CSmilRenderer::zm_pMoreInfoURL    = HXVER_MOREINFO;
const char* const CSmilRenderer::zm_pStreamMimeTypes[] =
{
#if defined(HANDLE_BETA1_SMIL_1_0_STREAM)
    "application/rma-driver",
#endif
#if defined(HANDLE_SMIL_1_0_STREAM)
    "application/vnd.rn-rmadriver",
#endif
#if defined(HANDLE_SMIL_2_0_LASTCALL_STREAM)
    SMIL20_AND_UP_STREAM_MIME_TYPE,
#endif
#if defined(HANDLE_SMIL_2_0_CANDIDATE_REC_STREAM)
    SMIL20_AND_UP_STREAM_MIME_TYPE,
#endif
#if defined(HANDLE_SMIL_2_0_STREAM)
    SMIL20_AND_UP_STREAM_MIME_TYPE,
#endif
    NULL
};
const char* const CSmilRenderer::zm_pRecognizedDefaultNamespaces[
	NUM_RECOGNIZED_DEFAULT_NAMESPACES+1] =
{
    // /This is the namespace in the <smil...> tag that declares that
    // this is a SMIL 1.0 document that we should handle *correctly* (per
    // spec); the SMIL file format plug-in would have sent any "old"
    // SMIL 1.0 document to the old SMIL 1.0 renderer via the old stream
    // mime type; this is the case for all files that do not contain
    // a default namespace (which is xmlns= as opposed to xmlns:):
    "http://www.w3.org/TR/REC-smil",
    // /This is the SMIL 2.0 Last Call namespace:
    "http://www.w3.org/TR/REC-smil/2000/SMIL20/LC/",
    // /This is the SMIL 2.0 Language Profile Candidate Rec namespace:
    "http://www.w3.org/2000/SMIL20/CR/Language",
    // /This is the SMIL 2.0 Language Profile Proposed Rec namespace
    // created June 2001:  (Fixes PR 55749):
    "http://www.w3.org/2001/SMIL20/PR/Language",
    // /This is the SMIL 2.0 Rec namespace (it became a W3C Rec on 8/7/2001):
#if defined(HANDLE_SMIL_2_0_STREAM)
    // /Adding "/Language" to this string fixes PR 62208:
    "http://www.w3.org/2001/SMIL20/Language",
#endif
    NULL
};



/************************************************************************
 *  Method:
 *    IHXPlugin::InitPlugin
 *  Purpose:
 *    Initializes the plugin for use. This interface must always be
 *    called before any other method is called. This is primarily needed 
 *    so that the plugin can have access to the context for creation of
 *    IHXBuffers and IMalloc.
 */
STDMETHODIMP CSmilRenderer::InitPlugin(IUnknown* /*IN*/ pContext)
{
    m_pContext = pContext;
    m_pContext->AddRef();

    m_pContext->QueryInterface(IID_IHXCommonClassFactory,
	    (void**)&m_pCommonClassFactory);
    HX_RELEASE(m_pErrorMessages);
    m_pContext->QueryInterface(IID_IHXErrorMessages,
                               (void**) &m_pErrorMessages);

    return HXR_OK;
}

/************************************************************************
 *  Method:
 *    IHXPlugin::GetPluginInfo
 *  Purpose:
 *    Returns the basic information about this plugin. Including:
 *
 *    bLoadMultiple	whether or not this plugin DLL can be loaded
 *			multiple times. All File Formats must set
 *			this value to TRUE.
 *    pDescription	which is used in about UIs (can be NULL)
 *    pCopyright	which is used in about UIs (can be NULL)
 *    pMoreInfoURL	which is used in about UIs (can be NULL)
 */
STDMETHODIMP CSmilRenderer::GetPluginInfo
(
    REF(BOOL)        /*OUT*/ bLoadMultiple,
    REF(const char*) /*OUT*/ pDescription,
    REF(const char*) /*OUT*/ pCopyright,
    REF(const char*) /*OUT*/ pMoreInfoURL,
    REF(ULONG32)     /*OUT*/ ulVersionNumber
)
{
    bLoadMultiple = TRUE;   // Must be true for file formats.

    pDescription    = (const char*) zm_pDescription;
    pCopyright	    = (const char*) zm_pCopyright;
    pMoreInfoURL    = (const char*) zm_pMoreInfoURL;
    ulVersionNumber = TARVER_ULONG32_VERSION;

    return HXR_OK;
}

/************************************************************************
 *  Method:
 *    IHXPlugin::GetRendererInfo
 *  Purpose:
 *    If this object is a file format object this method returns
 *    information vital to the instantiation of file format plugins.
 *    If this object is not a file format object, it should return
 *    HXR_UNEXPECTED.
 */
STDMETHODIMP CSmilRenderer::GetRendererInfo
(
    REF(const char**) /*OUT*/ pStreamMimeTypes,
    REF(UINT32)      /*OUT*/ unInitialGranularity
)
{
    pStreamMimeTypes = (const char**) zm_pStreamMimeTypes;
    unInitialGranularity = m_ulGranularity;

    return HXR_OK;
}

CSmilRenderer::CSmilRenderer()
	: m_lRefCount(0)
	, m_pContext(NULL)
	, m_pStream(NULL)
	, m_pPlayer(NULL)
	, m_pHeader(NULL)
	, m_ulLastTime(0)
	, m_pCommonClassFactory(0)
	, m_pPacketParser(0)
	, m_pSmilDocRenderer(0)
	, m_pEngine(0)
        , m_pErrorMessages(NULL)
	, m_pClientContext(0)
	, m_uLayoutRule(0)
	, m_uSourceRule(0)
	, m_ulTotalSMILPackets(0)
	, m_ulGranularity(INITIAL_GRANULARITY)
	, m_pURLFragment(0)
	, m_lastOnPacketResult(HXR_OK)
	, m_bInMetadata(FALSE)
	, m_bUseNestedMeta(TRUE)
	, m_pPersistentComponentManager(NULL)    
	, m_ulPersistentVersion(0)
	, m_persistentType(PersistentSMIL)
	, m_bStreamProxiedByOtherRenderer(FALSE)
	, m_pVersionNamespaceFromProxyRenderer(NULL)
{
    m_ulPersistentVersion = HX_ENCODE_PROD_VERSION(2, 0, 0, 0);
};

CSmilRenderer::~CSmilRenderer()
{
    if(m_pSmilDocRenderer)
    {
	m_pSmilDocRenderer->close(this);
	HX_RELEASE(m_pSmilDocRenderer);
    }

    // /First, see if this player has children who need to be cleaned up:
    if (m_pPlayer)
    {
	IHXPlayerNavigator* pPlayerNavRoot = NULL;
	HX_RESULT pnrslt = m_pPlayer->QueryInterface(IID_IHXPlayerNavigator,
		(void**)&pPlayerNavRoot);
	if (HXR_OK == pnrslt)
	{
	    UINT16 uiNumChildren = pPlayerNavRoot->GetNumChildPlayer();

	    while (uiNumChildren > 0)
	    {
		IHXPlayer* pChildPlayer = NULL;
		// /GetChildPlayer addrefs pChildPlayer:
		pPlayerNavRoot->GetChildPlayer(uiNumChildren-1,pChildPlayer);
		HX_ASSERT(NULL != pChildPlayer);
		if (pChildPlayer)
		{
		    IHXPlayerNavigator* pPlayerNavChild = NULL;

		    // /RemoveChildPlayer decrefs it:
		    pPlayerNavRoot->RemoveChildPlayer(pChildPlayer);
		    IHXPlayer* pParentPlayer = NULL;

		    pnrslt= pChildPlayer->QueryInterface(
			    IID_IHXPlayerNavigator,
			    (void**)&pPlayerNavChild);
		    if (HXR_OK == pnrslt)
		    {
			// /GetParentPlayer addrefs pParentPlayer...
			pPlayerNavChild->GetParentPlayer(pParentPlayer);
			if (pParentPlayer)
			{
			    // /RemoveParentPlayer decrefs it...
			    pPlayerNavChild->RemoveParentPlayer(
				    pParentPlayer);
			    // /And we need one more to kill our use of it:
			    HX_RELEASE(pParentPlayer);
			}
			// /Now, remove it from client engine's list:
			if (m_pEngine)
			{
			    pnrslt= m_pEngine->ClosePlayer(pChildPlayer);
			}
			// /And we need one more to kill our use of it:
			HX_RELEASE(pChildPlayer);
		    }
		    HX_RELEASE(pPlayerNavChild);
		}
		uiNumChildren--;
	    }
	    HX_RELEASE(pPlayerNavRoot);
	}
    }

    HX_RELEASE(m_pContext);
    HX_RELEASE(m_pClientContext);
    HX_RELEASE(m_pStream);
    HX_RELEASE(m_pEngine);
    HX_RELEASE(m_pErrorMessages);
    HX_RELEASE(m_pCommonClassFactory);
    HX_RELEASE(m_pPersistentComponentManager);

    HX_RELEASE(m_pVersionNamespaceFromProxyRenderer);

    HX_DELETE(m_pPacketParser);
    HX_RELEASE(m_pPlayer);
    HX_VECTOR_DELETE(m_pURLFragment);
}


// *** IUnknown methods ***

/////////////////////////////////////////////////////////////////////////
//  Method:
//	IUnknown::QueryInterface
//  Purpose:
//	Implement this to export the interfaces supported by your 
//	object.
//
STDMETHODIMP CSmilRenderer::QueryInterface(REFIID riid, void** ppvObj)
{
    if (IsEqualIID(riid, IID_IUnknown))
    {
	AddRef();
	*ppvObj = this;
	return HXR_OK;
    }
    else if (IsEqualIID(riid, IID_IHXPlugin))
    {
	AddRef();
	*ppvObj = (IHXPlugin*)this;
	return HXR_OK;
    }
    else if (IsEqualIID(riid, IID_IHXRenderer))
    {
	AddRef();
	*ppvObj = (IHXRenderer*)this;
	return HXR_OK;
    }
    else if (IsEqualIID(riid, IID_IHXSiteUser))
    {
	HX_ASSERT(0  &&  "Huh?!  CSmilRenderer doesn't implement IHXSiteUser");
	AddRef();
	*ppvObj = (IHXSiteUser*)this;
	return HXR_OK;
    }
/*
    else if (IsEqualIID(riid, IID_IHXValues))
    {
	AddRef();
	*ppvObj = (IHXValues*)this;
	return HXR_OK;
    }
*/
    else if (IsEqualIID(riid, IID_IHXStatistics))
    {
	AddRef();
	*ppvObj = (IHXStatistics*)this;
	return HXR_OK;
    }
    else if (IsEqualIID(riid, IID_IHXPersistentRenderer))
    {
	AddRef();
	*ppvObj = (IHXPersistentRenderer*)this;
	return HXR_OK;
    }
    else if (IsEqualIID(riid, IID_IHXSmilToSmilRendererCommunicator))
    {
	AddRef();
	*ppvObj = (IHXSmilToSmilRendererCommunicator*)this;
	return HXR_OK;
    }
    else if (m_pSmilDocRenderer &&
	     HXR_OK == m_pSmilDocRenderer->QueryInterface(riid, ppvObj))
    {
	return HXR_OK;
    }

    *ppvObj = NULL;
    return HXR_NOINTERFACE;
}

/////////////////////////////////////////////////////////////////////////
//  Method:
//	IUnknown::AddRef
//  Purpose:
//	Everyone usually implements this the same... feel free to use
//	this implementation.
//
STDMETHODIMP_(ULONG32) CSmilRenderer::AddRef()
{
    return InterlockedIncrement(&m_lRefCount);
}

/////////////////////////////////////////////////////////////////////////
//  Method:
//	IUnknown::Release
//  Purpose:
//	Everyone usually implements this the same... feel free to use
//	this implementation.
//
STDMETHODIMP_(ULONG32) CSmilRenderer::Release()
{
    if (InterlockedDecrement(&m_lRefCount) > 0)
    {
        return m_lRefCount;
    }

    delete this;
    return 0;
}

// *** IHXRenderer methods ***

/////////////////////////////////////////////////////////////////////////
//  Method:
//	IHXRenderer::StartStream
//  Purpose:
//	Called by client engine to inform the renderer of the stream it
//	will be rendering. The stream interface can provide access to
//	its source or player. This method also provides access to the 
//	primary client controller interface.
//
STDMETHODIMP CSmilRenderer::StartStream
(
    IHXStream*	    pStream,
    IHXPlayer*	    pPlayer
)
{
    MLOG_FLOW(m_pErrorMessages, "CSmilRenderer::StartStream(0x%08x,0x%08x) this=0x%08x\n",
              pStream, pPlayer, this);
    HX_RESULT rc = HXR_OK;

    // Save for later use!
    m_pStream  = pStream;
    m_pStream->AddRef();
    m_pPlayer  = pPlayer;
    m_pPlayer->AddRef();

    m_pPlayer->GetClientEngine(m_pEngine);
    m_pPlayer->GetClientContext(m_pClientContext);

    IHXBuffer* pBuffer = NULL;
    IHXRendererAdviseSink* pRendererAdviseSink = NULL;

    IUnknown* pUnknown = NULL;
    m_pPlayer->QueryInterface(IID_IUnknown, (void**) &pUnknown);
    if (pUnknown)
    {
        ::getBooleanPreference(pUnknown, "useNestedMeta", m_bUseNestedMeta);
    }
    HX_RELEASE(pUnknown);

    m_pSmilDocRenderer = new CSmilDocumentRenderer(this, m_pContext);
    m_pSmilDocRenderer->AddRef();

    if (m_bUseNestedMeta  &&
	    // /For handling case where SMIL 1.0 renderer is passing this higher-
	    // than-1.0-version stream  to this renderer, we don't want to do what
	    // the SMIL 1.0 renderer has already set up with the core:
	    !m_bStreamProxiedByOtherRenderer)
    {

	IHXPersistentComponent* pPersistentComponent = NULL;

	if(HXR_OK == m_pPlayer->QueryInterface(IID_IHXPersistentComponentManager, 
					       (void**)&m_pPersistentComponentManager))
	{
	    m_pPersistentComponentManager->CreatePersistentComponent(pPersistentComponent);

	    pPersistentComponent->Init((IHXPersistentRenderer*)this);
	    pPersistentComponent->AddRendererAdviseSink((IHXRendererAdviseSink*)m_pSmilDocRenderer);
	    pPersistentComponent->AddGroupSink((IHXGroupSink*)m_pSmilDocRenderer);

	    rc = m_pPersistentComponentManager->AddPersistentComponent(pPersistentComponent);
	
	}
    }
    else if (!m_bStreamProxiedByOtherRenderer)
    {
	IHXPersistenceManager* pMgr = 0;

	if(HXR_OK == m_pPlayer->QueryInterface(IID_IHXPersistenceManager, 
	    (void**)&pMgr))
	{
	    IUnknown* pUnk = 0;
	    if(HXR_OK == pMgr->GetPersistentComponent(pUnk))
	    {
		rc = HXR_FAIL;
		CSmilSMILSyntaxErrorHandler errHandler(m_pContext);
		errHandler.ReportError(SMILErrorMetaDatatype, NULL, 0);
		pUnk->Release();
	    }
	    else if(HXR_OK == QueryInterface(IID_IUnknown, (void**)&pUnk))
	    {
		pMgr->AddPersistentComponent(pUnk);
		pUnk->Release();
	    }
	    pMgr->Release();
	}

	IHXDriverStreamManager* pDriverStreamMgr = 0;
	if(HXR_OK == m_pPlayer->QueryInterface(IID_IHXDriverStreamManager,
	    (void**)&pDriverStreamMgr))
	{
	    if(!m_bStreamProxiedByOtherRenderer  &&
		    HXR_OK == m_pSmilDocRenderer->QueryInterface(IID_IHXRendererAdviseSink, 
							    (void**)&pRendererAdviseSink))
	    {
		pDriverStreamMgr->AddRendererAdviseSink(pRendererAdviseSink);
		pRendererAdviseSink->Release();
	    }
	    pDriverStreamMgr->Release();
	}

	IHXGroupManager* pGrpMgr = 0;
	if(HXR_OK == m_pPlayer->QueryInterface(IID_IHXGroupManager,
	    (void**)&pGrpMgr))
	{
	    IHXGroupSink* pSnk = 0;
	    if(!m_bStreamProxiedByOtherRenderer  &&
		    HXR_OK == m_pSmilDocRenderer->QueryInterface(
		    IID_IHXGroupSink, (void**)&pSnk))
	    {
		pGrpMgr->AddSink(pSnk);
		pSnk->Release();
	    }
	}
	HX_RELEASE(pGrpMgr);
    }

    generatePreFix();

    return rc;
}

/////////////////////////////////////////////////////////////////////////
//  Method:
//	IHXRenderer::EndStream
//  Purpose:
//	Called by client engine to inform the renderer that the stream
//	is was rendering is closed.
//
STDMETHODIMP CSmilRenderer::EndStream()
{
    MLOG_FLOW(m_pErrorMessages,
              "CSmilRenderer::EndStream() this=0x%08x\n", this);
    if(m_pSmilDocRenderer)
    {
	m_pSmilDocRenderer->endStream();
    }

    if(m_pPlayer)
    {
	if (m_bUseNestedMeta  &&  !m_bStreamProxiedByOtherRenderer)
	{
	    IHXPersistentComponent* pPersistentComponent = NULL;
	    IHXRendererAdviseSink* pRendererAdviseSink = 0;

	    if(m_pPersistentComponentManager && HXR_OK == m_pPersistentComponentManager->GetPersistentComponent( m_pSmilDocRenderer->m_ulPersistentComponentID,
                                                                                 pPersistentComponent))
	    {
		pPersistentComponent->RemoveRendererAdviseSink((IHXRendererAdviseSink*)m_pSmilDocRenderer);
		pPersistentComponent->RemoveGroupSink((IHXGroupSink*)m_pSmilDocRenderer);
	    }
	    HX_RELEASE(pPersistentComponent);	    
	}
	else if (!m_bStreamProxiedByOtherRenderer)
	{
	    IHXGroupManager* pGrpMgr = 0;
	    if(HXR_OK == m_pPlayer->QueryInterface(IID_IHXGroupManager, 
		(void**)&pGrpMgr))
	    {
		IHXGroupSink* pSnk = 0;
		if(m_pSmilDocRenderer &&
		    HXR_OK == m_pSmilDocRenderer->QueryInterface(IID_IHXGroupSink, 
		    (void**)&pSnk))
		{
		    pGrpMgr->RemoveSink(pSnk);
		    pSnk->Release();
		}
		pGrpMgr->Release();
	    }

	    IHXDriverStreamManager* pStrmMgr = 0;
	    if(HXR_OK == m_pPlayer->QueryInterface(IID_IHXDriverStreamManager,
		(void**)&pStrmMgr))
	    {
		IHXRendererAdviseSink* pSnk = 0;
		if(m_pSmilDocRenderer &&
		    HXR_OK == m_pSmilDocRenderer->QueryInterface(
		    IID_IHXRendererAdviseSink, (void**)&pSnk))
		{
		    pStrmMgr->RemoveRendererAdviseSink(pSnk);
		    pSnk->Release();
		}
		pStrmMgr->Release();
	    }
	}

	IHXClientAdviseSink* pSnk = NULL;
	if(!m_bStreamProxiedByOtherRenderer  &&
		m_pSmilDocRenderer  &&
		HXR_OK == m_pSmilDocRenderer->QueryInterface(
		IID_IHXClientAdviseSink, (void**)&pSnk))
	{
	    m_pPlayer->RemoveAdviseSink(pSnk);
	    HX_RELEASE(pSnk);
	}
    }

    HX_RELEASE(m_pStream);


    // /See if the player has child players who need to be stopped:
    if (m_pPlayer)
    {
	IHXPlayerNavigator* pPlayerNavRoot = NULL;
	HX_RESULT pnrslt = m_pPlayer->QueryInterface(IID_IHXPlayerNavigator,
		(void**)&pPlayerNavRoot);
	if (HXR_OK == pnrslt)
	{
	    UINT16 uiChild = pPlayerNavRoot->GetNumChildPlayer();

	    while (uiChild > 0)
	    {
		IHXPlayer* pChildPlayer = NULL;
		// /GetChildPlayer addrefs pChildPlayer:
		pPlayerNavRoot->GetChildPlayer(uiChild-1, pChildPlayer);
		HX_ASSERT(pChildPlayer);
		if (pChildPlayer)
		{
		    pChildPlayer->Stop();
		    HX_RELEASE(pChildPlayer);
		}
		uiChild--;
	    }
	    HX_RELEASE(pPlayerNavRoot);
	}
    }

    
    return HXR_OK;
}

/////////////////////////////////////////////////////////////////////////
//  Method:
//	IHXRenderer::OnHeader
//  Purpose:
//	Called by client engine when a header for this renderer is 
//	available. The header will arrive before any packets.
//
STDMETHODIMP CSmilRenderer::OnHeader(IHXValues* pHeader)
{
    MLOG_FLOW(m_pErrorMessages,
              "CSmilRenderer::OnHeader(0x%08x) this=0x%08x\n", pHeader, this);
    // check stream and content versions so an upgrade can
    // be called if necessary...

    BOOL bVersionOK = TRUE;

    UINT32 ulStreamVersion = 0;
    UINT32 ulContentVersion = 0;
    
    if (HXR_OK == pHeader->GetPropertyULONG32("StreamVersion", ulStreamVersion))
    {
	UINT32 ulMajorVersion = HX_GET_MAJOR_VERSION(ulStreamVersion);
	UINT32 ulMinorVersion = HX_GET_MINOR_VERSION(ulStreamVersion);

	if((ulMajorVersion > STREAM_MAJOR_VERSION) ||
	   (ulMinorVersion > STREAM_MINOR_VERSION &&
	    ulMajorVersion == STREAM_MAJOR_VERSION))
	{
	    bVersionOK = FALSE;
	}
    }

    if(bVersionOK &&
       HXR_OK == pHeader->GetPropertyULONG32("ContentVersion", ulContentVersion))
    {
	UINT32 ulMajorVersion = HX_GET_MAJOR_VERSION(ulContentVersion);
	UINT32 ulMinorVersion = HX_GET_MINOR_VERSION(ulContentVersion);

	if((ulMajorVersion > CONTENT_MAJOR_VERSION) ||
	   (ulMinorVersion > CONTENT_MINOR_VERSION &&
	    ulMajorVersion == CONTENT_MAJOR_VERSION))
	{
	    bVersionOK = FALSE;
	}
    }

    if(!bVersionOK)
    {
	IHXUpgradeCollection* pUpColl = NULL;
	if(m_pPlayer &&
	   (HXR_OK == m_pPlayer->QueryInterface(IID_IHXUpgradeCollection,
		(void**)&pUpColl)))
	{
	    CHXBuffer* pBuffer = new CHXBuffer;
	    pBuffer->AddRef();
	    pBuffer->Set((BYTE*)SMIL20_AND_UP_STREAM_MIME_TYPE, 
		strlen(SMIL20_AND_UP_STREAM_MIME_TYPE)+1);
	    pUpColl->Add(eUT_Required, pBuffer, 0, 0);
	    HX_RELEASE(pBuffer);
	    HX_RELEASE(pUpColl);
	}
	return HXR_FAIL;
    }

    m_pPacketParser = new CSmilPacketParser;

    m_pSmilDocRenderer->onHeader(pHeader);

    if (!m_pSmilDocRenderer->IsNestedMetaSupported())
    {
	return HXR_INVALID_METAFILE;
    }

    IHXClientAdviseSink* pSnk = 0;
    if(!m_bStreamProxiedByOtherRenderer  &&
	    HXR_OK == m_pSmilDocRenderer->QueryInterface(
	    IID_IHXClientAdviseSink, (void**)&pSnk))
    {
	m_pPlayer->AddAdviseSink(pSnk);
	HX_RELEASE(pSnk);
    }

    if (!m_bUseNestedMeta)
    {
	/* SMIL renderer currently removes previously added
	 * groups, if any. This is to solve the case where we have 
	 * SMIL file within a RAM file. We will do something more
	 * sensible later.
	 */
	IHXGroupManager* pGrpMgr = 0;
	if(HXR_OK == m_pPlayer->QueryInterface(IID_IHXGroupManager,
	    (void**)&pGrpMgr))
	{
	    while(pGrpMgr && pGrpMgr->GetGroupCount() > 0)
	    {
		pGrpMgr->RemoveGroup(0);
	    }
	}
	HX_RELEASE(pGrpMgr);
    }

    return HXR_OK;
}


/////////////////////////////////////////////////////////////////////////
//  Method:
//	IHXRenderer::OnPacket
//  Purpose:
//	Called by client engine when a packet for this renderer is 
//	due.
//
STDMETHODIMP CSmilRenderer::OnPacket(IHXPacket* pPacket, 
					 LONG32 lTimeOffset)
{
    MLOG_FLOW(m_pErrorMessages,
              "CSmilRenderer::OnPacket(0x%08x,%ld) this=0x%08x\n",
              pPacket, lTimeOffset, this);
    HX_RESULT rc = HXR_OK;

    HX_ASSERT(lTimeOffset <= 0);

    //Fix for PR 23352: if we already returned a fail value from
    // a prior OnPacket(), don't process this OnPacket():
    if (HXR_OK != m_lastOnPacketResult)
    {
	return m_lastOnPacketResult;
    }
    IHXBuffer* pBuffer = pPacket->GetBuffer();
    if(pBuffer)
    {
	// /If parse() runs into a missing-quote situation,
	// we should stop and display an error.  Note that
	// CSmilPacketParser::parse(..)  does not keep track of
	// line numbers; TODO: add line-number counting to it.
	CSmilPacketParser::SMILPacketParseResult pktPrsRslt
			= CSmilPacketParser::SMILUnknown;
	CSmilPacket* pSmilPacket = m_pPacketParser->parse(
	    pBuffer, pktPrsRslt);
	if (CSmilPacketParser::SMILMissingQuote
		== pktPrsRslt)
	{
	    CSmilSMILSyntaxErrorHandler errHandler(m_pContext);
	    errHandler.ReportError(SMILErrorBadAttribute,
		    "missing quote", 0);
	}
	else if(pSmilPacket)
	{
	    switch(pSmilPacket->m_type)
	    {
		case CSmilPacket::SMILDocument:
		{
		    rc = handleSMILDocumentPacket(
			(CSmilDocumentPacket*)pSmilPacket);
		    if (HXR_OK != rc)
		    {
			m_lastOnPacketResult = rc;
		    }
		}
		break;

		default:
		break;
	    }
	    delete pSmilPacket;
	}
	HX_RELEASE(pBuffer);
    }
    return rc;
}

/////////////////////////////////////////////////////////////////////////
//  Method:
//	IHXRenderer::OnTimeSync
//  Purpose:
//	Called by client engine to inform the renderer of the current
//	time relative to the streams synchronized time-line. The 
//	renderer should use this time value to update its display or
//	render it's stream data accordingly.
//
STDMETHODIMP CSmilRenderer::OnTimeSync(ULONG32 ulTime)
{
    MLOG_FLOW(m_pErrorMessages,
              "CSmilRenderer::OnTimeSync(%lu) this=0x%08x\n", ulTime, this);
    HX_RESULT rc = HXR_OK;
    if(m_pSmilDocRenderer)
    {
	rc = m_pSmilDocRenderer->onTimeSync(ulTime);
    }
    if (rc != HXR_OUTOFMEMORY)
    {
        rc = HXR_OK;
    }
    return rc;
}

/////////////////////////////////////////////////////////////////////////
//  Method:
//	IHXRenderer::OnPreSeek
//  Purpose:
//	Called by client engine to inform the renderer that a seek is
//	about to occur. The render is informed the last time for the 
//	stream's time line before the seek, as well as the first new
//	time for the stream's time line after the seek will be completed.
//
STDMETHODIMP CSmilRenderer::OnPreSeek(ULONG32 ulOldTime, ULONG32 ulNewTime)
{
    MLOG_FLOW(m_pErrorMessages,
              "CSmilRenderer::OnPreSeek(%lu,%lu) this=0x%08x\n",
              ulOldTime, ulNewTime, this);
    HX_RESULT rc = HXR_OK;
    if(m_pSmilDocRenderer)
    {
	rc = m_pSmilDocRenderer->onPreSeek(ulOldTime, ulNewTime);
    }
    return rc;
}

/////////////////////////////////////////////////////////////////////////
//  Method:
//	IHXRenderer::OnPostSeek
//  Purpose:
//	Called by client engine to inform the renderer that a seek has
//	just occured. The render is informed the last time for the 
//	stream's time line before the seek, as well as the first new
//	time for the stream's time line after the seek.
//
STDMETHODIMP CSmilRenderer::OnPostSeek(ULONG32 ulOldTime,
					   ULONG32 ulNewTime)
{
    MLOG_FLOW(m_pErrorMessages,
              "CSmilRenderer::OnPostSeek(%lu,%lu) this=0x%08x\n",
              ulOldTime, ulNewTime, this);
    return HXR_OK;
}

/////////////////////////////////////////////////////////////////////////
//  Method:
//	IHXRenderer::OnPause
//  Purpose:
//	Called by client engine to inform the renderer that a pause has
//	just occured. The render is informed the last time for the 
//	stream's time line before the pause.
//
STDMETHODIMP CSmilRenderer::OnPause(ULONG32 ulTime)
{
    MLOG_FLOW(m_pErrorMessages,
              "CSmilRenderer::OnPause(%lu) this=0x%08x\n", ulTime, this);
    if( m_pSmilDocRenderer )
    {
        m_pSmilDocRenderer->unlockSiteComposition();
    }
    
    return HXR_OK;
}

/////////////////////////////////////////////////////////////////////////
//  Method:
//	IHXRenderer::OnBegin
//  Purpose:
//	Called by client engine to inform the renderer that a begin or
//	resume has just occured. The render is informed the first time 
//	for the stream's time line after the resume.
//
STDMETHODIMP CSmilRenderer::OnBegin(ULONG32 ulTime)
{
    MLOG_FLOW(m_pErrorMessages,
              "CSmilRenderer::OnBegin(%lu) this=0x%08x\n", ulTime, this);
    if( m_pSmilDocRenderer )
    {
        m_pSmilDocRenderer->lockSiteComposition();
    }

    return HXR_OK;
}

/////////////////////////////////////////////////////////////////////////
//  Method:
//	IHXRenderer::OnBuffering
//  Purpose:
//	Called by client engine to inform the renderer that buffering
//	of data is occuring. The render is informed of the reason for
//	the buffering (start-up of stream, seek has occured, network
//	congestion, etc.), as well as percentage complete of the 
//	buffering process.
//
STDMETHODIMP CSmilRenderer::OnBuffering(ULONG32 ulFlags,
	UINT16 unPercentComplete)
{
    MLOG_FLOW(m_pErrorMessages,
              "CSmilRenderer::OnBuffering(%lu,%u) this=0x%08x\n",
              ulFlags, unPercentComplete, this);
    return HXR_OK;
}

/////////////////////////////////////////////////////////////////////////
//  Method:
//	IHXRenderer::GetDisplayType
//  Purpose:
//	Called by client engine to ask the renderer for it's preferred
//	display type. When layout information is not present, the 
//	renderer will be asked for it's prefered display type. Depending
//	on the display type a buffer of additional information may be 
//	needed. This buffer could contain information about preferred
//	window size.
//
STDMETHODIMP CSmilRenderer::GetDisplayType
(
    REF(HX_DISPLAY_TYPE)   ulFlags,
    REF(IHXBuffer*)	    pBuffer
)
{
    ulFlags = HX_DISPLAY_NONE;

    return HXR_OK;
}

/************************************************************************
 *	Method:
 *	    IHXRenderer::OnEndofPackets
 *	Purpose:
 *	    Called by client engine to inform the renderer that all the
 *	    packets have been delivered. However, if the user seeks before
 *	    EndStream() is called, renderer may start getting packets again
 *	    and the client engine will eventually call this function again.
 */
STDMETHODIMP CSmilRenderer::OnEndofPackets(void)
{
    MLOG_FLOW(m_pErrorMessages,
              "CSmilRenderer::OnEndofPackets() this=0x%08x\n", this);
    return HXR_OK;
}

/************************************************************************
 *	Method:
 *	    IHXStatistics::Init
 *	Purpose:
 *	    Pass registry ID to the caller
 *
 */
STDMETHODIMP
CSmilRenderer::InitializeStatistics
(
    UINT32	/*IN*/ ulRegistryID
)
{
    IHXRegistry* pRegistry = NULL;
    if (m_pContext &&
	HXR_OK == m_pContext->QueryInterface(IID_IHXRegistry, (void**)&pRegistry))
    {
	char	    szRegistryEntry[MAX_DISPLAY_NAME] = {0}; /* Flawfinder: ignore */
	IHXBuffer*	    pszRegistryName = NULL;

	// Get the current registry key name
	if (HXR_OK == pRegistry->GetPropName(ulRegistryID, pszRegistryName))
	{
	    IHXBuffer* pValue = new CHXBuffer();
	    pValue->AddRef();

	    SafeSprintf(szRegistryEntry, MAX_DISPLAY_NAME, "%s.name", pszRegistryName->GetBuffer());

	    pValue->Set((const UCHAR*)zm_pName, strlen(zm_pName) + 1);
	    pRegistry->AddStr(szRegistryEntry, pValue);

	    HX_RELEASE(pValue);
	    HX_RELEASE(pszRegistryName);
	}

	HX_RELEASE(pRegistry);
    }

    return HXR_OK;
}

/************************************************************************
 *	Method:
 *	    IHXStatistics::Update
 *	Purpose:
 *	    Notify the client to update its statistics stored in the registry
 *
 */
STDMETHODIMP 
CSmilRenderer::UpdateStatistics()
{
    return HXR_OK;
}

// IHXPersistentRenderer methods
STDMETHODIMP
CSmilRenderer::InitPersistent(UINT32			ulPersistentComponentID,
			     UINT16			uPersistentGroupID,
			     UINT16			uPersistentTrackID,
			     IHXPersistentRenderer*	pPersistentParent)
{
    return m_pSmilDocRenderer->InitPersistent(ulPersistentComponentID,
					      uPersistentGroupID,
					      uPersistentTrackID,
					      pPersistentParent);
}

STDMETHODIMP
CSmilRenderer::GetPersistentID(REF(UINT32) ulPersistentComponentID)
{
    ulPersistentComponentID = m_pSmilDocRenderer->m_ulPersistentComponentID;

    return HXR_OK;
}

STDMETHODIMP
CSmilRenderer::GetPersistentProperties(REF(IHXValues*) pProperties)
{
    HX_RESULT	rc = HXR_OK;

    pProperties = new CHXHeader();
    pProperties->AddRef();

    pProperties->SetPropertyULONG32("PersistentType", m_persistentType);
    pProperties->SetPropertyULONG32("PersistentVersion", m_ulPersistentVersion);

    return rc;
}

STDMETHODIMP
CSmilRenderer::GetElementProperties(UINT16		uGroupID,
				    UINT16		uTrackID,
                               	    REF(IHXValues*)	pProperties)
{
    return m_pSmilDocRenderer->GetElementProperties(uGroupID,
						    uTrackID,
						    pProperties);
}

STDMETHODIMP
CSmilRenderer::AttachElementLayout(UINT16	    uGroupID,
				   UINT16	    uTrackID,
				   IHXRenderer*    pRenderer,
				   IHXStream*	    pStream,
				   IHXValues*	    pProps)
{
    return m_pSmilDocRenderer->AttachElementLayout(uGroupID,
						   uTrackID,
						   pRenderer,
						   pStream,
						   pProps);
}

STDMETHODIMP
CSmilRenderer::DetachElementLayout(IUnknown* pLSG)
{
    return m_pSmilDocRenderer->DetachElementLayout(pLSG);
}




/************************************************************************
 *	Method:
 *	    IHXSmilToSmilRendererCommunicator::InitSmilStreamProxiedByOtherRenderer
 *	Purpose:
 *	    Notify the client to update its statistics stored in the registry
 *
 */

// IHXSmilToSmilRendererCommunicator methods
STDMETHODIMP
CSmilRenderer::InitSmilStreamProxiedByOtherRenderer(IHXBuffer* pDefaultNamespace)
{
    HX_RESULT rc = HXR_FAIL;

    m_bStreamProxiedByOtherRenderer = TRUE;
    if (pDefaultNamespace  &&  pDefaultNamespace->GetSize() > 0)
    {
	HX_RELEASE(m_pVersionNamespaceFromProxyRenderer);
	m_pVersionNamespaceFromProxyRenderer = pDefaultNamespace;
	m_pVersionNamespaceFromProxyRenderer->AddRef();
	rc = HXR_OK;
    }
    return rc;
}






STDMETHODIMP
CSmilRenderer::GetElementStatus(UINT16		    uGroupID,
				UINT16		    uTrackID,
				UINT32		    ulCurrentTime,
				REF(IHXValues*)    pStatus)
{
    return m_pSmilDocRenderer->GetElementStatus(uGroupID,
						uTrackID,
						ulCurrentTime,
						pStatus);
}


HX_RESULT STDAPICALLTYPE CSmilRenderer::HXCreateInstance(IUnknown** ppIUnknown)
{
    HX_RESULT retVal = HXR_FAIL;

    if (ppIUnknown)
    {
        CSmilRenderer* pObj = new CSmilRenderer();
        if (pObj)
        {
            retVal = pObj->QueryInterface(IID_IUnknown, (void**) ppIUnknown);
            if (FAILED(retVal))
            {
                HX_DELETE(pObj);
            }
        }
    }

    return retVal;
}

HX_RESULT STDAPICALLTYPE CSmilRenderer::CanUnload2(void)
{
    return ((CHXBaseCountingObject::ObjectsActive() > 0) ? HXR_FAIL : HXR_OK);
}

HX_RESULT
CSmilRenderer::HandleAddLayoutSiteGroup(IUnknown* pLSG)
{
    HX_RESULT		    rc = HXR_OK;
    IHXValues*		    pProps = NULL;
    IHXPersistentRenderer* pPersistentParentRenderer = NULL;

    pPersistentParentRenderer = m_pSmilDocRenderer->m_pPersistentParentRenderer;

    // nested meta, get layout from its parent
    if (pPersistentParentRenderer)
    {
	pProps = new CHXHeader();	
	if (pProps)
	{
	    pProps->AddRef();
	    pProps->SetPropertyULONG32("PersistentType", m_persistentType);
	}

	rc = pPersistentParentRenderer->AttachElementLayout(m_pSmilDocRenderer->m_uPersistentGroupID,
							    m_pSmilDocRenderer->m_uPersistentTrackID,
							    (IHXRenderer*)pLSG,
							    NULL,
							    pProps);
    }
    else if (m_pPlayer)
    {
	IHXLayoutSiteGroupManager* pLSGMgr = 0;
	if(HXR_OK == m_pPlayer->QueryInterface(IID_IHXLayoutSiteGroupManager, (void**)&pLSGMgr))
	{
	    rc = pLSGMgr->AddLayoutSiteGroup(pLSG);
	    pLSGMgr->Release();
	}
    }

    HX_RELEASE(pProps);

    return rc;
}

HX_RESULT
CSmilRenderer::HandleRemoveLayoutSiteGroup(IUnknown* pLSG)
{
    HX_RESULT		    rc = HXR_OK;
    IHXPersistentRenderer* pPersistentParentRenderer = NULL;

    pPersistentParentRenderer = m_pSmilDocRenderer->m_pPersistentParentRenderer;

    // nested meta, remove layout from its parent
    if (pPersistentParentRenderer)
    {
	rc = pPersistentParentRenderer->DetachElementLayout(pLSG);
    }
    else if (m_pPlayer)
    {
	IHXLayoutSiteGroupManager* pLSGMgr = 0;
	if(HXR_OK == m_pPlayer->QueryInterface(IID_IHXLayoutSiteGroupManager, (void**)&pLSGMgr))
	{
	    rc = pLSGMgr->RemoveLayoutSiteGroup(pLSG);
	    pLSGMgr->Release();
	}
    }
    return rc;
}

HX_RESULT
CSmilRenderer::HandleAttachElementLayout(IUnknown* pLSG, IHXValues* pProps)
{
    HX_RESULT	rc = HXR_OK;

    if (m_pPersistentComponentManager)
    {
	rc = m_pPersistentComponentManager->AttachPersistentComponentLayout(pLSG, pProps);
    }

    return rc;
}

HX_RESULT
CSmilRenderer::handleSMILDocumentPacket(CSmilDocumentPacket* pPacket)
{
    HX_RESULT rc = HXR_OK;

    if(pPacket->m_version == RMA_DRIVER_VERSION)
    {
	CHXBuffer* pBuffer = new CHXBuffer;
	pBuffer->AddRef();
	BOOL bLastPacket = FALSE;
	UINT32 ulDocLen = (UINT32)pPacket->m_document.GetLength();
	HX_ASSERT(ulDocLen);
	// /Extra safety check:
	if (0 == ulDocLen)
	{
	    rc = HXR_UNEXPECTED;
	    bLastPacket = FALSE;
	}
	else
	{
	    pBuffer->Set((const BYTE*)(const char*)pPacket->m_document,
		    pPacket->m_document.GetLength());
	    m_ulTotalSMILPackets++;
	    bLastPacket = pPacket->m_ulTotalPackets == m_ulTotalSMILPackets;
	    rc = m_pSmilDocRenderer->onPacket(pBuffer, bLastPacket);

	    const char* pPktContents = (const char*)pPacket->m_document;
	    while (pPktContents)
	    {
		// /See if there is a <metadata> tag; if so, add it and all
		// the rest of the text up to </metadata> to m_metadata:
		// /XXXEH- TODO: make sure we're not inside a <!--comment-->!:
		// Note, however, that comments are being stripped by the
		// file format, so we need only do this if the ff changes
		// in this respect.
		char* pMetadataTag =
			(char*)strstr(pPktContents, "<metadata");
		char* pMetadataEndTag =
			(char*)strstr(pPktContents, "</metadata");
		char* pVeryEndOfTag = pMetadataEndTag != NULL ?
		    (char*)strchr(pMetadataEndTag, '>') : NULL;
		if (m_bInMetadata)
		{
		    m_bInMetadata = (NULL == pMetadataEndTag);
		    // /Concatinate all the stuff up to the end tag; if there's
		    // no end tag, then concatinate the whole packet:
		    if (NULL != pMetadataEndTag)
		    {
			if (strlen(pVeryEndOfTag) > 1)
			{
			    char savedChar = pVeryEndOfTag[1];
			    pVeryEndOfTag[1] = NULL;
			    m_pSmilDocRenderer->m_metadata += pPktContents;
			    pVeryEndOfTag[1] = savedChar;
			}
		    }
		    else
		    {
			m_pSmilDocRenderer->m_metadata += pPktContents;
		    }
		}
		if (pMetadataTag)
		{
		    HX_ASSERT(!m_bInMetadata);
		    // /In case there is another end tag (multiple metadata tags):
		    if (pMetadataTag > pMetadataEndTag  &&  NULL != pMetadataEndTag)
		    {
			pMetadataEndTag = pVeryEndOfTag != NULL?
				strstr(pVeryEndOfTag, "</metadata") : NULL;
			pVeryEndOfTag = pMetadataEndTag!=NULL?
				strchr(pMetadataEndTag, '>') : NULL;
		    }
		    // /Concatinate all the stuff up to the end tag; if there's
		    // no end tag, then concatinate the whole packet:
		    if (NULL != pMetadataEndTag)
		    {
			char* pVeryEndOfTag = strchr(pMetadataEndTag, '>');
			if (strlen(pVeryEndOfTag) > 1)
			{
			    char savedChar = pVeryEndOfTag[1];
			    pVeryEndOfTag[1] = NULL;
			    m_pSmilDocRenderer->m_metadata += pMetadataTag;
			    pVeryEndOfTag[1] = savedChar;
			}
		    }
		    else
		    {
			m_bInMetadata = TRUE;
			m_pSmilDocRenderer->m_metadata += pMetadataTag;
		    }
		}
		pPktContents = (const char*)pVeryEndOfTag;
	    }

	    // /See if the <smil ...> tag had a default namespace declared
	    // in it; if so, see if we recognize it.  If there is none or
	    // if we don't recognize it, try an auto upgrade:
	    BOOL bDefaultNamespaceRecognized = FALSE;
	    const char* pDefaultNamespace =
		    m_pSmilDocRenderer->getDefaultNamespace();
	    if (pDefaultNamespace  &&  strlen(pDefaultNamespace)>0)
	    {
		UINT32 ui=0;
		for (ui = 0; ui < NUM_RECOGNIZED_DEFAULT_NAMESPACES; ui++)
		{
		    if (0 == strcmp(
			    (const char*) zm_pRecognizedDefaultNamespaces[ui],
			    pDefaultNamespace) )
		    {
			bDefaultNamespaceRecognized = TRUE;
			break;
		    }
		}
	    }
	    else
	    {
#if defined(HANDLE_BETA1_SMIL_1_0_STREAM)  || defined(HANDLE_SMIL_1_0_STREAM)
		bDefaultNamespaceRecognized = TRUE;
#else
		// /No-default-namespace files go to the old renderer so we should
		// never encounter this condition:
		HX_ASSERT(m_pSmilDocRenderer->m_pSmilParser->m_pDefaultNamespace);
#endif
	    }
	    if (!bDefaultNamespaceRecognized)
	    {
		// /We need to auto upgrade if we don't recognize the default
		// namespace.  This can occur under the following conditions
		// (but can not occur if there is no default namespace because
		// those files will all go to the old SMIL 1.0 renderer); note
		// that each of these conditions is a good basis for an AU request
		// except that (3) would best serve our customers if they were
		// notified of the exact reason for the AU request before it
		// happened.
		// /XXXEH- talk to Consumer Group about AU request dialog boxes
		// showing more info.
		// (1) SMIL 3.0 or higher namespace is specified (or whatever
		//     version of SMIL was undefined at the time this renderer was
		//     compiled).
		// (2) Some proprietary namespace that might be handled by some
		//     non-RealNetworks plug-in (or by another RN SMIL renderer).
		// (3) if someone misspells the default namespace that this renderer
		//     otherwise would recognize.
		HX_ASSERT(1);
		IHXUpgradeCollection* pUpColl = NULL;

		if(m_pPlayer &&
		   (HXR_OK == m_pPlayer->QueryInterface(IID_IHXUpgradeCollection,
			(void**)&pUpColl)))
		{
		    CHXBuffer* pBuffer = new CHXBuffer;
		    pBuffer->AddRef();
		    pBuffer->SetSize(strlen(SMIL20_AND_UP_STREAM_MIME_TYPE) +
			    strlen(pDefaultNamespace) + 1 + 1);
		    char* pBuf = (char*)pBuffer->GetBuffer();
		    strcpy(pBuf, SMIL20_AND_UP_STREAM_MIME_TYPE); /* Flawfinder: ignore */
		    strcat(pBuf, "."); /* Flawfinder: ignore */
		    strcat(pBuf, pDefaultNamespace); /* Flawfinder: ignore */
		    pUpColl->Add(eUT_Required, pBuffer, 0, 0);
		    HX_RELEASE(pBuffer);
		    HX_RELEASE(pUpColl);
		}

		return HXR_FAIL;
	    }
	}
	HX_RELEASE(pBuffer);

	if(HXR_OK != rc)
	{
	    // XML parsing error
	    UINT32 ulLineNumber = 0;
	    UINT32 ulColumnNumber = 0;
	    IHXBuffer* pErrorText = NULL;
	    m_pSmilDocRenderer->getErrorInfo(ulLineNumber,
		ulColumnNumber, pErrorText);

	    const char* pActualErrorText = NULL;
	    if(pErrorText)
	    {
		pActualErrorText = (const char*)pErrorText->GetBuffer();
	    }
	    CSmilXMLSyntaxErrorHandler errHandler(m_pContext);
	    errHandler.ReportError(rc, pActualErrorText, ulLineNumber);
	    HX_RELEASE(pErrorText);
	}
	else if(bLastPacket)
	{
	    HX_ASSERT(!m_bInMetadata);
	    m_bInMetadata = FALSE;
	    //[SMIL 1.0 compliance] Handle error from setDocument()
	    // otherwise it "plays" (nothing for 20 seconds) when it
	    // should halt under error conditions:
	    rc = m_pSmilDocRenderer->setDocument(m_pURLFragment);
	}
    }
    return rc;
}

void
CSmilRenderer::generatePreFix()
{
    // get the protocol/server for later...
    IHXStreamSource* pSource = 0;
    m_pStream->GetSource(pSource);
    HX_ASSERT(pSource);
    if (!pSource)
    {
	return;
    }

    const char* pURL = pSource->GetURL();
    HX_ASSERT(pURL);
    
    if (!pURL)
    {
	return;
    }

    CHXURL::GeneratePrefixRootFragment(pURL, m_urlPrefix, m_urlRoot, m_pURLFragment);
    HX_RELEASE(pSource);

    return;
}

HX_RESULT
CSmilRenderer::SmilDocTrackDurationSet(UINT32 ulGroupIndex,
	UINT32 ulTrackIndex, UINT32 ulDuration, UINT32 ulDelay, BOOL bIsLive)
{
    HX_RESULT rc = HXR_FAIL;
    if (m_pSmilDocRenderer)
    {
	rc = m_pSmilDocRenderer->TrackDurationSet(ulGroupIndex, ulTrackIndex,
		ulDuration, ulDelay, bIsLive);
    }
    return rc;
}

HX_RESULT
CSmilRenderer::SmilDocRepeatedTrackDurationSet(const char* pID,
	UINT32 ulDuration, BOOL bIsLive)
{
    HX_RESULT rc = HXR_FAIL;
    if (m_pSmilDocRenderer)
    {
	rc = m_pSmilDocRenderer->RepeatedTrackDurationSet(pID, ulDuration,
		bIsLive);
    }
    return rc;
}

HX_RESULT
CSmilRenderer::SmilDocTrackUpdated(UINT32 ulGroupIndex, UINT32 ulTrackIndex,
	IHXValues* pValues)
{
    HX_RESULT rc = HXR_FAIL;
    if (m_pSmilDocRenderer)
    {
	rc = m_pSmilDocRenderer->TrackUpdated(ulGroupIndex, ulTrackIndex, pValues);
    }
    return rc;
}

HX_RESULT
CSmilRenderer::SmilDocRendererInitialized(IHXRenderer* pRend,
	IUnknown* pStream, IHXValues* pInfo)
{
    HX_RESULT rc = HXR_FAIL;
    if (m_pSmilDocRenderer)
    {
	rc = m_pSmilDocRenderer->RendererInitialized(pRend, pStream, pInfo);
    }
    return rc;
}

HX_RESULT
CSmilRenderer::SmilDocRendererClosed(IHXRenderer* pRend, IHXValues* pInfo)
{
    HX_RESULT rc = HXR_FAIL;
    if (m_pSmilDocRenderer)
    {
	rc = m_pSmilDocRenderer->RendererClosed(pRend, pInfo);
    }
    return rc;
}

HX_RESULT
CSmilRenderer::SmilDocGroupAdded(UINT16 uGroupIndex, IHXGroup* pGroup)
{
    HX_RESULT rc = HXR_FAIL;
    if (m_pSmilDocRenderer)
    {
	rc = m_pSmilDocRenderer->GroupAdded(uGroupIndex, pGroup);
    }
    return rc;
}

HX_RESULT
CSmilRenderer::SmilDocGroupRemoved(UINT16 uGroupIndex, IHXGroup* pGroup)
{
    HX_RESULT rc = HXR_FAIL;
    if (m_pSmilDocRenderer)
    {
	rc = m_pSmilDocRenderer->GroupRemoved(uGroupIndex, pGroup);
    }
    return rc;
}

HX_RESULT
CSmilRenderer::SmilDocAllGroupsRemoved()
{
    HX_RESULT rc = HXR_FAIL;
    if (m_pSmilDocRenderer)
    {
	rc = m_pSmilDocRenderer->AllGroupsRemoved();
    }
    return rc;
}

HX_RESULT
CSmilRenderer::SmilDocTrackAdded(UINT16 uGroupIndex, UINT16 uTrackIndex,
	IHXValues* pTrack)
{
    HX_RESULT rc = HXR_FAIL;
    if (m_pSmilDocRenderer)
    {
	rc = m_pSmilDocRenderer->TrackAdded(uGroupIndex, uTrackIndex, pTrack);
    }
    return rc;
}

HX_RESULT
CSmilRenderer::SmilDocTrackRemoved(UINT16 uGroupIndex, UINT16 uTrackIndex,
	IHXValues* pTrack)
{
    HX_RESULT rc = HXR_FAIL;
    if (m_pSmilDocRenderer)
    {
	rc = m_pSmilDocRenderer->TrackRemoved(uGroupIndex, uTrackIndex, pTrack);
    }
    return rc;
}

HX_RESULT
CSmilRenderer::SmilDocTrackStarted(UINT16 uGroupIndex, UINT16 uTrackIndex,
	    IHXValues* pTrack)
{
    HX_RESULT rc = HXR_FAIL;
    if (m_pSmilDocRenderer)
    {
	rc = m_pSmilDocRenderer->TrackStarted(uGroupIndex, uTrackIndex, pTrack);
    }
    return rc;
}

HX_RESULT
CSmilRenderer::SmilDocTrackStopped(UINT16 uGroupIndex, UINT16 uTrackIndex,
	IHXValues* pTrack)
{
    HX_RESULT rc = HXR_FAIL;
    if (m_pSmilDocRenderer)
    {
	rc = m_pSmilDocRenderer->TrackStopped(uGroupIndex, uTrackIndex, pTrack);
    }
    return rc;
}

HX_RESULT
CSmilRenderer::SmilDocCurrentGroupSet(UINT16 uGroupIndex, IHXGroup* pGroup)
{
    HX_RESULT rc = HXR_FAIL;
    if (m_pSmilDocRenderer)
    {
	rc = m_pSmilDocRenderer->CurrentGroupSet(uGroupIndex, pGroup);
    }
    return rc;
}


