From 19e6bcffdbf88cf2413699e6cfbd493ca3cba0a8 Mon Sep 17 00:00:00 2001 From: Dan Sinclair Date: Tue, 13 Jun 2017 11:53:19 -0400 Subject: Add CFGAS_FormatString helper to extract digits. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This CL adds ExtractCountDigits and ExtractCountDigitsWithOptional to cleanup the digit extraction code. Change-Id: I6c3f4b435ec41b429b18cd9af9be46551a7fa391 Reviewed-on: https://pdfium-review.googlesource.com/6391 Commit-Queue: dsinclair Reviewed-by: Nicolás Peña --- xfa/fgas/crt/cfgas_formatstring.cpp | 358 ++++++++++++--------------- xfa/fgas/crt/cfgas_formatstring_unittest.cpp | 21 +- 2 files changed, 164 insertions(+), 215 deletions(-) diff --git a/xfa/fgas/crt/cfgas_formatstring.cpp b/xfa/fgas/crt/cfgas_formatstring.cpp index d67af97038..a9e5f7c795 100644 --- a/xfa/fgas/crt/cfgas_formatstring.cpp +++ b/xfa/fgas/crt/cfgas_formatstring.cpp @@ -198,14 +198,40 @@ bool GetNumericDotIndex(const CFX_WideString& wsNum, return false; } +bool ExtractCountDigits(const wchar_t* str, + int len, + int count, + int* cc, + uint32_t* value) { + for (int i = count; i > 0; --i) { + if (*cc >= len) + return false; + if (!FXSYS_isDecimalDigit(str[*cc])) + return false; + *value = *value * 10 + FXSYS_DecimalCharToInt(str[(*cc)++]); + } + return true; +} + +bool ExtractCountDigitsWithOptional(const wchar_t* str, + int len, + int count, + int* cc, + uint32_t* value) { + if (!ExtractCountDigits(str, len, count, cc, value)) + return false; + ExtractCountDigits(str, len, 1, cc, value); + return true; +} + bool ParseLocaleDate(const CFX_WideString& wsDate, const CFX_WideString& wsDatePattern, IFX_Locale* pLocale, CFX_DateTime* datetime, int32_t* cc) { - int32_t year = 1900; - int32_t month = 1; - int32_t day = 1; + uint32_t year = 1900; + uint32_t month = 1; + uint32_t day = 1; int32_t ccf = 0; const wchar_t* str = wsDate.c_str(); int32_t len = wsDate.GetLength(); @@ -238,25 +264,16 @@ bool ParseLocaleDate(const CFX_WideString& wsDate, symbol += strf[ccf++]; if (symbol == L"D" || symbol == L"DD") { - if (!FXSYS_isDecimalDigit(str[*cc])) + day = 0; + if (!ExtractCountDigitsWithOptional(str, len, 1, cc, &day)) return false; - - day = FXSYS_DecimalCharToInt(str[(*cc)++]); - if (*cc < len && (symbol == L"DD" || FXSYS_isDecimalDigit(str[*cc]))) - day = day * 10 + FXSYS_DecimalCharToInt(str[(*cc)++]); } else if (symbol == L"J") { - int i = 0; - while (*cc < len && i < 3 && FXSYS_isDecimalDigit(str[*cc])) { - (*cc)++; - i++; - } + uint32_t val = 0; + ExtractCountDigits(str, len, 3, cc, &val); } else if (symbol == L"M" || symbol == L"MM") { - if (!FXSYS_isDecimalDigit(str[*cc])) + month = 0; + if (!ExtractCountDigitsWithOptional(str, len, 1, cc, &month)) return false; - - month = FXSYS_DecimalCharToInt(str[(*cc)++]); - if (*cc < len && (symbol == L"MM" || FXSYS_isDecimalDigit(str[*cc]))) - month = month * 10 + FXSYS_DecimalCharToInt(str[(*cc)++]); } else if (symbol == L"MMM" || symbol == L"MMMM") { for (uint16_t i = 0; i < 12; i++) { CFX_WideString wsMonthName = pLocale->GetMonthName(i, symbol == L"MMM"); @@ -283,12 +300,8 @@ bool ParseLocaleDate(const CFX_WideString& wsDate, return false; year = 0; - for (int i = 0; i < symbol.GetLength(); ++i) { - if (!FXSYS_isDecimalDigit(str[*cc])) - return false; - year = year * 10 + FXSYS_DecimalCharToInt(str[(*cc)++]); - } - + if (!ExtractCountDigits(str, len, symbol.GetLength(), cc, &year)) + return false; if (symbol == L"YY") { if (year <= 29) year += 2000; @@ -311,8 +324,8 @@ bool ParseLocaleDate(const CFX_WideString& wsDate, void ResolveZone(FX_TIMEZONE tzDiff, IFX_Locale* pLocale, - uint8_t* wHour, - uint8_t* wMinute) { + uint32_t* wHour, + uint32_t* wMinute) { int32_t iMinuteDiff = *wHour * 60 + *wMinute; FX_TIMEZONE tzLocale = pLocale->GetTimeZone(); iMinuteDiff += tzLocale.tzHour * 60 + @@ -333,10 +346,10 @@ bool ParseLocaleTime(const CFX_WideString& wsTime, IFX_Locale* pLocale, CFX_DateTime* datetime, int32_t* cc) { - uint8_t hour = 0; - uint8_t minute = 0; - uint8_t second = 0; - uint16_t millisecond = 0; + uint32_t hour = 0; + uint32_t minute = 0; + uint32_t second = 0; + uint32_t millisecond = 0; int32_t ccf = 0; const wchar_t* str = wsTime.c_str(); int len = wsTime.GetLength(); @@ -372,76 +385,38 @@ bool ParseLocaleTime(const CFX_WideString& wsTime, symbol += strf[ccf++]; if (symbol == L"k" || symbol == L"K" || symbol == L"h" || symbol == L"H") { - if (!FXSYS_isDecimalDigit(str[*cc])) + hour = 0; + if (!ExtractCountDigitsWithOptional(str, len, 1, cc, &hour)) return false; - - hour = FXSYS_DecimalCharToInt(str[(*cc)++]); - if (*cc < len && FXSYS_isDecimalDigit(str[*cc])) - hour = hour * 10 + FXSYS_DecimalCharToInt(str[(*cc)++]); if (symbol == L"K" && hour == 24) hour = 0; } else if (symbol == L"kk" || symbol == L"KK" || symbol == L"hh" || symbol == L"HH") { - if (!FXSYS_isDecimalDigit(str[*cc])) - return false; - - hour = FXSYS_DecimalCharToInt(str[(*cc)++]); - if (*cc >= len) - return false; - if (!FXSYS_isDecimalDigit(str[*cc])) + hour = 0; + if (!ExtractCountDigits(str, len, 2, cc, &hour)) return false; - - hour = hour * 10 + FXSYS_DecimalCharToInt(str[(*cc)++]); if (symbol == L"KK" && hour == 24) hour = 0; } else if (symbol == L"M") { - if (!FXSYS_isDecimalDigit(str[*cc])) + minute = 0; + if (!ExtractCountDigitsWithOptional(str, len, 1, cc, &minute)) return false; - - minute = FXSYS_DecimalCharToInt(str[(*cc)++]); - if (*cc < len && FXSYS_isDecimalDigit(str[*cc])) - minute = minute * 10 + FXSYS_DecimalCharToInt(str[(*cc)++]); } else if (symbol == L"MM") { - if (!FXSYS_isDecimalDigit(str[*cc])) + minute = 0; + if (!ExtractCountDigits(str, len, 2, cc, &minute)) return false; - - minute = FXSYS_DecimalCharToInt(str[(*cc)++]); - if (*cc >= len) - return false; - if (!FXSYS_isDecimalDigit(str[*cc])) - return false; - - minute = minute * 10 + FXSYS_DecimalCharToInt(str[(*cc)++]); } else if (symbol == L"S") { - if (!FXSYS_isDecimalDigit(str[*cc])) + second = 0; + if (!ExtractCountDigitsWithOptional(str, len, 1, cc, &second)) return false; - - second = FXSYS_DecimalCharToInt(str[(*cc)++]); - if (*cc < len && FXSYS_isDecimalDigit(str[*cc])) - second = second * 10 + FXSYS_DecimalCharToInt(str[(*cc)++]); } else if (symbol == L"SS") { - if (!FXSYS_isDecimalDigit(str[*cc])) - return false; - - second = FXSYS_DecimalCharToInt(str[(*cc)++]); - if (*cc >= len) + second = 0; + if (!ExtractCountDigits(str, len, 2, cc, &second)) return false; - if (!FXSYS_isDecimalDigit(str[*cc])) - return false; - - second = second * 10 + FXSYS_DecimalCharToInt(str[(*cc)++]); } else if (symbol == L"FFF") { - if (*cc + 3 >= len) + millisecond = 0; + if (!ExtractCountDigits(str, len, 3, cc, &millisecond)) return false; - - int i = 0; - while (i < 3) { - if (!FXSYS_isDecimalDigit(str[*cc])) - return false; - - millisecond = millisecond * 10 + FXSYS_DecimalCharToInt(str[(*cc)++]); - i++; - } } else if (symbol == L"A") { CFX_WideString wsAM = pLocale->GetMeridiemName(true); CFX_WideString wsPM = pLocale->GetMeridiemName(false); @@ -524,13 +499,24 @@ int32_t GetNumTrailingLimit(const CFX_WideString& wsFormat, return iTreading; } +bool IsLeapYear(uint32_t year) { + return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0; +} + +bool MonthHas30Days(uint32_t month) { + return month == 4 || month == 6 || month == 9 || month == 11; +} + +bool MonthHas31Days(uint32_t month) { + return month != 2 && !MonthHas30Days(month); +} + // |month| is 1-based. e.g. 1 means January. uint16_t GetSolarMonthDays(uint16_t year, uint16_t month) { if (month == 2) return FX_IsLeapYear(year) ? 29 : 28; - if (month == 4 || month == 6 || month == 9 || month == 11) - return 30; - return 31; + + return MonthHas30Days(month) ? 30 : 31; } uint16_t GetWeekDay(uint16_t year, uint16_t month, uint16_t day) { @@ -729,71 +715,49 @@ CFX_WideString FormatDateTimeInternal(const CFX_DateTime& dt, bool FX_DateFromCanonical(const CFX_WideString& wsDate, CFX_DateTime* datetime) { - int32_t year = 1900; - int32_t month = 1; - int32_t day = 1; - uint16_t wYear = 0; - int cc_start = 0; - int cc = 0; const wchar_t* str = wsDate.c_str(); int len = wsDate.GetLength(); if (len > 10) return false; - while (cc < len && cc < 4) { - if (!FXSYS_isDecimalDigit(str[cc])) - return false; - - wYear = wYear * 10 + FXSYS_DecimalCharToInt(str[cc++]); - } - year = wYear; - if (cc < 4 || wYear < 1900) + int cc = 0; + uint32_t year = 0; + if (!ExtractCountDigits(str, len, 4, &cc, &year)) return false; + if (year < 1900) + return false; + if (cc >= len) { + datetime->SetDate(year, 1, 1); + return true; + } - if (cc < len) { - if (str[cc] == '-') - cc++; - - cc_start = cc; - uint8_t tmpM = 0; - while (cc < len && cc < cc_start + 2) { - if (!FXSYS_isDecimalDigit(str[cc])) - return false; - - tmpM = tmpM * 10 + FXSYS_DecimalCharToInt(str[cc++]); - } - month = tmpM; - if (cc == cc_start + 1 || tmpM > 12 || tmpM < 1) - return false; - if (cc < len) { - if (str[cc] == '-') - cc++; + if (str[cc] == '-') + cc++; - uint8_t tmpD = 0; - cc_start = cc; - while (cc < len && cc < cc_start + 2) { - if (!FXSYS_isDecimalDigit(str[cc])) - return false; + uint32_t month = 0; + if (!ExtractCountDigits(str, len, 2, &cc, &month)) + return false; + if (month > 12 || month < 1) + return false; + if (cc >= len) { + datetime->SetDate(year, month, 1); + return true; + } - tmpD = tmpD * 10 + FXSYS_DecimalCharToInt(str[cc++]); - } - day = tmpD; - if (tmpD < 1) - return false; - if ((tmpM == 1 || tmpM == 3 || tmpM == 5 || tmpM == 7 || tmpM == 8 || - tmpM == 10 || tmpM == 12) && - tmpD > 31) { - return false; - } - if ((tmpM == 4 || tmpM == 6 || tmpM == 9 || tmpM == 11) && tmpD > 30) - return false; + if (str[cc] == '-') + cc++; - bool iLeapYear = - ((wYear % 4 == 0 && wYear % 100 != 0) || wYear % 400 == 0); - if (tmpM == 2 && tmpD > (iLeapYear ? 29 : 28)) - return false; - } + uint32_t day = 0; + if (!ExtractCountDigits(str, len, 2, &cc, &day)) + return false; + if (day < 1) + return false; + if ((MonthHas31Days(month) && day > 31) || + (MonthHas30Days(month) && day > 30)) { + return false; } + if (month == 2 && day > (IsLeapYear(year) ? 29U : 28U)) + return false; datetime->SetDate(year, month, day); return true; @@ -805,86 +769,68 @@ bool FX_TimeFromCanonical(const CFX_WideStringC& wsTime, if (wsTime.GetLength() == 0) return false; - uint8_t hour = 0; - uint8_t minute = 0; - uint8_t second = 0; - uint16_t millisecond = 0; - int cc_start = 0; - int cc = 0; const wchar_t* str = wsTime.c_str(); int len = wsTime.GetLength(); - while (cc < len && cc < 2) { - if (!FXSYS_isDecimalDigit(str[cc])) - return false; - - hour = hour * 10 + FXSYS_DecimalCharToInt(str[cc++]); - } - if (cc < 2 || hour >= 24) + int cc = 0; + uint32_t hour = 0; + if (!ExtractCountDigits(str, len, 2, &cc, &hour)) return false; - if (cc < len) { - if (str[cc] == ':') - cc++; - - cc_start = cc; - while (cc < len && cc < cc_start + 2) { - if (!FXSYS_isDecimalDigit(str[cc])) - return false; + if (hour >= 24) + return false; + if (cc >= len) { + datetime->SetTime(hour, 0, 0, 0); + return true; + } - minute = minute * 10 + FXSYS_DecimalCharToInt(str[cc++]); - } - if (cc == cc_start + 1 || minute >= 60) - return false; + if (str[cc] == ':') + cc++; - if (cc < len) { - if (str[cc] == ':') - cc++; + uint32_t minute = 0; + if (!ExtractCountDigits(str, len, 2, &cc, &minute)) + return false; + if (minute >= 60) + return false; - if (str[cc] != 'Z') { - cc_start = cc; - while (cc < len && cc < cc_start + 2) { - if (!FXSYS_isDecimalDigit(str[cc])) - return false; + if (cc >= len) { + datetime->SetTime(hour, minute, 0, 0); + return true; + } - second = second * 10 + FXSYS_DecimalCharToInt(str[cc++]); - } - if (cc == cc_start + 1 || second >= 60) - return false; - if (cc < len) { - if (str[cc] == '.') { - cc++; - cc_start = cc; - while (cc < len && cc < cc_start + 3) { - if (!FXSYS_isDecimalDigit(str[cc])) - return false; + if (str[cc] == ':') + cc++; - millisecond = - millisecond * 10 + FXSYS_DecimalCharToInt(str[cc++]); - } - if (cc < cc_start + 3) - return false; - } - } - } + uint32_t second = 0; + uint32_t millisecond = 0; + if (str[cc] != 'Z') { + if (!ExtractCountDigits(str, len, 2, &cc, &second)) + return false; + if (second >= 60) + return false; + if (cc < len && str[cc] == '.') { + cc++; + if (!ExtractCountDigits(str, len, 3, &cc, &millisecond)) + return false; + } + } - // Skip until we find a + or - for the time zone. - while (cc < len) { - if (str[cc] == '+' || str[cc] == '-') - break; - ++cc; - } + // Skip until we find a + or - for the time zone. + while (cc < len) { + if (str[cc] == '+' || str[cc] == '-') + break; + ++cc; + } - if (cc < len) { - FX_TIMEZONE tzDiff; - tzDiff.tzHour = 0; - tzDiff.tzMinute = 0; - if (str[cc] != 'Z') - cc += ParseTimeZone(str + cc, len - cc, &tzDiff); + if (cc < len) { + FX_TIMEZONE tzDiff; + tzDiff.tzHour = 0; + tzDiff.tzMinute = 0; + if (str[cc] != 'Z') + cc += ParseTimeZone(str + cc, len - cc, &tzDiff); - ResolveZone(tzDiff, pLocale, &hour, &minute); - } - } + ResolveZone(tzDiff, pLocale, &hour, &minute); } + datetime->SetTime(hour, minute, second, millisecond); return true; } diff --git a/xfa/fgas/crt/cfgas_formatstring_unittest.cpp b/xfa/fgas/crt/cfgas_formatstring_unittest.cpp index 32bb23b22c..3adcedf7b2 100644 --- a/xfa/fgas/crt/cfgas_formatstring_unittest.cpp +++ b/xfa/fgas/crt/cfgas_formatstring_unittest.cpp @@ -177,15 +177,18 @@ TEST_F(CFGAS_FormatStringTest, DateTimeFormat) { const wchar_t* input; const wchar_t* pattern; const wchar_t* output; - } tests[] = {{L"en", L"1999-07-16T10:30Z", - L"'At' time{HH:MM Z} 'on' date{MMM DD, YYYY}", - L"At 10:30 GMT on Jul 16, 1999"}, - {L"en", L"1999-07-16T10:30Z", - L"time{'At' HH:MM Z} date{'on' MMM DD, YYYY}", - L"At 10:30 GMT on Jul 16, 1999"}, - {L"en", L"1999-07-16T10:30Z", - L"time{'At 'HH:MM Z}date{' on 'MMM DD, YYYY}", - L"At 10:30 GMT on Jul 16, 1999"}}; + } tests[] = { + {L"en", L"1999-07-16T10:30Z", + L"'At' time{HH:MM Z} 'on' date{MMM DD, YYYY}", + L"At 10:30 GMT on Jul 16, 1999"}, + {L"en", L"1999-07-16T10:30", L"'At' time{HH:MM} 'on' date{MMM DD, YYYY}", + L"At 10:30 on Jul 16, 1999"}, + {L"en", L"1999-07-16T10:30Z", + L"time{'At' HH:MM Z} date{'on' MMM DD, YYYY}", + L"At 10:30 GMT on Jul 16, 1999"}, + {L"en", L"1999-07-16T10:30Z", + L"time{'At 'HH:MM Z}date{' on 'MMM DD, YYYY}", + L"At 10:30 GMT on Jul 16, 1999"}}; for (size_t i = 0; i < FX_ArraySize(tests); ++i) { CFX_WideString result; -- cgit v1.2.3