Logo Search packages:      
Sourcecode: helix-player version File versions

smlparse.cpp

/* ***** BEGIN LICENSE BLOCK *****
 * Source last modified: $Id: smlparse.cpp,v 1.2.12.3 2005/01/26 20:09:29 ehyche 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 ***** */

#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>

#include "hxtypes.h"
#include "hxresult.h"
#include "hxcom.h"
#include "hxcomm.h"
#include "ihxpckts.h"
#include "hxfiles.h"
#include "hxformt.h"
#include "hxengin.h"
#include "hxplugn.h"
#include "hxpends.h"
#include "hxasm.h"
#include "hxprefs.h"
#include "hxupgrd.h"
#include "hxassert.h"
#include "chxpckts.h"
#include "upgrdcol.h"
#include "nptime.h"
#include "smpte.h"
#include "debug.h"
#include "hxstrutl.h"
#include "hxstring.h"
#include "cbqueue.h"
#include "hxslist.h"
#include "hxurl.h"
#include "hxmap.h"
#include "hxstack.h"
#include "hxwintyp.h"
#include "chxxtype.h"
#include "hxparse.h"

#include "hxxml.h"
#include "xmlreslt.h"

#include "looseprs.h"
#include "hxxmlprs.h" //HXXMLParser

#include "sm1elem.h"
#include "sm1time.h"
#include "sm1error.h"
#include "sm1parse.h"
#include "safestring.h"

#include "hxmon.h"

#include "debugout.h"
#include "hxheap.h"
#ifdef _DEBUG
#undef HX_THIS_FILE           
static const char HX_THIS_FILE[] = __FILE__;
#endif

static const UINT32 MAX_DRIVER_PACKET_SIZE = 1024;
static const UINT32 INITIAL_STREAM1_TIMESTAMP = 1;
static const UINT32 INITIAL_STREAM0_TIMESTAMP = 0;
static const UINT32 MAX_ERROR_LEN = 1024;

static const char* const RN_PREFIX = "rn";
static const char* const RN_TAG_RENDERER_LIST = "rn:renderer-list";
static const char* const RN_TAG_RENDERER = "rn:renderer";
static const char* const SYSTEM_COMPONENT_NAMESPACE = "http://features.real.com/systemComponent";
static const char* const SYSTEM_COMPONENT = "systemComponent";

static const struct smil1ColorTable
{
    char* m_pColorName;
    UINT8 m_ucRed;
    UINT8 m_ucGreen;
    UINT8 m_ucBlue;
} Smil1ColorTable[] =
{
    {"black",     0x00, 0x00, 0x00},
    {"silver",    0xc0, 0xc0, 0xc0},
    {"gray",      0x80, 0x80, 0x80},
    {"white",     0xff, 0xff, 0xff},
    {"maroon",    0x80, 0x00, 0x00},
    {"red",       0xff, 0x00, 0x00},
    {"purple",    0x80, 0x00, 0x80},
    {"fuchsia", 0xff, 0x00, 0xff},
    {"green",     0x00, 0x80, 0x00},
    {"lime",      0x00, 0xff, 0x00},
    {"olive",     0x80, 0x80, 0x00},
    {"yellow",    0xff, 0xff, 0x00},
    {"navy",      0x00, 0x00, 0x80},
    {"blue",      0x00, 0x00, 0xff},
    {"teal",      0x00, 0x80, 0x80},
    {"aqua",      0x00, 0xff, 0xff},
    {0,           0x00, 0x00, 0x00}
};

static const struct smil1TagTable
{
    SMIL1NodeTag m_tag;
    const char* m_name;
} smil1TagTable[] =
{
    {SMILSmil,              "smil"},
    {SMILMeta,              "meta"},
    {SMILHead,              "head"},
    {SMILBody,              "body"},
    {SMILBasicLayout,       "layout"},
    {SMILRootLayout,        "root-layout"},
    {SMILRegion,      "region"},
    {SMILSwitch,      "switch"},
    {SMILText,              "text"},
    {SMILImg,               "img"},
    {SMILRef,               "ref"},
    {SMILAudio,             "audio"},
    {SMILVideo,             "video"},
    {SMILAnimation,         "animation"},
    {SMILTextstream,        "textstream"},
    {SMILAnchor,      "anchor"},
    {SMILAAnchor,     "a"},
    {SMILPar,               "par"},
    {SMILSeq,               "seq"},
    {SMILRNRendererList,    RN_TAG_RENDERER_LIST},
    {SMILRendererPreFetch,  RN_TAG_RENDERER},
    {SMILUnknown,     "unknown"}
};


CSmil1Parser::CSmil1Parser(IUnknown* pContext):
    m_pContext(pContext),
    m_pClassFactory(NULL),
    m_pISystemRequired(NULL),
    m_pNodeList(0),
    m_pNodeListStack(0),
    m_pPacketQueue(0),
    m_pIDMap(0),
    m_pAddGroupMap(0),
    m_pSourceUpdateList(0),
    m_pRequireTagsMap(0),
    m_bNoNamespaces(FALSE),
    m_bRNNamespace(FALSE),
    m_bIgnoreUnrecognizedElements(TRUE),
    m_bSMILRootLayoutAlreadyFound(FALSE),
    m_bSMIL10FullCompliance(FALSE),
    m_pActiveNamespaceMap(NULL),
    m_pNSConflictList(NULL),
    m_bTimestampsResolved(FALSE),
    m_pCurNode(0),
    m_pNodeDependencies(0),
    m_pCurrentDependentNode(0),
    m_pAnchorStack(0),
    m_pCurrentAnchor(0),
    m_pEndLayout(0),
    m_ulBandwidthPreference(0),
    m_ulScreenHeightPreference(0),
    m_ulScreenWidthPreference(0),
    m_ulScreenDepthPreference(0),
    m_pLanguagePreferenceList(0),
    m_bCaptionsPreference(FALSE),
    m_pOverdubOrCaptionPreference(0),
    m_pBasePath(0),
    m_pTagAttributeMap(0),
    m_bContainsSource(FALSE),
    m_pEncoding(0),
    m_pTrackHintList(0),
    m_pParser(NULL),
    m_pResponse(NULL),
    m_ulErrorLineNumber(0),
    m_ulErrorColumnNumber(0),
    m_pErrorText(NULL)
    , m_bStoreErrors(FALSE)
    , m_pErrors(NULL)
    , m_ulPersistentComponentID(0)
    , m_elementWithinTag(WithinUnknown)
    , m_pVarName(NULL)
    , m_ulNextVar(0)
    , m_pTimelineElementManager(NULL)
{
    if(m_pContext)
    {
      m_pContext->AddRef();
      m_pContext->QueryInterface(IID_IHXCommonClassFactory, (void**)&m_pClassFactory);
    }

    initRequireTags();
    initTagAttributes();
    getPreferences();
    m_pVarName = new char [256];
    m_pTimelineElementManager = new CSmil1TimelineElementManager;
}

CSmil1Parser::~CSmil1Parser()
{
    deleteTagAttributes();
    HX_DELETE(m_pRequireTagsMap);

    if (m_pErrors)
    {
      int size = m_pErrors->GetSize();
      for (int i =0; i < size; ++i)
      {
          IHXBuffer* pBuf = (IHXBuffer*)(*m_pErrors)[i];
          HX_RELEASE(pBuf);
          (*m_pErrors)[i] = NULL;
      }
      HX_DELETE(m_pErrors);
    }
    
    if (m_pActiveNamespaceMap != NULL)
    {
      CHXMapStringToOb::Iterator ndxBuffer = m_pActiveNamespaceMap->Begin();
      for (; ndxBuffer != m_pActiveNamespaceMap->End(); ++ndxBuffer)
      {
          IHXBuffer* pBuffer = (IHXBuffer*)(*ndxBuffer);
          HX_RELEASE(pBuffer);
      }
      HX_DELETE(m_pActiveNamespaceMap);
    }

    if (m_pNSConflictList != NULL)
    {
      CHXSimpleList::Iterator ndx = m_pNSConflictList->Begin();
      for (; ndx != m_pNSConflictList->End(); ++ndx)
      {
          SMIL1Namespace* pNS = (SMIL1Namespace*)(*ndx);
          HX_DELETE(pNS);
      }
      HX_DELETE(m_pNSConflictList);
    }

    HX_DELETE(m_pNodeDependencies);
    HX_DELETE(m_pAnchorStack);
    HX_VECTOR_DELETE(m_pEncoding);
    if(m_pLanguagePreferenceList)
    {
      CHXSimpleList::Iterator i = m_pLanguagePreferenceList->Begin();
      for(; i != m_pLanguagePreferenceList->End(); ++i)
      {
          char* pLang = (char*)(*i);
          delete[] pLang;
      }
      HX_DELETE(m_pLanguagePreferenceList);
    }
    HX_DELETE(m_pOverdubOrCaptionPreference);
    HX_DELETE(m_pBasePath);

    close();

    HX_RELEASE(m_pClassFactory);
    HX_RELEASE(m_pContext);
    HX_VECTOR_DELETE(m_pVarName);
    HX_DELETE(m_pTimelineElementManager);
}

void
CSmil1Parser::initRequireTags()
{
    //XXXBAB - add required tags here
#if 0
    m_pRequireTagsMap = new CHXMapStringToOb;
    (*m_pRequireTagsMap)["foo-require"] = 0;
    (*m_pRequireTagsMap)["boo-require"] = 0;
#endif

}

void
CSmil1Parser::getPreferences()
{
    IHXPreferences*     pPrefs = 0;
    IHXRegistry*  pRegistry = NULL;

    m_pContext->QueryInterface(IID_IHXRegistry, (void**)&pRegistry);

    if(HXR_OK == m_pContext->QueryInterface(
      IID_IHXPreferences, (void**)&pPrefs))
    {
      IHXBuffer* pBuf = 0;
      CHXString strTemp;
      strTemp.Format("%s.%s",HXREGISTRY_PREFPROPNAME,"Language");

      if(pRegistry && HXR_OK == pRegistry->GetStrByName(strTemp, pBuf))
      {
          // language preference can be a comma-separated list

          const char* pLang = (const char*)pBuf->GetBuffer();
          // gonna call strtok, so copy the string...
          char* pLangCopy = new_string(pLang);
          m_pLanguagePreferenceList = new CHXSimpleList;
          char* pTok = strtok(pLangCopy, ",");
          while(pTok)
          {
            char* pLangString = new_string(pTok);
            m_pLanguagePreferenceList->AddTail(pLangString);
            pTok = strtok(NULL, ",");
          }
          delete[] pLangCopy;
          HX_RELEASE(pBuf);
      }
      if(HXR_OK == pPrefs->ReadPref("bandwidth", pBuf)  ||
            // /Fixes PR 84098 (SMIL 1.0 version) on Mac whose player
            // registry is case-sensitive and the registry value is
            // Bandwidth with a capital B:
            HXR_OK == pPrefs->ReadPref("Bandwidth", pBuf))
      {
          m_ulBandwidthPreference = 
            (UINT32)atol((const char*)pBuf->GetBuffer());
          HX_RELEASE(pBuf);
      }
      if(HXR_OK == pPrefs->ReadPref("screen_depth", pBuf))
      {
          m_ulScreenDepthPreference =
            (UINT32)atol((const char*)pBuf->GetBuffer());
          HX_RELEASE(pBuf);
      }
      if(HXR_OK == pPrefs->ReadPref("screen_height", pBuf))
      {
          m_ulScreenHeightPreference =
            (UINT32)atol((const char*)pBuf->GetBuffer());
          HX_RELEASE(pBuf);
      }
      if(HXR_OK == pPrefs->ReadPref("screen_width", pBuf))
      {
          m_ulScreenWidthPreference =
            (UINT32)atol((const char*)pBuf->GetBuffer());
          HX_RELEASE(pBuf);
      }
      if(HXR_OK == pPrefs->ReadPref("caption_switch", pBuf))
      {
          m_bCaptionsPreference = 
            (UINT32)atol((const char*)pBuf->GetBuffer());
          HX_RELEASE(pBuf);
      }
      if(HXR_OK == pPrefs->ReadPref("overdub_or_caption", pBuf))
      {
          const char* pStr = (const char*)pBuf->GetBuffer();
          m_pOverdubOrCaptionPreference = new_string(pStr);
          HX_RELEASE(pBuf);
      }

      HX_RELEASE(pPrefs);
    }

    HX_RELEASE(pRegistry);
}

void
CSmil1Parser::close()
{
    HX_DELETE(m_pPacketQueue);
    HX_DELETE(m_pEndLayout);
    HX_DELETE(m_pTrackHintList);
    HX_RELEASE(m_pResponse);
    HX_RELEASE(m_pErrorText);
    if (m_pParser)
    {
      m_pParser->Close();
      HX_RELEASE(m_pParser);
    }
    HX_RELEASE(m_pISystemRequired);

    if(m_pIDMap)
    {
      CHXMapStringToOb::Iterator i = m_pIDMap->Begin();
      for(; i != m_pIDMap->End(); ++i)
      {
          SMIL1Node* pNode = (SMIL1Node*)(*i);
          HX_DELETE(pNode->m_pElement);
      }
      HX_DELETE(m_pIDMap);
    }

    if(m_pAddGroupMap)
    {
      CHXMapLongToObj::Iterator i = m_pAddGroupMap->Begin();
      for(; i != m_pAddGroupMap->End(); ++i)
      {
          CSmil1AddGroup* pAddGroup = (CSmil1AddGroup*)(*i);
          delete pAddGroup;
      }
      HX_DELETE(m_pAddGroupMap);
    }

    if(m_pSourceUpdateList)
    {
      CHXSimpleList::Iterator i = m_pSourceUpdateList->Begin();
      for(; i != m_pSourceUpdateList->End(); ++i)
      {
          CSmil1SourceUpdate* pUpdate = (CSmil1SourceUpdate*)(*i);
          delete pUpdate;
      }
      HX_DELETE(m_pSourceUpdateList);
    }

    if (m_pActiveNamespaceMap)
    {
      CHXMapStringToOb::Iterator ndxBuffer = m_pActiveNamespaceMap->Begin();
      for (; ndxBuffer != m_pActiveNamespaceMap->End(); ++ndxBuffer)
      {
          IHXBuffer* pBuffer = (IHXBuffer*)(*ndxBuffer);
          HX_RELEASE(pBuffer);
      }
      HX_DELETE(m_pActiveNamespaceMap);
    }

    if (m_pNSConflictList != NULL)
    {
      CHXSimpleList::Iterator ndx = m_pNSConflictList->Begin();
      for (; ndx != m_pNSConflictList->End(); ++ndx)
      {
          SMIL1Namespace* pNS = (SMIL1Namespace*)(*ndx);
          HX_DELETE(pNS);
      }
      HX_DELETE(m_pNSConflictList);
    }

    delete m_pNodeListStack;
    if(m_pNodeList)
    {
      delete m_pNodeList->m_pParentNode;
    }
}

HX_RESULT
CSmil1Parser::init(BOOL bStoreErrors)
{
    HX_RESULT rc = HXR_OK;

    close();
    m_pNodeListStack = new CHXStack;
    m_pPacketQueue = new CHXSimpleList;
    m_pIDMap = new CHXMapStringToOb;
    m_pAddGroupMap = new CHXMapLongToObj;
    m_bStoreErrors = bStoreErrors;
    if (m_bStoreErrors)
    {
      // XXXJHUG  error stuff.
      // In the future if there was any reason, we could 
      // store the errors in the nodes that the errors occurred in.
      // for now when we get an error notification, we will
      // just call the storeError function which will add
      // a new IHXBuffer to this array..  This will also be
      // called when problems are found with tags...
      // this will save having to walk the tree when it 
      // is time to dump the errors.
      m_pErrors = new CHXPtrArray;
    }

    SMIL1Node* pRootNode = new SMIL1Node;
    pRootNode->m_id = "root";
    pRootNode->m_name = "root";
    m_pNodeList = new SMIL1NodeList;
    pRootNode->m_pNodeList = m_pNodeList;
    m_pNodeList->m_pParentNode = pRootNode;
    m_pNodeListStack->Push(pRootNode);

#ifdef USE_EXPAT_FOR_SMIL
    rc = m_pClassFactory->CreateInstance(CLSID_IHXXMLParser, (void**)&m_pParser);
    if (FAILED(rc))
    {
      // they don't have the parser...  use old one?
      // Don't QI core for IID_IHXXMLParser; use our own instance.
      m_pParser = new HXXMLParser;
      if (m_pParser)
      {
          rc = HXR_OK;
          m_pParser->AddRef();
      }
      else
      {
          rc = HXR_OUTOFMEMORY;
      }
    }
    HX_RELEASE(pFact);
    if (SUCCEEDED(rc))
    {
      m_pResponse = new CSmil1ParserResponse(this);
      m_pResponse->AddRef();
      // Expat is created off the CCF.
      // In strict mode it requires 100% compliant XML.   We will
      // create a "loose" version that allows &'s in attribute values.
      // (this parser is still MUCH stricter than the original XML parser)
      rc = m_pParser->Init(m_pResponse, "iso-8859-1", FALSE);     
    }

#else
    // Don't QI core for IID_IHXXMLParser; use our own instance.
    HXXMLParser* parser = new HXXMLParser();

    if (parser)
    {
      parser->AddRef();
    }
    else
    {
      rc = HXR_OUTOFMEMORY;
    }
    
    if (SUCCEEDED(rc))
    {
      m_pResponse = new CSmil1ParserResponse(this);
      m_pResponse->AddRef();
      rc = parser->Init(m_pResponse, NULL, TRUE);     // strict parser
    }
    if (m_bStoreErrors && parser)
    {
      parser->InitErrorNotifier(m_pResponse);
    }
    m_pParser = (IHXXMLParser*)parser;


#endif      
    
    return rc;
}

HX_RESULT
CSmil1Parser::parse(IHXBuffer* pBuffer, BOOL bIsFinal)
{
    HX_RESULT rc = HXR_OK;

    rc = m_pParser->Parse(pBuffer, bIsFinal);
    if(HXR_OK != rc)
    {
      m_pParser->GetCurrentLineNumber(m_ulErrorLineNumber);
      m_pParser->GetCurrentColumnNumber(m_ulErrorColumnNumber);
      HX_RELEASE(m_pErrorText);
      m_pParser->GetCurrentErrorText(m_pErrorText);
    }
    return rc;
}

HX_RESULT
CSmil1Parser::durationResolved(const char* pID, UINT32 ulDuration)
{
    SMIL1Node*    pNode = NULL;
    IHXBuffer* pBuf = NULL;

    if(m_pIDMap->Lookup(pID, (void*&)pNode))
    { 
      if (pNode->m_pElement->m_bIndefiniteDuration)
      {
          goto cleanup;
      }
      
      // add duration to parent element
      if(pNode &&
         pNode->m_pElement &&
         pNode->m_pElement->m_pTimelineElement)
      {
          pNode->m_pElement->m_pTimelineElement->setDuration(ulDuration);
      }
    }

cleanup:

    HX_RELEASE(pBuf);

    return HXR_OK;
}

BOOL AncestorEventsAreResolved(SMIL1Node* pNode)
{
    if (!pNode  ||  !pNode->m_pElement  ||
          !pNode->m_pElement->m_pTimelineElement  ||  pNode->m_tag == SMILBody)
    {
      return TRUE;
    }
    //Now, look to see if its duration and delay events, if any, are
    // resolved:
    if ( ( (pNode->m_pElement->m_pTimelineElement->durationEvent()  &&
      !pNode->m_pElement->m_pTimelineElement->durationSet())  ||
      (pNode->m_pElement->m_pTimelineElement->delayEvent()  &&
      !pNode->m_pElement->m_pTimelineElement->initialDelaySet()) )  &&
      //[SMIL 1.0 compliance] Helps fix PR 32578:
      //However, if we have a duration event and it's based on a child's
      // timing (as can happen via endsync="id(child)", then we want to
      // avoid this element waiting for its parent to be resolved while
      // the parent is waiting for this element to be resolved:
      (!pNode->m_pElement->m_pTimelineElement->durationEvent()  ||
      SMILEventSourceID != pNode->m_pElement->m_nEndsyncEventSourceTag) )
    {
      return FALSE; //We still need to await event resolution.
    }
    //pNode is ok but its dependency ancestors may still be unresolved and
    // thus pNode may still have timing constraints from its dependency
    // ancestors due to their unresolved event(s):
    return AncestorEventsAreResolved(pNode->m_pParent);
}

void
CSmil1Parser::insertTimelineElement(const char* pID, UINT32 ulDelay)
{
    SMIL1Node* pNode = 0;
    if(m_pIDMap->Lookup(pID, (void*&)pNode))
    {
      if(pNode &&
          pNode->m_pElement &&
          !pNode->m_pElement->m_bInsertedIntoTimeline  &&
          //[SMIL 1.0 compliance] Helps fix PR 16629:
          // We don't want to insert a node into the timeline if
          // its begin or end is dependent on another (not-yet-
          // resolved) element:
          ( (!pNode->m_pElement->m_pTimelineElement->durationEvent()  ||
          pNode->m_pElement->m_pTimelineElement->durationSet())  &&
          (!pNode->m_pElement->m_pTimelineElement->delayEvent()  ||
          pNode->m_pElement->m_pTimelineElement->initialDelaySet()) )
          //[SMIL 1.0 compliance] Helps fix 14420:
          // First, we need to look all the way up the tree of ancestors
          // to see if any of them have event-based delays or durations
          // and to make sure the appropriate time(s) are resolved.  If
          // not, we'll have to await those event resolutions before
          // inserting this element into the timeline:
          &&  AncestorEventsAreResolved(pNode)
          )
      {
          // /[SMIL 1.0 Compliance] Fixes PR 27644:
          // if our begin offset is same or greater than our parent's
          // end offset, then we should be ignored:
          if ( pNode->m_pParent  &&  pNode->m_pParent->m_pElement  &&
                pNode->m_pElement->m_ulBeginOffset != ((UINT32)-1)  &&
                pNode->m_pParent->m_pElement->m_ulEndOffset != 
                ((UINT32)-1)  &&
                (pNode->m_pElement->m_ulBeginOffset >
                pNode->m_pParent->m_pElement->m_ulEndOffset) )
          {
            return; //Don't insert this because it can't ever play.
          }

          // skip the element if its duration == 0
          if (0 == pNode->m_pElement->m_ulDuration)
          {
            durationResolved(pNode->m_id, 0);
          }
          else
          {
            pNode->m_pElement->m_ulDelay = ulDelay;
            pNode->m_pElement->m_ulTimestamp = INITIAL_STREAM1_TIMESTAMP;
            pNode->m_pElement->m_bInsertedIntoTimeline = TRUE;
            insertElementByTimestamp(pNode->m_pElement);
          }
      }
    }
}

