Order of day or month and time or year needs to be considered. The year also needs to be adjusted correctly.
-- v4: wininet/internet: Fix year parsing to include millennium. wininet/internet: Fix parsing order of http times. wininet/tests: Add more http time test strings.
From: Jacob Czekalla jczekalla@codeweavers.com
--- dlls/wininet/tests/internet.c | 9 +++++++++ 1 file changed, 9 insertions(+)
diff --git a/dlls/wininet/tests/internet.c b/dlls/wininet/tests/internet.c index f2579c4993a..e8f6d6de459 100644 --- a/dlls/wininet/tests/internet.c +++ b/dlls/wininet/tests/internet.c @@ -1105,6 +1105,10 @@ static void test_InternetTimeToSystemTime(void) WCHAR buffer[64]; static const SYSTEMTIME expect1 = { 2005, 1, 5, 7, 12, 6, 35, 0 }; static const SYSTEMTIME expect2 = { 2022, 1, 2, 11, 11, 13, 5, 0 }; + static const SYSTEMTIME expect3 = { 1999, 1, 5, 7, 12, 6, 35, 0 }; + static const SYSTEMTIME expect4 = { 100, 1, 5, 7, 12, 6, 35, 0 }; + static const SYSTEMTIME expect5 = { 1600, 1, 5, 7, 12, 6, 35, 0 }; + static const SYSTEMTIME expect6 = { 30828, 1, 5, 7, 12, 6, 35, 0 };
static const struct test_data { @@ -1131,6 +1135,11 @@ static void test_InternetTimeToSystemTime(void) { "Fri Jan 7 12:06:35 2005", &expect1, TRUE, TRUE }, { "Fri Jan 7 12:06:35 2005 GMT", &expect1, TRUE, TRUE }, { "Fri Jan 7 12:06:35 2005 UTC", &expect1, TRUE, TRUE }, + { "Fri, 7-Jan-05 12:06:35 GMT", &expect1, TRUE, TRUE }, + { "Fri Jan 7 12:06:35 99 UTC", &expect3, TRUE, TRUE }, + { "Fri Jan 7 12:06:35 100 UTC", &expect4, TRUE, TRUE }, + { "Fri Jan 7 12:06:35 1600 UTC", &expect5, TRUE, TRUE }, + { "Fri Jan 7 12:06:35 30828 UTC", &expect6, TRUE, TRUE } };
ret = pInternetTimeToSystemTimeA(NULL, NULL, 0);
From: Jacob Czekalla jczekalla@codeweavers.com
Order of day or month and time or year needs to be considered. --- dlls/wininet/internet.c | 136 ++++++++++++++++++++++++---------- dlls/wininet/tests/internet.c | 12 +-- 2 files changed, 102 insertions(+), 46 deletions(-)
diff --git a/dlls/wininet/internet.c b/dlls/wininet/internet.c index 17a7ce9385e..4d410e5f57b 100644 --- a/dlls/wininet/internet.c +++ b/dlls/wininet/internet.c @@ -3960,6 +3960,78 @@ BOOL WINAPI InternetTimeToSystemTimeA( LPCSTR string, SYSTEMTIME* time, DWORD re return ret; }
+static BOOL calc_month(SYSTEMTIME* time, const WCHAR **s) +{ + WCHAR *end; + + time->wMonth = 0; + if (**s == '\0') return TRUE; + + if (iswalpha(**s)) + { + if ((*s)[1] == '\0' || (*s)[2] == '\0') return TRUE; + for (int i = 0; i < 12; i++) + { + if (!wcsnicmp(WININET_month[i], *s, 3)) + { + time->wMonth = i + 1; + *s += 3; + break; + } + } + } + else if (is_time_digit(**s)) + { + time->wMonth = wcstol(*s, &end, 10); + *s = end; + } + return (time->wMonth == 0); +} + +static void calc_day(SYSTEMTIME* time, const WCHAR **s) +{ + WCHAR *end; + + time->wDay = wcstol( *s, &end, 10 ); + *s = end; +} + +static BOOL calc_time(SYSTEMTIME* time, const WCHAR **s) +{ + WCHAR *end; + + if (**s == '\0') return TRUE; + time->wHour = wcstol( *s, &end, 10 ); + *s = end; + + while (**s && !is_time_digit(**s)) (*s)++; + if (**s == '\0') return TRUE; + time->wMinute = wcstol( *s, &end, 10 ); + *s = end; + + while (**s && !is_time_digit(**s)) (*s)++; + if (**s == '\0') return TRUE; + time->wSecond = wcstol( *s, &end, 10 ); + *s = end; + + time->wMilliseconds = 0; + return FALSE; +} + +static BOOL calc_year(SYSTEMTIME* time, const WCHAR **s) +{ + WCHAR *end; + + time->wYear = wcstol( *s, &end, 10 ); + *s = end; + return FALSE; +} + +static BOOL is_time(const WCHAR *s) +{ + return (s[1] == L':' || s[2] == L':'); +} + /*********************************************************************** * InternetTimeToSystemTimeW (WININET.@) */ @@ -3992,6 +4064,7 @@ BOOL WINAPI InternetTimeToSystemTimeW( LPCWSTR string, SYSTEMTIME* time, DWORD r if (!wcsnicmp(WININET_wkday[i], s, 3)) { time->wDayOfWeek = i; + s += 3; break; } } @@ -4003,54 +4076,37 @@ BOOL WINAPI InternetTimeToSystemTimeW( LPCWSTR string, SYSTEMTIME* time, DWORD r } if (time->wDayOfWeek > 6) return TRUE;
- while (*s && !is_time_digit(*s)) s++; - time->wDay = wcstol( s, &end, 10 ); - s = end; - while (*s && !iswalpha(*s) && !is_time_digit(*s)) s++; if (*s == '\0') return TRUE; - time->wMonth = 0; - - if (iswalpha(*s)) + if (is_time_digit(*s)) { - if (s[1] == '\0' || s[2] == '\0') return TRUE; - for (i = 0; i < 12; i++) - { - if (!wcsnicmp(WININET_month[i], s, 3)) - { - time->wMonth = i + 1; - break; - } - } - } - else if (is_time_digit(*s)) + calc_day(time, &s); + while (*s && !iswalpha(*s) && !is_time_digit(*s)) s++; + if (calc_month(time, &s)) + return TRUE; + }else { - time->wMonth = wcstol(s, &end, 10); - s = end; + if (calc_month(time, &s)) + return TRUE; + while (*s && !iswalpha(*s) && !is_time_digit(*s)) s++; + calc_day(time, &s); } - if (time->wMonth == 0) return TRUE; - - while (*s && !is_time_digit(*s)) s++; - if (*s == '\0') return TRUE; - time->wYear = wcstol( s, &end, 10 ); - s = end; - - while (*s && !is_time_digit(*s)) s++; - if (*s == '\0') return TRUE; - time->wHour = wcstol( s, &end, 10 ); - s = end;
while (*s && !is_time_digit(*s)) s++; if (*s == '\0') return TRUE; - time->wMinute = wcstol( s, &end, 10 ); - s = end; - - while (*s && !is_time_digit(*s)) s++; - if (*s == '\0') return TRUE; - time->wSecond = wcstol( s, &end, 10 ); - s = end; - - time->wMilliseconds = 0; + if (is_time(s)) + { + if (calc_time(time, &s)) + return TRUE; + while (*s && !is_time_digit(*s)) s++; + calc_year(time, &s); + }else + { + if (calc_year(time, &s)) + return TRUE; + while (*s && !is_time_digit(*s)) s++; + calc_time(time, &s); + } return TRUE; }
diff --git a/dlls/wininet/tests/internet.c b/dlls/wininet/tests/internet.c index e8f6d6de459..84b62d3b32d 100644 --- a/dlls/wininet/tests/internet.c +++ b/dlls/wininet/tests/internet.c @@ -1132,14 +1132,14 @@ static void test_InternetTimeToSystemTime(void) { "2, 11*01/2022 11+13=05", &expect2, TRUE }, { "2, 11-Jan-2022 11:13:05", &expect2, TRUE }, { "Fr", NULL, FALSE }, - { "Fri Jan 7 12:06:35 2005", &expect1, TRUE, TRUE }, - { "Fri Jan 7 12:06:35 2005 GMT", &expect1, TRUE, TRUE }, - { "Fri Jan 7 12:06:35 2005 UTC", &expect1, TRUE, TRUE }, + { "Fri Jan 7 12:06:35 2005", &expect1, TRUE }, + { "Fri Jan 7 12:06:35 2005 GMT", &expect1, TRUE }, + { "Fri Jan 7 12:06:35 2005 UTC", &expect1, TRUE }, { "Fri, 7-Jan-05 12:06:35 GMT", &expect1, TRUE, TRUE }, { "Fri Jan 7 12:06:35 99 UTC", &expect3, TRUE, TRUE }, - { "Fri Jan 7 12:06:35 100 UTC", &expect4, TRUE, TRUE }, - { "Fri Jan 7 12:06:35 1600 UTC", &expect5, TRUE, TRUE }, - { "Fri Jan 7 12:06:35 30828 UTC", &expect6, TRUE, TRUE } + { "Fri Jan 7 12:06:35 100 UTC", &expect4, TRUE }, + { "Fri Jan 7 12:06:35 1600 UTC", &expect5, TRUE }, + { "Fri Jan 7 12:06:35 30828 UTC", &expect6, TRUE } };
ret = pInternetTimeToSystemTimeA(NULL, NULL, 0);
From: Jacob Czekalla jczekalla@codeweavers.com
Time strings like "25" were parsed as-is instead of "2025". --- dlls/wininet/internet.c | 12 ++++++++++++ dlls/wininet/tests/internet.c | 4 ++-- 2 files changed, 14 insertions(+), 2 deletions(-)
diff --git a/dlls/wininet/internet.c b/dlls/wininet/internet.c index 4d410e5f57b..ea278304bfd 100644 --- a/dlls/wininet/internet.c +++ b/dlls/wininet/internet.c @@ -4021,8 +4021,20 @@ static BOOL calc_time(SYSTEMTIME* time, const WCHAR **s) static BOOL calc_year(SYSTEMTIME* time, const WCHAR **s) { WCHAR *end; + WORD current_year = time->wYear; + WORD current_millennium;
+ if (**s == '\0') return TRUE; time->wYear = wcstol( *s, &end, 10 ); + if (100 > time->wYear) + { + current_millennium = current_year - (current_year % 1000); + if (time->wYear + current_millennium > current_year) + time->wYear += (current_millennium - 100); + else + time->wYear += current_millennium; + } + *s = end; return FALSE; } diff --git a/dlls/wininet/tests/internet.c b/dlls/wininet/tests/internet.c index 84b62d3b32d..0dbef68ebf2 100644 --- a/dlls/wininet/tests/internet.c +++ b/dlls/wininet/tests/internet.c @@ -1135,8 +1135,8 @@ static void test_InternetTimeToSystemTime(void) { "Fri Jan 7 12:06:35 2005", &expect1, TRUE }, { "Fri Jan 7 12:06:35 2005 GMT", &expect1, TRUE }, { "Fri Jan 7 12:06:35 2005 UTC", &expect1, TRUE }, - { "Fri, 7-Jan-05 12:06:35 GMT", &expect1, TRUE, TRUE }, - { "Fri Jan 7 12:06:35 99 UTC", &expect3, TRUE, TRUE }, + { "Fri, 7-Jan-05 12:06:35 GMT", &expect1, TRUE }, + { "Fri Jan 7 12:06:35 99 UTC", &expect3, TRUE }, { "Fri Jan 7 12:06:35 100 UTC", &expect4, TRUE }, { "Fri Jan 7 12:06:35 1600 UTC", &expect5, TRUE }, { "Fri Jan 7 12:06:35 30828 UTC", &expect6, TRUE }
Jacek Caban (@jacek) commented about dlls/wininet/internet.c:
static BOOL calc_year(SYSTEMTIME* time, const WCHAR **s) { WCHAR *end;
WORD current_year = time->wYear;
WORD current_millennium;
if (**s == '\0') return TRUE; time->wYear = wcstol( *s, &end, 10 );
if (100 > time->wYear)
{
current_millennium = current_year - (current_year % 1000);
if (time->wYear + current_millennium > current_year)
time->wYear += (current_millennium - 100);
else
time->wYear += current_millennium;
This doesn't seem reliable, since it prevents using the short form for future dates. A quick check on Windows suggests that 80 is used to distinguish between the 1900s and the 2000s. I'm also not sure we should rely on the current time to pick the millennium, it seems reasonable to hardcode that so the short form remains consistent, and expect the long form for dates past 2080.