smlparse.cpp
上传用户:zhongxx05
上传日期:2007-06-06
资源大小:33641k
文件大小:879k
源码类别:

Symbian

开发平台:

C/C++

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Version: RCSL 1.0/RPSL 1.0
  3.  *
  4.  * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved.
  5.  *
  6.  * The contents of this file, and the files included with this file, are
  7.  * subject to the current version of the RealNetworks Public Source License
  8.  * Version 1.0 (the "RPSL") available at
  9.  * http://www.helixcommunity.org/content/rpsl unless you have licensed
  10.  * the file under the RealNetworks Community Source License Version 1.0
  11.  * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl,
  12.  * in which case the RCSL will apply. You may also obtain the license terms
  13.  * directly from RealNetworks.  You may not use this file except in
  14.  * compliance with the RPSL or, if you have a valid RCSL with RealNetworks
  15.  * applicable to this file, the RCSL.  Please see the applicable RPSL or
  16.  * RCSL for the rights, obligations and limitations governing use of the
  17.  * contents of the file.
  18.  *
  19.  * This file is part of the Helix DNA Technology. RealNetworks is the
  20.  * developer of the Original Code and owns the copyrights in the portions
  21.  * it created.
  22.  *
  23.  * This file, and the files included with this file, is distributed and made
  24.  * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  25.  * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  26.  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
  27.  * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
  28.  *
  29.  * Technology Compatibility Kit Test Suite(s) Location:
  30.  *    http://www.helixcommunity.org/content/tck
  31.  *
  32.  * Contributor(s):
  33.  *
  34.  * ***** END LICENSE BLOCK ***** */
  35. // system
  36. #include <time.h>
  37. #include <math.h>
  38. #if defined(_UNIX)  &&  (!(defined(_BEOS))) && (!(defined(_MAC_UNIX)))
  39. /*for Display and Screen structs and X functions:*/
  40. #include "hlxclib/string.h"
  41. #include <X11/X.h>
  42. #include <X11/Xlib.h>
  43. #include <X11/Xutil.h>
  44. #include <X11/Xos.h>
  45. #include <sys/types.h>
  46. #endif
  47. #if defined (_SYMBIAN)
  48. #include <hal.h>
  49. #include <coemain.h>
  50. #include <e32svr.h>
  51. #include <e32math.h>
  52. #endif
  53. // include
  54. #include "hxtypes.h"
  55. #include "hxwintyp.h"
  56. #include "hxcom.h"
  57. #include "hxcomm.h"
  58. #include "hxprefs.h"
  59. #include "hxxml.h"
  60. #include "hxmon.h"
  61. #include "smiltype.h"
  62. #include "hxupgrd.h"
  63. // pncont
  64. #include "chxpckts.h"
  65. #include "hxstring.h"
  66. #include "hxslist.h"
  67. #include "rtsputil.h"
  68. #include "hxstack.h"
  69. // pnmisc
  70. #include "nptime.h"
  71. #include "smpte.h"
  72. #include "hxstrutl.h"
  73. #include "hxurl.h"
  74. #include "hxparse.h"
  75. #include "hxwinver.h"
  76. #include "dbcs.h" /* for HXGetNextChar() */
  77. // rnxmllib
  78. #include "xmlreslt.h"
  79. #include "hxxmlprs.h"
  80. // rmasmil
  81. #include "smlelem.h"
  82. #include "smltime.h"
  83. #include "smlerror.h"
  84. #include "smlprstime.h"
  85. #include "animattr.h"
  86. #include "binrymap.h"
  87. #include "smlparse.h"
  88. #include "parstabl.h"
  89. #include "smlutil.h"
  90. // pndebug
  91. #include "hxheap.h"
  92. #ifdef _DEBUG
  93. #undef HX_THIS_FILE
  94. static const char HX_THIS_FILE[] = __FILE__;
  95. #endif
  96. #define TARGET_OF_LINK_DESTINATION_SOUND_LEVEL_STR "targetOfLinkDestnSndLevel"
  97. #define TARGET_OF_LINK_SOURCE_SOUND_LEVEL_STR      "targetOfLinkSourceSndLevel"
  98. #if defined(_DEBUG)
  99. // /#define XXXEHODGE_DEBUG_EXCL_TRACK_REMOVAL
  100. #if defined(XXXEHODGE_DEBUG_EXCL_TRACK_REMOVAL)
  101. static BOOL bFirstExclTrackChangeDebugOut = TRUE;
  102. #endif
  103. #endif
  104. #if defined(_DEBUG)
  105. // /#define XXXEHODGE_DEBUG_RESETTIMELINEELEMENTDUR_AND_DELAY
  106. #if defined(XXXEHODGE_DEBUG_RESETTIMELINEELEMENTDUR_AND_DELAY)
  107. static BOOL bFirstResetTimelineElementDuration = TRUE;
  108. #endif /*XXXEHODGE_DEBUG_RESETTIMELINEELEMENTDUR_AND_DELAY*/
  109. #endif /*_DEBUG*/
  110. // /This enables RealPlayer 8 (and prior) behavior when there is no explicit
  111. // outer time container (seq, par, [or excl in a SMIL 2.0 doc]):
  112. #define ALLOW_PLAYLIST_STYLE_SEQ  1
  113. #define DONT_ALLOW_PLAYLIST_STYLE_SEQ_IF_EXPLICIT_OUTER_TIMECONTAINER  1
  114. #define CHECKPENDING_TIME_VS_CURTIME_FUDGE_FACTOR   150 /* in milliseconds .*/
  115. // /XXXEH- in order to get Interop Timing #25.6 working, we had to trick the
  116. // core into staying alive by adding this track in slightly before the one
  117. // that paused it has finished:
  118. #define FUDGE_FACTOR_WHEN_DEFERRING_PAST_END_OF_GROUP     100 /*milliseconds*/
  119. #define FUDGE_FACTOR_FOR_DEFERRING_PRIOR_TO_END_OF_GROUP  500 /*milliseconds*/
  120. static const UINT32 MAX_DRIVER_PACKET_SIZE = 1024;
  121. static const UINT32 INITIAL_STREAM1_TIMESTAMP = 1;
  122. static const UINT32 INITIAL_STREAM0_TIMESTAMP = 0;
  123. static const UINT32 MAX_ERROR_LEN = 1024;
  124. static const char* const RN_PREFIX = "rn";
  125. static const char* const RN_TAG_RENDERER_LIST = "rn:renderer-list";
  126. static const char* const RN_TAG_RENDERER = "rn:renderer";
  127. static const char* const SYSTEM_COMPONENT_NAMESPACE = "http://features.real.com/systemComponent";
  128. static const char* const SYSTEM_COMPONENT = "systemComponent";
  129. // /These are all the SMIL Module namespaces recognized by the
  130. // SMIL 2.0 Language:
  131. // (From http://www.w3.org/AudioVideo/Group/Modules/
  132. // smil-modules.html#smilModulesNSSMIL20ModuleIdentifiers)
  133. const char* const CSmilParser::zm_pSupportedSMIL2ModuleNamespaces[
  134. NUM_SUPPORTED_SMIL_2_0_MODULE_NAMESPACES+1] =
  135. {
  136.     // /XXXEH- TODO: OPTIMIZATION: these all share the same base URL, so
  137.     // we should just store the last part here and combine with the base
  138.     // when comparing to a used namespace:
  139.     "http://www.w3.org/2000/SMIL20/CR/NestedTimeContainers",
  140.     "http://www.w3.org/2000/SMIL20/CR/DeprecatedFeatures",
  141.     "http://www.w3.org/2000/SMIL20/CR/HostLanguage",
  142. #if defined(HANDLE_CATCHALL_NS_FOR_ALL_SMIL_2_0_MODULES)
  143.     "http://www.w3.org/2000/SMIL20/CR/",
  144. #else
  145.     "",
  146. #endif
  147.     "http://www.w3.org/2000/SMIL20/CR/Language",
  148.     "http://www.w3.org/2000/SMIL20/CR/IntegrationSet",
  149.     // /The rest are SMIL 2.0 Module namespaces:
  150.     "http://www.w3.org/2000/SMIL20/CR/AccessKeyTiming",
  151.     "http://www.w3.org/2000/SMIL20/CR/AudioLayout",
  152.     "http://www.w3.org/2000/SMIL20/CR/BasicAnimation",
  153.     "http://www.w3.org/2000/SMIL20/CR/BasicContentControl",
  154.     "http://www.w3.org/2000/SMIL20/CR/BasicInlineTiming",
  155.     "http://www.w3.org/2000/SMIL20/CR/BasicLayout",
  156.     "http://www.w3.org/2000/SMIL20/CR/BasicLinking",
  157.     "http://www.w3.org/2000/SMIL20/CR/BasicMedia",
  158.     "http://www.w3.org/2000/SMIL20/CR/BasicTimeContainers",
  159.     "http://www.w3.org/2000/SMIL20/CR/BasicTransistions",
  160.     "http://www.w3.org/2000/SMIL20/CR/BrushMedia",
  161.     "http://www.w3.org/2000/SMIL20/CR/CoordinatedTransitions",
  162.     "http://www.w3.org/2000/SMIL20/CR/CustomTestAttributes",
  163.     "http://www.w3.org/2000/SMIL20/CR/EventTiming",
  164.     "http://www.w3.org/2000/SMIL20/CR/ExclTimeContainers",
  165.     "http://www.w3.org/2000/SMIL20/CR/FillDefault",
  166.     "http://www.w3.org/2000/SMIL20/CR/HierarchicalLayout",
  167. #if defined(HANDLE_SMIL_2_0_INLINETRANSITIONS_MODULE)
  168.     "http://www.w3.org/2000/SMIL20/CR/InlineTransitions",
  169. #else
  170.     "",
  171. #endif
  172.     "http://www.w3.org/2000/SMIL20/CR/LinkingAttributes",
  173.     "http://www.w3.org/2000/SMIL20/CR/MediaAccessibility",
  174.     "http://www.w3.org/2000/SMIL20/CR/MediaClipMarkers",
  175.     "http://www.w3.org/2000/SMIL20/CR/MediaClipping",
  176.     "http://www.w3.org/2000/SMIL20/CR/MediaDescription",
  177.     "http://www.w3.org/2000/SMIL20/CR/MediaMarkerTiming",
  178.     "http://www.w3.org/2000/SMIL20/CR/MediaParam",
  179.     "http://www.w3.org/2000/SMIL20/CR/Metainformation",
  180.     "http://www.w3.org/2000/SMIL20/CR/MinMaxTiming",
  181.     "http://www.w3.org/2000/SMIL20/CR/MultiArcTiming",
  182.     "http://www.w3.org/2000/SMIL20/CR/MultiWindowLayout",
  183.     "http://www.w3.org/2000/SMIL20/CR/ObjectLinking",
  184.     "http://www.w3.org/2000/SMIL20/CR/PrefetchControl",
  185.     "http://www.w3.org/2000/SMIL20/CR/PrevTiming",
  186.     "http://www.w3.org/2000/SMIL20/CR/RepeatTiming",
  187.     "http://www.w3.org/2000/SMIL20/CR/RepeatValueTiming",
  188.     "http://www.w3.org/2000/SMIL20/CR/RestartDefault",
  189.     "http://www.w3.org/2000/SMIL20/CR/RestartTiming",
  190.     "http://www.w3.org/2000/SMIL20/CR/SkipContentControl",
  191. #if defined(HANDLE_SMIL_2_0_SPLINEANIMATION_MODULE)
  192.     "http://www.w3.org/2000/SMIL20/CR/SplineAnimation",
  193. #else
  194.     "",
  195. #endif
  196.     "http://www.w3.org/2000/SMIL20/CR/Structure",
  197.     "http://www.w3.org/2000/SMIL20/CR/SyncbaseTiming",
  198.     "http://www.w3.org/2000/SMIL20/CR/SyncBehavior",
  199.     "http://www.w3.org/2000/SMIL20/CR/SyncBehaviorDefault",
  200. #if defined(HANDLE_SMIL_2_0_SYNCMASTER_MODULE)
  201.     "http://www.w3.org/2000/SMIL20/CR/SyncMaster",
  202. #else
  203.     "",
  204. #endif
  205.     "http://www.w3.org/2000/SMIL20/CR/TimeContainerAttributes",
  206. #if defined(HANDLE_SMIL_2_0_TIME_MANIPULATIONS_MODULE)
  207.     "http://www.w3.org/2000/SMIL20/CR/TimeManipulations",
  208. #else
  209.     "",
  210. #endif
  211.     "http://www.w3.org/2000/SMIL20/CR/TransitionModifiers",
  212.     "http://www.w3.org/2000/SMIL20/CR/WallclockTiming",
  213.     "http://www.3gpp.org/SMIL20/PSS4/",
  214.     "http://www.3gpp.org/SMIL20/PSS5/",
  215.     NULL
  216. };
  217. static const struct smilTagTable
  218. {
  219.     SMILNodeTag m_tag;
  220.     const char* m_name;
  221. } SmilTagTable[] =
  222. {
  223.     {SMILSmil,     "smil"},
  224.     {SMILMeta,     "meta"},
  225.     {SMILMetadata,     "metadata"},
  226.     {SMILHead,     "head"},
  227.     {SMILBody,     "body"},
  228.     {SMILBasicLayout,     "layout"},
  229.     {SMILRootLayout,     "root-layout"},
  230.     {SMILRegion,     "region"},
  231.     {SMILRegPoint,     "regPoint"},
  232.     {SMILViewport,     "topLayout"},
  233.     {SMILTransition,     "transition"},
  234.     {SMILSwitch,     "switch"},
  235.     {SMILText,     "text"},
  236.     {SMILImg,     "img"},
  237.     {SMILRef,     "ref"},
  238.     {SMILAudio,     "audio"},
  239.     {SMILVideo,     "video"},
  240.     {SMILAnimation,     "animation"},
  241.     {SMILTextstream,     "textstream"},
  242.     {SMILBrush,     "brush"},
  243.     {SMILPrefetch,     "prefetch"},
  244.     {SMILAnchor,     "anchor"},
  245.     {SMILArea,     "area"},
  246.     {SMILAAnchor,     "a"},
  247.     {SMILPar,     "par"},
  248.     {SMILSeq,     "seq"},
  249.     {SMILExcl,     "excl"},
  250.     {SMILPriorityClass,     "priorityClass"},
  251.     {SMILCustomAttributes,  "customAttributes"},
  252.     {SMILCustomTest,     "customTest"},
  253.     {SMILRNRendererList,    RN_TAG_RENDERER_LIST},
  254.     {SMILRendererPreFetch,  RN_TAG_RENDERER},
  255.     {SMILAnimate,           "animate"},
  256.     {SMILSet,               "set"},
  257.     {SMILAnimateMotion,     "animateMotion"},
  258.     {SMILAnimateColor,      "animateColor"},
  259.     {SMILUnknown,     "unknown"}
  260. };
  261. SMILNamespace::SMILNamespace(SMILNamespace* pNS)
  262. {
  263.     if (pNS)
  264.     {
  265.         m_name   = new_string(pNS->m_name);
  266.         m_pValue = pNS->m_pValue;
  267.         if (m_pValue)
  268.         {
  269.             m_pValue->AddRef();
  270.         }
  271.     }
  272. }
  273. SMILNamespace::SMILNamespace(const char* name, IHXBuffer* pVal)
  274. {
  275.     m_name   = new_string(name);
  276.     m_pValue = pVal;
  277.     if (m_pValue)
  278.     {
  279.         m_pValue->AddRef();
  280.     }
  281. }
  282. SMILNamespace::~SMILNamespace()
  283. {
  284.     HX_VECTOR_DELETE(m_name);
  285.     HX_RELEASE(m_pValue);
  286. }
  287. CSmilParser::CSmilParser(IUnknown* pContext):
  288.     m_pContext(pContext),
  289.     m_pClassFactory(NULL),
  290.     m_pISystemRequired(NULL),
  291.     m_pNodeList(0),
  292.     m_pNodeListStack(0),
  293.     m_pPacketQueue(0),
  294.     m_pIDMap(0),
  295.     m_pAddGroupMap(0),
  296.     m_pSourceUpdateList(0),
  297.     m_pRequireTagsMap(0),
  298.     m_pCustomTestMap(NULL),
  299.     m_bNoNamespaces(FALSE),
  300.     m_bRNNamespace(FALSE),
  301.     // XXXJHUG -- shouldn't we always ignor?
  302.     m_bIgnoreUnrecognizedElements(TRUE),
  303.     m_bSMILRootLayoutAlreadyFound(FALSE),
  304.     m_pActiveNamespaceMap(NULL),
  305.     m_pNSConflictList(NULL),
  306.     m_bTimestampsResolved(FALSE),
  307.     m_pCurNode(0),
  308.     m_pNodeDependencies(0),
  309.     m_pCurrentDependentNode(0),
  310.     m_pAnchorStack(0),
  311.     m_pCurrentAnchor(0),
  312.     m_lLastCheckPendingTime(-1),
  313.     m_ulBandwidthPreference(0),
  314.     m_ulScreenHeightPreference(0),
  315.     m_ulScreenWidthPreference(0),
  316.     m_ulScreenDepthPreference(0),
  317.     m_pLanguagePreferenceList(0),
  318.     m_bCaptionsPreference(FALSE),
  319.     m_pOverdubOrCaptionPreference(0),
  320.     m_bSystemAudioDescPreference(FALSE),
  321.     m_bUseSystemCPU(TRUE), // /If regkey not present, treat as "TRUE"
  322.     m_bUseSystemOS(TRUE), // /If regkey not present, treat as "TRUE"
  323.     m_pBasePath(0),
  324.     m_pTagAttributeMap(0),
  325.     m_bContainsSource(FALSE),
  326.     m_bContainsInitiallyScheduledTrack(FALSE),
  327.     m_ulDurIfNoInitialTracksScheduled(DEFAULT_DUR_IF_NO_SOURCES_SCHEDULED),
  328.     m_pEncoding(0),
  329.     m_pTrackHintList(0),
  330.     m_pParser(NULL),
  331.     m_pResponse(NULL),
  332.     m_ulErrorLineNumber(0),
  333.     m_ulErrorColumnNumber(0),
  334.     m_pErrorText(NULL)
  335.     , m_bStoreErrors(FALSE)
  336.     , m_pErrors(NULL)
  337.     , m_pBeginTimeSyncList(NULL)
  338.     , m_pEndTimeSyncList(NULL)
  339.     , m_pBeginEventList(NULL)
  340.     , m_pEndEventList(NULL)
  341.     , m_pBeginMediaMarkerList(NULL)
  342.     , m_pEndMediaMarkerList(NULL)
  343.     , m_pClipBeginMarkerList(NULL)
  344.     , m_pClipEndMarkerList(NULL)
  345.     , m_pPendingBeginTimeList(NULL)
  346.     , m_pPendingEndTimeList(NULL)
  347.     , m_pOnLoadURLList(NULL)
  348.     , m_pOnLoadURLListCopyForPostSeek(NULL)
  349.     , m_bHandlePostSeekOnLoadURLs(FALSE)
  350. #if defined(HELIX_FEATURE_SMIL2_TRANSITIONS)
  351.     , m_pTransitionMap(NULL)
  352. #endif /* #if defined(HELIX_FEATURE_SMIL2_TRANSITIONS) */
  353.     , m_bFirstPacket(TRUE)
  354.     , m_pDefaultNamespace(NULL)
  355.     , m_ulPlatformVer(HX_PLATFORM_UNKNOWN)
  356.     , m_ulPersistentComponentID(0)
  357.     , m_ulPersistentComponentDelay(0)
  358.     , m_ulPersistentComponentDuration(0)
  359.     , m_bAllowPlaylistBehavior(FALSE)
  360.     , m_elementWithinTag(WithinUnknown)
  361.     , m_pElementMap(NULL)
  362.     , m_pAttributeMap(NULL)
  363. #if defined(HELIX_FEATURE_SMIL2_VALIDATION)
  364.     , m_pExtElementMap(NULL)
  365.     , m_pExtAttributeMap(NULL)
  366.     , m_pNamespaceMap(NULL)
  367.     , m_pLegalAttrMap(NULL)
  368.     , m_pContentModelMap(NULL)
  369.     , m_pAttrType(NULL)
  370.     , m_ppEnumAttrMap(NULL)
  371.     , m_ppReqAttrList(NULL)
  372. #endif /* #if defined(HELIX_FEATURE_SMIL2_VALIDATION) */
  373.     , m_pValNSList(NULL)
  374.     , m_pXMMFElementList(NULL)
  375.     , m_lParseError(HXR_OK)
  376.     , m_pAnimateElementList(NULL)
  377.     , m_pBeginTimeMap(NULL)
  378.     , m_pEndTimeMap(NULL)
  379.     , m_pExternalEventList(NULL)
  380.     , m_pExternalEventListPos(NULL)
  381.     , m_bAllTracksNeedReflushHint(FALSE)
  382.     , m_pElementsWithHandlerList(NULL)
  383.     , m_pVarName(NULL)
  384.     , m_ulNextVar(1024)
  385.     , m_pTimelineElementManager(NULL)
  386. {
  387.     if(m_pContext)
  388.     {
  389. m_pContext->AddRef();
  390. m_pContext->QueryInterface(IID_IHXCommonClassFactory, (void**)&m_pClassFactory);
  391.     }
  392.     initRequireTags();
  393.     initTagAttributes();
  394.     getPreferences();
  395.     initParsingMaps();
  396.     m_versionInfo.dwPlatformId = HX_PLATFORM_UNKNOWN;
  397.     m_versionInfo.dwMachineType = HX_MACHINE_UNKNOWN;
  398.     // /Get the OS and CPU version information:
  399.     m_ulPlatformVer = HXGetWinVer(&m_versionInfo);
  400.     // Allocate the variable name buffer
  401.     m_pVarName = new char [256];
  402.     // Allocate the timeline element manager
  403.     m_pTimelineElementManager = new CSmilTimelineElementManager;
  404. }
  405. CSmilParser::~CSmilParser()
  406. {
  407.     deleteTagAttributes();
  408.     HX_DELETE(m_pRequireTagsMap);
  409.     HX_DELETE(m_pCustomTestMap);
  410.     HX_DELETE(m_pElementMap);
  411.     HX_DELETE(m_pAttributeMap);
  412. #if defined(HELIX_FEATURE_SMIL2_VALIDATION)
  413.     HX_DELETE(m_pExtElementMap);
  414.     HX_DELETE(m_pExtAttributeMap);
  415.     HX_DELETE(m_pNamespaceMap);
  416.     HX_DELETE(m_pLegalAttrMap);
  417.     HX_DELETE(m_pContentModelMap);
  418.     HX_VECTOR_DELETE(m_pAttrType);
  419.     deleteEnumAttrMaps();
  420.     deleteReqAttrLists();
  421. #endif /* #if defined(HELIX_FEATURE_SMIL2_VALIDATION) */
  422.     HX_DELETE(m_pAnimateElementList);
  423.     deleteValidationNamespaceList();
  424.     if (m_pErrors)
  425.     {
  426. int size = m_pErrors->GetSize();
  427. for (int i =0; i < size; ++i)
  428. {
  429.     IHXBuffer* pBuf = (IHXBuffer*)(*m_pErrors)[i];
  430.     HX_RELEASE(pBuf);
  431.     (*m_pErrors)[i] = NULL;
  432. }
  433. HX_DELETE(m_pErrors);
  434.     }
  435.     if (m_pActiveNamespaceMap != NULL)
  436.     {
  437. CHXMapStringToOb::Iterator ndxBuffer = m_pActiveNamespaceMap->Begin();
  438. for (; ndxBuffer != m_pActiveNamespaceMap->End(); ++ndxBuffer)
  439. {
  440.     IHXBuffer* pBuffer = (IHXBuffer*)(*ndxBuffer);
  441.     HX_RELEASE(pBuffer);
  442. }
  443. HX_DELETE(m_pActiveNamespaceMap);
  444.     }
  445.     if (m_pNSConflictList != NULL)
  446.     {
  447. CHXSimpleList::Iterator ndx = m_pNSConflictList->Begin();
  448. for (; ndx != m_pNSConflictList->End(); ++ndx)
  449. {
  450.     SMILNamespace* pNS = (SMILNamespace*)(*ndx);
  451.     HX_DELETE(pNS);
  452. }
  453. HX_DELETE(m_pNSConflictList);
  454.     }
  455. #if defined(HELIX_FEATURE_SMIL2_TRANSITIONS)
  456.     HX_DELETE(m_pTransitionMap);
  457. #endif /* #if defined(HELIX_FEATURE_SMIL2_TRANSITIONS) */
  458.     // /XXXEH- TODO: check mem leaks; should be clean already...
  459.     HX_DELETE(m_pBeginTimeSyncList);
  460.     HX_DELETE(m_pEndTimeSyncList);
  461.     // /XXXEH- TODO: check mem leaks; should be clean already...
  462.     HX_DELETE(m_pBeginEventList);
  463.     HX_DELETE(m_pEndEventList);
  464.     // /XXXEH- TODO: check mem leaks; should be clean already...
  465.     HX_DELETE(m_pBeginMediaMarkerList);
  466.     HX_DELETE(m_pEndMediaMarkerList);
  467.     HX_DELETE(m_pXMMFElementList);
  468.     HX_DELETE(m_pClipBeginMarkerList);
  469.     HX_DELETE(m_pClipEndMarkerList);
  470.     // /XXXEH- TODO: check mem leaks; should be clean already...
  471.     HX_DELETE(m_pPendingBeginTimeList);
  472.     HX_DELETE(m_pPendingEndTimeList);
  473.     HX_DELETE(m_pOnLoadURLList);
  474.     HX_DELETE(m_pOnLoadURLListCopyForPostSeek);
  475.     HX_DELETE(m_pNodeDependencies);
  476.     HX_DELETE(m_pAnchorStack);
  477.     HX_VECTOR_DELETE(m_pEncoding);
  478.     if(m_pLanguagePreferenceList)
  479.     {
  480. CHXSimpleList::Iterator i = m_pLanguagePreferenceList->Begin();
  481. for(; i != m_pLanguagePreferenceList->End(); ++i)
  482. {
  483.     char* pLang = (char*)(*i);
  484.     delete[] pLang;
  485. }
  486. HX_DELETE(m_pLanguagePreferenceList);
  487.     }
  488.     HX_DELETE(m_pOverdubOrCaptionPreference);
  489.     HX_DELETE(m_pBasePath);
  490.     close();
  491.     HX_RELEASE(m_pClassFactory);
  492.     HX_RELEASE(m_pContext);
  493.     HX_VECTOR_DELETE(m_pVarName);
  494.     HX_DELETE(m_pTimelineElementManager);
  495. }
  496. void
  497. CSmilParser::initRequireTags()
  498. {
  499.     //XXXBAB - add required tags here
  500. #if 0
  501.     m_pRequireTagsMap = new CHXMapStringToOb;
  502.     (*m_pRequireTagsMap)["foo-require"] = 0;
  503.     (*m_pRequireTagsMap)["boo-require"] = 0;
  504. #endif
  505. }
  506. void
  507. CSmilParser::GetSystemScreenInfo(REF(UINT32) rulScreenHeight,
  508.  REF(UINT32) rulScreenWidth,
  509.  REF(UINT32) rulScreenBitDepth)
  510. {
  511.     rulScreenHeight = rulScreenWidth = rulScreenBitDepth = 0;
  512. #if defined(_WINDOWS)
  513.     rulScreenHeight = (UINT32)GetSystemMetrics(SM_CYSCREEN);
  514.     rulScreenWidth = (UINT32)GetSystemMetrics(SM_CXSCREEN);
  515.     HDC hDCMain = GetDC(NULL); // /Get screen DC.
  516.     if (hDCMain)
  517.     {
  518. rulScreenBitDepth = (UINT32)GetDeviceCaps(hDCMain, BITSPIXEL);
  519. ReleaseDC(NULL, hDCMain);
  520.     }
  521. #elif defined(_UNIX) && (!(defined(_BEOS))) && (!(defined(_MAC_UNIX)))
  522.     // /Pass NULL string to XOpenDisplay to get default display, which
  523.     // is the one that we're playing to:
  524.     Display* pDisplay = XOpenDisplay(NULL);
  525.     if (pDisplay)
  526.     {
  527. Screen* pScreen = XDefaultScreenOfDisplay(pDisplay);
  528. rulScreenHeight = (UINT32)HeightOfScreen(pScreen);
  529. rulScreenWidth = (UINT32)WidthOfScreen(pScreen);
  530. rulScreenBitDepth = (UINT32)DefaultDepthOfScreen(pScreen);
  531.     }
  532. #elif defined(_MACINTOSH) || defined(_MAC_UNIX)
  533.     // /XXXEH- note: on a Mac, you can have multiple display devices and our
  534.     // player can actually play to more than one at once, and can be dragged
  535.     // from one to the other while running.  Dynamic re-evaluation is needed.
  536.     GDHandle mainGD = ::GetMainDevice();
  537.     rulScreenHeight = (UINT32)((**mainGD).gdRect.bottom - (**mainGD).gdRect.top);
  538.     rulScreenWidth = (UINT32)((**mainGD).gdRect.right - (**mainGD).gdRect.left);
  539.     PixMapHandle pmh = (**mainGD).gdPMap;
  540.     if (pmh)
  541.     {
  542. rulScreenBitDepth = (UINT32)((**pmh).pixelSize);
  543.     }
  544. #elif defined(_SYMBIAN)
  545.     TInt aValue;
  546.     TReal aTrg1;
  547.     TReal aTrg2;
  548.     TInt log1;
  549.     TInt log2;
  550.     HAL::Get(HALData::EDisplayColors,aValue);
  551.     TScreenInfoV01 screenInfo;
  552.     TPckg<TScreenInfoV01> si(screenInfo);
  553.     UserSvr::ScreenInfo(si);
  554.     rulScreenWidth = screenInfo.iScreenSize.iWidth;
  555.     rulScreenHeight = screenInfo.iScreenSize.iHeight;
  556.     log1 = Math::Ln(aTrg1,aValue);
  557.     log2 = Math::Ln(aTrg2,2);
  558.     rulScreenBitDepth = (TUint32)(aTrg1/aTrg2);
  559. #else
  560.     HX_ASSERT(0  &&  "Contact ehodge: need screen info from this OS");
  561. #endif
  562. }
  563. void
  564. CSmilParser::getPreferences()
  565. {
  566.     IHXPreferences* pPrefs = 0;
  567.     IHXRegistry* pRegistry = NULL;
  568.     m_pContext->QueryInterface(IID_IHXRegistry, (void**)&pRegistry);
  569.     if(HXR_OK == m_pContext->QueryInterface(
  570. IID_IHXPreferences, (void**)&pPrefs))
  571.     {
  572. IHXBuffer* pBuf = 0;
  573. CHXString strTemp;
  574. strTemp.Format("%s.%s",HXREGISTRY_PREFPROPNAME,"Language");
  575. if(pRegistry && HXR_OK == pRegistry->GetStrByName(strTemp, pBuf))
  576. {
  577.     // language preference can be a comma-separated list
  578.     const char* pLang = (const char*)pBuf->GetBuffer();
  579.     // gonna call strtok, so copy the string...
  580.     char* pLangCopy = new_string(pLang);
  581.     m_pLanguagePreferenceList = new CHXSimpleList;
  582.     char* pTok = strtok(pLangCopy, ",");
  583.     while(pTok)
  584.     {
  585. // /Fixes TLC-set part of PR 58151: sometimes this list will
  586. // have tokens separated by ", " instead of just ",", so first
  587. // remove all whitespace chars after the ',' (and, if we run
  588. // into a whitespace-only string, go past the next comma):
  589. while (isspace(*pTok)  ||  ',' == *pTok)
  590. {
  591.     *pTok++;
  592. }
  593. if ('' == *pTok)
  594. {
  595.     break; // /Whitespace-only or emtpy string is not valid.
  596. }
  597. char* pLangString = new_string(pTok);
  598. m_pLanguagePreferenceList->AddTail(pLangString);
  599. pTok = strtok(NULL, ",");
  600.     }
  601.     delete[] pLangCopy;
  602.     HX_RELEASE(pBuf);
  603. }
  604. if(HXR_OK == pPrefs->ReadPref("bandwidth", pBuf)  ||
  605. // /Fixes PR 84098 (SMIL 2.0 version): on Mac, player registry
  606. // is case-sensitive and the registry value is Bandwidth
  607. // with a capital B:
  608. HXR_OK == pPrefs->ReadPref("Bandwidth", pBuf))
  609. {
  610.     m_ulBandwidthPreference =
  611. (UINT32)atol((const char*)pBuf->GetBuffer());
  612.     HX_RELEASE(pBuf);
  613. }
  614. UINT32 rulScreenHeight = 0;
  615. UINT32 rulScreenWidth = 0;
  616. UINT32 rulScreenBitDepth = 0;
  617. // /Each value found here will be used if the player prefs does not
  618. // already contain it.  For PR 58072 and PR 58075:
  619. GetSystemScreenInfo(rulScreenHeight, rulScreenWidth, rulScreenBitDepth);
  620. if(HXR_OK == pPrefs->ReadPref("screen_depth", pBuf))
  621. {
  622.     m_ulScreenDepthPreference =
  623. (UINT32)atol((const char*)pBuf->GetBuffer());
  624.     HX_RELEASE(pBuf);
  625. }
  626. // /Fixes PR 58075: if not in the player registry, then use the
  627. // screen (bit) depth obtained from the OS API call:
  628. else
  629. {
  630.     m_ulScreenDepthPreference = rulScreenBitDepth;
  631. }
  632. if(HXR_OK == pPrefs->ReadPref("screen_height", pBuf))
  633. {
  634.     m_ulScreenHeightPreference =
  635. (UINT32)atol((const char*)pBuf->GetBuffer());
  636.     HX_RELEASE(pBuf);
  637. }
  638. // /Fixes height part of PR 58072: if not in the player registry, then
  639. // use the screen height obtained from the OS API call:
  640. else
  641. {
  642.     m_ulScreenHeightPreference = rulScreenHeight;
  643. }
  644. if(HXR_OK == pPrefs->ReadPref("screen_width", pBuf))
  645. {
  646.     m_ulScreenWidthPreference =
  647. (UINT32)atol((const char*)pBuf->GetBuffer());
  648.     HX_RELEASE(pBuf);
  649. }
  650. // /Fixes width part of PR 58072: if not in the player registry, then
  651. // use the screen width obtained from the OS API call:
  652. else
  653. {
  654.     m_ulScreenWidthPreference = rulScreenWidth;
  655. }
  656. if(HXR_OK == pPrefs->ReadPref("caption_switch", pBuf))
  657. {
  658.     m_bCaptionsPreference =
  659. (BOOL)((UINT32)atol((const char*)pBuf->GetBuffer()));
  660.     HX_RELEASE(pBuf);
  661. }
  662. if(HXR_OK == pPrefs->ReadPref("overdub_or_caption", pBuf))
  663. {
  664.     const char* pStr = (const char*)pBuf->GetBuffer();
  665.     m_pOverdubOrCaptionPreference = new_string(pStr);
  666. // /XXXEH- TLC needs to allow BOTH captions and audio descriptions
  667. // so they'll need a "overdub_or_caption" option (choice) AND
  668. // a separate "audio_desc_switch" like "caption_switch", above.
  669. #define XXXEH_NEED_TLC_TO_HAVE_SEPARATE_audio_desc_AND_caption_PREFS
  670. #if defined(XXXEH_NEED_TLC_TO_HAVE_SEPARATE_audio_desc_AND_caption_PREFS)
  671.     // /In our player (RP8), "caption_switch" is what gets set to
  672.     // TRUE when *ALL* accessibility features are enabled.  So,
  673.     // it's possible to have accessibility features disabled but
  674.     // to have overdub_or_captions set to one or the other; we need
  675.     // to look at the caption_switch pref to see if we should enable
  676.     // audio descriptions:
  677.     if (m_bCaptionsPreference)
  678.     {
  679. m_bSystemAudioDescPreference = !strcmp(pStr, "overdub");
  680. if (m_bSystemAudioDescPreference)
  681. {
  682.     m_bCaptionsPreference = FALSE;
  683. }
  684.     }
  685. #endif
  686.     HX_RELEASE(pBuf);
  687. }
  688. if(HXR_OK == pPrefs->ReadPref("systemAudioDesc", pBuf))
  689. {
  690.     m_bSystemAudioDescPreference =
  691.     (BOOL)((UINT32)atol((const char*)pBuf->GetBuffer()));
  692.     HX_RELEASE(pBuf);
  693. }
  694. // /Fixes PR 64428:
  695. if(HXR_OK == pPrefs->ReadPref("UseSystemCPU", pBuf))
  696. {
  697.     m_bUseSystemCPU =
  698.     (BOOL)((UINT32)atol((const char*)pBuf->GetBuffer()));
  699.     HX_RELEASE(pBuf);
  700. }
  701. // /Fixes PR 64428:
  702. if(HXR_OK == pPrefs->ReadPref("UseSystemOS", pBuf))
  703. {
  704.     m_bUseSystemOS =
  705.     (BOOL)((UINT32)atol((const char*)pBuf->GetBuffer()));
  706.     HX_RELEASE(pBuf);
  707. }
  708. HX_RELEASE(pPrefs);
  709.     }
  710.     HX_RELEASE(pRegistry);
  711. }
  712. void
  713. CSmilParser::close()
  714. {
  715.     HX_DELETE(m_pPacketQueue);
  716.     HX_DELETE(m_pTrackHintList);
  717.     HX_RELEASE(m_pResponse);
  718.     HX_RELEASE(m_pErrorText);
  719.     HX_RELEASE(m_pDefaultNamespace);
  720.     if (m_pParser)
  721.     {
  722. m_pParser->Close();
  723. HX_RELEASE(m_pParser);
  724.     }
  725.     HX_RELEASE(m_pISystemRequired);
  726.     if (m_pCustomTestMap)
  727.     {
  728. CHXMapStringToOb::Iterator i = m_pCustomTestMap->Begin();
  729. for(; i != m_pCustomTestMap->End(); ++i)
  730. {
  731.     SMILNode* pNode = (SMILNode*)(*i);
  732.     HX_DELETE(pNode->m_pElement);
  733. }
  734. HX_DELETE(m_pCustomTestMap);
  735.     }
  736.     if(m_pIDMap)
  737.     {
  738. CHXMapStringToOb::Iterator i = m_pIDMap->Begin();
  739. for(; i != m_pIDMap->End(); ++i)
  740. {
  741.     SMILNode* pNode = (SMILNode*)(*i);
  742.     HX_DELETE(pNode->m_pElement);
  743. }
  744. HX_DELETE(m_pIDMap);
  745.     }
  746.     if(m_pAddGroupMap)
  747.     {
  748. CHXMapLongToObj::Iterator i = m_pAddGroupMap->Begin();
  749. for(; i != m_pAddGroupMap->End(); ++i)
  750. {
  751.     CSmilAddGroup* pAddGroup = (CSmilAddGroup*)(*i);
  752.     delete pAddGroup;
  753. }
  754. HX_DELETE(m_pAddGroupMap);
  755.     }
  756.     if(m_pSourceUpdateList)
  757.     {
  758. CHXSimpleList::Iterator i = m_pSourceUpdateList->Begin();
  759. for(; i != m_pSourceUpdateList->End(); ++i)
  760. {
  761.     CSmilSourceUpdate* pUpdate = (CSmilSourceUpdate*)(*i);
  762.     delete pUpdate;
  763. }
  764. HX_DELETE(m_pSourceUpdateList);
  765.     }
  766.     if (m_pActiveNamespaceMap)
  767.     {
  768. CHXMapStringToOb::Iterator ndxBuffer = m_pActiveNamespaceMap->Begin();
  769. for (; ndxBuffer != m_pActiveNamespaceMap->End(); ++ndxBuffer)
  770. {
  771.     IHXBuffer* pBuffer = (IHXBuffer*)(*ndxBuffer);
  772.     HX_RELEASE(pBuffer);
  773. }
  774. HX_DELETE(m_pActiveNamespaceMap);
  775.     }
  776.     if (m_pNSConflictList != NULL)
  777.     {
  778. CHXSimpleList::Iterator ndx = m_pNSConflictList->Begin();
  779. for (; ndx != m_pNSConflictList->End(); ++ndx)
  780. {
  781.     SMILNamespace* pNS = (SMILNamespace*)(*ndx);
  782.     HX_DELETE(pNS);
  783. }
  784. HX_DELETE(m_pNSConflictList);
  785.     }
  786. #if defined(HELIX_FEATURE_SMIL2_TRANSITIONS)
  787.     HX_DELETE(m_pTransitionMap);
  788. #endif /* #if defined(HELIX_FEATURE_SMIL2_TRANSITIONS) */
  789.     delete m_pNodeListStack;
  790.     if(m_pNodeList)
  791.     {
  792. delete m_pNodeList->m_pParentNode;
  793.     }
  794.     m_bFirstPacket = TRUE;
  795.     // Clear the begin time map
  796.     clearTimeValueMap(SmilBeginTimeList);
  797.     // Clear the end time map
  798.     clearTimeValueMap(SmilEndTimeList);
  799.     // Clear and delete the custom event list
  800.     clearExternalEventList();
  801.     HX_DELETE(m_pExternalEventList);
  802.     // Clear the handler list
  803.     HX_DELETE(m_pElementsWithHandlerList);
  804. }
  805. HX_RESULT
  806. CSmilParser::init(BOOL bStoreErrors)
  807. {
  808.     HX_RESULT rc = HXR_OK;
  809.     close();
  810.     m_pNodeListStack = new CHXStack;
  811.     m_pPacketQueue = new CHXSimpleList;
  812.     m_pIDMap = new CHXMapStringToOb;
  813.     m_pAddGroupMap = new CHXMapLongToObj;
  814.     m_bStoreErrors = bStoreErrors;
  815.     if (m_bStoreErrors)
  816.     {
  817. // XXXJHUG  error stuff.
  818. // In the future if there was any reason, we could
  819. // store the errors in the nodes that the errors occurred in.
  820. // for now when we get an error notification, we will
  821. // just call the storeError function which will add
  822. // a new IHXBuffer to this array..  This will also be
  823. // called when problems are found with tags...
  824. // this will save having to walk the tree when it
  825. // is time to dump the errors.
  826. m_pErrors = new CHXPtrArray;
  827.     }
  828.     SMILNode* pRootNode = new SMILNode;
  829.     pRootNode->m_id = "root";
  830.     pRootNode->m_name = "root";
  831.     m_pNodeList = new SMILNodeList;
  832.     pRootNode->m_pNodeList = m_pNodeList;
  833.     m_pNodeList->m_pParentNode = pRootNode;
  834.     m_pNodeListStack->Push(pRootNode);
  835. #if !defined(USE_EXPAT_FOR_SMIL)
  836. //#define USE_EXPAT_FOR_SMIL
  837. #endif
  838. #ifdef USE_EXPAT_FOR_SMIL
  839.     rc = m_pClassFactory->CreateInstance(CLSID_IHXXMLParser, (void**)&m_pParser);
  840.     if (FAILED(rc))
  841.     {
  842. // they don't have the parser...  use old one?
  843. // Don't QI core for IID_IHXXMLParser; use our own instance.
  844. m_pParser = new HXXMLParser;
  845. if (m_pParser)
  846. {
  847.     rc = HXR_OK;
  848.     m_pParser->AddRef();
  849. }
  850. else
  851. {
  852.     rc = HXR_OUTOFMEMORY;
  853. }
  854.     }
  855.     if (SUCCEEDED(rc))
  856.     {
  857. m_pResponse = new CSmilParserResponse(this);
  858. m_pResponse->AddRef();
  859. // Expat is created off the CCF.
  860. // In strict mode it requires 100% compliant XML.
  861. rc = m_pParser->Init(m_pResponse, "iso-8859-1", TRUE);
  862.     }
  863. #else
  864.     // Don't QI core for IID_IHXXMLParser; use our own instance.
  865.     HXXMLParser* parser = new HXXMLParser();
  866.     if (parser)
  867.     {
  868. parser->AddRef();
  869.     }
  870.     else
  871.     {
  872. rc = HXR_OUTOFMEMORY;
  873.     }
  874.     if (SUCCEEDED(rc))
  875.     {
  876. m_pResponse = new CSmilParserResponse(this);
  877. m_pResponse->AddRef();
  878. rc = parser->Init(m_pResponse, NULL, TRUE); // strict parser
  879.     }
  880.     if (m_bStoreErrors && parser)
  881.     {
  882. parser->InitErrorNotifier(m_pResponse);
  883.     }
  884.     m_pParser = (IHXXMLParser*)parser;
  885. #endif
  886.     return rc;
  887. }
  888. HX_RESULT
  889. CSmilParser::parse(IHXBuffer* pBuffer, BOOL bIsFinal)
  890. {
  891.     HX_RESULT rc = HXR_OK;
  892.     if (m_bFirstPacket)
  893.     {
  894. m_bFirstPacket = FALSE;
  895. time(&m_tRefTime);
  896.     }
  897.     rc = m_pParser->Parse(pBuffer, bIsFinal);
  898.     if (SUCCEEDED(rc) && FAILED(m_lParseError))
  899.     {
  900.         rc = m_lParseError;
  901.     }
  902.     if(HXR_OK != rc)
  903.     {
  904. m_pParser->GetCurrentLineNumber(m_ulErrorLineNumber);
  905. m_pParser->GetCurrentColumnNumber(m_ulErrorColumnNumber);
  906. HX_RELEASE(m_pErrorText);
  907. m_pParser->GetCurrentErrorText(m_pErrorText);
  908.     }
  909.     return rc;
  910. }
  911. HX_RESULT
  912. CSmilParser::durationResolved(const char* pID, UINT32 ulDuration,
  913.       // /Defaults to FALSE:
  914.       BOOL bSetByParent,
  915.       BOOL bDurationExtendingDueToPause)
  916. {
  917.     HX_RESULT rc = HXR_OK;
  918.     SMILNode* pNode = NULL;
  919.     if(m_pIDMap->Lookup(pID, (void*&)pNode))
  920.     {
  921. if (pNode->m_pElement->m_bIndefiniteDuration)
  922. {
  923. #if defined(XXXEH_OLD_SPECIAL_CASE_HANDLING_OF_INDEF_DUR)
  924.     goto cleanup;
  925. #endif
  926. }
  927. // add duration to parent element
  928. if(pNode &&
  929.    pNode->m_pElement &&
  930.    pNode->m_pElement->m_pTimelineElement)
  931. {
  932.     pNode->m_pElement->m_pTimelineElement->setDuration(ulDuration,
  933.     bSetByParent, bDurationExtendingDueToPause);
  934. }
  935.     }
  936. #if defined(XXXEH_OLD_SPECIAL_CASE_HANDLING_OF_INDEF_DUR)
  937. cleanup:
  938. #endif
  939.     return rc;
  940. }
  941. BOOL AncestorEventsAreResolved(SMILNode* pNode, SMILNode* pOriginalChildNode)
  942. {
  943.     if (!pNode  ||  !pNode->m_pElement  ||
  944.     !pNode->m_pParent  ||  pNode->m_tag == SMILBody)
  945.     {
  946. return TRUE;
  947.     }
  948.     // /For any parent that's not a timeline element, e.g., priorityClass,
  949.     // just ignore and return its parent's results:
  950.     else if (!pNode->m_pElement->m_pTimelineElement)
  951.     {
  952. return AncestorEventsAreResolved(pNode->m_pParent, pOriginalChildNode);
  953.     }
  954.     //Now, look to see if its duration and delay events, if any, are
  955.     // resolved:
  956.     if ( ( (pNode->m_pElement->m_pTimelineElement->durationEvent()  &&
  957. !pNode->m_pElement->m_pTimelineElement->durationSet()  &&
  958. // /Fixes 1/2 of PR 50535: don't care about duration event for child
  959. // itself; it's OK to add a timeline element that has an unresolved
  960. // end; (but if parent has unresolved end, we may need to wait):
  961. pNode != pOriginalChildNode)  ||
  962. (pNode->m_pElement->m_pTimelineElement->delayEvent()  &&
  963. !pNode->m_pElement->m_pTimelineElement->initialDelaySet()) )  &&
  964. //[SMIL 1.0 compliance] Helps fix PR 32578:
  965. //However, if we have a duration event and it's based on a child's
  966. // timing (as can happen via endsync="id(child)", then we want to
  967. // avoid this element waiting for its parent to be resolved while
  968. // the parent is waiting for this element to be resolved:
  969. (!pNode->m_pElement->m_pTimelineElement->durationEvent()  ||
  970. SMILEventSourceID != pNode->m_pElement->m_nEndsyncEventSourceTag) )
  971.     {
  972. return FALSE; //We still need to await event resolution.
  973.     }
  974.     //pNode is ok but its dependency ancestors may still be unresolved and
  975.     // thus pNode may still have timing constraints from its dependency
  976.     // ancestors due to their unresolved event(s):
  977.     return AncestorEventsAreResolved(pNode->m_pParent, pOriginalChildNode);
  978. }
  979. HX_RESULT
  980. CSmilParser::adjustForNegativeOffset(const char* pID)
  981. {
  982.     HX_RESULT pnresult = HXR_OK;
  983.     SMILNode* pNode = 0;
  984.     if(!m_pIDMap->Lookup(pID, (void*&)pNode))
  985.     {
  986. pnresult = HXR_FAILED;
  987.     }
  988.     else if (pNode  &&  pNode->m_pElement  &&
  989.     !pNode->m_pElement->m_bInsertedIntoTimeline  &&
  990.     pNode->m_pParent  &&  pNode->m_pParent->m_pElement)
  991.     {
  992. // /Use syncBase, not parent here (in case parent is <a>, <switch>,
  993. // or <priorityClass> element); this fixes bug (PR 56233 repro case)
  994. // where clipBegin was calculted wrong, below, because priorityClass
  995. // was being used as syncbase and it had a begin time later than this:
  996. SMILNode* pSyncBaseNode = getSyncAncestor(pNode);
  997. if (!pSyncBaseNode  ||  !pSyncBaseNode->m_pElement)
  998. {
  999.     pnresult = HXR_FAILED;
  1000.     goto cleanup;
  1001. }
  1002. // /If we have a negative begin offset or delay which starts us
  1003. // earlier than the begin offset or delay of our syncbase, we need
  1004. // to do a clip-begin equal to the difference, and we need to
  1005. // update our duration as well:
  1006. LONG32 lParentBegin =
  1007. // /If delay is valid, use it otherwise use valid beginOffset
  1008. pSyncBaseNode->m_pElement->m_ulDelay != ((UINT32)-1) ?
  1009. (LONG32)pSyncBaseNode->m_pElement->m_ulDelay :
  1010. pSyncBaseNode->m_pElement->m_bBeginOffsetSet?
  1011. pSyncBaseNode->m_pElement->m_lBeginOffset : 0;
  1012. LONG32 lCurElementBegin =
  1013. pNode->m_pElement->m_ulDelay != ((UINT32)-1) ?
  1014. (LONG32)pNode->m_pElement->m_ulDelay :
  1015. pNode->m_pElement->m_bBeginOffsetSet?
  1016. pNode->m_pElement->m_lBeginOffset :
  1017. // /In adjustForNegativeOffset():
  1018. // /Fixes case where parent has explicit dur, explicit
  1019. // begin offset, and pNode's element begins on an event;
  1020. // this used to set lCurElementBegin to 0 and erroneous
  1021. // clip-begin equal to parent's begin offset would ensue:
  1022. MAX_LONG32;
  1023. // /First, we need to see if this is happening during playback; if
  1024. // so, our begin may have resolved to a time in the past that is
  1025. // later than our sync-parent's begin; in that case, we need to
  1026. // adjust the clip-begin and delay to account for the diff between
  1027. // now and lCurElementBegin:
  1028. if (m_lLastCheckPendingTime > (lCurElementBegin +
  1029. // /(re)Fixes broken long-sync-arc test file
  1030. // BUG-20001110_BeginOffsetInPar...BeginningOnClickAllowsSync.smi
  1031. // where the clipBegin was being *re*-computed here, after
  1032. // having already been adjusted in setDelay() for a long-sync-
  1033. // arc negative offset.  We shouldn't do any adjustment here
  1034. // if the difference is very small (which is not due to
  1035. // user or authored delay clipping, but is due to processor
  1036. // time between when our parent resolved and when the last
  1037. // check pending time):
  1038. CHECKPENDING_TIME_VS_CURTIME_FUDGE_FACTOR))
  1039. {
  1040.     lParentBegin = m_lLastCheckPendingTime;
  1041. }
  1042. if (lCurElementBegin < lParentBegin)
  1043. {
  1044.     LONG32 lDiff = lParentBegin - lCurElementBegin;
  1045.     HX_ASSERT(lDiff >= 0);
  1046.     if (lDiff > 0)
  1047.     {
  1048. ULONG32 ulPriorPureDuration = pNode->m_pElement->getPureDuration();
  1049. ULONG32 ulDiff = (ULONG32)lDiff;
  1050. // /If clip-begin is invalid, set it otherwise add to it:
  1051. pNode->m_pElement->m_ulClipBegin = ((UINT32)-1 ==
  1052. pNode->m_pElement->m_ulAuthoredClipBegin? ulDiff :
  1053. ulDiff+pNode->m_pElement->m_ulAuthoredClipBegin);
  1054. if ((UINT32)-1 != pNode->m_pElement->m_ulDuration)
  1055. {
  1056.     if (pNode->m_pElement->m_ulDuration > ulDiff)
  1057.     {
  1058. pNode->m_pElement->m_ulDuration -= ulDiff;
  1059.     }
  1060.     // /else duration is negative; it can't ever play:
  1061.     else
  1062.     {
  1063. pNode->m_pElement->m_ulDuration = 0;
  1064.     }
  1065. }
  1066. // /And, we should now begin when our parent does:
  1067. pNode->m_pElement->m_ulDelay = lParentBegin;
  1068. // /Only reset duration if it's not 0xFFFFFFFF and
  1069. // if it's not the same as it was before:
  1070. if ((UINT32)-1 != pNode->m_pElement->m_ulDuration  &&
  1071. ulPriorPureDuration != pNode->m_pElement->getPureDuration())
  1072. {
  1073.     resetTimelineElementDuration(pID,
  1074.     pNode->m_pElement->getPureDuration(),
  1075.     ulPriorPureDuration);
  1076. }
  1077.                 if (m_pTimelineElementManager) m_pTimelineElementManager->notify(pID);
  1078.     }
  1079. }
  1080.     }
  1081. cleanup:
  1082.     return pnresult;
  1083. }
  1084. void
  1085. CSmilParser::insertTimelineElement(const char* pID, UINT32 ulDelay)
  1086. {
  1087. #if defined(_DEBUG)  &&  defined(XXXEH_DEBUGOUT_ADDDURATION)
  1088. {
  1089.     FILE* f1 = ::fopen("c:\smil2AddDuration.txt", "a+");
  1090.     ::fprintf(f1, "CSmilParser::insertTimelineElement(%s, delay=%lu) _-_-_-_-_-_-_-_-_n",
  1091.     (const char*)pID, ulDelay);
  1092.     ::fclose(f1);
  1093. }
  1094. #endif
  1095.     SMILNode* pNode = 0;
  1096.     if(m_pIDMap->Lookup(pID, (void*&)pNode))
  1097.     {
  1098. if(pNode &&
  1099.     pNode->m_pElement &&
  1100.     // /XXXEH- TODO: we need to handle restart!="never" which
  1101.     // means that the following if condition should take this
  1102.     // into account:
  1103.     !pNode->m_pElement->m_bInsertedIntoTimeline  &&
  1104.     //[SMIL 1.0 compliance] Helps fix PR 16629:
  1105.     // We don't want to insert a node into the timeline if
  1106.     // its begin is dependent on another (not-yet-
  1107.     // resolved) element:
  1108.     ((!pNode->m_pElement->m_pTimelineElement->delayEvent()  ||
  1109.     pNode->m_pElement->m_pTimelineElement->initialDelaySet()) )
  1110.     //[SMIL 1.0 compliance] Helps fix 14420:
  1111.     // First, we need to look all the way up the tree of ancestors
  1112.     // to see if any of them have event-based delays or durations
  1113.     // and to make sure the appropriate time(s) are resolved.  If
  1114.     // not, we'll have to await those event resolutions before
  1115.     // inserting this element into the timeline:
  1116.     &&  AncestorEventsAreResolved(pNode, pNode)
  1117.     // /For SMIL 2.0, we can have begin="indefinite" which should
  1118.     // be treated as un unresolved event (but only if that's the
  1119.     // sole begin time specified; begin="indefinite; 5s" should be
  1120.     // treated as begin="5s"):
  1121.     &&  !pNode->m_pElement->m_bIndefiniteBegin
  1122.     )
  1123. {
  1124.     ULONG32 ulDelayBeyondParentDelay = 0;
  1125.     ULONG32 ulSyncBaseDelay = 0;
  1126.     SMILNode* pSyncAncestor = getSyncAncestor(pNode);
  1127.     HX_ASSERT((UINT32)-1 != pSyncAncestor->m_pElement->m_ulDelay);
  1128.     // /Check hard time boundaries set by parent:
  1129.     if  (pSyncAncestor  && pSyncAncestor->m_pElement  &&
  1130.     (UINT32)-1 != pSyncAncestor->m_pElement->m_ulDelay)
  1131.     {
  1132. ulSyncBaseDelay = pSyncAncestor->m_pElement->m_ulDelay;
  1133. ulDelayBeyondParentDelay = ulDelay - ulSyncBaseDelay;
  1134. HX_ASSERT(ulDelay >= ulSyncBaseDelay);
  1135. if (ulDelay < ulSyncBaseDelay)
  1136. {
  1137.     ulDelayBeyondParentDelay = 0;
  1138. }
  1139. // /If child has delay beyond parent's delay+duration, i.e.,
  1140. // begin resolved on an event or sync arc, then don't insert it:
  1141. else
  1142. {
  1143.     if (pSyncAncestor->m_pElement->m_bHasExplicitDur  &&
  1144.     !pSyncAncestor->m_pElement->m_bIndefiniteDuration  &&
  1145.     !pSyncAncestor->m_pElement->m_bIndefiniteEnd  &&
  1146.     (ulDelayBeyondParentDelay >=
  1147.     pSyncAncestor->m_pElement->m_ulDuration) )
  1148.     {
  1149. goto cleanup; //It can't ever play.
  1150.     }
  1151.     else if (pSyncAncestor->m_pElement->m_bEndOffsetSet  &&
  1152.     !pSyncAncestor->m_pElement->m_bIndefiniteDuration  &&
  1153.     !pSyncAncestor->m_pElement->m_bIndefiniteEnd)
  1154.     {
  1155. if (ulDelayBeyondParentDelay >=
  1156. pSyncAncestor->m_pElement->m_ulDuration)
  1157. {
  1158.     goto cleanup; //It can't ever play.
  1159. }
  1160.     }
  1161. }
  1162.     }
  1163.     else
  1164.     {
  1165. // /Fixes PR 50411: long sync-arc begin resolved before parent
  1166. // begin resolved and is thus not adjusted for any offset
  1167. // from parent begin; dur:=0 if it ends before parent begin:
  1168. if (pSyncAncestor)
  1169. {
  1170.     pNode->m_pElement->m_bAwaitingSyncAncestorBeginNotification=
  1171.     TRUE;
  1172. }
  1173. goto cleanup; // /Wait to insert this until parent is resolved.
  1174.     }
  1175. #define XXXEH_ABOVE_SHOULD_HANDLE_THIS__REMOVE_IF_NO_ASSERT0_BY_20010530
  1176. #if defined(XXXEH_ABOVE_SHOULD_HANDLE_THIS__REMOVE_IF_NO_ASSERT0_BY_20010530)
  1177.     // /[SMIL 1.0 Compliance] Fixes PR 27644:
  1178.     // if our begin offset is same or greater than our parent's
  1179.     // end offset, then we should be ignored:
  1180.     if ( pNode->m_pParent  &&  pNode->m_pParent->m_pElement  &&
  1181.     pNode->m_pElement->m_bBeginOffsetSet &&
  1182.     pNode->m_pParent->m_pElement->m_bEndOffsetSet &&
  1183.     (pNode->m_pElement->m_lBeginOffset >
  1184.     pNode->m_pParent->m_pElement->m_lEndOffset) )
  1185.     {
  1186. // /See if above replaces this code; if no assert reported by
  1187. // 2001-05-20, then I'm going to remove this whole if() block:
  1188. HX_ASSERT(0  &&  "mailto: ehodge@real.com");
  1189. goto cleanup; //Don't insert this because it can't ever play.
  1190.     }
  1191.     // /Also, need to check parent *dur* and make sure we don't
  1192.     // exceed it if it's been explicitly set to a finite amount:
  1193.     if ( pNode->m_pParent  &&  pNode->m_pParent->m_pElement  &&
  1194.     pNode->m_pElement->m_bBeginOffsetSet  &&
  1195.     pNode->m_pParent->m_pElement->m_bHasExplicitDur  &&
  1196.     !pNode->m_pParent->m_pElement->m_bIndefiniteDuration  &&
  1197.     (pNode->m_pElement->m_lBeginOffset > 0  &&
  1198.     (UINT32)pNode->m_pElement->m_lBeginOffset >
  1199.     pNode->m_pParent->m_pElement->m_ulDuration) )
  1200.     {
  1201. // /See if above replaces this code; if no assert reported by
  1202. // 2001-05-20, then I'm going to remove this whole if() block:
  1203. HX_ASSERT(0  &&  "mailto: ehodge@real.com");
  1204. goto cleanup; //Don't insert this because it can't ever play.
  1205.     }
  1206. #endif
  1207.             // If this element uses media markers for clipBegin
  1208.             // then those markers need to be resolved
  1209.             if (pNode->m_pElement->m_bClipBeginUsesMarker &&
  1210.                 !pNode->m_pElement->m_bClipBeginMarkerResolved)
  1211.             {
  1212.                 // Set the flag saying we WOULD have scheduled
  1213.                 // this element except the clip begin marker wasn't
  1214.                 // resolved yet.
  1215.                 pNode->m_pElement->m_bWaitingOnClipBeginToResolve = TRUE;
  1216.                 goto cleanup; // don't insert cause we don't know the clipBegin yet
  1217.             }
  1218.             // If this element uses media markers for clipEnd
  1219.             // then those markers need to be resolved
  1220.             if (pNode->m_pElement->m_bClipEndUsesMarker &&
  1221.                 !pNode->m_pElement->m_bClipEndMarkerResolved)
  1222.             {
  1223.                 // Set the flag saying we WOULD have scheduled
  1224.                 // this element except the clip end marker wasn't
  1225.                 // resolved yet.
  1226.                 pNode->m_pElement->m_bWaitingOnClipEndToResolve = TRUE;
  1227.                 goto cleanup; // don't insert cause we don't know the clipEnd yet
  1228.             }
  1229.     // skip the element if its duration == 0
  1230.     if (0 == pNode->m_pElement->m_ulDuration)
  1231.     {
  1232. durationResolved(pNode->m_id, 0);
  1233.     }
  1234.     else
  1235.     {
  1236.                 // XXXMEH - we need to know about animations that
  1237.                 // involve sources before we know about the sources.
  1238.                 // Therefore, we need to ensure that the animate
  1239.                 // elements are put before the source elements.
  1240.                 UINT32 ulTS = INITIAL_STREAM1_TIMESTAMP;
  1241.                 if (pNode->m_tag == SMILAnimate      ||
  1242.                     pNode->m_tag == SMILSet          ||
  1243.                     pNode->m_tag == SMILAnimateColor ||
  1244.                     pNode->m_tag == SMILAnimateMotion)
  1245.                 {
  1246.                     ulTS = INITIAL_STREAM0_TIMESTAMP;
  1247.                 }
  1248. pNode->m_pElement->m_ulDelay               = ulDelay;
  1249. pNode->m_pElement->m_ulTimestamp           = ulTS;
  1250. pNode->m_pElement->m_bInsertedIntoTimeline = TRUE;
  1251. pNode->m_pElement->m_bHasBeenScheduled = TRUE;
  1252. // /This helps fix problem where time container has multiple
  1253. // begin conditions and, when second begin was being
  1254. // processed, wasn't being seen as having started before so
  1255. // prepForRestart() wasn't being called when it should.
  1256. // Allow more than one level, i.e., recurse up the tree to
  1257. // set this for all ancestor time containers:
  1258. SMILNode* pNextHigherSyncAncestor = pSyncAncestor;
  1259. while (pNextHigherSyncAncestor  &&
  1260. pNextHigherSyncAncestor->m_pElement)
  1261. {
  1262.     pNextHigherSyncAncestor->m_pElement->m_bInsertedIntoTimeline = TRUE;
  1263.     pNextHigherSyncAncestor->m_pElement->m_bHasBeenScheduled = TRUE;
  1264.     pNextHigherSyncAncestor = getSyncAncestor(
  1265.     pNextHigherSyncAncestor);
  1266. }
  1267. insertElementByTimestamp(pNode->m_pElement);
  1268.     }
  1269. }
  1270.     }
  1271. cleanup:
  1272.     return;
  1273. }
  1274. HX_RESULT
  1275. CSmilParser::trackRemoved(const char* pID,
  1276.   UINT32 ulDuration)
  1277. {
  1278.     HX_RESULT hr = HXR_OK;
  1279.     SMILNode* pNode = NULL;
  1280.     IHXBuffer* pBuf = NULL;
  1281.     if(m_pIDMap->Lookup(pID, (void*&)pNode))
  1282.     {
  1283. // add duration to parent element
  1284. if(pNode &&
  1285.    pNode->m_pElement &&
  1286.    pNode->m_pElement->m_pTimelineElement)
  1287. {
  1288.     pNode->m_pElement->m_pTimelineElement->resetDuration(ulDuration);
  1289. }
  1290.     }
  1291.     return hr;
  1292. }
  1293. void
  1294. CSmilParser::resetTimelineElementDuration(const char* pID,
  1295. // /These durations must NOT include delay (for PR 79699 et al):
  1296. UINT32 ulPureDuration,
  1297. UINT32 ulPriorPureDuration)
  1298. {
  1299. #if defined(_DEBUG)  &&  defined(XXXEHODGE_DEBUG_RESETTIMELINEELEMENTDUR_AND_DELAY)
  1300. {
  1301.     FILE* f1 = ::fopen("c:\smil2ResetTimelineDurOrDelay.txt", bFirstResetTimelineElementDuration?"w":"a+");
  1302.     bFirstResetTimelineElementDuration = FALSE;
  1303.     ::fprintf(f1, "Element id = %s;t%sresetting (pure) duration to %lu from %lun",
  1304.     pID, ulPureDuration==ulPriorPureDuration?
  1305. #if XXXEH_TEST_THIS_MORE
  1306.     "Skipping ":"",
  1307. #else
  1308.     "":"",
  1309. #endif
  1310.     ulPureDuration, ulPriorPureDuration);
  1311.     ::fclose(f1);
  1312.     f1 = ::fopen("c:\smil2AddDuration.txt", "a+");
  1313.     ::fprintf(f1, "nElement id = %s;t%sresetting duration to %lu from %lunn",
  1314.     pID, ulPureDuration==ulPriorPureDuration?
  1315. #if XXXEH_TEST_THIS_MORE
  1316.     "Skipping ":"",
  1317. #else
  1318.     "":"",
  1319. #endif
  1320.     ulPureDuration, ulPriorPureDuration);
  1321.     ::fclose(f1);
  1322. }
  1323. #endif
  1324.     SMILNode* pNode = NULL;
  1325.     // /Fixes bug exposed by fixes for PR 59584 and others (by undoing the
  1326.     // original fix for PR 61174(version1) and par version of PR 56686).
  1327.     // Don't reset duration if it's the same, otherwise SourceUpdate will be
  1328.     // created possibly prior to TrackDurationSet() even being called, which
  1329.     // would cause this delay event to be used to possibly mess things up in
  1330.     // rendererInitialized():
  1331. #if defined(XXXEH_TEST_THIS_MORE)
  1332.     // /TEST THIS! A test file fails due to this when both are same,
  1333.     // "..relatedToPR59584andPR62688(endsync1stWithRestartVersion..smil"
  1334.     if (ulPureDuration == ulPriorPureDuration)
  1335.     {
  1336. goto cleanup;
  1337.     }
  1338. #endif
  1339.     if(m_pIDMap->Lookup(pID, (void*&)pNode))
  1340.     {
  1341. CSmilSourceUpdate* pUpdate = new CSmilSourceUpdate;
  1342. pUpdate->m_ulTimestamp = INITIAL_STREAM1_TIMESTAMP;
  1343. pUpdate->m_srcID = pID;
  1344. pUpdate->m_updateTag = UpdateDuration;
  1345. pUpdate->m_ulUpdatedDuration = ulPureDuration;
  1346. pUpdate->m_bDurationIsPureOfDelay = TRUE;
  1347. if(!m_pSourceUpdateList)
  1348. {
  1349.     m_pSourceUpdateList = new CHXSimpleList;
  1350. }
  1351. m_pSourceUpdateList->AddTail(pUpdate);
  1352. insertElementByTimestamp(pUpdate);
  1353.     }
  1354. #if defined(XXXEH_TEST_THIS_MORE)
  1355. cleanup:
  1356. #endif
  1357.     return;
  1358. }
  1359. void
  1360. CSmilParser::resetTimelineElementDelay(const char* pID,
  1361.        UINT32 ulDelay,
  1362.        UINT32 ulPriorDelay)
  1363. {
  1364. #if defined(_DEBUG)  &&  defined(XXXEHODGE_DEBUG_RESETTIMELINEELEMENTDUR_AND_DELAY)
  1365. {
  1366.     FILE* f1 = ::fopen("c:\smil2ResetTimelineDurOrDelay.txt", bFirstResetTimelineElementDuration?"w":"a+");
  1367.     bFirstResetTimelineElementDuration = FALSE;
  1368.     ::fprintf(f1, "Element id = %s;t%sresetting delay to %lu from %lun",
  1369.     pID, ulDelay==ulPriorDelay?"Skipping ":"", ulDelay, ulPriorDelay);
  1370.     ::fclose(f1);
  1371.     f1 = ::fopen("c:\smil2AddDuration.txt", "a+");
  1372.     ::fprintf(f1, "nElement id = %s;t%sresetting delay to %lu from %lunn",
  1373.     pID, ulDelay==ulPriorDelay?"Skipping ":"", ulDelay, ulPriorDelay);
  1374.     ::fclose(f1);
  1375. }
  1376. #endif
  1377.     SMILNode* pNode = NULL;
  1378.     // /Fixes bug exposed by fixes for PR 59584 and others (by undoing the
  1379.     // original fix for PR 61174(version1) and par version of PR 56686).
  1380.     // Don't reset delay if it's the same, otherwise SourceUpdate will be
  1381.     // created possibly prior to TrackDurationSet() even being called, which
  1382.     // would cause this delay event to be used to possibly mess things up in
  1383.     // rendererInitialized():
  1384.     if (ulDelay == ulPriorDelay)
  1385.     {
  1386. goto cleanup;
  1387.     }
  1388.     if(m_pIDMap->Lookup(pID, (void*&)pNode))
  1389.     {
  1390. CSmilSourceUpdate* pUpdate = new CSmilSourceUpdate;
  1391. pUpdate->m_ulTimestamp = INITIAL_STREAM1_TIMESTAMP;
  1392. pUpdate->m_srcID = pID;
  1393. pUpdate->m_updateTag = UpdateDelay;
  1394. pUpdate->m_ulUpdatedDelay = ulDelay;
  1395. if(!m_pSourceUpdateList)
  1396. {
  1397.     m_pSourceUpdateList = new CHXSimpleList;
  1398. }
  1399. m_pSourceUpdateList->AddTail(pUpdate);
  1400. insertElementByTimestamp(pUpdate);
  1401.     }
  1402. cleanup:
  1403.     return;
  1404. }
  1405. CSmilElement*
  1406. CSmilParser::findElement(const char* pID)
  1407. {
  1408.     SMILNode* pNode = NULL;
  1409.     if(m_pIDMap->Lookup(pID, (void*&)pNode))
  1410.     {
  1411. return pNode->m_pElement;
  1412.     }
  1413.     return NULL;
  1414. }
  1415. const char*
  1416. CSmilParser::assignID(const char* pPrefix)
  1417. {
  1418.     SafeSprintf(m_pVarName, 256, "%s_%ld", pPrefix, GetUniqueNumber());
  1419.     return m_pVarName;
  1420. }
  1421. UINT16
  1422. CSmilParser::getFragmentGroup(const char* pFragment)
  1423. {
  1424.     if(pFragment)
  1425.     {
  1426. SMILNode* pNode = 0;
  1427. if(m_pIDMap->Lookup(pFragment, (void*&)pNode))
  1428. {
  1429.     if(!pNode->m_bDelete)
  1430.     {
  1431. if(pNode->m_tag == SMILAAnchor ||
  1432.     pNode->m_tag == SMILSwitch)
  1433. {
  1434.     SMILNode* pChildNode = getTimelineDescendent(pNode, NULL);
  1435.     while(pChildNode)
  1436.     {
  1437. if(!pChildNode->m_bDelete)
  1438. {
  1439.     return pChildNode->m_nGroup;
  1440. }
  1441. pChildNode = getTimelineDescendent(pNode, pChildNode);
  1442.     }
  1443. }
  1444. else if(pNode->m_tag == SMILAnchor  ||
  1445. pNode->m_tag == SMILArea)
  1446. {
  1447.     SMILNode* pParentNode = pNode->m_pParent;
  1448.     if(pParentNode &&
  1449. !pParentNode->m_bDelete)
  1450.     {
  1451. return pParentNode->m_nGroup;
  1452.     }
  1453. }
  1454. else
  1455. {
  1456.     return pNode->m_nGroup;
  1457. }
  1458.     }
  1459. }
  1460.     }
  1461.     return 0;
  1462. }
  1463. UINT32
  1464. CSmilParser::getFragmentOffset(const char* pFragment,
  1465. //This BOOL will be set to FALSE if the fragment
  1466. // does not exist; this was necessary to fix PR 22655.
  1467. BOOL& bFragFoundAndResolved,
  1468. BOOL bResolveBeginOfFragmentTarget,
  1469. ULONG32 ulCurTime)
  1470. {
  1471.     bFragFoundAndResolved = FALSE;
  1472.     if(pFragment)
  1473.     {
  1474. INT32 lAnchorBegin = 0;
  1475. SMILNode* pNode = NULL;
  1476. CSmilElement* pElement = NULL;
  1477. CSmilElement* pFragmentElement = NULL;
  1478. if(m_pIDMap->Lookup(pFragment, (void*&)pNode) &&
  1479.     pNode->m_pElement)
  1480. {
  1481.     pElement = pNode->m_pElement;
  1482.     if(pNode->m_tag == SMILSwitch ||
  1483. pNode->m_tag == SMILAAnchor)
  1484.     {
  1485. SMILNode* pChildNode = getTimelineDescendent(
  1486.     pNode, NULL);
  1487. while(pChildNode)
  1488. {
  1489.     if(!pChildNode->m_bDelete)
  1490.     {
  1491. pFragmentElement = pChildNode->m_pElement;
  1492. break;
  1493.     }
  1494.     pChildNode = getTimelineDescendent(
  1495. pNode, pChildNode);
  1496. }
  1497.     }
  1498.     else if(pNode->m_tag == SMILAnchor  ||
  1499.     pNode->m_tag == SMILArea)
  1500.     {
  1501. if(pElement->m_bBeginOffsetSet)
  1502. {
  1503.     lAnchorBegin = pElement->m_lBeginOffset;
  1504. }
  1505. SMILNode* pParent = pNode->m_pParent;
  1506. if(pParent)
  1507. {
  1508.     pFragmentElement = pParent->m_pElement;
  1509. }
  1510.     }
  1511.     else
  1512.     {
  1513. pFragmentElement = pElement;
  1514.     }
  1515.     if(pFragmentElement)
  1516.     {
  1517. bFragFoundAndResolved = TRUE;
  1518. //[SMIL 1.0 Compliance] Fixes PR 26464:
  1519. // Use delay (which already includes begin offset)
  1520. // if it's a valid value, else use begin offset
  1521. // without delay added (see comment below):
  1522. if(pFragmentElement->m_ulDelay != (UINT32)-1)
  1523. {
  1524.     INT32 offset = pFragmentElement->m_ulDelay +
  1525. lAnchorBegin;
  1526.     return (offset >= 0 ? (UINT32)offset: 0);
  1527. }
  1528. else if(pFragmentElement->m_bBeginOffsetSet)
  1529. {
  1530.     //Changed this while fixing PR 26464:
  1531.     // This used to return pFragmentElement->m_ulDelay +
  1532.     // pFragmentElement->m_lBeginOffset + lAnchorBegin but
  1533.     // the delay can already account for the begin if both
  1534.     // are set so we'd end up seeking past where we were
  1535.     // supposed to go by the amount of the begin offset.
  1536.     // Also, we weren't even checking to see
  1537.     // if delay was valid before using it (and now we're
  1538.     // sure it is invalid per check above):
  1539.     INT32 offset = pFragmentElement->m_lBeginOffset +
  1540. lAnchorBegin;
  1541.     return (offset >= 0 ? (UINT32)offset: 0);
  1542. }
  1543. // /Fixes SMIL 2.0 Interop Linking tests #1.4 & #1.5:
  1544. // if we've been instructed to resolve this #-ref'd
  1545. // internally-linked element's delay, then we need to
  1546. // do so to the current time:
  1547. else if (bResolveBeginOfFragmentTarget  &&
  1548. pFragmentElement->m_pTimelineElement)
  1549. {
  1550.     SMILNode* pSyncAncestor =
  1551.     getSyncAncestor(pFragmentElement->m_pNode);
  1552.     // /Fixes PR 50848:
  1553.     // /The following is needed to completely fix SMIL 2.0
  1554.     // Interop Linking #1.5 (to make the clicked-on child of
  1555.     // a seq go away when the clicked-to one starts):
  1556.     if (pSyncAncestor  &&  SMILSeq == pSyncAncestor->m_tag)
  1557.     {
  1558. SMILNode* pSibling = pSyncAncestor->getFirstChild();
  1559. SMILNode* pPrevSibling = NULL;
  1560. while (pSibling)
  1561. {
  1562.     if (pSibling->m_id ==
  1563.     pFragmentElement->m_pNode->m_id)
  1564.     {
  1565. break;
  1566.     }
  1567.     // /Fixes case where pFragmentElement has non-
  1568.     // timeline-element parent, e.g., <a> or <switch>
  1569.     else if (pFragmentElement->m_pNode->m_pParent !=
  1570.     pSyncAncestor)
  1571.     {
  1572. SMILNode* pFirstSiblingChild =
  1573. pSibling->getFirstChild();
  1574. if (pFirstSiblingChild  &&
  1575. pFirstSiblingChild->m_id ==
  1576. pFragmentElement->m_pNode->m_id)
  1577. {
  1578.     break;
  1579. }
  1580.     }
  1581.     pPrevSibling = pSibling;
  1582.     pSibling = pSyncAncestor->getNextChild();
  1583. }
  1584. if (pPrevSibling)
  1585. {
  1586.     // /XXXEH- TODO: if prev sib is not a timeline
  1587.     // element, use its first child as prev sibling.
  1588.     if (pPrevSibling->m_pElement  &&
  1589.    pPrevSibling->m_pElement->m_pTimelineElement)
  1590.     {
  1591. ULONG32 ulCurStartTime = 0;
  1592. if (HXR_OK == pPrevSibling->m_pElement->
  1593. getCurrentScheduledStartTime(
  1594. ulCurStartTime)  &&
  1595. ulCurTime > ulCurStartTime)
  1596. {
  1597.     ULONG32 ulNewDuration =
  1598.     ulCurTime - ulCurStartTime;
  1599.          durationResolved(pPrevSibling->m_id,
  1600.     ulNewDuration);
  1601.                                     if (m_pTimelineElementManager)
  1602.                                         m_pTimelineElementManager->notify((const char*)pPrevSibling->m_id);
  1603. }
  1604.     }
  1605. }
  1606.     }
  1607.     // /If not child of seq, then just set its delay to now:
  1608.     else
  1609.     {
  1610. pFragmentElement->m_pTimelineElement->setDelay(
  1611. ulCurTime,FALSE);
  1612.     }
  1613. }
  1614. else
  1615. {
  1616.     // /Must just be a mouse move, so return the
  1617.     // unresolved value so mouse cursor can change:
  1618.     return ((UINT32)-1);
  1619. }
  1620.     }
  1621. }
  1622.     }
  1623.     return 0;
  1624. }
  1625. SMILNode*
  1626. CSmilParser::findFirstNode(SMILNodeList* pNodeList, SMILNodeTag tag)
  1627. {
  1628.     if(!pNodeList)
  1629.     {
  1630. return 0;
  1631.     }
  1632.     SMILNode* pFoundNode = 0;
  1633.     CHXSimpleList::Iterator i;
  1634.     for(i=pNodeList->Begin();i!=pNodeList->End();++i)
  1635.     {
  1636. SMILNode* pNode = (SMILNode*)(*i);
  1637. if(pNode->m_tag == tag)
  1638. {
  1639.     pFoundNode = pNode;
  1640. }
  1641. else
  1642. {
  1643.     pFoundNode = findFirstNode(pNode->m_pNodeList, tag);
  1644. }
  1645. if(pFoundNode)
  1646. {
  1647.     break;
  1648. }
  1649.     }
  1650.     return pFoundNode;
  1651. }
  1652. SMILNode*
  1653. CSmilParser::findFirstNode(SMILNodeTag tag)
  1654. {
  1655.     return findFirstNode(m_pNodeList, tag);
  1656. }
  1657. SMILNode*
  1658. CSmilParser::getFirstNodeChild(SMILNode* pNode)
  1659. {
  1660.     m_pCurNode = pNode;
  1661.     if(!m_pCurNode)
  1662.     {
  1663. return 0;
  1664.     }
  1665.    return m_pCurNode->getFirstChild();
  1666. }
  1667. SMILNode*
  1668. CSmilParser::getNextNodeChild()
  1669. {
  1670.     if(!m_pCurNode)
  1671.     {
  1672. return 0;
  1673.     }
  1674.     return m_pCurNode->getNextChild();
  1675. }
  1676. HX_RESULT
  1677. CSmilParser::parseClockValue(const char* pValue, UINT32& ulTimeValue)
  1678. {
  1679.     // try npt
  1680.     char* pPtr = (char *)strstr(pValue, "npt=");
  1681.     if(pPtr)
  1682.     {
  1683. pPtr += 4;  // point to beginning of clock value
  1684. //[SMIL 1.0 compliance] fixes PR 26445: if "npt=4h" is specified,
  1685. // we need to convert to "14400s" otherwise the 4 is treated as
  1686. // seconds:
  1687. char* pHourChar = strchr(pPtr, 'h');
  1688. if (pHourChar  &&  !strchr(pPtr, ':')) //then it's hours without ':'
  1689. {
  1690.     IHXBuffer* pBuf = new CHXBuffer;
  1691.     if (pBuf)
  1692.     {
  1693. pBuf->AddRef();
  1694. *pHourChar = ''; //get rid of the 'h' in pPtr.
  1695. pBuf->Set((const unsigned char *)pPtr,
  1696.     strlen(pPtr) + strlen(":00:00") + 1);
  1697. char* pTmp = (char*)pBuf->GetBuffer();
  1698. strcat(pTmp, ":00:00"); /* Flawfinder: ignore */
  1699. NPTime clockTime((const char*)pTmp);
  1700. ulTimeValue = (UINT32)clockTime;
  1701. pBuf->Release();
  1702.     }
  1703.     else
  1704.     {
  1705. return HXR_OUTOFMEMORY;
  1706.     }
  1707. }
  1708. //END fix for PR 26445.
  1709. else
  1710. {
  1711.     NPTime clockTime(pPtr);
  1712.     ulTimeValue = (UINT32)clockTime;
  1713. }
  1714. return HXR_OK;
  1715.     }
  1716.     // try smpte
  1717.     pPtr = (char *)strstr(pValue, "smpte=");
  1718.     if(pPtr)
  1719.     {
  1720. pPtr += 6;  // point to beginning of clock value
  1721. SMPTETimeCode clockTime(pPtr);
  1722. ulTimeValue = (UINT32)clockTime;
  1723. return HXR_OK;
  1724.     }
  1725.     pPtr = (char *)strstr(pValue, "smpte-30-drop=");
  1726.     if(pPtr)
  1727.     {
  1728. pPtr += 14;  // point to beginning of clock value
  1729. SMPTETimeCode clockTime(pPtr);
  1730. ulTimeValue = (UINT32)clockTime;
  1731. return HXR_OK;
  1732.     }
  1733.     pPtr = (char *)strstr(pValue, "smpte-25=");
  1734.     if(pPtr)
  1735.     {
  1736. pPtr += 9;  // point to beginning of clock value
  1737. SMPTETimeCode clockTime;
  1738.         clockTime.m_framesPerSec = SMPTETimeCode::FPS_25;
  1739.         clockTime.fromString(pPtr);
  1740. ulTimeValue = (UINT32)clockTime;
  1741. return HXR_OK;
  1742.     }
  1743.     else if(strchr(pValue, ':'))     // try just hh:mm:ss with no prefix/suffix
  1744.     {
  1745. NPTime clockTime(pValue);
  1746. ulTimeValue = (UINT32)clockTime;
  1747. return HXR_OK;
  1748.     }
  1749.     // ok, try h/min/s/ms
  1750.     char* pEndPtr = 0;
  1751.     double dVal = strtod(pValue, &pEndPtr);
  1752.     if(strcmp(pEndPtr, "h") == 0)
  1753.     {
  1754. ulTimeValue = (UINT32)(dVal * 60.0 * 60.0 * 1000.0);
  1755. return HXR_OK;
  1756.     }
  1757.     else if(strcmp(pEndPtr, "min") == 0)
  1758.     {
  1759. ulTimeValue = (UINT32)(dVal * 60.0 * 1000.0);
  1760. return HXR_OK;
  1761.     }
  1762.     else if(strcmp(pEndPtr, "s") == 0  ||
  1763.     //[SMIL 1.0 compliance] Fixes PR 22673: the SMIL doc says that we
  1764.     // need to default to seconds if no unit-type is given:
  1765.     //     Timecount-val         ::= Timecount ("." Fraction)?
  1766.     //              ("h" | "min" | "s" | "ms")? ; default is "s"
  1767.     (!strlen(pEndPtr)) )
  1768.     {
  1769. ulTimeValue = (UINT32)(dVal * 1000.0);
  1770. return HXR_OK;
  1771.     }
  1772.     else if(strcmp(pEndPtr, "ms") == 0)
  1773.     {
  1774. ulTimeValue = (UINT32)(dVal);
  1775. return HXR_OK;
  1776.     }
  1777.     //else something other than "h", "min", "s", "", or "ms" was specified:
  1778.     else
  1779.     {
  1780. return HXR_FAIL;
  1781.     }
  1782. }
  1783. HX_RESULT
  1784. CSmilParser::parseSyncBehaviorVal(const char* pSyncBehaviorBuf,
  1785.        CSmilElement* pElement,
  1786.        SMILSyncAttributeTag nTag)
  1787. {
  1788.     HX_RESULT ret = HXR_OK;
  1789.     if (NULL == pSyncBehaviorBuf  ||  (SMILSyncAttrSyncBehavior != nTag  &&
  1790.     SMILSyncAttrSyncBehaviorDefault != nTag))
  1791.     {
  1792. HX_ASSERT(FALSE);
  1793. return HXR_UNEXPECTED;
  1794.     }
  1795.     // First, eat all whitespace:
  1796.     const char* pCh = pSyncBehaviorBuf;
  1797.     while (*pCh  &&  isspace(*pCh))
  1798.     {
  1799. ++pCh;
  1800.     }
  1801.     if (*pCh == '')
  1802.     {
  1803. // nothing, empty attribute...
  1804. return HXR_OK;
  1805.     }
  1806.     BOOL bParsedOK = TRUE;
  1807.     SMILSyncBehaviorType sbtype = SmilSyncBehaviorInvalid;
  1808.     if (strncmp(pCh, "canSlip", 7) == 0)
  1809.     {
  1810. pCh += 7;
  1811. sbtype = SmilSyncBehaviorCanSlip;
  1812.     }
  1813.     else if (strncmp(pCh, "locked", 6) == 0)
  1814.     {
  1815. pCh += 6;
  1816. sbtype = SmilSyncBehaviorLocked;
  1817.     }
  1818.     else if (strncmp(pCh, "independent", 11) == 0)
  1819.     {
  1820. pCh += 11;
  1821. sbtype = SmilSyncBehaviorIndependent;
  1822.     }
  1823.     else if (strncmp(pCh, "default", 7) == 0)
  1824.     {
  1825. pCh += 7;
  1826. sbtype = SmilSyncBehaviorDefault;
  1827.     }
  1828.     else if (strncmp(pCh, "inherit", 7) == 0)
  1829.     {
  1830. pCh += 7;
  1831. sbtype = SmilSyncBehaviorInherit;
  1832.     }
  1833.     else
  1834.     {
  1835. bParsedOK = FALSE;
  1836.     }
  1837.     if (bParsedOK)
  1838.     {
  1839. while (*pCh  &&  isspace(*pCh))
  1840. {
  1841.     ++pCh;
  1842. }
  1843. if (*pCh)
  1844. {
  1845.     bParsedOK = FALSE;  // /Should only be whitespace after value.
  1846. }
  1847.     }
  1848.     if (SMILSyncAttrSyncBehavior == nTag)
  1849.     {
  1850. pElement->m_syncBehavior = sbtype;
  1851. // /syncBehavior can not be "inherit":
  1852. bParsedOK = bParsedOK  &&  (SmilSyncBehaviorInherit != sbtype);
  1853.     }
  1854.     else
  1855.     {
  1856. pElement->m_syncBehaviorDefault = sbtype;
  1857. // /syncBehaviorDefault can not be "default":
  1858. bParsedOK = bParsedOK  &&  (SmilSyncBehaviorDefault != sbtype);
  1859.     }
  1860.     if (SmilSyncBehaviorInvalid == sbtype  ||  !bParsedOK)
  1861.     {
  1862. ret = HXR_INVALID_PARAMETER;
  1863.     }
  1864.     return ret;
  1865. }
  1866. HX_RESULT
  1867. CSmilParser::parsePeersHigherLower(const char* pBuf,
  1868.        CSmilPriorityClassElement* pPCElement,
  1869.        SMILPriorityClassPeersHigherLowerAttrib nAttrib)
  1870. {
  1871.     HX_RESULT ret = HXR_OK;
  1872.     if (NULL == pBuf  ||  (SMILPriorityClassPeers != nAttrib  &&
  1873.     SMILPriorityClassHigher != nAttrib  &&
  1874.     SMILPriorityClassLower != nAttrib))
  1875.     {
  1876. HX_ASSERT(FALSE);
  1877. return HXR_UNEXPECTED;
  1878.     }
  1879.     BOOL bParsedOK = TRUE;
  1880.     SMILPriorityClassPeersHigherLowerVal val =
  1881.     SMILPriorityClassPeersHigherLowerInvalid;
  1882.     // First, eat all whitespace:
  1883.     const char* pCh = pBuf;
  1884.     while (*pCh  &&  isspace(*pCh))
  1885.     {
  1886. ++pCh;
  1887.     }
  1888.     if (*pCh == '')
  1889.     {
  1890. ret = HXR_INVALID_PARAMETER;
  1891. goto cleanup;
  1892.     }
  1893.     if (strncmp(pCh, "stop", 4) == 0)
  1894.     {
  1895. pCh += 4;
  1896. val = SMILPriorityClassStop;
  1897.     }
  1898.     else if (strncmp(pCh, "pause", 5) == 0)
  1899.     {
  1900. pCh += 5;
  1901. val = SMILPriorityClassPause;
  1902.     }
  1903.     else if (strncmp(pCh, "defer", 5) == 0)
  1904.     {
  1905. pCh += 5;
  1906. val = SMILPriorityClassDefer;
  1907.     }
  1908.     else if (strncmp(pCh, "never", 5) == 0)
  1909.     {
  1910. pCh += 5;
  1911. val = SMILPriorityClassNever;
  1912.     }
  1913.     else
  1914.     {
  1915. bParsedOK = FALSE;
  1916.     }
  1917.     if (bParsedOK)
  1918.     {
  1919. while (*pCh  &&  isspace(*pCh))
  1920. {
  1921.     ++pCh;
  1922. }
  1923. if (*pCh)
  1924. {
  1925.     bParsedOK = FALSE;  // /Should only be whitespace after value.
  1926. }
  1927.     }
  1928.     if (SMILPriorityClassPeers == nAttrib)
  1929.     {
  1930. pPCElement->m_peers = val;
  1931.     }
  1932.     else if (SMILPriorityClassHigher == nAttrib)
  1933.     {
  1934. pPCElement->m_higher = val;
  1935. // /higher can't be "defer" or "never":
  1936. bParsedOK = bParsedOK  &&  (SMILPriorityClassDefer != val  &&
  1937. SMILPriorityClassNever != val);
  1938.     }
  1939.     else // /SMILPriorityClassLower
  1940.     {
  1941. pPCElement->m_lower = val;
  1942. // /lower can't be "stop" or "pause":
  1943. bParsedOK = bParsedOK  &&  (SMILPriorityClassStop != val  &&
  1944. SMILPriorityClassPause != val);
  1945.     }
  1946.     if (SMILPriorityClassPeersHigherLowerAttribInvalid== val  ||  !bParsedOK)
  1947.     {
  1948. ret = HXR_INVALID_PARAMETER;
  1949.     }
  1950. cleanup:
  1951.     return ret;
  1952. }
  1953. HX_RESULT
  1954. CSmilParser::parsePauseDisplay(const char* pBuf,
  1955.        CSmilPriorityClassElement* pPCElement)
  1956. {
  1957.     HX_RESULT ret = HXR_OK;
  1958.     if (NULL == pBuf)
  1959.     {
  1960. HX_ASSERT(FALSE);
  1961. return HXR_UNEXPECTED;
  1962.     }
  1963.     BOOL bParsedOK = TRUE;
  1964.     // First, eat all whitespace:
  1965.     const char* pCh = pBuf;
  1966.     while (*pCh  &&  isspace(*pCh))
  1967.     {
  1968. ++pCh;
  1969.     }
  1970.     if (*pCh == '')
  1971.     {
  1972. ret = HXR_INVALID_PARAMETER;
  1973. goto cleanup;
  1974.     }
  1975.     pPCElement->m_pauseDisplay = SMILPriorityClassPauseDisplayInvalid;
  1976.     if (strncmp(pCh, "disable", 7) == 0)
  1977.     {
  1978. pCh += 7;
  1979. pPCElement->m_pauseDisplay = SMILPriorityClassPauseDisplayDisable;
  1980.     }
  1981.     else if (strncmp(pCh, "hide", 4) == 0)
  1982.     {
  1983. pCh += 4;
  1984. pPCElement->m_pauseDisplay = SMILPriorityClassPauseDisplayHide;
  1985.     }
  1986.     else if (strncmp(pCh, "show", 4) == 0)
  1987.     {
  1988. pCh += 4;
  1989. pPCElement->m_pauseDisplay = SMILPriorityClassPauseDisplayShow;
  1990.     }
  1991.     else
  1992.     {
  1993. bParsedOK = FALSE;
  1994.     }
  1995.     if (bParsedOK)
  1996.     {
  1997. while (*pCh  &&  isspace(*pCh))
  1998. {
  1999.     ++pCh;
  2000. }
  2001. if (*pCh)
  2002. {
  2003.     bParsedOK = FALSE;  // /Should only be whitespace after value.
  2004. }
  2005.     }
  2006.     if (SMILPriorityClassPauseDisplayInvalid == pPCElement->m_pauseDisplay
  2007.     ||  !bParsedOK)
  2008.     {
  2009. ret = HXR_INVALID_PARAMETER;
  2010.     }
  2011. cleanup:
  2012.     return ret;
  2013. }
  2014. HX_RESULT
  2015. CSmilParser::parseAnchorCoords(const char* pCoords,
  2016.        CSmilAnchorElement* pAnchor)
  2017. {
  2018.     HX_RESULT rc = HXR_OK;
  2019.     INT16 iNumCoords = 0;
  2020.     BOOL bIsCircle = FALSE;
  2021.     BOOL bIsPoly = FALSE;
  2022.     if (0==pAnchor->m_shape.GetLength()  ||
  2023.     0==strcmp(pAnchor->m_shape, "rect"))
  2024.     {
  2025. iNumCoords = 4;
  2026.     }
  2027.     else if (0==strcmp(pAnchor->m_shape, "circle"))
  2028.     {
  2029. bIsCircle = TRUE;
  2030. iNumCoords = 3;
  2031.     }
  2032.     // /XXXEH- TODO: handle shape="poly":
  2033.     else if (0==strcmp(pAnchor->m_shape, "poly"))
  2034.     {
  2035. // /Handles conversion of string to array:
  2036. pAnchor->convertRawPolyData(pCoords);
  2037. bIsPoly = TRUE;
  2038.     }
  2039.     else
  2040.     {
  2041. return HXR_INVALID_PARAMETER;
  2042.     }
  2043.     if (!bIsPoly)
  2044.     {
  2045. double coordArray[4];
  2046. BOOL percentArray[4];
  2047. int i = 0;
  2048. for(i=0; i<4; ++i)
  2049. {
  2050.     coordArray[i] = 0.0;
  2051.     percentArray[i] = FALSE;
  2052. }
  2053. char* pCoordCopy = new_string(pCoords);
  2054. char* pTok = strtok(pCoordCopy, ",");
  2055. for(i=0;i<iNumCoords,pTok;++i)
  2056. {
  2057.     char* pEndPtr = 0;
  2058.     double dVal = strtod(pTok, &pEndPtr);
  2059.     coordArray[i] = dVal;
  2060.     percentArray[i] = (*pEndPtr == '%') ? TRUE: FALSE;
  2061.     pTok = strtok(NULL, ",");
  2062. }
  2063. delete[] pCoordCopy;
  2064. pAnchor->m_ulOriginalLeftX = pAnchor->m_ulLeftX =
  2065.     (UINT32)coordArray[0];
  2066. pAnchor->m_bLeftXIsPercent = percentArray[0];
  2067. pAnchor->m_ulOriginalTopY = pAnchor->m_ulTopY =
  2068.     (UINT32)coordArray[1];
  2069. pAnchor->m_bTopYIsPercent = percentArray[1];
  2070. if (bIsCircle)
  2071. {
  2072.     pAnchor->m_ulOriginalRadius = pAnchor->m_ulRadius =
  2073. (UINT32)coordArray[2];
  2074.     pAnchor->m_bRadiusIsPercent = percentArray[2];
  2075. }
  2076. else // /Rect:
  2077. {
  2078.     pAnchor->m_ulOriginalRightX = pAnchor->m_ulRightX =
  2079. (UINT32)coordArray[2];
  2080.     pAnchor->m_bRightXIsPercent = percentArray[2];
  2081.     pAnchor->m_ulOriginalBottomY = pAnchor->m_ulBottomY =
  2082. (UINT32)coordArray[3];
  2083.     pAnchor->m_bBottomYIsPercent = percentArray[3];
  2084. }
  2085.     }
  2086.     pAnchor->m_bCoordsSet = TRUE;
  2087.     return rc;
  2088. }
  2089. // Functions to parse SMIL Boston Begin & Ends
  2090. HX_RESULT
  2091. CSmilParser::parseBeginEnd(const char* pBuffer,
  2092.        CSmilElement* pElement,
  2093.        SMILSyncAttributeTag nTag)
  2094. {
  2095.     HX_RESULT ret = HXR_OK;
  2096.     if (pBuffer == NULL || (nTag != SMILSyncAttrBegin &&
  2097. nTag != SMILSyncAttrEnd))
  2098.     {
  2099. HX_ASSERT(FALSE);
  2100. return HXR_FAIL;
  2101.     }
  2102.     // First we will eat all whitespace.
  2103.     const char* pCh = pBuffer;
  2104.     while (*pCh && isspace(*pCh))
  2105.     {
  2106. ++pCh;
  2107.     }
  2108.     if (*pCh == '')
  2109.     {
  2110. // nothing, empty attribute...
  2111. return HXR_OK;
  2112.     }
  2113.     // /XXXEH- make sure this is not followed by a list of times,
  2114.     // which would be an error, e.g., begin="id(foo)(begin); 5s".
  2115.     // we need to check for a smil-1.0-syncbase-value && indefinite
  2116.     if (strncmp(pCh, "id(", 3) == 0)
  2117.     {
  2118. // /XXXEH- TODO: make sure this value gets inserted into the
  2119. // begin|end time list so that any calls to getNextResolvedTimeValue
  2120. // return the correct (and only) value:
  2121. ret = parseSmil1SyncbaseValue(pCh, pElement, nTag);
  2122. // smil-1.0-syncbase-value
  2123. if (SMILSyncAttrEnd == nTag)
  2124. {
  2125.     // /This is needed to trick the core into letting the
  2126.     // media play when we give it a yet-unresolved end:
  2127.     pElement->m_ulDuration = WAY_IN_THE_FUTURE;
  2128. }
  2129.     }
  2130.     else
  2131.     {
  2132. // /If we see "indefinite" in a begin or end list, we need to ignore
  2133. // it if any other begin or end time in the list is valid:
  2134. BOOL bAlreadyHasValidNonIndefiniteValue = FALSE;
  2135. // /Fixes PR 50676(parts 1,2,3 & 4) where element has end=[some event]
  2136. // or end="indefinite" and dur=[some val]; we want to use the dur and
  2137. // ignore the end (for now, if it's an event-based end) in that case:
  2138. if (pElement->m_bHasExplicitDur  &&  !pElement->m_bIndefiniteDuration)
  2139. {
  2140.     bAlreadyHasValidNonIndefiniteValue = TRUE;
  2141. }
  2142. // It's a value or value list:
  2143. do
  2144. {
  2145.     if (*pCh == ';')
  2146.     {
  2147. ++pCh;
  2148. // /SMIL Boston spec says that leading and trailing white-
  2149. // space characters are allowed and should be ignored.
  2150. // e.g., "5s; foo.activateEvent":
  2151. // /Get rid of white space after each ';'
  2152. while (*pCh  &&  isspace(*pCh) )
  2153. {
  2154.     ++pCh;
  2155. }
  2156. if (!(*pCh))
  2157. {
  2158.     break; // /We've found nothing but spaces after the ;
  2159. }
  2160.     }
  2161.     SmilTimeValue* pVal = new SmilTimeValue(m_pContext,
  2162. pElement->m_pNode->m_ulTagStartLine, pElement);
  2163.     const char* begin = pCh;
  2164.     char* buffer = NULL;
  2165.     while (*pCh && *pCh != ';')
  2166.     {
  2167. ++pCh;
  2168.     }
  2169.     if (*pCh == ';')
  2170.     {
  2171. #if XXXEH
  2172. // /SMIL Boston spec says that leading and trailing white-
  2173. // space characters are allowed and should be ignored.
  2174. // e.g., "5s; foo.activateEvent":
  2175. // /Get rid of white space before each ';'
  2176. const char* pBkCh = pCh-1;
  2177. while (*pBkCh  &&  pBkCh!=begin  &&  isspace(*pBkCh) )
  2178. {
  2179.     --pCh;
  2180.     --pBkCh;
  2181. }
  2182. #endif
  2183. buffer = new char[pCh - begin + 1];
  2184. strncpy(buffer, begin, pCh - begin); /* Flawfinder: ignore */
  2185. buffer[pCh - begin] = '';
  2186. begin = buffer;
  2187.     }
  2188.     if (strcmp(begin, "indefinite") == 0  &&
  2189.     !bAlreadyHasValidNonIndefiniteValue)
  2190.     {
  2191. // / "indefinite"
  2192. if (nTag == SMILSyncAttrBegin)
  2193. {
  2194.     pElement->m_bIndefiniteBegin = TRUE;
  2195. }
  2196. else if (nTag == SMILSyncAttrEnd)
  2197. {
  2198.     pElement->m_bIndefiniteEnd = TRUE;
  2199.     pElement->m_bIndefiniteDuration = TRUE;
  2200. }
  2201.     }
  2202.     else
  2203.     {
  2204. ret = pVal->parseValue(begin, nTag,
  2205. (const char*)(pElement->m_pNode->m_id));
  2206. HX_VECTOR_DELETE(buffer); // /Fix mem leak for >1st list times.
  2207. pVal->setTimeOffset(m_tRefTime);
  2208. HX_VECTOR_DELETE(buffer);
  2209. if (SUCCEEDED(ret))
  2210. {
  2211.     if (SmilTimeEvent == pVal->m_type)
  2212.     {
  2213. pElement->m_bHasAtLeastOneEventBasedBegin = TRUE;
  2214.     }
  2215.     else
  2216.     {
  2217. pElement->m_bHasAtLeastOneNonEventBasedBegin = TRUE;
  2218.     }
  2219.     if (nTag == SMILSyncAttrBegin)
  2220.     {
  2221. // /If time found was a resolved time (i.e., not an
  2222. // event-arc or sync-arc, then reset indefinite-begin
  2223. // flag since we've found another begin time (which
  2224. // means we should now ignore any "indefinite"
  2225. // value(s) already found):
  2226. if (pVal->isTimeResolved())
  2227. {
  2228.     pElement->m_bIndefiniteBegin = FALSE;
  2229.     bAlreadyHasValidNonIndefiniteValue = TRUE;
  2230. }
  2231. if (!pElement->m_pBeginTimeList)
  2232. {
  2233.     pElement->m_pBeginTimeList = new CHXSimpleList;
  2234. }
  2235. pElement->m_pBeginTimeList->AddTail(pVal);
  2236.     }
  2237.     else // (nTag == SMILSyncAttrEnd)
  2238.     {
  2239. // /If time found was a resolved time (i.e., not an
  2240. // event-arc or sync-arc, then reset indefinite-begin
  2241. // flag since we've found another end time (which
  2242. // means we should now ignore any "indefinite"
  2243. // value(s) already found):
  2244. if (pVal->isTimeResolved())
  2245. {
  2246.     pElement->m_bIndefiniteEnd = FALSE;
  2247.     pElement->m_bIndefiniteDuration = FALSE;
  2248.     bAlreadyHasValidNonIndefiniteValue = TRUE;
  2249. }
  2250. if (!pElement->m_pEndTimeList)
  2251. {
  2252.     pElement->m_pEndTimeList = new CHXSimpleList;
  2253. }
  2254. pElement->m_pEndTimeList->AddTail(pVal);
  2255.     }
  2256. }
  2257.     }
  2258. }
  2259. while (SUCCEEDED(ret) && *pCh == ';');
  2260. if (SMILSyncAttrEnd == nTag  &&
  2261. !bAlreadyHasValidNonIndefiniteValue)
  2262. {
  2263.     // /XXXEH- this is needed to trick the core into letting the
  2264.     // media play when we give it an indefinite end:
  2265.     pElement->m_ulDuration = WAY_IN_THE_FUTURE;
  2266. }
  2267. if (SUCCEEDED(ret))
  2268. {
  2269.     if (nTag == SMILSyncAttrBegin)
  2270.     {
  2271. if (FAILED(pElement->setBeginTime(this)))
  2272. {
  2273.     ret = HXR_FAIL;
  2274.     CSmilSMILSyntaxErrorHandler errHandler(m_pContext);
  2275.     errHandler.ReportError(SMILErrorTimeValueNotallowed,
  2276. pBuffer, pElement->m_pNode->m_ulTagStartLine);
  2277. }
  2278.     }
  2279.     else
  2280.     {
  2281. if (FAILED(pElement->setEndTime(this)))
  2282. {
  2283.     ret = HXR_FAIL;
  2284.     CSmilSMILSyntaxErrorHandler errHandler(m_pContext);
  2285.     errHandler.ReportError(SMILErrorTimeValueNotallowed,
  2286. pBuffer, pElement->m_pNode->m_ulTagStartLine);
  2287. }
  2288.     }
  2289. }
  2290.     }
  2291.     return ret;
  2292. }
  2293. HX_RESULT
  2294. CSmilParser::parseRestart(const char* pBuffer,
  2295.        CSmilElement* pElement)
  2296. {
  2297.     HX_RESULT ret = HXR_OK;
  2298.     if (NULL == pBuffer  ||  NULL == pElement)
  2299.     {
  2300. ret = HXR_FAILED;
  2301.     }
  2302.     else if (strcmp(pBuffer, "never") == 0)
  2303.     {
  2304. pElement->m_restartBehavior = SmilRestartNever;
  2305.     }
  2306.     else if (strcmp(pBuffer, "whenNotActive") == 0)
  2307.     {
  2308. pElement->m_restartBehavior = SmilRestartWhenNotActive;
  2309.     }
  2310.     else if (strcmp(pBuffer, "always") == 0)
  2311.     {
  2312. pElement->m_restartBehavior = SmilRestartAlways;
  2313.     }
  2314.     else if (strcmp(pBuffer, "default") == 0)
  2315.     {
  2316. pElement->m_restartBehavior =
  2317. pElement->m_restartDefaultBehavior;
  2318. if (SmilRestartInherit == pElement->m_restartBehavior)
  2319. {
  2320.     pElement->getParentRestartDefault();
  2321. }
  2322.     }
  2323.     else
  2324.     {
  2325. ret = HXR_FAILED;
  2326.     }
  2327.     return ret;
  2328. }
  2329. // /XXXEH- TODO: use this in all parseXXX() functions:
  2330. const char*
  2331. CSmilParser::removeSurroundingWhitespace(const char* pValue)
  2332. {
  2333.     const char* pRetStr = pValue;
  2334.     if (pRetStr)
  2335.     {
  2336. while (*pRetStr  &&  isspace(*pRetStr))
  2337. {
  2338.     pRetStr++;
  2339. }
  2340.     }
  2341.     UINT32 ulLen = (UINT32)strlen(pRetStr);
  2342.     char* pRetStrEnd = ulLen>0? (char*)(&(pRetStr[ulLen-1])) : NULL;
  2343.     if (pRetStrEnd)
  2344.     {
  2345. while (pRetStrEnd>pRetStr  &&  *pRetStrEnd  &&
  2346. isspace(*pRetStrEnd))
  2347. {
  2348.     pRetStrEnd--;
  2349. }
  2350. // /End the string (this may already be '', but who cares?):
  2351. *(pRetStrEnd+1) = '';
  2352.     }
  2353.     return pRetStr;
  2354. }
  2355. HX_RESULT
  2356. CSmilParser::parseSensitivity(const char* pValue, CSmilElement* pSource)
  2357. {
  2358.     HX_RESULT ret = HXR_OK;
  2359.     const char* pWhitespaceRemoved = removeSurroundingWhitespace(pValue);
  2360.     if (NULL == pWhitespaceRemoved  ||  NULL == pSource)
  2361.     {
  2362. ret = HXR_INVALID_PARAMETER;
  2363.     }
  2364.     else
  2365.     {
  2366. UINT32 ulStrLen = strlen(pWhitespaceRemoved);
  2367. if (strcmp(pWhitespaceRemoved, "opaque") == 0)
  2368. {
  2369.     pSource->m_sensitivityToMouseEvents = pWhitespaceRemoved;
  2370. }
  2371. else if (strcmp(pWhitespaceRemoved, "transparent") == 0)
  2372. {
  2373.     pSource->m_sensitivityToMouseEvents = pWhitespaceRemoved;
  2374. }
  2375. // /Can't be longer than "+100%" or shorter than "0%":
  2376. else if (ulStrLen <= 5  &&  ulStrLen >= 2)
  2377. {
  2378.     // /Spec "Valid values are non-negative CSS2 percentage values":
  2379.     if ('+' == *pWhitespaceRemoved)
  2380.     {
  2381. pWhitespaceRemoved++;
  2382. ulStrLen--;
  2383.     }
  2384.     // /Then, add up the numbers:
  2385.     char* pTmp = (char*)pWhitespaceRemoved;
  2386.     ULONG32 ulNum = 0;
  2387.     BOOL bFoundNumber = FALSE;
  2388.     while (*pTmp  &&  (*pTmp>='0'  &&  *pTmp<='9'))
  2389.     {
  2390. ulNum *= 10;
  2391. ulNum += *pTmp-'0';
  2392. ++pTmp;
  2393. bFoundNumber=TRUE;
  2394.     }
  2395.     // /Verify # was found, followed by '%', followed by nothing else:
  2396.     if (!bFoundNumber  ||  *pTmp != '%'  ||  *(pTmp+1) != '')
  2397.     {
  2398. ret = HXR_INVALID_PARAMETER;
  2399.     }
  2400.     else
  2401.     {
  2402. *pTmp = '';
  2403. pSource->m_sensitivityToMouseEvents = pWhitespaceRemoved;
  2404.     }
  2405. }
  2406. else
  2407. {
  2408.     ret = HXR_INVALID_PARAMETER;
  2409. }
  2410.     }
  2411.     return ret;
  2412. }
  2413. HX_RESULT
  2414. CSmilParser::parseRestartDefault(const char* pBuffer,
  2415.        CSmilElement* pElement)
  2416. {
  2417.     HX_RESULT ret = HXR_OK;
  2418.     if (NULL == pBuffer  ||  NULL == pElement)
  2419.     {
  2420. ret = HXR_FAILED;
  2421.     }
  2422.     else if (strcmp(pBuffer, "never") == 0)
  2423.     {
  2424. pElement->m_restartDefaultBehavior = pElement->m_restartBehavior =
  2425. SmilRestartNever;
  2426.     }
  2427.     else if (strcmp(pBuffer, "whenNotActive") == 0)
  2428.     {
  2429. pElement->m_restartDefaultBehavior = pElement->m_restartBehavior =
  2430. SmilRestartWhenNotActive;
  2431.     }
  2432.     else if (strcmp(pBuffer, "always") == 0)
  2433.     {
  2434. pElement->m_restartDefaultBehavior = pElement->m_restartBehavior =
  2435. SmilRestartAlways;
  2436.     }
  2437.     else if (strcmp(pBuffer, "inherit") == 0)
  2438.     {
  2439. pElement->getParentRestartDefault();
  2440.     }
  2441.     else
  2442.     {
  2443. ret = HXR_FAILED;
  2444.     }
  2445.     return ret;
  2446. }
  2447. FillDefaultType CSmilParser::getFillDefault(CSmilElement* pElement)
  2448. {
  2449.     FillDefaultType eFillDefault = FillDefaultAuto;
  2450.     if (pElement)
  2451.     {
  2452.         // Get our fillDefault
  2453.         eFillDefault = pElement->m_eFillDefault;
  2454.         // If the fillDefault is "inherit", then
  2455.         // get our parent's fillDefault
  2456.         if (eFillDefault == FillDefaultInherit &&
  2457.             pElement->m_pNode && pElement->m_pNode->m_pParent)
  2458.         {
  2459.             eFillDefault = getFillDefault(pElement->m_pNode->m_pParent->m_pElement);
  2460.         }
  2461.     }
  2462.     return eFillDefault;
  2463. }
  2464. void CSmilParser::resolveFillValue(CSmilElement* pElement)
  2465. {
  2466.     if (pElement)
  2467.     {
  2468.         // Get the tag of this element
  2469.         SMILNodeTag eTag = SMILUnknown;
  2470.         if (pElement->m_pNode)
  2471.         {
  2472.             eTag = pElement->m_pNode->m_tag;
  2473.         }
  2474.         // Resolve based on the parsed fill value.
  2475.         // If fill="default", then we resolve based on
  2476.         // the value of fillDefault. Also, if fill="transition"
  2477.         // and this is a time container, then we ignore
  2478.         // the parsed value (which makes it revert to the
  2479.         // default of fill="default").
  2480.         if (pElement->m_eFill == FillDefault ||
  2481.             (pElement->m_eFill == FillTransition &&
  2482.              (eTag == SMILPar || eTag == SMILSeq || eTag == SMILExcl)))
  2483.         {
  2484.             // Resolve the fillDefault attribute
  2485.             FillDefaultType eDefault = getFillDefault(pElement);
  2486.             // Map this to a fill value
  2487.             if (eDefault == FillDefaultRemove)
  2488.             {
  2489.                 pElement->m_eActualFill = FillDefault;
  2490.             }
  2491.             else if (eDefault == FillDefaultFreeze)
  2492.             {
  2493.                 pElement->m_eActualFill = FillFreeze;
  2494.             }
  2495.             else if (eDefault == FillDefaultHold)
  2496.             {
  2497.                 pElement->m_eActualFill = FillHold;
  2498.             }
  2499.             else if (eDefault == FillDefaultTransition)
  2500.             {
  2501.                 pElement->m_eActualFill = FillTransition;
  2502.             }
  2503.             else if (eDefault == FillDefaultAuto)
  2504.             {
  2505.                 // For fill="auto", we have to determine if either "dur",
  2506.                 // "end", "repeatCount", or "repeatDur" are specified.
  2507.                 // If none of these are specified, then we use fill="freeze".
  2508.                 // Otherwise, it's fill="remove". So initially we assign
  2509.                 // fill="remove" and then if none of these four are
  2510.                 // specified, then we replace it with fill="freeze".
  2511.                 if (isAttributeSpecified(pElement, "dur")         ||
  2512.                     isAttributeSpecified(pElement, "end")         ||
  2513.                     isAttributeSpecified(pElement, "repeatCount") ||
  2514.                     isAttributeSpecified(pElement, "repeatDur"))
  2515.                 {
  2516.                     pElement->m_eActualFill = FillRemove;
  2517.                 }
  2518.                 else
  2519.                 {
  2520.                     pElement->m_eActualFill = FillFreeze;
  2521.                 }
  2522.             }
  2523.         }
  2524.         else
  2525.         {
  2526.             pElement->m_eActualFill = pElement->m_eFill;
  2527.         }
  2528.     }
  2529. }
  2530. BOOL CSmilParser::isAttributeSpecified(CSmilElement* pElement,
  2531.                                        const char*   pszAttr)
  2532. {
  2533.     BOOL bRet = FALSE;
  2534.     if (pElement &&
  2535.         pElement->m_pNode &&
  2536.         pElement->m_pNode->m_pValues &&
  2537.         pszAttr)
  2538.     {
  2539.         IHXBuffer* pTmp = NULL;
  2540.         HX_RESULT   rv   = pElement->m_pNode->m_pValues->GetPropertyCString(pszAttr, pTmp);
  2541.         if (SUCCEEDED(rv))
  2542.         {
  2543.             bRet = TRUE;
  2544.         }
  2545.         HX_RELEASE(pTmp);
  2546.     }
  2547.     return bRet;
  2548. }
  2549. #if defined(HELIX_FEATURE_SMIL2_TRANSITIONS)
  2550. HX_RESULT CSmilParser::getNextTransitionEnd(CSmilElement* pElement, REF(UINT32) rulTime)
  2551. {
  2552.     HX_RESULT retVal = HXR_FAIL;
  2553.     if (pElement)
  2554.     {
  2555.         // Make sure this element has defined start
  2556.         // and end times
  2557.         if (pElement->m_ulDelay    != ((UINT32) -1) &&
  2558.             pElement->m_ulDuration != ((UINT32) -1))
  2559.         {
  2560.             // Get the time we would normally be removed
  2561.             // XXXMEH - DELAY_DUR_FIX
  2562.             UINT32 ulOurNormalRemoveTime = pElement->m_ulDelay + pElement->m_ulDuration -
  2563.                                            (pElement->m_bBeginOffsetSet ? pElement->m_lBeginOffset : 0);
  2564.             UINT32    ulStop = 0;
  2565.             HX_RESULT rv     = pElement->getCurrentScheduledStopTime(ulStop);
  2566.             if (SUCCEEDED(rv))
  2567.             {
  2568.                 ulOurNormalRemoveTime = ulStop;
  2569.             }
  2570.             // Get the parent of this element
  2571.             SMILNode* pParentNode = getSyncAncestor(pElement->m_pNode);
  2572.             if (pParentNode)
  2573.             {
  2574.                 // Loop through the children of the parent
  2575.                 BOOL      bFound     = FALSE;
  2576.                 UINT32    ulNextTime = 0;
  2577.                 SMILNode* pChildNode = pParentNode->getFirstChild();
  2578.                 while (pChildNode)
  2579.                 {
  2580.                     // Get the CSmilElement for this child
  2581.                     CSmilElement* pChildElement = pChildNode->m_pElement;
  2582.                     if (pChildElement)
  2583.                     {
  2584.                         // Does this child have a begin transition?
  2585.                         if (pChildElement->m_beginTransition.GetLength() > 0)
  2586.                         {
  2587.                             // Is this child scheduled?
  2588.                             if (pChildElement->m_ulDelay != ((UINT32) -1))
  2589.                             {
  2590.                                 // Look up the transition
  2591.                                 void* pVoid = NULL;
  2592.                                 if (m_pTransitionMap &&
  2593.                                     m_pTransitionMap->Lookup((const char*) pChildElement->m_beginTransition,
  2594.                                                              pVoid) &&
  2595.                                     pVoid)
  2596.                                 {
  2597.                                     // Get the start time of this transition
  2598.                                     UINT32 ulStart = pChildElement->m_ulDelay;
  2599.                                     // Get the ending time of this transition
  2600.                                     CSmilTransition* pTrans = (CSmilTransition*) pVoid;
  2601.                                     UINT32           ulEnd  = pChildElement->m_ulDelay +
  2602.                                                               pTrans->m_ulDuration;
  2603.                                     // Does this transition start after our
  2604.                                     // normal remove time?
  2605.                                     if (ulStart >= ulOurNormalRemoveTime)
  2606.                                     {
  2607.                                         // We have found a potential transition, so
  2608.                                         // save the minimum time of these potential
  2609.                                         // transition ends
  2610.                                         if (bFound)
  2611.                                         {
  2612.                                             if (ulEnd < ulNextTime)
  2613.                                             {
  2614.                                                 ulNextTime = ulEnd;
  2615.                                             }
  2616.                                         }
  2617.                                         else
  2618.                                         {
  2619.                                             bFound     = TRUE;
  2620.                                             ulNextTime = ulEnd;
  2621.                                         }
  2622.                                     }
  2623.                                 }
  2624.                             }
  2625.                         }
  2626.                     }
  2627.                     pChildNode = pParentNode->getNextChild();
  2628.                 }
  2629.                 // Did we find any suitable transition end time?
  2630.                 if (bFound)
  2631.                 {
  2632.                     rulTime = ulNextTime;
  2633.                     retVal  = HXR_OK;
  2634.                 }
  2635.             }
  2636.         }
  2637.     }
  2638.     return retVal;
  2639. }
  2640. #endif /* #if defined(HELIX_FEATURE_SMIL2_TRANSITIONS) */
  2641. void CSmilParser::initParsingMaps()
  2642. {
  2643.     UINT32 i = 0;
  2644.     // Init the element map
  2645.     HX_DELETE(m_pElementMap);
  2646.     m_pElementMap = new CHXMapStringToOb();
  2647.     if (m_pElementMap)
  2648.     {
  2649.         SMILElementTable* pTmp = (SMILElementTable*) &g_ElementTable[0];
  2650.         while (pTmp && pTmp->m_eElement != NumSMIL2Elements)
  2651.         {
  2652.             m_pElementMap->SetAt(pTmp->m_pszString,
  2653.                                  (void*) pTmp->m_eElement);
  2654.             pTmp++;
  2655.         }
  2656.     }
  2657.     // Alloc the attribute map
  2658.     HX_DELETE(m_pAttributeMap);
  2659.     m_pAttributeMap = new CHXMapStringToOb();
  2660.     if (m_pAttributeMap)
  2661.     {
  2662.         // Init the SMIL 2 attribute map. This
  2663.         // ONLY contains attributes from the SMIL 2 namespace
  2664.         SMILAttributeTable* pTmp = (SMILAttributeTable*) &g_AttributeTable[0];
  2665.         while (pTmp && pTmp->m_eAttribute != NumSMIL2Attributes)
  2666.         {
  2667.             m_pAttributeMap->SetAt(pTmp->m_pszString,
  2668.                                    (void*) pTmp->m_eAttribute);
  2669.             pTmp++;
  2670.         }
  2671.     }
  2672. #if defined(HELIX_FEATURE_SMIL2_VALIDATION)
  2673.     // Init the RN extension element map
  2674.     HX_DELETE(m_pExtElementMap);
  2675.     m_pExtElementMap = new CHXMapStringToOb();
  2676.     if (m_pExtElementMap)
  2677.     {
  2678.         SMILElementTable* pTmp = (SMILElementTable*) &g_ExtElementTable[0];
  2679.         while (pTmp && pTmp->m_eElement != NumSMIL2Elements)
  2680.         {
  2681.             m_pExtElementMap->SetAt(pTmp->m_pszString,
  2682.                                     (void*) pTmp->m_eElement);
  2683.             pTmp++;
  2684.         }
  2685.     }
  2686.     // Create the attribute type array
  2687.     HX_VECTOR_DELETE(m_pAttrType);
  2688.     m_pAttrType = new XMLAttributeType [NumSMIL2Attributes];
  2689.     if (m_pAttrType)
  2690.     {
  2691.         // Init the SMIL 2 attribute map. This
  2692.         // ONLY contains attributes from the SMIL 2 namespace
  2693.         SMILAttributeTable* pTmp = (SMILAttributeTable*) &g_AttributeTable[0];
  2694.         while (pTmp && pTmp->m_eAttribute != NumSMIL2Attributes)
  2695.         {
  2696.             m_pAttrType[pTmp->m_eAttribute] = pTmp->m_eType;
  2697.             pTmp++;
  2698.         }
  2699.     }
  2700.     // Alloc the extension attribute map
  2701.     HX_DELETE(m_pExtAttributeMap);
  2702.     m_pExtAttributeMap = new CHXMapStringToOb();
  2703.     if (m_pExtAttributeMap)
  2704.     {
  2705.         // Init the SMIL 2 extension attribute map. This
  2706.         // ONLY contains attributes from the RN extension namespace
  2707.         SMILAttributeTable* pTmp = (SMILAttributeTable*) &g_ExtAttributeTable[0];
  2708.         while (pTmp && pTmp->m_eAttribute != NumSMIL2Attributes)
  2709.         {
  2710.             m_pExtAttributeMap->SetAt(pTmp->m_pszString,
  2711.                                       (void*) pTmp->m_eAttribute);
  2712.             if (m_pAttrType) m_pAttrType[pTmp->m_eAttribute] = pTmp->m_eType;
  2713.             pTmp++;
  2714.         }
  2715.     }
  2716.     // Init the legal attribute map
  2717.     HX_DELETE(m_pLegalAttrMap);
  2718.     m_pLegalAttrMap = new CRNBinaryMap();
  2719.     if (m_pLegalAttrMap)
  2720.     {
  2721.         HX_RESULT rv = m_pLegalAttrMap->Init(NumSMIL2Elements, NumSMIL2Attributes);
  2722.         if (SUCCEEDED(rv))
  2723.         {
  2724.             BYTE* pVal   = (BYTE*) g_LegalAttr;
  2725.             BYTE* pLimit = pVal + sizeof(g_LegalAttr);
  2726.             while (pVal < pLimit && *pVal != NumSMIL2Elements)
  2727.             {
  2728.                 // First in list is an element
  2729.                 UINT32 ulElement = *pVal++;
  2730.                 // Next is the number of attribute collections
  2731.                 UINT32 ulNumColl = *pVal++;
  2732.                 // Next is the number of attributes not in collections
  2733.                 UINT32 ulNumAttr = *pVal++;
  2734.                 // Process the attribute collections
  2735.                 for (i = 0; i < ulNumColl; i++)
  2736.                 {
  2737.                     UINT32 ulCollectionIndex = *pVal++;
  2738.                     processCollection(m_pLegalAttrMap, ulElement, ulCollectionIndex);
  2739.                 }
  2740.                 // Process the attributes which are not in a collection
  2741.                 for (i = 0; i < ulNumAttr; i++)
  2742.                 {
  2743.                     UINT32 ulAttr = *pVal++;
  2744.                     m_pLegalAttrMap->Set(ulElement, ulAttr);
  2745.                 }
  2746.             }
  2747.         }
  2748.     }
  2749.     // Init the content model
  2750.     HX_DELETE(m_pContentModelMap);
  2751.     m_pContentModelMap = new CRNBinaryMap();
  2752.     if (m_pContentModelMap)
  2753.     {
  2754.         HX_RESULT rv = m_pContentModelMap->Init(NumSMIL2Elements, NumSMIL2Elements);
  2755.         if (SUCCEEDED(rv))
  2756.         {
  2757.             BYTE*  pVal   = (BYTE*) g_LegalContent;
  2758.             BYTE*  pLimit = pVal + sizeof(g_LegalContent);
  2759.             while (pVal < pLimit && *pVal != NumSMIL2Elements)
  2760.             {
  2761.                 // First in list is an element
  2762.                 UINT32 ulElement = *pVal++;
  2763.                 // Next is the number of legal elements which
  2764.                 // can be children of this element
  2765.                 UINT32 ulNumElements = *pVal++;
  2766.                 // Process the list of elements
  2767.                 for (i = 0; i < ulNumElements; i++)
  2768.                 {
  2769.                     UINT32 ulLegalContentElement = *pVal++;
  2770.                     m_pContentModelMap->Set(ulElement, ulLegalContentElement);
  2771.                 }
  2772.             }
  2773.         }
  2774.     }
  2775.     // Init the enumerated attribute map
  2776.     deleteEnumAttrMaps();
  2777.     m_ppEnumAttrMap = new CHXMapStringToOb* [NumSMIL2Attributes];
  2778.     if (m_ppEnumAttrMap)
  2779.     {
  2780.         // Null out the pointer array
  2781.         memset((void*) m_ppEnumAttrMap, 0,
  2782.                NumSMIL2Attributes * sizeof(CHXMapStringToOb*));
  2783.         // Now run through the enumerated attribute table
  2784.         struct EnumAttrTable* pEntry = (struct EnumAttrTable*) g_EnumAttrTable;
  2785.         while (pEntry &&
  2786.                pEntry->m_eAttr != NumSMIL2Attributes)
  2787.         {
  2788.             // Get the attribute
  2789.             SMIL2Attribute eAttr = pEntry->m_eAttr;
  2790.             // Does a map already exist for this attribute?
  2791.             if (!m_ppEnumAttrMap[eAttr])
  2792.             {
  2793.                 m_ppEnumAttrMap[eAttr] = new CHXMapStringToOb();
  2794.             }
  2795.             if (m_ppEnumAttrMap[eAttr])
  2796.             {
  2797.                 // Set the enumerated type string into the map
  2798.                 m_ppEnumAttrMap[eAttr]->SetAt(pEntry->m_pszStr,
  2799.                                               (void*) pEntry->m_ucEnum);
  2800.             }
  2801.             pEntry++;
  2802.         }
  2803.     }
  2804.     // Init the required attribute lists
  2805.     deleteReqAttrLists();
  2806.     m_ppReqAttrList = new CHXSimpleList* [NumSMIL2Elements];
  2807.     if (m_ppReqAttrList)
  2808.     {
  2809.         // Null out the pointer array
  2810.         memset((void*) m_ppReqAttrList, 0,
  2811.                NumSMIL2Elements * sizeof(CHXSimpleList*));
  2812.         // Now run through the required attribute table
  2813.         BYTE* pVal   = (BYTE*) g_RequiredAttr;
  2814.         BYTE* pLimit = pVal + sizeof(g_RequiredAttr);
  2815.         while (pVal < pLimit && *pVal != NumSMIL2Elements)
  2816.         {
  2817.             // Get the element
  2818.             UINT32 ulElement = *pVal++;
  2819.             // Get the number of required attributes
  2820.             UINT32 ulNumReqAttrs = *pVal++;
  2821.             // Do we already have a list for this element?
  2822.             if (!m_ppReqAttrList[ulElement])
  2823.             {
  2824.                 // We don't already have one, so create one
  2825.                 m_ppReqAttrList[ulElement] = new CHXSimpleList();
  2826.             }
  2827.             if (m_ppReqAttrList[ulElement])
  2828.             {
  2829.                 for (UINT32 i = 0; i < ulNumReqAttrs; i++)
  2830.                 {
  2831.                     // Get the required attribute
  2832.                     UINT32 ulAttr = *pVal++;
  2833.                     // Add it to the list
  2834.                     m_ppReqAttrList[ulElement]->AddTail((void*) ulAttr);
  2835.                 }
  2836.             }
  2837.         }
  2838.     }
  2839.     // Init the namespace map
  2840.     HX_DELETE(m_pNamespaceMap);
  2841.     m_pNamespaceMap = new CHXMapStringToOb();
  2842.     if (m_pNamespaceMap)
  2843.     {
  2844.         struct NamespaceTable* pEntry = (struct NamespaceTable*) g_NamespaceTable;
  2845.         while (pEntry->m_eNamespace != NamespaceNotImplemented)
  2846.         {
  2847.             m_pNamespaceMap->SetAt(pEntry->m_pszStr, (void*) pEntry->m_eNamespace);
  2848.             pEntry++;
  2849.         }
  2850.     }
  2851. #endif /* #if defined(HELIX_FEATURE_SMIL2_VALIDATION) */
  2852. }
  2853. #if defined(HELIX_FEATURE_SMIL2_VALIDATION)
  2854. void CSmilParser::processCollection(CRNBinaryMap* pMap,
  2855.                                     UINT32        ulElement,
  2856.                                     UINT32        ulCollection)
  2857. {
  2858.     if (pMap                            &&
  2859.         ulElement    < NumSMIL2Elements &&
  2860.         ulCollection < NumSMIL2AttributeCollections)
  2861.     {
  2862.         // Init the parsing variables
  2863.         BYTE* pVal   = (BYTE*) g_AttrCollections;
  2864.         BYTE* pLimit = pVal + sizeof(g_AttrCollections);
  2865.         // Find our collection
  2866.         while (pVal < pLimit)
  2867.         {
  2868.             // Get the current collection
  2869.             UINT32 ulColl = *pVal++;
  2870.             // Get the number of attributes in this collection
  2871.             UINT32 ulNumAttr = *pVal++;
  2872.             // Is this our collection?
  2873.             if (ulColl == ulCollection)
  2874.             {
  2875.                 // This IS our collection, so process it
  2876.                 for (UINT32 i = 0; i < ulNumAttr; i++)
  2877.                 {
  2878.                     // Get the attribute
  2879.                     UINT32 ulAttr = *pVal++;
  2880.                     // Set it in the map
  2881.                     pMap->Set(ulElement, ulAttr);
  2882.                 }
  2883.                 // Now we can break out of the loop
  2884.                 break;
  2885.             }
  2886.             else
  2887.             {
  2888.                 // Not our collection, so just skip past it
  2889.                 pVal += ulNumAttr;
  2890.             }
  2891.         }
  2892.     }
  2893. }
  2894. void CSmilParser::deleteEnumAttrMaps()
  2895. {
  2896.     if (m_ppEnumAttrMap)
  2897.     {
  2898.         for (UINT32 i = 0; i < NumSMIL2Attributes; i++)
  2899.         {
  2900.             HX_DELETE(m_ppEnumAttrMap[i]);
  2901.         }
  2902.     }
  2903.     HX_VECTOR_DELETE(m_ppEnumAttrMap);
  2904. }
  2905. void CSmilParser::deleteReqAttrLists()
  2906. {
  2907.     if (m_ppReqAttrList)
  2908.     {
  2909.         for (UINT32 i = 0; i < NumSMIL2Elements; i++)
  2910.         {
  2911.             HX_DELETE(m_ppReqAttrList);
  2912.         }
  2913.     }
  2914.     HX_VECTOR_DELETE(m_ppReqAttrList);
  2915. }
  2916. #endif /* #if defined(HELIX_FEATURE_SMIL2_VALIDATION) */
  2917. void CSmilParser::deleteValidationNamespaceList()
  2918. {
  2919.     if (m_pValNSList)
  2920.     {
  2921.         LISTPOSITION pos = m_pValNSList->GetHeadPosition();
  2922.         while (pos)
  2923.         {
  2924.             CNamespaceInfo* pInfo = (CNamespaceInfo*) m_pValNSList->GetNext(pos);
  2925.             HX_DELETE(pInfo);
  2926.         }
  2927.     }
  2928.     HX_DELETE(m_pValNSList);
  2929. }
  2930. void CSmilParser::checkForXMMFDependency(CSmilElement* pElement)
  2931. {
  2932.     if (pElement->m_bUsesExternalMediaMarkerFile)
  2933.     {
  2934.         if (!m_pXMMFElementList)
  2935.         {
  2936.             m_pXMMFElementList = new CHXSimpleList();
  2937.         }
  2938.         if (m_pXMMFElementList)
  2939.         {
  2940.             m_pXMMFElementList->AddTail((void*) pElement);
  2941.         }
  2942.     }
  2943. }
  2944. void CSmilParser::handleAllXMMFReferences()
  2945. {
  2946.     if (m_pXMMFElementList)
  2947.     {
  2948.         LISTPOSITION pos = m_pXMMFElementList->GetHeadPosition();
  2949.         while (pos)
  2950.         {
  2951.             CSmilElement* pElement =
  2952.                 (CSmilElement*) m_pXMMFElementList->GetNext(pos);
  2953.             if (pElement)
  2954.             {
  2955.                 // Handle any external media marker file
  2956.                 // references in the begin time list
  2957.                 handleBeginEndListXMMFReferences(pElement,
  2958.                                                  pElement->m_pBeginTimeList);
  2959.                 // Handle any external media marker file
  2960.                 // references in the end time list
  2961.                 handleBeginEndListXMMFReferences(pElement,
  2962.                                                  pElement->m_pEndTimeList);
  2963.                 // Handle any external media marker file
  2964.                 // references in clipBegin
  2965.                 if (pElement->m_bClipBeginUsesMarker &&
  2966.                     pElement->m_pszClipBeginExternalMarkerFileName)
  2967.                 {
  2968.                     handleClipBeginEndXMMFReference(pElement, TRUE);
  2969.                 }
  2970.                 // Handle any external media marker file
  2971.                 // references in clipEnd
  2972.                 if (pElement->m_bClipEndUsesMarker &&
  2973.                     pElement->m_pszClipEndExternalMarkerFileName)
  2974.                 {
  2975.                     handleClipBeginEndXMMFReference(pElement, FALSE);
  2976.                 }
  2977.             }
  2978.         }
  2979.     }
  2980. }
  2981. void CSmilParser::handleBeginEndListXMMFReferences(CSmilElement*  pElement,
  2982.                                                    CHXSimpleList* pList)
  2983. {
  2984.     if (pElement && pList)
  2985.     {
  2986.         LISTPOSITION pos = pList->GetHeadPosition();
  2987.         while (pos)
  2988.         {
  2989.             SmilTimeValue* pValue = (SmilTimeValue*) pList->GetNext(pos);
  2990.             if (pValue &&
  2991.                 pValue->getTimeType() == SmilTimeMediaMarker &&
  2992.                 pValue->isExternalMarker())
  2993.             {
  2994.                 // Get the external file name
  2995.                 const char* pszExtFile = pValue->getExternalMarkerFileName();
  2996.                 // Get the src that this external
  2997.                 // file name is relative to
  2998.                 const char*   pszSrc     = NULL;
  2999.                 CSmilElement* pIDElement = findElement(pValue->getIdRef());
  3000.                 if (pIDElement &&
  3001.                     pIDElement->m_pNode &&
  3002.                     (isMediaObject(pIDElement->m_pNode) &&
  3003.                      pIDElement->m_pNode->m_tag != SMILBrush))
  3004.                 {
  3005.                     CSmilSource* pSource = (CSmilSource*) pIDElement;
  3006.                     if (pSource &&
  3007.                         pSource->m_src.GetLength() > 0)
  3008.                     {
  3009.                         pszSrc = (const char*) pSource->m_src;
  3010.                     }
  3011.                 }
  3012.                 // Handle this external file
  3013.                 pElement->handleXMMF(pValue->getIdRef(), pszExtFile, pszSrc);
  3014.             }
  3015.         }
  3016.     }
  3017. }
  3018. void CSmilParser::handleClipBeginEndXMMFReference(CSmilElement*  pElement,
  3019.                                                   BOOL           bIsClipBegin)
  3020. {
  3021.     if (pElement && pElement->m_pNode)
  3022.     {
  3023.         // Get the id for this element
  3024.         const char* pszID = (const char*) pElement->m_pNode->m_id;
  3025.         // Get the src attribute for this element
  3026.         const char* pszSrc = NULL;
  3027.         if (isMediaObject(pElement->m_pNode) &&
  3028.             pElement->m_pNode->m_tag != SMILBrush)
  3029.         {
  3030.             CSmilSource* pSource = (CSmilSource*) pElement;
  3031.             pszSrc = (const char*) pSource->m_src;
  3032.         }
  3033.         // Get the external file name
  3034.         const char* pszExt = (bIsClipBegin ?
  3035.                               pElement->m_pszClipBeginExternalMarkerFileName :
  3036.                               pElement->m_pszClipEndExternalMarkerFileName);
  3037.         // Now handle the external marker file
  3038.         pElement->handleXMMF(pszID, pszExt, pszSrc);
  3039.     }
  3040. }
  3041. HX_RESULT CSmilParser::setElementHandler(SMILNode*            pNode,
  3042.                                          CSmilElementHandler* pHandler)
  3043. {
  3044.     HX_RESULT retVal = HXR_OK;
  3045.     if (pNode)
  3046.     {
  3047.         // Does this node have a CSmilElement?
  3048.         if (pNode->m_pElement)
  3049.         {
  3050.             pNode->m_pElement->m_pHandler = pHandler;
  3051.         }
  3052.         // Loop through the children and set them as well
  3053.         if (pNode->m_pNodeList)
  3054.         {
  3055.             LISTPOSITION pos = pNode->m_pNodeList->GetHeadPosition();
  3056.             while (pos && SUCCEEDED(retVal))
  3057.             {
  3058.                 SMILNode* pChildNode =
  3059.                     (SMILNode*) pNode->m_pNodeList->GetNext(pos);
  3060.                 retVal = setElementHandler(pChildNode, pHandler);
  3061.             }
  3062.         }
  3063.     }
  3064.     return retVal;
  3065. }
  3066. void CSmilParser::addToBeginOrEndTimeMap(SmilTimeValue*     pValue,
  3067.                                          SmilTimingListType eType)
  3068. {
  3069.     if (pValue && (eType == SmilBeginTimeList || eType == SmilEndTimeList))
  3070.     {
  3071.         const char* pszEventName = pValue->getEventName();
  3072.         const char* pszElementID = pValue->getIdRef();
  3073.         if (pszEventName && pszElementID)
  3074.         {
  3075.             CHXMapStringToOb* pEventNameMap = NULL;
  3076.             if (eType == SmilBeginTimeList)
  3077.             {
  3078.                 if (!m_pBeginTimeMap)
  3079.                 {
  3080.                     m_pBeginTimeMap = new CHXMapStringToOb();
  3081.                 }
  3082.                 pEventNameMap = m_pBeginTimeMap;
  3083.             }
  3084.             else
  3085.             {
  3086.                 if (!m_pEndTimeMap)
  3087.                 {
  3088.                     m_pEndTimeMap = new CHXMapStringToOb();
  3089.                 }
  3090.                 pEventNameMap = m_pEndTimeMap;
  3091.             }
  3092.             if (pEventNameMap)
  3093.             {
  3094.                 // This is a two-layer map.
  3095.                 // First layer is a event name lookup
  3096.                 // Second layer is an element ID lookup
  3097.                 // The element ID lookup points to a list of SmilTimeValue's.
  3098.                 //
  3099.                 // Do we already have an event name entry?
  3100.                 CHXMapStringToOb* pElementIDMap = NULL;
  3101.                 void*             pVoid         = NULL;
  3102.                 if (!pEventNameMap->Lookup(pszEventName, pVoid))
  3103.                 {
  3104.                     // We don't have an event name entry for this event name
  3105.                     // so first create one
  3106.                     pElementIDMap = new CHXMapStringToOb();
  3107.                     // And now stick it in the event name map
  3108.                     if (pElementIDMap)
  3109.                     {
  3110.                        pEventNameMap->SetAt(pszEventName, (void*) pElementIDMap);
  3111.                     }
  3112.                 }
  3113.                 else
  3114.                 {
  3115.                     pElementIDMap = (CHXMapStringToOb*) pVoid;
  3116.                 }
  3117.                 if (pElementIDMap)
  3118.                 {
  3119.                     // Now see if we already have a list for this element ID
  3120.                     CHXSimpleList* pTimeValueList = NULL;
  3121.                     pVoid                         = NULL;
  3122.                     if (!pElementIDMap->Lookup(pszElementID, pVoid))
  3123.                     {
  3124.                         // We don't have a list of time values for
  3125.                         // that element ID, so create one
  3126.                         pTimeValueList = new CHXSimpleList();
  3127.                         // And now stick that list in the map
  3128.                         if (pTimeValueList)
  3129.                         {
  3130.                             pElementIDMap->SetAt(pszElementID, (void*) pTimeValueList);
  3131.                         }
  3132.                     }
  3133.                     else
  3134.                     {
  3135.                         pTimeValueList = (CHXSimpleList*) pVoid;
  3136.                     }
  3137.                     if (pTimeValueList)
  3138.                     {
  3139.                         // Add this SmilTimeValue to the list
  3140.                         pTimeValueList->AddTail((void*) pValue);
  3141.                     }
  3142.                 }
  3143.             }
  3144.         }
  3145.     }
  3146. }
  3147. void CSmilParser::removeFromBeginOrEndTimeMap(SmilTimeValue*     pValue,
  3148.                                               SmilTimingListType eType)
  3149. {
  3150.     if (pValue && (eType == SmilBeginTimeList || eType == SmilEndTimeList))
  3151.     {
  3152.         const char* pszEventName = pValue->getEventName();
  3153.         const char* pszElementID = pValue->getIdRef();
  3154.         if (pszEventName && pszElementID)
  3155.         {
  3156.             // Get event name map, depending
  3157.             // on whether this is a begin or end time value
  3158.             CHXMapStringToOb* pEventNameMap = (eType == SmilBeginTimeList ?
  3159.                                                m_pBeginTimeMap : m_pEndTimeMap);
  3160.             if (pEventNameMap)
  3161.             {
  3162.                 // Look up element ID map
  3163.                 void* pVoid1 = NULL;
  3164.                 if (pEventNameMap->Lookup(pszEventName, pVoid1) && pVoid1)
  3165.                 {
  3166.                     // Cast to CHXMapStringToOb
  3167.                     CHXMapStringToOb* pElementIDMap = (CHXMapStringToOb*) pVoid1;
  3168.                     // Lookup SmilTimeValue list
  3169.                     void* pVoid2 = NULL;
  3170.                     if (pElementIDMap->Lookup(pszElementID, pVoid2) && pVoid2)
  3171.                     {
  3172.                         // Cast to CHXSimpleList*
  3173.                         CHXSimpleList* pTimeValueList = (CHXSimpleList*) pVoid2;
  3174.                         // Now run through the list to find the value
  3175.                         LISTPOSITION pos = pTimeValueList->GetHeadPosition();
  3176.                         while (pos)
  3177.                         {
  3178.                             SmilTimeValue* pListValue =
  3179.                                 (SmilTimeValue*) pTimeValueList->GetAt(pos);
  3180.                             if (pListValue &&
  3181.                                 pListValue == pValue)
  3182.                             {
  3183.                                 // Remove this entry from the list
  3184.                                 pos = pTimeValueList->RemoveAt(pos);
  3185.                             }
  3186.                             else
  3187.                             {
  3188.                                 // Just go the next one
  3189.                                 pTimeValueList->GetNext(pos);
  3190.                             }
  3191.                         }
  3192.                     }
  3193.                 }
  3194.             }
  3195.         }
  3196.     }
  3197. }
  3198. BOOL CSmilParser::isTimeValueListPresent(const char*         pszEventName,
  3199.                                          const char*         pszElementID,
  3200.                                          SmilTimingListType  eType,
  3201.                                          REF(CHXSimpleList*) rpList)
  3202. {
  3203.     BOOL bRet = FALSE;
  3204.     if (pszEventName && pszElementID  &&
  3205.         (eType == SmilBeginTimeList ||
  3206.          eType == SmilEndTimeList))
  3207.     {
  3208.         // Set default
  3209.         rpList = NULL;
  3210.         // Get event name map, depending
  3211.         // on whether this is a begin or end time value
  3212.         CHXMapStringToOb* pEventNameMap = (eType == SmilBeginTimeList ?
  3213.                                            m_pBeginTimeMap : m_pEndTimeMap);
  3214.         if (pEventNameMap)
  3215.         {
  3216.             // Look up element ID map
  3217.             void* pVoid1 = NULL;
  3218.             if (pEventNameMap->Lookup(pszEventName, pVoid1) && pVoid1)
  3219.             {
  3220.                 // Cast to CHXMapStringToOb
  3221.                 CHXMapStringToOb* pElementIDMap = (CHXMapStringToOb*) pVoid1;
  3222.                 // Lookup SmilTimeValue list
  3223.                 void* pVoid2 = NULL;
  3224.                 if (pElementIDMap->Lookup(pszElementID, pVoid2) && pVoid2)
  3225.                 {
  3226.                     // Cast to CHXSimpleList*
  3227.                     rpList = (CHXSimpleList*) pVoid2;
  3228.                     // set return value
  3229.                     bRet = TRUE;
  3230.                 }
  3231.             }
  3232.         }
  3233.     }
  3234.     return bRet;
  3235. }
  3236. void CSmilParser::clearTimeValueMap(SmilTimingListType eType)
  3237. {
  3238.     if (eType == SmilBeginTimeList ||
  3239.         eType == SmilEndTimeList)
  3240.     {
  3241.         CHXMapStringToOb* pEventNameMap = (eType == SmilBeginTimeList ?
  3242.                                            m_pBeginTimeMap : m_pEndTimeMap);
  3243.         if (pEventNameMap)
  3244.         {
  3245.             POSITION pos1 = pEventNameMap->GetStartPosition();
  3246.             while (pos1)
  3247.             {
  3248.                 const char* pszKey1 = NULL;
  3249.                 void*       pVoid1  = NULL;
  3250.                 pEventNameMap->GetNextAssoc(pos1, pszKey1, pVoid1);
  3251.                 if (pVoid1)
  3252.                 {
  3253.                     // Cast to a CHXMapStringToOb
  3254.                     CHXMapStringToOb* pElementIDMap = (CHXMapStringToOb*) pVoid1;
  3255.                     // Run through all entries in this map
  3256.                     POSITION pos2 = pElementIDMap->GetStartPosition();
  3257.                     while (pos2)
  3258.                     {
  3259.                         const char* pszKey2 = NULL;
  3260.                         void*       pVoid2  = NULL;
  3261.                         pElementIDMap->GetNextAssoc(pos2, pszKey2, pVoid2);
  3262.                         if (pVoid2)
  3263.                         {
  3264.                             // Cast to a CHXSimpleList
  3265.                             CHXSimpleList* pTimeValueList = (CHXSimpleList*) pVoid2;
  3266.                             // Now delete it
  3267.                             HX_DELETE(pTimeValueList);
  3268.                         }
  3269.                     }
  3270.                 }
  3271.             }
  3272.         }
  3273.         if (eType == SmilBeginTimeList)
  3274.         {
  3275.             HX_DELETE(m_pBeginTimeMap);
  3276.         }
  3277.         else
  3278.         {
  3279.             HX_DELETE(m_pEndTimeMap);
  3280.         }
  3281.     }
  3282. }
  3283. void CSmilParser::checkNodeForExternalEvents(SMILNode* pNode)
  3284. {
  3285.     if (pNode)
  3286.     {
  3287.         // Does this node have a CSmilElement?
  3288.         if (pNode->m_pElement)
  3289.         {
  3290.             // Check its begin time list for custom events
  3291.             checkNodeTimeListForExternalEvents(pNode->m_pElement->m_pBeginTimeList);
  3292.             // Check its end time list for custom events
  3293.             checkNodeTimeListForExternalEvents(pNode->m_pElement->m_pEndTimeList);
  3294.         }
  3295.         // Recursively check the children of this node
  3296.         if (pNode->m_pNodeList)
  3297.         {
  3298.             LISTPOSITION pos = pNode->m_pNodeList->GetHeadPosition();
  3299.             while (pos)
  3300.             {
  3301.                 // Get a child node
  3302.                 SMILNode* pChildNode = (SMILNode*) pNode->m_pNodeList->GetNext(pos);
  3303.                 // Check it for custom events
  3304.                 checkNodeForExternalEvents(pChildNode);
  3305.             }
  3306.         }
  3307.     }
  3308. }
  3309. void CSmilParser::checkNodeTimeListForExternalEvents(CHXSimpleList* pList)
  3310. {
  3311.     if (pList)
  3312.     {
  3313.         LISTPOSITION pos = pList->GetHeadPosition();
  3314.         while (pos)
  3315.         {
  3316.             SmilTimeValue* pTime = (SmilTimeValue*) pList->GetNext(pos);
  3317.             if (pTime &&
  3318.                 pTime->getTimeType() == SmilTimeEvent)
  3319.             {
  3320.                 // Get the event name
  3321.                 const char* pszEventName = pTime->getEventName();
  3322.                 // Check whether this is a namespaced event name
  3323.                 const char* pszEventNameNoPrefix = NULL;
  3324.                 CNamespaceInfo* pInfo = getNamespaceInfo(pszEventName,
  3325.                                                          pszEventNameNoPrefix);
  3326.                 if (pInfo)
  3327.                 {
  3328.                     // This *is* a namespaced event name, so we need
  3329.                     // to add this custom event to the list
  3330.                     addExternalEventToList(pTime->getIdRef(),
  3331.                                            pszEventName,
  3332.                                            pszEventNameNoPrefix,
  3333.                                            pInfo);
  3334.                 }
  3335.             }
  3336.         }
  3337.     }
  3338. }
  3339. void CSmilParser::addExternalEventToList(const char*     pszID,
  3340.                                          const char*     pszFullName,
  3341.                                          const char*     pszName,
  3342.                                          CNamespaceInfo* pInfo)
  3343. {
  3344.     if (pszID && pszFullName && pszName && pInfo)
  3345.     {
  3346.         if (!m_pExternalEventList)
  3347.         {
  3348.             m_pExternalEventList = new CHXSimpleList();
  3349.         }
  3350.         if (m_pExternalEventList)
  3351.         {
  3352.             // First see if this custom event is already present
  3353.             BOOL         bPresent = FALSE;
  3354.             LISTPOSITION pos      = m_pExternalEventList->GetHeadPosition();
  3355.             while (pos)
  3356.             {
  3357.                 ExternalEventInfo* pListInfo =
  3358.                     (ExternalEventInfo*) m_pExternalEventList->GetNext(pos);
  3359.                 if (pListInfo                                     &&
  3360.                     pListInfo->m_EventBaseID       == pszID       &&
  3361.                     pListInfo->m_PrefixedEventName == pszFullName &&
  3362.                     pListInfo->m_EventName         == pszName     &&
  3363.                     pListInfo->m_pInfo             == pInfo)
  3364.                 {
  3365.                     bPresent = TRUE;
  3366.                     break;
  3367.                 }
  3368.             }
  3369.             // If it's not present, then add it
  3370.             if (!bPresent)
  3371.             {
  3372.                 ExternalEventInfo* pNewInfo = new ExternalEventInfo;
  3373.                 if (pNewInfo)
  3374.                 {
  3375.                     // Set the members
  3376.                     pNewInfo->m_EventBaseID       = pszID;
  3377.                     pNewInfo->m_PrefixedEventName = pszFullName;
  3378.                     pNewInfo->m_EventName         = pszName;
  3379.                     pNewInfo->m_pInfo             = pInfo;
  3380.                     // Append to the list
  3381.                     m_pExternalEventList->AddTail((void*) pNewInfo);
  3382.                 }
  3383.             }
  3384.         }
  3385.     }
  3386. }
  3387. void CSmilParser::clearExternalEventList()
  3388. {
  3389.     if (m_pExternalEventList)
  3390.     {
  3391.         LISTPOSITION pos = m_pExternalEventList->GetHeadPosition();
  3392.         while (pos)
  3393.         {
  3394.             ExternalEventInfo* pInfo =
  3395.                 (ExternalEventInfo*) m_pExternalEventList->GetNext(pos);
  3396.             HX_DELETE(pInfo);
  3397.         }
  3398.         m_pExternalEventList->RemoveAll();
  3399.     }
  3400. }
  3401. void CSmilParser::addStringProperty(IHXValues* pValues,
  3402.                                     IUnknown*   pContext,
  3403.                                     const char* pszName,
  3404.                                     const char* pszValue)
  3405. {
  3406.     if (pValues && pContext && pszName && pszValue)
  3407.     {
  3408.         IHXCommonClassFactory* pFact = NULL;
  3409.         pContext->QueryInterface(IID_IHXCommonClassFactory, (void**) &pFact);
  3410.         if (pFact)
  3411.         {
  3412.             IHXBuffer* pBuf = NULL;
  3413.             pFact->CreateInstance(CLSID_IHXBuffer, (void**) &pBuf);
  3414.             if (pBuf)
  3415.             {
  3416.                 HX_RESULT rv = pBuf->Set((const UCHAR*) pszValue, strlen(pszValue) + 1);
  3417.                 if (SUCCEEDED(rv))
  3418.                 {
  3419.                     pValues->SetPropertyCString(pszName, pBuf);
  3420.                 }
  3421.             }
  3422.             HX_RELEASE(pBuf);