void
CSmil1Parser::resetTimelineElementDuration(const char* pID, 
                                UINT32 ulDuration)
{
    SMIL1Node* pNode = NULL;
    if(m_pIDMap->Lookup(pID, (void*&)pNode))
    {
      CSmil1SourceUpdate* pUpdate = new CSmil1SourceUpdate;
      pUpdate->m_ulTimestamp = INITIAL_STREAM1_TIMESTAMP;
      pUpdate->m_srcID = pID;
      pUpdate->m_ulUpdatedDuration = ulDuration;

      if(!m_pSourceUpdateList)
      {
          m_pSourceUpdateList = new CHXSimpleList;
      }
      m_pSourceUpdateList->AddTail(pUpdate);
      insertElementByTimestamp(pUpdate);
    }
}

CSmil1Element*
CSmil1Parser::findElement(const char* pID)
{
    SMIL1Node* pNode = NULL;
    if(m_pIDMap->Lookup(pID, (void*&)pNode))
    {
      return pNode->m_pElement;
    }
    return NULL;
}

const char*
CSmil1Parser::assignID(const char* pPrefix)
{
    SafeSprintf(m_pVarName, 256, "%s_%ld", pPrefix, GetUniqueNumber());
    return m_pVarName;
}

UINT16
CSmil1Parser::getFragmentGroup(const char* pFragment)
{
    if(pFragment)
    {
      SMIL1Node* pNode = 0;
      if(m_pIDMap->Lookup(pFragment, (void*&)pNode))
      {
          if(!pNode->m_bDelete)
          {
            if(pNode->m_tag == SMILAAnchor ||
                pNode->m_tag == SMILSwitch)
            {
                SMIL1Node* pChildNode = getTimelineDescendent(pNode, NULL);
                while(pChildNode)
                {
                  if(!pChildNode->m_bDelete)
                  {
                      return pChildNode->m_nGroup;
                  }
                  pChildNode = getTimelineDescendent(pNode, pChildNode);
                }
            }
            else if(pNode->m_tag == SMILAnchor)
            {
                SMIL1Node* pParentNode = pNode->m_pParent;
                if(pParentNode &&
                  !pParentNode->m_bDelete)
                {
                  return pParentNode->m_nGroup;
                }
            }
            else
            {
                return pNode->m_nGroup;
            }
          }
      }
    }
    return 0;
}

UINT32
CSmil1Parser::getFragmentOffset(const char* pFragment,
      //This BOOL will be set to FALSE if the fragment
      // does not exist or does not yet have a resolved
      // begin time.  This was necessary to fix PR 22655:
      BOOL& bFragFoundAndResolved)
{
    bFragFoundAndResolved = FALSE;
    if(pFragment)
    {
      UINT32 ulAnchorBegin = 0;
      SMIL1Node* pNode = NULL;
      CSmil1Element* pElement = NULL;
      CSmil1Element* pActualElement = NULL;
      if(m_pIDMap->Lookup(pFragment, (void*&)pNode) &&
          pNode->m_pElement)
      {
          pElement = pNode->m_pElement;
          if(pNode->m_tag == SMILSwitch ||
            pNode->m_tag == SMILAAnchor)
          {
            SMIL1Node* pChildNode = getTimelineDescendent(
                pNode, NULL);
            while(pChildNode)
            {
                if(!pChildNode->m_bDelete)
                {
                  pActualElement = pChildNode->m_pElement;
                  break;
                }
                pChildNode = getTimelineDescendent(
                  pNode, pChildNode);
            }
          }
          else if(pNode->m_tag == SMILAnchor)
          {
            if(pElement->m_ulBeginOffset != (UINT32)-1)
            {
                ulAnchorBegin = pElement->m_ulBeginOffset;
            }
            SMIL1Node* pParent = pNode->m_pParent;
            if(pParent)
            {
                pActualElement = pParent->m_pElement;
            }
          }
          else
          {
            pActualElement = pElement;
          }

          if(pActualElement)
          {
            //[SMIL 1.0 Compliance] Fixes PR 26464:
            // Use delay (which already includes begin offset)
            // if it's a valid value, else use begin offset
            // without delay added (see comment below):
            if(pActualElement->m_ulDelay != (UINT32)-1)
            {
                bFragFoundAndResolved = TRUE;
                return pActualElement->m_ulDelay +
                  ulAnchorBegin;
            }
            else if(pActualElement->m_ulBeginOffset != (UINT32)-1)
            { 
                bFragFoundAndResolved = TRUE; 
                //Changed this while fixing PR 26464:
                // This used to return pActualElement->m_ulDelay +
                // pActualElement->m_ulBeginOffset + ulAnchorBegin but
                // the delay can already account for the begin if both
                // are set so we'd end up seeking past where we were
                // supposed to go by the amount of the begin offset. 
                // Also, we weren't even checking to see
                // if delay was valid before using it (and now we're
                // sure it is invalid per check above): 
                return pActualElement->m_ulBeginOffset +
                  ulAnchorBegin; 
            } 
            else
            {
                return 0;
            }
          }
      }
    }
    return 0;
}

SMIL1Node*
CSmil1Parser::findFirstNode(SMIL1NodeList* pNodeList, SMIL1NodeTag tag)
{
    if(!pNodeList)
    {
      return 0;
    }

    SMIL1Node* pFoundNode = 0;
    CHXSimpleList::Iterator i;
    for(i=pNodeList->Begin();i!=pNodeList->End();++i)
    {
      SMIL1Node* pNode = (SMIL1Node*)(*i);
      if(pNode->m_tag == tag)
      {
          pFoundNode = pNode;
      }
      else
      {
          pFoundNode = findFirstNode(pNode->m_pNodeList, tag);
      }
      if(pFoundNode)
      {
          break;
      }
    }
    return pFoundNode;
}

SMIL1Node*
CSmil1Parser::findFirstNode(SMIL1NodeTag tag)
{
    return findFirstNode(m_pNodeList, tag);
}

SMIL1Node*
CSmil1Parser::getFirstNodeChild(SMIL1Node* pNode)
{
    m_pCurNode = pNode;
    if(!m_pCurNode)
    {
      return 0;
    }
   return m_pCurNode->getFirstChild();
}

SMIL1Node*
CSmil1Parser::getNextNodeChild()
{
    if(!m_pCurNode)
    {
      return 0;
    }
    return m_pCurNode->getNextChild();
}

HX_RESULT
CSmil1Parser::parseClockValue(const char* pValue, UINT32& ulTimeValue)
{
    // try npt
    char* pPtr = (char *)strstr(pValue, "npt=");
    if(pPtr)
    {
      pPtr += 4;  // point to beginning of clock value
      //[SMIL 1.0 compliance] fixes PR 26445: if "npt=4h" is specified,
      // we need to convert to "14400s" otherwise the 4 is treated as
      // seconds:
      char* pHourChar = strchr(pPtr, 'h');
      if (pHourChar  &&  !strchr(pPtr, ':')) //then it's hours without ':'
      {
          IHXBuffer* pBuf = new CHXBuffer;
          if (pBuf)
          {
            pBuf->AddRef();

            *pHourChar = '\0'; //get rid of the 'h' in pPtr.
            pBuf->Set((const unsigned char *)pPtr,
                strlen(pPtr) + strlen(":00:00") + 1);
            char* pTmp = (char*)pBuf->GetBuffer();
            strcat(pTmp, ":00:00"); /* Flawfinder: ignore */
            NPTime clockTime((const char*)pTmp);
            ulTimeValue = (UINT32)clockTime;
            pBuf->Release();
          }
          else
          {
            return HXR_OUTOFMEMORY;
          }
      }
      //END fix for PR 26445.
      else
      {
          NPTime clockTime(pPtr);
          ulTimeValue = (UINT32)clockTime;
      }
      return HXR_OK;
    }
    // try smpte
    pPtr = (char *)strstr(pValue, "smpte=");
    if(pPtr)
    {
      pPtr += 6;  // point to beginning of clock value
      SMPTETimeCode clockTime(pPtr);
      ulTimeValue = (UINT32)clockTime;
      return HXR_OK;
    }
    pPtr = (char *)strstr(pValue, "smpte-30-drop=");
    if(pPtr)
    {
      pPtr += 14;  // point to beginning of clock value
      SMPTETimeCode clockTime(pPtr);
      ulTimeValue = (UINT32)clockTime;
      return HXR_OK;
    }
    pPtr = (char *)strstr(pValue, "smpte-25=");
    if(pPtr)
    {
      pPtr += 9;  // point to beginning of clock value
      SMPTETimeCode clockTime;
        clockTime.m_framesPerSec = SMPTETimeCode::FPS_25;
        clockTime.fromString(pPtr);
      ulTimeValue = (UINT32)clockTime;
      return HXR_OK;
    }
    else if(strchr(pValue, ':'))     // try just hh:mm:ss with no prefix/suffix
    {
      NPTime clockTime(pValue);
      ulTimeValue = (UINT32)clockTime;
      return HXR_OK;
    }

    // ok, try h/min/s/ms

    char* pEndPtr = 0;
    double dVal = strtod(pValue, &pEndPtr);
    if(strcmp(pEndPtr, "h") == 0)
    {
      ulTimeValue = (UINT32)(dVal * 60.0 * 60.0 * 1000.0);
      return HXR_OK;
    }
    else if(strcmp(pEndPtr, "min") == 0)
    {
      ulTimeValue = (UINT32)(dVal * 60.0 * 1000.0);
      return HXR_OK;
    }
    else if(strcmp(pEndPtr, "s") == 0  ||
          //[SMIL 1.0 compliance] Fixes PR 22673: the SMIL doc says that we
          // need to default to seconds if no unit-type is given:
          //     Timecount-val         ::= Timecount ("." Fraction)?
          //              ("h" | "min" | "s" | "ms")? ; default is "s"
          (!strlen(pEndPtr)) )
    {
      ulTimeValue = (UINT32)(dVal * 1000.0);
      return HXR_OK;
    }
    else if(strcmp(pEndPtr, "ms") == 0)
    {
      ulTimeValue = (UINT32)(dVal);
      return HXR_OK;
    }
    //else something other than "h", "min", "s", "", or "ms" was specified:
    else
    {
      return HXR_FAIL;
    }
}

HX_RESULT
CSmil1Parser::parseAnchorCoords(const char* pCoords, CSmil1AnchorElement* pAnchor)
{
    HX_RESULT rc = HXR_OK;
    double coordArray[4];
    BOOL percentArray[4];

    int i = 0;
    for(i=0; i<4; ++i)
    {
      coordArray[i] = 0.0;
      percentArray[i] = FALSE;
    }

    char* pCoordCopy = new_string(pCoords);
    char* pTok = strtok(pCoordCopy, ",");
    for(i=0;i<4,pTok;++i)
    {
      char* pEndPtr = 0;
      double dVal = strtod(pTok, &pEndPtr);
      coordArray[i] = dVal;
      percentArray[i] = (*pEndPtr == '%') ? TRUE: FALSE;

      pTok = strtok(NULL, ",");
    }
    delete[] pCoordCopy;

    pAnchor->m_ulOriginalLeftX = pAnchor->m_ulLeftX = 
      (UINT32)coordArray[0];
    pAnchor->m_bLeftXIsPercent = percentArray[0];
    pAnchor->m_ulOriginalTopY = pAnchor->m_ulTopY = 
      (UINT32)coordArray[1];
    pAnchor->m_bTopYIsPercent = percentArray[1];
    pAnchor->m_ulOriginalRightX = pAnchor->m_ulRightX = 
      (UINT32)coordArray[2];
    pAnchor->m_bRightXIsPercent = percentArray[2];
    pAnchor->m_ulOriginalBottomY = pAnchor->m_ulBottomY = 
      (UINT32)coordArray[3];
    pAnchor->m_bBottomYIsPercent = percentArray[3];
    
    pAnchor->m_bCoordsSet = TRUE;
    return rc;
}


HX_RESULT
CSmil1Parser::parseDuration(const char* pDuration, CSmil1Element* pElement,
    SMILSyncAttributeTag nTag)
{
    HX_RESULT rc = HXR_OK;

    if(!pDuration)
    {
      return HXR_FAIL;
    }

    const char* pCh = pDuration;

    // check for event-source
    // syntax is: id(a)(4s)
    if(strncmp(pCh, "id(", 3) == 0)
    {
      BOOL bParseError = FALSE;
      BOOL bHasEvent = TRUE;

      UINT32 clockValue = 0;
      char* pIdTag = new char[strlen(pDuration)+1];
      char* pEvent = new char[strlen(pDuration)+1];
      pIdTag[0] = 0;
      pEvent[0] = 0;

      pCh += 3;   // skip over 'id('

      int i = 0;
      while(*pCh && (*pCh != ')'))
      {
          pIdTag[i++] = *pCh++;
      }
      if(*pCh == ')')
      {
          pIdTag[i] = 0;

          // lookup ID to see if it references an existing entity,
          // otherwise it is an error
          void* pDummy = NULL;
          if(!m_pIDMap->Lookup(pIdTag, pDummy))
          {
            rc = HXR_FAIL;
            CSmil1SMILSyntaxErrorHandler errHandler(m_pContext);
            errHandler.ReportError(SMILErrorBadDuration, pDuration, 
                pElement->m_pNode->m_ulTagStartLine);
            bParseError = TRUE;
          }
          else
          {
            switch(nTag)
            {
                case SMILSyncAttrBegin:
                {
                  pElement->m_BeginEventSourceID = pIdTag;
                }
                break;

                case SMILSyncAttrEnd:
                {
                  pElement->m_EndEventSourceID = pIdTag;
                }
                break;

                case SMILSyncAttrEndsync:
                {
                  pElement->m_EndsyncEventSourceID = pIdTag;
                }
                break;

                default:
                break;
            }
          }

          delete[] pIdTag;

          if(strlen(pCh) > 2)
          {
            if(nTag != SMILSyncAttrEndsync)
            {
                pCh++;  // skip over ')'
                pCh++;  // skip over '('
                i = 0;
                while(*pCh && (*pCh != ')'))
                {
                  pEvent[i++] = *pCh++;
                }
                if(*pCh == ')')
                {
                  pEvent[i] = 0;
                }
                else
                {
                  bParseError = TRUE;
                }
            }
            else
            {
                bParseError = TRUE;
            }
          }
          else
          {
            if(nTag == SMILSyncAttrEndsync)
            {
                pElement->m_nEndsyncEventSourceTag = SMILEventSourceID;
                bHasEvent = FALSE;
            }
            else
            {
                bParseError = TRUE;
            }
          }
      }
      else
      {
          bParseError = TRUE;
      }
      if(bParseError)
      {
          rc = HXR_FAIL;
          CSmil1SMILSyntaxErrorHandler errHandler(m_pContext);
          errHandler.ReportError(SMILErrorBadDuration, pDuration, 
            pElement->m_pNode->m_ulTagStartLine);
      }
      else if(bHasEvent)
      {
          SMILEventSourceTag eSourceTag = SMILEventSourceNone;
          UINT32 ulEventClockValue = 0;
          if(strcmp(pEvent, "begin") == 0)
          {
            eSourceTag = SMILEventSourceBegin;
          }
          else if(strcmp(pEvent, "end") == 0)
          {
            eSourceTag = SMILEventSourceEnd;
          }
          else
          {
            if(HXR_OK == parseClockValue(pEvent, ulEventClockValue))
            {
                eSourceTag = SMILEventSourceClock;
            }
            else
            {
                rc = HXR_FAIL;
                CSmil1SMILSyntaxErrorHandler errHandler(m_pContext);
                errHandler.ReportError(SMILErrorBadDuration, pDuration, 
                  pElement->m_pNode->m_ulTagStartLine);
            }
          }

          switch(nTag)
          {
            case SMILSyncAttrBegin:
            {
                pElement->m_nBeginEventSourceTag = eSourceTag;
                pElement->m_ulBeginEventClockValue = ulEventClockValue;
            }
            break;

            case SMILSyncAttrEnd:
            {
                pElement->m_nEndEventSourceTag = eSourceTag;
                pElement->m_ulEndEventClockValue = ulEventClockValue;
            }
            break;

            case SMILSyncAttrEndsync:
            {
                pElement->m_nEndsyncEventSourceTag = eSourceTag;
            }
            break;

            default:
            break;
          }
      }
      delete[] pEvent;
    }
    else if(strcmp(pCh, "first") == 0)
    {
      if(nTag == SMILSyncAttrEndsync)
      {
          pElement->m_nEndsyncEventSourceTag = SMILEventSourceFirst;
      }
    }
    else if(strcmp(pCh, "last") == 0)
    {
      if(nTag == SMILSyncAttrEndsync)
      {
          pElement->m_nEndsyncEventSourceTag = SMILEventSourceLast;
      }
    }
    else if(strcmp(pCh, "indefinite") == 0)
    {
      if (pElement->m_pNode->m_tag == SMILSeq || 
          pElement->m_pNode->m_tag == SMILPar)
      {
          rc = HXR_FAIL;
          CSmil1SMILSyntaxErrorHandler errHandler(m_pContext);
          errHandler.ReportError(SMILErrorIndefiniteNotSupported, NULL, 
            pElement->m_pNode->m_ulTagStartLine);
      }
      else
      {
          pElement->m_bIndefiniteDuration = TRUE;
      }
    }
    else
    {
      UINT32 ulClockValue = 0;
      if(HXR_OK == parseClockValue(pCh, ulClockValue))
      {
          switch(nTag)
          {
            case SMILSyncAttrBegin:
            {
                pElement->m_ulBeginOffset = ulClockValue;
            }
            break;

            case SMILSyncAttrEnd:
            {
                pElement->m_ulEndOffset = ulClockValue;
            }
            break;

            case SMILSyncAttrDur:
            {
                pElement->m_ulDuration = ulClockValue;
            }
            break;

            case SMILSyncAttrEndsync:
            {
                pElement->m_ulEndSync = ulClockValue;
            }
            break;

            case SMILSyncAttrClipBegin:
            {
                pElement->m_ulClipBegin = ulClockValue;
            }
            break;

            case SMILSyncAttrClipEnd:
            {
                pElement->m_ulClipEnd = ulClockValue;
            }
            break;
                
            default:
            break;
          }
      }
      else
      {
          rc = HXR_FAIL;
          CSmil1SMILSyntaxErrorHandler errHandler(m_pContext);
          errHandler.ReportError(SMILErrorBadDuration, pCh, 
            pElement->m_pNode->m_ulTagStartLine);
      }
    }
    return rc;
}

HX_RESULT
CSmil1Parser::adjustDuration(CSmil1Element* pElement)
{
    HX_RESULT rc = HXR_OK;

    // check for duration errors
    if(pElement->m_ulEndOffset != (UINT32)-1)
    {
      if(pElement->m_ulBeginOffset != (UINT32)-1)
      {
          if(pElement->m_ulEndOffset < 
            pElement->m_ulBeginOffset)
          {
            pElement->m_ulDuration = 0;
            goto exit;
          }
          if(pElement->m_ulDuration != (UINT32)-1)
          {
            if(pElement->m_ulDuration !=
                pElement->m_ulEndOffset -
                pElement->m_ulBeginOffset)
            {
                // If the element has both an explicit dur and an explicit
                // end, the desired end is the minimum of: the sum of the 
                // desired begin and the explicit dur; and the explicit end. 
                
                // override "dur"
                if ( pElement->m_ulBeginOffset + pElement->m_ulDuration > 
                  pElement->m_ulEndOffset )
                {
                  // we want to override the duration, because it is 
                  // greater than the end offset.
                  pElement->m_ulDuration =
                      pElement->m_ulEndOffset -
                      pElement->m_ulBeginOffset;
                }
                else
                {
                  // else we want to use the current duration, 
                  // and override the end offset.
                  pElement->m_ulEndOffset = pElement->m_ulBeginOffset
                      + pElement->m_ulDuration;
                }
                  
                goto exit;
            }
          }
      }
      else
      {
          if(pElement->m_ulDuration != (UINT32)-1)
          {
            if(pElement->m_ulEndOffset >
                pElement->m_ulDuration)
            {
                pElement->m_ulDuration = pElement->m_ulEndOffset;
                goto exit;
            }
          }
      }
    }
   
    // adjust for begin/end/dur attributes
    if(pElement->m_ulDuration == (UINT32)-1) // duration not set
    {
      if(pElement->m_ulEndOffset != (UINT32)-1)
      {
          // has an end but no duration
          if(pElement->m_ulBeginOffset != (UINT32)-1)
          {
            pElement->m_ulDuration = pElement->m_ulEndOffset -
                              pElement->m_ulBeginOffset;
          }
          else
          {
            pElement->m_ulDuration = pElement->m_ulEndOffset;
          }
      }
    }
    else    // explicit duration set
    {
      if(pElement->m_ulEndOffset != (UINT32)-1)
      {
          // has a duration and an end
          UINT32 ulDur = 0;
          if(pElement->m_ulBeginOffset != (UINT32)-1)
          {
            ulDur = pElement->m_ulEndOffset - 
                     pElement->m_ulBeginOffset;
          }
          else
          {
            ulDur = pElement->m_ulEndOffset;
          }
          pElement->m_ulDuration = ulDur;
      }
    }

exit:
    return rc;
}

