int parseTransformParamList(const UChar*& ptr, const UChar* end, float* values, int required, int optional) { int optionalParams = 0, requiredParams = 0; if (!skipOptionalSpaces(ptr, end) || *ptr != '(') return -1; ptr++; skipOptionalSpaces(ptr, end); while (requiredParams < required) { if (ptr >= end || !parseNumber(ptr, end, values[requiredParams], false)) return -1; requiredParams++; if (requiredParams < required) skipOptionalSpacesOrDelimiter(ptr, end); } if (!skipOptionalSpaces(ptr, end)) return -1; bool delimParsed = skipOptionalSpacesOrDelimiter(ptr, end); if (ptr >= end) return -1; if (*ptr == ')') { // skip optionals ptr++; if (delimParsed) return -1; } else { while (optionalParams < optional) { if (ptr >= end || !parseNumber(ptr, end, values[requiredParams + optionalParams], false)) return -1; optionalParams++; if (optionalParams < optional) skipOptionalSpacesOrDelimiter(ptr, end); } if (!skipOptionalSpaces(ptr, end)) return -1; delimParsed = skipOptionalSpacesOrDelimiter(ptr, end); if (ptr >= end || *ptr != ')' || delimParsed) return -1; ptr++; } return requiredParams + optionalParams; }
// only used to parse largeArcFlag and sweepFlag which must be a "0" or "1" // and might not have any whitespace/comma after it bool parseArcFlag(const SQChar*& ptr, const SQChar* end, bool& flag) { const SQChar flagChar = *ptr++; if (flagChar == '0') flag = false; else if (flagChar == '1') flag = true; else return false; skipOptionalSpacesOrDelimiter(ptr, end); return true; }
void SVGLengthList::parse(const String& value, const SVGStyledElement* context, SVGLengthMode mode) { ExceptionCode ec = 0; clear(ec); const UChar* ptr = value.characters(); const UChar* end = ptr + value.length(); while (ptr < end) { const UChar* start = ptr; while (ptr < end && *ptr != ',' && !isWhitespace(*ptr)) ptr++; if (ptr == start) break; appendItem(SVGLength(context, mode, String(start, ptr - start)), ec); skipOptionalSpacesOrDelimiter(ptr, end); } }
void SVGStringList::parse(const String& data, UChar delimiter) { // TODO : more error checking/reporting ExceptionCode ec = 0; clear(ec); const UChar* ptr = data.characters(); const UChar* end = ptr + data.length(); while (ptr < end) { const UChar* start = ptr; while (ptr < end && *ptr != delimiter && !isWhitespace(*ptr)) ptr++; if (ptr == start) break; appendItem(String(start, ptr - start), ec); skipOptionalSpacesOrDelimiter(ptr, end, delimiter); } }
// We use this generic parseNumber function to allow the Path parsing code to work // at a higher precision internally, without any unnecessary runtime cost or code // complexity. template <typename FloatType> static bool genericParseNumber(const SQChar*& ptr, const SQChar* end, FloatType& number, bool skip) { FloatType integer, decimal, frac, exponent; int sign, expsign; const SQChar* start = ptr; exponent = 0; integer = 0; frac = 1; decimal = 0; sign = 1; expsign = 1; // read the sign if (ptr < end && *ptr == '+') ptr++; else if (ptr < end && *ptr == '-') { ptr++; sign = -1; } if (ptr == end || ((*ptr < '0' || *ptr > '9') && *ptr != '.')) // The first character of a number must be one of [0-9+-.] return false; // read the integer part, build right-to-left const SQChar* ptrStartIntPart = ptr; while (ptr < end && *ptr >= '0' && *ptr <= '9') ++ptr; // Advance to first non-digit. if (ptr != ptrStartIntPart) { const SQChar* ptrScanIntPart = ptr - 1; FloatType multiplier = 1; while (ptrScanIntPart >= ptrStartIntPart) { integer += multiplier * static_cast<FloatType>(*(ptrScanIntPart--) - '0'); multiplier *= 10; } // Bail out early if this overflows. if (!isValidRange(integer)) return false; } if (ptr < end && *ptr == '.') { // read the decimals ptr++; // There must be a least one digit following the . if (ptr >= end || *ptr < '0' || *ptr > '9') return false; while (ptr < end && *ptr >= '0' && *ptr <= '9') decimal += (*(ptr++) - '0') * (frac *= static_cast<FloatType>(0.1)); } // read the exponent part if (ptr != start && ptr + 1 < end && (*ptr == 'e' || *ptr == 'E') && (ptr[1] != 'x' && ptr[1] != 'm')) { ptr++; // read the sign of the exponent if (*ptr == '+') ptr++; else if (*ptr == '-') { ptr++; expsign = -1; } // There must be an exponent if (ptr >= end || *ptr < '0' || *ptr > '9') return false; while (ptr < end && *ptr >= '0' && *ptr <= '9') { exponent *= static_cast<FloatType>(10); exponent += *ptr - '0'; ptr++; } // Make sure exponent is valid. if (!isValidRange(exponent) || exponent > std::numeric_limits<FloatType>::max_exponent) return false; } number = integer + decimal; number *= sign; if (exponent) number *= static_cast<FloatType>(pow(10.0, expsign * static_cast<int>(exponent))); // Don't return Infinity() or NaN(). if (!isValidRange(number)) return false; if (start == ptr) return false; if (skip) skipOptionalSpacesOrDelimiter(ptr, end); return true; }