OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2009 Google Inc. All rights reserved. | 2 * Copyright (C) 2009 Google Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
6 * met: | 6 * met: |
7 * | 7 * |
8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
91 int result = (day + 13 * shiftedMonth / 5 + lowYear + lowYear / 4 + highYear
/ 4 + 5 * highYear + 6) % 7; | 91 int result = (day + 13 * shiftedMonth / 5 + lowYear + lowYear / 4 + highYear
/ 4 + 5 * highYear + 6) % 7; |
92 return result; | 92 return result; |
93 } | 93 } |
94 | 94 |
95 int DateComponents::maxWeekNumberInYear() const | 95 int DateComponents::maxWeekNumberInYear() const |
96 { | 96 { |
97 int day = dayOfWeek(m_year, 0, 1); // January 1. | 97 int day = dayOfWeek(m_year, 0, 1); // January 1. |
98 return day == Thursday || (day == Wednesday && isLeapYear(m_year)) ? maximum
WeekNumber : maximumWeekNumber - 1; | 98 return day == Thursday || (day == Wednesday && isLeapYear(m_year)) ? maximum
WeekNumber : maximumWeekNumber - 1; |
99 } | 99 } |
100 | 100 |
101 static unsigned countDigits(const UChar* src, unsigned length, unsigned start) | 101 static unsigned countDigits(const String& src, unsigned start) |
102 { | 102 { |
103 unsigned index = start; | 103 unsigned index = start; |
104 for (; index < length; ++index) { | 104 for (; index < src.length(); ++index) { |
105 if (!isASCIIDigit(src[index])) | 105 if (!isASCIIDigit(src[index])) |
106 break; | 106 break; |
107 } | 107 } |
108 return index - start; | 108 return index - start; |
109 } | 109 } |
110 | 110 |
111 // Very strict integer parser. Do not allow leading or trailing whitespace unlik
e charactersToIntStrict(). | 111 // Very strict integer parser. Do not allow leading or trailing whitespace unlik
e charactersToIntStrict(). |
112 static bool toInt(const UChar* src, unsigned length, unsigned parseStart, unsign
ed parseLength, int& out) | 112 static bool toInt(const String& src, unsigned parseStart, unsigned parseLength,
int& out) |
113 { | 113 { |
114 if (parseStart + parseLength > length || parseLength <= 0) | 114 if (parseStart + parseLength > src.length() || parseLength <= 0) |
115 return false; | 115 return false; |
116 int value = 0; | 116 int value = 0; |
117 const UChar* current = src + parseStart; | 117 unsigned current = parseStart; |
118 const UChar* end = current + parseLength; | 118 unsigned end = current + parseLength; |
119 | 119 |
120 // We don't need to handle negative numbers for ISO 8601. | 120 // We don't need to handle negative numbers for ISO 8601. |
121 for (; current < end; ++current) { | 121 for (; current < end; ++current) { |
122 if (!isASCIIDigit(*current)) | 122 if (!isASCIIDigit(src[current])) |
123 return false; | 123 return false; |
124 int digit = *current - '0'; | 124 int digit = src[current] - '0'; |
125 if (value > (INT_MAX - digit) / 10) // Check for overflow. | 125 if (value > (INT_MAX - digit) / 10) // Check for overflow. |
126 return false; | 126 return false; |
127 value = value * 10 + digit; | 127 value = value * 10 + digit; |
128 } | 128 } |
129 out = value; | 129 out = value; |
130 return true; | 130 return true; |
131 } | 131 } |
132 | 132 |
133 bool DateComponents::parseYear(const UChar* src, unsigned length, unsigned start
, unsigned& end) | 133 bool DateComponents::parseYear(const String& src, unsigned start, unsigned& end) |
134 { | 134 { |
135 unsigned digitsLength = countDigits(src, length, start); | 135 unsigned digitsLength = countDigits(src, start); |
136 // Needs at least 4 digits according to the standard. | 136 // Needs at least 4 digits according to the standard. |
137 if (digitsLength < 4) | 137 if (digitsLength < 4) |
138 return false; | 138 return false; |
139 int year; | 139 int year; |
140 if (!toInt(src, length, start, digitsLength, year)) | 140 if (!toInt(src, start, digitsLength, year)) |
141 return false; | 141 return false; |
142 if (year < minimumYear() || year > maximumYear()) | 142 if (year < minimumYear() || year > maximumYear()) |
143 return false; | 143 return false; |
144 m_year = year; | 144 m_year = year; |
145 end = start + digitsLength; | 145 end = start + digitsLength; |
146 return true; | 146 return true; |
147 } | 147 } |
148 | 148 |
149 static bool withinHTMLDateLimits(int year, int month) | 149 static bool withinHTMLDateLimits(int year, int month) |
150 { | 150 { |
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
278 if (!addDay(carry)) | 278 if (!addDay(carry)) |
279 return false; | 279 return false; |
280 if (!withinHTMLDateLimits(m_year, m_month, m_monthDay, hour, minute, m_secon
d, m_millisecond)) | 280 if (!withinHTMLDateLimits(m_year, m_month, m_monthDay, hour, minute, m_secon
d, m_millisecond)) |
281 return false; | 281 return false; |
282 m_minute = minute; | 282 m_minute = minute; |
283 m_hour = hour; | 283 m_hour = hour; |
284 return true; | 284 return true; |
285 } | 285 } |
286 | 286 |
287 // Parses a timezone part, and adjust year, month, monthDay, hour, minute, secon
d, millisecond. | 287 // Parses a timezone part, and adjust year, month, monthDay, hour, minute, secon
d, millisecond. |
288 bool DateComponents::parseTimeZone(const UChar* src, unsigned length, unsigned s
tart, unsigned& end) | 288 bool DateComponents::parseTimeZone(const String& src, unsigned start, unsigned&
end) |
289 { | 289 { |
290 if (start >= length) | 290 if (start >= src.length()) |
291 return false; | 291 return false; |
292 unsigned index = start; | 292 unsigned index = start; |
293 if (src[index] == 'Z') { | 293 if (src[index] == 'Z') { |
294 end = index + 1; | 294 end = index + 1; |
295 return true; | 295 return true; |
296 } | 296 } |
297 | 297 |
298 bool minus; | 298 bool minus; |
299 if (src[index] == '+') | 299 if (src[index] == '+') |
300 minus = false; | 300 minus = false; |
301 else if (src[index] == '-') | 301 else if (src[index] == '-') |
302 minus = true; | 302 minus = true; |
303 else | 303 else |
304 return false; | 304 return false; |
305 ++index; | 305 ++index; |
306 | 306 |
307 int hour; | 307 int hour; |
308 int minute; | 308 int minute; |
309 if (!toInt(src, length, index, 2, hour) || hour < 0 || hour > 23) | 309 if (!toInt(src, index, 2, hour) || hour < 0 || hour > 23) |
310 return false; | 310 return false; |
311 index += 2; | 311 index += 2; |
312 | 312 |
313 if (index >= length || src[index] != ':') | 313 if (index >= src.length() || src[index] != ':') |
314 return false; | 314 return false; |
315 ++index; | 315 ++index; |
316 | 316 |
317 if (!toInt(src, length, index, 2, minute) || minute < 0 || minute > 59) | 317 if (!toInt(src, index, 2, minute) || minute < 0 || minute > 59) |
318 return false; | 318 return false; |
319 index += 2; | 319 index += 2; |
320 | 320 |
321 if (minus) { | 321 if (minus) { |
322 hour = -hour; | 322 hour = -hour; |
323 minute = -minute; | 323 minute = -minute; |
324 } | 324 } |
325 | 325 |
326 // Subtract the timezone offset. | 326 // Subtract the timezone offset. |
327 if (!addMinute(-(hour * 60 + minute))) | 327 if (!addMinute(-(hour * 60 + minute))) |
328 return false; | 328 return false; |
329 end = index; | 329 end = index; |
330 return true; | 330 return true; |
331 } | 331 } |
332 | 332 |
333 bool DateComponents::parseMonth(const UChar* src, unsigned length, unsigned star
t, unsigned& end) | 333 bool DateComponents::parseMonth(const String& src, unsigned start, unsigned& end
) |
334 { | 334 { |
335 ASSERT(src); | |
336 unsigned index; | 335 unsigned index; |
337 if (!parseYear(src, length, start, index)) | 336 if (!parseYear(src, start, index)) |
338 return false; | 337 return false; |
339 if (index >= length || src[index] != '-') | 338 if (index >= src.length() || src[index] != '-') |
340 return false; | 339 return false; |
341 ++index; | 340 ++index; |
342 | 341 |
343 int month; | 342 int month; |
344 if (!toInt(src, length, index, 2, month) || month < 1 || month > 12) | 343 if (!toInt(src, index, 2, month) || month < 1 || month > 12) |
345 return false; | 344 return false; |
346 --month; | 345 --month; |
347 if (!withinHTMLDateLimits(m_year, month)) | 346 if (!withinHTMLDateLimits(m_year, month)) |
348 return false; | 347 return false; |
349 m_month = month; | 348 m_month = month; |
350 end = index + 2; | 349 end = index + 2; |
351 m_type = Month; | 350 m_type = Month; |
352 return true; | 351 return true; |
353 } | 352 } |
354 | 353 |
355 bool DateComponents::parseDate(const UChar* src, unsigned length, unsigned start
, unsigned& end) | 354 bool DateComponents::parseDate(const String& src, unsigned start, unsigned& end) |
356 { | 355 { |
357 ASSERT(src); | |
358 unsigned index; | 356 unsigned index; |
359 if (!parseMonth(src, length, start, index)) | 357 if (!parseMonth(src, start, index)) |
360 return false; | 358 return false; |
361 // '-' and 2-digits are needed. | 359 // '-' and 2-digits are needed. |
362 if (index + 2 >= length) | 360 if (index + 2 >= src.length()) |
363 return false; | 361 return false; |
364 if (src[index] != '-') | 362 if (src[index] != '-') |
365 return false; | 363 return false; |
366 ++index; | 364 ++index; |
367 | 365 |
368 int day; | 366 int day; |
369 if (!toInt(src, length, index, 2, day) || day < 1 || day > maxDayOfMonth(m_y
ear, m_month)) | 367 if (!toInt(src, index, 2, day) || day < 1 || day > maxDayOfMonth(m_year, m_m
onth)) |
370 return false; | 368 return false; |
371 if (!withinHTMLDateLimits(m_year, m_month, day)) | 369 if (!withinHTMLDateLimits(m_year, m_month, day)) |
372 return false; | 370 return false; |
373 m_monthDay = day; | 371 m_monthDay = day; |
374 end = index + 2; | 372 end = index + 2; |
375 m_type = Date; | 373 m_type = Date; |
376 return true; | 374 return true; |
377 } | 375 } |
378 | 376 |
379 bool DateComponents::parseWeek(const UChar* src, unsigned length, unsigned start
, unsigned& end) | 377 bool DateComponents::parseWeek(const String& src, unsigned start, unsigned& end) |
380 { | 378 { |
381 ASSERT(src); | |
382 unsigned index; | 379 unsigned index; |
383 if (!parseYear(src, length, start, index)) | 380 if (!parseYear(src, start, index)) |
384 return false; | 381 return false; |
385 | 382 |
386 // 4 characters ('-' 'W' digit digit) are needed. | 383 // 4 characters ('-' 'W' digit digit) are needed. |
387 if (index + 3 >= length) | 384 if (index + 3 >= src.length()) |
388 return false; | 385 return false; |
389 if (src[index] != '-') | 386 if (src[index] != '-') |
390 return false; | 387 return false; |
391 ++index; | 388 ++index; |
392 if (src[index] != 'W') | 389 if (src[index] != 'W') |
393 return false; | 390 return false; |
394 ++index; | 391 ++index; |
395 | 392 |
396 int week; | 393 int week; |
397 if (!toInt(src, length, index, 2, week) || week < minimumWeekNumber || week
> maxWeekNumberInYear()) | 394 if (!toInt(src, index, 2, week) || week < minimumWeekNumber || week > maxWee
kNumberInYear()) |
398 return false; | 395 return false; |
399 if (m_year == maximumYear() && week > maximumWeekInMaximumYear) | 396 if (m_year == maximumYear() && week > maximumWeekInMaximumYear) |
400 return false; | 397 return false; |
401 m_week = week; | 398 m_week = week; |
402 end = index + 2; | 399 end = index + 2; |
403 m_type = Week; | 400 m_type = Week; |
404 return true; | 401 return true; |
405 } | 402 } |
406 | 403 |
407 bool DateComponents::parseTime(const UChar* src, unsigned length, unsigned start
, unsigned& end) | 404 bool DateComponents::parseTime(const String& src, unsigned start, unsigned& end) |
408 { | 405 { |
409 ASSERT(src); | |
410 int hour; | 406 int hour; |
411 if (!toInt(src, length, start, 2, hour) || hour < 0 || hour > 23) | 407 if (!toInt(src, start, 2, hour) || hour < 0 || hour > 23) |
412 return false; | 408 return false; |
413 unsigned index = start + 2; | 409 unsigned index = start + 2; |
414 if (index >= length) | 410 if (index >= src.length()) |
415 return false; | 411 return false; |
416 if (src[index] != ':') | 412 if (src[index] != ':') |
417 return false; | 413 return false; |
418 ++index; | 414 ++index; |
419 | 415 |
420 int minute; | 416 int minute; |
421 if (!toInt(src, length, index, 2, minute) || minute < 0 || minute > 59) | 417 if (!toInt(src, index, 2, minute) || minute < 0 || minute > 59) |
422 return false; | 418 return false; |
423 index += 2; | 419 index += 2; |
424 | 420 |
425 int second = 0; | 421 int second = 0; |
426 int millisecond = 0; | 422 int millisecond = 0; |
427 // Optional second part. | 423 // Optional second part. |
428 // Do not return with false because the part is optional. | 424 // Do not return with false because the part is optional. |
429 if (index + 2 < length && src[index] == ':') { | 425 if (index + 2 < src.length() && src[index] == ':') { |
430 if (toInt(src, length, index + 1, 2, second) && second >= 0 && second <=
59) { | 426 if (toInt(src, index + 1, 2, second) && second >= 0 && second <= 59) { |
431 index += 3; | 427 index += 3; |
432 | 428 |
433 // Optional fractional second part. | 429 // Optional fractional second part. |
434 if (index < length && src[index] == '.') { | 430 if (index < src.length() && src[index] == '.') { |
435 unsigned digitsLength = countDigits(src, length, index + 1); | 431 unsigned digitsLength = countDigits(src, index + 1); |
436 if (digitsLength > 0) { | 432 if (digitsLength > 0) { |
437 ++index; | 433 ++index; |
438 bool ok; | 434 bool ok; |
439 if (digitsLength == 1) { | 435 if (digitsLength == 1) { |
440 ok = toInt(src, length, index, 1, millisecond); | 436 ok = toInt(src, index, 1, millisecond); |
441 millisecond *= 100; | 437 millisecond *= 100; |
442 } else if (digitsLength == 2) { | 438 } else if (digitsLength == 2) { |
443 ok = toInt(src, length, index, 2, millisecond); | 439 ok = toInt(src, index, 2, millisecond); |
444 millisecond *= 10; | 440 millisecond *= 10; |
445 } else // digitsLength >= 3 | 441 } else { // digitsLength >= 3 |
446 ok = toInt(src, length, index, 3, millisecond); | 442 ok = toInt(src, index, 3, millisecond); |
| 443 } |
447 ASSERT_UNUSED(ok, ok); | 444 ASSERT_UNUSED(ok, ok); |
448 index += digitsLength; | 445 index += digitsLength; |
449 } | 446 } |
450 } | 447 } |
451 } | 448 } |
452 } | 449 } |
453 m_hour = hour; | 450 m_hour = hour; |
454 m_minute = minute; | 451 m_minute = minute; |
455 m_second = second; | 452 m_second = second; |
456 m_millisecond = millisecond; | 453 m_millisecond = millisecond; |
457 end = index; | 454 end = index; |
458 m_type = Time; | 455 m_type = Time; |
459 return true; | 456 return true; |
460 } | 457 } |
461 | 458 |
462 bool DateComponents::parseDateTimeLocal(const UChar* src, unsigned length, unsig
ned start, unsigned& end) | 459 bool DateComponents::parseDateTimeLocal(const String& src, unsigned start, unsig
ned& end) |
463 { | 460 { |
464 ASSERT(src); | |
465 unsigned index; | 461 unsigned index; |
466 if (!parseDate(src, length, start, index)) | 462 if (!parseDate(src, start, index)) |
467 return false; | 463 return false; |
468 if (index >= length) | 464 if (index >= src.length()) |
469 return false; | 465 return false; |
470 if (src[index] != 'T') | 466 if (src[index] != 'T') |
471 return false; | 467 return false; |
472 ++index; | 468 ++index; |
473 if (!parseTime(src, length, index, end)) | 469 if (!parseTime(src, index, end)) |
474 return false; | 470 return false; |
475 if (!withinHTMLDateLimits(m_year, m_month, m_monthDay, m_hour, m_minute, m_s
econd, m_millisecond)) | 471 if (!withinHTMLDateLimits(m_year, m_month, m_monthDay, m_hour, m_minute, m_s
econd, m_millisecond)) |
476 return false; | 472 return false; |
477 m_type = DateTimeLocal; | 473 m_type = DateTimeLocal; |
478 return true; | 474 return true; |
479 } | 475 } |
480 | 476 |
481 bool DateComponents::parseDateTime(const UChar* src, unsigned length, unsigned s
tart, unsigned& end) | 477 bool DateComponents::parseDateTime(const String& src, unsigned start, unsigned&
end) |
482 { | 478 { |
483 ASSERT(src); | |
484 unsigned index; | 479 unsigned index; |
485 if (!parseDate(src, length, start, index)) | 480 if (!parseDate(src, start, index)) |
486 return false; | 481 return false; |
487 if (index >= length) | 482 if (index >= src.length()) |
488 return false; | 483 return false; |
489 if (src[index] != 'T') | 484 if (src[index] != 'T') |
490 return false; | 485 return false; |
491 ++index; | 486 ++index; |
492 if (!parseTime(src, length, index, index)) | 487 if (!parseTime(src, index, index)) |
493 return false; | 488 return false; |
494 if (!parseTimeZone(src, length, index, end)) | 489 if (!parseTimeZone(src, index, end)) |
495 return false; | 490 return false; |
496 if (!withinHTMLDateLimits(m_year, m_month, m_monthDay, m_hour, m_minute, m_s
econd, m_millisecond)) | 491 if (!withinHTMLDateLimits(m_year, m_month, m_monthDay, m_hour, m_minute, m_s
econd, m_millisecond)) |
497 return false; | 492 return false; |
498 m_type = DateTime; | 493 m_type = DateTime; |
499 return true; | 494 return true; |
500 } | 495 } |
501 | 496 |
502 static inline double positiveFmod(double value, double divider) | 497 static inline double positiveFmod(double value, double divider) |
503 { | 498 { |
504 double remainder = fmod(value, divider); | 499 double remainder = fmod(value, divider); |
(...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
719 case Week: | 714 case Week: |
720 return String::format("%04d-W%02d", m_year, m_week); | 715 return String::format("%04d-W%02d", m_year, m_week); |
721 case Invalid: | 716 case Invalid: |
722 break; | 717 break; |
723 } | 718 } |
724 ASSERT_NOT_REACHED(); | 719 ASSERT_NOT_REACHED(); |
725 return String("(Invalid DateComponents)"); | 720 return String("(Invalid DateComponents)"); |
726 } | 721 } |
727 | 722 |
728 } // namespace WebCore | 723 } // namespace WebCore |
OLD | NEW |