UINT8
CSmil1Parser::getColorElement(const char* pColorFrag, int len)
{
    UINT8 ucValue = 0;

    char* pTmpBuf = new char[len+1];
    strncpy(pTmpBuf, pColorFrag, len); /* Flawfinder: ignore */
    pTmpBuf[len] = 0;

    ucValue = (UINT8)strtol(pTmpBuf, 0, 16);
    delete[] pTmpBuf;
    return ucValue;
}
    
HXxColor
CSmil1Parser::parseColor(const char* pColorString)
{
    HXxColor theColor = 0;
    UINT8 ucRed = 0;
    UINT8 ucGreen = 0;
    UINT8 ucBlue = 0;
    if(pColorString[0] == '#')
    {
      if(strlen(pColorString) == 4)
      {
          /* #rgb, duplicate the numbers */
          char tmpBuf[6]; /* Flawfinder: ignore */
          tmpBuf[0] = tmpBuf[1] = pColorString[1];
          tmpBuf[2] = tmpBuf[3] = pColorString[2];
          tmpBuf[4] = tmpBuf[5] = pColorString[3];
          ucRed = getColorElement(&tmpBuf[0], 2);
          ucGreen = getColorElement(&tmpBuf[2], 2);
          ucBlue = getColorElement(&tmpBuf[4], 2);
      }
      else if(strlen(pColorString) == 7)
      {
          /* #rrggbb */
          ucRed = getColorElement(&pColorString[1], 2);
          ucGreen = getColorElement(&pColorString[3], 2);
          ucBlue = getColorElement(&pColorString[5], 2);
      }
    }
    else
    {
      // string, try to get it from the color table
      int i = 0;
      const char* pColorName = Smil1ColorTable[i].m_pColorName;
      while(pColorName)
      {
          if(strcmp(pColorName, pColorString) == 0)
          {
            ucRed = Smil1ColorTable[i].m_ucRed;
            ucBlue = Smil1ColorTable[i].m_ucBlue;
            ucGreen = Smil1ColorTable[i].m_ucGreen;
            break;
          }
          pColorName = Smil1ColorTable[++i].m_pColorName;
      }
    }

#ifdef _WINDOWS
    theColor = (HXxColor)(RGB(ucRed, ucGreen, ucBlue));
#else
    theColor = (HXxColor)
          (ucRed << 16 |
          ucGreen << 8 |
          ucBlue);
#endif
    return theColor;
}

void
CSmil1Parser::badAttributeError(SMIL1NodeTag tag, const char* pAttrName,
                         UINT32 ulLineNumber, BOOL bJustStore)
{
    const char* pTagName = "unknown";
    // get tag name from table
    int i = 0;
    SMIL1NodeTag thisTag = smil1TagTable[i].m_tag;
    while(thisTag != SMILUnknown)
    {
      if(thisTag == tag)
      {
          pTagName = smil1TagTable[i].m_name;
          break;
      }
      ++i;
      thisTag = smil1TagTable[i].m_tag;
    }
    
    char tmpBuf[256]; /* Flawfinder: ignore */
    SafeSprintf(tmpBuf, 256, "<%s>: %s",
      pTagName, pAttrName);

    if (m_bStoreErrors)
    {
      storeError(SMILErrorUnrecognizedAttribute, tmpBuf, 0, 
          ulLineNumber, 0, FALSE);
    }

    if (!bJustStore)
    {
      CSmil1SMILSyntaxErrorHandler errHandler(m_pContext);
      errHandler.ReportError(SMILErrorUnrecognizedAttribute, tmpBuf, ulLineNumber);
    }
}

CSmil1Meta*
CSmil1Parser::makeMeta(SMIL1Node* pNode)
{
    CSmil1Meta* pMeta = new CSmil1Meta(pNode);
    if(pNode->m_pValues)
    {
      const char* pName = 0;
      IHXBuffer* pBuf = 0;

      HX_RESULT rc = pNode->m_pValues->GetFirstPropertyCString(pName, pBuf);
      while(HXR_OK == rc)
      {
          if(strcmp(pName, "name") == 0)
          {
            pMeta->m_name = (const char*)pBuf->GetBuffer();
          }
          else if(strcmp(pName, "content") == 0)
          {
            pMeta->m_content = (const char*)pBuf->GetBuffer();
          }
          HX_RELEASE(pBuf);
          rc = pNode->m_pValues->GetNextPropertyCString(pName, pBuf);
      }
      HX_RELEASE(pBuf);

      // check for 'base'
      if(pMeta->m_name == "base")
      {
          HX_DELETE(m_pBasePath);
          m_pBasePath = new_string((const char*)pMeta->m_content);
          HX_RELEASE(pBuf);
      }
    }
    return pMeta;
}

CSmil1RendererPreFetch*
CSmil1Parser::makeRendererPreFetch(SMIL1Node* pNode)
{
    CSmil1RendererPreFetch* pRenderer = 
      new CSmil1RendererPreFetch(pNode);
    if(pNode->m_pValues)
    {
      const char* pName = 0;
      IHXBuffer* pBuf = 0;
      HX_RESULT rc = pNode->m_pValues->GetFirstPropertyCString(pName, pBuf);
      while(HXR_OK == rc)
      {
          if(strcmp(pName, "type") == 0)
          {
            pRenderer->m_mimeType = (const char*)pBuf->GetBuffer();
          }
          rc = pNode->m_pValues->GetNextPropertyCString(pName, pBuf);
      }
    }
    return pRenderer;
}

CSmil1RootLayout*
CSmil1Parser::makeRootLayout(SMIL1Node* pNode)
{
    BOOL bHasHeight = FALSE;
    BOOL bHasWidth = FALSE;

    //[SMIL 1.0 compliance] Fixes PR 22674.  SMIL 1.0 documentation states:
    //  "If a document contains more than one "root-layout" element,
    //   this is an error, and the document should not be displayed."
    if (m_bSMILRootLayoutAlreadyFound  &&  m_bSMIL10FullCompliance)
    {
      CSmil1SMILSyntaxErrorHandler errHandler(m_pContext);
      errHandler.ReportError(SMILErrorUnexpectedTag,
            (const char*)pNode->m_name, pNode->m_ulTagStartLine);
      return NULL;
    }
    else if (m_bStoreErrors && m_bSMILRootLayoutAlreadyFound)
    {
      storeError(SMILErrorUnexpectedTag, pNode->m_name, 0, 
            pNode->m_ulTagStartLine, 0, FALSE);
    }


    m_bSMILRootLayoutAlreadyFound = TRUE;

    CSmil1RootLayout* pLayout = new CSmil1RootLayout(pNode);
    if(pNode->m_pValues)
    {
      const char* pName = 0;
      IHXBuffer* pBuf = 0;
      HX_RESULT rc = pNode->m_pValues->GetFirstPropertyCString(pName, pBuf);
      while(HXR_OK == rc)
      {
          //[SMIL 1.0 compliance] Fixes PR 24628.  SMIL 1.0
          // documentation states in section 3.3.1 that only "length"
          // values are allowed in a root-layout height or width;
          // percentages are not allowed:
          // [SMIL 1.0 compliance] Also fixes PR 25694: don't allow
          // ANYTHING other than numeric values with 'px' allowed as
          // the only valid units string:
          if (m_bSMIL10FullCompliance)
          {
            if(!strcmp(pName, "height")  ||  !strcmp(pName, "width"))
            {
                const char* pTmp = (const char*)pBuf->GetBuffer();
                UINT32 ulBuflen = pBuf->GetSize();
                UINT32 ulCounter = 0L;
                BOOL bNumCharFound = FALSE;
                BOOL bPxFoundAlready = FALSE;
                while (pTmp  &&  *pTmp)
                {
                  //The SMIL 1.0 spec says to use a "length" value as
                  // defined in the CSS2 spec, except that the "px"
                  // units are optional.  The CSS2 spec can be found
                  // here:
                  //  http://www.w3.org/TR/REC-CSS2/syndata.html
                  // with the specific definition found here in that
                  // page:
                  //    .../syndata.html#value-def-length
                  // Look for: "[+|-](#*)[.][(#*)][px]"
                  if (bPxFoundAlready  ||  
                        ( ('0' > *pTmp  ||  '9' < *pTmp)  &&
                        '.' != *pTmp  &&
                        (bNumCharFound  ||  ('-' != *pTmp  &&
                        '+' != *pTmp)) ) )
                  {
                      //If at least one number was found already
                      // and "px" follows, then this char (*pTmp)
                      // is not illegal here:
                      if (!bPxFoundAlready  &&
                            bNumCharFound  &&
                            'p' == *pTmp  &&
                            ulCounter < ulBuflen-1  &&
                            'x' == *(pTmp+1) )
                      {
                        //the first "px" following a number is ok;
                        bPxFoundAlready = TRUE;
                        ++pTmp; //jump past the 'x'.
                      }
                      else
                      {
                        CSmil1SMILSyntaxErrorHandler errHandler(
                                m_pContext);
                        errHandler.ReportError(SMILErrorBadAttribute,
                                (const char*)pBuf->GetBuffer(),
                              pNode->m_ulTagStartLine);
                        return NULL;
                      }
                  }
                  else if ('.' == *pTmp  ||  '-' == *pTmp  ||
                        '+' == *pTmp)
                  {
                      //Valid chars at start, so keep going.
                  }
                  else
                  {
                      bNumCharFound = TRUE;
                  }
                  ++pTmp;
                  ++ulCounter;
                }
            }
          }
          if(strcmp(pName, "height") == 0)
          {
            pLayout->m_ulHeight = atol((const char*)pBuf->GetBuffer());
            bHasHeight = TRUE;
          }
          else if(strcmp(pName, "width") == 0)
          {
            pLayout->m_ulWidth = atol((const char*)pBuf->GetBuffer());
            bHasWidth = TRUE;
          }
          else if(strcmp(pName, "background-color") == 0)
          {
                UINT32    ulColor = 0;
                HX_RESULT rv = HXParseColorUINT32((const char*) pBuf->GetBuffer(),
                                                  ulColor);
                if (SUCCEEDED(rv))
                {
                    pLayout->m_ulBgColor = ulColor;
                }
          }
          else if(strcmp(pName, "overflow") == 0)
          {
            pLayout->m_overflow = (const char*)pBuf->GetBuffer();
          }
          else if(strcmp(pName, "title") == 0)
          {
            pLayout->m_title = (const char*)pBuf->GetBuffer();
          }
          else if((strcmp(pName, "id") == 0) ||
                (strcmp(pName, "skip-content") == 0))
          {
            // dont' do anything with these attributes
          }
          
          HX_RELEASE(pBuf);
          rc = pNode->m_pValues->GetNextPropertyCString(pName, pBuf);
      }
    }

    //[SMIL 1.0 Compliance]: PR 24630:
    // height and width are not required in root layout, per the 1.0 spec:
    pLayout->m_bHeightUnspecified = !bHasHeight;
    pLayout->m_bWidthUnspecified = !bHasWidth;

    return pLayout;
}

CSmil1Region*
CSmil1Parser::makeRegion(SMIL1Node* pNode)
{
    CSmil1Region* pRegion = new CSmil1Region(pNode);

    if(pNode->m_pValues)
    {
      const char* pName = 0;
      IHXBuffer* pBuf = 0;
      HX_RESULT rc = pNode->m_pValues->GetFirstPropertyCString(pName, pBuf);
      while(HXR_OK == rc)
      {
          //[SMIL 1.0 compliance] Fixes PR 25697.  SMIL 1.0
          // documentation states in section 3.3.1 that only percentage and
          // "length" values are allowed in a root-layout height or width;
          if (m_bSMIL10FullCompliance)
          {
            if(!strcmp(pName, "height")  ||  !strcmp(pName, "width")  ||
                  !strcmp(pName, "top")  ||  !strcmp(pName, "left"))
            {
                const char* pTmp = (const char*)pBuf->GetBuffer();
                UINT32 ulBuflen = pBuf->GetSize();
                UINT32 ulCounter = 0L;
                BOOL bNumCharFound = FALSE;
                BOOL bPxOrPercentFoundAlready = FALSE;
                while (pTmp  &&  *pTmp)
                {
                  //The SMIL 1.0 spec says to use a percentage value
                  // or a "length" value as defined in the CSS2 spec,
                  // except that the "px" units are the only ones
                  // allowed and are optional.
                  // The CSS2 spec can be found here:
                  //  http://www.w3.org/TR/REC-CSS2/syndata.html
                  // with the specific definition found here in that
                  // page:
                  //    .../syndata.html#value-def-length
                  // Look for: "[+|-](#*)[.][(#*)][px|%]"
                  if (bPxOrPercentFoundAlready  ||
                        ( ('0' > *pTmp  ||  '9' < *pTmp)  &&
                        '.' != *pTmp  &&
                        (bNumCharFound  ||  ('-' != *pTmp  &&
                        '+' != *pTmp)) ) )
                  {
                      //If at least one number was found already
                      // and "px" or "%" follows, then this char
                      // (*pTmp) is not illegal here:
                      if (!bPxOrPercentFoundAlready  &&
                            bNumCharFound  &&
                            ( '%' == *pTmp  ||
                            ('p' == *pTmp  &&
                            ulCounter < ulBuflen-1  &&
                            'x' == *(pTmp+1))) )
                      {
                        //The first "px" or "%" following a number
                        // is ok;
                        bPxOrPercentFoundAlready = TRUE;
                        if ('p' == *pTmp)
                        {
                            ++pTmp; //jump past the 'x'.
                        }
                      }
                      else
                      {
                        CSmil1SMILSyntaxErrorHandler errHandler(
                                m_pContext);
                        errHandler.ReportError(SMILErrorBadAttribute,
                                (const char*)pBuf->GetBuffer(),
                              pNode->m_ulTagStartLine);
                        return NULL;
                      }
                  }
                  else if ('.' == *pTmp  ||  '-' == *pTmp  ||
                        '+' == *pTmp)
                  {
                      //Valid chars at start, so keep going.
                  }
                  else
                  {
                      bNumCharFound = TRUE;
                  }
                  ++pTmp;
                  ++ulCounter;
                }
            }
          }
          if(strcmp(pName, "left") == 0)
          {
            pRegion->m_left = (const char*)pBuf->GetBuffer();
          }
          else if(strcmp(pName, "top") == 0)
          {
            pRegion->m_top = (const char*)pBuf->GetBuffer();
          }
          else if(strcmp(pName, "height") == 0)
          {
            pRegion->m_height = (const char*)pBuf->GetBuffer();
          }
          else if(strcmp(pName, "width") == 0)
          {
            pRegion->m_width = (const char*)pBuf->GetBuffer();
          }
          else if(strcmp(pName, "fit") == 0)
          {
            pRegion->m_fit = (const char*)pBuf->GetBuffer();
          }
          else if(strcmp(pName, "z-index") == 0)
          {
            pRegion->m_zIndex = atol((const char*)pBuf->GetBuffer());
          }
          else if(strcmp(pName, "background-color") == 0)
          {
            const char* pActualColor = (const char*)pBuf->GetBuffer();
            if(strcmp(pActualColor, "transparent") == 0)
            {
                pRegion->m_bBgColorSet = FALSE;
            }
            else
            {
                    UINT32 ulColor = 0;
                    HX_RESULT rv = HXParseColorUINT32((const char*) pBuf->GetBuffer(),
                                                      ulColor);
                    if (SUCCEEDED(rv))
                    {
                        pRegion->m_ulBgColor   = ulColor;
                        pRegion->m_bBgColorSet = TRUE;
                    }
            }
          }
          
          pBuf->Release();
          rc = pNode->m_pValues->GetNextPropertyCString(pName, pBuf);
      }
    }
    return pRegion;
}

CSmil1AAnchorElement*
CSmil1Parser::makeAAnchorElement(SMIL1Node* pNode)
{
    CSmil1AAnchorElement* pAnchor = 
      new CSmil1AAnchorElement(pNode);
    if(pNode->m_pValues)
    {
      const char* pName = 0;
      IHXBuffer* pBuf = 0;
      HX_RESULT rc = pNode->m_pValues->GetFirstPropertyCString(pName, pBuf);
      while(HXR_OK == rc)
      {
          if(strcmp(pName, "href") == 0)
          {
            pAnchor->m_href = (const char*)pBuf->GetBuffer();
          }
          else if(strcmp(pName, "show") == 0)
          {
            pAnchor->m_show = (const char*)pBuf->GetBuffer();
          }

          pBuf->Release();
          rc = pNode->m_pValues->GetNextPropertyCString(pName, pBuf);
      }
    }
    return pAnchor;
}

CSmil1AnchorElement*
CSmil1Parser::makeAnchorElement(SMIL1Node* pNode)
{
    CSmil1AnchorElement* pAnchor = new CSmil1AnchorElement(pNode);
    if(pNode->m_pValues)
    {
      const char* pName = 0;
      IHXBuffer* pBuf = 0;
      HX_RESULT rc = pNode->m_pValues->GetFirstPropertyCString(pName, pBuf);
      while(HXR_OK == rc)
      {
          if(strcmp(pName, "href") == 0)
          {
            pAnchor->m_href = (const char*)pBuf->GetBuffer();
          }
          else if(strcmp(pName, "show") == 0)
          {
            pAnchor->m_show = (const char*)pBuf->GetBuffer();
          }
          else if(strcmp(pName, "coords") == 0)
          {
            rc = parseAnchorCoords((const char*)pBuf->GetBuffer(),
                pAnchor);
          }
          else if(strcmp(pName, "fragment-id") == 0)
          {
            pAnchor->m_fragmentID = (const char*)pBuf->GetBuffer();
          }
          else if(strcmp(pName, "z-index") == 0)
          {
            pAnchor->m_zIndex = atol((const char*)pBuf->GetBuffer());
          }
          else if(strcmp(pName, "begin") == 0)
          {
            rc = parseDuration((const char*)pBuf->GetBuffer(), pAnchor, 
                SMILSyncAttrBegin);
            if(HXR_OK == rc)
            {
                pAnchor->m_bTimeValueSet = TRUE;
            }
          }
          else if(strcmp(pName, "end") == 0)
          {
            rc = parseDuration((const char*)pBuf->GetBuffer(), pAnchor,
                SMILSyncAttrEnd);
            if(HXR_OK == rc)
            {
                pAnchor->m_bTimeValueSet = TRUE;
            }
          }

          pBuf->Release();
          rc = pNode->m_pValues->GetNextPropertyCString(pName, pBuf);
      }
    }
    return pAnchor;
}

CSmil1Source*
CSmil1Parser::makeSource(SMIL1Node* pNode)
{
    HX_RESULT rc = HXR_OK;
    CSmil1Source* pSource = new CSmil1Source(pNode);

    // assign to a group
    if(pNode->m_nGroup == (UINT16)-1)
    {
      SMIL1Node* pParent = pNode->m_pParent;
      while(pParent)
      {
          if(pParent->m_nGroup != (UINT16)-1)
          {
            pNode->m_nGroup = pParent->m_nGroup;
            break;
          }
          pParent = pParent->m_pParent;
      }
    }

    if(pNode->m_pValues)
    {
      const char* pName = 0;
      IHXBuffer* pBuf = 0;
      rc = pNode->m_pValues->GetFirstPropertyCString(pName, pBuf);
      while(HXR_OK == rc)
      {
          if(strcmp(pName, "src") == 0)
          {
            CHXString src = (const char*)pBuf->GetBuffer();
            
            // trim leading/trailing spaces
            src.TrimRight();
            src.TrimLeft();

            if(m_pBasePath &&
                isRelativeURL(src))
            {
                pSource->m_src = CHXString(m_pBasePath) + src;
            }
            else
            {
                pSource->m_src = src;
            }
          }
          else if(strcmp(pName, "region") == 0)
          {
            //char szPersistentComponentID[MAX_DISPLAY_NAME] = {0};
            //itoa(m_ulPersistentComponentID, szPersistentComponentID, 10);
   
            // append persistent ID to the end of region id
            // to make it unique in nested meta
            pSource->m_region = (const char*)pBuf->GetBuffer();
            //pSource->m_region += "_";
            //pSource->m_region += szPersistentComponentID;
          }
          else if(strcmp(pName, "begin") == 0)
          {
            rc = parseDuration((const char*)pBuf->GetBuffer(), pSource, 
                SMILSyncAttrBegin);
          }
          else if(strcmp(pName, "end") == 0)
          {
            rc = parseDuration((const char*)pBuf->GetBuffer(), pSource,
                SMILSyncAttrEnd);
          }
          else if(strcmp(pName, "clip-begin") == 0)
          {
            rc = parseDuration((const char*)pBuf->GetBuffer(), pSource,
                SMILSyncAttrClipBegin);
          }
          else if(strcmp(pName, "clip-end") == 0)
          {
            rc = parseDuration((const char*)pBuf->GetBuffer(), pSource,
                SMILSyncAttrClipEnd);
          }
          else if(strcmp(pName, "dur") == 0)
          {
            rc = parseDuration((const char*)pBuf->GetBuffer(), pSource,
                SMILSyncAttrDur);
          }
          else if(strcmp(pName, "fill") == 0)
          {
            pSource->m_fill = (const char*)pBuf->GetBuffer();
          }
          else if(strcmp(pName, "title") == 0)
          {
            pSource->m_title = (const char*)pBuf->GetBuffer();
          }
          else if(strcmp(pName, "repeat") == 0)
          {
            const char* pRepeatCount = (const char*)pBuf->GetBuffer();

            if(strcmp(pRepeatCount, "indefinite") == 0)
            {
                pSource->m_ulRepeatValue = MAX_UINT32;
            }
            else
            {
                pSource->m_ulRepeatValue = atol(pRepeatCount);
            }
          }


          pBuf->Release();
          if(HXR_OK != rc)
          {
            goto exit;
          }

          rc = pNode->m_pValues->GetNextPropertyCString(pName, pBuf);
      }
    }

    rc = adjustDuration(pSource);

exit:
    if(HXR_OK != rc)
    {
      HX_DELETE(pSource);
    }

    return pSource;
}

