nsresult nsSMILParserUtils::ParseRepeatCount(const nsAString& aSpec, nsSMILRepeatCount& aResult) { nsresult rv = NS_OK; NS_ConvertUTF16toUTF8 spec(aSpec); nsACString::const_iterator start, end; spec.BeginReading(start); spec.EndReading(end); SkipWsp(start, end); if (start != end) { if (ConsumeSubstring(start, end, "indefinite")) { aResult.SetIndefinite(); } else { double value = GetFloat(start, end, &rv); if (NS_SUCCEEDED(rv)) { /* Repeat counts must be > 0 */ if (value <= 0.0) { rv = NS_ERROR_FAILURE; } else { aResult = value; } } } /* Check for trailing junk */ SkipWsp(start, end); if (start != end) { rv = NS_ERROR_FAILURE; } } else { /* Empty spec */ rv = NS_ERROR_FAILURE; } if (NS_FAILED(rv)) { aResult.Unset(); } return rv; }
nsresult nsSMILParserUtils::ParseClockValue(const nsAString& aSpec, nsSMILTimeValue* aResult, PRUint32 aFlags, // = 0 bool* aIsMedia) // = nullptr { nsSMILTime offset = 0L; double component = 0.0; PRInt8 sign = 0; PRUint8 colonCount = 0; // Indicates we have started parsing a clock-value (not including the optional // +/- that precedes the clock-value) or keyword ("media", "indefinite") bool started = false; PRInt32 metricMultiplicand = MSEC_PER_SEC; bool numIsReal = false; bool prevNumCouldBeMin = false; bool numCouldBeMin = false; bool numCouldBeSec = false; bool isIndefinite = false; if (aIsMedia) { *aIsMedia = false; } NS_ConvertUTF16toUTF8 spec(aSpec); const char* start = spec.BeginReading(); const char* end = spec.EndReading(); while (start != end) { if (IsSpace(*start)) { ++start; if (started) { break; } } else if (!started && (aFlags & kClockValueAllowSign) && (*start == '+' || *start == '-')) { // check sign has not already been set (e.g. ++10s) if (sign != 0) { return NS_ERROR_FAILURE; } sign = (*start == '+') ? 1 : -1; ++start; // The NS_IS_DIGIT etc. macros are not locale-specific } else if (NS_IS_DIGIT(*start)) { prevNumCouldBeMin = numCouldBeMin; if (!ParseClockComponent(start, end, component, numIsReal, numCouldBeMin, numCouldBeSec)) { return NS_ERROR_FAILURE; } started = true; } else if (started && *start == ':') { ++colonCount; // Neither minutes nor hours can be reals if (numIsReal) { return NS_ERROR_FAILURE; } // Can't have more than two colons if (colonCount > 2) { return NS_ERROR_FAILURE; } // Multiply the offset by 60 and add the last accumulated component offset = offset * 60 + nsSMILTime(component); component = 0.0; ++start; } else if (NS_IS_ALPHA(*start)) { if (colonCount > 0) { return NS_ERROR_FAILURE; } if (!started && (aFlags & kClockValueAllowIndefinite) && ConsumeSubstring(start, end, "indefinite")) { // We set a separate flag because we don't know what the state of the // passed in time value is and we shouldn't change it in the case of a // bad input string (so we can't initialise it to 0ms for example). isIndefinite = true; if (aResult) { aResult->SetIndefinite(); } started = true; } else if (!started && aIsMedia && ConsumeSubstring(start, end, "media")) { *aIsMedia = true; started = true; } else if (!ParseMetricMultiplicand(start, end, metricMultiplicand)) { return NS_ERROR_FAILURE; } // Nothing must come after the string except whitespace break; } else { return NS_ERROR_FAILURE; } } // Whitespace/empty string if (!started) { return NS_ERROR_FAILURE; } // Process remainder of string (if any) to ensure it is only trailing // whitespace (embedded whitespace is not allowed) SkipBeginWsp(start, end); if (start != end) { return NS_ERROR_FAILURE; } // No more processing required if the value was "indefinite" or "media". if (isIndefinite || (aIsMedia && *aIsMedia)) { return NS_OK; } // If there is more than one colon then the previous component must be a // correctly formatted minute (i.e. two digits between 00 and 59) and the // latest component must be a correctly formatted second (i.e. two digits // before the .) if (colonCount > 0 && (!prevNumCouldBeMin || !numCouldBeSec)) { return NS_ERROR_FAILURE; } // Tack on the last component if (colonCount > 0) { offset *= 60 * 1000; component *= 1000; // rounding component = (component >= 0) ? component + 0.5 : component - 0.5; offset += nsSMILTime(component); } else { component *= metricMultiplicand; // rounding component = (component >= 0) ? component + 0.5 : component - 0.5; offset = nsSMILTime(component); } // we haven't applied the sign yet so if the result is negative we must have // overflowed if (offset < 0) { return NS_ERROR_FAILURE; } if (aResult) { if (sign == -1) { offset = -offset; } aResult->SetMillis(offset); } return NS_OK; }
nsresult nsSMILParserUtils::ParseClockValue(const nsAString& aSpec, nsSMILTimeValue* aResult, PRUint32 aFlags, // = 0 PRBool* aIsMedia) // = nsnull { nsSMILTime offset = 0L; double component = 0.0; PRInt8 sign = 0; PRUint8 colonCount = 0; PRBool started = PR_FALSE; PRBool isValid = PR_TRUE; PRInt32 metricMultiplicand = MSEC_PER_SEC; PRBool numIsReal = PR_FALSE; PRBool prevNumCouldBeMin = PR_FALSE; PRBool numCouldBeMin = PR_FALSE; PRBool numCouldBeSec = PR_FALSE; PRBool isIndefinite = PR_FALSE; if (aIsMedia) { *aIsMedia = PR_FALSE; } NS_ConvertUTF16toUTF8 spec(aSpec); nsACString::const_iterator start, end; spec.BeginReading(start); spec.EndReading(end); while (start != end) { if (IsSpace(*start)) { if (started) { ++start; break; } // else, we haven't started yet, ignore initial whitespace ++start; } else if ((aFlags & kClockValueAllowSign) && (*start == '+' || *start == '-')) { if (sign != 0) { // sign has already been set isValid = PR_FALSE; break; } if (started) { // sign appears in the middle of the string isValid = PR_FALSE; break; } sign = (*start == '+') ? 1 : -1; ++start; // The NS_IS_DIGIT etc. macros are not locale-specific } else if (NS_IS_DIGIT(*start)) { prevNumCouldBeMin = numCouldBeMin; if (!ParseClockComponent(start, end, component, numIsReal, numCouldBeMin, numCouldBeSec)) { isValid = PR_FALSE; break; } started = PR_TRUE; } else if (*start == ':') { ++colonCount; // Neither minutes nor hours can be reals if (numIsReal) { isValid = PR_FALSE; break; } // Clock value can't start with a ':' if (!started) { isValid = PR_FALSE; break; } // Can't have more than two colons if (colonCount > 2) { isValid = PR_FALSE; break; } // Multiply the offset by 60 and add the last accumulated component offset = offset * 60 + PRInt64(component); component = 0.0; ++start; } else if (NS_IS_ALPHA(*start)) { if (colonCount > 0) { isValid = PR_FALSE; break; } if ((aFlags & kClockValueAllowIndefinite) && ConsumeSubstring(start, end, "indefinite")) { // We set a separate flag because we don't know what the state of the // passed in time value is and we shouldn't change it in the case of a // bad input string (so we can't initialise it to 0ms for example). isIndefinite = PR_TRUE; if (aResult) { aResult->SetIndefinite(); } } else if (aIsMedia && ConsumeSubstring(start, end, "media")) { *aIsMedia = PR_TRUE; } else if (!ParseMetricMultiplicand(start, end, metricMultiplicand)) { isValid = PR_FALSE; break; } // Nothing must come after the string except whitespace break; } else { isValid = PR_FALSE; break; } } if (!started) { isValid = PR_FALSE; } // Process remainder of string (if any) to ensure it is only trailing // whitespace (embedded whitespace is not allowed) SkipWsp(start, end); if (start != end) { isValid = PR_FALSE; } // No more processing required if the value was "indefinite" or "media". if (isIndefinite || (aIsMedia && *aIsMedia)) return NS_OK; // If there is more than one colon then the previous component must be a // correctly formatted minute (i.e. two digits between 00 and 59) and the // latest component must be a correctly formatted second (i.e. two digits // before the .) if (colonCount > 0 && (!prevNumCouldBeMin || !numCouldBeSec)) { isValid = PR_FALSE; } if (isValid) { // Tack on the last component if (colonCount > 0) { offset = offset * 60 * 1000; component *= 1000; // rounding component = (component >= 0) ? component + 0.5 : component - 0.5; offset += PRInt64(component); } else { component *= metricMultiplicand; // rounding component = (component >= 0) ? component + 0.5 : component - 0.5; offset = PRInt64(component); } if (aResult) { nsSMILTime millis = offset; if (sign == -1) { millis = -offset; } aResult->SetMillis(millis); } } return (isValid) ? NS_OK : NS_ERROR_FAILURE; }