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

Symbian

开发平台:

C/C++

  1.                                         // XXXMEH - illegal accelerate attribute
  2.                                         CSmilSMILSyntaxErrorHandler errHandler(m_pContext);
  3.                                         errHandler.ReportError(SMILErrorBadAttribute,
  4.                                                                pName,
  5.                                                                pAnim->m_pNode->m_ulTagStartLine);
  6.                                     }
  7.                                 }
  8.                                 else if(strcmp(pszAttr, "decelerate") == 0)
  9.                                 {
  10.                                     retVal = parseAccelDecel(pszVal, pAnim->m_dDecelerate);
  11.                                     if (FAILED(retVal))
  12.                                     {
  13.                                         // XXXMEH - illegal decelerate attribute
  14.                                         CSmilSMILSyntaxErrorHandler errHandler(m_pContext);
  15.                                         errHandler.ReportError(SMILErrorBadAttribute,
  16.                                                                pName,
  17.                                                                pAnim->m_pNode->m_ulTagStartLine);
  18.                                     }
  19.                                 }
  20.                                 else if(strcmp(pszAttr, "autoReverse") == 0)
  21.                                 {
  22.                                     if (strcmp(pszVal, "true") == 0)
  23.                                     {
  24.                                         pAnim->m_bAutoReverse = TRUE;
  25.                                     }
  26.                                     else if (strcmp(pszVal, "false") == 0)
  27.                                     {
  28.                                         pAnim->m_bAutoReverse = FALSE;
  29.                                     }
  30.                                     else
  31.                                     {
  32.                                         // XXXMEH - illegal autoReverse
  33.                                         retVal = HXR_FAIL;
  34.                                         CSmilSMILSyntaxErrorHandler errHandler(m_pContext);
  35.                                         errHandler.ReportError(SMILErrorBadAttribute,
  36.                                                                pName,
  37.                                                                pAnim->m_pNode->m_ulTagStartLine);
  38.                                     }
  39.                                 }
  40.                                 else if(strcmp(pszAttr, "speed") == 0)
  41.                                 {
  42.                                     double dVal = 0.0;
  43.                                     retVal = HXParseDouble(pszVal, dVal);
  44.                                     if (SUCCEEDED(retVal))
  45.                                     {
  46.                                         // Spec explicitly says to ignore a speed of 0.0,
  47.                                         // so if we see a 0.0, we simply set it back to
  48.                                         // the default speed of 1.0
  49.                                         if (dVal == 0.0)
  50.                                         {
  51.                                             dVal = 1.0;
  52.                                         }
  53.                                         // Assign to the speed parameter
  54.                                         pAnim->m_dSpeed = dVal;
  55.                                     }
  56.                                     else
  57.                                     {
  58.                                         // XXXMEH - illegal speed attribute
  59.                                         CSmilSMILSyntaxErrorHandler errHandler(m_pContext);
  60.                                         errHandler.ReportError(SMILErrorBadAttribute,
  61.                                                                pName,
  62.                                                                pAnim->m_pNode->m_ulTagStartLine);
  63.                                     }
  64.                                 }
  65.                             }
  66. #if defined(XXXMEH_SPLINE_ANIMATION)
  67.                             else if (pNSInfo->m_eNamespace == NamespaceSMIL2SplineAnimation)
  68.                             {
  69.                                 // We need to parse for "keyTimes", "keySplines", "path"
  70.                                 if(strcmp(pszAttr, "keyTimes") == 0)
  71.                                 {
  72.                                     retVal = parseKeyTimes(pszVal, pAnim);
  73.                                 }
  74.                                 else if(strcmp(pszAttr, "keySplines") == 0)
  75.                                 {
  76.                                     retVal = parseKeySplines(pszVal, pAnim);
  77.                                 }
  78.                                 else if(strcmp(pszAttr, "path") == 0)
  79.                                 {
  80.                                     retVal = parseSVGPath(pszVal, pAnim);
  81.                                 }
  82.                                 else if (strcmp(pszAttr, "calcMode") == 0)
  83.                                 {
  84.                                     bGotNSCalcMode = TRUE;
  85.                                     if (strcmp(pszVal, "discrete") == 0)
  86.                                     {
  87.                                         pAnim->m_ucCalcMode = kCalcModeDiscrete;
  88.                                     }
  89.                                     else if (strcmp(pszVal, "linear") == 0)
  90.                                     {
  91.                                         pAnim->m_ucCalcMode = kCalcModeLinear;
  92.                                     }
  93.                                     else if (strcmp(pszVal, "paced") == 0)
  94.                                     {
  95.                                         pAnim->m_ucCalcMode = kCalcModePaced;
  96.                                     }
  97.                                     else if (strcmp(pszVal, "spline") == 0)
  98.                                     {
  99.                                         pAnim->m_ucCalcMode = kCalcModeSpline;
  100.                                     }
  101.                                     else
  102.                                     {
  103.                                         retVal = HXR_FAIL;
  104.                                     }
  105.                                 }
  106.                                 if (FAILED(retVal))
  107.                                 {
  108.                                     CSmilSMILSyntaxErrorHandler errHandler(m_pContext);
  109.                                     errHandler.ReportError(SMILErrorBadAttribute,
  110.                                                            pName,
  111.                                                            pAnim->m_pNode->m_ulTagStartLine);
  112.                                 }
  113.                             }
  114. #endif // #if defined(XXXMEH_SPLINE_ANIMATION)
  115.                         }
  116.                     }
  117.             }
  118.             HX_RELEASE(pVal);
  119.             if (SUCCEEDED(retVal))
  120.             {
  121.                 rc = pAnim->m_pNode->m_pValues->GetNextPropertyCString(pName, pVal);
  122.             }
  123.         }
  124. // /Fixes animate version of PR 60111: : if this didn't have a "begin"
  125. // attribute, then set the following to TRUE because default begin is a
  126. // clock value (if our syncBase isn't an excl):
  127. if (!pAnim->m_pBeginTimeList)
  128. {
  129.     SMILNode* pSyncBase = getSyncAncestor(pAnim->m_pNode);
  130.     if (pSyncBase  &&  SMILExcl != pSyncBase->m_tag)
  131.     {
  132. pAnim->m_bHasAtLeastOneNonEventBasedBegin = TRUE;
  133.     }
  134. }
  135.         if (SUCCEEDED(retVal))
  136.         {
  137.             // Set the authored dur
  138.             pAnim->m_ulAuthoredDur = pAnim->m_ulDuration;
  139.             // If our "fill" attribute is "default", then we have
  140.             // to resolve it from either our fillDefault attribute
  141.             // (which may involve checking our ancestors).
  142.             resolveFillValue(pAnim);
  143.             // If this element didn't have a "begin" attribute,
  144.             // then set the following to TRUE because default begin is a clock value
  145.             // (if our syncBase isn't an excl):
  146.             if (!pAnim->m_pBeginTimeList)
  147.             {
  148.         SMILNode* pSyncBase = getSyncAncestor(pAnim->m_pNode);
  149.         if (pSyncBase  &&  SMILExcl != pSyncBase->m_tag)
  150.         {
  151.             pAnim->m_bHasAtLeastOneNonEventBasedBegin = TRUE;
  152.         }
  153.             }
  154.             // Now we can do some additional checking
  155.             //
  156.             // SPEC: If the target attribute does not support linear
  157.             // interpolation (e.g. for strings), or if the values attribute
  158.             // has only one value, the calcMode attribute is ignored and
  159.             // discrete interpolation is used.
  160.             // SPEC: This attribute (accumulate) is ignored if the target
  161.             // attribute value does not support addition. (Thus, if it
  162.             // is ignored, it defaults to "none").
  163.             // SPEC: This attribute (additive) is ignored if the target
  164.             // attribute does not support additive animation. (Thus, if
  165.             // it is ignored, then it defaults to "replace").
  166.             if (pAnim->m_ucAttributeName == kAttrNameCoords ||
  167.                 pAnim->m_ucAttributeName == kAttrNameValue)
  168.             {
  169.                 pAnim->m_ucCalcMode   = kCalcModeDiscrete;
  170.                 pAnim->m_ucAccumulate = kAccumulateNone;
  171.                 pAnim->m_ucAdditive   = kAdditiveReplace;
  172.             }
  173.             // If the attribute doesn't have a meaningful notion of distance,
  174.             // then we can't do paced animation. Therefore, if we specified
  175.             // paced for one of these attributes, then we should default
  176.             // back to linear animation. Note that we don't have to worry
  177.             // about coords, since it was handled separately above.
  178.             if (pAnim->m_ucCalcMode == kCalcModePaced &&
  179.                 (pAnim->m_ucAttributeName == kAttrNameZIndex ||
  180.                  pAnim->m_ucAttributeName == kAttrNameSoundLevel))
  181.             {
  182.                 pAnim->m_ucCalcMode = kCalcModeLinear;
  183.             }
  184.             // Check to make sure that accelerate and decelerate attributes
  185.             // don't sum to more than 1.0. Spec says:
  186.             //
  187.             // The sum of accelerate and decelerate must not exceed 1.
  188.             // If the individual values of the accelerate and decelerate
  189.             // attributes are between 0 and 1 and the sum is greater
  190.             // than 1, then both the accelerate and decelerate attributes
  191.             // will be ignored and the timed element will behave as if
  192.             // neither attribute was specified.
  193.             if (pAnim->m_dAccelerate + pAnim->m_dDecelerate > 1.0)
  194.             {
  195.                 // Reset them to their defaults, as
  196.                 // if they had not been specified.
  197.                 pAnim->m_dAccelerate = 0.0;
  198.                 pAnim->m_dDecelerate = 0.0;
  199.             }
  200.             // If the target element is not specified, then make
  201.             // the parent element the target element
  202.             if (!bTargetElementSpecified)
  203.             {
  204.                 if (pAnim->m_pNode->m_pParent)
  205.                 {
  206.                     pAnim->m_pTargetElementID = new CHXString(pAnim->m_pNode->m_pParent->m_id);
  207.                     if (pAnim->m_pTargetElementID)
  208.                     {
  209.                         // Check to see if this is a real id
  210.                         SMILNode* pNode = NULL;
  211.                         if(!m_pIDMap->Lookup((const char*) *pAnim->m_pTargetElementID,
  212.                                             (void*&)pNode))
  213.                         {
  214.                             // There's no element with this id in the map
  215.                             retVal = HXR_FAIL;
  216.                             CSmilSMILSyntaxErrorHandler errHandler(m_pContext);
  217.                             errHandler.ReportError(SMILErrorNonexistentID,
  218.                                                    pName,
  219.                                                    pAnim->m_pNode->m_ulTagStartLine);
  220.                         }
  221.                     }
  222.                     else
  223.                     {
  224.                         retVal = HXR_OUTOFMEMORY;
  225.                     }
  226.                 }
  227.                 else
  228.                 {
  229.                     // XXXMEH - huh? no parent?
  230.                     HX_ASSERT(FALSE);
  231.                     retVal = HXR_FAIL;
  232.                     CSmilSMILSyntaxErrorHandler errHandler(m_pContext);
  233.                     errHandler.ReportError(SMILErrorGeneralError,
  234.                                            pName,
  235.                                            pAnim->m_pNode->m_ulTagStartLine);
  236.                 }
  237.             }
  238.             // If the attribute was not specified, then we have to
  239.             // be <animateMotion>, since these implicitly target
  240.             // attributes.
  241.             if (SUCCEEDED(retVal) && !bAttrNameSpecified)
  242.             {
  243.                 if (pAnim->m_pNode->m_tag == SMILAnimateMotion)
  244.                 {
  245.                     // If we are <animateMotion>, then we know we are
  246.                     // animating "left" and "top" of a region.
  247.                     pAnim->m_ucAttributeName = kAttrNameLeftTop;
  248.                 }
  249.                 else
  250.                 {
  251.                     // Uh-oh, no attribute name specified, but
  252.                     // we are not <animateMotion>. This is an error.
  253.                     retVal = HXR_FAIL;
  254.                     CSmilSMILSyntaxErrorHandler errHandler(m_pContext);
  255.                     errHandler.ReportError(SMILErrorRequiredAttributeMissing,
  256.                                            "attributeName",
  257.                                            pAnim->m_pNode->m_ulTagStartLine);
  258.                 }
  259.             }
  260.             if (SUCCEEDED(retVal))
  261.             {
  262.                 // Now let's check to see that the animation element,
  263.                 // target element, the attribute name match up correctly
  264.                 SMILNode* pNode = NULL;
  265.                 if(m_pIDMap->Lookup((const char*) *pAnim->m_pTargetElementID,
  266.                                     (void*&)pNode))
  267.                 {
  268.                     // Set the target element tag
  269.                     pAnim->m_eTargetElementTag = pNode->m_tag;
  270.                     // Check the element/attribute combination
  271.                     if (pAnim->m_pNode->m_tag == SMILAnimate ||
  272.                         pAnim->m_pNode->m_tag == SMILSet)
  273.                     {
  274.                         if (pNode->m_tag == SMILRegion)
  275.                         {
  276.                             if (!(pAnim->m_ucAttributeName == kAttrNameSoundLevel ||
  277.                                   pAnim->m_ucAttributeName == kAttrNameWidth      ||
  278.                                   pAnim->m_ucAttributeName == kAttrNameHeight     ||
  279.                                   pAnim->m_ucAttributeName == kAttrNameZIndex     ||
  280.                                   pAnim->m_ucAttributeName == kAttrNameLeft       ||
  281.                                   pAnim->m_ucAttributeName == kAttrNameRight      ||
  282.                                   pAnim->m_ucAttributeName == kAttrNameTop        ||
  283.                                   pAnim->m_ucAttributeName == kAttrNameBottom     ||
  284.                                   pAnim->m_ucAttributeName == kAttrNameBackgroundColor))
  285.                             {
  286.                                 retVal = HXR_FAIL;
  287.                             }
  288.                         }
  289.                         else if (pNode->m_tag == SMILAnchor  ||
  290.                                  pNode->m_tag == SMILArea)
  291.                         {
  292.                             if (pAnim->m_ucAttributeName != kAttrNameCoords)
  293.                             {
  294.                                 retVal = HXR_FAIL;
  295.                             }
  296.                         }
  297.                         else if (pNode->m_tag == SMILText       ||
  298.                                  pNode->m_tag == SMILImg        ||
  299.                                  pNode->m_tag == SMILAnimation  ||
  300.                                  pNode->m_tag == SMILRef        ||
  301.                                  pNode->m_tag == SMILAudio      ||
  302.                                  pNode->m_tag == SMILVideo      ||
  303.                                  pNode->m_tag == SMILTextstream)
  304.                         {
  305.                             if (!(pAnim->m_ucAttributeName == kAttrNameLeft            ||
  306.                                   pAnim->m_ucAttributeName == kAttrNameRight           ||
  307.                                   pAnim->m_ucAttributeName == kAttrNameTop             ||
  308.                                   pAnim->m_ucAttributeName == kAttrNameBottom          ||
  309.                                   pAnim->m_ucAttributeName == kAttrNameWidth           ||
  310.                                   pAnim->m_ucAttributeName == kAttrNameHeight          ||
  311.                                   pAnim->m_ucAttributeName == kAttrNameZIndex          ||
  312.                                   pAnim->m_ucAttributeName == kAttrNameBackgroundColor ||
  313.                                   pAnim->m_ucAttributeName == kAttrNameMediaOpacity    ||
  314.                                   pAnim->m_ucAttributeName == kAttrNameBackgroundOpacity))
  315.                             {
  316.                                 retVal = HXR_FAIL;
  317.                             }
  318.                         }
  319.                         else if (pNode->m_tag == SMILBrush)
  320.                         {
  321.                             if (!(pAnim->m_ucAttributeName == kAttrNameLeft       ||
  322.                                   pAnim->m_ucAttributeName == kAttrNameRight      ||
  323.                                   pAnim->m_ucAttributeName == kAttrNameTop        ||
  324.                                   pAnim->m_ucAttributeName == kAttrNameBottom     ||
  325.                                   pAnim->m_ucAttributeName == kAttrNameWidth      ||
  326.                                   pAnim->m_ucAttributeName == kAttrNameHeight     ||
  327.                                   pAnim->m_ucAttributeName == kAttrNameZIndex     ||
  328.                                   pAnim->m_ucAttributeName == kAttrNameColor      ||
  329.                                   pAnim->m_ucAttributeName == kAttrNameBackgroundColor))
  330.                             {
  331.                                 retVal = HXR_FAIL;
  332.                             }
  333.                         }
  334.                         else if (pNode->m_tag == SMILRootLayout ||
  335.                                  pNode->m_tag == SMILViewport)
  336.                         {
  337.                             if (!(pAnim->m_ucAttributeName == kAttrNameWidth ||
  338.                                   pAnim->m_ucAttributeName == kAttrNameHeight))
  339.                             {
  340.                                 retVal = HXR_FAIL;
  341.                             }
  342.                         }
  343.                         else if (pNode->m_tag == SMILParam)
  344.                         {
  345.                             if (pAnim->m_ucAttributeName != kAttrNameValue)
  346.                             {
  347.                                 retVal = HXR_FAIL;
  348.                             }
  349.                         }
  350.                         else
  351.                         {
  352.                             retVal = HXR_FAIL;
  353.                         }
  354.                     }
  355.                     else if (pAnim->m_pNode->m_tag == SMILAnimateMotion)
  356.                     {
  357.                         if (pNode->m_tag == SMILRegion     ||
  358.                             pNode->m_tag == SMILText       ||
  359.                             pNode->m_tag == SMILImg        ||
  360.                             pNode->m_tag == SMILAnimation  ||
  361.                             pNode->m_tag == SMILRef        ||
  362.                             pNode->m_tag == SMILAudio      ||
  363.                             pNode->m_tag == SMILVideo      ||
  364.                             pNode->m_tag == SMILTextstream ||
  365.                             pNode->m_tag == SMILBrush)
  366.                         {
  367.                             if (pAnim->m_ucAttributeName != kAttrNameLeftTop)
  368.                             {
  369.                                 retVal = HXR_FAIL;
  370.                             }
  371.                         }
  372.                         else
  373.                         {
  374.                             retVal = HXR_FAIL;
  375.                         }
  376.                     }
  377.                     else if (pAnim->m_pNode->m_tag == SMILAnimateColor)
  378.                     {
  379.                         if (pNode->m_tag == SMILRegion    ||
  380.                             pNode->m_tag == SMILText      ||
  381.                             pNode->m_tag == SMILImg       ||
  382.                             pNode->m_tag == SMILAnimation ||
  383.                             pNode->m_tag == SMILRef       ||
  384.                             pNode->m_tag == SMILAudio     ||
  385.                             pNode->m_tag == SMILVideo     ||
  386.                             pNode->m_tag == SMILTextstream)
  387.                         {
  388.                             if (pAnim->m_ucAttributeName != kAttrNameBackgroundColor)
  389.                             {
  390.                                 retVal = HXR_FAIL;
  391.                             }
  392.                         }
  393.                         else if (pNode->m_tag == SMILBrush)
  394.                         {
  395.                             if (pAnim->m_ucAttributeName != kAttrNameColor)
  396.                             {
  397.                                 retVal = HXR_FAIL;
  398.                             }
  399.                         }
  400.                         else
  401.                         {
  402.                             retVal = HXR_FAIL;
  403.                         }
  404.                     }
  405.                 }
  406.                 if (FAILED(retVal))
  407.                 {
  408.                     // We either had an illegal target element or
  409.                     // an illegal attribute name.
  410.                     CSmilSMILSyntaxErrorHandler errHandler(m_pContext);
  411.                     errHandler.ReportError(SMILErrorBadAttribute,
  412.                                            "attributeName",
  413.                                            pAnim->m_pNode->m_ulTagStartLine);
  414.                 }
  415.             }
  416.             if (SUCCEEDED(retVal))
  417.             {
  418.                 // Did we have a simple dur specified?
  419.                 if (pAnim->m_ulSimpleDuration != ((UINT32) -1))
  420.                 {
  421.                     // Yes the simple duration was specified.
  422.                     //
  423.                     // Compute active duration. First initialize
  424.                     // it to the simple duration
  425.                     pAnim->m_ulActiveDuration = pAnim->m_ulSimpleDuration;
  426.                     // Did we have repeatDur="indefinite"?
  427.                     if (pAnim->m_bRepeatDurIsIndefinite)
  428.                     {
  429.                         // Yes, we have repeatDur="indefinite"
  430.                         //
  431.                         // Do we have any repeatCount?
  432.                         if (pAnim->m_dRepeatCount != 1.0)
  433.                         {
  434.                             // Yes, we have a repeatCount specified.
  435.                             //
  436.                             // Do we have autoReverse?
  437.                             double dRC = 0.0;
  438.                             if (pAnim->m_bAutoReverse)
  439.                             {
  440.                                 dRC = (double) pAnim->m_dRepeatCount * pAnim->m_ulSimpleDuration * 2;
  441.                             }
  442.                             else
  443.                             {
  444.                                 dRC = (double) pAnim->m_dRepeatCount * pAnim->m_ulSimpleDuration;
  445.                             }
  446.                             // This repeatCount-driven active duration will
  447.                             // take precedence over the repeatDur="indefinite"
  448.                             pAnim->m_ulActiveDuration          = (UINT32) floor(dRC + 0.5);
  449.                             pAnim->m_bIndefiniteActiveDuration = FALSE;
  450.                             // m_ulADNoSpeed is the active duration without taking
  451.                             // the speed attribute into account, so we simply initialize
  452.                             // it before we make the speed modification
  453.                             pAnim->m_ulADNoSpeed = pAnim->m_ulActiveDuration;
  454.                             // Now if speed is not 1.0, then we have to adjust
  455.                             // the active duration by the absolute value of the speed
  456.                             // Speed globally scales the active duration
  457.                             if (pAnim->m_dSpeed != 1.0 &&
  458.                                 pAnim->m_dSpeed != 0.0)
  459.                             {
  460.                                 double dSpeedAbs = fabs(pAnim->m_dSpeed);
  461.                                 double dNewAD    = (double) pAnim->m_ulActiveDuration / dSpeedAbs;
  462.                                 pAnim->m_ulActiveDuration = (UINT32) floor(dNewAD + 0.5);
  463.                             }
  464.                         }
  465.                         else
  466.                         {
  467.                             // We don't have a repeatCount, so the active duration
  468.                             // is indefinite
  469.                             pAnim->m_bIndefiniteActiveDuration = TRUE;
  470.                         }
  471.                     }
  472.                     else
  473.                     {
  474.                         // Do we repeat at all?
  475.                         if (pAnim->m_dRepeatCount != 1.0 ||
  476.                             pAnim->m_ulRepeatDur  != ((UINT32) -1))
  477.                         {
  478.                             // Yes we repeat. Compute how long we would
  479.                             // repeat from repeatCount
  480.                             UINT32 ulADRepeatCount = 0xFFFFFFFF;
  481.                             if (pAnim->m_dRepeatCount != 1.0)
  482.                             {
  483.                                 // Do we have autoReverse?
  484.                                 double dRC = 0.0;
  485.                                 if (pAnim->m_bAutoReverse)
  486.                                 {
  487.                                     dRC = (double) pAnim->m_dRepeatCount * pAnim->m_ulSimpleDuration * 2;
  488.                                 }
  489.                                 else
  490.                                 {
  491.                                     dRC = (double) pAnim->m_dRepeatCount * pAnim->m_ulSimpleDuration;
  492.                                 }
  493.                                 ulADRepeatCount = (UINT32) floor(dRC + 0.5);
  494.                             }
  495.                             // Get how long we would repeat from repeatDur
  496.                             UINT32 ulADRepeatDur = 0xFFFFFFFF;
  497.                             if (pAnim->m_ulRepeatDur != ((UINT32) -1))
  498.                             {
  499.                                 ulADRepeatDur = pAnim->m_ulRepeatDur;
  500.                             }
  501.                             // Now compute the active duration - it will be the minimum
  502.                             // of the simple duration, active duration from repeatCount,
  503.                             // and active duration from repeatDur.
  504.                             pAnim->m_ulActiveDuration = 0xFFFFFFFF;
  505.                             if (ulADRepeatCount < pAnim->m_ulActiveDuration)
  506.                             {
  507.                                 pAnim->m_ulActiveDuration = ulADRepeatCount;
  508.                             }
  509.                             if (ulADRepeatDur < pAnim->m_ulActiveDuration)
  510.                             {
  511.                                 pAnim->m_ulActiveDuration = ulADRepeatDur;
  512.                             }
  513.                             // If active duration is still 0xFFFFFFFF (shouldn't happen), then
  514.                             // the active duration is just the same as the
  515.                             // simple duration
  516.                             if (pAnim->m_ulActiveDuration == 0xFFFFFFFF)
  517.                             {
  518.                                 pAnim->m_ulActiveDuration = pAnim->m_ulSimpleDuration;
  519.                             }
  520.                         }
  521.                         else
  522.                         {
  523.                             // Do we have autoReverse?
  524.                             if (pAnim->m_bAutoReverse)
  525.                             {
  526.                                 pAnim->m_ulActiveDuration = pAnim->m_ulSimpleDuration * 2;
  527.                             }
  528.                         }
  529.                         // m_ulADNoSpeed is the active duration without taking
  530.                         // the speed attribute into account, so we simply initialize
  531.                         // it before we make the speed modification
  532.                         pAnim->m_ulADNoSpeed = pAnim->m_ulActiveDuration;
  533.                         // Now if speed is not 1.0, then we have to adjust
  534.                         // the active duration by the absolute value of the speed
  535.                         // Speed globally scales the active duration
  536.                         if (pAnim->m_dSpeed != 1.0 &&
  537.                             pAnim->m_dSpeed != 0.0)
  538.                         {
  539.                             double dSpeedAbs = fabs(pAnim->m_dSpeed);
  540.                             double dNewAD    = (double) pAnim->m_ulActiveDuration / dSpeedAbs;
  541.                             pAnim->m_ulActiveDuration = (UINT32) floor(dNewAD + 0.5);
  542.                         }
  543.                     }
  544.                 }
  545.                 else
  546.                 {
  547.                     // No simple duration was specified. Therefore, we have
  548.                     // an indefinite simple duration.
  549.                     pAnim->m_bIndefiniteSimpleDuration = TRUE;
  550.                     // Do we have a non-indefinite repeatDur specified?
  551.                     if (pAnim->m_ulRepeatDur != ((UINT32) -1))
  552.                     {
  553.                         // Yes, repeatDur was specified and it was NOT
  554.                         // "indefinite". Therefore, our active duration
  555.                         // is NOT indefinite.
  556.                         pAnim->m_bIndefiniteActiveDuration = FALSE;
  557.                         // Our active duration is the repeatDur
  558.                         pAnim->m_ulActiveDuration          = pAnim->m_ulRepeatDur;
  559.                     }
  560.                     else
  561.                     {
  562.                         // Either repeatDur wasn't specified or it was
  563.                         // specified and it was "indefinite". Either way,
  564.                         // our active duration is going to be indefinite.
  565.                         pAnim->m_bIndefiniteActiveDuration = TRUE;
  566.                     }
  567.                 }
  568.             }
  569.             if (SUCCEEDED(retVal))
  570.             {
  571.                 // First let's determine what kind of animation it is
  572.                 if (bValuesSpecified)
  573.                 {
  574.                     // SPEC: If values is specified, from/by/to are ignored
  575.                     pAnim->m_ucAnimationType = kAnimTypeValues;
  576.                 }
  577.                 else
  578.                 {
  579.                     // No values specified, so let's look at the from/by/to
  580.                     //
  581.                     // SPEC: "The simpler from/to/by syntax provides for several
  582.                     // variants. To use one of these variants, one of by or to must
  583.                     // be specified; a from value is optional. It is not legal to
  584.                     // specify both by and to attributes; if both are specified, only
  585.                     // the to attribute will be used (the by will be ignored)."
  586.                     if (bToSpecified)
  587.                     {
  588.                         if (bFromSpecified)
  589.                         {
  590.                             // This is a "from-to" animation
  591.                             pAnim->m_ucAnimationType = kAnimTypeFromTo;
  592.                         }
  593.                         else
  594.                         {
  595.                             // This is a "to" animation
  596.                             pAnim->m_ucAnimationType = kAnimTypeTo;
  597.                             // Handle special cases for "to" animations -
  598.                             // cumulative animations are not defined, so we always
  599.                             // for accumulate="none"
  600.                             pAnim->m_ucAccumulate = kAccumulateNone;
  601.                         }
  602.                     }
  603.                     else if (bBySpecified)
  604.                     {
  605.                         if (bFromSpecified)
  606.                         {
  607.                             // This is a "from-by" animation
  608.                             pAnim->m_ucAnimationType = kAnimTypeFromBy;
  609.                         }
  610.                         else
  611.                         {
  612.                             // This is a "by" animation
  613.                             pAnim->m_ucAnimationType = kAnimTypeBy;
  614.                             // SPEC: "A by animation with a by value vb is equivalent
  615.                             // to the same animation with a values list with 2 values,
  616.                             // 0 and vb, and additive="sum". Any other specification of
  617.                             // the additive attribute in a by animation is ignored."
  618.                             //
  619.                             // So if the additive value is not sum, set it to sum
  620.                             if (pAnim->m_ucAdditive != kAdditiveSum)
  621.                             {
  622.                                 pAnim->m_ucAdditive = kAdditiveSum;
  623.                             }
  624.                         }
  625.                     }
  626.                     else
  627.                     {
  628.                         // XXXMEH - no "values", "to", or "by" specified - the
  629.                         // animation should do nothing. For now, we fail. We won't
  630.                         // throw an error, but we will just not do this
  631.                         // animation. I'm just commenting out the error popup,
  632.                         // cause I think we should still have it.
  633.                         retVal = HXR_FAIL;
  634. //                        CSmilSMILSyntaxErrorHandler errHandler(m_pContext);
  635. //                        errHandler.ReportError(SMILErrorRequiredAttributeMissing,
  636. //                                               "values",
  637. //                                               pAnim->m_pNode->m_ulTagStartLine);
  638.                     }
  639.                 }
  640.                 if (SUCCEEDED(retVal))
  641.                 {
  642.                     // Now we can parse the values of the values/from/to/by attributes
  643.                     if (pAnim->m_ucAnimationType == kAnimTypeValues)
  644.                     {
  645.                         // Get the "values" attribute
  646.                         IHXBuffer* pVal = NULL;
  647.                         retVal           = pAnim->m_pNode->m_pValues->GetPropertyCString("values", pVal);
  648.                         if (SUCCEEDED(retVal))
  649.                         {
  650.                             const char* pszVal = (const char*) pVal->GetBuffer();
  651.                             // First count and separate the different values arguments
  652.                             char*  pStr  = NULL;
  653.                             char** ppStr = NULL;
  654.                             retVal       = animCountValues(pszVal, pStr, pAnim->m_ulNumValues, ppStr);
  655.                             if (SUCCEEDED(retVal))
  656.                             {
  657.                                 // Allocate the array of CAttr*
  658.                                 pAnim->m_ppValue = new CAttr* [pAnim->m_ulNumValues];
  659.                                 if (pAnim->m_ppValue)
  660.                                 {
  661.                                     // Zero out the memory
  662.                                     memset((void*) pAnim->m_ppValue, 0,
  663.                                            sizeof(CAttr*) * pAnim->m_ulNumValues);
  664.                                     // Loop through and parse each argument
  665.                                     for (UINT32 i = 0; i < pAnim->m_ulNumValues && SUCCEEDED(retVal); i++)
  666.                                     {
  667.                                         retVal = animParseValue(pAnim, ppStr[i], i);
  668.                                     }
  669.                                 }
  670.                                 else
  671.                                 {
  672.                                     pAnim->m_ulNumValues = 0;
  673.                                     retVal = HXR_OUTOFMEMORY;
  674.                                 }
  675.                             }
  676.                             // Free the temporary strings
  677.                             HX_VECTOR_DELETE(ppStr);
  678.                             HX_VECTOR_DELETE(pStr);
  679.                         }
  680.                         HX_RELEASE(pVal);
  681.                     }
  682.                     else
  683.                     {
  684.                         // If we are not a values type, then there will
  685.                         // always be two CAttr*
  686.                         pAnim->m_ulNumValues = 2;
  687.                         // Allocate the array of CAttr*
  688.                         pAnim->m_ppValue = new CAttr* [pAnim->m_ulNumValues];
  689.                         if (pAnim->m_ppValue)
  690.                         {
  691.                             // Zero out the memory
  692.                             memset((void*) pAnim->m_ppValue, 0,
  693.                                    sizeof(CAttr*) * pAnim->m_ulNumValues);
  694.                             // Parse the from attribute
  695.                             if (pAnim->m_ucAnimationType == kAnimTypeFromTo ||
  696.                                 pAnim->m_ucAnimationType == kAnimTypeFromBy)
  697.                             {
  698.                                 IHXBuffer* pVal = NULL;
  699.                                 retVal           = pAnim->m_pNode->m_pValues->GetPropertyCString("from", pVal);
  700.                                 if (SUCCEEDED(retVal))
  701.                                 {
  702.                                     const char* pszVal = (const char*) pVal->GetBuffer();
  703.                                     retVal = animParseValue(pAnim, pszVal, 0);
  704.                                 }
  705.                                 HX_RELEASE(pVal);
  706.                             }
  707.                             // Parse the to attribute
  708.                             if (SUCCEEDED(retVal) &&
  709.                                 (pAnim->m_ucAnimationType == kAnimTypeFromTo ||
  710.                                  pAnim->m_ucAnimationType == kAnimTypeTo))
  711.                             {
  712.                                 IHXBuffer* pVal = NULL;
  713.                                 retVal           = pAnim->m_pNode->m_pValues->GetPropertyCString("to", pVal);
  714.                                 if (SUCCEEDED(retVal))
  715.                                 {
  716.                                     const char* pszVal = (const char*) pVal->GetBuffer();
  717.                                     retVal = animParseValue(pAnim, pszVal, 1);
  718.                                 }
  719.                                 HX_RELEASE(pVal);
  720.                             }
  721.                             // Parse the by attribute
  722.                             if (SUCCEEDED(retVal) &&
  723.                                 (pAnim->m_ucAnimationType == kAnimTypeFromBy ||
  724.                                  pAnim->m_ucAnimationType == kAnimTypeBy))
  725.                             {
  726.                                 IHXBuffer* pVal = NULL;
  727.                                 retVal           = pAnim->m_pNode->m_pValues->GetPropertyCString("by", pVal);
  728.                                 if (SUCCEEDED(retVal))
  729.                                 {
  730.                                     const char* pszVal = (const char*) pVal->GetBuffer();
  731.                                     retVal = animParseValue(pAnim, pszVal, 1);
  732.                                 }
  733.                                 HX_RELEASE(pVal);
  734.                             }
  735.                             // If this is either a "to" or "by" animation,
  736.                             // then we need to fill in m_ppValue[0] with a
  737.                             // zero-valued placeholder
  738.                             if (pAnim->m_ucAnimationType == kAnimTypeTo ||
  739.                                 pAnim->m_ucAnimationType == kAnimTypeBy)
  740.                             {
  741.                                 pAnim->m_ppValue[0] = new CAttr(pAnim->m_ucAttributeName);
  742.                                 if (!pAnim->m_ppValue[0])
  743.                                 {
  744.                                     retVal = HXR_OUTOFMEMORY;
  745.                                 }
  746.                             }
  747.                         }
  748.                         else
  749.                         {
  750.                             pAnim->m_ulNumValues = 0;
  751.                             retVal = HXR_OUTOFMEMORY;
  752.                         }
  753.                     }
  754.                 }
  755.                 // Check if we are animating width
  756.                 // or height of a root-layout or topLayout
  757.                 if (SUCCEEDED(retVal) &&
  758.                     (pAnim->m_eTargetElementTag == SMILRootLayout ||
  759.                      pAnim->m_eTargetElementTag == SMILViewport))
  760.                 {
  761.                     // Make sure that none of the attributes
  762.                     // are percentages. It's illegal for a <root-layout>
  763.                     // or topLayout to have a percentage value
  764.                     // at any time.
  765.                     for (UINT32 i = 0; i < pAnim->m_ulNumValues; i++)
  766.                     {
  767.                         if (pAnim->m_ppValue[i] &&
  768.                             pAnim->m_ppValue[i]->GetCSS2Type(0) == CSS2TypePercentage)
  769.                         {
  770.                             retVal = HXR_FAIL;
  771.                             break;
  772.                         }
  773.                     }
  774.                 }
  775. #if defined(XXXMEH_SPLINE_ANIMATION)
  776.                 // Check any SplineAnimation parameters, if there are any
  777.                 if (SUCCEEDED(retVal))
  778.                 {
  779.                     retVal = checkSplineAnimation(pAnim);
  780.                 }
  781. #endif
  782.             }
  783.         }
  784.     }
  785.     else
  786.     {
  787.         retVal = HXR_FAIL;
  788.     }
  789.     return retVal;
  790. }
  791. #if defined(XXXMEH_SPLINE_ANIMATION)
  792. HX_RESULT CSmilParser::checkSplineAnimation(CSmilAnimateElement* pAnim)
  793. {
  794.     HX_RESULT retVal = HXR_OK;
  795.     if (pAnim)
  796.     {
  797.         // Do we have a "path" attribute?
  798.         if (pAnim->m_ppPathCmd && pAnim->m_ulNumPathCmds)
  799.         {
  800.             // First, convert all implicit path
  801.             // commands to explicit path commands
  802.             retVal = makeSVGPathExplicit(pAnim);
  803.         }
  804.         if (SUCCEEDED(retVal))
  805.         {
  806.             // Do we have any keyTimes?
  807.             if (pAnim->m_ulNumKeyTimes && pAnim->m_pdKeyTime)
  808.             {
  809.                 // Do we have from/to/values attribute or a path specification?
  810.                 if (pAnim->m_ulNumValues && pAnim->m_ppValue)
  811.                 {
  812.                     // SPEC: If a list of keyTimes is specified, there
  813.                     // must be exactly as many values in the keyTimes
  814.                     // list as in the values list.
  815.                     if (pAnim->m_ulNumValues != pAnim->m_ulNumKeyTimes)
  816.                     {
  817.                         retVal = HXR_FAIL;
  818.                     }
  819.                 }
  820.                 else if (pAnim->m_ppPathCmd && pAnim->m_ulNumPathCmds)
  821.                 {
  822.                 }
  823.             }
  824.         }
  825.     }
  826.     else
  827.     {
  828.         retVal = HXR_FAIL;
  829.     }
  830.     return retVal;
  831. }
  832. HX_RESULT CSmilParser::makeSVGPathExplicit(CSmilAnimateElement* pAnim)
  833. {
  834.     HX_RESULT retVal = HXR_OK;
  835.     if (pAnim)
  836.     {
  837.         if (pAnim->m_ppPathCmd && pAnim->m_ulNumPathCmds)
  838.         {
  839.             // Run through and count how many we would
  840.             // have in the completely explicit array
  841.             UINT32 i             = 0;
  842.             UINT32 ulNumExplicit = 0;
  843.             for (i = 0; i < pAnim->m_ulNumPathCmds; i++)
  844.             {
  845.                 if (pAnim->m_ppPathCmd[i])
  846.                 {
  847.                     PathCmdType eType       = pAnim->m_ppPathCmd[i]->m_eType;
  848.                     UINT32      ulNumCoords = pAnim->m_ppPathCmd[i]->m_ulNumCoords;
  849.                     switch (eType)
  850.                     {
  851.                         case PathCmdTypeMoveTo:
  852.                         case PathCmdTypeLineTo:
  853.                             {
  854.                                 ulNumExplicit += ulNumCoords / 2;
  855.                             }
  856.                             break;
  857.                         case PathCmdTypeHorzLineTo:
  858.                         case PathCmdTypeVertLineTo:
  859.                             {
  860.                                 ulNumExplicit += ulNumCoords;
  861.                             }
  862.                             break;
  863.                         case PathCmdTypeClosePath:
  864.                             {
  865.                                 ++ulNumExplicit;
  866.                             }
  867.                             break;
  868.                         case PathCmdTypeCubicBezierCurveTo:
  869.                             {
  870.                                 ulNumExplicit += ulNumCoords / 6;
  871.                             }
  872.                             break;
  873.                     }
  874.                 }
  875.             }
  876.             // Is the completely explicit number the same
  877.             // as the current number? If so, we don't have
  878.             // any work to do
  879.             if (ulNumExplicit != pAnim->m_ulNumPathCmds)
  880.             {
  881.                 // Allocate an array of PathCmd*'s
  882.                 PathCmd** ppPathCmd = new PathCmd* [ulNumExplicit];
  883.                 if (ppPathCmd)
  884.                 {
  885.                     // NULL out the array
  886.                     memset(ppPathCmd, 0, ulNumExplicit & sizeof(PathCmd*));
  887.                     // Now run through the existing array. If the PathCmd
  888.                     // has no implicit commands in it, then we just copy
  889.                     // the pointer. If the PathCmd has implicit commands,
  890.                     // then we need to create some number of PathCmd
  891.                     // objects and then fill them in
  892.                     //
  893.                     // Initialize the explicit array index
  894.                     UINT32 ulExplicitIndex = 0;
  895.                     for (i = 0; i < pAnim->m_ulNumPathCmds; i++)
  896.                     {
  897.                         if (pAnim->m_ppPathCmd[i])
  898.                         {
  899.                             PathCmdType eType       = pAnim->m_ppPathCmd[i]->m_eType;
  900.                             UINT32      ulNumCoords = pAnim->m_ppPathCmd[i]->m_ulNumCoords;
  901.                             UINT32      ulNumCmds   = 0;
  902.                             switch (eType)
  903.                             {
  904.                                 case PathCmdTypeMoveTo:
  905.                                     {
  906.                                         ulNumCmds = ulNumCoords / 2;
  907.                                         if (ulNumCmds == 1)
  908.                                         {
  909.                                             // Just copy over the pointer
  910.                                             ppPathCmd[ulExplicitIndex++] = pAnim->m_ppPathCmd[i];
  911.                                         }
  912.                                         else
  913.                                         {
  914.                                             for (UINT32 j = 0; j < ulNumCmds && SUCCEEDED(retVal); j++)
  915.                                             {
  916.                                                 // Create a PathCmd
  917.                                                 PathCmd* pNew = new PathCmd();
  918.                                                 if (pNew)
  919.                                                 {
  920.                                                     // Copy the type and relative members.
  921.                                                     // The first one should be a MoveTo and
  922.                                                     // the rest should be LineTo's.
  923.                                                     pNew->m_eType     = (j ? PathCmdTypeLineTo : PathCmdTypeMoveTo);
  924.                                                     pNew->m_bRelative = pAnim->m_ppPathCmd[i]->m_bRelative;
  925.                                                     // Allocate 2 doubles
  926.                                                     pNew->m_ulNumCoords = 2;
  927.                                                     pNew->m_pdCoord     = new double [2];
  928.                                                     if (pNew->m_pdCoord)
  929.                                                     {
  930.                                                         // Get the j*2-th and j*2+1-th
  931.                                                         // coordinates from the original
  932.                                                         UINT32 k = j * 2;
  933.                                                         pNew->m_pdCoord[0] = pAnim->m_ppPathCmd[i]->m_pdCoord[k];
  934.                                                         pNew->m_pdCoord[1] = pAnim->m_ppPathCmd[i]->m_pdCoord[k+1];
  935.                                                         // Add this to the new array
  936.                                                         ppPathCmd[ulExplicitIndex++] = pNew;
  937.                                                     }
  938.                                                     else
  939.                                                     {
  940.                                                         retVal = HXR_OUTOFMEMORY;
  941.                                                     }
  942.                                                 }
  943.                                                 else
  944.                                                 {
  945.                                                     retVal = HXR_OUTOFMEMORY;
  946.                                                 }
  947.                                             }
  948.                                             // Now we can delete the old PathCmd
  949.                                             HX_DELETE(pAnim->m_ppPathCmd[i]);
  950.                                         }
  951.                                     }
  952.                                     break;
  953.                                 case PathCmdTypeLineTo:
  954.                                     {
  955.                                         ulNumCmds = ulNumCoords / 2;
  956.                                         if (ulNumCmds == 1)
  957.                                         {
  958.                                             // Just copy over the pointer
  959.                                             ppPathCmd[ulExplicitIndex++] = pAnim->m_ppPathCmd[i];
  960.                                         }
  961.                                         else
  962.                                         {
  963.                                             for (UINT32 j = 0; j < ulNumCmds && SUCCEEDED(retVal); j++)
  964.                                             {
  965.                                                 // Create a PathCmd
  966.                                                 PathCmd* pNew = new PathCmd();
  967.                                                 if (pNew)
  968.                                                 {
  969.                                                     // Copy the type and relative members
  970.                                                     // from the original PathCmd
  971.                                                     pNew->m_eType       = pAnim->m_ppPathCmd[i]->m_eType;
  972.                                                     pNew->m_bRelative   = pAnim->m_ppPathCmd[i]->m_bRelative;
  973.                                                     // Allocate 2 doubles
  974.                                                     pNew->m_ulNumCoords = 2;
  975.                                                     pNew->m_pdCoord     = new double [2];
  976.                                                     if (pNew->m_pdCoord)
  977.                                                     {
  978.                                                         // Get the j*2-th and j*2+1-th
  979.                                                         // coordinates from the original
  980.                                                         UINT32 k = j * 2;
  981.                                                         pNew->m_pdCoord[0] = pAnim->m_ppPathCmd[i]->m_pdCoord[k];
  982.                                                         pNew->m_pdCoord[1] = pAnim->m_ppPathCmd[i]->m_pdCoord[k+1];
  983.                                                         // Add this to the new array
  984.                                                         ppPathCmd[ulExplicitIndex++] = pNew;
  985.                                                     }
  986.                                                     else
  987.                                                     {
  988.                                                         retVal = HXR_OUTOFMEMORY;
  989.                                                     }
  990.                                                 }
  991.                                                 else
  992.                                                 {
  993.                                                     retVal = HXR_OUTOFMEMORY;
  994.                                                 }
  995.                                             }
  996.                                             // Now we can delete the old PathCmd
  997.                                             HX_DELETE(pAnim->m_ppPathCmd[i]);
  998.                                         }
  999.                                     }
  1000.                                     break;
  1001.                                 case PathCmdTypeHorzLineTo:
  1002.                                 case PathCmdTypeVertLineTo:
  1003.                                     {
  1004.                                         ulNumCmds = ulNumCoords;
  1005.                                         if (ulNumCmds == 1)
  1006.                                         {
  1007.                                             // Just copy over the pointer
  1008.                                             ppPathCmd[ulExplicitIndex++] = pAnim->m_ppPathCmd[i];
  1009.                                         }
  1010.                                         else
  1011.                                         {
  1012.                                             for (UINT32 j = 0; j < ulNumCmds && SUCCEEDED(retVal); j++)
  1013.                                             {
  1014.                                                 // Create a PathCmd
  1015.                                                 PathCmd* pNew = new PathCmd();
  1016.                                                 if (pNew)
  1017.                                                 {
  1018.                                                     // Copy the type and relative members
  1019.                                                     // from the original PathCmd
  1020.                                                     pNew->m_eType       = pAnim->m_ppPathCmd[i]->m_eType;
  1021.                                                     pNew->m_bRelative   = pAnim->m_ppPathCmd[i]->m_bRelative;
  1022.                                                     // Allocate 2 doubles
  1023.                                                     pNew->m_ulNumCoords = 1;
  1024.                                                     pNew->m_pdCoord     = new double [1];
  1025.                                                     if (pNew->m_pdCoord)
  1026.                                                     {
  1027.                                                         // Get the j-th coordinates
  1028.                                                         // from the original
  1029.                                                         pNew->m_pdCoord[0] = pAnim->m_ppPathCmd[i]->m_pdCoord[j];
  1030.                                                         // Add this to the new array
  1031.                                                         ppPathCmd[ulExplicitIndex++] = pNew;
  1032.                                                     }
  1033.                                                     else
  1034.                                                     {
  1035.                                                         retVal = HXR_OUTOFMEMORY;
  1036.                                                     }
  1037.                                                 }
  1038.                                                 else
  1039.                                                 {
  1040.                                                     retVal = HXR_OUTOFMEMORY;
  1041.                                                 }
  1042.                                             }
  1043.                                             // Now we can delete the old PathCmd
  1044.                                             HX_DELETE(pAnim->m_ppPathCmd[i]);
  1045.                                         }
  1046.                                     }
  1047.                                     break;
  1048.                                 case PathCmdTypeClosePath:
  1049.                                     {
  1050.                                         // Just copy over the pointer
  1051.                                         ppPathCmd[ulExplicitIndex++] = pAnim->m_ppPathCmd[i];
  1052.                                     }
  1053.                                     break;
  1054.                                 case PathCmdTypeCubicBezierCurveTo:
  1055.                                     {
  1056.                                         ulNumCmds = ulNumCoords / 6;
  1057.                                         if (ulNumCmds == 1)
  1058.                                         {
  1059.                                             // Just copy over the pointer
  1060.                                             ppPathCmd[ulExplicitIndex++] = pAnim->m_ppPathCmd[i];
  1061.                                         }
  1062.                                         else
  1063.                                         {
  1064.                                             for (UINT32 j = 0; j < ulNumCmds && SUCCEEDED(retVal); j++)
  1065.                                             {
  1066.                                                 // Create a PathCmd
  1067.                                                 PathCmd* pNew = new PathCmd();
  1068.                                                 if (pNew)
  1069.                                                 {
  1070.                                                     // Copy the type and relative members
  1071.                                                     // from the original PathCmd
  1072.                                                     pNew->m_eType       = pAnim->m_ppPathCmd[i]->m_eType;
  1073.                                                     pNew->m_bRelative   = pAnim->m_ppPathCmd[i]->m_bRelative;
  1074.                                                     // Allocate 2 doubles
  1075.                                                     pNew->m_ulNumCoords = 6;
  1076.                                                     pNew->m_pdCoord     = new double [6];
  1077.                                                     if (pNew->m_pdCoord)
  1078.                                                     {
  1079.                                                         // Get the coordinates from the original
  1080.                                                         UINT32 k = j * 6;
  1081.                                                         for (UINT32 q = 0; q < 6; q++)
  1082.                                                         {
  1083.                                                             pNew->m_pdCoord[q] = pAnim->m_ppPathCmd[i]->m_pdCoord[k+q];
  1084.                                                         }
  1085.                                                         // Add this to the new array
  1086.                                                         ppPathCmd[ulExplicitIndex++] = pNew;
  1087.                                                     }
  1088.                                                     else
  1089.                                                     {
  1090.                                                         retVal = HXR_OUTOFMEMORY;
  1091.                                                     }
  1092.                                                 }
  1093.                                                 else
  1094.                                                 {
  1095.                                                     retVal = HXR_OUTOFMEMORY;
  1096.                                                 }
  1097.                                             }
  1098.                                             // Now we can delete the old PathCmd
  1099.                                             HX_DELETE(pAnim->m_ppPathCmd[i]);
  1100.                                         }
  1101.                                     }
  1102.                                     break;
  1103.                             }
  1104.                         }
  1105.                     }
  1106.                     // Now we can replace the old PathCmd array
  1107.                     // with the new one
  1108.                     HX_VECTOR_DELETE(pAnim->m_ppPathCmd);
  1109.                     pAnim->m_ppPathCmd     = ppPathCmd;
  1110.                     pAnim->m_ulNumPathCmds = ulNumExplicit;
  1111.                 }
  1112.                 else
  1113.                 {
  1114.                     retVal = HXR_OUTOFMEMORY;
  1115.                 }
  1116.             }
  1117.         }
  1118.     }
  1119.     else
  1120.     {
  1121.         retVal = HXR_FAIL;
  1122.     }
  1123.     return retVal;
  1124. }
  1125. #endif // #if defined(XXXMEH_SPLINE_ANIMATION)
  1126. HX_RESULT CSmilParser::animCountValues(const char* pszStr,
  1127.                                        REF(char*)  rpStr,
  1128.                                        REF(UINT32) rulNumValues,
  1129.                                        REF(char**) rppStr)
  1130. {
  1131.     HX_RESULT retVal = HXR_OK;
  1132.     // Set defaults
  1133.     rpStr        = NULL;
  1134.     rulNumValues = 0;
  1135.     rppStr       = NULL;
  1136.     // Allocate the string
  1137.     char* pStr = new char [strlen(pszStr) + 1];
  1138.     if (pStr)
  1139.     {
  1140.         // Copy the string
  1141.         strcpy(pStr, pszStr); /* Flawfinder: ignore */
  1142.         // Init the count
  1143.         UINT32 ulNumValues = 0;
  1144.         // Count the values
  1145.         char* pszToken = strtok(pStr, ";");
  1146.         while (pszToken)
  1147.         {
  1148.             ulNumValues++;
  1149.             pszToken = strtok(NULL, ";");
  1150.         }
  1151.         // Got to have at least one
  1152.         if (ulNumValues)
  1153.         {
  1154.             // Allocate an array of strings
  1155.             char** ppStr = new char* [ulNumValues];
  1156.             if (ppStr)
  1157.             {
  1158.                 // Zero out the memory
  1159.                 memset((void*) ppStr, 0, ulNumValues * sizeof(char*));
  1160.                 // Recopy the string
  1161.                 strcpy(pStr, pszStr); /* Flawfinder: ignore */
  1162.                 // Run through again and find the points
  1163.                 char*  pszToken = strtok(pStr, ";");
  1164.                 UINT32 i        = 0;
  1165.                 while (pszToken)
  1166.                 {
  1167.                     ppStr[i++] = pszToken;
  1168.                     pszToken = strtok(NULL, ";");
  1169.                 }
  1170.                 // Assign the out parameters
  1171.                 rpStr        = pStr;
  1172.                 rulNumValues = ulNumValues;
  1173.                 rppStr       = ppStr;
  1174.             }
  1175.             else
  1176.             {
  1177.                 retVal = HXR_OUTOFMEMORY;
  1178.             }
  1179.             if (FAILED(retVal))
  1180.             {
  1181.                 HX_VECTOR_DELETE(ppStr);
  1182.             }
  1183.         }
  1184.         else
  1185.         {
  1186.             retVal = HXR_FAIL;
  1187.         }
  1188.     }
  1189.     else
  1190.     {
  1191.         retVal = HXR_OUTOFMEMORY;
  1192.     }
  1193.     if (FAILED(retVal))
  1194.     {
  1195.         HX_VECTOR_DELETE(pStr);
  1196.     }
  1197.     return retVal;
  1198. }
  1199. HX_RESULT CSmilParser::animParseValue(CSmilAnimateElement* pAnim,
  1200.                                       const char*          pszVal,
  1201.                                       UINT32               i)
  1202. {
  1203.     HX_RESULT retVal = HXR_OK;
  1204.     if (pAnim && pszVal && i < pAnim->m_ulNumValues)
  1205.     {
  1206.         // Allocate a new CAttr
  1207.         CAttr* pAttr = new CAttr(pAnim->m_ucAttributeName, pszVal);
  1208.         if (pAttr)
  1209.         {
  1210.             retVal = pAttr->GetLastError();
  1211.             if (SUCCEEDED(retVal))
  1212.             {
  1213.                 HX_DELETE(pAnim->m_ppValue[i]);
  1214.                 pAnim->m_ppValue[i] = pAttr;
  1215.             }
  1216.         }
  1217.         else
  1218.         {
  1219.             retVal = HXR_OUTOFMEMORY;
  1220.         }
  1221.         if (FAILED(retVal))
  1222.         {
  1223.             HX_DELETE(pAttr);
  1224.         }
  1225.     }
  1226.     else
  1227.     {
  1228.         retVal = HXR_FAIL;
  1229.     }
  1230.     return retVal;
  1231. }
  1232. #endif /* #if defined(HELIX_FEATURE_SMIL2_ANIMATION) */
  1233. CSmilParamElement* CSmilParser::makeParamElement(SMILNode* pNode)
  1234. {
  1235.     CSmilParamElement* pRet   = NULL;
  1236.     HX_RESULT          retVal = HXR_OK;
  1237.     if (pNode)
  1238.     {
  1239.         pRet = new CSmilParamElement(pNode);
  1240.         if (pRet)
  1241.         {
  1242.             if (pNode->m_pValues)
  1243.             {
  1244.                 const char* pszName = NULL;
  1245.                 IHXBuffer* pValue  = NULL;
  1246.                 HX_RESULT   rv      = pNode->m_pValues->GetFirstPropertyCString(pszName, pValue);
  1247.                 while (SUCCEEDED(rv) && SUCCEEDED(retVal))
  1248.                 {
  1249.                     // Get the string version of the value
  1250.                     const char* pszValue = (const char*) pValue->GetBuffer();
  1251.                     // Get the SMIL2Attribute
  1252.                     SMIL2Attribute eAttr = getSMIL2Attribute(pszName);
  1253.                     // Switch on attribute name
  1254.                     switch (eAttr)
  1255.                     {
  1256.                         case SMIL2AttrName:
  1257.                             {
  1258.                                 HX_RELEASE(pRet->m_pName);
  1259.                                 pRet->m_pName = pValue;
  1260.                                 pRet->m_pName->AddRef();
  1261.                             }
  1262.                             break;
  1263.                         case SMIL2AttrValue:
  1264.                             {
  1265.                                 HX_RELEASE(pRet->m_pValue);
  1266.                                 pRet->m_pValue = pValue;
  1267.                                 pRet->m_pValue->AddRef();
  1268.                             }
  1269.                             break;
  1270.                         default:
  1271.                             {
  1272.                                 // Find out if this attribute is namespace-prefixed. Since
  1273.                                 // we assume that this document has already been validated,
  1274.                                 // then we don't have to throw an error if it's not - it's
  1275.                                 // probably just an attribute we are not parsing above.
  1276.                                 const char*     pszAttr = NULL;
  1277.                                 CNamespaceInfo* pNSInfo = getNamespaceInfo(pszName, pszAttr);
  1278.                                 if (pNSInfo)
  1279.                                 {
  1280.                                     // This attribute IS namespace-prefixed.
  1281.                                     //
  1282.                                     // If this is the Param namespace, then
  1283.                                     // we should parse it for "delivery"
  1284.                                     if (pNSInfo->m_eNamespace == NamespaceParam ||
  1285.                                         pNSInfo->m_eNamespace == NamespaceAllSMIL2Extensions)
  1286.                                     {
  1287.                                         if(!strcmp(pszAttr, "delivery"))
  1288.                                         {
  1289.                                             if (!strcmp(pszValue, "server"))
  1290.                                             {
  1291.                                                 pRet->m_eDelivery = DeliveryServer;
  1292.                                             }
  1293.                                             else if (!strcmp(pszValue, "client"))
  1294.                                             {
  1295.                                                 pRet->m_eDelivery = DeliveryClient;
  1296.                                             }
  1297.                                             else
  1298.                                             {
  1299.                                                 retVal = HXR_FAIL;
  1300.                                                 CSmilSMILSyntaxErrorHandler errHandler(m_pContext);
  1301.                                                 errHandler.ReportError(SMILErrorBadAttribute,
  1302.                                                                        pszName,
  1303.                                                                        pRet->m_pNode->m_ulTagStartLine);
  1304.                                             }
  1305.                                         }
  1306.                                     }
  1307.                                 }
  1308.                             }
  1309.                     }
  1310.                     // Get the next attribute
  1311.                     HX_RELEASE(pValue);
  1312.                     rv = pNode->m_pValues->GetNextPropertyCString(pszName, pValue);
  1313.                 }
  1314.             }
  1315.         }
  1316.         else
  1317.         {
  1318.             retVal = HXR_OUTOFMEMORY;
  1319.         }
  1320.     }
  1321.     else
  1322.     {
  1323.         retVal = HXR_FAIL;
  1324.     }
  1325.     if (FAILED(retVal))
  1326.     {
  1327.         HX_DELETE(pRet);
  1328.     }
  1329.     return pRet;
  1330. }
  1331. CSmilBodyElement* CSmilParser::makeBodyElement(SMILNode* pNode)
  1332. {
  1333.     CSmilBodyElement* pRet   = NULL;
  1334.     HX_RESULT         retVal = HXR_OK;
  1335.     if (pNode)
  1336.     {
  1337.         pRet = new CSmilBodyElement(pNode);
  1338.         if (pRet)
  1339.         {
  1340.             if (pNode->m_pValues)
  1341.             {
  1342.                 const char* pszName = NULL;
  1343.                 IHXBuffer* pValue  = NULL;
  1344.                 HX_RESULT   rv      = pNode->m_pValues->GetFirstPropertyCString(pszName, pValue);
  1345.                 while (SUCCEEDED(rv) && SUCCEEDED(retVal))
  1346.                 {
  1347.                     // Get the string version of the value
  1348.                     const char* pszValue = (const char*) pValue->GetBuffer();
  1349.                     // Get the SMIL2Attribute
  1350.                     SMIL2Attribute eAttr = getSMIL2Attribute(pszName);
  1351.                     // Switch on attribute name
  1352.                     switch (eAttr)
  1353.                     {
  1354.                         // We currently don't care about other
  1355.                         // attributes on <body>
  1356.                         default:
  1357.                             {
  1358.                                 // Find out if this attribute is namespace-prefixed. Since
  1359.                                 // we assume that this document has already been validated,
  1360.                                 // then we don't have to throw an error if it's not - it's
  1361.                                 // probably just an attribute we are not parsing above.
  1362.                                 const char*     pszAttr = NULL;
  1363.                                 CNamespaceInfo* pNSInfo = getNamespaceInfo(pszName, pszAttr);
  1364.                                 if (pNSInfo)
  1365.                                 {
  1366.                                     // This attribute IS namespace-prefixed.
  1367.                                     if (pNSInfo->m_eNamespace == NamespaceAccessErrorBehavior ||
  1368.                                         pNSInfo->m_eNamespace == NamespaceAllSMIL2Extensions)
  1369.                                     {
  1370.                                         if(!strcmp(pszAttr, "accessErrorBehavior"))
  1371.                                         {
  1372.                                             retVal = parseAccessErrorBehavior(pszValue, pRet->m_eAccessErrorBehavior);
  1373.                                             if (FAILED(retVal))
  1374.                                             {
  1375.                                                 CSmilSMILSyntaxErrorHandler errHandler(m_pContext);
  1376.                                                 errHandler.ReportError(SMILErrorBadAttribute,
  1377.                                                                        pszName,
  1378.                                                                        pRet->m_pNode->m_ulTagStartLine);
  1379.                                             }
  1380.                                         }
  1381.                                     }
  1382.                                 }
  1383.                             }
  1384.                     }
  1385.                     // Get the next attribute
  1386.                     HX_RELEASE(pValue);
  1387.                     rv = pNode->m_pValues->GetNextPropertyCString(pszName, pValue);
  1388.                 }
  1389.             }
  1390.         }
  1391.         else
  1392.         {
  1393.             retVal = HXR_OUTOFMEMORY;
  1394.         }
  1395.     }
  1396.     else
  1397.     {
  1398.         retVal = HXR_FAIL;
  1399.     }
  1400.     if (FAILED(retVal))
  1401.     {
  1402.         HX_DELETE(pRet);
  1403.     }
  1404.     return pRet;
  1405. }
  1406. HX_RESULT
  1407. CSmilParser::insertElementByTimestamp(CSmilElement* pPacket)
  1408. {
  1409.     LISTPOSITION lPos = m_pPacketQueue->GetHeadPosition();
  1410.     LISTPOSITION lPrev = lPos;
  1411.     while(lPos)
  1412.     {
  1413. CSmilElement* pPkt = (CSmilElement*)m_pPacketQueue->GetNext(lPos);
  1414. if(pPkt->m_ulTimestamp > pPacket->m_ulTimestamp)
  1415. {
  1416.     m_pPacketQueue->InsertBefore(lPrev, pPacket);
  1417.     return HXR_OK;
  1418. }
  1419. lPrev = lPos;
  1420.     }
  1421.     m_pPacketQueue->AddTail(pPacket);
  1422.     return HXR_OK;
  1423. }
  1424. HX_RESULT
  1425. CSmilParser::mapID(SMILNode* pNode, BOOL bOverWrite)
  1426. {
  1427.     HX_RESULT rc = HXR_OK;
  1428.     void* pTmp = 0;
  1429.     if(!bOverWrite && m_pIDMap->Lookup((const char*)pNode->m_id, (void*&)pTmp))
  1430.     {
  1431. rc = HXR_FAIL;
  1432. CSmilSMILSyntaxErrorHandler errHandler(m_pContext);
  1433. errHandler.ReportError(SMILErrorDuplicateID, pNode->m_id,
  1434. pNode->m_ulTagStartLine);
  1435.     }
  1436.     else
  1437.     {
  1438. (*m_pIDMap)[(const char*)pNode->m_id] = pNode;
  1439.     }
  1440.     return rc;
  1441. }
  1442. //This function is needed to fix PR 13319.  If you have a repeat of greater
  1443. // than 1 in a <seq>, we need a way to map the IDs of the children created
  1444. // when the additional <seq>(s) are created
  1445. HX_RESULT
  1446. CSmilParser::mapChildrenIDs(SMILNodeList* pNodeList, BOOL bOverWrite)
  1447. {
  1448.     HX_RESULT rc = HXR_OK;
  1449.     if (!pNodeList)
  1450.     {
  1451. return rc;
  1452.     }
  1453.     CHXSimpleList::Iterator i;
  1454.     for(i=pNodeList->Begin();rc == HXR_OK && i!=pNodeList->End();++i)
  1455.     {
  1456. SMILNode* pNode = (SMILNode*)(*i);
  1457. rc = mapID(pNode, bOverWrite);
  1458. HX_ASSERT(rc == HXR_OK);
  1459. if(pNode->m_pNodeList)
  1460. {
  1461.     rc = mapChildrenIDs(pNode->m_pNodeList, bOverWrite);
  1462. }
  1463.     }
  1464.     return rc;
  1465. }
  1466. HX_RESULT
  1467. CSmilParser::markRepeatReplica(SMILNodeList* pNodeList, RepeatTag repeatTag)
  1468. {
  1469.     HX_RESULT rc = HXR_OK;
  1470.     if(!pNodeList)
  1471.     {
  1472. return rc;
  1473.     }
  1474.     CHXSimpleList::Iterator i;
  1475.     for(i=pNodeList->Begin();rc == HXR_OK && i!=pNodeList->End();++i)
  1476.     {
  1477. SMILNode* pNode = (SMILNode*)(*i);
  1478. pNode->m_repeatTag = repeatTag;
  1479. if(pNode->m_pNodeList)
  1480. {
  1481.     rc = markRepeatReplica(pNode->m_pNodeList, repeatTag);
  1482. }
  1483.     }
  1484.     return rc;
  1485. }
  1486. #if defined(HELIX_FEATURE_SMIL2_VALIDATION)
  1487. HX_RESULT CSmilParser::validateContentModel(UINT32 ulElement, SMILNodeList* pChildren)
  1488. {
  1489.     HX_RESULT retVal = HXR_OK;
  1490.     if (pChildren)
  1491.     {
  1492.         if (ulElement < NumSMIL2Elements)
  1493.         {
  1494.             // First just do a check to make sure that
  1495.             // there are no illegal elements.
  1496.             UINT32 ulNumLegalChildren  = 0;
  1497.             UINT32 ulNumPCChildren     = 0;
  1498.             UINT32 ulNumLayoutChildren = 0;
  1499.             UINT32 ulHeadIndex         = 0;
  1500.             UINT32 ulBodyIndex         = 0;
  1501.             LISTPOSITION pos = pChildren->GetHeadPosition();
  1502.             while (pos && SUCCEEDED(retVal))
  1503.             {
  1504.                 SMILNode* pChild = (SMILNode*) pChildren->GetNext(pos);
  1505.                 if (pChild &&
  1506.                     !pChild->m_bCloseNode &&
  1507.                     !pChild->m_bNamespacedElement)
  1508.                 {
  1509.                     if (!m_pContentModelMap->IsSet(ulElement, pChild->m_eElement))
  1510.                     {
  1511.                         retVal = HXR_FAIL;
  1512.                         CSmilSMILSyntaxErrorHandler errHandler(m_pContext);
  1513.                         errHandler.ReportError(SMILErrorUnexpectedTag,
  1514.                                                pChild->m_name,
  1515.                                                pChild->m_ulTagStartLine);
  1516.                     }
  1517.                     else
  1518.                     {
  1519.                         if (ulElement == SMIL2ElemExcl &&
  1520.                             pChild->m_eElement == SMIL2ElemPriorityClass)
  1521.                         {
  1522.                             ulNumPCChildren++;
  1523.                         }
  1524.                         else if (ulElement == SMIL2ElemSwitch &&
  1525.                                  pChild->m_eElement == SMIL2ElemLayout)
  1526.                         {
  1527.                             ulNumLayoutChildren++;
  1528.                         }
  1529.                         else if (ulElement == SMIL2ElemSmil)
  1530.                         {
  1531.                             if (pChild->m_eElement == SMIL2ElemHead)
  1532.                             {
  1533.                                 ulHeadIndex = ulNumLegalChildren;
  1534.                             }
  1535.                             else if (pChild->m_eElement == SMIL2ElemBody)
  1536.                             {
  1537.                                 ulBodyIndex = ulNumLegalChildren;
  1538.                             }
  1539.                         }
  1540.                         ulNumLegalChildren++;
  1541.                     }
  1542.                 }
  1543.             }
  1544.             // Now if we succeeded, then there are a few elements with
  1545.             // very specific content models.
  1546.             if (SUCCEEDED(retVal))
  1547.             {
  1548.                 switch (ulElement)
  1549.                 {
  1550.                     case SMIL2ElemCustomAttributes:
  1551.                         {
  1552.                             // Must be at least 1 customTest element
  1553.                             if (!ulNumLegalChildren)
  1554.                             {
  1555.                                 retVal = HXR_FAIL;
  1556.                             }
  1557.                         }
  1558.                         break;
  1559.                     case SMIL2ElemExcl:
  1560.                         {
  1561.                             // If there are ANY priority class children, then they
  1562.                             // have to be the ONLY children.
  1563.                             if (ulNumPCChildren > 0 &&
  1564.                                 ulNumPCChildren < ulNumLegalChildren)
  1565.                             {
  1566.                                 retVal = HXR_FAIL;
  1567.                             }
  1568.                         }
  1569.                         break;
  1570.                     case SMIL2ElemHead:
  1571.                         {
  1572.                             // XXXMEH - TODO: figure out what
  1573.                             // is meant by the content model of <head>.
  1574.                         }
  1575.                         break;
  1576.                     case SMIL2ElemSmil:
  1577.                         {
  1578.                             // Content model is (head?, body?), so if there's
  1579.                             // only 1 legal child, then we know we're correct.
  1580.                             // If there's two, then we have to make sure the
  1581.                             // first is a <head> and the second is a <body>
  1582.                             if (ulNumLegalChildren == 2 &&
  1583.                                 ulBodyIndex <= ulHeadIndex)
  1584.                             {
  1585.                                 retVal = HXR_FAIL;
  1586.                             }
  1587.                         }
  1588.                         break;
  1589.                     case SMIL2ElemSwitch:
  1590.                         {
  1591.                             // If there are ANY layout children, then they
  1592.                             // have to be the ONLY children.
  1593.                             if (ulNumLayoutChildren > 0 &&
  1594.                                 ulNumLayoutChildren < ulNumLegalChildren)
  1595.                             {
  1596.                                 retVal = HXR_FAIL;
  1597.                             }
  1598.                         }
  1599.                         break;
  1600.                 }
  1601.             }
  1602.         }
  1603.         else
  1604.         {
  1605.             retVal = HXR_FAIL;
  1606.         }
  1607.     }
  1608.     return retVal;
  1609. }
  1610. HX_RESULT CSmilParser::validateNode(SMILNode* pNode)
  1611. {
  1612.     HX_RESULT retVal = HXR_OK;
  1613.     if (pNode &&
  1614.         !pNode->m_bCloseNode &&       // don't care about closing nodes
  1615.         !pNode->m_bNamespacedElement) // won't validate namespaced elements
  1616.     {
  1617.         // Initialize the IHXValues which will hold
  1618.         // any attributes which are different from
  1619.         // their normalized form
  1620.         IHXValues* pNormAttributes = NULL;
  1621.         // Initialize error info
  1622.         SMILErrorTag eError       = SMILErrorNone;
  1623.         BOOL         bChildFailed = FALSE;
  1624.         CHXString    cErrStr;
  1625.         // Check that all the attributes are legal attributes
  1626.         if (pNode->m_pValues)
  1627.         {
  1628.             const char* pszName = NULL;
  1629.             IHXBuffer* pValue  = NULL;
  1630.             HX_RESULT   rv      = pNode->m_pValues->GetFirstPropertyCString(pszName, pValue);
  1631.             while (SUCCEEDED(rv) && SUCCEEDED(retVal))
  1632.             {
  1633.                 // Is the attribute name valid?
  1634.                 BOOL               bNSAttr     = FALSE;
  1635.                 BOOL               bUnknownNS  = FALSE;
  1636.                 SupportedNamespace eNS         = NamespaceNotImplemented;
  1637.                 UINT32             ulAttribute = 0;
  1638.                 void* pVoid        = NULL;
  1639.                 if (m_pAttributeMap->Lookup(pszName, pVoid))
  1640.                 {
  1641.                     // Get the attribute index
  1642.                     ulAttribute = (UINT32) pVoid;
  1643.                 }
  1644.                 else
  1645.                 {
  1646.                     // We didn't find the attribute in the SMIL 2 namespace,
  1647.                     // so let's see if the attribute has a valid namespace prefix
  1648.                     const char*     pszAttr = NULL;
  1649.                     CNamespaceInfo* pNSInfo = getNamespaceInfo(pszName, pszAttr);
  1650.                     if (pNSInfo)
  1651.                     {
  1652.                         // Set the flag saying this is a namespaced attribute
  1653.                         bNSAttr = TRUE;
  1654.                         // Yes, this attribute has a valid namespace prefix
  1655.                         // But is this a namespace we support?
  1656.                         if (pNSInfo->m_eNamespace != NamespaceNotImplemented)
  1657.                         {
  1658.                             // Set the namespace to use for later
  1659.                             eNS = pNSInfo->m_eNamespace;
  1660.                             // Look up the attribute in our
  1661.                             // extension namespace map
  1662.                             if (m_pExtAttributeMap->Lookup(pszAttr, pVoid))
  1663.                             {
  1664.                                 // Get the attribute index
  1665.                                 ulAttribute = (UINT32) pVoid;
  1666.                             }
  1667.                             else
  1668.                             {
  1669.                                 // We don't have this attribute in our
  1670.                                 // namespace map
  1671.                                 retVal  = HXR_FAIL;
  1672.                                 eError  = SMILErrorUnrecognizedAttribute;
  1673.                                 cErrStr = pszName;
  1674.                             }
  1675.                         }
  1676.                         else
  1677.                         {
  1678.                             // Valid namespace, but not one we implement
  1679.                             bUnknownNS = TRUE;
  1680.                         }
  1681.                     }
  1682.                     else
  1683.                     {
  1684.                         // No this attribute doesn't have a namespace
  1685.                         // prefix that has been declared.
  1686.                         //
  1687.                         // Is this the <smil> element and is this an xmlns:foo attribute?
  1688.                         // If so, then let it go by since we have already processed
  1689.                         // the namespaces
  1690.                         if (pNode->m_eElement != SMIL2ElemSmil ||
  1691.                             strncmp(pszName, "xmlns:", 6) != 0)
  1692.                         {
  1693.                             // This is just an error
  1694.                             retVal  = HXR_FAIL;
  1695.                             eError  = SMILErrorUnrecognizedAttribute;
  1696.                             cErrStr = pszName;
  1697.                         }
  1698.                         else
  1699.                         {
  1700.                             // We don't want to do validation on xmlns:xx
  1701.                             // attributes, so treat this as an unknown NS
  1702.                             bUnknownNS = TRUE;
  1703.                         }
  1704.                     }
  1705.                 }
  1706.                 if (SUCCEEDED(retVal))
  1707.                 {
  1708.                     // Did we recognize the namespace? If we didn't
  1709.                     // implement the namespace, then we don't need to
  1710.                     // do anything further
  1711.                     if (!bUnknownNS)
  1712.                     {
  1713.                         // If this was a namespaced attribute, then
  1714.                         // check the namespace it came from
  1715.                         if (bNSAttr)
  1716.                         {
  1717.                             retVal = checkExtensionAttributeNamespace((SMIL2Attribute) ulAttribute, eNS);
  1718.                             if (FAILED(retVal))
  1719.                             {
  1720.                                 eError  = SMILErrorUnrecognizedAttribute;
  1721.                                 cErrStr = pszName;
  1722.                             }
  1723.                         }
  1724.                         if (SUCCEEDED(retVal))
  1725.                         {
  1726.                             // Check if the attribute is legal for this element
  1727.                             if (m_pLegalAttrMap->IsSet(pNode->m_eElement, ulAttribute))
  1728.                             {
  1729.                                 // Legal attribute, now validate the attribute
  1730.                                 const char* pszOrigAttr = (const char*) pValue->GetBuffer();
  1731.                                 char*       pszNormAttr = NULL;
  1732.                                 retVal = validateAttribute(pNode->m_eElement, ulAttribute,
  1733.                                                            pszOrigAttr, pszNormAttr);
  1734.                                 if (SUCCEEDED(retVal))
  1735.                                 {
  1736.                                     // We validated correctly.
  1737.                                     //
  1738.                                     // Now check if the normalized attribute
  1739.                                     // was different from the original attribute.
  1740.                                     if (strcmp(pszOrigAttr, pszNormAttr))
  1741.                                     {
  1742.                                         if (!pNormAttributes)
  1743.                                         {
  1744.                                             m_pClassFactory->CreateInstance(CLSID_IHXValues,
  1745.                                                                             (void**) &pNormAttributes);
  1746.                                         }
  1747.                                         addStringProperty(pNormAttributes,
  1748.                                                           m_pContext,
  1749.                                                           pszName,
  1750.                                                           pszNormAttr);
  1751.                                     }
  1752.                                 }
  1753.                                 else
  1754.                                 {
  1755.                                     // Attribute doesn't validate
  1756.                                     eError  = SMILErrorBadAttribute;
  1757.                                     cErrStr = pszName;
  1758.                                 }
  1759.                                 HX_VECTOR_DELETE(pszNormAttr);
  1760.                             }
  1761.                             else
  1762.                             {
  1763.                                 // Nope, this attribute is not legal on this element
  1764.                                 retVal  = HXR_FAIL;
  1765.                                 eError  = SMILErrorUnrecognizedAttribute;
  1766.                                 cErrStr = pszName;
  1767.                             }
  1768.                         }
  1769.                     }
  1770.                 }
  1771.                 // Get the next attribute
  1772.                 HX_RELEASE(pValue);
  1773.                 rv = pNode->m_pValues->GetNextPropertyCString(pszName, pValue);
  1774.             }
  1775.         }
  1776.         if (SUCCEEDED(retVal))
  1777.         {
  1778.             // Now check if all REQUIRED attributes are present
  1779.             // If there is an entry for our element, then we have
  1780.             // required attributes to check. If not, then this
  1781.             // element has no required attributes
  1782.             if (m_ppReqAttrList &&
  1783.                 m_ppReqAttrList[pNode->m_eElement])
  1784.             {
  1785.                 // Get the list
  1786.                 CHXSimpleList* pList = m_ppReqAttrList[pNode->m_eElement];
  1787.                 // This element does have required attributes - check them
  1788.                 LISTPOSITION pos = pList->GetHeadPosition();
  1789.                 while (pos && SUCCEEDED(retVal))
  1790.                 {
  1791.                     UINT32 ulAttr = (UINT32) pList->GetNext(pos);
  1792.                     if (ulAttr < NumSMIL2Attributes)
  1793.                     {
  1794.                         // Get the attribute string
  1795.                         const char* pszStr = g_AttributeTable[ulAttr].m_pszString;
  1796.                         // Does this element have any attributes?
  1797.                         if (pNode->m_pValues)
  1798.                         {
  1799.                             // Check if this attribute is present
  1800.                             IHXBuffer* pAttrBuf = NULL;
  1801.                             retVal = pNode->m_pValues->GetPropertyCString(pszStr, pAttrBuf);
  1802.                             HX_RELEASE(pAttrBuf);
  1803.                         }
  1804.                         else
  1805.                         {
  1806.                             // No attributes, so we KNOW it doesn't have
  1807.                             // this required attribute
  1808.                             retVal  = HXR_FAIL;
  1809.                         }
  1810.                         if (FAILED(retVal))
  1811.                         {
  1812.                             cErrStr = pszStr;
  1813.                         }
  1814.                     }
  1815.                 }
  1816.                 if (FAILED(retVal))
  1817.                 {
  1818.                     eError = SMILErrorRequiredAttributeMissing;
  1819.                 }
  1820.             }
  1821.             if (SUCCEEDED(retVal))
  1822.             {
  1823.                 // Validate the content according to the DTD content model
  1824.                 retVal = validateContentModel(pNode->m_eElement, pNode->m_pNodeList);
  1825.                 if (SUCCEEDED(retVal))
  1826.                 {
  1827.                     // Now loop through each of the children and
  1828.                     // validate each of them. First, do we have any children?
  1829.                     if (pNode->m_pNodeList)
  1830.                     {
  1831.                         LISTPOSITION pos = pNode->m_pNodeList->GetHeadPosition();
  1832.                         while (pos && SUCCEEDED(retVal))
  1833.                         {
  1834.                             SMILNode* pChildNode = (SMILNode*) pNode->m_pNodeList->GetNext(pos);
  1835.                             if (pChildNode)
  1836.                             {
  1837.                                 retVal = validateNode(pChildNode);
  1838.                                 if (FAILED(retVal))
  1839.                                 {
  1840.                                     bChildFailed = TRUE;
  1841.                                 }
  1842.                             }
  1843.                         }
  1844.                     }
  1845.                 }
  1846.             }
  1847.         }
  1848.         // Now check if we need to overwrite some of
  1849.         // the original attributes with their normalized forms.
  1850.         if (SUCCEEDED(retVal) && pNormAttributes)
  1851.         {
  1852.             // We need to copy all the strings for
  1853.             // which the normalized attribute value
  1854.             // was different than the original attribute
  1855.             // value. Note that this will replace the
  1856.             // original attribute value.
  1857.             const char* pszName    = NULL;
  1858.             IHXBuffer* pNormValue = NULL;
  1859.             HX_RESULT rv = pNormAttributes->GetFirstPropertyCString(pszName, pNormValue);
  1860.             while (SUCCEEDED(rv))
  1861.             {
  1862.                 // Sanity check to make sure the attribute already exists
  1863.                 // in the current attributes IHXValues
  1864.                 IHXBuffer* pOrigValue = NULL;
  1865.                 pNode->m_pValues->GetPropertyCString(pszName, pOrigValue);
  1866.                 if (pOrigValue)
  1867.                 {
  1868.                     pNode->m_pValues->SetPropertyCString(pszName, pNormValue);
  1869.                 }
  1870.                 HX_RELEASE(pOrigValue);
  1871.                 // Get the next normalized attribute
  1872.                 HX_RELEASE(pNormValue);
  1873.                 rv = pNormAttributes->GetNextPropertyCString(pszName, pNormValue);
  1874.             }
  1875.         }
  1876.         // Now report any errors, but not if it
  1877.         // was just that the child of this node failed, because
  1878.         // presumably that node threw an error when it
  1879.         // was validated.
  1880.         if (FAILED(retVal) && !bChildFailed)
  1881.         {
  1882.             CSmilSMILSyntaxErrorHandler errHandler(m_pContext);
  1883.             errHandler.ReportError(eError, cErrStr, pNode->m_ulTagStartLine);
  1884.         }
  1885.         // Release the normalized attributes
  1886.         HX_RELEASE(pNormAttributes);
  1887.     }
  1888.     return retVal;
  1889. }
  1890. HX_RESULT CSmilParser::validateCDATA(const char* pszStr) const
  1891. {
  1892.     HX_RESULT retVal = HXR_OK;
  1893.     if (pszStr)
  1894.     {
  1895.         char*  pCh   = (char*) pszStr;
  1896.         while (*pCh)
  1897.         {
  1898.     // /Removing the ++ from "...= *pCh++;" fixes bug where
  1899.     // HXGetNextChar(pCh), below, otherwise will go on into
  1900.     // whatever is past the end of pCh:
  1901.             UCHAR c = *pCh;
  1902.             if (c <  0x20 &&
  1903.                 c != 0x09 &&
  1904.                 c != 0x0A &&
  1905.                 c != 0x0D)
  1906.             {
  1907.                 retVal = HXR_FAIL;
  1908.                 break;
  1909.             }
  1910.             pCh = HXGetNextChar(pCh);
  1911.         }
  1912.     }
  1913.     else
  1914.     {
  1915.         retVal = HXR_FAIL;
  1916.     }
  1917.     return retVal;
  1918. }
  1919. HX_RESULT CSmilParser::validateIDREF(const char* pszStr) const
  1920. {
  1921.     HX_RESULT retVal = HXR_OK;
  1922.     if (pszStr)
  1923.     {
  1924.         UINT32 ulLen = (UINT32) strlen(pszStr);
  1925.         char*  pCh   = (char*) pszStr;
  1926.         // Check first character
  1927.         char c = *pCh++;
  1928.         ulLen--;
  1929.         if (isXMLLetter(c) ||
  1930.             c == '_'       ||
  1931.             c == ':')
  1932.         {
  1933.             // Check rest of letters
  1934.             while (ulLen--)
  1935.             {
  1936.                 char c = *pCh++;
  1937.                 if (!isXMLNameChar(c))
  1938.                 {
  1939.                     retVal = HXR_FAIL;
  1940.                     break;
  1941.                 }
  1942.             }
  1943.         }
  1944.     }
  1945.     else
  1946.     {
  1947.         retVal = HXR_FAIL;
  1948.     }
  1949.     return retVal;
  1950. }
  1951. HX_RESULT CSmilParser::validateNMTOKEN(const char* pszStr) const
  1952. {
  1953.     HX_RESULT retVal = HXR_OK;
  1954.     if (pszStr)
  1955.     {
  1956.         UINT32 ulLen = (UINT32) strlen(pszStr);
  1957.         if (ulLen >= 1)
  1958.         {
  1959.             char* pCh = (char*) pszStr;
  1960.             while (ulLen--)
  1961.             {
  1962.                 char c = *pCh++;
  1963.                 if (!isXMLNameChar(c))
  1964.                 {
  1965.                     retVal = HXR_FAIL;
  1966.                     break;
  1967.                 }
  1968.             }
  1969.         }
  1970.         else
  1971.         {
  1972.             retVal = HXR_FAIL;
  1973.         }
  1974.     }
  1975.     else
  1976.     {
  1977.         retVal = HXR_FAIL;
  1978.     }
  1979.     return retVal;
  1980. }
  1981. HX_RESULT CSmilParser::validateEnumerated(UINT32 ulElem, UINT32 ulAttr, const char* pszStr)
  1982. {
  1983.     HX_RESULT retVal = HXR_FAIL;
  1984.     if (pszStr &&
  1985.         ulAttr < NumSMIL2Attributes &&
  1986.         m_ppEnumAttrMap &&
  1987.         m_ppEnumAttrMap[ulAttr])
  1988.     {
  1989.         void* pVoid = NULL;
  1990.         if (m_ppEnumAttrMap[ulAttr]->Lookup(pszStr, pVoid))
  1991.         {
  1992.             retVal = HXR_OK;
  1993.         }
  1994.         else
  1995.         {
  1996.             // If this is the "type" or "subtype" attribute
  1997.             // on the <transition> element, then we also
  1998.             // have to check for namespaced attribute values
  1999.             if (ulElem == SMIL2ElemTransition &&
  2000.                 (ulAttr == SMIL2AttrType ||
  2001.                  ulAttr == SMIL2AttrSubtype))
  2002.             {
  2003.                 // XXXMEH - the spec says that we should not
  2004.                 // error out on bad transition types or subtypes.
  2005.                 // Previously, we required that a transition
  2006.                 // type or subtype be namespaced in order not
  2007.                 // throw an error. Now we don't require that.
  2008. //                if (isNamespacePrefixed(pszStr))
  2009. //                {
  2010.                     retVal = HXR_OK;
  2011. //                }
  2012.             }
  2013.         }
  2014.     }
  2015.     return retVal;
  2016. }
  2017. BOOL CSmilParser::isNamespacePrefixed(const char* pszStr)
  2018. {
  2019.     BOOL bRet = FALSE;
  2020.     if (pszStr && m_pValNSList)
  2021.     {
  2022.         LISTPOSITION pos = m_pValNSList->GetHeadPosition();
  2023.         while (pos)
  2024.         {
  2025.             CNamespaceInfo* pInfo = (CNamespaceInfo*) m_pValNSList->GetNext(pos);
  2026.             if (pInfo)
  2027.             {
  2028.                 UINT32 ulPrefixLen = (UINT32) strlen(pInfo->m_pszPrefix);
  2029.                 if (!strncmp(pszStr, pInfo->m_pszPrefix, ulPrefixLen))
  2030.                 {
  2031.                     // We match this namespace prefix
  2032.                     bRet = TRUE;
  2033.                     break;
  2034.                 }
  2035.             }
  2036.         }
  2037.     }
  2038.     return bRet;
  2039. }
  2040. HX_RESULT CSmilParser::normalizeAttribute(const char* pszStr,
  2041.                                           BOOL        bIsCDATA,
  2042.                                           REF(char*)  rpszNormal)
  2043. {
  2044.     HX_RESULT retVal = HXR_FAIL;
  2045.     if (pszStr)
  2046.     {
  2047.         UINT32 ulLen    = (UINT32) strlen(pszStr);
  2048.         char*  pNormal1 = new char [ulLen + 1];
  2049.         if (pNormal1)
  2050.         {
  2051.             memset(pNormal1, 0, ulLen + 1);
  2052.             // Do first part of XML normalization algorithm
  2053.             char* pSrc = (char*) pszStr;
  2054.             char* pDst = pNormal1;
  2055.             while (ulLen--)
  2056.             {
  2057.                 char c = *pSrc++;
  2058.                 if (c == 0x20 ||
  2059.                     c == 0x0D ||
  2060.                     c == 0x0A ||
  2061.                     c == 0x09)
  2062.                 {
  2063.                     *pDst++ = (char) 0x20;
  2064.                 }
  2065.                 else
  2066.                 {
  2067.                     *pDst++ = c;
  2068.                 }
  2069.             }
  2070.             // If the attribute is not CDATA, then we
  2071.             // need to remove leading and trailing spaces
  2072.             // as well as remove sequences of spaces.
  2073.             if (bIsCDATA)
  2074.             {
  2075.                 HX_VECTOR_DELETE(rpszNormal);
  2076.                 rpszNormal = pNormal1;
  2077.                 retVal     = HXR_OK;
  2078.             }
  2079.             else
  2080.             {
  2081.                 ulLen = (UINT32) strlen(pNormal1);
  2082.                 char* pNormal2 = new char [ulLen + 1];
  2083.                 if (pNormal2)
  2084.                 {
  2085.                     memset(pNormal2, 0, ulLen + 1);
  2086.                     BOOL  bFirst   = TRUE;
  2087.                     char* pszToken = strtok(pNormal1, " ");
  2088.                     while (pszToken)
  2089.                     {
  2090.                         if (!bFirst)
  2091.                         {
  2092.                             strcat(pNormal2, " "); /* Flawfinder: ignore */
  2093.                         }
  2094.                         strcat(pNormal2, pszToken); /* Flawfinder: ignore */
  2095.                         if (bFirst) bFirst = FALSE;
  2096.                         pszToken = strtok(NULL, " ");
  2097.                     }
  2098.                     // Copy to the out parameter
  2099.                     HX_VECTOR_DELETE(pNormal1);
  2100.                     HX_VECTOR_DELETE(rpszNormal);
  2101.                     rpszNormal = pNormal2;
  2102.                     retVal     = HXR_OK;
  2103.                 }
  2104.             }
  2105.         }
  2106.     }
  2107.     return retVal;
  2108. }
  2109. HX_RESULT CSmilParser::validateAttribute(UINT32      ulElement,
  2110.                                          UINT32      ulAttrib,
  2111.                                          const char* pszStr,
  2112.                                          REF(char*)  rpszNormStr)
  2113. {
  2114.     HX_RESULT retVal = HXR_OK;
  2115.     if (ulElement < NumSMIL2Elements &&
  2116.         ulAttrib  < NumSMIL2Attributes &&
  2117.         pszStr)
  2118.     {
  2119.         // Look up the attribute type
  2120.         XMLAttributeType eType = m_pAttrType[ulAttrib];
  2121.         // There are two different elements with
  2122.         // two different "type" attributes, so distinguish
  2123.         // in between them.
  2124.         if (ulAttrib == SMIL2AttrType)
  2125.         {
  2126.             if (ulElement == SMIL2ElemTransition)
  2127.             {
  2128.                 eType = XMLAttrTypeEnumerated;
  2129.             }
  2130.             else
  2131.             {
  2132.                 eType = XMLAttrTypeCDATA;
  2133.             }
  2134.         }
  2135.         // Normalize the attribute
  2136.         HX_VECTOR_DELETE(rpszNormStr);
  2137.         retVal = normalizeAttribute(pszStr, (eType == XMLAttrTypeCDATA), rpszNormStr);
  2138.         if (SUCCEEDED(retVal))
  2139.         {
  2140.             switch (eType)
  2141.             {
  2142.                 case XMLAttrTypeCDATA:
  2143.                     retVal = validateCDATA(rpszNormStr);
  2144.                     break;
  2145.                 case XMLAttrTypeEnumerated:
  2146.                     retVal = validateEnumerated(ulElement, ulAttrib, rpszNormStr);
  2147.                     break;
  2148.                 case XMLAttrTypeID:
  2149.                 case XMLAttrTypeIDREF:
  2150.                     retVal = validateIDREF(rpszNormStr);
  2151.                     break;
  2152.                 case XMLAttrTypeNMTOKEN:
  2153.                     retVal = validateNMTOKEN(rpszNormStr);
  2154.                     break;
  2155.                 default:
  2156.                     HX_ASSERT(FALSE);
  2157.                     break;
  2158.             }
  2159.         }
  2160.     }
  2161.     else
  2162.     {
  2163.         retVal = HXR_FAIL;
  2164.     }
  2165.     return retVal;
  2166. }
  2167. HX_RESULT CSmilParser::validateElementName(SMILNode* pNode)
  2168. {
  2169.     HX_RESULT retVal = HXR_OK;
  2170.     if (pNode && !pNode->m_bCloseNode)
  2171.     {
  2172.         // Is the element name legal?
  2173.         void*              pVoid        = NULL;
  2174.         UINT32             ulElement    = 0;
  2175.         BOOL               bUnknownNS   = FALSE;
  2176.         BOOL               bChildFailed = FALSE;
  2177.         SupportedNamespace eNS          = NamespaceNotImplemented;
  2178.         if (m_pElementMap->Lookup(pNode->m_name, pVoid))
  2179.         {
  2180.             // We found the element in our SMIL 2 namespace
  2181.             //
  2182.             // Get the element index
  2183.             ulElement = (UINT32) pVoid;
  2184.         }
  2185.         else
  2186.         {
  2187.             // We didn't find the element in our SMIL 2 namespace
  2188.             //
  2189.             // This element name didn't look up in the legal list, so
  2190.             // we should first check if it is a namespaced element
  2191.             const char*     pszElem = NULL;
  2192.             CNamespaceInfo* pNSInfo = getNamespaceInfo(pNode->m_name, pszElem);
  2193.             if (pNSInfo)
  2194.             {
  2195.                 // Yes, this is a namespaced element, so set
  2196.                 // the flag so we can remember this later
  2197.                 pNode->m_bNamespacedElement = TRUE;
  2198.                 // Is this a recognized RN namespace?
  2199.                 if (pNSInfo->m_eNamespace != NamespaceNotImplemented)
  2200.                 {
  2201.                     // Save the namespace for later
  2202.                     eNS = pNSInfo->m_eNamespace;
  2203.                     // Now that we know we are in a namespace that
  2204.                     // we have implemented, then let's look up
  2205.                     // the element name in our map
  2206.                     if (m_pExtElementMap->Lookup(pszElem, pVoid))
  2207.                     {
  2208.                         // Get the element index
  2209.                         ulElement = (UINT32) pVoid;
  2210.                     }
  2211.                     else
  2212.                     {
  2213.                         // This element claims to be in the above
  2214.                         // extension namespaces, but is not an extension
  2215.                         // element we recognize
  2216.                         retVal = HXR_FAIL;
  2217.                     }
  2218.                 }
  2219.                 else
  2220.                 {
  2221.                     // Properly namespaced, but not a namespace
  2222.                     // we recognize. So ignore it.
  2223.                     bUnknownNS = TRUE;
  2224.                 }
  2225.             }
  2226.         }
  2227.         // At this point if we have retVal == HXR_FAIL, then
  2228.         // we have an illegal element name. If we have retVal == HXR_OK
  2229.         // and bUnknownNS == TRUE, then this element is properly namespaced
  2230.         // with an namespace we don't recognize.
  2231.         if (SUCCEEDED(retVal) && !bUnknownNS)
  2232.         {
  2233.             // Do a sanity check on the index
  2234.             if (ulElement < NumSMIL2Elements)
  2235.             {
  2236.                 // Assign the element enum
  2237.                 pNode->m_eElement = g_ElementEnumMap[ulElement];
  2238.                 // If we are an rn:param, then we treat this
  2239.                 // as a normal <param>
  2240.                 if (pNode->m_eElement == SMIL2ElemRNParam)
  2241.                 {
  2242.                     pNode->m_tag = SMILParam;
  2243.                 }
  2244.                 // If we are an extension element, then check
  2245.                 // our namespace
  2246.                 if (pNode->m_bNamespacedElement)
  2247.                 {
  2248.                     retVal = checkExtensionElementNamespace(pNode->m_eElement,
  2249.                                                             eNS);
  2250.                 }
  2251.                 // Recursively check our children
  2252.                 if (SUCCEEDED(retVal))
  2253.                 {
  2254.                     if (pNode->m_pNodeList)
  2255.                     {
  2256.                         LISTPOSITION pos = pNode->m_pNodeList->GetHeadPosition();
  2257.                         while (pos && SUCCEEDED(retVal))
  2258.                         {
  2259.                             SMILNode* pChildNode = (SMILNode*) pNode->m_pNodeList->GetNext(pos);
  2260.                             retVal = validateElementName(pChildNode);
  2261.                             if (FAILED(retVal))
  2262.                             {
  2263.                                 bChildFailed = TRUE;
  2264.                             }
  2265.                         }
  2266.                     }
  2267.                 }
  2268.             }
  2269.             else
  2270.             {
  2271.                 retVal = HXR_FAIL;
  2272.             }
  2273.         }
  2274.         // If we failed somewhere along the way, then throw an error.
  2275.         // However, since error returns bubble up, then we don't
  2276.         // need to throw an error on this element if its child failed.
  2277.         if (FAILED(retVal) && !bChildFailed)
  2278.         {
  2279.             CSmilSMILSyntaxErrorHandler errHandler(m_pContext);
  2280.             errHandler.ReportError(SMILErrorUnrecognizedTag,
  2281.                                    pNode->m_name,
  2282.                                    pNode->m_ulTagStartLine);
  2283.         }
  2284.     }
  2285.     return retVal;
  2286. }
  2287. HX_RESULT CSmilParser::setupValidationNamespaces(SMILNode* pNode)
  2288. {
  2289.     HX_RESULT retVal = HXR_OK;
  2290.     if (pNode &&
  2291.         pNode->m_tag == SMILSmil &&
  2292.         pNode->m_pValues)
  2293.     {
  2294.         // Clear out any existing namespaces
  2295.         deleteValidationNamespaceList();
  2296.         // Loop through the attributes, looking for xmlns:foo attributes
  2297.         const char* pszName = NULL;
  2298.         IHXBuffer* pValue  = NULL;
  2299.         HX_RESULT   rv      = pNode->m_pValues->GetFirstPropertyCString(pszName, pValue);
  2300.         while (SUCCEEDED(rv) && SUCCEEDED(retVal))
  2301.         {
  2302.             // Is this an xmlns:foo attribute?
  2303.             if (strncmp(pszName, "xmlns:", 6) == 0)
  2304.             {
  2305.                 // This is a namespace declaration, so we need to
  2306.                 // record the namespace abbreviation
  2307.                 //
  2308.                 // If we don't already have a list of namespace
  2309.                 // declarations, then create one
  2310.                 if (!m_pValNSList)
  2311.                 {
  2312.                     m_pValNSList = new CHXSimpleList();
  2313.                 }
  2314.                 if (m_pValNSList)
  2315.                 {
  2316.                     // Create a CNamespaceInfo object
  2317.                     CNamespaceInfo* pInfo = new CNamespaceInfo();
  2318.                     if (pInfo)
  2319.                     {
  2320.                         // Make a copy of the namespace abbreviation
  2321.                         const char* pszNS  = pszName + 6;
  2322.                         UINT32      ulLen  = (UINT32) strlen(pszNS);
  2323.                         pInfo->m_pszPrefix = new char [ulLen + 2];
  2324.                         if (pInfo->m_pszPrefix)
  2325.                         {
  2326.                             // Copy the abbreviation
  2327.                             strcpy(pInfo->m_pszPrefix, pszNS); /* Flawfinder: ignore */
  2328.                             // Concatenate the ":" character to the prefix
  2329.                             strcat(pInfo->m_pszPrefix, ":"); /* Flawfinder: ignore */
  2330.                             // Now copy the URL
  2331.                             const char* pszURL = (const char*) pValue->GetBuffer();
  2332.                             pInfo->m_pszURL    = new char [strlen(pszURL) + 1];
  2333.                             if (pInfo->m_pszURL)
  2334.                             {
  2335.                                 // Copy into the member
  2336.                                 strcpy(pInfo->m_pszURL, pszURL); /* Flawfinder: ignore */
  2337.                                 // Now map this string to a supported namespace
  2338.                                 if (m_pNamespaceMap)
  2339.                                 {
  2340.                                     void* pVoid = NULL;
  2341.                                     if (m_pNamespaceMap->Lookup(pszURL, pVoid))
  2342.                                     {
  2343.                                         pInfo->m_eNamespace   = (SupportedNamespace) (UINT32) pVoid;
  2344.                                         pInfo->m_bImplemented = TRUE;
  2345.                                     }
  2346.                                 }
  2347.                                 // Append the namespace info object to the list
  2348.                                 m_pValNSList->AddTail((void*) pInfo);
  2349.                             }
  2350.                         }
  2351.                     }
  2352.                 }
  2353.             }
  2354.             // Get the next attribute
  2355.             HX_RELEASE(pValue);
  2356.             rv = pNode->m_pValues->GetNextPropertyCString(pszName, pValue);
  2357.         }
  2358.     }
  2359.     return retVal;
  2360. }
  2361. HX_RESULT CSmilParser::validateAgainstDTD()
  2362. {
  2363.     HX_RESULT retVal = HXR_FAIL;
  2364.     if (m_pElementMap && m_pAttributeMap &&
  2365.         m_pExtElementMap && m_pExtAttributeMap &&
  2366.         m_pLegalAttrMap && m_pContentModelMap)
  2367.     {
  2368.         SMILNode* pSmilNode = findFirstNode(SMILSmil);
  2369.         if (pSmilNode)
  2370.         {
  2371.             retVal = setupValidationNamespaces(pSmilNode);
  2372.             if (SUCCEEDED(retVal))
  2373.             {
  2374.                 retVal = validateElementName(pSmilNode);
  2375.                 if (SUCCEEDED(retVal))
  2376.                 {
  2377.                     retVal = validateNode(pSmilNode);
  2378.                 }
  2379.             }
  2380.         }
  2381.     }
  2382.     return retVal;
  2383. }
  2384. HX_RESULT CSmilParser::checkExtensionElementNamespace(SMIL2Element eElem,
  2385.                                                       SupportedNamespace eNS)
  2386. {
  2387.     HX_RESULT retVal = HXR_FAIL;
  2388.     switch (eElem)
  2389.     {
  2390.         case SMIL2ElemRNParam:
  2391.             {
  2392.                 if (eNS == NamespaceAllSMIL2Extensions ||
  2393.                     eNS == NamespaceParam)
  2394.                 {
  2395.                     retVal = HXR_OK;
  2396.                 }
  2397.             }
  2398.             break;
  2399.         case SMIL2ElemRNRendererList:
  2400.         case SMIL2ElemRNRenderer:
  2401.             {
  2402.                 if (eNS == NamespaceAllSMIL2Extensions ||
  2403.                     eNS == NamespaceRendererList)
  2404.                 {
  2405.                     retVal = HXR_OK;
  2406.                 }
  2407.             }
  2408.             break;
  2409.     }
  2410.     return retVal;
  2411. }
  2412. HX_RESULT CSmilParser::checkExtensionAttributeNamespace(SMIL2Attribute eAttr,
  2413.                                                         SupportedNamespace eNS)
  2414. {
  2415.     HX_RESULT retVal = HXR_FAIL;
  2416.     switch (eAttr)
  2417.     {
  2418.         case SMIL2AttrRNBackgroundOpacity:
  2419.         case SMIL2AttrRNChromaKey:
  2420.         case SMIL2AttrRNChromaKeyOpacity:
  2421.         case SMIL2AttrRNChromaKeyTolerance:
  2422.         case SMIL2AttrRNMediaOpacity:
  2423.         case SMIL2AttrRNOpacity:
  2424.             {
  2425.                 if (eNS == NamespaceAllSMIL2Extensions ||
  2426.                     eNS == NamespaceAlphaControl)
  2427.                 {
  2428.                     retVal = HXR_OK;
  2429.                 }
  2430.             }
  2431.             break;
  2432.         case SMIL2AttrRNDelivery:
  2433.             {
  2434.                 if (eNS == NamespaceAllSMIL2Extensions ||
  2435.                     eNS == NamespaceParam)
  2436.                 {
  2437.                     retVal = HXR_OK;
  2438.                 }
  2439.             }
  2440.             break;
  2441.         case SMIL2AttrRNHandledBy:
  2442.             {
  2443.                 if (eNS == NamespaceAllSMIL2Extensions ||
  2444.                     eNS == NamespaceHandledBy)
  2445.                 {
  2446.                     retVal = HXR_OK;
  2447.                 }
  2448.             }
  2449.             break;
  2450.         case SMIL2AttrRNSendTo:
  2451.         case SMIL2AttrRNContextWindow:
  2452.             {
  2453.                 if (eNS == NamespaceAllSMIL2Extensions ||
  2454.                     eNS == NamespaceSendTo)
  2455.                 {
  2456.                     retVal = HXR_OK;
  2457.                 }
  2458.             }
  2459.             break;
  2460.         case SMIL2AttrRNSystemComponent:
  2461.             {
  2462.                 if (eNS == NamespaceSystemComponent)
  2463.                 {
  2464.                     retVal = HXR_OK;
  2465.                 }
  2466.             }
  2467.             break;
  2468.         case SMIL2AttrRNResizeBehavior:
  2469.             {
  2470.                 if (eNS == NamespaceAllSMIL2Extensions ||
  2471.                     eNS == NamespaceSizeControl)
  2472.                 {
  2473.                     retVal = HXR_OK;
  2474.                 }
  2475.             }
  2476.             break;
  2477.         case XMLEventsAttrHandler:
  2478.             {
  2479.                 if (eNS == NamespaceXMLEvents)
  2480.                 {
  2481.                     retVal = HXR_OK;
  2482.                 }
  2483.             }
  2484.             break;
  2485.         case SMIL2AttrRNAccessErrorBehavior:
  2486.             {
  2487.                 if (eNS == NamespaceAllSMIL2Extensions ||
  2488.                     eNS == NamespaceAccessErrorBehavior)
  2489.                 {
  2490.                     retVal = HXR_OK;
  2491.                 }
  2492.             }
  2493.             break;
  2494.     }
  2495.     return retVal;
  2496. }
  2497. #endif /* #if defined(HELIX_FEATURE_SMIL2_VALIDATION) */
  2498. CNamespaceInfo* CSmilParser::getNamespaceInfo(const char*      pszStr,
  2499.                                               REF(const char*) rpszAttr)
  2500. {
  2501.     CNamespaceInfo* pRet = NULL;
  2502.     if (pszStr && m_pValNSList)
  2503.     {
  2504.         LISTPOSITION pos = m_pValNSList->GetHeadPosition();
  2505.         while (pos)
  2506.         {
  2507.             CNamespaceInfo* pInfo = (CNamespaceInfo*) m_pValNSList->GetNext(pos);
  2508.             if (pInfo)
  2509.             {
  2510.                 UINT32 ulPrefixLen = (UINT32) strlen(pInfo->m_pszPrefix);
  2511.                 if (!strncmp(pszStr, pInfo->m_pszPrefix, ulPrefixLen))
  2512.                 {
  2513.                     pRet     = pInfo;
  2514.                     rpszAttr = pszStr + ulPrefixLen;
  2515.                     break;
  2516.                 }
  2517.             }
  2518.         }
  2519.     }
  2520.     return pRet;
  2521. }
  2522. HX_RESULT
  2523. CSmilParser::createElements()
  2524. {
  2525.     HX_RESULT rc = HXR_OK;
  2526.     SMILNode* pSmilNode = findFirstNode(SMILSmil);
  2527.     if(!pSmilNode)  // dangerwillrobinson!!!
  2528.     {
  2529. rc = HXR_FAIL;
  2530. CSmilSMILSyntaxErrorHandler errHandler(m_pContext);
  2531. errHandler.ReportError(SMILErrorNotSMIL, NULL, 0);
  2532. return rc;
  2533.     }
  2534.     rc = addToNamespaceScope(pSmilNode);
  2535.     if (SUCCEEDED(rc))
  2536.     {
  2537. // XXXJEFFA Hardcode "cv" namespace prefix for Redstone alpha 7
  2538.         // XXXMEH - remove for SMIL 2
  2539. // rc = addGlobalNamespace(SYSTEM_COMPONENT_NAMESPACE, "cv");
  2540. // /Now, fix Structure Interop #2.1 (unrecognized smil-tag namespace)
  2541. // and #2.3 (SMIL 2.0-module namespaces in the smil tag):
  2542. BOOL bFailedTest = testAttributeFailed(pSmilNode);
  2543. if (bFailedTest)
  2544. {
  2545.     // / systemRequired was specified on the whole document, via the
  2546.     // <smil ...> tag, and the associated namespace was not specified
  2547.     // or is not a supported one.  Helps fix SMIL 2.0 Interop
  2548.     // Structure Module tests #2.1-#2.3.  Is NOT an error condition:
  2549.     rc = HXR_OK;
  2550.     return rc;
  2551. }
  2552.     }
  2553.     if (FAILED(rc))
  2554.     {
  2555. return rc;
  2556.     }
  2557.     SMILNode* pHeadNode = findFirstNode(SMILHead);
  2558.     if(pHeadNode)
  2559.     {
  2560. rc = markTestAttributeNodes(pHeadNode->m_pNodeList);
  2561. if (SUCCEEDED(rc))
  2562. {
  2563.     rc = addToNamespaceScope(pHeadNode);
  2564. }
  2565. if(SUCCEEDED(rc))
  2566. {
  2567.     rc = createHeadElements(pHeadNode->m_pNodeList);
  2568. }
  2569. if (SUCCEEDED(rc))
  2570. {
  2571.       rc = removeFromNamespaceScope(pHeadNode);
  2572. }
  2573.     }
  2574.     if(rc == HXR_OK)
  2575.     {
  2576. SMILNode* pBodyNode = findFirstNode(SMILBody);
  2577. if(pBodyNode &&
  2578.     pBodyNode->m_pNodeList)
  2579. {
  2580.             CSmilBodyElement* pBodyEl = makeBodyElement(pBodyNode);
  2581.             if (pBodyEl)
  2582.             {
  2583.                 pBodyNode->m_pElement = pBodyEl;
  2584.             }
  2585.     rc = addToNamespaceScope(pBodyNode);
  2586.     if (SUCCEEDED(rc))
  2587.     {
  2588. SMILNode* pTopNode = getTimelineDescendent(pBodyNode, NULL);
  2589. // /XXXEH- TODO: need to look at body element's m_pValues and
  2590. // see if it has any timing attributes explicitly set; if
  2591. // so, set the following to TRUE, else to FALSE:
  2592. BOOL bBodyTagHasTimingAttributes = TRUE;
  2593. m_bAllowPlaylistBehavior = TRUE;
  2594. #if defined(ALLOW_PLAYLIST_STYLE_SEQ)
  2595. #if defined(DONT_ALLOW_PLAYLIST_STYLE_SEQ_IF_EXPLICIT_OUTER_TIMECONTAINER)
  2596. // /Here's the deal: if pTopNode is an ancestor of *all*
  2597. // media elements, then we don't play as a playlist; the
  2598. // *only* case where we play as a playlist is if there are
  2599. // multiple timed children of the body element, where a
  2600. // child of the body, for these purposes, is defined as a
  2601. // timeline element that has no timeline ancestors other
  2602. // than the body element:
  2603. // /First, look for sibling of pTopNode:
  2604. if (pTopNode)
  2605. {
  2606.     SMILNode* pSiblingTopNode =
  2607.     getTimelineDescendent(pBodyNode, pTopNode);
  2608.     if (pSiblingTopNode  &&
  2609.     SMILUnknown != pSiblingTopNode->m_tag)
  2610.     {
  2611. SMILNode* pSyncAncestorTopNode =
  2612. getSyncAncestor(pTopNode);
  2613. SMILNode* pSyncAncestorSiblingTopNode =
  2614. getSyncAncestor(pSiblingTopNode);
  2615. // /If the sync bases are different, or if each is
  2616. // the body element, then do playlist, else don't:
  2617. if ((pSyncAncestorTopNode !=
  2618. pSyncAncestorSiblingTopNode)  ||
  2619. (!pSyncAncestorTopNode  &&
  2620. !pSyncAncestorSiblingTopNode)  ||
  2621. (SMILBody == pSyncAncestorTopNode->m_tag  &&
  2622. SMILBody ==
  2623. pSyncAncestorSiblingTopNode->m_tag) )
  2624. {
  2625.     m_bAllowPlaylistBehavior = TRUE;
  2626. }
  2627. else
  2628. {
  2629.     m_bAllowPlaylistBehavior = FALSE;
  2630. }
  2631.     }
  2632.     else
  2633.     {
  2634. m_bAllowPlaylistBehavior = FALSE;
  2635.     }
  2636. }
  2637. #endif /* DONT_ALLOW_PLAYLIST_STYLE_SEQ_IF_EXPLICIT_OUTER_TIMECONTAINER. */
  2638. // adjust context based on itself position within its parent
  2639. // in nested meta
  2640. if (m_elementWithinTag == WithinPar ||
  2641.     m_elementWithinTag == WithinSeqInPar)
  2642. {
  2643.     m_bAllowPlaylistBehavior = FALSE;
  2644. }
  2645. if(pTopNode  &&
  2646. (pTopNode->m_tag != SMILSeq  ||
  2647. // /If body tag has timing attributes, we need to
  2648. // create an outer tag no matter what's already there
  2649. // so this outer tag can take the body's timing:
  2650. bBodyTagHasTimingAttributes) )
  2651. {
  2652.     createSeqWrapper(pBodyNode->m_pNodeList,
  2653.     !m_bAllowPlaylistBehavior);
  2654. }
  2655. //[SMIL 1.0 compliance] fix for PR 23050:
  2656. // if first descendent of body is a <switch> and its first child
  2657. // is a <seq> that did not get chosen in the switch, then we
  2658. // would be tricked into thinking we already had a valid outer
  2659. // seq, but we wouldn't.  Let's put one there in this case,
  2660. // noting that we don't yet know if that seq is valid or not.
  2661. // However, it doesn't matter either way:
  2662. if(pTopNode  &&  SMILSeq == pTopNode->m_tag  &&
  2663. pTopNode->m_pParent  &&
  2664. pTopNode->m_pParent->m_tag == SMILSwitch)
  2665. {
  2666.     createSeqWrapper(pBodyNode->m_pNodeList, FALSE);
  2667. }
  2668. #else
  2669. if (SMILSeq == pTop->m_tag)
  2670. {
  2671.     m_bAllowPlaylistBehavior = TRUE;
  2672. }
  2673. else
  2674. {
  2675.     m_bAllowPlaylistBehavior = FALSE;
  2676. }
  2677. // adjust context based on itself position within its parent
  2678. // in nested meta
  2679. if (m_elementWithinTag == WithinPar ||
  2680.     m_elementWithinTag == WithinSeqInPar)
  2681. {
  2682.     m_bAllowPlaylistBehavior = FALSE;
  2683. }
  2684. // /We no longer care if it's a seq or not; we have to
  2685. // respect any timing attributes that have been put on
  2686. // the body element, and we also have to stop doing the
  2687. // playlist-style seq handling:
  2688. if(pTopNode)
  2689. {
  2690.     createSeqWrapper(pBodyNode->m_pNodeList,
  2691.      m_bAllowPlaylistBehavior);
  2692. }
  2693. #endif
  2694. if(HXR_OK != markTestAttributeNodes(pBodyNode->m_pNodeList) ||
  2695.    HXR_OK != expandRepeatElements(pBodyNode->m_pNodeList) ||
  2696.    HXR_OK != createBodyElements(pBodyNode->m_pNodeList) ||
  2697.    HXR_OK != resolveSyncBaseElements() ||
  2698.    HXR_OK != assignGroupIndexes(pBodyNode->m_pNodeList) ||
  2699.    HXR_OK != constructTimelineElements(pBodyNode->m_pNodeList) ||
  2700.    HXR_OK != setInitialDelays(pBodyNode->m_pNodeList) ||
  2701.    //HXR_OK != updateEventElements(pBodyNode->m_pNodeList) ||
  2702.    HXR_OK != handleExclDescendants()  ||
  2703. #ifdef _DEBUG
  2704.    HXR_OK != printBodyElements(pBodyNode->m_pNodeList) ||
  2705. #endif
  2706.    HXR_OK != insertGroups())
  2707. {
  2708.     rc = HXR_FAIL;
  2709. }
  2710.     }
  2711.     if (SUCCEEDED(rc))
  2712.     {
  2713. rc = removeFromNamespaceScope(pBodyNode);
  2714.     }
  2715. }
  2716. if(rc == HXR_OK && !m_bContainsSource)
  2717. {
  2718.     rc = HXR_OK;
  2719.     //[SMIL 1.0 compliance] fixes PR 27672:
  2720.     // don't call SMILErrorNoBodyElements error as it is not one
  2721.     // per the SMIL 1.0 spec.
  2722. }
  2723.     }
  2724.     // Check for any custom events
  2725.     if (SUCCEEDED(rc))
  2726.     {
  2727.         checkForExternalEvents();
  2728.         // Check to see if any of the sources
  2729.         // had the "handler" attribute defined,
  2730.         // and if so, then set corresponding info in
  2731.         // the the source which is the handler
  2732.         checkForEventHandlers();
  2733.     }
  2734.     return rc;
  2735. }
  2736. HX_RESULT
  2737. CSmilParser::createSeqWrapper(SMILNodeList* pNodeList, BOOL bMakeInnerPar)
  2738. {
  2739.     // /Create a default <seq></seq> wrapper within the <body></body>
  2740.     // and move all children as well as attributes of the body to the seq.
  2741.     // Then, make an internal par within that seq to get rid of the
  2742.     // "playlist" behavior that we've all come to love to hate when the
  2743.     // outer time container is a seq:
  2744.     HX_RESULT rc = HXR_OK;
  2745.     SMILNode* pSeqNode = new SMILNode;
  2746.     SMILNode* pParNode = NULL;
  2747.     SMILNode* pEndParNode = NULL;
  2748.     SMILNode* pWrapperNodeThatGetsTheChildren = pSeqNode;
  2749.     int count = pNodeList->GetCount();
  2750.     SMILNode* pEndBodyNode = NULL;
  2751.     SMILNode* pEndSeqNode = NULL;
  2752.     if (!pSeqNode)
  2753.     {
  2754. rc = HXR_FAIL;
  2755. goto cleanup;
  2756.     }
  2757.     pSeqNode->m_name = "seq";
  2758.     pSeqNode->m_pParent = pNodeList->m_pParentNode;
  2759.     pSeqNode->m_id = assignID("seq");
  2760.     pSeqNode->m_tag = SMILSeq;
  2761.     pSeqNode->m_pNodeList = new SMILNodeList;
  2762.     // /XXXEH- TODO: fix SMIL 2.0 Interop Structure Module #1.2 which needs
  2763.     // the following var to be set to FALSE if and only if there really is
  2764.     // explicit dur or end on the body element (and we don't want to do
  2765.     // playlist behavior in that case either):
  2766.     pSeqNode->m_bIsOuterWrapperTimeContainer = TRUE;
  2767.     HX_ASSERT(pSeqNode->m_pParent);
  2768.     if (pSeqNode->m_pParent  &&  SMILBody == pSeqNode->m_pParent->m_tag)
  2769.     {
  2770. // /Copy all of body element's timing to this seq element:
  2771. pSeqNode->m_pParent->m_pValues->AddRef();
  2772. pSeqNode->m_pValues = pSeqNode->m_pParent->m_pValues;
  2773. // /Give seq wrapper the id of the body since it is now the
  2774. // acting body container:
  2775. HX_ASSERT(pSeqNode->m_pParent->m_id.GetLength() > 0);
  2776. if (pSeqNode->m_pParent->m_id.GetLength() > 0)
  2777. {
  2778.     pSeqNode->m_id = pSeqNode->m_pParent->m_id;
  2779.     (*m_pIDMap)[(const char*)pSeqNode->m_id] =
  2780.     pSeqNode;
  2781.     pSeqNode->m_pParent->m_id = assignID("body");
  2782.     (*m_pIDMap)[(const char*)pSeqNode->m_pParent->m_id] =
  2783.     pSeqNode->m_pParent;
  2784. }
  2785.     }
  2786.     if (bMakeInnerPar)
  2787.     {
  2788. pParNode = new SMILNode;
  2789. if (!pParNode)
  2790. {
  2791.     HX_DELETE(pSeqNode);
  2792.     rc = HXR_FAIL;
  2793.     goto cleanup;
  2794. }
  2795. pParNode->m_name = "par";
  2796. pParNode->m_pParent = pSeqNode;
  2797. pParNode->m_id = assignID("par");
  2798. pParNode->m_tag = SMILPar;
  2799. pParNode->m_pNodeList = new SMILNodeList;
  2800. pParNode->m_bIsOuterWrapperTimeContainer = TRUE;
  2801. if (!pParNode->m_pNodeList)
  2802. {
  2803.     HX_DELETE(pSeqNode);
  2804.     HX_DELETE(pParNode);
  2805.     rc = HXR_FAIL;
  2806.     goto cleanup;
  2807. }
  2808. // /This par will be the one that adopts the children of the body:
  2809. pWrapperNodeThatGetsTheChildren = pParNode;
  2810. // /The par is a child of the seq wrapper:
  2811. pSeqNode->m_pNodeList->AddTail(pParNode);
  2812. // /Create a </par> node and add it to the new par's list:
  2813. pEndParNode = new SMILNode;
  2814. pEndParNode->m_name = "par";
  2815. pEndParNode->m_pParent = pParNode;
  2816. pEndParNode->m_id = "CLOSE-par";
  2817. pEndParNode->m_tag = SMILEndSeq;
  2818.     }
  2819.     // move children from bodyNode list to seq list
  2820.     while( count > 0) // don't reparent </body> tag
  2821.     {
  2822. SMILNode* pChildNode = (SMILNode*)pNodeList->RemoveHead();
  2823. // /Don't reparent the </body> tag...
  2824. if ( pChildNode->m_id != "CLOSE-body" )
  2825. {
  2826.     pChildNode->m_pParent = pWrapperNodeThatGetsTheChildren;
  2827.     pWrapperNodeThatGetsTheChildren->m_pNodeList->AddTail(pChildNode);
  2828. }
  2829. else
  2830. {
  2831.     pEndBodyNode = pChildNode;
  2832. }
  2833. --count;
  2834.     }
  2835.     // set the persistent duration on this wrapper node to
  2836.     // restrain the whole SMIL presentation
  2837.     //
  2838.     // XXX HP need to remove setting m_ulPersistentComponentDuration
  2839.     //       explicitly to the group object in ::addGroup() after
  2840.     //       Erik fix body duration
  2841.     if (m_ulPersistentComponentDuration)
  2842.     {
  2843. if (!pWrapperNodeThatGetsTheChildren->m_pValues)
  2844. {
  2845.     pWrapperNodeThatGetsTheChildren->m_pValues = new CHXHeader();
  2846.     pWrapperNodeThatGetsTheChildren->m_pValues->AddRef();
  2847. }
  2848. char szValue[MAX_DISPLAY_NAME] = {0}; /* Flawfinder: ignore */
  2849. IHXBuffer* pBuffer = new CHXBuffer();
  2850. pBuffer->AddRef();
  2851. sprintf(szValue, "%lums", m_ulPersistentComponentDuration); /* Flawfinder: ignore */
  2852. pBuffer->Set((const UCHAR*)szValue, strlen(szValue) + 1);
  2853. pWrapperNodeThatGetsTheChildren->m_pValues->SetPropertyCString("dur", pBuffer);
  2854. HX_RELEASE(pBuffer);
  2855.     }
  2856.     if (pParNode)
  2857.     {
  2858. HX_ASSERT(pEndParNode);
  2859. if (pEndParNode)
  2860. {
  2861.     pParNode->m_pNodeList->AddTail(pEndParNode);
  2862. }
  2863.     }
  2864.     pEndSeqNode = new SMILNode;
  2865.     pEndSeqNode->m_name = "seq";
  2866.     pEndSeqNode->m_id = "CLOSE-seq";
  2867.     pEndSeqNode->m_pParent = pSeqNode;
  2868.     pEndSeqNode->m_tag = SMILEndSeq;
  2869.     pSeqNode->m_pNodeList->AddTail(pEndSeqNode);
  2870.     // now add it to the <body> parent...
  2871.     pNodeList->AddHead(pSeqNode);
  2872.     pNodeList->AddTail(pEndBodyNode);
  2873. cleanup:
  2874.     return rc;
  2875. }
  2876. // /This handles creating a node for the case where an anchor (a or area) tag
  2877. // has a target="x" where "x" is the id of an existing region: (PR 52891)
  2878. HX_RESULT
  2879. CSmilParser::createElementForAnchorTarget(CSmilAAnchorElement* pAnchor,
  2880.         SMILNodeList* pNodeList)
  2881. {
  2882.     HX_RESULT rc = HXR_OK;
  2883.     SMILNode* pRefNode = NULL;
  2884.     SMILNode* pTailNode = NULL;
  2885.     IHXValues* pAttribs = NULL;
  2886.     int count = -1;
  2887.     if (!pAnchor  ||  !pAnchor->m_pNode  ||  !(const char*)pAnchor->m_pNode->m_id  ||
  2888.     !pNodeList  ||   !m_pClassFactory  ||  pAnchor->m_href.IsEmpty())
  2889.     {
  2890. HX_ASSERT(pAnchor  &&  pAnchor->m_pNode  &&  (const char*)pAnchor->m_pNode->m_id  &&
  2891. pNodeList  &&  m_pClassFactory  &&  !pAnchor->m_href.IsEmpty());
  2892. rc = HXR_FAIL;
  2893. goto cleanup;
  2894.     }
  2895.     pRefNode = new SMILNode;
  2896.     count = pNodeList->GetCount();
  2897.     if (!pRefNode  ||  count<2) // /2 <= a|area + CLOSE-par + ...
  2898.     {
  2899. HX_ASSERT(pRefNode  &&  count>=2);
  2900. rc = HXR_FAIL;
  2901. goto cleanup;
  2902.     }
  2903.     pRefNode->m_name = "ref";
  2904.     pRefNode->m_pParent = pNodeList->m_pParentNode;
  2905.     pRefNode->m_id = assignID("ref_forLinkTarget");
  2906.     pRefNode->m_tag = SMILRef;
  2907.     // /Now, set the begin and src properties:
  2908.     if (HXR_OK == m_pClassFactory->CreateInstance(IID_IHXValues,
  2909.     (void**)&pAttribs))
  2910.     {
  2911.         pRefNode->m_pValues = pAttribs;
  2912. IHXBuffer* pBufBegin = NULL;
  2913. IHXBuffer* pBufSrc = NULL;
  2914. IHXBuffer* pBufRegion = NULL;
  2915. IHXBuffer* pBufLinkDestnSndLevel = NULL;
  2916. IHXBuffer* pBufLinkSourceSndLevel = NULL;
  2917. if ((HXR_OK == m_pClassFactory->CreateInstance(IID_IHXBuffer,
  2918. (void**)&pBufBegin))  &&
  2919. (HXR_OK == m_pClassFactory->CreateInstance(IID_IHXBuffer,
  2920. (void**)&pBufSrc))  &&
  2921. (HXR_OK == m_pClassFactory->CreateInstance(IID_IHXBuffer,
  2922. (void**)&pBufRegion))  &&
  2923. (HXR_OK == m_pClassFactory->CreateInstance(IID_IHXBuffer,
  2924. (void**)&pBufLinkDestnSndLevel))  &&
  2925. (HXR_OK == m_pClassFactory->CreateInstance(IID_IHXBuffer,
  2926. (void**)&pBufLinkSourceSndLevel)) )
  2927. {
  2928.     CHXString valStr = (const char*)(pAnchor->m_pNode->m_id);
  2929.     valStr += ".activateEvent";
  2930.     valStr += '';
  2931.     const char* pVal = valStr;
  2932.     pBufBegin->Set((const unsigned char*)pVal, strlen(valStr)+1);
  2933.     pRefNode->m_pValues->SetPropertyCString("begin", pBufBegin);
  2934.     pBufSrc->Set((const unsigned char*)((const char*)pAnchor->m_href),
  2935.     pAnchor->m_href.GetLength()+1);
  2936.     pRefNode->m_pValues->SetPropertyCString("src", pBufSrc);
  2937.     pBufRegion->Set((const unsigned char*)((const char*)pAnchor->m_target),
  2938.     pAnchor->m_target.GetLength()+1);
  2939.     pRefNode->m_pValues->SetPropertyCString("region", pBufRegion);
  2940.     // /Helps fix PR 66650: set "soundLevel" here using the anchor's
  2941.     // destinationLevel and then use it if|when this source gets added
  2942.     char* pszTmp = new char[64];
  2943.     if (!pszTmp)
  2944.     {
  2945. rc = HXR_OUTOFMEMORY;
  2946.     }
  2947.     else
  2948.     {
  2949. sprintf(pszTmp, "%lu", pAnchor->m_ulDestinationLevel_pct); /* Flawfinder: ignore */
  2950. pBufLinkDestnSndLevel->Set((const unsigned char*)pszTmp,
  2951. strlen(pszTmp)+1);
  2952. pRefNode->m_pValues->SetPropertyCString(
  2953. TARGET_OF_LINK_DESTINATION_SOUND_LEVEL_STR,
  2954. pBufLinkDestnSndLevel);
  2955. sprintf(pszTmp, "%lu", pAnchor->m_ulSourceLevel_pct); /* Flawfinder: ignore */
  2956. pBufLinkSourceSndLevel->Set((const unsigned char*)pszTmp,
  2957. strlen(pszTmp)+1);
  2958. pRefNode->m_pValues->SetPropertyCString(
  2959. TARGET_OF_LINK_SOURCE_SOUND_LEVEL_STR,
  2960. pBufLinkSourceSndLevel);
  2961. delete [] pszTmp;
  2962. // /This is needed for PR 55120, PR 66650, and PR 55791; a link
  2963. // that has sourcePlaystate="play"|"pause" and messes with audio
  2964. // level of either player will require reflush hint to be set:
  2965. if (pAnchor->m_ulSourceLevel_pct !=
  2966. pAnchor->m_ulDestinationLevel_pct  &&
  2967. (SMILLinkPlaystatePlay == pAnchor->m_sourcePlaystate  ||
  2968. SMILLinkPlaystatePause == pAnchor->m_sourcePlaystate) )
  2969. {
  2970.     m_bAllTracksNeedReflushHint = TRUE;
  2971. }
  2972.     }
  2973.     HX_RELEASE(pBufBegin);
  2974.     HX_RELEASE(pBufSrc);
  2975.     HX_RELEASE(pBufRegion);
  2976. }
  2977.     }
  2978.     // /Now add it to the par ancestor after first removing the "CLOSE-par"
  2979.     // node from the tail (adding it back afterwards):
  2980.     pTailNode = (SMILNode*)pNodeList->RemoveTail();
  2981.     pNodeList->AddTail(pRefNode);
  2982.     (*m_pIDMap)[(const char*)pRefNode->m_id] = pRefNode;
  2983.     if (pTailNode)
  2984.     {
  2985. pNodeList->AddTail(pTailNode);
  2986.     }
  2987.     // /Set this in here since we know this setup was successful:
  2988.     pAnchor->m_bTargetIsARegion = TRUE;
  2989. cleanup:
  2990.     return rc;
  2991. }
  2992. #if 0  /*XXXEH- I wrote this and then didn't need it but it may come in
  2993.  handy later so #if(0) it out: */
  2994. BOOL
  2995. CSmilParser::hasNoSourceChildren(SMILNode* pNode)
  2996. {
  2997.     BOOL bNoSourceChildrenFound = TRUE;
  2998.     if (pNode  &&  pNode->m_pNodeList)
  2999.     {
  3000. int count = pNode->m_pNodeList->GetCount();
  3001. while( count > 0)
  3002. {
  3003.     SMILNode* pChildNode =(SMILNode*)(pNode->m_pNodeList->GetHead());
  3004.     if (!pChildNode)
  3005.     {
  3006. break;
  3007.     }
  3008.     if (isMediaObject(pChildNode))
  3009.     {
  3010. bNoSourceChildrenFound = FALSE;
  3011. break;
  3012.     }
  3013.     // /Recurse on down:
  3014.     else if (!hasNoSourceChildren(pChildNode))
  3015.     {
  3016. bNoSourceChildrenFound = FALSE;
  3017. break;
  3018.     }
  3019.     --count;
  3020. }
  3021.     }
  3022.     return bNoSourceChildrenFound;
  3023. }
  3024. #endif /* 0 */
  3025. #if 0
  3026. //XXXBAB - useful for debugging
  3027. void
  3028. CSmilParser::PrintNode(SMILNode* pNode, FILE* fp, int level)
  3029. {
  3030.     for(int tab=0;tab<level;++tab)
  3031.     {
  3032. fprintf(fp, "t");
  3033.     }
  3034.     fprintf(fp, "%sn", (const char*)pNode->m_id);
  3035.     if(pNode->m_pNodeList)
  3036.     {
  3037. CHXSimpleList::Iterator i = pNode->m_pNodeList->Begin();
  3038. for(; i != pNode->m_pNodeList->End(); ++i)
  3039. {
  3040.     SMILNode* pChildNode = (SMILNode*)(*i);
  3041.     PrintNode(pChildNode, fp, level+1);
  3042. }
  3043.     }
  3044. }
  3045. void
  3046. CSmilParser::PrintNodes()
  3047. {
  3048.     FILE* fp = fopen("nodes.txt", "w");
  3049.     SMILNode* pNode = (SMILNode*)m_pNodeList->GetHead();
  3050.     PrintNode(pNode, fp, 0);
  3051.     fclose(fp);
  3052. }
  3053. #endif
  3054. HX_RESULT
  3055. CSmilParser::printBodyElements(SMILNodeList* pNodeList)
  3056. {
  3057.     // debugging code...
  3058.     HX_RESULT rc = HXR_OK;
  3059. //#define FOR_DEBUGGING_ONLY
  3060. #if defined(_DEBUG)  &&  defined(FOR_DEBUGGING_ONLY)
  3061.     static int level = 0;
  3062.     if(!pNodeList)
  3063.     {
  3064. return rc;
  3065.     }
  3066.     CHXSimpleList::Iterator i;
  3067.     for(i=pNodeList->Begin();i!=pNodeList->End();++i)
  3068.     {
  3069. if(HXR_OK != rc)
  3070. {
  3071.     return rc;
  3072. }
  3073. SMILNode* pNode = (SMILNode*)(*i);
  3074. FILE* fp=fopen("c:\temp\smil.txt", "a+");
  3075. if (!fp)
  3076. {
  3077.     break;
  3078. }
  3079. for(int i=0;i<level;++i)
  3080. {
  3081.     fprintf(fp, "t");
  3082. }
  3083. UINT32 ulDelay = (UINT32)-1;
  3084. UINT32 ulDuration = (UINT32)-1;
  3085. if(pNode->m_pElement &&
  3086.     pNode->m_pElement->m_pTimelineElement)
  3087. {
  3088.     ulDelay = pNode->m_pElement->m_pTimelineElement->getDelay();
  3089.     ulDuration = pNode->m_pElement->m_pTimelineElement->getDuration();
  3090. }
  3091. fprintf(fp, "%s tag=%d group=%d repeatid=%s delay=%d duration=%d deleted=%dn", (const char*)pNode->m_id,
  3092.     pNode->m_tag, pNode->m_nGroup, (const char*)pNode->m_repeatid, ulDelay, ulDuration, pNode->m_bDelete);
  3093. fclose(fp);
  3094. if(pNode->m_pNodeList)
  3095. {
  3096.     ++level;
  3097.     rc = printBodyElements(pNode->m_pNodeList);
  3098.     --level;
  3099. }
  3100.     }
  3101. #endif
  3102.     return rc;
  3103. }
  3104. HX_RESULT
  3105. CSmilParser::insertGroups()
  3106. {
  3107.     HX_RESULT rc = HXR_OK;
  3108.     if(!m_pAddGroupMap)
  3109.     {
  3110. rc = HXR_UNEXPECTED;
  3111.     }
  3112.     else
  3113.     {
  3114. UINT32 ulGroupNo = 0;
  3115. CSmilAddGroup* pAddGroup = 0;
  3116. BOOL bGroupInserted = FALSE;
  3117. while(m_pAddGroupMap->Lookup(ulGroupNo++, (void*&)pAddGroup))
  3118. {
  3119.     bGroupInserted = TRUE;
  3120.     pAddGroup->m_ulDelay = 0;
  3121.     pAddGroup->m_ulTimestamp = INITIAL_STREAM0_TIMESTAMP;
  3122.     insertElementByTimestamp(pAddGroup);
  3123. }
  3124.     }
  3125.     return rc;
  3126. }
  3127. BOOL
  3128. CSmilParser::inLanguagePreference(const char* pLang)
  3129. {
  3130.     // return FALSE if language preference is not in m_pLanguagePreferenceList
  3131.     BOOL rc = FALSE;
  3132.     // pLang can be comma separated lists,
  3133.     // with '*' accepting all languages
  3134.     // copy the string so strtok doesn't modify something bad...
  3135.     char* pLangCopy = new_string(pLang);
  3136.     char* pLangFrag = strtok(pLangCopy, ",");
  3137.     while(pLangFrag)
  3138.     {
  3139. // /Fixes the SMIL-file part of PR 58151: sometimes this list will
  3140. // have tokens that are padded w/whitespaces or are separated by ", "
  3141. // instead of just ",", so first remove all whitespace chars after
  3142. // the ',' (or at the start of the first token) and, if we run
  3143. // into a whitespace-only string, go past the next comma:
  3144. while (isspace(*pLangFrag)  ||  ',' == *pLangFrag)
  3145. {
  3146.     *pLangFrag++;
  3147. }
  3148. if ('' == *pLangFrag)
  3149. {
  3150.     break; // /Whitespace-only or emtpy string is not valid.
  3151. }
  3152. if(*pLangFrag == '*') // wildcard
  3153. {
  3154.     rc = TRUE;
  3155.     break;
  3156. }
  3157. // copy the primary tag part of the language (up to '-')
  3158. char* pPrimaryTag = new char[strlen(pLang)+1];
  3159. char* pTagPtr = pPrimaryTag;
  3160. char* pFragPtr = pLangFrag;
  3161. while(*pFragPtr && *pFragPtr != '-')
  3162. {
  3163.     *pTagPtr++ = *pFragPtr++;
  3164. }
  3165. *pTagPtr = '';
  3166. CHXSimpleList::Iterator i = m_pLanguagePreferenceList->Begin();
  3167. for(; i != m_pLanguagePreferenceList->End(); ++i)
  3168. {
  3169.     char* pPrefLang = (char*)(*i);
  3170.     if(*pPrefLang == '*'  &&  // wildcard
  3171.     // /Adding this check for "*"-only string "fixes" TLC's
  3172.     // PR 64646 that they don't want to fix for fear it will
  3173.     // break other things; only allow "*[x]" where [x] is one
  3174.     // or more characters since TLC sends (has since 1998) a
  3175.     // solo "*" at the end of the language list (for purposes
  3176.     // other than SMIL).  Without this fix, every language
  3177.     // (like systemLanguage="holwerMonkey") evaluates to TRUE:
  3178.     *(pPrefLang+1) != '')
  3179.     {
  3180. rc = TRUE;
  3181.     }
  3182.     else if(strcmp(pPrefLang, pLangFrag) == 0)
  3183.     {
  3184. rc = TRUE;
  3185.     }
  3186.     else if(strncmp(pPrefLang, pPrimaryTag, strlen(pPrimaryTag)) == 0)
  3187.     {
  3188. rc = TRUE;
  3189.     }
  3190.     if(rc)
  3191.     {
  3192. break;
  3193.     }
  3194. }
  3195. delete[] pPrimaryTag;
  3196. if(rc)
  3197. {
  3198.     break;
  3199. }
  3200. pLangFrag = strtok(NULL, ",");
  3201.     }
  3202.     delete[] pLangCopy;
  3203.     return rc;
  3204. }
  3205. BOOL
  3206. CSmilParser::systemComponentFailed(IHXBuffer* pRequiredValue)
  3207. {
  3208.     BOOL bFailed = TRUE;
  3209.     if (m_pContext)
  3210.     {
  3211.         IHXUpgradeCollection* pUpgradeCollection = NULL;
  3212.         m_pContext->QueryInterface(IID_IHXUpgradeCollection,
  3213.                                    (void**) &pUpgradeCollection);
  3214.         if (pUpgradeCollection)
  3215.         {
  3216.     UINT32 ulIndexOfAddedValue =
  3217.     pUpgradeCollection->Add(eUT_Required, pRequiredValue, 0, 0);
  3218.             if (!m_pISystemRequired)
  3219.             {
  3220.                 m_pContext->QueryInterface(IID_IHXSystemRequired,
  3221.                                            (void**) &m_pISystemRequired);
  3222.             }
  3223.             if (m_pISystemRequired)
  3224.             {
  3225.                 bFailed = FAILED(m_pISystemRequired->HasFeatures(pUpgradeCollection));
  3226.             }
  3227.     if (bFailed)
  3228.     {
  3229. // /Removing failed component fixes PR 95617. The
  3230. // (persistent m_pContext's) upgradeCollection will fail the
  3231. // next time, too, even if the next value should succeed, if
  3232. // the current non-supported value remains in it:
  3233. pUpgradeCollection->Remove(ulIndexOfAddedValue);
  3234.     }
  3235.         }
  3236.         HX_RELEASE(pUpgradeCollection);
  3237.     }
  3238.     return bFailed;
  3239. }
  3240. BOOL
  3241. CSmilParser::testAttributeFailed(SMILNode* pNode)
  3242. {
  3243.     HX_RESULT rc = HXR_OK;
  3244.     BOOL bFailed = FALSE;
  3245.     IHXBuffer* pBuf = 0;
  3246.     if(pNode->m_pValues)
  3247.     {
  3248. rc = pNode->m_pValues->GetPropertyCString("system-required", pBuf);
  3249. if (FAILED(rc))
  3250. {
  3251.     rc = pNode->m_pValues->GetPropertyCString("systemRequired", pBuf);
  3252. }
  3253. if(HXR_OK == rc)
  3254. {
  3255.     const char* pActualString = (const char*)pBuf->GetBuffer();
  3256.     // Check with the core first
  3257.     if(m_pRequireTagsMap)
  3258.     {
  3259. void* pTag = 0;
  3260. // /In SMIL 2.0, this may be a list of logically ANDed values
  3261. // separated by a '+', e.g., "HostLanguage+BrushMedia".  We
  3262. // need to look up all of them and, if any in the list are
  3263. // not found, we fail on the whole thing.  (See SMIL 2.0
  3264. // Interop Structure Module test #2.2 & #2.3):
  3265. // /XXXEH- do whitespace removal on either side of '+'s:
  3266. const char* pStrWalker = pActualString;
  3267. char* pNextPlusSign = (char*)(strchr(pStrWalker,'+'));
  3268. do
  3269. {
  3270.     if (pNextPlusSign)
  3271.     {
  3272. *pNextPlusSign = '';
  3273.     }
  3274.     if (!m_pRequireTagsMap->Lookup(pStrWalker, (void*&)pTag))
  3275.     {
  3276. bFailed = TRUE;
  3277.     }
  3278.     if (pNextPlusSign)
  3279.     {
  3280. *pNextPlusSign = '+';
  3281. pStrWalker = pNextPlusSign+1;
  3282. pNextPlusSign = (char*)(strchr(pStrWalker,'+'));
  3283.     }
  3284.     else
  3285.     {
  3286. pStrWalker = NULL;
  3287.     }
  3288. } while (!bFailed  &&  pStrWalker);
  3289.     }
  3290.     else // no required list, can't parse it
  3291.     {
  3292. bFailed = TRUE;
  3293.     }
  3294.     pBuf->Release();
  3295.     if(bFailed)
  3296.     {
  3297. goto exit;
  3298.     }
  3299. }
  3300. rc = pNode->m_pValues->GetPropertyCString("systemBitrate", pBuf);
  3301. if (FAILED(rc))
  3302. {
  3303.     rc = pNode->m_pValues->GetPropertyCString("system-bitrate", pBuf);
  3304. }
  3305. if(HXR_OK == rc)
  3306. {
  3307.     UINT32 ulBandwidth = atol((const char*)pBuf->GetBuffer());
  3308.     if(m_ulBandwidthPreference < ulBandwidth)
  3309.     {
  3310. bFailed = TRUE;
  3311.     }
  3312.     pBuf->Release();
  3313.     if(bFailed)
  3314.     {
  3315. goto exit;
  3316.     }
  3317. }
  3318. rc = pNode->m_pValues->GetPropertyCString("systemLanguage", pBuf);
  3319. if (FAILED(rc))
  3320. {
  3321.     rc = pNode->m_pValues->GetPropertyCString("system-language", pBuf);
  3322. }
  3323. if(HXR_OK == rc)
  3324. {
  3325.     if(m_pLanguagePreferenceList)
  3326.     {
  3327. const char* pLang = (const char*)pBuf->GetBuffer();
  3328. if(!inLanguagePreference(pLang))
  3329. {
  3330.     bFailed = TRUE;
  3331. }
  3332.     }
  3333.     else    // no preference, can't do it...
  3334.     {
  3335. bFailed = TRUE;
  3336.     }
  3337.     pBuf->Release();
  3338.     if(bFailed)
  3339.     {
  3340. goto exit;
  3341.     }
  3342. }
  3343. rc = pNode->m_pValues->GetPropertyCString("systemCaptions", pBuf);
  3344. if (FAILED(rc))
  3345. {
  3346.     rc = pNode->m_pValues->GetPropertyCString("system-captions", pBuf);
  3347. }
  3348. if(HXR_OK == rc)
  3349. {
  3350.     const char* pActualValue = (const char*)pBuf->GetBuffer();
  3351.     if(strcmp(pActualValue, "on") == 0)
  3352.     {
  3353. if(!m_bCaptionsPreference)
  3354. {
  3355.     bFailed = TRUE;
  3356. }
  3357.     }
  3358.     else
  3359.     {
  3360. if(m_bCaptionsPreference)
  3361. {
  3362.     bFailed = TRUE;
  3363. }
  3364.     }
  3365.     pBuf->Release();
  3366.     if(bFailed)
  3367.     {
  3368. goto exit;
  3369.     }
  3370. }
  3371. rc = pNode->m_pValues->GetPropertyCString("systemOverdubOrSubtitle",
  3372.     pBuf);
  3373. if (FAILED(rc))
  3374. {
  3375.     rc = pNode->m_pValues->GetPropertyCString(
  3376. "system-overdub-or-caption", pBuf);
  3377. }
  3378. if (rc == HXR_OK)
  3379. {
  3380.     if(m_pOverdubOrCaptionPreference)
  3381.     {
  3382. const char* pActualValue = (const char*)pBuf->GetBuffer();
  3383. if(strcmp(pActualValue, "caption") == 0)
  3384. {
  3385.     if(strcmp(m_pOverdubOrCaptionPreference, "caption") != 0)
  3386.     {
  3387. bFailed = TRUE;
  3388.     }
  3389. }
  3390. else if(strcmp(pActualValue, "overdub") == 0)
  3391. {
  3392.     if(strcmp(m_pOverdubOrCaptionPreference, "overdub") != 0)
  3393.     {
  3394. bFailed = TRUE;
  3395.     }
  3396. }
  3397.     }
  3398.     else
  3399.     {
  3400. bFailed = TRUE;
  3401.     }
  3402.     pBuf->Release();
  3403.     if(bFailed)
  3404.     {
  3405. goto exit;
  3406.     }
  3407. }
  3408. rc = pNode->m_pValues->GetPropertyCString("systemScreenSize", pBuf);
  3409. if (FAILED(rc))
  3410. {
  3411.     rc = pNode->m_pValues->GetPropertyCString("system-screen-size",
  3412. pBuf);
  3413. }
  3414. if(HXR_OK == rc)
  3415. {
  3416.     UINT32 ulScreenHeight = 0;
  3417.     UINT32 ulScreenWidth = 0;
  3418.     const char* pScreenSize = (const char*)pBuf->GetBuffer();
  3419.     // format is screen-height "X" screen-width
  3420.     char tmp[256]; /* Flawfinder: ignore */
  3421.     SafeStrCpy(tmp,  pScreenSize, 256);
  3422.     char* pScreenHeight = strtok(tmp, "X");
  3423.     if(pScreenHeight)
  3424.     {
  3425. ulScreenHeight = atol(pScreenHeight);
  3426. char* pScreenWidth = strtok(NULL, "");
  3427. if(pScreenWidth)
  3428. {
  3429.     ulScreenWidth = atol(pScreenWidth);
  3430. }
  3431.     }
  3432.     // /If it's (0,0) in our system, then we failed to get the values
  3433.     // from the OS via GetSystemScreenInfo() & thus don't support this
  3434.     // in this OS.  SMIL 2.0 spec says to return "TRUE" if you don't
  3435.     // support a test attribute:
  3436.     if((!m_ulScreenHeightPreference  &&  !m_ulScreenWidthPreference))
  3437.     {
  3438. bFailed = FALSE;
  3439.     }
  3440.     else if((m_ulScreenHeightPreference < ulScreenHeight) ||
  3441.        (m_ulScreenWidthPreference < ulScreenWidth))
  3442.     {
  3443. bFailed = TRUE;
  3444.     }
  3445.     pBuf->Release();
  3446.     if(bFailed)
  3447.     {
  3448. goto exit;
  3449.     }
  3450. }
  3451. rc = pNode->m_pValues->GetPropertyCString("systemScreenDepth", pBuf);
  3452. if (FAILED(rc))
  3453. {
  3454.     rc = pNode->m_pValues->GetPropertyCString("system-screen-depth",
  3455. pBuf);
  3456. }
  3457. if(HXR_OK == rc)
  3458. {
  3459.     UINT32 ulScreenDepth = atol((const char*)pBuf->GetBuffer());
  3460.     // /If it's 0 in our system, then our player does not (in this
  3461.     // current build) support this.  The SMIL 2.0 spec says to
  3462.     // return "TRUE" if you don't support a test attribute:
  3463.     if(!m_ulScreenDepthPreference)
  3464.     {
  3465. bFailed = FALSE;
  3466.     }
  3467.     else if(m_ulScreenDepthPreference < ulScreenDepth)
  3468.     {
  3469. bFailed = TRUE;
  3470.     }
  3471.     pBuf->Release();
  3472.     if(bFailed)