CSmil1SeqElement*
CSmil1Parser::makeSeqElement(SMIL1Node* pNode)
{
    HX_RESULT rc = HXR_OK;

    CSmil1SeqElement* pElement = 
      new CSmil1SeqElement(pNode);
    if(pNode->m_pValues)
    {
      const char* pName = 0;
      IHXBuffer* pBuf = 0;
      rc = pNode->m_pValues->GetFirstPropertyCString(pName, pBuf);
      while(HXR_OK == rc)
      {
          if(strcmp(pName, "dur") == 0)
          {
            rc = parseDuration((const char*)pBuf->GetBuffer(), pElement,
                SMILSyncAttrDur);
          }
            else if(strcmp(pName, "begin") == 0)
            {
            rc = parseDuration((const char*)pBuf->GetBuffer(), pElement,
                SMILSyncAttrBegin);
            }
            else if(strcmp(pName, "end") == 0)
            {
            rc = parseDuration((const char*)pBuf->GetBuffer(), pElement,
                SMILSyncAttrEnd);
            }
          else if(strcmp(pName, "title") == 0)
          {
            pElement->m_title = (const char*)pBuf->GetBuffer();
          }
          else if(strcmp(pName, "repeat") == 0)
          {
            pElement->m_ulRepeatValue = atol((const char*)pBuf->GetBuffer());
          }

          pBuf->Release();

          if(HXR_OK != rc)
          {
            goto exit;
          }

          rc = pNode->m_pValues->GetNextPropertyCString(pName, pBuf);
      }
    }

    rc = adjustDuration(pElement);

exit:
    if(HXR_OK != rc)
    {
      HX_DELETE(pElement);
    }

    return pElement;
}

CSmil1ParElement*
CSmil1Parser::makeParElement(SMIL1Node* pNode)
{
    HX_RESULT rc = HXR_OK;

    CSmil1ParElement* pElement = 
      new CSmil1ParElement(pNode);
    if(pNode->m_pValues)
    {
      const char* pName = 0;
      IHXBuffer* pBuf = 0;
      rc = pNode->m_pValues->GetFirstPropertyCString(pName, pBuf);
      while(HXR_OK == rc)
      {
          if(strcmp(pName, "dur") == 0)
          {
            rc = parseDuration((const char*)pBuf->GetBuffer(), pElement,
                SMILSyncAttrDur);
          }
            else if(strcmp(pName, "begin") == 0)
            {
            rc = parseDuration((const char*)pBuf->GetBuffer(), pElement,
                SMILSyncAttrBegin);
            }
            else if(strcmp(pName, "end") == 0)
            {
            rc = parseDuration((const char*)pBuf->GetBuffer(), pElement,
                SMILSyncAttrEnd);
            }
          else if(strcmp(pName, "endsync") == 0)
          {
            rc = parseDuration((const char*)pBuf->GetBuffer(), pElement,
                SMILSyncAttrEndsync);
          }
          else if(strcmp(pName, "title") == 0)
          {
            pElement->m_title = (const char*)pBuf->GetBuffer();
          }
          else if(strcmp(pName, "repeat") == 0)
          {
            pElement->m_ulRepeatValue = atol((const char*)pBuf->GetBuffer());
          }


          pBuf->Release();

          if(HXR_OK != rc)
          {
            goto exit;
          }

          rc = pNode->m_pValues->GetNextPropertyCString(pName, pBuf);
      }
    }

    rc = adjustDuration(pElement);

exit:
    if(HXR_OK != rc)
    {
      HX_DELETE(pElement);
    }

    return pElement;
}

HX_RESULT
CSmil1Parser::insertElementByTimestamp(CSmil1Element* pPacket)
{
    LISTPOSITION lPos = m_pPacketQueue->GetHeadPosition();
    LISTPOSITION lPrev = lPos;

    while(lPos)
    {
      CSmil1Element* pPkt = (CSmil1Element*)m_pPacketQueue->GetNext(lPos);
      if(pPkt->m_ulTimestamp > pPacket->m_ulTimestamp)
      {
          m_pPacketQueue->InsertBefore(lPrev, pPacket);
          return HXR_OK;
      }
      lPrev = lPos;
    }
    m_pPacketQueue->AddTail(pPacket);

    return HXR_OK;
}

HX_RESULT
CSmil1Parser::mapID(SMIL1Node* pNode, BOOL bOverWrite)
{
    HX_RESULT rc = HXR_OK;

    void* pTmp = 0;
    if(!bOverWrite && m_pIDMap->Lookup((const char*)pNode->m_id, (void*&)pTmp))
    {
      rc = HXR_FAIL;
      CSmil1SMILSyntaxErrorHandler errHandler(m_pContext);
      errHandler.ReportError(SMILErrorDuplicateID, pNode->m_id, 
                        pNode->m_ulTagStartLine);
    }
    else
    {
      (*m_pIDMap)[(const char*)pNode->m_id] = pNode;
    }
    return rc;
}

//This function is needed to fix PR 13319.  If you have a repeat of greater
// than 1 in a <seq>, we need a way to map the IDs of the children created
// when the additional <seq>(s) are created
HX_RESULT
CSmil1Parser::mapChildrenIDs(SMIL1NodeList* pNodeList, BOOL bOverWrite)
{
    HX_RESULT rc = HXR_OK;

    if (!pNodeList)
    {
      return rc;
    }

    CHXSimpleList::Iterator i;
    for(i=pNodeList->Begin();rc == HXR_OK && i!=pNodeList->End();++i)
    {
      SMIL1Node* pNode = (SMIL1Node*)(*i);
      rc = mapID(pNode, bOverWrite);

      HX_ASSERT(rc == HXR_OK);

      if(pNode->m_pNodeList)
      {
          rc = mapChildrenIDs(pNode->m_pNodeList, bOverWrite);
      }
    }

    return rc;
}

HX_RESULT
CSmil1Parser::markRepeatReplica(SMIL1NodeList* pNodeList, RepeatTag repeatTag)
{
    HX_RESULT rc = HXR_OK;

    if(!pNodeList)
    {
      return rc;
    }

    CHXSimpleList::Iterator i;
    for(i=pNodeList->Begin();rc == HXR_OK && i!=pNodeList->End();++i)
    {
      SMIL1Node* pNode = (SMIL1Node*)(*i);
      pNode->m_repeatTag = repeatTag;

      if(pNode->m_pNodeList)
      {
          rc = markRepeatReplica(pNode->m_pNodeList, repeatTag);
      }
    }

    return rc;
}

HX_RESULT
CSmil1Parser::createElements()
{
    HX_RESULT rc = HXR_OK;
    
    SMIL1Node* pSMIL1Node = findFirstNode(SMILSmil);
    if(!pSMIL1Node)  // dangerwillrobinson!!!
    {
      rc = HXR_FAIL;
      CSmil1SMILSyntaxErrorHandler errHandler(m_pContext);
      errHandler.ReportError(SMILErrorNotSMIL, NULL, 0);
      return rc;
    }

    rc = addToNamespaceScope(pSMIL1Node);
    if (SUCCEEDED(rc))
    {
      // XXXJEFFA Hardcode "cv" namespace prefix for Redstone alpha 7
      rc = addGlobalNamespace((const char*) SYSTEM_COMPONENT_NAMESPACE, "cv");
    }
    
    if (FAILED(rc))
    {
      HX_ASSERT(FALSE);
      return rc;
    }
    
    SMIL1Node* pHeadNode = findFirstNode(SMILHead);
    if(pHeadNode)
    {
      rc = markTestAttributeNodes(pHeadNode->m_pNodeList);
      if (SUCCEEDED(rc))
      {
          rc = addToNamespaceScope(pHeadNode);
      }
      if(SUCCEEDED(rc))
      {
          rc = createHeadElements(pHeadNode->m_pNodeList);
      }
      if (SUCCEEDED(rc))
      {
          rc = removeFromNamespaceScope(pHeadNode);
      }
    }

    if(rc == HXR_OK)
    {
      SMIL1Node* pBodyNode = findFirstNode(SMILBody);
      if(pBodyNode && 
          pBodyNode->m_pNodeList)
      {
          rc = addToNamespaceScope(pBodyNode);
          if (SUCCEEDED(rc))
          {
            SMIL1Node* pTopNode = getTimelineDescendent(pBodyNode, NULL);
            if(pTopNode &&
                pTopNode->m_tag != SMILSeq)
            {
                createSeqWrapper(pBodyNode->m_pNodeList);
            }
            //[SMIL 1.0 compliance] fix for PR 23050:
            // if first descendent of body is a <switch> and its first child
            // is a <seq> that did not get chosen in the switch, then we
            // would be tricked into thinking we already had a valid outer
            // seq, but we wouldn't.  Let's put one there in this case,
            // noting that we don't yet know if that seq is valid or not.
            // However, it doesn't matter either way:
            if(pTopNode  &&  SMILSeq == pTopNode->m_tag  &&
                  pTopNode->m_pParent  &&
                  pTopNode->m_pParent->m_tag == SMILSwitch)
            {
                createSeqWrapper(pBodyNode->m_pNodeList);
            }

            
            if(HXR_OK != markTestAttributeNodes(pBodyNode->m_pNodeList) ||
               HXR_OK != expandRepeatElements(pBodyNode->m_pNodeList)   ||
               HXR_OK != createBodyElements(pBodyNode->m_pNodeList) ||
               HXR_OK != assignGroupIndexes(pBodyNode->m_pNodeList) ||
               HXR_OK != constructTimelineElements(pBodyNode->m_pNodeList) ||
               HXR_OK != setInitialDelays(pBodyNode->m_pNodeList) ||
               // HXR_OK != updateEventElements(pBodyNode->m_pNodeList) ||
      #ifdef _DEBUG
               HXR_OK != printBodyElements(pBodyNode->m_pNodeList) ||
      #endif
               HXR_OK != insertGroups())
            {
                rc = HXR_FAIL;
            }
          }

          if (SUCCEEDED(rc))
          {
            rc = removeFromNamespaceScope(pBodyNode);
          }
      }
      if(rc == HXR_OK && !m_bContainsSource)
      {
          rc = HXR_OK;
          //[SMIL 1.0 compliance] fixes PR 27672:
          // don't call SMILErrorNoBodyElements error as it is not one
          // per the SMIL 1.0 spec.
      }
    }

    return rc;
}

HX_RESULT
CSmil1Parser::createSeqWrapper(SMIL1NodeList* pNodeList)
{
    // create a default <seq></seq> wrapper within the <body></body>
    HX_RESULT rc = HXR_OK;
    SMIL1Node* pSeqNode = new SMIL1Node;
    pSeqNode->m_name = "seq";
    pSeqNode->m_pParent = pNodeList->m_pParentNode;
    pSeqNode->m_id = assignID("seq");
    pSeqNode->m_tag = SMILSeq;
    pSeqNode->m_pNodeList = new SMIL1NodeList;
    // Must put the node in the id map - otherwise
    // we leak the node
    mapID(pSeqNode, TRUE);

    // move children from bodyNode list to seq list
    int count = pNodeList->GetCount();
    SMIL1Node* pEndBodyNode = NULL;
    while( count > 0)   // don't reparent </body> tag 
    {
      SMIL1Node* pChildNode = (SMIL1Node*)pNodeList->RemoveHead();
      //XXXJHUG don't reparent the </body> tag...
      if ( pChildNode->m_id != "CLOSE-body" )
      {
          pChildNode->m_pParent = pSeqNode;
          pSeqNode->m_pNodeList->AddTail(pChildNode);
      }
      else
      {
          pEndBodyNode = pChildNode;
      }
      --count;
    }

    SMIL1Node* pEndSeqNode = new SMIL1Node;
    pEndSeqNode->m_name = "seq";
    pEndSeqNode->m_id = "CLOSE-seq";
    pEndSeqNode->m_pParent = pSeqNode;
    pEndSeqNode->m_tag = SMILEndSeq;
    pSeqNode->m_pNodeList->AddTail(pEndSeqNode);

    // now add it to the <body> parent...
    pNodeList->AddHead(pSeqNode);
    pNodeList->AddTail(pEndBodyNode);

    return rc;
}

#if 0
//XXXBAB - useful for debugging
void
CSmil1Parser::PrintNode(SMIL1Node* pNode, FILE* fp, int level)
{
    for(int tab=0;tab<level;++tab)
    {
      fprintf(fp, "\t");
    }
    fprintf(fp, "%s\n", (const char*)pNode->m_id);
    if(pNode->m_pNodeList)
    {
      CHXSimpleList::Iterator i = pNode->m_pNodeList->Begin();
      for(; i != pNode->m_pNodeList->End(); ++i)
      {
          SMIL1Node* pChildNode = (SMIL1Node*)(*i);
          PrintNode(pChildNode, fp, level+1);
      }
    }
}

void
CSmil1Parser::PrintNodes()
{
    FILE* fp = fopen("nodes.txt", "w");
    SMIL1Node* pNode = (SMIL1Node*)m_pNodeList->GetHead();
    PrintNode(pNode, fp, 0);
    fclose(fp);
}
#endif


HX_RESULT
CSmil1Parser::printBodyElements(SMIL1NodeList* pNodeList)
{
    // debugging code...
    HX_RESULT rc = HXR_OK;

//#define XXXEH_FOR_DEBUGGING_ONLY
#if defined(XXXEH_FOR_DEBUGGING_ONLY)
    static int level = 0;

    if(!pNodeList)
    {
      return rc;
    }

    CHXSimpleList::Iterator i;
    for(i=pNodeList->Begin();i!=pNodeList->End();++i)
    {
      if(HXR_OK != rc)
      {
          return rc;
      }

      SMIL1Node* pNode = (SMIL1Node*)(*i);

      FILE* fp=fopen("c:\\temp\\smil.txt", "a+");
      if (!fp)
      {
          break;
      }

      for(int i=0;i<level;++i)
      {
          fprintf(fp, "\t");
      }
      UINT32 ulDelay = (UINT32)-1;
      if(pNode->m_pElement &&
          pNode->m_pElement->m_pTimelineElement)
      {
          ulDelay = pNode->m_pElement->m_pTimelineElement->getDelay();
      }
      fprintf(fp, "%s tag %d group %d repeatid %s delay %d deleted %d\n", (const char*)pNode->m_id,
          pNode->m_tag, pNode->m_nGroup, (const char*)pNode->m_repeatid, ulDelay, pNode->m_bDelete);
      fclose(fp);

      if(pNode->m_pNodeList)
      {
          ++level;
          rc = printBodyElements(pNode->m_pNodeList);
          --level;
      }
    }
#endif
    return rc;
}

HX_RESULT
CSmil1Parser::insertGroups()
{
    HX_RESULT rc = HXR_OK;

    if(!m_pAddGroupMap)
    {
      rc = HXR_UNEXPECTED;
    }
    else
    {
      UINT32 ulGroupNo = 0;
      CSmil1AddGroup* pAddGroup = 0;
      BOOL bGroupInserted = FALSE;
      while(m_pAddGroupMap->Lookup(ulGroupNo++, (void*&)pAddGroup))
      {
          bGroupInserted = TRUE;
          pAddGroup->m_ulDelay = 0;
          pAddGroup->m_ulTimestamp = INITIAL_STREAM0_TIMESTAMP;
          insertElementByTimestamp(pAddGroup);
      }
    }
    return rc;
}

BOOL
CSmil1Parser::inLanguagePreference(const char* pLang)
{
    // return FALSE if language preference is not in m_pLanguagePreferenceList

    BOOL rc = FALSE;

    // pLang can be comma separated lists,
    // with '*' accepting all languages

    // copy the string so strtok doesn't modify something bad...
    char* pLangCopy = new_string(pLang);
    char* pLangFrag = strtok(pLangCopy, ",");
    while(pLangFrag)
    {
      if(*pLangFrag == '*')   // wildcard
      {
          rc = TRUE;
          break;
      }

      // copy the primary tag part of the language (up to '-')
      char* pPrimaryTag = new char[strlen(pLang)+1];
      char* pTagPtr = pPrimaryTag;
      char* pFragPtr = pLangFrag;
      while(*pFragPtr && *pFragPtr != '-')
      {
          *pTagPtr++ = *pFragPtr++;
      }
      *pTagPtr = '\0';

      CHXSimpleList::Iterator i = m_pLanguagePreferenceList->Begin();
      for(; i != m_pLanguagePreferenceList->End(); ++i)
      {
          char* pPrefLang = (char*)(*i);
          if(*pPrefLang == '*')     // wildcard
          {
            rc = TRUE;
          }
          else if(strcmp(pPrefLang, pLangFrag) == 0)
          {
            rc = TRUE;
          }
          else if(strncmp(pPrefLang, pPrimaryTag, strlen(pPrimaryTag)) == 0)
          {
            rc = TRUE;
          }
          if(rc)
          {
            break;
          }
      }

      delete[] pPrimaryTag;

      if(rc)
      {
          break;
      }
      pLangFrag = strtok(NULL, ",");
    }
    delete[] pLangCopy;

    return rc;
}

BOOL
CSmil1Parser::systemComponentFailed(IHXBuffer* pRequiredValue)
{
    BOOL bFailed = TRUE;
    IHXUpgradeCollection* pUpgradeCollection = new HXUpgradeCollection;
    pUpgradeCollection->AddRef();

    pUpgradeCollection->Add(eUT_Required, pRequiredValue, 0, 0);
    if (m_pISystemRequired == NULL)
    {
      m_pContext->QueryInterface(IID_IHXSystemRequired, 
          (void**)&m_pISystemRequired);
    }

    // there may not be a system required interface
    if (m_pISystemRequired != NULL)
    {
      bFailed = FAILED(m_pISystemRequired->HasFeatures(pUpgradeCollection));
    }

    HX_RELEASE(pUpgradeCollection);

    return bFailed;
}

BOOL
CSmil1Parser::testAttributeFailed(SMIL1Node* pNode)
{
    HX_RESULT rc = HXR_OK;
    BOOL bFailed = FALSE;
    IHXBuffer* pBuf = 0;

    if(pNode->m_pValues)
    {
      rc = pNode->m_pValues->GetPropertyCString("system-required", pBuf);
      if(HXR_OK == rc)
      {
          const char* pActualString = (const char*)pBuf->GetBuffer();
          // Check with the core first
          
          if(m_pRequireTagsMap)
          {
            void* pTag = 0;
            if(!m_pRequireTagsMap->Lookup(pActualString, 
                (void*&) pTag))
            {
                bFailed = TRUE;
            }
          }
          else    // no required list, can't parse it
          {
            bFailed = TRUE;
          }

          pBuf->Release();
          if(bFailed)
          {
            goto exit;
          }
      }

      rc = pNode->m_pValues->GetPropertyCString("system-bitrate", pBuf);
      if(HXR_OK == rc)
      {
          UINT32 ulBandwidth = atol((const char*)pBuf->GetBuffer());

          if(m_ulBandwidthPreference < ulBandwidth)
          {
            bFailed = TRUE;
          }
          pBuf->Release();
          if(bFailed)
          {
            goto exit;
          }
      }

      rc = pNode->m_pValues->GetPropertyCString("system-language", pBuf);
      if(HXR_OK == rc)
      {
          if(m_pLanguagePreferenceList)
          {
            const char* pLang = (const char*)pBuf->GetBuffer();
            if(!inLanguagePreference(pLang))
            {
                bFailed = TRUE;
            }
          }
          else    // no preference, can't do it...
          {
            bFailed = TRUE;
          }
          pBuf->Release();
          if(bFailed)
          {
            goto exit;
          }
      }

      rc = pNode->m_pValues->GetPropertyCString("system-captions", pBuf);
      if(HXR_OK == rc)
      {
          const char* pActualValue = (const char*)pBuf->GetBuffer();
          if(strcmp(pActualValue, "on") == 0)
          {
            if(!m_bCaptionsPreference)
            {
                bFailed = TRUE;
            }
          }
          else
          {
            if(m_bCaptionsPreference)
            {
                bFailed = TRUE;
            }
          }
          pBuf->Release();
          if(bFailed)
          {
            goto exit;
          }
      }

      if(HXR_OK == pNode->m_pValues->GetPropertyCString(
          "system-overdub-or-caption", pBuf))
      {
          if(m_pOverdubOrCaptionPreference)
          {
            const char* pActualValue = (const char*)pBuf->GetBuffer();
            if(strcmp(pActualValue, "caption") == 0)
            {
                if(strcmp(m_pOverdubOrCaptionPreference, "caption") != 0)
                {
                  bFailed = TRUE;
                }
            }
            else if(strcmp(pActualValue, "overdub") == 0)
            {
                if(strcmp(m_pOverdubOrCaptionPreference, "overdub") != 0)
                {
                  bFailed = TRUE;
                }
            }
          }
          else
          {
            bFailed = TRUE;
          }
          pBuf->Release();
          if(bFailed)
          {
            goto exit;
          }
      }

      rc = pNode->m_pValues->GetPropertyCString(
          "system-screen-size", pBuf);
      if(HXR_OK == rc)
      {
          UINT32 ulScreenHeight = 0;
          UINT32 ulScreenWidth = 0;

          const char* pScreenSize = (const char*)pBuf->GetBuffer();
          // format is screen-height "X" screen-width
          char tmp[256]; /* Flawfinder: ignore */
          SafeStrCpy(tmp, pScreenSize, 256);
          char* pScreenHeight = strtok(tmp, "X");
          if(pScreenHeight)
          {
            ulScreenHeight = atol(pScreenHeight);
            char* pScreenWidth = strtok(NULL, "");
            if(pScreenWidth)
            {
                ulScreenWidth = atol(pScreenWidth);
            }
          }
          if((m_ulScreenHeightPreference < ulScreenHeight) ||
             (m_ulScreenWidthPreference < ulScreenWidth))
          {
            bFailed = TRUE;
          }
          pBuf->Release();
          if(bFailed)
          {
            goto exit;
          }
      }

      rc = pNode->m_pValues->GetPropertyCString(
          "system-screen-depth", pBuf);
      if(HXR_OK == rc)
      {
          UINT32 ulScreenDepth = atol((const char*)pBuf->GetBuffer());
          if(m_ulScreenDepthPreference < ulScreenDepth)
          {
            bFailed = TRUE;
          }
          pBuf->Release();
          if(bFailed)
          {
            goto exit;
          }
      }

      if (m_pActiveNamespaceMap)
      {
          // look through name spaces for systemComponent name space.  If it's there
          // append the prefix and look for systemComponent test attribute
          CHXMapStringToOb::Iterator ndxBuffer = m_pActiveNamespaceMap->Begin();
          for (; ndxBuffer != m_pActiveNamespaceMap->End(); ++ndxBuffer)
          {
            IHXBuffer* pBuffer = (IHXBuffer*)(*ndxBuffer);
            if (strcmp((const char*) SYSTEM_COMPONENT_NAMESPACE, (const char*)pBuffer->GetBuffer()) == 0)
            {
                const char* pPrefix = (const char*)ndxBuffer.get_key();
                // +1 for the : in the namespace and 1 for the \0
                char* pAttrName = new char[strlen(pPrefix) + strlen((const char*) SYSTEM_COMPONENT) + 2];
                
                pAttrName[0] = '\0';
                strcat(pAttrName, pPrefix); /* Flawfinder: ignore */
                strcat(pAttrName, ":"); /* Flawfinder: ignore */
                strcat(pAttrName, (const char*) SYSTEM_COMPONENT); /* Flawfinder: ignore */

                rc = pNode->m_pValues->GetPropertyCString(
                  pAttrName, pBuf);

                HX_VECTOR_DELETE(pAttrName);
                
                if(HXR_OK == rc)
                {
                  bFailed = systemComponentFailed(pBuf);
                  pBuf->Release();
                  
                  // If I get in here, I found the right prefix
                  if (bFailed)
                  {
                      goto exit;
                  }
                }
            }
          }
      }
    }

exit:
    return bFailed;
}

