1 /* 2 * Copyright (C) 2002, 2003 The Karbon Developers 3 * Copyright (C) 2006 Alexander Kellett <lypanov (at) kde.org> 4 * Copyright (C) 2006, 2007 Rob Buis <buis (at) kde.org> 5 * Copyright (C) 2007, 2009 Apple Inc. All rights reserved. 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Library General Public 9 * License as published by the Free Software Foundation; either 10 * version 2 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Library General Public License for more details. 16 * 17 * You should have received a copy of the GNU Library General Public License 18 * along with this library; see the file COPYING.LIB. If not, write to 19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 20 * Boston, MA 02110-1301, USA. 21 */ 22 23 #include "config.h" 24 25 #if ENABLE(SVG) 26 #include "SVGParserUtilities.h" 27 28 #include "Document.h" 29 #include "FloatPoint.h" 30 #include "SVGPointList.h" 31 32 #include <limits> 33 #include <wtf/ASCIICType.h> 34 35 namespace WebCore { 36 37 template <typename FloatType> static inline bool isValidRange(const FloatType& x) 38 { 39 static const FloatType max = std::numeric_limits<FloatType>::max(); 40 return x >= -max && x <= max; 41 } 42 43 // We use this generic parseNumber function to allow the Path parsing code to work 44 // at a higher precision internally, without any unnecessary runtime cost or code 45 // complexity. 46 template <typename FloatType> static bool genericParseNumber(const UChar*& ptr, const UChar* end, FloatType& number, bool skip) 47 { 48 FloatType integer, decimal, frac, exponent; 49 int sign, expsign; 50 const UChar* start = ptr; 51 52 exponent = 0; 53 integer = 0; 54 frac = 1; 55 decimal = 0; 56 sign = 1; 57 expsign = 1; 58 59 // read the sign 60 if (ptr < end && *ptr == '+') 61 ptr++; 62 else if (ptr < end && *ptr == '-') { 63 ptr++; 64 sign = -1; 65 } 66 67 if (ptr == end || ((*ptr < '0' || *ptr > '9') && *ptr != '.')) 68 // The first character of a number must be one of [0-9+-.] 69 return false; 70 71 // read the integer part, build right-to-left 72 const UChar* ptrStartIntPart = ptr; 73 while (ptr < end && *ptr >= '0' && *ptr <= '9') 74 ++ptr; // Advance to first non-digit. 75 76 if (ptr != ptrStartIntPart) { 77 const UChar* ptrScanIntPart = ptr - 1; 78 FloatType multiplier = 1; 79 while (ptrScanIntPart >= ptrStartIntPart) { 80 integer += multiplier * static_cast<FloatType>(*(ptrScanIntPart--) - '0'); 81 multiplier *= 10; 82 } 83 // Bail out early if this overflows. 84 if (!isValidRange(integer)) 85 return false; 86 } 87 88 if (ptr < end && *ptr == '.') { // read the decimals 89 ptr++; 90 91 // There must be a least one digit following the . 92 if (ptr >= end || *ptr < '0' || *ptr > '9') 93 return false; 94 95 while (ptr < end && *ptr >= '0' && *ptr <= '9') 96 decimal += (*(ptr++) - '0') * (frac *= static_cast<FloatType>(0.1)); 97 } 98 99 // read the exponent part 100 if (ptr != start && ptr + 1 < end && (*ptr == 'e' || *ptr == 'E') 101 && (ptr[1] != 'x' && ptr[1] != 'm')) { 102 ptr++; 103 104 // read the sign of the exponent 105 if (*ptr == '+') 106 ptr++; 107 else if (*ptr == '-') { 108 ptr++; 109 expsign = -1; 110 } 111 112 // There must be an exponent 113 if (ptr >= end || *ptr < '0' || *ptr > '9') 114 return false; 115 116 while (ptr < end && *ptr >= '0' && *ptr <= '9') { 117 exponent *= static_cast<FloatType>(10); 118 exponent += *ptr - '0'; 119 ptr++; 120 } 121 // Make sure exponent is valid. 122 if (!isValidRange(exponent) || exponent > std::numeric_limits<FloatType>::max_exponent) 123 return false; 124 } 125 126 number = integer + decimal; 127 number *= sign; 128 129 if (exponent) 130 number *= static_cast<FloatType>(pow(10.0, expsign * static_cast<int>(exponent))); 131 132 // Don't return Infinity() or NaN(). 133 if (!isValidRange(number)) 134 return false; 135 136 if (start == ptr) 137 return false; 138 139 if (skip) 140 skipOptionalSpacesOrDelimiter(ptr, end); 141 142 return true; 143 } 144 145 bool parseNumber(const UChar*& ptr, const UChar* end, float& number, bool skip) 146 { 147 return genericParseNumber(ptr, end, number, skip); 148 } 149 150 // only used to parse largeArcFlag and sweepFlag which must be a "0" or "1" 151 // and might not have any whitespace/comma after it 152 bool parseArcFlag(const UChar*& ptr, const UChar* end, bool& flag) 153 { 154 const UChar flagChar = *ptr++; 155 if (flagChar == '0') 156 flag = false; 157 else if (flagChar == '1') 158 flag = true; 159 else 160 return false; 161 162 skipOptionalSpacesOrDelimiter(ptr, end); 163 164 return true; 165 } 166 167 bool parseNumberOptionalNumber(const String& s, float& x, float& y) 168 { 169 if (s.isEmpty()) 170 return false; 171 const UChar* cur = s.characters(); 172 const UChar* end = cur + s.length(); 173 174 if (!parseNumber(cur, end, x)) 175 return false; 176 177 if (cur == end) 178 y = x; 179 else if (!parseNumber(cur, end, y, false)) 180 return false; 181 182 return cur == end; 183 } 184 185 bool pointsListFromSVGData(SVGPointList& pointsList, const String& points) 186 { 187 if (points.isEmpty()) 188 return true; 189 const UChar* cur = points.characters(); 190 const UChar* end = cur + points.length(); 191 192 skipOptionalSpaces(cur, end); 193 194 bool delimParsed = false; 195 while (cur < end) { 196 delimParsed = false; 197 float xPos = 0.0f; 198 if (!parseNumber(cur, end, xPos)) 199 return false; 200 201 float yPos = 0.0f; 202 if (!parseNumber(cur, end, yPos, false)) 203 return false; 204 205 skipOptionalSpaces(cur, end); 206 207 if (cur < end && *cur == ',') { 208 delimParsed = true; 209 cur++; 210 } 211 skipOptionalSpaces(cur, end); 212 213 pointsList.append(FloatPoint(xPos, yPos)); 214 } 215 return cur == end && !delimParsed; 216 } 217 218 bool parseGlyphName(const String& input, HashSet<String>& values) 219 { 220 // FIXME: Parsing error detection is missing. 221 values.clear(); 222 223 const UChar* ptr = input.characters(); 224 const UChar* end = ptr + input.length(); 225 skipOptionalSpaces(ptr, end); 226 227 while (ptr < end) { 228 // Leading and trailing white space, and white space before and after separators, will be ignored. 229 const UChar* inputStart = ptr; 230 while (ptr < end && *ptr != ',') 231 ++ptr; 232 233 if (ptr == inputStart) 234 break; 235 236 // walk backwards from the ; to ignore any whitespace 237 const UChar* inputEnd = ptr - 1; 238 while (inputStart < inputEnd && isWhitespace(*inputEnd)) 239 --inputEnd; 240 241 values.add(String(inputStart, inputEnd - inputStart + 1)); 242 skipOptionalSpacesOrDelimiter(ptr, end, ','); 243 } 244 245 return true; 246 } 247 248 static bool parseUnicodeRange(const UChar* characters, unsigned length, UnicodeRange& range) 249 { 250 if (length < 2 || characters[0] != 'U' || characters[1] != '+') 251 return false; 252 253 // Parse the starting hex number (or its prefix). 254 unsigned startRange = 0; 255 unsigned startLength = 0; 256 257 const UChar* ptr = characters + 2; 258 const UChar* end = characters + length; 259 while (ptr < end) { 260 if (!isASCIIHexDigit(*ptr)) 261 break; 262 ++startLength; 263 if (startLength > 6) 264 return false; 265 startRange = (startRange << 4) | toASCIIHexValue(*ptr); 266 ++ptr; 267 } 268 269 // Handle the case of ranges separated by "-" sign. 270 if (2 + startLength < length && *ptr == '-') { 271 if (!startLength) 272 return false; 273 274 // Parse the ending hex number (or its prefix). 275 unsigned endRange = 0; 276 unsigned endLength = 0; 277 ++ptr; 278 while (ptr < end) { 279 if (!isASCIIHexDigit(*ptr)) 280 break; 281 ++endLength; 282 if (endLength > 6) 283 return false; 284 endRange = (endRange << 4) | toASCIIHexValue(*ptr); 285 ++ptr; 286 } 287 288 if (!endLength) 289 return false; 290 291 range.first = startRange; 292 range.second = endRange; 293 return true; 294 } 295 296 // Handle the case of a number with some optional trailing question marks. 297 unsigned endRange = startRange; 298 while (ptr < end) { 299 if (*ptr != '?') 300 break; 301 ++startLength; 302 if (startLength > 6) 303 return false; 304 startRange <<= 4; 305 endRange = (endRange << 4) | 0xF; 306 ++ptr; 307 } 308 309 if (!startLength) 310 return false; 311 312 range.first = startRange; 313 range.second = endRange; 314 return true; 315 } 316 317 bool parseKerningUnicodeString(const String& input, UnicodeRanges& rangeList, HashSet<String>& stringList) 318 { 319 // FIXME: Parsing error detection is missing. 320 const UChar* ptr = input.characters(); 321 const UChar* end = ptr + input.length(); 322 323 while (ptr < end) { 324 const UChar* inputStart = ptr; 325 while (ptr < end && *ptr != ',') 326 ++ptr; 327 328 if (ptr == inputStart) 329 break; 330 331 // Try to parse unicode range first 332 UnicodeRange range; 333 if (parseUnicodeRange(inputStart, ptr - inputStart, range)) 334 rangeList.append(range); 335 else 336 stringList.add(String(inputStart, ptr - inputStart)); 337 ++ptr; 338 } 339 340 return true; 341 } 342 343 Vector<String> parseDelimitedString(const String& input, const char seperator) 344 { 345 Vector<String> values; 346 347 const UChar* ptr = input.characters(); 348 const UChar* end = ptr + input.length(); 349 skipOptionalSpaces(ptr, end); 350 351 while (ptr < end) { 352 // Leading and trailing white space, and white space before and after semicolon separators, will be ignored. 353 const UChar* inputStart = ptr; 354 while (ptr < end && *ptr != seperator) // careful not to ignore whitespace inside inputs 355 ptr++; 356 357 if (ptr == inputStart) 358 break; 359 360 // walk backwards from the ; to ignore any whitespace 361 const UChar* inputEnd = ptr - 1; 362 while (inputStart < inputEnd && isWhitespace(*inputEnd)) 363 inputEnd--; 364 365 values.append(String(inputStart, inputEnd - inputStart + 1)); 366 skipOptionalSpacesOrDelimiter(ptr, end, seperator); 367 } 368 369 return values; 370 } 371 372 } 373 374 #endif // ENABLE(SVG) 375