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 |