HX_RESULT
CSmil1Parser::selectSwitchNodes(SMIL1Node* pSwitchNode)
{
    HX_RESULT rc = HXR_OK;

    SMIL1NodeList* pNodeList = pSwitchNode->m_pNodeList;
    if(!pNodeList)
    {
      return rc;
    }

    SMIL1Node* pSelectedNode = 0;
    CHXSimpleList* pRejectedNodeList = new CHXSimpleList;

    CHXSimpleList::Iterator i;
    for(i=pNodeList->Begin();i!=pNodeList->End();++i)
    {
      SMIL1Node* pNode = (SMIL1Node*)(*i);

      if(!pNode->m_bDelete)
      {
          if(testAttributeFailed(pNode))
          {
            pRejectedNodeList->AddTail(pNode);
          }
          else
          {
            pSelectedNode = pNode; 
            //[SMIL 1.0 Compliance] Fixes PR 26732:
            //Now, update selected node's id to that of the switch so
            // that anchors pointing to the switch id will reference
            // the node of the switch that was selected.  Note that
            // we can't fix this the other way around, namely to rename
            // all anchors' id strings to that of the selected node
            // since not all of them have been parsed/set yet:
            HX_ASSERT(pSelectedNode->m_id.GetLength() > 0  && 
                pSwitchNode->m_id.GetLength() > 0);
            if (pSelectedNode->m_id.GetLength() > 0 &&  
                pSwitchNode->m_id.GetLength() > 0)
            {
                pSelectedNode->m_id = pSwitchNode->m_id;
                (*m_pIDMap)[(const char*)pSelectedNode->m_id] =
                      pSelectedNode;
                pSwitchNode->m_id = assignID("switch");
                (*m_pIDMap)[(const char*)pSwitchNode->m_id] =
                      pSwitchNode;
            }
            break;
          }
      }
    }

    HX_DELETE(pRejectedNodeList);

    // delete non-selected nodes
    for(i=pNodeList->Begin();i!=pNodeList->End();++i)
    {
      SMIL1Node* pNode = (SMIL1Node*)(*i);
      if(pNode != pSelectedNode)
      {
          pNode->m_bDelete = TRUE;
      }
    }

    return rc;
}

HX_RESULT
CSmil1Parser::markTestAttributeNodes(SMIL1NodeList* pNodeList)
{
    HX_RESULT rc = HXR_OK;

    if(!pNodeList)
    {
      return rc;
    }

    CHXSimpleList::Iterator i;
    for(i=pNodeList->Begin();i!=pNodeList->End() && SUCCEEDED(rc);++i)
    {
      SMIL1Node* pNode = (SMIL1Node*)(*i);

      rc = addToNamespaceScope(pNode);
      if (FAILED(rc))
      {
          return rc;
      }

      if(pNode->m_tag == SMILSwitch)
      {
          selectSwitchNodes(pNode);
      }
      else
      {
          if(testAttributeFailed(pNode))
          {
            pNode->m_bDelete = TRUE;
          }
      }
      //Fix for PR 21303: we need to keep drilling down
      // through the tree even if we've just called
      // selectSwitchNodes() to delete all but one
      // child of the switch; the descendants of that
      // child may have attributes as well that need
      // to be checked:
      //(For efficiency, only do the following code if
      // the node is not already slated for deletion
      // because a deletable node's children will be
      // deleted anyway):
      if (!pNode->m_bDelete)
      {
          rc = markTestAttributeNodes(pNode->m_pNodeList);
      }
      if (SUCCEEDED(rc))
      {
          rc = removeFromNamespaceScope(pNode);
      }
    }
    return rc;
}

BOOL
CSmil1Parser::firstDependentChild(SMIL1Node* pNode)
{
    if(getFirstNodeChild(pNode->m_pDependency) == pNode)
    {
      return TRUE;
    }
    return FALSE;
}

BOOL
CSmil1Parser::hasParParent(SMIL1Node* pNode)
{
    // walk up parent chain until we find a PAR
    BOOL rc = FALSE;
    while(pNode)
    {
      pNode = pNode->m_pParent;
      if(pNode && pNode->m_tag == SMILPar)
      {
          rc = TRUE;
          break;
      }
    }
    return rc;
}

SMIL1NodeTag
CSmil1Parser::getSyncTag(SMIL1Node* pNode)
{
    // walk up parent chain until we either find
    // a PAR or a SEQ
    SMIL1NodeTag tag = SMILSeq;     // assume a SEQ
    while(pNode)
    {
      pNode = pNode->m_pParent;
      if(pNode && pNode->m_tag == SMILPar)
      {
          tag = SMILPar;
          break;
      }
      else if(pNode && pNode->m_tag == SMILSeq)
      {
          tag = SMILSeq;
          break;
      }
    }
    return tag;
}

SMIL1Node*
CSmil1Parser::getSyncParent(SMIL1Node* pNode)
{
    SMIL1Node* pReturnNode = NULL;
    while(pNode)
    {
      pNode = pNode->m_pParent;
      if(pNode && 
          (pNode->m_tag == SMILPar ||
           pNode->m_tag == SMILSeq))
      {
          pReturnNode = pNode;
          break;
      }
    }
    return pReturnNode;
}

BOOL
CSmil1Parser::inSeq(SMIL1Node* pNode)
{
    SMIL1NodeTag tag = getSyncTag(pNode);
    return tag == SMILSeq;
}

HX_RESULT
CSmil1Parser::createHeadElements(SMIL1NodeList* pNodeList)
{
    HX_RESULT rc = HXR_OK;

    if(!pNodeList)
    {
      return rc;
    }

    CHXSimpleList::Iterator i;
    for(i=pNodeList->Begin();i!=pNodeList->End();++i)
    {
      if(HXR_OK != rc)
      {
          return rc;
      }

      SMIL1Node* pNode = (SMIL1Node*)(*i);

      if(pNode->m_bDelete)    // skip this puppy
      {
          continue;
      }

      rc = addToNamespaceScope(pNode);
      if (FAILED(rc))
      {
          return rc;
      }

      switch(pNode->m_tag)
      {
          case SMILRegion:
          {
            //[SMIL 1.0 compliance] Fixes PR 25798: a region element may
            // only be contained inside a layout element:
            if (m_bSMIL10FullCompliance  &&  pNode->m_pParent  &&
                  pNode->m_pParent->m_name.GetLength()  &&
                  strcmp((const char*)pNode->m_pParent->m_name,
                  "layout"))
            {
                CSmil1SMILSyntaxErrorHandler errHandler(m_pContext);
                errHandler.ReportError(SMILErrorUnexpectedTag,
                      (const char*)pNode->m_name,
                      pNode->m_ulTagStartLine);
                return HXR_FAIL;
            }
          }
          break;

          case SMILMeta:
          {
            CSmil1Meta* pMeta = makeMeta(pNode);
            if(pMeta)
            {
                pNode->m_pElement = pMeta;
                pMeta->m_ulDelay = 0;
                pMeta->m_ulTimestamp = INITIAL_STREAM0_TIMESTAMP;
                insertElementByTimestamp(pMeta);
            }
            else
            {
                return HXR_FAIL;
            }
          }
          break;

          case SMILBasicLayout:
          {
            const char* pLayoutName = (const char*)pNode->m_id;
            BOOL bHasRegions = FALSE;
            SMIL1Node* pLayoutNode = pNode->getFirstChild();
            while(pLayoutNode && !pLayoutNode->m_bDelete)
            {
                switch(pLayoutNode->m_tag)
                {
                  case SMILRootLayout:
                  {
                      CSmil1RootLayout* pRootLayout = 
                        makeRootLayout(pLayoutNode);
                      if(pRootLayout)
                      {
                        pLayoutNode->m_pElement = pRootLayout;
                        pRootLayout->m_ulDelay = 0;
                        pRootLayout->m_ulTimestamp =
                            INITIAL_STREAM0_TIMESTAMP;
                        insertElementByTimestamp(pRootLayout);
                      }
                      else
                      {
                        return HXR_FAIL;
                      }
                  }
                  break;

                  case SMILRegion:
                  {
                      CSmil1Region* pRegion = 
                        makeRegion(pLayoutNode);
                      if(pRegion)
                      {
                        pLayoutNode->m_pElement = pRegion;
                        bHasRegions = TRUE;
                        pRegion->m_ulDelay = 0;
                        pRegion->m_ulTimestamp = 
                            INITIAL_STREAM0_TIMESTAMP;
                        insertElementByTimestamp(pRegion);
                      }
                      else
                      {
                        return HXR_FAIL;
                      }
                  }
                  break;

                  case SMILMeta:
                  {
                      CSmil1Meta* pMeta = makeMeta(pLayoutNode);
                      if(pMeta)
                      {
                        pNode->m_pElement = pMeta;
                        pMeta->m_ulDelay = 0;
                        pMeta->m_ulTimestamp = 
                            INITIAL_STREAM0_TIMESTAMP;
                        insertElementByTimestamp(pMeta);
                      }
                      else
                      {
                        return HXR_FAIL;
                      }
                  }
                  break;

                  default:
                  break;
                }
                pLayoutNode = pNode->getNextChild();
            }
            if(bHasRegions)
            {
                // send end-layout packet at TS 0
                m_pEndLayout = new CSmil1EndLayout;
                m_pEndLayout->m_ulDelay = 0;
                m_pEndLayout->m_ulTimestamp = INITIAL_STREAM0_TIMESTAMP;
                insertElementByTimestamp(m_pEndLayout);
            }
          }
          break;
            
          case SMILRNRendererList:
          {
            SMIL1Node* pRendererNode = pNode->getFirstChild();
            while(pRendererNode && 
                pRendererNode->m_tag == SMILRendererPreFetch)
            {
                CSmil1RendererPreFetch* pRenderer = 
                  makeRendererPreFetch(pRendererNode);
                pRendererNode->m_pElement = pRenderer;
                pRenderer->m_ulDelay = 0;
                pRenderer->m_ulTimestamp = INITIAL_STREAM0_TIMESTAMP;
                insertElementByTimestamp(pRenderer);

                pRendererNode = pNode->getNextChild();
            }
          }
          break;

          default:
          break;
      }
      rc = createHeadElements(pNode->m_pNodeList);

      if (SUCCEEDED(rc))
      {
          rc = removeFromNamespaceScope(pNode);
      }
    }
    return rc;
}

HX_RESULT
CSmil1Parser::setInitialDelays(SMIL1NodeList* pNodeList)
{
    HX_RESULT rc = HXR_OK;

    UINT16 nGroup = (UINT16)-1;

    if(!pNodeList)
    {
      return rc;
    }

    CHXSimpleList::Iterator i = pNodeList->Begin();
    for(;i!=pNodeList->End();++i)
    {
      if(HXR_OK != rc)
      {
          return rc;
      }

      SMIL1Node* pNode = (SMIL1Node*)(*i);

      if(pNode->m_bDelete)    // skip this puppy
      {
          continue;
      }
      else if(pNode->m_tag == SMILAAnchor ||
              pNode->m_tag == SMILSwitch)
      {
          pNode = getTimelineDescendent(pNode);
          if(!pNode)
          {
            continue;
          }
      }

      setInitialDelay(pNode);
      switch(pNode->m_tag)
      {
          case SMILSeq:
          {
            setInitialDelayOnSeq(pNode);
          }
          break;
          case SMILPar:
          {
            SMIL1Node* pThisNode =
                getTimelineDescendent(pNode, NULL);
            while(pThisNode)
            {
                setInitialDelay(pThisNode);
                pThisNode =
                  getTimelineDescendent(pNode, pThisNode);
            }
          }
          break;
      }
    }
    return rc;
}

void
CSmil1Parser::setInitialDelay(SMIL1Node* pNode)
{
    if(pNode->m_pElement &&
      pNode->m_pElement->m_pTimelineElement &&
      !pNode->m_pElement->m_pTimelineElement->initialDelaySet())
    {
      pNode->m_pElement->m_pTimelineElement->setDelay(0);
    }

    if(pNode->m_pNodeList)
    {
      if(pNode->m_tag == SMILSeq ||
          pNode->m_tag == SMILPar)
      {
          if(pNode->m_pElement &&
            pNode->m_pElement->m_pTimelineElement &&
            pNode->m_pElement->m_ulDuration != (UINT32)-1)
          {
            pNode->m_pElement->m_pTimelineElement->setDuration(
                pNode->m_pElement->m_ulDuration);
          }
      }

      if(pNode->m_tag == SMILSeq)
      {
          setInitialDelayOnSeq(pNode);
      }
      //If the element doesn't exist or it does but the timelineElement
      // doesn't exist, or it does but there is no delay event, or there is
      // one but the delay is already set, then it's ok to set call
      // setInitialDelay():
      else if ((!pNode->m_pElement  ||
            !pNode->m_pElement->m_pTimelineElement)  ||
            //[SMIL 1.0 Compliance] Helps fix PR 14420:
            //Don't call this if pNode has an unresolved delay event:
            (!pNode->m_pElement->m_pTimelineElement->delayEvent()  ||
            pNode->m_pElement->m_pTimelineElement->initialDelaySet() ) )
      {
          SMIL1Node* pThisNode = 
            getTimelineDescendent(pNode, NULL);
          while(pThisNode)
          {
            setInitialDelay(pThisNode);
            pThisNode = getTimelineDescendent(pNode, pThisNode);
          }
      }
    }
}

void 
CSmil1Parser::setInitialDelayOnSeq(SMIL1Node* pNode)
{
    UINT16 nGroup = (UINT16)-1;
    
    SMIL1Node* pThisNode = getTimelineDescendent(pNode, NULL);
    while(pThisNode)
    {
      if(pThisNode->m_nGroup != nGroup)
      {
          nGroup = pThisNode->m_nGroup;
          setInitialDelay(pThisNode);
      }
      pThisNode = getTimelineDescendent(pNode, pThisNode);
    }
}

HX_RESULT
CSmil1Parser::assignGroupIndexes(SMIL1NodeList* pNodeList)
{
    HX_RESULT rc = HXR_OK;

    if(!pNodeList)
    {
      return rc;
    }

    UINT16 nGroup = 0;
    CHXSimpleList::Iterator i = pNodeList->Begin();
    for(; i != pNodeList->End(); ++i)
    {
      if(HXR_OK != rc)
      {
          return rc;
      }

      SMIL1Node* pNode = (SMIL1Node*)(*i);

      if(pNode->m_bDelete)    // skip this puppy
      {
          continue;
      }
      else if(pNode->m_tag == SMILAAnchor ||
              pNode->m_tag == SMILSwitch)
      {
          pNode = getTimelineDescendent(pNode);
          if(!pNode)
          {
            continue;
          }
      }

      switch(pNode->m_tag)
      {
          case SMILSeq:
          {
            SMIL1Node* pThisNode =
                getTimelineDescendent(pNode, NULL);
            while(pThisNode)
            {
                rc = assignGroupIndexOnSeq(pThisNode, nGroup);
                if(HXR_OK == rc)
                {
                  pThisNode =
                      getTimelineDescendent(pNode, pThisNode);
                  nGroup++;
                }
                else
                {
                  break;
                }
            }
          }
          break;

          case SMILPar:
          {
            // top-level par, each child has group 0
            SMIL1Node* pThisNode =
                getTimelineDescendent(pNode, NULL);
            while(pThisNode)
            {
                rc = assignGroupIndexOnPar(pThisNode, nGroup);
                if(HXR_OK == rc)
                {
                  pThisNode =
                      getTimelineDescendent(pNode, pThisNode);
                }
                else
                {
                  break;
                }
            }
          }
          break;

          default:
          break;
      }
    }

    return rc;
}

HX_RESULT
CSmil1Parser::assignGroupIndexOnPar(SMIL1Node* pNode,
                           UINT16 nGroup)
{
    HX_RESULT rc = HXR_OK;

    if(pNode->m_bDelete)
    {
      return rc;
    }

    pNode->m_nGroup = nGroup;
    pNode->m_repeatid.AppendULONG(nGroup);

    if (isMediaObject(pNode))
    {
      addGroup(pNode);
    }
    else if (SMILSeq == pNode->m_tag ||
           SMILPar == pNode->m_tag)
    {
      // top-level par, each child has group 0
      SMIL1Node* pThisNode =
          getTimelineDescendent(pNode, NULL);
      while(pThisNode)
      {
          rc = assignGroupIndexOnPar(pThisNode, nGroup);
          if(HXR_OK == rc)
          {
            pThisNode =
                getTimelineDescendent(pNode, pThisNode);
          }
          else
          {
            break;
          }
      }
    }

    return rc;
}

HX_RESULT
CSmil1Parser::assignGroupIndexOnSeq(SMIL1Node* pNode,
                           UINT16& nGroup)
{
    HX_RESULT rc = HXR_OK;

    if(pNode->m_bDelete)
    {
      return rc;
    }

    pNode->m_nGroup = nGroup;
    pNode->m_repeatid.AppendULONG(nGroup);

    if (isMediaObject(pNode))
    {
      addGroup(pNode);
    }
    else if (SMILSeq == pNode->m_tag)
    {
      SMIL1Node* pThisNode =
          getTimelineDescendent(pNode, NULL);
      while(pThisNode)
      {
          rc = assignGroupIndexOnSeq(pThisNode, nGroup);
          if(HXR_OK == rc)
          {
            pThisNode = getTimelineDescendent(pNode, pThisNode);
            if (pThisNode)
            {
                if (isMediaObject(pThisNode)    ||
                  SMILSeq == pThisNode->m_tag ||
                  SMILPar == pThisNode->m_tag)
                {
                  nGroup++;
                }
            }
          }
          else
          {
            break;
          }
      }
    }
    else if (SMILPar == pNode->m_tag)
    {
      SMIL1Node* pThisNode =
          getTimelineDescendent(pNode, NULL);
      while(pThisNode)
      {
          rc = assignGroupIndexOnPar(pThisNode, nGroup);
          if(HXR_OK == rc)
          {
            pThisNode =
                getTimelineDescendent(pNode, pThisNode);
          }
          else
          {
            break;
          }
      }
    }

    return rc;
}

BOOL 
CSmil1Parser::isMediaObject(SMIL1Node* pNode)
{
    BOOL bResult = FALSE;

    if (NULL == pNode || pNode->m_bDelete)
    {
      goto cleanup;
    }

    switch(pNode->m_tag)
    {
      case SMILRef:
      case SMILText:
      case SMILImg:
      case SMILAudio:
      case SMILVideo:
      case SMILAnimation:
      case SMILTextstream:
      {
          bResult = TRUE;
      }
      break;
      
      default:
      break;
    }

cleanup:

    return bResult;
}

