Move another chunk of code to fx_date_helper.cpp.
In this step, several methods need to become public as they are
used both locally and in cjs_publicmethods.cpp. Same too for the
kMonth/kFullMonth arrays (now namespaced).
Move the non-JS parts of ParseDateUsingFormat as well.
Change-Id: Iff19a3aa94be39bf84d694f2b2e02224e0a36300
Reviewed-on: https://pdfium-review.googlesource.com/c/45032
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Tom Sepez <tsepez@chromium.org>
diff --git a/fxjs/cjs_publicmethods.cpp b/fxjs/cjs_publicmethods.cpp
index e26af63..436e802 100644
--- a/fxjs/cjs_publicmethods.cpp
+++ b/fxjs/cjs_publicmethods.cpp
@@ -66,15 +66,6 @@
constexpr double kDoubleCorrect = 0.000000000000001;
#endif
-constexpr const wchar_t* kMonths[] = {L"Jan", L"Feb", L"Mar", L"Apr",
- L"May", L"Jun", L"Jul", L"Aug",
- L"Sep", L"Oct", L"Nov", L"Dec"};
-
-constexpr const wchar_t* kFullMonths[] = {L"January", L"February", L"March",
- L"April", L"May", L"June",
- L"July", L"August", L"September",
- L"October", L"November", L"December"};
-
constexpr const wchar_t* kDateFormats[] = {L"m/d",
L"m/d/yy",
L"mm/dd/yy",
@@ -207,27 +198,6 @@
str->Replace(L",", L".");
}
-bool IsValidMonth(int m) {
- return m >= 1 && m <= 12;
-}
-
-// TODO(thestig): Should this take the month into consideration?
-bool IsValidDay(int d) {
- return d >= 1 && d <= 31;
-}
-
-// TODO(thestig): Should 24 be allowed? Similarly, 60 for minutes and seconds.
-bool IsValid24Hour(int h) {
- return h >= 0 && h <= 24;
-}
-
-bool IsValidMinute(int m) {
- return m >= 0 && m <= 60;
-}
-
-bool IsValidSecond(int s) {
- return s >= 0 && s <= 60;
-}
} // namespace
@@ -406,10 +376,10 @@
// TODO(thestig): Should the else case set |bWrongFormat| to true?
// case2: month/day
// case3: day/month
- if (IsValidMonth(number[0]) && IsValidDay(number[1])) {
+ if (FX_IsValidMonth(number[0]) && FX_IsValidDay(number[1])) {
nMonth = number[0];
nDay = number[1];
- } else if (IsValidDay(number[0]) && IsValidMonth(number[1])) {
+ } else if (FX_IsValidDay(number[0]) && FX_IsValidMonth(number[1])) {
nDay = number[0];
nMonth = number[1];
}
@@ -421,16 +391,17 @@
// case1: year/month/day
// case2: month/day/year
// case3: day/month/year
- if (number[0] > 12 && IsValidMonth(number[1]) && IsValidDay(number[2])) {
+ if (number[0] > 12 && FX_IsValidMonth(number[1]) &&
+ FX_IsValidDay(number[2])) {
nYear = number[0];
nMonth = number[1];
nDay = number[2];
- } else if (IsValidMonth(number[0]) && IsValidDay(number[1]) &&
+ } else if (FX_IsValidMonth(number[0]) && FX_IsValidDay(number[1]) &&
number[2] > 31) {
nMonth = number[0];
nDay = number[1];
nYear = number[2];
- } else if (IsValidDay(number[0]) && IsValidMonth(number[1]) &&
+ } else if (FX_IsValidDay(number[0]) && FX_IsValidMonth(number[1]) &&
number[2] > 31) {
nDay = number[0];
nMonth = number[1];
@@ -453,260 +424,19 @@
double CJS_PublicMethods::ParseDateUsingFormat(const WideString& value,
const WideString& format,
bool* bWrongFormat) {
- double dt = FX_GetDateTime();
+ double dRet = std::nan("");
+ fxjs::ConversionStatus status = FX_ParseDateUsingFormat(value, format, &dRet);
+ if (status == fxjs::ConversionStatus::kSuccess)
+ return dRet;
- if (format.IsEmpty() || value.IsEmpty())
- return dt;
+ if (status == fxjs::ConversionStatus::kBadDate) {
+ dRet = JS_DateParse(value);
+ if (!std::isnan(dRet))
+ return dRet;
+ }
- int nYear = FX_GetYearFromTime(dt);
- int nMonth = FX_GetMonthFromTime(dt) + 1;
- int nDay = FX_GetDayFromTime(dt);
- int nHour = FX_GetHourFromTime(dt);
- int nMin = FX_GetMinFromTime(dt);
- int nSec = FX_GetSecFromTime(dt);
-
- int nYearSub = 99; // nYear - 2000;
-
- bool bPm = false;
- bool bExit = false;
bool bBadFormat = false;
-
- size_t i = 0;
- size_t j = 0;
-
- while (i < format.GetLength()) {
- if (bExit)
- break;
-
- wchar_t c = format[i];
- switch (c) {
- case ':':
- case '.':
- case '-':
- case '\\':
- case '/':
- i++;
- j++;
- break;
-
- case 'y':
- case 'm':
- case 'd':
- case 'H':
- case 'h':
- case 'M':
- case 's':
- case 't': {
- size_t oldj = j;
- size_t nSkip = 0;
- size_t remaining = format.GetLength() - i - 1;
-
- if (remaining == 0 || format[i + 1] != c) {
- switch (c) {
- case 'y':
- i++;
- j++;
- break;
- case 'm':
- nMonth = FX_ParseStringInteger(value, j, &nSkip, 2);
- i++;
- j += nSkip;
- break;
- case 'd':
- nDay = FX_ParseStringInteger(value, j, &nSkip, 2);
- i++;
- j += nSkip;
- break;
- case 'H':
- nHour = FX_ParseStringInteger(value, j, &nSkip, 2);
- i++;
- j += nSkip;
- break;
- case 'h':
- nHour = FX_ParseStringInteger(value, j, &nSkip, 2);
- i++;
- j += nSkip;
- break;
- case 'M':
- nMin = FX_ParseStringInteger(value, j, &nSkip, 2);
- i++;
- j += nSkip;
- break;
- case 's':
- nSec = FX_ParseStringInteger(value, j, &nSkip, 2);
- i++;
- j += nSkip;
- break;
- case 't':
- bPm = (j < value.GetLength() && value[j] == 'p');
- i++;
- j++;
- break;
- }
- } else if (remaining == 1 || format[i + 2] != c) {
- switch (c) {
- case 'y':
- nYear = FX_ParseStringInteger(value, j, &nSkip, 2);
- i += 2;
- j += nSkip;
- break;
- case 'm':
- nMonth = FX_ParseStringInteger(value, j, &nSkip, 2);
- i += 2;
- j += nSkip;
- break;
- case 'd':
- nDay = FX_ParseStringInteger(value, j, &nSkip, 2);
- i += 2;
- j += nSkip;
- break;
- case 'H':
- nHour = FX_ParseStringInteger(value, j, &nSkip, 2);
- i += 2;
- j += nSkip;
- break;
- case 'h':
- nHour = FX_ParseStringInteger(value, j, &nSkip, 2);
- i += 2;
- j += nSkip;
- break;
- case 'M':
- nMin = FX_ParseStringInteger(value, j, &nSkip, 2);
- i += 2;
- j += nSkip;
- break;
- case 's':
- nSec = FX_ParseStringInteger(value, j, &nSkip, 2);
- i += 2;
- j += nSkip;
- break;
- case 't':
- bPm = (j + 1 < value.GetLength() && value[j] == 'p' &&
- value[j + 1] == 'm');
- i += 2;
- j += 2;
- break;
- }
- } else if (remaining == 2 || format[i + 3] != c) {
- switch (c) {
- case 'm': {
- WideString sMonth = FX_ParseStringString(value, j, &nSkip);
- bool bFind = false;
- for (int m = 0; m < 12; m++) {
- if (sMonth.CompareNoCase(kMonths[m]) == 0) {
- nMonth = m + 1;
- i += 3;
- j += nSkip;
- bFind = true;
- break;
- }
- }
-
- if (!bFind) {
- nMonth = FX_ParseStringInteger(value, j, &nSkip, 3);
- i += 3;
- j += nSkip;
- }
- } break;
- case 'y':
- break;
- default:
- i += 3;
- j += 3;
- break;
- }
- } else if (remaining == 3 || format[i + 4] != c) {
- switch (c) {
- case 'y':
- nYear = FX_ParseStringInteger(value, j, &nSkip, 4);
- j += nSkip;
- i += 4;
- break;
- case 'm': {
- bool bFind = false;
-
- WideString sMonth = FX_ParseStringString(value, j, &nSkip);
- sMonth.MakeLower();
-
- for (int m = 0; m < 12; m++) {
- WideString sFullMonths = WideString(kFullMonths[m]);
- sFullMonths.MakeLower();
-
- if (sFullMonths.Contains(sMonth.c_str())) {
- nMonth = m + 1;
- i += 4;
- j += nSkip;
- bFind = true;
- break;
- }
- }
-
- if (!bFind) {
- nMonth = FX_ParseStringInteger(value, j, &nSkip, 4);
- i += 4;
- j += nSkip;
- }
- } break;
- default:
- i += 4;
- j += 4;
- break;
- }
- } else {
- if (j >= value.GetLength() || format[i] != value[j]) {
- bBadFormat = true;
- bExit = true;
- }
- i++;
- j++;
- }
-
- if (oldj == j) {
- bBadFormat = true;
- bExit = true;
- }
- break;
- }
-
- default:
- if (value.GetLength() <= j) {
- bExit = true;
- } else if (format[i] != value[j]) {
- bBadFormat = true;
- bExit = true;
- }
-
- i++;
- j++;
- break;
- }
- }
-
- if (bPm)
- nHour += 12;
-
- if (nYear >= 0 && nYear <= nYearSub)
- nYear += 2000;
-
- if (!bBadFormat) {
- bBadFormat = !IsValidMonth(nMonth) || !IsValidDay(nDay) ||
- !IsValid24Hour(nHour) || !IsValidMinute(nMin) ||
- !IsValidSecond(nSec);
- }
-
- double dRet;
- if (bBadFormat) {
- dRet = ParseDate(value, &bBadFormat);
- } else {
- dRet = FX_MakeDate(FX_MakeDay(nYear, nMonth - 1, nDay),
- FX_MakeTime(nHour, nMin, nSec, 0));
- if (std::isnan(dRet))
- dRet = JS_DateParse(value);
- }
-
- if (std::isnan(dRet))
- dRet = ParseDate(value, &bBadFormat);
-
+ dRet = ParseDate(value, &bBadFormat);
if (bWrongFormat)
*bWrongFormat = bBadFormat;
@@ -801,8 +531,8 @@
switch (c) {
case 'm':
i += 3;
- if (IsValidMonth(nMonth))
- sPart += kMonths[nMonth - 1];
+ if (FX_IsValidMonth(nMonth))
+ sPart += fxjs::kMonths[nMonth - 1];
break;
default:
i += 3;
@@ -819,8 +549,8 @@
break;
case 'm':
i += 4;
- if (IsValidMonth(nMonth))
- sPart += kFullMonths[nMonth - 1];
+ if (FX_IsValidMonth(nMonth))
+ sPart += fxjs::kFullMonths[nMonth - 1];
break;
default:
i += 4;
@@ -1184,8 +914,8 @@
int nMonth = 1;
sTemp = wsArray[1];
- for (size_t i = 0; i < FX_ArraySize(kMonths); ++i) {
- if (sTemp.Compare(kMonths[i]) == 0) {
+ for (size_t i = 0; i < FX_ArraySize(fxjs::kMonths); ++i) {
+ if (sTemp.Compare(fxjs::kMonths[i]) == 0) {
nMonth = i + 1;
break;
}
@@ -1225,8 +955,8 @@
if (strValue.IsEmpty())
return CJS_Result::Success();
- WideString sFormat = pRuntime->ToWideString(params[0]);
bool bWrongFormat = false;
+ WideString sFormat = pRuntime->ToWideString(params[0]);
double dRet = ParseDateUsingFormat(strValue, sFormat, &bWrongFormat);
if (bWrongFormat || std::isnan(dRet)) {
WideString swMsg = WideString::Format(
diff --git a/fxjs/fx_date_helpers.cpp b/fxjs/fx_date_helpers.cpp
index 403a731..847e8c3 100644
--- a/fxjs/fx_date_helpers.cpp
+++ b/fxjs/fx_date_helpers.cpp
@@ -8,6 +8,8 @@
#include <time.h>
+#include <cmath>
+
#include "core/fxcrt/fx_extension.h"
#include "core/fxcrt/fx_system.h"
#include "fpdfsdk/cpdfsdk_helpers.h"
@@ -164,6 +166,15 @@
} // namespace
+const wchar_t* const kMonths[12] = {L"Jan", L"Feb", L"Mar", L"Apr",
+ L"May", L"Jun", L"Jul", L"Aug",
+ L"Sep", L"Oct", L"Nov", L"Dec"};
+
+const wchar_t* const kFullMonths[12] = {L"January", L"February", L"March",
+ L"April", L"May", L"June",
+ L"July", L"August", L"September",
+ L"October", L"November", L"December"};
+
double FX_GetDateTime() {
if (!FSDK_IsSandBoxPolicyEnabled(FPDF_POLICY_MACHINETIME_ACCESS))
return 0;
@@ -199,6 +210,28 @@
return (int)Mod(floor(dt / 1000), 60);
}
+bool FX_IsValidMonth(int m) {
+ return m >= 1 && m <= 12;
+}
+
+// TODO(thestig): Should this take the month into consideration?
+bool FX_IsValidDay(int d) {
+ return d >= 1 && d <= 31;
+}
+
+// TODO(thestig): Should 24 be allowed? Similarly, 60 for minutes and seconds.
+bool FX_IsValid24Hour(int h) {
+ return h >= 0 && h <= 24;
+}
+
+bool FX_IsValidMinute(int m) {
+ return m >= 0 && m <= 60;
+}
+
+bool FX_IsValidSecond(int s) {
+ return s >= 0 && s <= 60;
+}
+
double FX_LocalTime(double d) {
return d + GetLocalTZA() + GetDaylightSavingTA(d);
}
@@ -272,4 +305,258 @@
return swRet;
}
+ConversionStatus FX_ParseDateUsingFormat(const WideString& value,
+ const WideString& format,
+ double* result) {
+ double dt = FX_GetDateTime();
+ if (format.IsEmpty() || value.IsEmpty()) {
+ *result = dt;
+ return ConversionStatus::kSuccess;
+ }
+
+ int nYear = FX_GetYearFromTime(dt);
+ int nMonth = FX_GetMonthFromTime(dt) + 1;
+ int nDay = FX_GetDayFromTime(dt);
+ int nHour = FX_GetHourFromTime(dt);
+ int nMin = FX_GetMinFromTime(dt);
+ int nSec = FX_GetSecFromTime(dt);
+ int nYearSub = 99; // nYear - 2000;
+ bool bPm = false;
+ bool bExit = false;
+ bool bBadFormat = false;
+ size_t i = 0;
+ size_t j = 0;
+
+ while (i < format.GetLength()) {
+ if (bExit)
+ break;
+
+ wchar_t c = format[i];
+ switch (c) {
+ case ':':
+ case '.':
+ case '-':
+ case '\\':
+ case '/':
+ i++;
+ j++;
+ break;
+
+ case 'y':
+ case 'm':
+ case 'd':
+ case 'H':
+ case 'h':
+ case 'M':
+ case 's':
+ case 't': {
+ size_t oldj = j;
+ size_t nSkip = 0;
+ size_t remaining = format.GetLength() - i - 1;
+
+ if (remaining == 0 || format[i + 1] != c) {
+ switch (c) {
+ case 'y':
+ i++;
+ j++;
+ break;
+ case 'm':
+ nMonth = FX_ParseStringInteger(value, j, &nSkip, 2);
+ i++;
+ j += nSkip;
+ break;
+ case 'd':
+ nDay = FX_ParseStringInteger(value, j, &nSkip, 2);
+ i++;
+ j += nSkip;
+ break;
+ case 'H':
+ nHour = FX_ParseStringInteger(value, j, &nSkip, 2);
+ i++;
+ j += nSkip;
+ break;
+ case 'h':
+ nHour = FX_ParseStringInteger(value, j, &nSkip, 2);
+ i++;
+ j += nSkip;
+ break;
+ case 'M':
+ nMin = FX_ParseStringInteger(value, j, &nSkip, 2);
+ i++;
+ j += nSkip;
+ break;
+ case 's':
+ nSec = FX_ParseStringInteger(value, j, &nSkip, 2);
+ i++;
+ j += nSkip;
+ break;
+ case 't':
+ bPm = (j < value.GetLength() && value[j] == 'p');
+ i++;
+ j++;
+ break;
+ }
+ } else if (remaining == 1 || format[i + 2] != c) {
+ switch (c) {
+ case 'y':
+ nYear = FX_ParseStringInteger(value, j, &nSkip, 2);
+ i += 2;
+ j += nSkip;
+ break;
+ case 'm':
+ nMonth = FX_ParseStringInteger(value, j, &nSkip, 2);
+ i += 2;
+ j += nSkip;
+ break;
+ case 'd':
+ nDay = FX_ParseStringInteger(value, j, &nSkip, 2);
+ i += 2;
+ j += nSkip;
+ break;
+ case 'H':
+ nHour = FX_ParseStringInteger(value, j, &nSkip, 2);
+ i += 2;
+ j += nSkip;
+ break;
+ case 'h':
+ nHour = FX_ParseStringInteger(value, j, &nSkip, 2);
+ i += 2;
+ j += nSkip;
+ break;
+ case 'M':
+ nMin = FX_ParseStringInteger(value, j, &nSkip, 2);
+ i += 2;
+ j += nSkip;
+ break;
+ case 's':
+ nSec = FX_ParseStringInteger(value, j, &nSkip, 2);
+ i += 2;
+ j += nSkip;
+ break;
+ case 't':
+ bPm = (j + 1 < value.GetLength() && value[j] == 'p' &&
+ value[j + 1] == 'm');
+ i += 2;
+ j += 2;
+ break;
+ }
+ } else if (remaining == 2 || format[i + 3] != c) {
+ switch (c) {
+ case 'm': {
+ WideString sMonth = FX_ParseStringString(value, j, &nSkip);
+ bool bFind = false;
+ for (int m = 0; m < 12; m++) {
+ if (sMonth.CompareNoCase(kMonths[m]) == 0) {
+ nMonth = m + 1;
+ i += 3;
+ j += nSkip;
+ bFind = true;
+ break;
+ }
+ }
+
+ if (!bFind) {
+ nMonth = FX_ParseStringInteger(value, j, &nSkip, 3);
+ i += 3;
+ j += nSkip;
+ }
+ } break;
+ case 'y':
+ break;
+ default:
+ i += 3;
+ j += 3;
+ break;
+ }
+ } else if (remaining == 3 || format[i + 4] != c) {
+ switch (c) {
+ case 'y':
+ nYear = FX_ParseStringInteger(value, j, &nSkip, 4);
+ j += nSkip;
+ i += 4;
+ break;
+ case 'm': {
+ bool bFind = false;
+
+ WideString sMonth = FX_ParseStringString(value, j, &nSkip);
+ sMonth.MakeLower();
+
+ for (int m = 0; m < 12; m++) {
+ WideString sFullMonths = WideString(kFullMonths[m]);
+ sFullMonths.MakeLower();
+
+ if (sFullMonths.Contains(sMonth.c_str())) {
+ nMonth = m + 1;
+ i += 4;
+ j += nSkip;
+ bFind = true;
+ break;
+ }
+ }
+
+ if (!bFind) {
+ nMonth = FX_ParseStringInteger(value, j, &nSkip, 4);
+ i += 4;
+ j += nSkip;
+ }
+ } break;
+ default:
+ i += 4;
+ j += 4;
+ break;
+ }
+ } else {
+ if (j >= value.GetLength() || format[i] != value[j]) {
+ bBadFormat = true;
+ bExit = true;
+ }
+ i++;
+ j++;
+ }
+
+ if (oldj == j) {
+ bBadFormat = true;
+ bExit = true;
+ }
+ break;
+ }
+
+ default:
+ if (value.GetLength() <= j) {
+ bExit = true;
+ } else if (format[i] != value[j]) {
+ bBadFormat = true;
+ bExit = true;
+ }
+
+ i++;
+ j++;
+ break;
+ }
+ }
+
+ if (bBadFormat)
+ return ConversionStatus::kBadFormat;
+
+ if (bPm)
+ nHour += 12;
+
+ if (nYear >= 0 && nYear <= nYearSub)
+ nYear += 2000;
+
+ if (!FX_IsValidMonth(nMonth) || !FX_IsValidDay(nDay) ||
+ !FX_IsValid24Hour(nHour) || !FX_IsValidMinute(nMin) ||
+ !FX_IsValidSecond(nSec)) {
+ return ConversionStatus::kBadDate;
+ }
+
+ dt = FX_MakeDate(FX_MakeDay(nYear, nMonth - 1, nDay),
+ FX_MakeTime(nHour, nMin, nSec, 0));
+ if (std::isnan(dt))
+ return ConversionStatus::kBadDate;
+
+ *result = dt;
+ return ConversionStatus::kSuccess;
+}
+
} // namespace fxjs
diff --git a/fxjs/fx_date_helpers.h b/fxjs/fx_date_helpers.h
index 8c21df0..f92caba 100644
--- a/fxjs/fx_date_helpers.h
+++ b/fxjs/fx_date_helpers.h
@@ -13,6 +13,11 @@
namespace fxjs {
+enum class ConversionStatus { kSuccess = 0, kBadFormat, kBadDate };
+
+extern const wchar_t* const kMonths[12];
+extern const wchar_t* const kFullMonths[12];
+
double FX_GetDateTime();
int FX_GetYearFromTime(double dt);
int FX_GetMonthFromTime(double dt);
@@ -20,6 +25,11 @@
int FX_GetHourFromTime(double dt);
int FX_GetMinFromTime(double dt);
int FX_GetSecFromTime(double dt);
+bool FX_IsValidMonth(int m);
+bool FX_IsValidDay(int d);
+bool FX_IsValid24Hour(int h);
+bool FX_IsValidMinute(int m);
+bool FX_IsValidSecond(int s);
double FX_LocalTime(double d);
double FX_MakeDay(int nYear, int nMonth, int nDay);
double FX_MakeTime(int nHour, int nMin, int nSec, int nMs);
@@ -34,6 +44,10 @@
size_t nStart,
size_t* pSkip);
+ConversionStatus FX_ParseDateUsingFormat(const WideString& value,
+ const WideString& format,
+ double* result);
+
} // namespace fxjs
using fxjs::FX_GetDateTime;
@@ -43,11 +57,17 @@
using fxjs::FX_GetHourFromTime;
using fxjs::FX_GetMinFromTime;
using fxjs::FX_GetSecFromTime;
+using fxjs::FX_IsValidMonth;
+using fxjs::FX_IsValidDay;
+using fxjs::FX_IsValid24Hour;
+using fxjs::FX_IsValidMinute;
+using fxjs::FX_IsValidSecond;
using fxjs::FX_LocalTime;
using fxjs::FX_MakeDay;
using fxjs::FX_MakeTime;
using fxjs::FX_MakeDate;
using fxjs::FX_ParseStringInteger;
using fxjs::FX_ParseStringString;
+using fxjs::FX_ParseDateUsingFormat;
#endif // FXJS_FX_DATE_HELPERS_H_