1*3ac0a46fSAndroid Build Coastguard Worker // Copyright 2014 The PDFium Authors
2*3ac0a46fSAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*3ac0a46fSAndroid Build Coastguard Worker // found in the LICENSE file.
4*3ac0a46fSAndroid Build Coastguard Worker
5*3ac0a46fSAndroid Build Coastguard Worker // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6*3ac0a46fSAndroid Build Coastguard Worker
7*3ac0a46fSAndroid Build Coastguard Worker #include "fxjs/fx_date_helpers.h"
8*3ac0a46fSAndroid Build Coastguard Worker
9*3ac0a46fSAndroid Build Coastguard Worker #include <math.h>
10*3ac0a46fSAndroid Build Coastguard Worker #include <time.h>
11*3ac0a46fSAndroid Build Coastguard Worker #include <wctype.h>
12*3ac0a46fSAndroid Build Coastguard Worker
13*3ac0a46fSAndroid Build Coastguard Worker #include <iterator>
14*3ac0a46fSAndroid Build Coastguard Worker
15*3ac0a46fSAndroid Build Coastguard Worker #include "build/build_config.h"
16*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxcrt/fx_extension.h"
17*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxcrt/fx_system.h"
18*3ac0a46fSAndroid Build Coastguard Worker #include "fpdfsdk/cpdfsdk_helpers.h"
19*3ac0a46fSAndroid Build Coastguard Worker
20*3ac0a46fSAndroid Build Coastguard Worker namespace fxjs {
21*3ac0a46fSAndroid Build Coastguard Worker namespace {
22*3ac0a46fSAndroid Build Coastguard Worker
23*3ac0a46fSAndroid Build Coastguard Worker constexpr uint16_t daysMonth[12] = {0, 31, 59, 90, 120, 151,
24*3ac0a46fSAndroid Build Coastguard Worker 181, 212, 243, 273, 304, 334};
25*3ac0a46fSAndroid Build Coastguard Worker constexpr uint16_t leapDaysMonth[12] = {0, 31, 60, 91, 121, 152,
26*3ac0a46fSAndroid Build Coastguard Worker 182, 213, 244, 274, 305, 335};
27*3ac0a46fSAndroid Build Coastguard Worker
Mod(double x,double y)28*3ac0a46fSAndroid Build Coastguard Worker double Mod(double x, double y) {
29*3ac0a46fSAndroid Build Coastguard Worker double r = fmod(x, y);
30*3ac0a46fSAndroid Build Coastguard Worker if (r < 0)
31*3ac0a46fSAndroid Build Coastguard Worker r += y;
32*3ac0a46fSAndroid Build Coastguard Worker return r;
33*3ac0a46fSAndroid Build Coastguard Worker }
34*3ac0a46fSAndroid Build Coastguard Worker
GetLocalTZA()35*3ac0a46fSAndroid Build Coastguard Worker double GetLocalTZA() {
36*3ac0a46fSAndroid Build Coastguard Worker if (!IsPDFSandboxPolicyEnabled(FPDF_POLICY_MACHINETIME_ACCESS))
37*3ac0a46fSAndroid Build Coastguard Worker return 0;
38*3ac0a46fSAndroid Build Coastguard Worker time_t t = 0;
39*3ac0a46fSAndroid Build Coastguard Worker FXSYS_time(&t);
40*3ac0a46fSAndroid Build Coastguard Worker FXSYS_localtime(&t);
41*3ac0a46fSAndroid Build Coastguard Worker #if BUILDFLAG(IS_WIN)
42*3ac0a46fSAndroid Build Coastguard Worker // In gcc 'timezone' is a global variable declared in time.h. In VC++, that
43*3ac0a46fSAndroid Build Coastguard Worker // variable was removed in VC++ 2015, with _get_timezone replacing it.
44*3ac0a46fSAndroid Build Coastguard Worker long timezone = 0;
45*3ac0a46fSAndroid Build Coastguard Worker _get_timezone(&timezone);
46*3ac0a46fSAndroid Build Coastguard Worker #endif
47*3ac0a46fSAndroid Build Coastguard Worker return (double)(-(timezone * 1000));
48*3ac0a46fSAndroid Build Coastguard Worker }
49*3ac0a46fSAndroid Build Coastguard Worker
GetDaylightSavingTA(double d)50*3ac0a46fSAndroid Build Coastguard Worker int GetDaylightSavingTA(double d) {
51*3ac0a46fSAndroid Build Coastguard Worker if (!IsPDFSandboxPolicyEnabled(FPDF_POLICY_MACHINETIME_ACCESS))
52*3ac0a46fSAndroid Build Coastguard Worker return 0;
53*3ac0a46fSAndroid Build Coastguard Worker time_t t = (time_t)(d / 1000);
54*3ac0a46fSAndroid Build Coastguard Worker struct tm* tmp = FXSYS_localtime(&t);
55*3ac0a46fSAndroid Build Coastguard Worker if (!tmp)
56*3ac0a46fSAndroid Build Coastguard Worker return 0;
57*3ac0a46fSAndroid Build Coastguard Worker if (tmp->tm_isdst > 0)
58*3ac0a46fSAndroid Build Coastguard Worker // One hour.
59*3ac0a46fSAndroid Build Coastguard Worker return (int)60 * 60 * 1000;
60*3ac0a46fSAndroid Build Coastguard Worker return 0;
61*3ac0a46fSAndroid Build Coastguard Worker }
62*3ac0a46fSAndroid Build Coastguard Worker
IsLeapYear(int year)63*3ac0a46fSAndroid Build Coastguard Worker bool IsLeapYear(int year) {
64*3ac0a46fSAndroid Build Coastguard Worker return (year % 4 == 0) && ((year % 100 != 0) || (year % 400 != 0));
65*3ac0a46fSAndroid Build Coastguard Worker }
66*3ac0a46fSAndroid Build Coastguard Worker
DayFromYear(int y)67*3ac0a46fSAndroid Build Coastguard Worker int DayFromYear(int y) {
68*3ac0a46fSAndroid Build Coastguard Worker return (int)(365 * (y - 1970.0) + floor((y - 1969.0) / 4) -
69*3ac0a46fSAndroid Build Coastguard Worker floor((y - 1901.0) / 100) + floor((y - 1601.0) / 400));
70*3ac0a46fSAndroid Build Coastguard Worker }
71*3ac0a46fSAndroid Build Coastguard Worker
TimeFromYear(int y)72*3ac0a46fSAndroid Build Coastguard Worker double TimeFromYear(int y) {
73*3ac0a46fSAndroid Build Coastguard Worker return 86400000.0 * DayFromYear(y);
74*3ac0a46fSAndroid Build Coastguard Worker }
75*3ac0a46fSAndroid Build Coastguard Worker
TimeFromYearMonth(int y,int m)76*3ac0a46fSAndroid Build Coastguard Worker double TimeFromYearMonth(int y, int m) {
77*3ac0a46fSAndroid Build Coastguard Worker const uint16_t* pMonth = IsLeapYear(y) ? leapDaysMonth : daysMonth;
78*3ac0a46fSAndroid Build Coastguard Worker return TimeFromYear(y) + ((double)pMonth[m]) * 86400000;
79*3ac0a46fSAndroid Build Coastguard Worker }
80*3ac0a46fSAndroid Build Coastguard Worker
Day(double t)81*3ac0a46fSAndroid Build Coastguard Worker int Day(double t) {
82*3ac0a46fSAndroid Build Coastguard Worker return static_cast<int>(floor(t / 86400000.0));
83*3ac0a46fSAndroid Build Coastguard Worker }
84*3ac0a46fSAndroid Build Coastguard Worker
YearFromTime(double t)85*3ac0a46fSAndroid Build Coastguard Worker int YearFromTime(double t) {
86*3ac0a46fSAndroid Build Coastguard Worker // estimate the time.
87*3ac0a46fSAndroid Build Coastguard Worker int y = 1970 + static_cast<int>(t / (365.2425 * 86400000.0));
88*3ac0a46fSAndroid Build Coastguard Worker if (TimeFromYear(y) <= t) {
89*3ac0a46fSAndroid Build Coastguard Worker while (TimeFromYear(y + 1) <= t)
90*3ac0a46fSAndroid Build Coastguard Worker y++;
91*3ac0a46fSAndroid Build Coastguard Worker } else {
92*3ac0a46fSAndroid Build Coastguard Worker while (TimeFromYear(y) > t)
93*3ac0a46fSAndroid Build Coastguard Worker y--;
94*3ac0a46fSAndroid Build Coastguard Worker }
95*3ac0a46fSAndroid Build Coastguard Worker return y;
96*3ac0a46fSAndroid Build Coastguard Worker }
97*3ac0a46fSAndroid Build Coastguard Worker
DayWithinYear(double t)98*3ac0a46fSAndroid Build Coastguard Worker int DayWithinYear(double t) {
99*3ac0a46fSAndroid Build Coastguard Worker int year = YearFromTime(t);
100*3ac0a46fSAndroid Build Coastguard Worker int day = Day(t);
101*3ac0a46fSAndroid Build Coastguard Worker return day - DayFromYear(year);
102*3ac0a46fSAndroid Build Coastguard Worker }
103*3ac0a46fSAndroid Build Coastguard Worker
MonthFromTime(double t)104*3ac0a46fSAndroid Build Coastguard Worker int MonthFromTime(double t) {
105*3ac0a46fSAndroid Build Coastguard Worker // Check for negative |day| values and check for January.
106*3ac0a46fSAndroid Build Coastguard Worker int day = DayWithinYear(t);
107*3ac0a46fSAndroid Build Coastguard Worker if (day < 0)
108*3ac0a46fSAndroid Build Coastguard Worker return -1;
109*3ac0a46fSAndroid Build Coastguard Worker if (day < 31)
110*3ac0a46fSAndroid Build Coastguard Worker return 0;
111*3ac0a46fSAndroid Build Coastguard Worker
112*3ac0a46fSAndroid Build Coastguard Worker if (IsLeapYear(YearFromTime(t)))
113*3ac0a46fSAndroid Build Coastguard Worker --day;
114*3ac0a46fSAndroid Build Coastguard Worker
115*3ac0a46fSAndroid Build Coastguard Worker // Check for February onwards.
116*3ac0a46fSAndroid Build Coastguard Worker static constexpr int kCumulativeDaysInMonths[] = {
117*3ac0a46fSAndroid Build Coastguard Worker 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365};
118*3ac0a46fSAndroid Build Coastguard Worker for (size_t i = 0; i < std::size(kCumulativeDaysInMonths); ++i) {
119*3ac0a46fSAndroid Build Coastguard Worker if (day < kCumulativeDaysInMonths[i])
120*3ac0a46fSAndroid Build Coastguard Worker return static_cast<int>(i) + 1;
121*3ac0a46fSAndroid Build Coastguard Worker }
122*3ac0a46fSAndroid Build Coastguard Worker
123*3ac0a46fSAndroid Build Coastguard Worker return -1;
124*3ac0a46fSAndroid Build Coastguard Worker }
125*3ac0a46fSAndroid Build Coastguard Worker
DateFromTime(double t)126*3ac0a46fSAndroid Build Coastguard Worker int DateFromTime(double t) {
127*3ac0a46fSAndroid Build Coastguard Worker int day = DayWithinYear(t);
128*3ac0a46fSAndroid Build Coastguard Worker int year = YearFromTime(t);
129*3ac0a46fSAndroid Build Coastguard Worker int leap = IsLeapYear(year);
130*3ac0a46fSAndroid Build Coastguard Worker int month = MonthFromTime(t);
131*3ac0a46fSAndroid Build Coastguard Worker switch (month) {
132*3ac0a46fSAndroid Build Coastguard Worker case 0:
133*3ac0a46fSAndroid Build Coastguard Worker return day + 1;
134*3ac0a46fSAndroid Build Coastguard Worker case 1:
135*3ac0a46fSAndroid Build Coastguard Worker return day - 30;
136*3ac0a46fSAndroid Build Coastguard Worker case 2:
137*3ac0a46fSAndroid Build Coastguard Worker return day - 58 - leap;
138*3ac0a46fSAndroid Build Coastguard Worker case 3:
139*3ac0a46fSAndroid Build Coastguard Worker return day - 89 - leap;
140*3ac0a46fSAndroid Build Coastguard Worker case 4:
141*3ac0a46fSAndroid Build Coastguard Worker return day - 119 - leap;
142*3ac0a46fSAndroid Build Coastguard Worker case 5:
143*3ac0a46fSAndroid Build Coastguard Worker return day - 150 - leap;
144*3ac0a46fSAndroid Build Coastguard Worker case 6:
145*3ac0a46fSAndroid Build Coastguard Worker return day - 180 - leap;
146*3ac0a46fSAndroid Build Coastguard Worker case 7:
147*3ac0a46fSAndroid Build Coastguard Worker return day - 211 - leap;
148*3ac0a46fSAndroid Build Coastguard Worker case 8:
149*3ac0a46fSAndroid Build Coastguard Worker return day - 242 - leap;
150*3ac0a46fSAndroid Build Coastguard Worker case 9:
151*3ac0a46fSAndroid Build Coastguard Worker return day - 272 - leap;
152*3ac0a46fSAndroid Build Coastguard Worker case 10:
153*3ac0a46fSAndroid Build Coastguard Worker return day - 303 - leap;
154*3ac0a46fSAndroid Build Coastguard Worker case 11:
155*3ac0a46fSAndroid Build Coastguard Worker return day - 333 - leap;
156*3ac0a46fSAndroid Build Coastguard Worker default:
157*3ac0a46fSAndroid Build Coastguard Worker return 0;
158*3ac0a46fSAndroid Build Coastguard Worker }
159*3ac0a46fSAndroid Build Coastguard Worker }
160*3ac0a46fSAndroid Build Coastguard Worker
FindSubWordLength(const WideString & str,size_t nStart)161*3ac0a46fSAndroid Build Coastguard Worker size_t FindSubWordLength(const WideString& str, size_t nStart) {
162*3ac0a46fSAndroid Build Coastguard Worker pdfium::span<const wchar_t> data = str.span();
163*3ac0a46fSAndroid Build Coastguard Worker size_t i = nStart;
164*3ac0a46fSAndroid Build Coastguard Worker while (i < data.size() && iswalnum(data[i]))
165*3ac0a46fSAndroid Build Coastguard Worker ++i;
166*3ac0a46fSAndroid Build Coastguard Worker return i - nStart;
167*3ac0a46fSAndroid Build Coastguard Worker }
168*3ac0a46fSAndroid Build Coastguard Worker
169*3ac0a46fSAndroid Build Coastguard Worker } // namespace
170*3ac0a46fSAndroid Build Coastguard Worker
171*3ac0a46fSAndroid Build Coastguard Worker const wchar_t* const kMonths[12] = {L"Jan", L"Feb", L"Mar", L"Apr",
172*3ac0a46fSAndroid Build Coastguard Worker L"May", L"Jun", L"Jul", L"Aug",
173*3ac0a46fSAndroid Build Coastguard Worker L"Sep", L"Oct", L"Nov", L"Dec"};
174*3ac0a46fSAndroid Build Coastguard Worker
175*3ac0a46fSAndroid Build Coastguard Worker const wchar_t* const kFullMonths[12] = {L"January", L"February", L"March",
176*3ac0a46fSAndroid Build Coastguard Worker L"April", L"May", L"June",
177*3ac0a46fSAndroid Build Coastguard Worker L"July", L"August", L"September",
178*3ac0a46fSAndroid Build Coastguard Worker L"October", L"November", L"December"};
179*3ac0a46fSAndroid Build Coastguard Worker
180*3ac0a46fSAndroid Build Coastguard Worker static constexpr size_t KMonthAbbreviationLength = 3; // Anything in |kMonths|.
181*3ac0a46fSAndroid Build Coastguard Worker static constexpr size_t kLongestFullMonthLength = 9; // September
182*3ac0a46fSAndroid Build Coastguard Worker
FX_GetDateTime()183*3ac0a46fSAndroid Build Coastguard Worker double FX_GetDateTime() {
184*3ac0a46fSAndroid Build Coastguard Worker if (!IsPDFSandboxPolicyEnabled(FPDF_POLICY_MACHINETIME_ACCESS))
185*3ac0a46fSAndroid Build Coastguard Worker return 0;
186*3ac0a46fSAndroid Build Coastguard Worker
187*3ac0a46fSAndroid Build Coastguard Worker time_t t = FXSYS_time(nullptr);
188*3ac0a46fSAndroid Build Coastguard Worker struct tm* pTm = FXSYS_localtime(&t);
189*3ac0a46fSAndroid Build Coastguard Worker double t1 = TimeFromYear(pTm->tm_year + 1900);
190*3ac0a46fSAndroid Build Coastguard Worker return t1 + pTm->tm_yday * 86400000.0 + pTm->tm_hour * 3600000.0 +
191*3ac0a46fSAndroid Build Coastguard Worker pTm->tm_min * 60000.0 + pTm->tm_sec * 1000.0;
192*3ac0a46fSAndroid Build Coastguard Worker }
193*3ac0a46fSAndroid Build Coastguard Worker
FX_GetYearFromTime(double dt)194*3ac0a46fSAndroid Build Coastguard Worker int FX_GetYearFromTime(double dt) {
195*3ac0a46fSAndroid Build Coastguard Worker return YearFromTime(dt);
196*3ac0a46fSAndroid Build Coastguard Worker }
197*3ac0a46fSAndroid Build Coastguard Worker
FX_GetMonthFromTime(double dt)198*3ac0a46fSAndroid Build Coastguard Worker int FX_GetMonthFromTime(double dt) {
199*3ac0a46fSAndroid Build Coastguard Worker return MonthFromTime(dt);
200*3ac0a46fSAndroid Build Coastguard Worker }
201*3ac0a46fSAndroid Build Coastguard Worker
FX_GetDayFromTime(double dt)202*3ac0a46fSAndroid Build Coastguard Worker int FX_GetDayFromTime(double dt) {
203*3ac0a46fSAndroid Build Coastguard Worker return DateFromTime(dt);
204*3ac0a46fSAndroid Build Coastguard Worker }
205*3ac0a46fSAndroid Build Coastguard Worker
FX_GetHourFromTime(double dt)206*3ac0a46fSAndroid Build Coastguard Worker int FX_GetHourFromTime(double dt) {
207*3ac0a46fSAndroid Build Coastguard Worker return (int)Mod(floor(dt / (60 * 60 * 1000)), 24);
208*3ac0a46fSAndroid Build Coastguard Worker }
209*3ac0a46fSAndroid Build Coastguard Worker
FX_GetMinFromTime(double dt)210*3ac0a46fSAndroid Build Coastguard Worker int FX_GetMinFromTime(double dt) {
211*3ac0a46fSAndroid Build Coastguard Worker return (int)Mod(floor(dt / (60 * 1000)), 60);
212*3ac0a46fSAndroid Build Coastguard Worker }
213*3ac0a46fSAndroid Build Coastguard Worker
FX_GetSecFromTime(double dt)214*3ac0a46fSAndroid Build Coastguard Worker int FX_GetSecFromTime(double dt) {
215*3ac0a46fSAndroid Build Coastguard Worker return (int)Mod(floor(dt / 1000), 60);
216*3ac0a46fSAndroid Build Coastguard Worker }
217*3ac0a46fSAndroid Build Coastguard Worker
FX_IsValidMonth(int m)218*3ac0a46fSAndroid Build Coastguard Worker bool FX_IsValidMonth(int m) {
219*3ac0a46fSAndroid Build Coastguard Worker return m >= 1 && m <= 12;
220*3ac0a46fSAndroid Build Coastguard Worker }
221*3ac0a46fSAndroid Build Coastguard Worker
222*3ac0a46fSAndroid Build Coastguard Worker // TODO(thestig): Should this take the month into consideration?
FX_IsValidDay(int d)223*3ac0a46fSAndroid Build Coastguard Worker bool FX_IsValidDay(int d) {
224*3ac0a46fSAndroid Build Coastguard Worker return d >= 1 && d <= 31;
225*3ac0a46fSAndroid Build Coastguard Worker }
226*3ac0a46fSAndroid Build Coastguard Worker
227*3ac0a46fSAndroid Build Coastguard Worker // TODO(thestig): Should 24 be allowed? Similarly, 60 for minutes and seconds.
FX_IsValid24Hour(int h)228*3ac0a46fSAndroid Build Coastguard Worker bool FX_IsValid24Hour(int h) {
229*3ac0a46fSAndroid Build Coastguard Worker return h >= 0 && h <= 24;
230*3ac0a46fSAndroid Build Coastguard Worker }
231*3ac0a46fSAndroid Build Coastguard Worker
FX_IsValidMinute(int m)232*3ac0a46fSAndroid Build Coastguard Worker bool FX_IsValidMinute(int m) {
233*3ac0a46fSAndroid Build Coastguard Worker return m >= 0 && m <= 60;
234*3ac0a46fSAndroid Build Coastguard Worker }
235*3ac0a46fSAndroid Build Coastguard Worker
FX_IsValidSecond(int s)236*3ac0a46fSAndroid Build Coastguard Worker bool FX_IsValidSecond(int s) {
237*3ac0a46fSAndroid Build Coastguard Worker return s >= 0 && s <= 60;
238*3ac0a46fSAndroid Build Coastguard Worker }
239*3ac0a46fSAndroid Build Coastguard Worker
FX_LocalTime(double d)240*3ac0a46fSAndroid Build Coastguard Worker double FX_LocalTime(double d) {
241*3ac0a46fSAndroid Build Coastguard Worker return d + GetLocalTZA() + GetDaylightSavingTA(d);
242*3ac0a46fSAndroid Build Coastguard Worker }
243*3ac0a46fSAndroid Build Coastguard Worker
FX_MakeDay(int nYear,int nMonth,int nDate)244*3ac0a46fSAndroid Build Coastguard Worker double FX_MakeDay(int nYear, int nMonth, int nDate) {
245*3ac0a46fSAndroid Build Coastguard Worker double y = static_cast<double>(nYear);
246*3ac0a46fSAndroid Build Coastguard Worker double m = static_cast<double>(nMonth);
247*3ac0a46fSAndroid Build Coastguard Worker double dt = static_cast<double>(nDate);
248*3ac0a46fSAndroid Build Coastguard Worker double ym = y + floor(m / 12);
249*3ac0a46fSAndroid Build Coastguard Worker double mn = Mod(m, 12);
250*3ac0a46fSAndroid Build Coastguard Worker double t = TimeFromYearMonth(static_cast<int>(ym), static_cast<int>(mn));
251*3ac0a46fSAndroid Build Coastguard Worker if (YearFromTime(t) != ym || MonthFromTime(t) != mn || DateFromTime(t) != 1)
252*3ac0a46fSAndroid Build Coastguard Worker return nan("");
253*3ac0a46fSAndroid Build Coastguard Worker
254*3ac0a46fSAndroid Build Coastguard Worker return Day(t) + dt - 1;
255*3ac0a46fSAndroid Build Coastguard Worker }
256*3ac0a46fSAndroid Build Coastguard Worker
FX_MakeTime(int nHour,int nMin,int nSec,int nMs)257*3ac0a46fSAndroid Build Coastguard Worker double FX_MakeTime(int nHour, int nMin, int nSec, int nMs) {
258*3ac0a46fSAndroid Build Coastguard Worker double h = static_cast<double>(nHour);
259*3ac0a46fSAndroid Build Coastguard Worker double m = static_cast<double>(nMin);
260*3ac0a46fSAndroid Build Coastguard Worker double s = static_cast<double>(nSec);
261*3ac0a46fSAndroid Build Coastguard Worker double milli = static_cast<double>(nMs);
262*3ac0a46fSAndroid Build Coastguard Worker return h * 3600000 + m * 60000 + s * 1000 + milli;
263*3ac0a46fSAndroid Build Coastguard Worker }
264*3ac0a46fSAndroid Build Coastguard Worker
FX_MakeDate(double day,double time)265*3ac0a46fSAndroid Build Coastguard Worker double FX_MakeDate(double day, double time) {
266*3ac0a46fSAndroid Build Coastguard Worker if (!isfinite(day) || !isfinite(time))
267*3ac0a46fSAndroid Build Coastguard Worker return nan("");
268*3ac0a46fSAndroid Build Coastguard Worker
269*3ac0a46fSAndroid Build Coastguard Worker return day * 86400000 + time;
270*3ac0a46fSAndroid Build Coastguard Worker }
271*3ac0a46fSAndroid Build Coastguard Worker
FX_ParseStringInteger(const WideString & str,size_t nStart,size_t * pSkip,size_t nMaxStep)272*3ac0a46fSAndroid Build Coastguard Worker int FX_ParseStringInteger(const WideString& str,
273*3ac0a46fSAndroid Build Coastguard Worker size_t nStart,
274*3ac0a46fSAndroid Build Coastguard Worker size_t* pSkip,
275*3ac0a46fSAndroid Build Coastguard Worker size_t nMaxStep) {
276*3ac0a46fSAndroid Build Coastguard Worker int nRet = 0;
277*3ac0a46fSAndroid Build Coastguard Worker size_t nSkip = 0;
278*3ac0a46fSAndroid Build Coastguard Worker for (size_t i = nStart; i < str.GetLength(); ++i) {
279*3ac0a46fSAndroid Build Coastguard Worker if (i - nStart > 10)
280*3ac0a46fSAndroid Build Coastguard Worker break;
281*3ac0a46fSAndroid Build Coastguard Worker
282*3ac0a46fSAndroid Build Coastguard Worker wchar_t c = str[i];
283*3ac0a46fSAndroid Build Coastguard Worker if (!FXSYS_IsDecimalDigit(c))
284*3ac0a46fSAndroid Build Coastguard Worker break;
285*3ac0a46fSAndroid Build Coastguard Worker
286*3ac0a46fSAndroid Build Coastguard Worker nRet = nRet * 10 + FXSYS_DecimalCharToInt(c);
287*3ac0a46fSAndroid Build Coastguard Worker ++nSkip;
288*3ac0a46fSAndroid Build Coastguard Worker if (nSkip >= nMaxStep)
289*3ac0a46fSAndroid Build Coastguard Worker break;
290*3ac0a46fSAndroid Build Coastguard Worker }
291*3ac0a46fSAndroid Build Coastguard Worker
292*3ac0a46fSAndroid Build Coastguard Worker *pSkip = nSkip;
293*3ac0a46fSAndroid Build Coastguard Worker return nRet;
294*3ac0a46fSAndroid Build Coastguard Worker }
295*3ac0a46fSAndroid Build Coastguard Worker
FX_ParseDateUsingFormat(const WideString & value,const WideString & format,double * result)296*3ac0a46fSAndroid Build Coastguard Worker ConversionStatus FX_ParseDateUsingFormat(const WideString& value,
297*3ac0a46fSAndroid Build Coastguard Worker const WideString& format,
298*3ac0a46fSAndroid Build Coastguard Worker double* result) {
299*3ac0a46fSAndroid Build Coastguard Worker double dt = FX_GetDateTime();
300*3ac0a46fSAndroid Build Coastguard Worker if (format.IsEmpty() || value.IsEmpty()) {
301*3ac0a46fSAndroid Build Coastguard Worker *result = dt;
302*3ac0a46fSAndroid Build Coastguard Worker return ConversionStatus::kSuccess;
303*3ac0a46fSAndroid Build Coastguard Worker }
304*3ac0a46fSAndroid Build Coastguard Worker
305*3ac0a46fSAndroid Build Coastguard Worker int nYear = FX_GetYearFromTime(dt);
306*3ac0a46fSAndroid Build Coastguard Worker int nMonth = FX_GetMonthFromTime(dt) + 1;
307*3ac0a46fSAndroid Build Coastguard Worker int nDay = FX_GetDayFromTime(dt);
308*3ac0a46fSAndroid Build Coastguard Worker int nHour = FX_GetHourFromTime(dt);
309*3ac0a46fSAndroid Build Coastguard Worker int nMin = FX_GetMinFromTime(dt);
310*3ac0a46fSAndroid Build Coastguard Worker int nSec = FX_GetSecFromTime(dt);
311*3ac0a46fSAndroid Build Coastguard Worker int nYearSub = 99; // nYear - 2000;
312*3ac0a46fSAndroid Build Coastguard Worker bool bPm = false;
313*3ac0a46fSAndroid Build Coastguard Worker bool bExit = false;
314*3ac0a46fSAndroid Build Coastguard Worker bool bBadFormat = false;
315*3ac0a46fSAndroid Build Coastguard Worker size_t i = 0;
316*3ac0a46fSAndroid Build Coastguard Worker size_t j = 0;
317*3ac0a46fSAndroid Build Coastguard Worker
318*3ac0a46fSAndroid Build Coastguard Worker while (i < format.GetLength()) {
319*3ac0a46fSAndroid Build Coastguard Worker if (bExit)
320*3ac0a46fSAndroid Build Coastguard Worker break;
321*3ac0a46fSAndroid Build Coastguard Worker
322*3ac0a46fSAndroid Build Coastguard Worker wchar_t c = format[i];
323*3ac0a46fSAndroid Build Coastguard Worker switch (c) {
324*3ac0a46fSAndroid Build Coastguard Worker case ':':
325*3ac0a46fSAndroid Build Coastguard Worker case '.':
326*3ac0a46fSAndroid Build Coastguard Worker case '-':
327*3ac0a46fSAndroid Build Coastguard Worker case '\\':
328*3ac0a46fSAndroid Build Coastguard Worker case '/':
329*3ac0a46fSAndroid Build Coastguard Worker i++;
330*3ac0a46fSAndroid Build Coastguard Worker j++;
331*3ac0a46fSAndroid Build Coastguard Worker break;
332*3ac0a46fSAndroid Build Coastguard Worker
333*3ac0a46fSAndroid Build Coastguard Worker case 'y':
334*3ac0a46fSAndroid Build Coastguard Worker case 'm':
335*3ac0a46fSAndroid Build Coastguard Worker case 'd':
336*3ac0a46fSAndroid Build Coastguard Worker case 'H':
337*3ac0a46fSAndroid Build Coastguard Worker case 'h':
338*3ac0a46fSAndroid Build Coastguard Worker case 'M':
339*3ac0a46fSAndroid Build Coastguard Worker case 's':
340*3ac0a46fSAndroid Build Coastguard Worker case 't': {
341*3ac0a46fSAndroid Build Coastguard Worker size_t oldj = j;
342*3ac0a46fSAndroid Build Coastguard Worker size_t nSkip = 0;
343*3ac0a46fSAndroid Build Coastguard Worker size_t remaining = format.GetLength() - i - 1;
344*3ac0a46fSAndroid Build Coastguard Worker
345*3ac0a46fSAndroid Build Coastguard Worker if (remaining == 0 || format[i + 1] != c) {
346*3ac0a46fSAndroid Build Coastguard Worker switch (c) {
347*3ac0a46fSAndroid Build Coastguard Worker case 'y':
348*3ac0a46fSAndroid Build Coastguard Worker i++;
349*3ac0a46fSAndroid Build Coastguard Worker j++;
350*3ac0a46fSAndroid Build Coastguard Worker break;
351*3ac0a46fSAndroid Build Coastguard Worker case 'm':
352*3ac0a46fSAndroid Build Coastguard Worker nMonth = FX_ParseStringInteger(value, j, &nSkip, 2);
353*3ac0a46fSAndroid Build Coastguard Worker i++;
354*3ac0a46fSAndroid Build Coastguard Worker j += nSkip;
355*3ac0a46fSAndroid Build Coastguard Worker break;
356*3ac0a46fSAndroid Build Coastguard Worker case 'd':
357*3ac0a46fSAndroid Build Coastguard Worker nDay = FX_ParseStringInteger(value, j, &nSkip, 2);
358*3ac0a46fSAndroid Build Coastguard Worker i++;
359*3ac0a46fSAndroid Build Coastguard Worker j += nSkip;
360*3ac0a46fSAndroid Build Coastguard Worker break;
361*3ac0a46fSAndroid Build Coastguard Worker case 'H':
362*3ac0a46fSAndroid Build Coastguard Worker nHour = FX_ParseStringInteger(value, j, &nSkip, 2);
363*3ac0a46fSAndroid Build Coastguard Worker i++;
364*3ac0a46fSAndroid Build Coastguard Worker j += nSkip;
365*3ac0a46fSAndroid Build Coastguard Worker break;
366*3ac0a46fSAndroid Build Coastguard Worker case 'h':
367*3ac0a46fSAndroid Build Coastguard Worker nHour = FX_ParseStringInteger(value, j, &nSkip, 2);
368*3ac0a46fSAndroid Build Coastguard Worker i++;
369*3ac0a46fSAndroid Build Coastguard Worker j += nSkip;
370*3ac0a46fSAndroid Build Coastguard Worker break;
371*3ac0a46fSAndroid Build Coastguard Worker case 'M':
372*3ac0a46fSAndroid Build Coastguard Worker nMin = FX_ParseStringInteger(value, j, &nSkip, 2);
373*3ac0a46fSAndroid Build Coastguard Worker i++;
374*3ac0a46fSAndroid Build Coastguard Worker j += nSkip;
375*3ac0a46fSAndroid Build Coastguard Worker break;
376*3ac0a46fSAndroid Build Coastguard Worker case 's':
377*3ac0a46fSAndroid Build Coastguard Worker nSec = FX_ParseStringInteger(value, j, &nSkip, 2);
378*3ac0a46fSAndroid Build Coastguard Worker i++;
379*3ac0a46fSAndroid Build Coastguard Worker j += nSkip;
380*3ac0a46fSAndroid Build Coastguard Worker break;
381*3ac0a46fSAndroid Build Coastguard Worker case 't':
382*3ac0a46fSAndroid Build Coastguard Worker bPm = (j < value.GetLength() && value[j] == 'p');
383*3ac0a46fSAndroid Build Coastguard Worker i++;
384*3ac0a46fSAndroid Build Coastguard Worker j++;
385*3ac0a46fSAndroid Build Coastguard Worker break;
386*3ac0a46fSAndroid Build Coastguard Worker }
387*3ac0a46fSAndroid Build Coastguard Worker } else if (remaining == 1 || format[i + 2] != c) {
388*3ac0a46fSAndroid Build Coastguard Worker switch (c) {
389*3ac0a46fSAndroid Build Coastguard Worker case 'y':
390*3ac0a46fSAndroid Build Coastguard Worker nYear = FX_ParseStringInteger(value, j, &nSkip, 2);
391*3ac0a46fSAndroid Build Coastguard Worker i += 2;
392*3ac0a46fSAndroid Build Coastguard Worker j += nSkip;
393*3ac0a46fSAndroid Build Coastguard Worker break;
394*3ac0a46fSAndroid Build Coastguard Worker case 'm':
395*3ac0a46fSAndroid Build Coastguard Worker nMonth = FX_ParseStringInteger(value, j, &nSkip, 2);
396*3ac0a46fSAndroid Build Coastguard Worker i += 2;
397*3ac0a46fSAndroid Build Coastguard Worker j += nSkip;
398*3ac0a46fSAndroid Build Coastguard Worker break;
399*3ac0a46fSAndroid Build Coastguard Worker case 'd':
400*3ac0a46fSAndroid Build Coastguard Worker nDay = FX_ParseStringInteger(value, j, &nSkip, 2);
401*3ac0a46fSAndroid Build Coastguard Worker i += 2;
402*3ac0a46fSAndroid Build Coastguard Worker j += nSkip;
403*3ac0a46fSAndroid Build Coastguard Worker break;
404*3ac0a46fSAndroid Build Coastguard Worker case 'H':
405*3ac0a46fSAndroid Build Coastguard Worker nHour = FX_ParseStringInteger(value, j, &nSkip, 2);
406*3ac0a46fSAndroid Build Coastguard Worker i += 2;
407*3ac0a46fSAndroid Build Coastguard Worker j += nSkip;
408*3ac0a46fSAndroid Build Coastguard Worker break;
409*3ac0a46fSAndroid Build Coastguard Worker case 'h':
410*3ac0a46fSAndroid Build Coastguard Worker nHour = FX_ParseStringInteger(value, j, &nSkip, 2);
411*3ac0a46fSAndroid Build Coastguard Worker i += 2;
412*3ac0a46fSAndroid Build Coastguard Worker j += nSkip;
413*3ac0a46fSAndroid Build Coastguard Worker break;
414*3ac0a46fSAndroid Build Coastguard Worker case 'M':
415*3ac0a46fSAndroid Build Coastguard Worker nMin = FX_ParseStringInteger(value, j, &nSkip, 2);
416*3ac0a46fSAndroid Build Coastguard Worker i += 2;
417*3ac0a46fSAndroid Build Coastguard Worker j += nSkip;
418*3ac0a46fSAndroid Build Coastguard Worker break;
419*3ac0a46fSAndroid Build Coastguard Worker case 's':
420*3ac0a46fSAndroid Build Coastguard Worker nSec = FX_ParseStringInteger(value, j, &nSkip, 2);
421*3ac0a46fSAndroid Build Coastguard Worker i += 2;
422*3ac0a46fSAndroid Build Coastguard Worker j += nSkip;
423*3ac0a46fSAndroid Build Coastguard Worker break;
424*3ac0a46fSAndroid Build Coastguard Worker case 't':
425*3ac0a46fSAndroid Build Coastguard Worker bPm = (j + 1 < value.GetLength() && value[j] == 'p' &&
426*3ac0a46fSAndroid Build Coastguard Worker value[j + 1] == 'm');
427*3ac0a46fSAndroid Build Coastguard Worker i += 2;
428*3ac0a46fSAndroid Build Coastguard Worker j += 2;
429*3ac0a46fSAndroid Build Coastguard Worker break;
430*3ac0a46fSAndroid Build Coastguard Worker }
431*3ac0a46fSAndroid Build Coastguard Worker } else if (remaining == 2 || format[i + 3] != c) {
432*3ac0a46fSAndroid Build Coastguard Worker switch (c) {
433*3ac0a46fSAndroid Build Coastguard Worker case 'm': {
434*3ac0a46fSAndroid Build Coastguard Worker bool bFind = false;
435*3ac0a46fSAndroid Build Coastguard Worker nSkip = FindSubWordLength(value, j);
436*3ac0a46fSAndroid Build Coastguard Worker if (nSkip == KMonthAbbreviationLength) {
437*3ac0a46fSAndroid Build Coastguard Worker WideString sMonth = value.Substr(j, KMonthAbbreviationLength);
438*3ac0a46fSAndroid Build Coastguard Worker for (size_t m = 0; m < std::size(kMonths); ++m) {
439*3ac0a46fSAndroid Build Coastguard Worker if (sMonth.CompareNoCase(kMonths[m]) == 0) {
440*3ac0a46fSAndroid Build Coastguard Worker nMonth = static_cast<int>(m) + 1;
441*3ac0a46fSAndroid Build Coastguard Worker i += 3;
442*3ac0a46fSAndroid Build Coastguard Worker j += nSkip;
443*3ac0a46fSAndroid Build Coastguard Worker bFind = true;
444*3ac0a46fSAndroid Build Coastguard Worker break;
445*3ac0a46fSAndroid Build Coastguard Worker }
446*3ac0a46fSAndroid Build Coastguard Worker }
447*3ac0a46fSAndroid Build Coastguard Worker }
448*3ac0a46fSAndroid Build Coastguard Worker
449*3ac0a46fSAndroid Build Coastguard Worker if (!bFind) {
450*3ac0a46fSAndroid Build Coastguard Worker nMonth = FX_ParseStringInteger(value, j, &nSkip, 3);
451*3ac0a46fSAndroid Build Coastguard Worker i += 3;
452*3ac0a46fSAndroid Build Coastguard Worker j += nSkip;
453*3ac0a46fSAndroid Build Coastguard Worker }
454*3ac0a46fSAndroid Build Coastguard Worker } break;
455*3ac0a46fSAndroid Build Coastguard Worker case 'y':
456*3ac0a46fSAndroid Build Coastguard Worker break;
457*3ac0a46fSAndroid Build Coastguard Worker default:
458*3ac0a46fSAndroid Build Coastguard Worker i += 3;
459*3ac0a46fSAndroid Build Coastguard Worker j += 3;
460*3ac0a46fSAndroid Build Coastguard Worker break;
461*3ac0a46fSAndroid Build Coastguard Worker }
462*3ac0a46fSAndroid Build Coastguard Worker } else if (remaining == 3 || format[i + 4] != c) {
463*3ac0a46fSAndroid Build Coastguard Worker switch (c) {
464*3ac0a46fSAndroid Build Coastguard Worker case 'y':
465*3ac0a46fSAndroid Build Coastguard Worker nYear = FX_ParseStringInteger(value, j, &nSkip, 4);
466*3ac0a46fSAndroid Build Coastguard Worker j += nSkip;
467*3ac0a46fSAndroid Build Coastguard Worker i += 4;
468*3ac0a46fSAndroid Build Coastguard Worker break;
469*3ac0a46fSAndroid Build Coastguard Worker case 'm': {
470*3ac0a46fSAndroid Build Coastguard Worker bool bFind = false;
471*3ac0a46fSAndroid Build Coastguard Worker nSkip = FindSubWordLength(value, j);
472*3ac0a46fSAndroid Build Coastguard Worker if (nSkip <= kLongestFullMonthLength) {
473*3ac0a46fSAndroid Build Coastguard Worker WideString sMonth = value.Substr(j, nSkip);
474*3ac0a46fSAndroid Build Coastguard Worker sMonth.MakeLower();
475*3ac0a46fSAndroid Build Coastguard Worker for (size_t m = 0; m < std::size(kFullMonths); ++m) {
476*3ac0a46fSAndroid Build Coastguard Worker WideString sFullMonths = WideString(kFullMonths[m]);
477*3ac0a46fSAndroid Build Coastguard Worker sFullMonths.MakeLower();
478*3ac0a46fSAndroid Build Coastguard Worker if (sFullMonths.Contains(sMonth.AsStringView())) {
479*3ac0a46fSAndroid Build Coastguard Worker nMonth = static_cast<int>(m) + 1;
480*3ac0a46fSAndroid Build Coastguard Worker i += 4;
481*3ac0a46fSAndroid Build Coastguard Worker j += nSkip;
482*3ac0a46fSAndroid Build Coastguard Worker bFind = true;
483*3ac0a46fSAndroid Build Coastguard Worker break;
484*3ac0a46fSAndroid Build Coastguard Worker }
485*3ac0a46fSAndroid Build Coastguard Worker }
486*3ac0a46fSAndroid Build Coastguard Worker }
487*3ac0a46fSAndroid Build Coastguard Worker if (!bFind) {
488*3ac0a46fSAndroid Build Coastguard Worker nMonth = FX_ParseStringInteger(value, j, &nSkip, 4);
489*3ac0a46fSAndroid Build Coastguard Worker i += 4;
490*3ac0a46fSAndroid Build Coastguard Worker j += nSkip;
491*3ac0a46fSAndroid Build Coastguard Worker }
492*3ac0a46fSAndroid Build Coastguard Worker } break;
493*3ac0a46fSAndroid Build Coastguard Worker default:
494*3ac0a46fSAndroid Build Coastguard Worker i += 4;
495*3ac0a46fSAndroid Build Coastguard Worker j += 4;
496*3ac0a46fSAndroid Build Coastguard Worker break;
497*3ac0a46fSAndroid Build Coastguard Worker }
498*3ac0a46fSAndroid Build Coastguard Worker } else {
499*3ac0a46fSAndroid Build Coastguard Worker if (j >= value.GetLength() || format[i] != value[j]) {
500*3ac0a46fSAndroid Build Coastguard Worker bBadFormat = true;
501*3ac0a46fSAndroid Build Coastguard Worker bExit = true;
502*3ac0a46fSAndroid Build Coastguard Worker }
503*3ac0a46fSAndroid Build Coastguard Worker i++;
504*3ac0a46fSAndroid Build Coastguard Worker j++;
505*3ac0a46fSAndroid Build Coastguard Worker }
506*3ac0a46fSAndroid Build Coastguard Worker
507*3ac0a46fSAndroid Build Coastguard Worker if (oldj == j) {
508*3ac0a46fSAndroid Build Coastguard Worker bBadFormat = true;
509*3ac0a46fSAndroid Build Coastguard Worker bExit = true;
510*3ac0a46fSAndroid Build Coastguard Worker }
511*3ac0a46fSAndroid Build Coastguard Worker break;
512*3ac0a46fSAndroid Build Coastguard Worker }
513*3ac0a46fSAndroid Build Coastguard Worker
514*3ac0a46fSAndroid Build Coastguard Worker default:
515*3ac0a46fSAndroid Build Coastguard Worker if (value.GetLength() <= j) {
516*3ac0a46fSAndroid Build Coastguard Worker bExit = true;
517*3ac0a46fSAndroid Build Coastguard Worker } else if (format[i] != value[j]) {
518*3ac0a46fSAndroid Build Coastguard Worker bBadFormat = true;
519*3ac0a46fSAndroid Build Coastguard Worker bExit = true;
520*3ac0a46fSAndroid Build Coastguard Worker }
521*3ac0a46fSAndroid Build Coastguard Worker
522*3ac0a46fSAndroid Build Coastguard Worker i++;
523*3ac0a46fSAndroid Build Coastguard Worker j++;
524*3ac0a46fSAndroid Build Coastguard Worker break;
525*3ac0a46fSAndroid Build Coastguard Worker }
526*3ac0a46fSAndroid Build Coastguard Worker }
527*3ac0a46fSAndroid Build Coastguard Worker
528*3ac0a46fSAndroid Build Coastguard Worker if (bBadFormat)
529*3ac0a46fSAndroid Build Coastguard Worker return ConversionStatus::kBadFormat;
530*3ac0a46fSAndroid Build Coastguard Worker
531*3ac0a46fSAndroid Build Coastguard Worker if (bPm)
532*3ac0a46fSAndroid Build Coastguard Worker nHour += 12;
533*3ac0a46fSAndroid Build Coastguard Worker
534*3ac0a46fSAndroid Build Coastguard Worker if (nYear >= 0 && nYear <= nYearSub)
535*3ac0a46fSAndroid Build Coastguard Worker nYear += 2000;
536*3ac0a46fSAndroid Build Coastguard Worker
537*3ac0a46fSAndroid Build Coastguard Worker if (!FX_IsValidMonth(nMonth) || !FX_IsValidDay(nDay) ||
538*3ac0a46fSAndroid Build Coastguard Worker !FX_IsValid24Hour(nHour) || !FX_IsValidMinute(nMin) ||
539*3ac0a46fSAndroid Build Coastguard Worker !FX_IsValidSecond(nSec)) {
540*3ac0a46fSAndroid Build Coastguard Worker return ConversionStatus::kBadDate;
541*3ac0a46fSAndroid Build Coastguard Worker }
542*3ac0a46fSAndroid Build Coastguard Worker
543*3ac0a46fSAndroid Build Coastguard Worker dt = FX_MakeDate(FX_MakeDay(nYear, nMonth - 1, nDay),
544*3ac0a46fSAndroid Build Coastguard Worker FX_MakeTime(nHour, nMin, nSec, 0));
545*3ac0a46fSAndroid Build Coastguard Worker if (isnan(dt))
546*3ac0a46fSAndroid Build Coastguard Worker return ConversionStatus::kBadDate;
547*3ac0a46fSAndroid Build Coastguard Worker
548*3ac0a46fSAndroid Build Coastguard Worker *result = dt;
549*3ac0a46fSAndroid Build Coastguard Worker return ConversionStatus::kSuccess;
550*3ac0a46fSAndroid Build Coastguard Worker }
551*3ac0a46fSAndroid Build Coastguard Worker
552*3ac0a46fSAndroid Build Coastguard Worker } // namespace fxjs
553