HX_RESULT
CSmil1Parser::addGroup(SMIL1Node* pNode)
{
    HX_RESULT rc = HXR_OK;

    // set group info information
    CSmil1AddGroup* pAddGroup = 0;
    if(m_pAddGroupMap->Lookup(pNode->m_nGroup, (void*&)pAddGroup))
    {
      // we don't count self-replicated elements as they
      // share the same track ID
      if (pNode->m_repeatTag == RepeatUnknown)
      {
          pAddGroup->m_nTotalTracks++;
          if(pNode->m_pElement &&
             pNode->m_pElement->m_ulDelay == 0)
          {
            pAddGroup->m_nInitTracks++;
          }
      }
    }
    else
    {
      CSmil1AddGroup* pAddGroup = new CSmil1AddGroup;
      pAddGroup->m_nGroup = pNode->m_nGroup;
      
      // reference PAR properties in group
      if(pNode->m_pDependency &&
         pNode->m_pDependency->m_tag == SMILPar &&
         hasParParent(pNode))
      {
          IHXValues* pValues = pNode->m_pDependency->m_pValues;
          if(pValues)
          {
            pAddGroup->m_pValues = pValues;
            pAddGroup->m_pValues->AddRef();
          }
          pAddGroup->m_ulDuration = 
            pNode->m_pDependency->m_pElement->m_ulDuration;
      }

      // XXXJHUG  -- If the group is from a Seq, we still want
      // to pass along the Title, author, copyright & abstract from
      // the dependant parrent sequence group.
      if (pNode->m_pDependency &&
          pNode->m_pDependency->m_tag == SMILSeq)
      {
          IHXValues* pValues = pNode->m_pDependency->m_pValues;
          if(pValues)
          {
            // XXXJH should use CCF
            pAddGroup->m_pValues = new CHXHeader();
            IHXBuffer* pBuf = NULL;
            const char* name = NULL;
            pAddGroup->m_pValues->AddRef();
            if (SUCCEEDED(pValues->GetFirstPropertyCString(name, pBuf)))
            {
                do
                {
                  if (strcmp("title",name)==0 ||
                      strcmp("author",name)==0 ||
                      strcmp("abstract",name)==0 ||
                      strcmp("copyright",name)==0)
                  {
                      pAddGroup->m_pValues->SetPropertyCString(name, pBuf);
                  }
                  HX_RELEASE(pBuf);
                }
                while(SUCCEEDED(pValues->GetNextPropertyCString(name, pBuf)));
            }
          }
          // the duration for a sequence is dependant on the elements
          // within the sequence.
      }

      (*m_pAddGroupMap)[pNode->m_nGroup] = pAddGroup;
      pAddGroup->m_nTotalTracks = 1;
      if(pNode->m_pElement &&
          pNode->m_pElement->m_ulDelay == 0)
      {
          pAddGroup->m_nInitTracks = 1;
      }
    }
    return rc;
}

HX_RESULT
CSmil1Parser::createBodyElements(SMIL1NodeList* pNodeList)
{
    HX_RESULT rc = HXR_OK;

    if(!pNodeList)
    {
      return rc;
    }

    if(!m_pNodeDependencies)
    {
      m_pNodeDependencies = new CHXStack;
    }

    if(!m_pAnchorStack)
    {
      m_pAnchorStack = new CHXStack;
    }

    if(!m_pTrackHintList)
    {
      m_pTrackHintList = new CHXSimpleList;
    }

    UINT32 ulTrackHint = 1;

    CHXSimpleList::Iterator i;
    for(i=pNodeList->Begin();i!=pNodeList->End();++i)
    {
      if(HXR_OK != rc)
      {
          return rc;
      }

      SMIL1Node* pNode = (SMIL1Node*)(*i);

      if(pNode->m_bDelete)    // skip this puppy
      {
          continue;
      }

      rc = addToNamespaceScope(pNode);
      if (FAILED(rc))
      {
          return rc;
      }

      switch(pNode->m_tag)
      {
          case SMILSeq:
          {
            CSmil1SeqElement* pElement = makeSeqElement(pNode);
            if(!pElement)
            {
                return HXR_FAIL;
            }
            pNode->m_pElement = pElement;

            CSmil1TimelineSeq* pTimelineSeq =
                new CSmil1TimelineSeq(pElement, this);

            pElement->m_pTimelineElement = pTimelineSeq;

            if(!m_pCurrentDependentNode)  // at the top
            {
                //pNode->m_nGroup = (UINT16)-1;   // top level
            }
            else
            {
                pNode->m_pDependency = m_pCurrentDependentNode;

                if(!hasParParent(pNode))
                {
                  //pNode->m_nGroup = 
                  //    m_pCurrentDependentNode->m_nGroup + 1;
                }
                else
                {
                  //pNode->m_nGroup = 
                  //    m_pCurrentDependentNode->m_nGroup;
                }
            }
            m_pCurrentDependentNode = pNode;
            m_pNodeDependencies->Push(m_pCurrentDependentNode);

            ulTrackHint = 1;
            m_pTrackHintList->AddTail((void*)ulTrackHint);
          }
          break;

          case SMILPar:
          {
            CSmil1ParElement* pElement = makeParElement(pNode);
            if(!pElement)
            {
                return HXR_FAIL;
            }
            pNode->m_pElement = pElement;
            CSmil1TimelinePar* pTimelinePar = 
                new CSmil1TimelinePar(pElement, this);
            pElement->m_pTimelineElement = pTimelinePar;

            if(!m_pCurrentDependentNode)  // at the top
            {
                // pNode->m_nGroup = 0;
            }
            else
            {
                pNode->m_pDependency = m_pCurrentDependentNode;
                if(!hasParParent(pNode))
                {
                  //pNode->m_nGroup = 
                  //    m_pCurrentDependentNode->m_nGroup + 1;
                }
                else
                {
                  //pNode->m_nGroup = m_pCurrentDependentNode->m_nGroup;
                }
            }
            if(firstDependentChild(pNode) || m_pCurrentDependentNode == 0)
            {
                ulTrackHint = 1;
                m_pTrackHintList->AddTail((void*)ulTrackHint);
            }
            else
            {
                if(m_pTrackHintList->GetCount() > 0)
                {
                  ulTrackHint = (UINT32)m_pTrackHintList->RemoveTail();
                }
                m_pTrackHintList->AddTail((void*)++ulTrackHint);
            }

            m_pCurrentDependentNode = pNode;
            m_pNodeDependencies->Push(m_pCurrentDependentNode);

          }
          break;

          case SMILEndSeq:
          {
            m_pCurrentDependentNode = 
                (SMIL1Node*)m_pNodeDependencies->Pop();

            if(m_pTrackHintList->GetCount() > 0)
            {
                m_pTrackHintList->RemoveTail();
            }
          }
          break;

          case SMILEndPar:
          {
            m_pCurrentDependentNode = 
                (SMIL1Node*)m_pNodeDependencies->Pop();

            if(m_pTrackHintList->GetCount() > 0)
            {
                m_pTrackHintList->RemoveTail();
            }
          }
          break;

          case SMILAAnchor:
          {
            CSmil1AAnchorElement* pElement = makeAAnchorElement(pNode);
            if(pElement)
            {
                pNode->m_pElement = pElement;
                m_pAnchorStack->Push(m_pCurrentAnchor);
                m_pCurrentAnchor = pElement;
            }
          }
          break;

          case SMILEndAAnchor:
          {
            m_pCurrentAnchor = (CSmil1AAnchorElement*)m_pAnchorStack->Pop();
          }
          break;

          case SMILAnchor:
          {
            CSmil1AnchorElement* pElement = makeAnchorElement(pNode);
            if(pElement)
            {
                pNode->m_pElement = pElement;

                //[SMIL 1.0 compliance] Helps fix PR 26471:
                // In order to get a notification that we have a resolved
                // event-based begin time, we need to be a
                // timeline element:
                CSmil1TimelineAnchor* pTimelineAnchor = 
                  new CSmil1TimelineAnchor(pElement, this);
                pElement->m_pTimelineElement = pTimelineAnchor;

                // add link to parent
                SMIL1Node* pParent = pNode->m_pParent;
                if(pParent->m_pElement)
                {
                  pParent->m_pElement->m_pHyperlinks->AddTail(pElement);
                }

                if(!m_pCurrentDependentNode)
                { 
                  //anchor should NEVER be top element:
                  HX_ASSERT(m_pCurrentDependentNode);
                } 
                else 
                { 
                  pNode->m_pDependency = m_pCurrentDependentNode;
                } 
                if(firstDependentChild(pNode) || m_pCurrentDependentNode == 0)
                { 
                  ulTrackHint = 1;
                  m_pTrackHintList->AddTail((void*)ulTrackHint);
                } 
                else 
                { 
                  if(m_pTrackHintList->GetCount() > 0)
                  {
                      ulTrackHint = (UINT32)m_pTrackHintList->RemoveTail();
                  }
                  m_pTrackHintList->AddTail((void*)++ulTrackHint);
                } 
                m_pCurrentDependentNode = pNode;
                m_pNodeDependencies->Push(m_pCurrentDependentNode);
                //end of part of fix for PR 26471.
            }
          }
          break;

          case SMILRef:
          case SMILText:
          case SMILImg:
          case SMILAudio:
          case SMILVideo:
          case SMILAnimation:
          case SMILTextstream:
          {
            CSmil1Source* pSource = makeSource(pNode);
            if(!pSource)
            {
                return HXR_FAIL;
            }
            m_bContainsSource = TRUE;
            pNode->m_pElement = pSource;

            CSmil1TimelineElement* pTimelineElement = 
                new CSmil1TimelineElement(pSource, this);

            pNode->m_pElement->m_pTimelineElement = pTimelineElement;

            // attach any links
            if(m_pCurrentAnchor)
            {
                pSource->m_pHyperlinks->AddTail(m_pCurrentAnchor);
            }

            if(!m_pCurrentDependentNode)
            {
                // make it behave like it's in a SEQ
                pNode->m_pDependency = 0;
                //pNode->m_nGroup = 0;
                m_pCurrentDependentNode = pNode;
                ulTrackHint = 1;
                m_pTrackHintList->AddTail((void*)ulTrackHint);
            }
            else
            {
                pNode->m_pDependency = m_pCurrentDependentNode;

                if(inSeq(pNode))
                {
                  if(firstDependentChild(pNode))
                  {
                      ulTrackHint = 1;
                      m_pTrackHintList->AddTail((void*)ulTrackHint);
                  }
                  else
                  {
                      if(m_pTrackHintList->GetCount() > 0)
                      {
                        ulTrackHint = 
                            (UINT32)m_pTrackHintList->RemoveTail();
                      }
                      m_pTrackHintList->AddTail((void*)++ulTrackHint);
                  }
                }
                else
                {
                  if(firstDependentChild(pNode))
                  {
                      ulTrackHint = 1;
                      m_pTrackHintList->AddTail((void*)ulTrackHint);
                  }
                }

                if(inSeq(pNode) && !hasParParent(pNode))
                {
                  if(firstDependentChild(pNode))
                  {
                      //pNode->m_nGroup = m_pCurrentDependentNode->m_nGroup;
                  }
                  else
                  {
                      //pNode->m_nGroup = 
                        //m_pCurrentDependentNode->m_nGroup + 1;
                  }
                  m_pCurrentDependentNode = pNode;
                }
                else if(inSeq(pNode))
                {
                  //pNode->m_nGroup = m_pCurrentDependentNode->m_nGroup;
                  m_pCurrentDependentNode = pNode;
                }
                else    // in PAR
                {
                  // pNode->m_nGroup = m_pCurrentDependentNode->m_nGroup;
                }
            }

            // set track hint info
            BOOL bFirstHint = TRUE;
            CHXSimpleList::Iterator hintIter = m_pTrackHintList->Begin();
            for(; hintIter != m_pTrackHintList->End(); ++hintIter)
            {
                char tmpBuf[20]; /* Flawfinder: ignore */

                UINT32 ulTrackHint = (UINT32)(*hintIter);
                if(bFirstHint)
                {
                  sprintf(tmpBuf, "%d", ulTrackHint); /* Flawfinder: ignore */
                  bFirstHint = FALSE;
                }
                else
                {
                  sprintf(tmpBuf, ".%d", ulTrackHint); /* Flawfinder: ignore */
                }
                pNode->m_trackHint += tmpBuf;
            }
          }
          break;

          default:
          break;
      }
      rc = createBodyElements(pNode->m_pNodeList);
      
      if (SUCCEEDED(rc))
      {
          rc = removeFromNamespaceScope(pNode);
      }
    }
    return rc;
}

HX_RESULT
CSmil1Parser::expandRepeatElements(SMIL1NodeList* pNodeList)
{
    // walk through tree and expand any "repeat" attributes
    
    HX_RESULT rc = HXR_OK;
    if(!pNodeList)
    {
      return rc;
    }

    LISTPOSITION lPos = pNodeList->GetHeadPosition();
    while (lPos && HXR_OK == rc)
    {
      SMIL1Node* pNode = (SMIL1Node*)pNodeList->GetAt(lPos);

      if(pNode->m_bDelete)    // skip this puppy
      {
          pNodeList->GetNext(lPos);
          continue;
      }

      if(pNode->m_pValues)
      {
          const char* pName = 0;
          IHXBuffer* pBuf = 0;

          if (!pNode->m_bRepeatHandled &&
            HXR_OK == pNode->m_pValues->GetPropertyCString("repeat", pBuf))
          {
            BOOL      bRepeatIndefinite = FALSE;
            const char* pRepeatCount = (const char*)pBuf->GetBuffer();
            if(pRepeatCount)
            {
                INT32 lRepeatCount = 0;

                if(strcmp(pRepeatCount, "indefinite") == 0)
                {
                  bRepeatIndefinite = TRUE;
                  lRepeatCount = 2;
                }
                else
                {
                  lRepeatCount = atol(pRepeatCount);
                }

                if(lRepeatCount == 0)
                {
                  pNode->m_bDelete = TRUE;
                }
                else if(lRepeatCount > 1)
                {
                  // build a <seq>/</seq> around the repeated element...
                  SMIL1Node* pSeqNode = NULL;
                  SMIL1Node* pSeqEndNode = NULL;
                  
                  createParent(pNode, SMILSeq, pSeqNode, pSeqEndNode);

                  SMIL1Node* pNodeCopy = NULL;
                  BOOL    bOverWrite = TRUE;
                  for(INT32 lCount = 0; lCount < lRepeatCount;
                      ++lCount)
                  {
                      // we want to keep the original ids for the
                      // 1st repeat so that we don't break any links
                      if (0 == lCount)
                      {
                        pNodeCopy = new SMIL1Node(*pNode, TRUE, this);
                        bOverWrite = TRUE;
                      }
                      else
                      {
                        pNodeCopy = new SMIL1Node(*pNode, FALSE, this);
                        bOverWrite = FALSE;
                      }
                        
                      pNodeCopy->m_pParent = pSeqNode;
                      pNodeCopy->m_pNodeList->m_pParentNode = pNodeCopy;
                      pNodeCopy->m_bRepeatHandled = TRUE;

                      // after the 1st repeat, mark the rest of repeats
                      // as replica(used in counting tracks etc.)
                      if (lCount > 0)
                      {
                        if (bRepeatIndefinite)
                        {
                            if (pNodeCopy->m_tag == SMILSeq ||
                              pNodeCopy->m_tag == SMILPar)
                            {
                              // set indefinite repeat tag on seq
                              // will be used in constructing timeline elements
                              pSeqNode->m_repeatTag = RepeatIndefiniteOnMe;
                              pNodeCopy->m_repeatTag = RepeatIndefiniteOnGroup;
                              markRepeatReplica(pNodeCopy->m_pNodeList, RepeatIndefiniteOnGroup);
                            }
                            else
                            {
                              pNodeCopy->m_repeatTag = RepeatIndefiniteOnMe;
                            }
                        }
                        else
                        {
                            pNodeCopy->m_repeatTag = RepeatReplica;
                            
                            if (pNodeCopy->m_tag == SMILSeq ||
                              pNodeCopy->m_tag == SMILPar)
                            {
                              markRepeatReplica(pNodeCopy->m_pNodeList, RepeatReplica);
                            }
                        }
                      }

                      mapID(pNodeCopy, bOverWrite);
                      //Fix for PR 13119: internal elements (source
                      // elements, especially) of a repeated <seq> or
                      // <par> tag were not getting mapped and thus
                      // never played, so we need to map the IDs of
                      // all in the m_pNodeList of the pNodeCopy:
                      mapChildrenIDs(pNodeCopy->m_pNodeList, bOverWrite);

                      pSeqNode->m_pNodeList->AddTail(pNodeCopy);
                  }
                  pSeqNode->m_pNodeList->AddTail(pSeqEndNode);

                  // special case to ensure all repeated elements
                  // are within the same group(share the same timeline)
                  if (!hasParParent(pSeqNode))
                  {
                      SMIL1Node* pParNode = NULL;
                      SMIL1Node* pParEndNode = NULL;

                      createParent(pSeqNode, SMILPar, pParNode, pParEndNode);

                      pParNode->m_repeatTag = pSeqNode->m_repeatTag;
                      pParNode->m_pNodeList->AddTail(pSeqNode);                   
                      pParNode->m_pNodeList->AddTail(pParEndNode);

                      // now add the list to the parent...
                      pNodeList->InsertBefore(lPos, pParNode);
                      pNode->m_bDelete = TRUE;  // delete original node
                      pNode = pParNode;
                  }
                  else
                  {
                      // now add the list to the parent...
                      pNodeList->InsertBefore(lPos, pSeqNode);
                      pNode->m_bDelete = TRUE;  // delete original node
                      pNode = pSeqNode;
                  }
                }
            }
          }
      }
      // breadth first
      rc = expandRepeatElements(pNode->m_pNodeList);
      pNodeList->GetNext(lPos);
    }
    return rc;
}

HX_RESULT
CSmil1Parser::createParent (SMIL1Node*    pChildNode, 
                     SMIL1NodeTag   tag,
                     SMIL1Node*&    pParent,
                     SMIL1Node*&    pParentEnd)
{
    HX_RESULT     hr = HXR_OK;

    pParent = NULL;
    pParentEnd = NULL;

    if (!pChildNode)
    {
      hr = HXR_FAILED;
      goto cleanup;
    }

    pParent = new SMIL1Node;                  
    pParent->m_pParent = pChildNode->m_pParent;
    pParent->m_tag = tag;
    
    pParent->m_pNodeList = new SMIL1NodeList;
    pParent->m_pNodeList->m_pParentNode = pParent;
    
    pParentEnd = new SMIL1Node;
    pParentEnd->m_pParent = pParent;

    if (SMILPar == tag)
    {
      pParent->m_name = "par";
      pParentEnd->m_name = "par";
      pParentEnd->m_id = assignID("CLOSE-par"); 
      pParentEnd->m_tag = SMILEndPar;
    }
    else if (SMILSeq == tag)
    {
      pParent->m_name = "seq";
      pParentEnd->m_name = "seq";
      pParentEnd->m_id = assignID("CLOSE-seq");
      pParentEnd->m_tag = SMILEndSeq;
    }
    else
    {
      HX_ASSERT(FALSE);
      hr = HXR_FAILED;
      goto cleanup;
    }
    
    mapID(pParent, TRUE);
    mapID(pParentEnd, TRUE);

cleanup:

    return hr;
}

void
CSmil1Parser::resetTimeline()
{
    if (m_pTimelineElementManager)
    {
        m_pTimelineElementManager->resetTimeline();
    }
}

SMIL1Node*
CSmil1Parser::getTimelineDescendent(SMIL1Node* pParentNode)
{
    SMIL1Node* pDescendentNode = NULL;

    CHXSimpleList* pNodeList = pParentNode->m_pNodeList;
    if(!pNodeList)
    {
      return pDescendentNode;
    }

    CHXSimpleList::Iterator i;
    for(i=pNodeList->Begin();i!=pNodeList->End();++i)
    {
      SMIL1Node* pNode = (SMIL1Node*)(*i);
      if(pNode->m_bDelete)
      {
          continue;
      }
      if(pNode->m_tag == SMILAAnchor ||
         pNode->m_tag == SMILSwitch)
      {
          pNode = getTimelineDescendent(pNode);
          if(pNode)
          {
            pDescendentNode = pNode;
            break;
          }
      }
      else
      {
          if(pNode->m_tag == SMILSeq ||
            pNode->m_tag == SMILPar ||
            pNode->m_tag == SMILRef ||
            pNode->m_tag == SMILText ||
            pNode->m_tag == SMILImg ||
            pNode->m_tag == SMILAudio ||
            pNode->m_tag == SMILVideo ||
            pNode->m_tag == SMILAnimation ||
            pNode->m_tag == SMILTextstream ||
            pNode->m_tag == SMILAnchor)
          {
            pDescendentNode = pNode;
            break;
          }
      }
    }
    return pDescendentNode;
}

SMIL1Node*
CSmil1Parser::getTimelineDescendent(SMIL1Node* pParentNode, SMIL1Node* pSiblingNode)
{
    SMIL1Node* pFirstDescendent = getTimelineDescendent(pParentNode);
    if(!pSiblingNode)
    {
      return pFirstDescendent;
    }

    // first, find parent of sibling
    SMIL1Node* pSiblingParent = pSiblingNode->m_pParent;
    while(pSiblingParent &&
        pSiblingParent->m_tag != SMILSeq &&
        pSiblingParent->m_tag != SMILPar)
    {
      pSiblingParent = pSiblingParent->m_pParent;
    }

    if(!pSiblingParent)
    {
      return NULL;
    }

    // now find the sibling, then next sibling will be 
    // returned. Brain damaged, but what are ya gonna do?
    BOOL bFoundSibling = FALSE;
    SMIL1Node* pNewSibling = NULL;
    CHXSimpleList::Iterator i = pSiblingParent->m_pNodeList->Begin();
    for(; i != pSiblingParent->m_pNodeList->End() && !pNewSibling; ++i)
    {
      SMIL1Node* pThisNode = (SMIL1Node*)(*i);

      if(pThisNode->m_bDelete)
      {
          continue;
      }

      if(pThisNode->m_tag == SMILAAnchor ||
          pThisNode->m_tag == SMILSwitch)
      {
          CHXSimpleList::Iterator j = pThisNode->m_pNodeList->Begin();

          for(; j != pThisNode->m_pNodeList->End(); ++j)
          {
            SMIL1Node* pChildNode = (SMIL1Node*)(*j);
            if(pChildNode->m_bDelete)
            {
                continue;
            }
            if(pChildNode == pSiblingNode)
            {
                bFoundSibling = TRUE;
                break;
            }
            else if(bFoundSibling)
            {
                pNewSibling = pChildNode;
                break;
            }
          }
      }
      else
      {
          if(pThisNode == pSiblingNode)
          {
            bFoundSibling = TRUE;
          }
          else if(bFoundSibling)
          {
            pNewSibling = pThisNode;
            break;
          }
      }
    }

    return pNewSibling;
}

