| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) | 2 * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) |
| 3 * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. | 3 * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. |
| 4 * Copyright (C) 2009 Google Inc. All rights reserved. | 4 * Copyright (C) 2009 Google Inc. All rights reserved. |
| 5 * Copyright (C) 2007-2009 Torch Mobile, Inc. | 5 * Copyright (C) 2007-2009 Torch Mobile, Inc. |
| 6 * Copyright (C) 2010 &yet, LLC. (nate@andyet.net) | 6 * Copyright (C) 2010 &yet, LLC. (nate@andyet.net) |
| 7 * | 7 * |
| 8 * The Original Code is Mozilla Communicator client code, released | 8 * The Original Code is Mozilla Communicator client code, released |
| 9 * March 31, 1998. | 9 * March 31, 1998. |
| 10 * | 10 * |
| (...skipping 557 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 568 // This is a bit more lenient on the year string than ES5 specifies: | 568 // This is a bit more lenient on the year string than ES5 specifies: |
| 569 // instead of restricting to 4 digits (or 6 digits with mandatory +/-), | 569 // instead of restricting to 4 digits (or 6 digits with mandatory +/-), |
| 570 // it accepts any integer value. Consider this an implementation fallback. | 570 // it accepts any integer value. Consider this an implementation fallback. |
| 571 if (!parseInt(currentPosition, &postParsePosition, 10, &year)) | 571 if (!parseInt(currentPosition, &postParsePosition, 10, &year)) |
| 572 return 0; | 572 return 0; |
| 573 | 573 |
| 574 // Check for presence of -MM portion. | 574 // Check for presence of -MM portion. |
| 575 if (*postParsePosition != '-') | 575 if (*postParsePosition != '-') |
| 576 return postParsePosition; | 576 return postParsePosition; |
| 577 currentPosition = postParsePosition + 1; | 577 currentPosition = postParsePosition + 1; |
| 578 | 578 |
| 579 if (!isASCIIDigit(*currentPosition)) | 579 if (!isASCIIDigit(*currentPosition)) |
| 580 return 0; | 580 return 0; |
| 581 if (!parseLong(currentPosition, &postParsePosition, 10, &month)) | 581 if (!parseLong(currentPosition, &postParsePosition, 10, &month)) |
| 582 return 0; | 582 return 0; |
| 583 if ((postParsePosition - currentPosition) != 2) | 583 if ((postParsePosition - currentPosition) != 2) |
| 584 return 0; | 584 return 0; |
| 585 | 585 |
| 586 // Check for presence of -DD portion. | 586 // Check for presence of -DD portion. |
| 587 if (*postParsePosition != '-') | 587 if (*postParsePosition != '-') |
| 588 return postParsePosition; | 588 return postParsePosition; |
| 589 currentPosition = postParsePosition + 1; | 589 currentPosition = postParsePosition + 1; |
| 590 | 590 |
| 591 if (!isASCIIDigit(*currentPosition)) | 591 if (!isASCIIDigit(*currentPosition)) |
| 592 return 0; | 592 return 0; |
| 593 if (!parseLong(currentPosition, &postParsePosition, 10, &day)) | 593 if (!parseLong(currentPosition, &postParsePosition, 10, &day)) |
| 594 return 0; | 594 return 0; |
| 595 if ((postParsePosition - currentPosition) != 2) | 595 if ((postParsePosition - currentPosition) != 2) |
| 596 return 0; | 596 return 0; |
| 597 return postParsePosition; | 597 return postParsePosition; |
| 598 } | 598 } |
| 599 | 599 |
| 600 // Parses a time with the format HH:mm[:ss[.sss]][Z|(+|-)00:00]. | 600 // Parses a time with the format HH:mm[:ss[.sss]][Z|(+|-)00:00]. |
| 601 // Fractional seconds parsing is lenient, allows any number of digits. | 601 // Fractional seconds parsing is lenient, allows any number of digits. |
| 602 // Returns 0 if a parse error occurs, else returns the end of the parsed portion
of the string. | 602 // Returns 0 if a parse error occurs, else returns the end of the parsed portion
of the string. |
| 603 static char* parseES5TimePortion(char* currentPosition, long& hours, long& minut
es, double& seconds, long& timeZoneSeconds) | 603 static char* parseES5TimePortion(char* currentPosition, long& hours, long& minut
es, double& seconds, long& timeZoneSeconds) |
| 604 { | 604 { |
| 605 char* postParsePosition; | 605 char* postParsePosition; |
| 606 if (!isASCIIDigit(*currentPosition)) | 606 if (!isASCIIDigit(*currentPosition)) |
| 607 return 0; | 607 return 0; |
| 608 if (!parseLong(currentPosition, &postParsePosition, 10, &hours)) | 608 if (!parseLong(currentPosition, &postParsePosition, 10, &hours)) |
| 609 return 0; | 609 return 0; |
| 610 if (*postParsePosition != ':' || (postParsePosition - currentPosition) != 2) | 610 if (*postParsePosition != ':' || (postParsePosition - currentPosition) != 2) |
| 611 return 0; | 611 return 0; |
| 612 currentPosition = postParsePosition + 1; | 612 currentPosition = postParsePosition + 1; |
| 613 | 613 |
| 614 if (!isASCIIDigit(*currentPosition)) | 614 if (!isASCIIDigit(*currentPosition)) |
| 615 return 0; | 615 return 0; |
| 616 if (!parseLong(currentPosition, &postParsePosition, 10, &minutes)) | 616 if (!parseLong(currentPosition, &postParsePosition, 10, &minutes)) |
| 617 return 0; | 617 return 0; |
| 618 if ((postParsePosition - currentPosition) != 2) | 618 if ((postParsePosition - currentPosition) != 2) |
| 619 return 0; | 619 return 0; |
| 620 currentPosition = postParsePosition; | 620 currentPosition = postParsePosition; |
| 621 | 621 |
| 622 // Seconds are optional. | 622 // Seconds are optional. |
| 623 if (*currentPosition == ':') { | 623 if (*currentPosition == ':') { |
| 624 ++currentPosition; | 624 ++currentPosition; |
| 625 | 625 |
| 626 long intSeconds; | 626 long intSeconds; |
| 627 if (!isASCIIDigit(*currentPosition)) | 627 if (!isASCIIDigit(*currentPosition)) |
| 628 return 0; | 628 return 0; |
| 629 if (!parseLong(currentPosition, &postParsePosition, 10, &intSeconds)) | 629 if (!parseLong(currentPosition, &postParsePosition, 10, &intSeconds)) |
| 630 return 0; | 630 return 0; |
| 631 if ((postParsePosition - currentPosition) != 2) | 631 if ((postParsePosition - currentPosition) != 2) |
| 632 return 0; | 632 return 0; |
| 633 seconds = intSeconds; | 633 seconds = intSeconds; |
| 634 if (*postParsePosition == '.') { | 634 if (*postParsePosition == '.') { |
| 635 currentPosition = postParsePosition + 1; | 635 currentPosition = postParsePosition + 1; |
| 636 | 636 |
| 637 // In ECMA-262-5 it's a bit unclear if '.' can be present without mi
lliseconds, but | 637 // In ECMA-262-5 it's a bit unclear if '.' can be present without mi
lliseconds, but |
| 638 // a reasonable interpretation guided by the given examples and RFC
3339 says "no". | 638 // a reasonable interpretation guided by the given examples and RFC
3339 says "no". |
| 639 // We check the next character to avoid reading +/- timezone hours a
fter an invalid decimal. | 639 // We check the next character to avoid reading +/- timezone hours a
fter an invalid decimal. |
| 640 if (!isASCIIDigit(*currentPosition)) | 640 if (!isASCIIDigit(*currentPosition)) |
| 641 return 0; | 641 return 0; |
| 642 | 642 |
| 643 // We are more lenient than ES5 by accepting more or less than 3 fra
ction digits. | 643 // We are more lenient than ES5 by accepting more or less than 3 fra
ction digits. |
| 644 long fracSeconds; | 644 long fracSeconds; |
| 645 if (!parseLong(currentPosition, &postParsePosition, 10, &fracSeconds
)) | 645 if (!parseLong(currentPosition, &postParsePosition, 10, &fracSeconds
)) |
| 646 return 0; | 646 return 0; |
| 647 | 647 |
| 648 long numFracDigits = postParsePosition - currentPosition; | 648 long numFracDigits = postParsePosition - currentPosition; |
| 649 seconds += fracSeconds * pow(10.0, static_cast<double>(-numFracDigit
s)); | 649 seconds += fracSeconds * pow(10.0, static_cast<double>(-numFracDigit
s)); |
| 650 } | 650 } |
| 651 currentPosition = postParsePosition; | 651 currentPosition = postParsePosition; |
| 652 } | 652 } |
| 653 | 653 |
| 654 if (*currentPosition == 'Z') | 654 if (*currentPosition == 'Z') |
| 655 return currentPosition + 1; | 655 return currentPosition + 1; |
| 656 | 656 |
| 657 bool tzNegative; | 657 bool tzNegative; |
| 658 if (*currentPosition == '-') | 658 if (*currentPosition == '-') |
| 659 tzNegative = true; | 659 tzNegative = true; |
| 660 else if (*currentPosition == '+') | 660 else if (*currentPosition == '+') |
| 661 tzNegative = false; | 661 tzNegative = false; |
| 662 else | 662 else |
| 663 return currentPosition; // no timezone | 663 return currentPosition; // no timezone |
| 664 ++currentPosition; | 664 ++currentPosition; |
| 665 | 665 |
| 666 long tzHours; | 666 long tzHours; |
| 667 long tzHoursAbs; | 667 long tzHoursAbs; |
| 668 long tzMinutes; | 668 long tzMinutes; |
| 669 | 669 |
| 670 if (!isASCIIDigit(*currentPosition)) | 670 if (!isASCIIDigit(*currentPosition)) |
| 671 return 0; | 671 return 0; |
| 672 if (!parseLong(currentPosition, &postParsePosition, 10, &tzHours)) | 672 if (!parseLong(currentPosition, &postParsePosition, 10, &tzHours)) |
| 673 return 0; | 673 return 0; |
| 674 if (*postParsePosition != ':' || (postParsePosition - currentPosition) != 2) | 674 if (*postParsePosition != ':' || (postParsePosition - currentPosition) != 2) |
| 675 return 0; | 675 return 0; |
| 676 tzHoursAbs = labs(tzHours); | 676 tzHoursAbs = labs(tzHours); |
| 677 currentPosition = postParsePosition + 1; | 677 currentPosition = postParsePosition + 1; |
| 678 | 678 |
| 679 if (!isASCIIDigit(*currentPosition)) | 679 if (!isASCIIDigit(*currentPosition)) |
| 680 return 0; | 680 return 0; |
| 681 if (!parseLong(currentPosition, &postParsePosition, 10, &tzMinutes)) | 681 if (!parseLong(currentPosition, &postParsePosition, 10, &tzMinutes)) |
| 682 return 0; | 682 return 0; |
| 683 if ((postParsePosition - currentPosition) != 2) | 683 if ((postParsePosition - currentPosition) != 2) |
| 684 return 0; | 684 return 0; |
| 685 currentPosition = postParsePosition; | 685 currentPosition = postParsePosition; |
| 686 | 686 |
| 687 if (tzHoursAbs > 24) | 687 if (tzHoursAbs > 24) |
| 688 return 0; | 688 return 0; |
| 689 if (tzMinutes < 0 || tzMinutes > 59) | 689 if (tzMinutes < 0 || tzMinutes > 59) |
| 690 return 0; | 690 return 0; |
| 691 | 691 |
| 692 timeZoneSeconds = 60 * (tzMinutes + (60 * tzHoursAbs)); | 692 timeZoneSeconds = 60 * (tzMinutes + (60 * tzHoursAbs)); |
| 693 if (tzNegative) | 693 if (tzNegative) |
| 694 timeZoneSeconds = -timeZoneSeconds; | 694 timeZoneSeconds = -timeZoneSeconds; |
| 695 | 695 |
| 696 return currentPosition; | 696 return currentPosition; |
| 697 } | 697 } |
| 698 | 698 |
| 699 double parseES5DateFromNullTerminatedCharacters(const char* dateString) | 699 double parseES5DateFromNullTerminatedCharacters(const char* dateString) |
| 700 { | 700 { |
| 701 // This parses a date of the form defined in ECMA-262-5, section 15.9.1.15 | 701 // This parses a date of the form defined in ECMA-262-5, section 15.9.1.15 |
| 702 // (similar to RFC 3339 / ISO 8601: YYYY-MM-DDTHH:mm:ss[.sss]Z). | 702 // (similar to RFC 3339 / ISO 8601: YYYY-MM-DDTHH:mm:ss[.sss]Z). |
| 703 // In most cases it is intentionally strict (e.g. correct field widths, no s
tray whitespace). | 703 // In most cases it is intentionally strict (e.g. correct field widths, no s
tray whitespace). |
| 704 | 704 |
| 705 static const long daysPerMonth[12] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 3
1, 30, 31 }; | 705 static const long daysPerMonth[12] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 3
1, 30, 31 }; |
| 706 | 706 |
| 707 // The year must be present, but the other fields may be omitted - see ES5.1
15.9.1.15. | 707 // The year must be present, but the other fields may be omitted - see ES5.1
15.9.1.15. |
| 708 int year = 0; | 708 int year = 0; |
| 709 long month = 1; | 709 long month = 1; |
| 710 long day = 1; | 710 long day = 1; |
| 711 long hours = 0; | 711 long hours = 0; |
| 712 long minutes = 0; | 712 long minutes = 0; |
| 713 double seconds = 0; | 713 double seconds = 0; |
| 714 long timeZoneSeconds = 0; | 714 long timeZoneSeconds = 0; |
| 715 | 715 |
| 716 // Parse the date YYYY[-MM[-DD]] | 716 // Parse the date YYYY[-MM[-DD]] |
| (...skipping 24 matching lines...) Expand all Loading... |
| 741 if (hours == 24 && (minutes || seconds)) | 741 if (hours == 24 && (minutes || seconds)) |
| 742 return std::numeric_limits<double>::quiet_NaN(); | 742 return std::numeric_limits<double>::quiet_NaN(); |
| 743 if (minutes < 0 || minutes > 59) | 743 if (minutes < 0 || minutes > 59) |
| 744 return std::numeric_limits<double>::quiet_NaN(); | 744 return std::numeric_limits<double>::quiet_NaN(); |
| 745 if (seconds < 0 || seconds >= 61) | 745 if (seconds < 0 || seconds >= 61) |
| 746 return std::numeric_limits<double>::quiet_NaN(); | 746 return std::numeric_limits<double>::quiet_NaN(); |
| 747 if (seconds > 60) { | 747 if (seconds > 60) { |
| 748 // Discard leap seconds by clamping to the end of a minute. | 748 // Discard leap seconds by clamping to the end of a minute. |
| 749 seconds = 60; | 749 seconds = 60; |
| 750 } | 750 } |
| 751 | 751 |
| 752 double dateSeconds = ymdhmsToSeconds(year, month, day, hours, minutes, secon
ds) - timeZoneSeconds; | 752 double dateSeconds = ymdhmsToSeconds(year, month, day, hours, minutes, secon
ds) - timeZoneSeconds; |
| 753 return dateSeconds * msPerSecond; | 753 return dateSeconds * msPerSecond; |
| 754 } | 754 } |
| 755 | 755 |
| 756 // Odd case where 'exec' is allowed to be 0, to accomodate a caller in WebCore. | 756 // Odd case where 'exec' is allowed to be 0, to accomodate a caller in WebCore. |
| 757 double parseDateFromNullTerminatedCharacters(const char* dateString, bool& haveT
Z, int& offset) | 757 double parseDateFromNullTerminatedCharacters(const char* dateString, bool& haveT
Z, int& offset) |
| 758 { | 758 { |
| 759 haveTZ = false; | 759 haveTZ = false; |
| 760 offset = 0; | 760 offset = 0; |
| 761 | 761 |
| 762 // This parses a date in the form: | 762 // This parses a date in the form: |
| 763 // Tuesday, 09-Nov-99 23:12:40 GMT | 763 // Tuesday, 09-Nov-99 23:12:40 GMT |
| 764 // or | 764 // or |
| 765 // Sat, 01-Jan-2000 08:00:00 GMT | 765 // Sat, 01-Jan-2000 08:00:00 GMT |
| 766 // or | 766 // or |
| 767 // Sat, 01 Jan 2000 08:00:00 GMT | 767 // Sat, 01 Jan 2000 08:00:00 GMT |
| 768 // or | 768 // or |
| 769 // 01 Jan 99 22:00 +0100 (exceptions in rfc822/rfc2822) | 769 // 01 Jan 99 22:00 +0100 (exceptions in rfc822/rfc2822) |
| 770 // ### non RFC formats, added for Javascript: | 770 // ### non RFC formats, added for Javascript: |
| 771 // [Wednesday] January 09 1999 23:12:40 GMT | 771 // [Wednesday] January 09 1999 23:12:40 GMT |
| 772 // [Wednesday] January 09 23:12:40 GMT 1999 | 772 // [Wednesday] January 09 23:12:40 GMT 1999 |
| 773 // | 773 // |
| 774 // We ignore the weekday. | 774 // We ignore the weekday. |
| 775 | 775 |
| 776 // Skip leading space | 776 // Skip leading space |
| 777 skipSpacesAndComments(dateString); | 777 skipSpacesAndComments(dateString); |
| 778 | 778 |
| 779 long month = -1; | 779 long month = -1; |
| 780 const char *wordStart = dateString; | 780 const char *wordStart = dateString; |
| 781 // Check contents of first words if not number | 781 // Check contents of first words if not number |
| 782 while (*dateString && !isASCIIDigit(*dateString)) { | 782 while (*dateString && !isASCIIDigit(*dateString)) { |
| 783 if (isASCIISpace(*dateString) || *dateString == '(') { | 783 if (isASCIISpace(*dateString) || *dateString == '(') { |
| 784 if (dateString - wordStart >= 3) | 784 if (dateString - wordStart >= 3) |
| 785 month = findMonth(wordStart); | 785 month = findMonth(wordStart); |
| (...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 953 } else if (strncasecmp(dateString, "PM", 2) == 0) { | 953 } else if (strncasecmp(dateString, "PM", 2) == 0) { |
| 954 if (hour > 12) | 954 if (hour > 12) |
| 955 return std::numeric_limits<double>::quiet_NaN(); | 955 return std::numeric_limits<double>::quiet_NaN(); |
| 956 if (hour != 12) | 956 if (hour != 12) |
| 957 hour += 12; | 957 hour += 12; |
| 958 dateString += 2; | 958 dateString += 2; |
| 959 skipSpacesAndComments(dateString); | 959 skipSpacesAndComments(dateString); |
| 960 } | 960 } |
| 961 } | 961 } |
| 962 } | 962 } |
| 963 | 963 |
| 964 // The year may be after the time but before the time zone. | 964 // The year may be after the time but before the time zone. |
| 965 if (isASCIIDigit(*dateString) && year == -1) { | 965 if (isASCIIDigit(*dateString) && year == -1) { |
| 966 if (!parseInt(dateString, &newPosStr, 10, &year)) | 966 if (!parseInt(dateString, &newPosStr, 10, &year)) |
| 967 return std::numeric_limits<double>::quiet_NaN(); | 967 return std::numeric_limits<double>::quiet_NaN(); |
| 968 dateString = newPosStr; | 968 dateString = newPosStr; |
| 969 skipSpacesAndComments(dateString); | 969 skipSpacesAndComments(dateString); |
| 970 } | 970 } |
| 971 | 971 |
| 972 // Don't fail if the time zone is missing. | 972 // Don't fail if the time zone is missing. |
| 973 // Some websites omit the time zone (4275206). | 973 // Some websites omit the time zone (4275206). |
| 974 if (*dateString) { | 974 if (*dateString) { |
| 975 if (strncasecmp(dateString, "GMT", 3) == 0 || strncasecmp(dateString, "U
TC", 3) == 0) { | 975 if (strncasecmp(dateString, "GMT", 3) == 0 || strncasecmp(dateString, "U
TC", 3) == 0) { |
| 976 dateString += 3; | 976 dateString += 3; |
| 977 haveTZ = true; | 977 haveTZ = true; |
| 978 } | 978 } |
| 979 | 979 |
| 980 if (*dateString == '+' || *dateString == '-') { | 980 if (*dateString == '+' || *dateString == '-') { |
| 981 int o; | 981 int o; |
| 982 if (!parseInt(dateString, &newPosStr, 10, &o)) | 982 if (!parseInt(dateString, &newPosStr, 10, &o)) |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1027 if (*dateString) | 1027 if (*dateString) |
| 1028 return std::numeric_limits<double>::quiet_NaN(); | 1028 return std::numeric_limits<double>::quiet_NaN(); |
| 1029 | 1029 |
| 1030 // Y2K: Handle 2 digit years. | 1030 // Y2K: Handle 2 digit years. |
| 1031 if (year >= 0 && year < 100) { | 1031 if (year >= 0 && year < 100) { |
| 1032 if (year < 50) | 1032 if (year < 50) |
| 1033 year += 2000; | 1033 year += 2000; |
| 1034 else | 1034 else |
| 1035 year += 1900; | 1035 year += 1900; |
| 1036 } | 1036 } |
| 1037 | 1037 |
| 1038 return ymdhmsToSeconds(year, month + 1, day, hour, minute, second) * msPerSe
cond; | 1038 return ymdhmsToSeconds(year, month + 1, day, hour, minute, second) * msPerSe
cond; |
| 1039 } | 1039 } |
| 1040 | 1040 |
| 1041 double parseDateFromNullTerminatedCharacters(const char* dateString) | 1041 double parseDateFromNullTerminatedCharacters(const char* dateString) |
| 1042 { | 1042 { |
| 1043 bool haveTZ; | 1043 bool haveTZ; |
| 1044 int offset; | 1044 int offset; |
| 1045 double ms = parseDateFromNullTerminatedCharacters(dateString, haveTZ, offset
); | 1045 double ms = parseDateFromNullTerminatedCharacters(dateString, haveTZ, offset
); |
| 1046 if (std::isnan(ms)) | 1046 if (std::isnan(ms)) |
| 1047 return std::numeric_limits<double>::quiet_NaN(); | 1047 return std::numeric_limits<double>::quiet_NaN(); |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1086 | 1086 |
| 1087 stringBuilder.append(utcOffset > 0 ? '+' : '-'); | 1087 stringBuilder.append(utcOffset > 0 ? '+' : '-'); |
| 1088 int absoluteUTCOffset = abs(utcOffset); | 1088 int absoluteUTCOffset = abs(utcOffset); |
| 1089 stringBuilder.append(twoDigitStringFromNumber(absoluteUTCOffset / 60)); | 1089 stringBuilder.append(twoDigitStringFromNumber(absoluteUTCOffset / 60)); |
| 1090 stringBuilder.append(twoDigitStringFromNumber(absoluteUTCOffset % 60)); | 1090 stringBuilder.append(twoDigitStringFromNumber(absoluteUTCOffset % 60)); |
| 1091 | 1091 |
| 1092 return stringBuilder.toString(); | 1092 return stringBuilder.toString(); |
| 1093 } | 1093 } |
| 1094 | 1094 |
| 1095 } // namespace WTF | 1095 } // namespace WTF |
| OLD | NEW |