HX_RESULT
CSmil1Parser::constructTimelineElements(SMIL1NodeList* pNodeList)
{
    HX_RESULT rc = HXR_OK;

    if(!pNodeList)
    {
      return rc;
    }

    CHXSimpleList::Iterator i;
    for(i=pNodeList->Begin();i!=pNodeList->End();++i)
    {
      if(HXR_OK != rc)
      {
          return rc;
      }

      SMIL1Node* pNode = (SMIL1Node*)(*i);

      if(pNode->m_bDelete)    // skip this puppy
      {
          continue;
      }

      switch(pNode->m_tag)
      {
          case SMILSeq:
          {
            SMIL1Node* pChildNode = getTimelineDescendent(pNode, NULL);
            CSmil1TimelineElement* pPrevElement = NULL;
            UINT16 uPrevGroup = (UINT16)-1;
            while(pChildNode)
            {
                if (pChildNode->m_pElement &&
                  pChildNode->m_pElement->m_pTimelineElement)
                {             
                  pNode->m_pElement->m_pTimelineElement->addChild(
                        pChildNode->m_pElement->m_pTimelineElement);

                  if(pPrevElement &&
                     uPrevGroup == pChildNode->m_nGroup)
                  {
                      pPrevElement->setDependent(pChildNode->m_pElement->m_pTimelineElement);
                  }
                  
                  pPrevElement = pChildNode->m_pElement->m_pTimelineElement;
                  uPrevGroup = pChildNode->m_nGroup;
                }

                // there is no dependent on pChildNode which would repeat 
                // itself indefinitely within the same seq
                if (pChildNode->m_repeatTag == RepeatIndefiniteOnMe)
                {
                  break;
                }
                
                pChildNode = getTimelineDescendent(pNode, pChildNode);
            }
          }
          break;

          case SMILPar:
          {
            SMIL1Node* pChildNode = getTimelineDescendent(pNode, NULL);
            while(pChildNode)
            {
                if(pChildNode->m_pElement &&
                   pChildNode->m_pElement->m_pTimelineElement)
                {
                  pNode->m_pElement->m_pTimelineElement->addChild(
                      pChildNode->m_pElement->m_pTimelineElement);
                }

                pChildNode = getTimelineDescendent(pNode, pChildNode);
            }
          }
          break;

          default:
          break;
      }
      rc = constructTimelineElements(pNode->m_pNodeList);
    }
    return rc;
}

HX_RESULT
CSmil1Parser::handleNextElement(CSmil1ElementHandler* pHandler)
{
    HX_RESULT rc = HXR_OK;
    if(m_pPacketQueue->GetCount() > 0)
    {
      CSmil1Element* pElement = (CSmil1Element*)m_pPacketQueue->RemoveHead();
      pElement->m_pHandler = pHandler;
      rc = pElement->handleElement();
    }
    else if(m_bTimestampsResolved)
    {
      rc = HXR_STREAM_DONE;
    }
    else
    {
      rc = HXR_NO_DATA;
    }

    return rc;
}

void
CSmil1Parser::initTagAttributes()
{
    if(!m_pTagAttributeMap)
    {
      m_pTagAttributeMap = new CHXMapLongToObj;
    }
    CHXMapStringToOb* pStringMap = 0;

    // SMILSmil
    pStringMap = new CHXMapStringToOb;
    (*pStringMap)["id"] = 0;
    (*m_pTagAttributeMap)[SMILSmil] = pStringMap;

    // SMILHead
    pStringMap = new CHXMapStringToOb;
    (*pStringMap)["id"] = 0;
    (*m_pTagAttributeMap)[SMILHead] = pStringMap;

    // SMILBasicLayout
    pStringMap = new CHXMapStringToOb;
    (*pStringMap)["id"] = 0;
    (*pStringMap)["type"] = 0;
    (*m_pTagAttributeMap)[SMILBasicLayout] = pStringMap;

    // SMILRegion
    pStringMap = new CHXMapStringToOb;
    (*pStringMap)["id"] = 0;
    (*pStringMap)["title"] = 0;
    (*pStringMap)["height"] = 0;
    (*pStringMap)["width"] = 0;
    (*pStringMap)["background-color"] = 0;
    (*pStringMap)["left"] = 0;
    (*pStringMap)["top"] = 0;
    (*pStringMap)["z-index"] = 0;
    (*pStringMap)["fit"] = 0;
    (*pStringMap)["skip-content"] = 0;
    (*m_pTagAttributeMap)[SMILRegion] = pStringMap;

    // SMILRootLayout
    pStringMap = new CHXMapStringToOb;
    (*pStringMap)["id"] = 0;
    (*pStringMap)["title"] = 0;
    (*pStringMap)["height"] = 0;
    (*pStringMap)["width"] = 0;
    (*pStringMap)["background-color"] = 0;
    (*pStringMap)["overflow"] = 0;
    (*pStringMap)["skip-content"] = 0;
    (*m_pTagAttributeMap)[SMILRootLayout] = pStringMap;

    // SMILMeta
    pStringMap = new CHXMapStringToOb;
    (*pStringMap)["name"] = 0;
    (*pStringMap)["content"] = 0;
    (*pStringMap)["skip-content"] = 0;
    (*m_pTagAttributeMap)[SMILMeta] = pStringMap;

    // SMILBody
    pStringMap = new CHXMapStringToOb;
    (*pStringMap)["id"] = 0;
    (*m_pTagAttributeMap)[SMILBody] = pStringMap;

    // SMILPar
    pStringMap = new CHXMapStringToOb;
    (*pStringMap)["id"] = 0;
    (*pStringMap)["title"] = 0;
    (*pStringMap)["abstract"] = 0;
    (*pStringMap)["author"] = 0;
    (*pStringMap)["copyright"] = 0;
    (*pStringMap)["endsync"] = 0;
    (*pStringMap)["dur"] = 0;
    (*pStringMap)["repeat"] = 0;
    (*pStringMap)["region"] = 0;
    (*pStringMap)["begin"] = 0;
    (*pStringMap)["end"] = 0;
    (*pStringMap)["system-bitrate"] = 0;
    (*pStringMap)["system-language"] = 0;
    (*pStringMap)["system-required"] = 0;
    (*pStringMap)["system-screen-size"] = 0;
    (*pStringMap)["system-screen-depth"] = 0;
    (*pStringMap)["system-captions"] = 0;
    (*pStringMap)["system-overdub-or-caption"] = 0;
    (*m_pTagAttributeMap)[SMILPar] = pStringMap;

    // SMILSeq
    pStringMap = new CHXMapStringToOb;
    (*pStringMap)["id"] = 0;
    (*pStringMap)["title"] = 0;
    (*pStringMap)["abstract"] = 0;
    (*pStringMap)["author"] = 0;
    (*pStringMap)["copyright"] = 0;
    (*pStringMap)["dur"] = 0;
    (*pStringMap)["repeat"] = 0;
    (*pStringMap)["region"] = 0;
    (*pStringMap)["begin"] = 0;
    (*pStringMap)["end"] = 0;
    (*pStringMap)["system-bitrate"] = 0;
    (*pStringMap)["system-language"] = 0;
    (*pStringMap)["system-required"] = 0;
    (*pStringMap)["system-screen-size"] = 0;
    (*pStringMap)["system-screen-depth"] = 0;
    (*pStringMap)["system-captions"] = 0;
    (*pStringMap)["system-overdub-or-caption"] = 0;
    (*m_pTagAttributeMap)[SMILSeq] = pStringMap;

    // SMILSwitch
    pStringMap = new CHXMapStringToOb;
    (*pStringMap)["id"] = 0;
    (*pStringMap)["title"] = 0;
    (*m_pTagAttributeMap)[SMILSwitch] = pStringMap;

    // SMILRef
    pStringMap = new CHXMapStringToOb;
    (*pStringMap)["id"] = 0;
    (*pStringMap)["title"] = 0;
    (*pStringMap)["abstract"] = 0;
    (*pStringMap)["author"] = 0;
    (*pStringMap)["copyright"] = 0;
    (*pStringMap)["region"] = 0;
    (*pStringMap)["alt"] = 0;
    (*pStringMap)["longdesc"] = 0;
    (*pStringMap)["src"] = 0;
    (*pStringMap)["type"] = 0;
    (*pStringMap)["dur"] = 0;
    (*pStringMap)["repeat"] = 0;
    (*pStringMap)["fill"] = 0;
    (*pStringMap)["begin"] = 0;
    (*pStringMap)["end"] = 0;
    (*pStringMap)["clip-begin"] = 0;
    (*pStringMap)["clip-end"] = 0;
    (*pStringMap)["skip-content"] = 0;
    (*pStringMap)["system-bitrate"] = 0;
    (*pStringMap)["system-language"] = 0;
    (*pStringMap)["system-required"] = 0;
    (*pStringMap)["system-screen-size"] = 0;
    (*pStringMap)["system-screen-depth"] = 0;
    (*pStringMap)["system-captions"] = 0;
    (*pStringMap)["system-overdub-or-caption"] = 0;
    (*m_pTagAttributeMap)[SMILRef] = pStringMap;

    // SMILAAnchor
    pStringMap = new CHXMapStringToOb;
    (*pStringMap)["id"] = 0;
    (*pStringMap)["title"] = 0;
    (*pStringMap)["href"] = 0;
    (*pStringMap)["show"] = 0;
    (*m_pTagAttributeMap)[SMILAAnchor] = pStringMap;

    // SMILAnchor
    pStringMap = new CHXMapStringToOb;
    (*pStringMap)["id"] = 0;
    (*pStringMap)["title"] = 0;
    (*pStringMap)["href"] = 0;
    (*pStringMap)["show"] = 0;
    (*pStringMap)["begin"] = 0;
    (*pStringMap)["end"] = 0;
    (*pStringMap)["coords"] = 0;
    (*pStringMap)["fragment-id"] = 0;
    (*pStringMap)["skip-content"] = 0;
    (*pStringMap)["z-index"] = 0;
    (*m_pTagAttributeMap)[SMILAnchor] = pStringMap;

    // SMILRendererPreFetch
    pStringMap = new CHXMapStringToOb;
    (*pStringMap)["type"] = 0;
    (*m_pTagAttributeMap)[SMILRendererPreFetch] = pStringMap;
}

void
CSmil1Parser::deleteTagAttributes()
{
    if(m_pTagAttributeMap)
    {
        CHXMapLongToObj::Iterator i = m_pTagAttributeMap->Begin();
      for(; i != m_pTagAttributeMap->End(); ++i)
      {
          CHXMapStringToOb* pStringMap = (CHXMapStringToOb*)(*i);
          delete pStringMap;
      }
    }
    HX_DELETE(m_pTagAttributeMap);
}

BOOL
CSmil1Parser::isLegalAttribute(SMIL1NodeTag tag, const char* pAttName)
{
    // use SMILRef for all media object checks
    if(tag == SMILText ||
       tag == SMILImg ||
       tag == SMILAudio ||
       tag == SMILVideo ||
       tag == SMILAnimation ||
       tag == SMILTextstream)
    {
      tag = SMILRef;
    }
    CHXMapStringToOb* pStringMap = 0;
    if(m_pTagAttributeMap->Lookup(tag, (void*&)pStringMap))
    {
      void* pVoid = 0;
      if(pStringMap->Lookup(pAttName, pVoid))
      {
          return TRUE;
      }
      else if (strcmp(pAttName, "xmlns") == 0 || 
          strncmp(pAttName, "xmlns:", 6) == 0)
      {
          // accept any namespace declarations.
          return TRUE;
      }
      else
      {
          BOOL bValidAttribute = FALSE;
          char* pColon = (char *)strchr(pAttName, ':');
          if(pColon)
          {
            //check for valid namespace tag we can
            // ignore

            char* pTmpNam = new_string(pAttName);
            char* pNamespace = strtok(pTmpNam, ":");
            if(pNamespace)
            {
                UINT32 ulTemp = 0;
                if(m_pActiveNamespaceMap &&
                  (m_pActiveNamespaceMap->Lookup(pNamespace,
                  (void*&)ulTemp)))
                {
                  // OK, we can ignore it...
                  bValidAttribute = TRUE;
                }
            }
            delete[] pTmpNam;
          }
          if(bValidAttribute)
          {
            return TRUE;
          }
      }
    }

    return FALSE;
}

BOOL
CSmil1Parser::isRelativeURL(const char* pURL)
{
    BOOL rc = TRUE;

    CHXURL urlObj(pURL);
    IHXValues* pHeader = urlObj.GetProperties();
    if(pHeader)
    {
        IHXBuffer* pBuffer = NULL;

      if(HXR_OK == pHeader->GetPropertyBuffer(PROPERTY_SCHEME, pBuffer))
      {
          // fully qualified URL
          rc = FALSE;
          HX_RELEASE(pBuffer);
      }
    }

    HX_RELEASE(pHeader);
    return rc;
}


HX_RESULT
CSmil1Parser::storeNamespaces(SMIL1Node* pNode)
{
    HX_RESULT rc = HXR_OK;

    if (pNode->m_pValues)
    {
      const char* pName = NULL;
      IHXBuffer* pBuffer = NULL;
      HX_RESULT res = pNode->m_pValues->GetFirstPropertyCString(pName, pBuffer);
      while (SUCCEEDED(rc) && SUCCEEDED(res))
      {
          if (strcmp(pName, "xmlns") == 0)
          {
            if (!pNode->m_pNamespaceList)
            {
                pNode->m_pNamespaceList = new CHXSimpleList;
                if (!pNode->m_pNamespaceList)
                {
                  rc = HXR_OUTOFMEMORY;
                  break;
                }
            }
            
            // duplicate atributes should allready be caught...
            SMIL1Namespace* pNS = new SMIL1Namespace("", pBuffer);
            pNode->m_pNamespaceList->AddHead(pNS);
          }
          else if (strncmp(pName, "xmlns:", 6) == 0)
          {
            if (!pNode->m_pNamespaceList)
            {
                pNode->m_pNamespaceList = new CHXSimpleList;
                if (!pNode->m_pNamespaceList)
                {
                  rc = HXR_OUTOFMEMORY;
                  break;
                }
            }

            char* nsPrefix = (char *)strchr(pName, ':');
            ++nsPrefix;

            SMIL1Namespace* pNS = new SMIL1Namespace(nsPrefix, pBuffer);
            pNode->m_pNamespaceList->AddHead(pNS);
          }

          HX_RELEASE(pBuffer);
          res = pNode->m_pValues->GetNextPropertyCString(pName, pBuffer);
      }
    }
    return rc;
}

HX_RESULT
CSmil1Parser::addToNamespaceScope(SMIL1Node* pNode)
{
    HX_RESULT rc = HXR_OK;

    if (!m_pActiveNamespaceMap)
    {
      m_pActiveNamespaceMap = new CHXMapStringToOb;
      if (!m_pActiveNamespaceMap)
      {
          return HXR_OUTOFMEMORY;
      }
    }

    if (pNode &&
      pNode->m_pNamespaceList)
    {
      for (CHXSimpleList::Iterator pIt = pNode->m_pNamespaceList->Begin();
           pIt != pNode->m_pNamespaceList->End(); ++pIt)
      {
          SMIL1Namespace* pNS = (SMIL1Namespace*)(*pIt);
          IHXBuffer* pBuf = (IHXBuffer*)(*m_pActiveNamespaceMap)[pNS->m_name];

          if (pBuf)
          {
            if (!m_pNSConflictList)
            {
                m_pNSConflictList = new CHXSimpleList;
                if (!m_pNSConflictList)
                {
                  rc = HXR_OUTOFMEMORY;
                  break;
                }
            }

            SMIL1Namespace* pConflict = new SMIL1Namespace(pNS);
            if (!pConflict)
            {
                rc = HXR_OUTOFMEMORY;
                break;
            }

            m_pNSConflictList->AddHead(pConflict);
            
            HX_RELEASE(pBuf);

            (*m_pActiveNamespaceMap)[pNS->m_name] = pNS->m_pValue;
            pNS->m_pValue->AddRef();
          }
          else
          {
            (*m_pActiveNamespaceMap)[pNS->m_name] = pNS->m_pValue;
            pNS->m_pValue->AddRef();
          }
      }
    }
    return rc;
}

HX_RESULT
CSmil1Parser::removeFromNamespaceScope(SMIL1Node* pNode)
{
    HX_RESULT rc = HXR_OK;
    
    if (pNode->m_pNamespaceList)
    {
      for (CHXSimpleList::Iterator pIt = pNode->m_pNamespaceList->Begin();
           pIt != pNode->m_pNamespaceList->End(); ++pIt)
      {
          SMIL1Namespace* pNS = (SMIL1Namespace*)(*pIt);

          HX_ASSERT((*m_pActiveNamespaceMap)[pNS->m_name]);
          IHXBuffer* pBuf = (IHXBuffer*)(*m_pActiveNamespaceMap)[pNS->m_name];

          if (pBuf != NULL)
          {
            HX_RELEASE(pBuf);
            m_pActiveNamespaceMap->RemoveKey(pNS->m_name);

            // check for conficts.
            if (m_pNSConflictList)
            {
                LISTPOSITION pos = m_pNSConflictList->GetHeadPosition();
                while (pos)
                {
                  SMIL1Namespace* pCon = 
                      (SMIL1Namespace*)m_pNSConflictList->GetAt(pos);

                  if (strcmp(pCon->m_name, pNS->m_name) == 0)
                  {
                      (*m_pActiveNamespaceMap)[pCon->m_name] = pCon->m_pValue;
                      pCon->m_pValue->AddRef();

                      HX_DELETE(pCon);

                      m_pNSConflictList->RemoveAt(pos);
                      // BREAK at the first found match.
                      break;
                  }

                  m_pNSConflictList->GetNext(pos);
                }
            }
          }
      }
    }
    return rc;
}


HX_RESULT
CSmil1Parser::addGlobalNamespace(const char* pNamespace,
                    const char* pPrefix)
{
    HX_RESULT rc = HXR_OK;

    if(m_bNoNamespaces)
    {
      rc = HXR_FAIL;
      CSmil1SMILSyntaxErrorHandler errHandler(m_pContext);
      errHandler.ReportError(SMILErrorSMIL10Document, NULL, 0);
    }
    else if (pNamespace)
    {
      if(!m_pActiveNamespaceMap)
      {
          m_pActiveNamespaceMap = new CHXMapStringToOb;
      }

      if (!m_pRequireTagsMap)
      {
          m_pRequireTagsMap = new CHXMapStringToOb;
      }

      if(pPrefix)
      {
          // get an IHXBuffer
          //XXXJEFFA should use CF for this
          IHXBuffer* pBuffer = (IHXBuffer*) new CHXBuffer;
          pBuffer->AddRef();
          pBuffer->Set((UINT8*)pNamespace, strlen(pNamespace) + 1);

          (*m_pActiveNamespaceMap)[pPrefix] = pBuffer;
          
          // add the prefix to the require map so system 
          // required checks work
          (*m_pRequireTagsMap)[pPrefix] = 0;

          if(strcmp(pPrefix, (const char*) RN_PREFIX) == 0)
          {
            m_bRNNamespace = TRUE;
          }
      }
      else
      {
          // empty prefix, 
          // don't ignore unrecognized elements...
          m_bIgnoreUnrecognizedElements = FALSE;
      }
    }

    return rc;
}


HX_RESULT
CSmil1Parser::storeError(HX_RESULT errCode, const char* pErrorString, 
                   const char* pFrameString, UINT32 ulLineNumber, 
                   UINT32 ulLinePosition, BOOL bXml)
{
    // XXXJHUG - this is what the SMIL error hanndler uses 1024....
    char errorString[1024]; /* Flawfinder: ignore */
    if (bXml)
    {
      CSmil1XMLSyntaxErrorHandler errHandler(m_pContext);
    
      errHandler.GetReportString(errCode, errorString);
    }
    else
    {
      CSmil1SMILSyntaxErrorHandler errHandler(m_pContext);
    
      errHandler.GetReportString((SMILErrorTag)errCode, errorString);
    }

    IHXBuffer* pBuf;
    m_pClassFactory->CreateInstance(CLSID_IHXBuffer, (void**)&pBuf);

    pBuf->SetSize(strlen(errorString) + strlen(pErrorString) + 10);
    char* buffer = (char*) pBuf->GetBuffer();
    sprintf(buffer, errorString, ulLineNumber, pErrorString); /* Flawfinder: ignore */

    m_pErrors->Add(pBuf);

    return HXR_OK;
}


HX_RESULT
CSmil1Parser::getErrors(CHXPtrArray** pErrs)
{
    *pErrs = m_pErrors;
    return HXR_OK;
}

ElementWithinTag
CSmil1Parser::GetElementWithin(const char* pID)
{
    ElementWithinTag    elementWithinTag = WithinUnknown;
    SMIL1Node*          pNode = NULL;
    SMIL1Node*          pParentNode = NULL;

    if(!m_pIDMap->Lookup(pID, (void*&)pNode))
    { 
      HX_ASSERT(FALSE);
      goto cleanup;
    }

    while (pNode->m_pParent)
    { 
      switch (pNode->m_pParent->m_tag)
      {
      case SMILPar:
          if (elementWithinTag == WithinSeq)
          {
            elementWithinTag = WithinSeqInPar;
          }
          else
          {
            elementWithinTag = WithinPar;
          }
          goto cleanup;
      case SMILSeq:
          elementWithinTag = WithinSeq;
          break;
      default:
          break;
      }

      pNode = pNode->m_pParent;
    }

cleanup:

    return elementWithinTag;
}

void
CSmil1Parser::InitPersistent(UINT32 ulPersistentComponentID, 
                      ElementWithinTag elementWithinTag)
{
    m_ulPersistentComponentID = ulPersistentComponentID;
    m_elementWithinTag = elementWithinTag;
}

/*
 * CSmil1ParserResponse methods
 */

CSmil1ParserResponse::CSmil1ParserResponse(CSmil1Parser* pParser)
:   m_pParser(pParser)
,   m_lRefCount(0)
{
}

CSmil1ParserResponse::~CSmil1ParserResponse()
{
}

STDMETHODIMP 
CSmil1ParserResponse::QueryInterface(REFIID riid, void** ppvObj)
{
    if (IsEqualIID(riid, IID_IUnknown))
    {
      AddRef();
      *ppvObj = this;
      return HXR_OK;
    }
    else if (IsEqualIID(riid, IID_IHXXMLParserResponse))
    {
      AddRef();
      *ppvObj = (IHXXMLParserResponse*)this;
      return HXR_OK;
    }

    *ppvObj = NULL;
    return HXR_NOINTERFACE;
}

STDMETHODIMP_(ULONG32) 
CSmil1ParserResponse::AddRef()
{
    return InterlockedIncrement(&m_lRefCount);
}

STDMETHODIMP_(ULONG32) 
CSmil1ParserResponse::Release()
{
    if (InterlockedDecrement(&m_lRefCount) > 0)
    {
        return m_lRefCount;
    }

    delete this;
    return 0;
}

STDMETHODIMP
CSmil1ParserResponse::HandleStartElement(const char* pName,
                         IHXValues* pAttributes,
                         UINT32 ulLineNumber,
                         UINT32 ulColumnNumber)
{
    HX_RESULT rc = HXR_OK;

    SMIL1Node* pParentNode = 
      (SMIL1Node*)m_pParser->m_pNodeListStack->TopOfStack();
    HX_ASSERT(pParentNode);

    SMIL1Node* pNode = new SMIL1Node;
    pNode->m_name = pName;
    pNode->m_pParent = pParentNode;

    pNode->m_pNodeList = new SMIL1NodeList;
    pNode->m_pNodeList->m_pParentNode = pNode;

    pNode->m_ulTagStartLine = ulLineNumber;
    pNode->m_ulTagStartColumn = ulColumnNumber;

    if(!pNode->m_pParent->m_bSkipContent)
    {
      IHXBuffer* pBuffer = NULL;
      if(HXR_OK == pAttributes->GetPropertyCString("id", pBuffer))
      {
          const char* pID = (const char*)pBuffer->GetBuffer();
          // XXXMEH - 04/27/99 - change this to still throw
          // an error for isspace(), but not for isdigit()
          // - not legal SMIL, but we still allowed
          // it in previous players.
//        if (isdigit(*pID) || isspace(*pID))
          if (isspace(*pID))
          {
            rc = HXR_XML_ILLEGALID;
            CSmil1XMLSyntaxErrorHandler errHandler(m_pParser->m_pContext);
            errHandler.ReportError(rc, pID, ulLineNumber);
            goto exit;
          }
          else if (m_pParser->m_bStoreErrors && isdigit(*pID))
          {
            m_pParser->storeError(HXR_XML_ILLEGALID, pID, 0, 
                ulLineNumber, ulColumnNumber);
          }
          else
          {
            // append persistent ID to the end of region id
            // to make it unique in nested meta
            if (!strcmp(pNode->m_name, "region"))
            {
                //char szPersistentComponentID[MAX_DISPLAY_NAME] = {0};
                //itoa(m_pParser->m_ulPersistentComponentID, szPersistentComponentID, 10);
            
                pNode->m_id = pID;
                //pNode->m_id += "_";
                //pNode->m_id += szPersistentComponentID;

                pNode->m_repeatid = pNode->m_id;
            }
            else
            {
                pNode->m_id = pID;
                pNode->m_repeatid = pID;
            }
            HX_RELEASE(pBuffer);
          }
      }
      else
      {
          //[SMIL 1.0 Compliance] Fixes PR 24034: region tag must have
          // an id attribute:
          if (m_pParser->m_bSMIL10FullCompliance  &&
                !strcmp(pNode->m_name, "region"))
          {
            rc = HXR_XML_ILLEGALID;
            CSmil1XMLSyntaxErrorHandler errHandler(m_pParser->m_pContext);
            const char* pTmp = "region id=\"\"";
            errHandler.ReportError(rc, pTmp, ulLineNumber);
            goto exit;
          }
          else
          {
            pNode->m_id = m_pParser->assignID(pName);
            pNode->m_repeatid = pNode->m_id;
          }

          if (m_pParser->m_bStoreErrors && !strcmp(pNode->m_name, "region"))
          {
            const char* pTmp = "region id=\"\"";
            m_pParser->storeError(HXR_XML_ILLEGALID, pTmp, 0, 
                ulLineNumber, ulColumnNumber);
          }
      }
      
      if(HXR_OK != m_pParser->mapID(pNode))
      {
          rc = HXR_XML_ILLEGALID;
          CSmil1XMLSyntaxErrorHandler errHandler(m_pParser->m_pContext);
          errHandler.ReportError(rc, pNode->m_id, ulLineNumber);
          goto exit;
      }

      if(strcmp(pName, "smil") == 0)
      {
          pNode->m_tag = SMILSmil;
      }
      else if(strcmp(pName, "layout") == 0)
      {
          pNode->m_tag = SMILBasicLayout;
          if(HXR_OK == pAttributes->GetPropertyCString("type", pBuffer))
          {
            const char* pType = (const char*)pBuffer->GetBuffer();
            if(strcmp(pType, "text/smil-basic-layout") != 0)
            {
                pNode->m_bDelete = TRUE;  // only basic layout supported
            }
            HX_RELEASE(pBuffer);
          }
      }
      else if(strcmp(pName, "meta") == 0)
      {
          pNode->m_tag = SMILMeta;
          pNode->m_bSkipContent = TRUE;
      }
      else if(strcmp(pName, "head") == 0)
      {
          pNode->m_id = "head";
          pNode->m_tag = SMILHead;
      }
      else if(strcmp(pName, "body") == 0)
      {
          pNode->m_id = "body";
          pNode->m_tag = SMILBody;
      }
      else if(strcmp(pName, "region") == 0)
      {
          pNode->m_tag = SMILRegion;
          pNode->m_bSkipContent = TRUE;
      }
      else if(strcmp(pName, "root-layout") == 0)
      {
          pNode->m_tag = SMILRootLayout;
          pNode->m_bSkipContent = TRUE;
      }
      else if(strcmp(pName, "switch") == 0)
      {
          pNode->m_tag = SMILSwitch;
      }
      else if(strcmp(pName, "text") == 0)
      {
          pNode->m_tag = SMILText;
      }
      else if(strcmp(pName, "img") == 0)
      {
          pNode->m_tag = SMILImg;
      }
      else if(strcmp(pName, "ref") == 0)
      {
          pNode->m_tag = SMILRef;
      }
      else if(strcmp(pName, "audio") == 0)
      {
          pNode->m_tag = SMILAudio;
      }
      else if(strcmp(pName, "video") == 0)
      {
          pNode->m_tag = SMILVideo;
      }
      else if(strcmp(pName, "animation") == 0)
      {
          pNode->m_tag = SMILAnimation;
      }
      else if(strcmp(pName, "textstream") == 0)
      {
          pNode->m_tag = SMILTextstream;
      }
      else if(strcmp(pName, "a") == 0)
      {
          pNode->m_tag = SMILAAnchor;
      }
      else if(strcmp(pName, "anchor") == 0)
      {
          pNode->m_tag = SMILAnchor;
          pNode->m_bSkipContent = TRUE;
      }
      else if(strcmp(pName, "par") == 0)
      {
          pNode->m_tag = SMILPar;
      }
      else if(strcmp(pName, "seq") == 0)
      {
          pNode->m_tag = SMILSeq;
      }
      else if(m_pParser->m_bRNNamespace && 
          strcmp(pName, (const char*) RN_TAG_RENDERER_LIST) == 0)
      {
          pNode->m_id = m_pParser->assignID((const char*) RN_TAG_RENDERER_LIST);
          pNode->m_tag = SMILRNRendererList;
      }
      else if(strcmp(pName, (const char*) RN_TAG_RENDERER) == 0)
      {
          pNode->m_tag = SMILRendererPreFetch;
      }
      else 
      {
          BOOL bValidTag = FALSE;
          char* pColon = (char *)strchr(pName, ':');
          if(pColon)
          {
            //check for valid namespace tag we can
            // ignore

            char* pTmpNam = new_string(pName);
            char* pNamespace = strtok(pTmpNam, ":");
            if(pNamespace)
            {
                UINT32 ulTemp = 0;
                if(m_pParser->m_pActiveNamespaceMap &&
                  (m_pParser->m_pActiveNamespaceMap->Lookup(pNamespace,
                  (void*&)ulTemp)))
                {
                  // OK, we can ignore it...
                  bValidTag = TRUE;
                }
            }
            delete[] pTmpNam;
          }
          if(!bValidTag && 
            !m_pParser->m_bIgnoreUnrecognizedElements)
          {
            rc = HXR_FAIL;
            CSmil1SMILSyntaxErrorHandler errHandler(m_pParser->m_pContext);
            errHandler.ReportError(SMILErrorUnrecognizedTag, pName, ulLineNumber);
            goto exit;
          }
          else
          {
            pNode->m_bDelete = TRUE;      // don't ask, don't tell...
          }

          if (!bValidTag && m_pParser->m_bStoreErrors)
          {
            m_pParser->storeError(SMILErrorUnrecognizedTag, pName, 0, 
                ulLineNumber, ulColumnNumber, FALSE);
          }
      }

      pNode->m_pValues = pAttributes;
      pNode->m_pValues->AddRef();

      rc = m_pParser->storeNamespaces(pNode);
      if (SUCCEEDED(rc))
      {
          rc = m_pParser->addToNamespaceScope(pNode);
      }

      const char* pName = NULL;
      HX_RESULT res = pAttributes->GetFirstPropertyCString(pName, pBuffer);
      while(HXR_OK == res && SUCCEEDED(rc))
      {
          const char* pActualValue = (const char*)pBuffer->GetBuffer();

          if(!m_pParser->isLegalAttribute(pNode->m_tag, pName) )
          {
            if (!m_pParser->m_bIgnoreUnrecognizedElements)
            {
                rc = HXR_FAIL;
                m_pParser->badAttributeError(pNode->m_tag, pName,
                  pNode->m_ulTagStartLine, FALSE);
                break;
            }
            
            if (m_pParser->m_bStoreErrors)
            {
                m_pParser->badAttributeError(pNode->m_tag, pName, 
                  ulLineNumber, TRUE);
            }

          }

          if(strcmp(pName, "skip-content") == 0)
          {
            if(strcmp(pActualValue, "true") == 0)
            {
                pNode->m_bSkipContent = TRUE;
            }
            else
            {
                pNode->m_bSkipContent = FALSE;
            }
          }
          HX_RELEASE(pBuffer);
          res = pAttributes->GetNextPropertyCString(pName, pBuffer);
      }

      m_pParser->m_pNodeListStack->Push(pNode);
    }

exit:
    return rc;
}

STDMETHODIMP
CSmil1ParserResponse::HandleEndElement(const char* pName,
                              UINT32 ulLineNumber,
                              UINT32 ulColumnNumber)
{
    HX_RESULT rc = HXR_OK;

    SMIL1Node* pCurrentNode = (SMIL1Node*)m_pParser->m_pNodeListStack->Pop();
    SMIL1Node* pParentNode = (SMIL1Node*)m_pParser->m_pNodeListStack->TopOfStack();
    HX_ASSERT(pCurrentNode);
    HX_ASSERT(pParentNode);

    if (pParentNode)
    {
        pParentNode->m_pNodeList->AddTail(pCurrentNode);
    }

    SMIL1Node* pEndNode = new SMIL1Node;
    pEndNode->m_name = pName;
    pEndNode->m_id.Format("CLOSE-%s", pName);
    pEndNode->m_pParent = pParentNode;
    pEndNode->m_ulTagStartLine = ulLineNumber;
    pEndNode->m_ulTagStartColumn = ulColumnNumber;

    if(strcmp(pName, "seq") == 0)
    {
      pEndNode->m_tag = SMILEndSeq;
    }
    else if(strcmp(pName, "par") == 0)
    {
      pEndNode->m_tag = SMILEndPar;
    }
    else if(strcmp(pName, "a") == 0)
    {
      pEndNode->m_tag = SMILEndAAnchor;
    }

    pCurrentNode->m_pNodeList->AddTail(pEndNode);

    rc = m_pParser->removeFromNamespaceScope(pCurrentNode);

    return rc;
}

STDMETHODIMP
CSmil1ParserResponse::HandleCharacterData(IHXBuffer* pBuffer,
                               UINT32 ulLineNumber,
                               UINT32 ulColumnNumber)
{
    HX_RESULT rc = HXR_OK;

    return rc;
}

STDMETHODIMP
CSmil1ParserResponse::HandleProcessingInstruction(const char* pTarget,
                                IHXValues* pAttributes,
                                UINT32 ulLineNumber,
                                UINT32 ulColumnNumber)
{
    HX_RESULT rc = HXR_OK;

    if(strcmp(pTarget, "xml:namespace") == 0)
    {
      IHXBuffer* pNamespaceBuffer = NULL;
      IHXBuffer* pPrefixBuffer = NULL;
      const char* pNamespace = NULL;
      const char* pPrefix = NULL;
      if(HXR_OK == pAttributes->GetPropertyCString("ns", pNamespaceBuffer))
      {
          pNamespace = (const char*)pNamespaceBuffer->GetBuffer();
      }
      if(HXR_OK == pAttributes->GetPropertyCString("prefix", pPrefixBuffer))
      {
          pPrefix = (const char*)pPrefixBuffer->GetBuffer();
      }
      rc = m_pParser->addGlobalNamespace(pNamespace, pPrefix);
      HX_RELEASE(pNamespaceBuffer);
      HX_RELEASE(pPrefixBuffer);
    }
    return rc;
}

STDMETHODIMP
CSmil1ParserResponse::HandleUnparsedEntityDecl(const char* /*IN*/  pEntityName,
                              const char* /*IN*/  pSystemID,
                              const char* /*IN*/  pPublicID,
                              const char* /*IN*/  pNotationName,
                              UINT32 ulLineNumber,
                              UINT32 ulColumnNumber)
{
    HX_RESULT rc = HXR_OK;

    return rc;
}

STDMETHODIMP
CSmil1ParserResponse::HandleNotationDecl(const char* /*IN*/  pNotationName,
                        const char* /*IN*/  pSystemID,
                        const char* /*IN*/  pPublicID,
                        UINT32 ulLineNumber,
                        UINT32 ulColumnNumber)
{
    HX_RESULT rc = HXR_OK;

    return rc;
}

STDMETHODIMP
CSmil1ParserResponse::HandleUnparsedDoctypeDecl(const char*  /*IN*/ pName, 
                                  const char*  /*IN*/ pSystemID,
                                  const char*  /*IN*/ pPublicID, 
                                  UINT32   /*IN*/     ulLineNumber,
                                  UINT32   /*IN*/     ulColumNumber)
{
    HX_RESULT rc = HXR_OK;

    if(strcmp(pName, "smil") == 0 &&
       strcmp(pSystemID, "http://www.w3.org/TR/REC-smil/SMIL10.dtd") == 0 &&
       strcmp(pPublicID, "-//W3C//DTD SMIL 1.0//EN") == 0)
    {
      // only be strict, still allow namespaces...
      //m_pParser->m_bNoNamespaces = TRUE;
      m_pParser->m_bIgnoreUnrecognizedElements = FALSE;
    }

    return rc;
}

STDMETHODIMP
CSmil1ParserResponse::HandleComment(const char* /*IN*/  pComment,
                           UINT32 ulLineNumber,
                           UINT32 ulColumnNumber)
{
    HX_RESULT rc = HXR_OK;

    return rc;
}

STDMETHODIMP
CSmil1ParserResponse::HandleDefault(IHXBuffer*  /*IN*/      pBuffer,
                           UINT32 ulLineNumber,
                           UINT32 ulColumnNumber)
{
    HX_RESULT rc = HXR_OK;

    return rc;
}

HX_RESULT
CSmil1ParserResponse::ErrorInLastTag(HX_RESULT err, 
    const char* pErrorString, const char* pFrameString, 
    UINT32 ulLineNumber, UINT32 ulLinePosition)
{
    // XXXJHUG - we could add the error to the actual node...
    // SMIL1Node* pCurrentNode = (SMIL1Node*)m_pParser->m_pNodeListStack->Pop();
    // pCurrentNode->m_errs->Add
    //

    // If we were going to warn for errors I think the warnings should be
    // thrown from here.  (modify ReportError to have a warning level.)
    //
    // But for dumping the errors there is no benifit for this.
    // therefore we will just add the error to a ptr array of errors.
    // this array will also be added to when the SMIL attributes are bad.
    //
    // XXX to store in the parse tree you also have to make sure the last
    // call was a tag, and not a PI or a directive or something that was 
    // ignored.
    
    return m_pParser->storeError(err, pErrorString, pFrameString, 
          ulLineNumber, ulLinePosition);
}

/*
 * SMIL1Node methods
 */

SMIL1Node::SMIL1Node():
    m_pNodeList(0),
    m_pParent(0),
    m_pDependency(0),
    m_tag(SMILUnknown),
    m_num(0),
    m_pValues(0),
    m_curPosition(0),
    m_pElement(0),
    m_nGroup((UINT16)-1),
    m_bLastInGroup(FALSE),
    m_bDelete(FALSE),
    m_bSkipContent(FALSE),
    m_pNamespaceList(NULL),
    m_bRepeatHandled(FALSE),
    m_repeatTag(RepeatUnknown)
{
}

SMIL1Node::SMIL1Node(const SMIL1Node& rhs, BOOL bKeepId, CSmil1Parser* pParser)
{
    if (bKeepId)
    {
      m_id = rhs.m_id;
    }
    else
    {
      // need a unique ID, so make one...
      char* pIDName = new char [256];
        if (pIDName && pParser)
        {
          sprintf(pIDName, "node_copy_%ld", pParser->GetUniqueNumber()); /* Flawfinder: ignore */
          m_id = pIDName;
        }
        HX_VECTOR_DELETE(pIDName);
    }

    m_repeatid = rhs.m_repeatid;
    m_pParent = rhs.m_pParent;
    m_pDependency = rhs.m_pDependency;
    m_tag = rhs.m_tag;
    m_num = rhs.m_num;
    m_curPosition = rhs.m_curPosition;
    m_pElement = rhs.m_pElement;
    m_nGroup = rhs.m_nGroup;
    m_bLastInGroup = rhs.m_bLastInGroup;
    m_bDelete = rhs.m_bDelete;
    m_bSkipContent = rhs.m_bSkipContent;
    m_bRepeatHandled = FALSE;
    m_repeatTag = rhs.m_repeatTag;

    if(rhs.m_pValues)
    {
      m_pValues = rhs.m_pValues;
      m_pValues->AddRef();
    }
    else
    {
      m_pValues = NULL;
    }
    if(rhs.m_pNodeList)
    {
      m_pNodeList = rhs.m_pNodeList->copy(this, bKeepId, pParser);
    }
    else
    {
      m_pNodeList = NULL;
    }
    if (rhs.m_pNamespaceList)
    {
      m_pNamespaceList = new CHXSimpleList;
      for (CHXSimpleList::Iterator pIt = rhs.m_pNamespaceList->Begin();
           pIt != rhs.m_pNamespaceList->End(); ++pIt)
      {
          SMIL1Namespace* pNS = (SMIL1Namespace*)(*pIt);
          SMIL1Namespace* pNewNS = new SMIL1Namespace(pNS);
          m_pNamespaceList->AddHead(pNewNS);
      }
    }
    else
    {
      m_pNamespaceList = NULL;
    }
}

SMIL1Node::~SMIL1Node()
{
    HX_DELETE(m_pNodeList);
    HX_RELEASE(m_pValues);

    if (m_pNamespaceList) 
    {
      while (!m_pNamespaceList->IsEmpty())
      {
          SMIL1Namespace* pNS = (SMIL1Namespace*)m_pNamespaceList->RemoveHead();
          HX_DELETE(pNS);
      }
    }
    HX_DELETE(m_pNamespaceList);
}

SMIL1Node*
SMIL1Node::getFirstChild()
{
    if(!m_pNodeList)
    {
      return 0;
    }
    m_curPosition = m_pNodeList->GetHeadPosition();
    if(m_curPosition)
    {
      return (SMIL1Node*)m_pNodeList->GetNext(m_curPosition);
    }
    return 0;
}

SMIL1Node*
SMIL1Node::getNextChild()
{
    if(m_curPosition)
    {
      return (SMIL1Node*)m_pNodeList->GetNext(m_curPosition);
    }
    return 0;
}

SMIL1NodeList::SMIL1NodeList():
    m_pParentNode(0)
{
}

SMIL1NodeList::~SMIL1NodeList()
{
    CHXSimpleList::Iterator i;

    for(i = Begin(); i != End(); ++i)
    {
      SMIL1Node* pNode = (SMIL1Node*)(*i);
      HX_DELETE(pNode);
    }
}

SMIL1NodeList*
SMIL1NodeList::copy(SMIL1Node* pParent, BOOL bKeepId, CSmil1Parser* pParser)
{
    SMIL1NodeList* pNewList = new SMIL1NodeList;
    m_pParentNode = pParent;

    CHXSimpleList::Iterator i = Begin();
    for(; i != End(); ++i)
    {
      SMIL1Node* pNode = (SMIL1Node*)(*i);
      SMIL1Node* pNodeCopy = new SMIL1Node(*pNode, bKeepId, pParser);
      pNodeCopy->m_pParent = pParent;
      pNewList->AddTail(pNodeCopy);
    }
    return pNewList;
}

Generated by  Doxygen 1.6.0   Back to index