1 /*
2  * Copyright (c) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include "date_time_format_module.h"
16 #if (FEATURE_DATE_FORMAT == 1)
17 #include <cstring>
18 #include "ace_log.h"
19 #include "locale_util.h"
20 #include "keys.h"
21 #include "key_parser.h"
22 #include "string_util.h"
23 
24 namespace OHOS {
25 namespace ACELite {
26 using namespace I18N;
27 jerry_object_native_info_t DateTimeFormatModule::GC_CALLBACK = {.free_cb = DateTimeFormatModule::DeleteDateFormat};
28 
DateTimeFormatModule()29 DateTimeFormatModule::DateTimeFormatModule()
30     : dateFormat_(nullptr),
31       info_(nullptr),
32       timePattern_(I18N::AvailableDateTimeFormatPattern::SHORT),
33       datePattern_(I18N::AvailableDateTimeFormatPattern::SHORT),
34       weekStyle_(StyleState::UNKNOWN),
35       monthStyle_(StyleState::UNKNOWN),
36       numArray_(nullptr),
37       isSetTime_(false),
38       isSetDate_(false)
39 {
40     if (memset_s(digitArray_, TIME_NUMBER_LEN, 0, TIME_NUMBER_LEN) != EOK) {
41         HILOG_ERROR(HILOG_MODULE_ACE, "init digit array failed");
42     }
43 }
44 
Init(jerry_value_t intlHandle)45 void DateTimeFormatModule::Init(jerry_value_t intlHandle)
46 {
47     jerry_value_t constructor = jerry_create_external_function(CreateDateTimeFormat);
48     jerry_value_t format = jerry_create_external_function(Format);
49     jerry_value_t baseObj = jerry_create_object();
50     JerrySetNamedProperty(baseObj, "format", format);
51     JerrySetNamedProperty(constructor, "prototype", baseObj);
52     JerrySetNamedProperty(intlHandle, "DateTimeFormat", constructor);
53     ReleaseJerryValue(constructor, format, baseObj, VA_ARG_END_FLAG);
54 }
55 
~DateTimeFormatModule()56 DateTimeFormatModule::~DateTimeFormatModule()
57 {
58     ACE_DELETE(dateFormat_);
59     ACE_DELETE(info_);
60     ReleaseNumArray();
61 }
62 
ReleaseNumArray()63 void DateTimeFormatModule::ReleaseNumArray()
64 {
65     if (numArray_ != nullptr) {
66         for (int i = 0; i < MAX_NUM_LEN; i++) {
67             ACE_FREE(numArray_[i]);
68         }
69         ace_free(numArray_);
70         numArray_ = nullptr;
71     }
72 }
73 
InitNumArray(LocaleInfo info)74 bool DateTimeFormatModule::InitNumArray(LocaleInfo info)
75 {
76     ReleaseNumArray();
77     int status = 0;
78     NumberFormat numFormat(info, status);
79     if (status == I18nStatus::IERROR) {
80         HILOG_ERROR(HILOG_MODULE_ACE, "init number format failed");
81         return false;
82     }
83     numArray_ = reinterpret_cast<char **>(ace_malloc(MAX_NUM_LEN * sizeof(char *)));
84     if (numArray_ == nullptr) {
85         HILOG_ERROR(HILOG_MODULE_ACE, "malloc number array failed");
86         return false;
87     }
88     // get the number value 0-9 in specified locale info
89     for (uint8_t i = 0; i < MAX_NUM_LEN; i++) {
90         int numStatus = 0;
91         std::string result = numFormat.Format(i, numStatus);
92         if ((numStatus == I18nStatus::IERROR) || (result.empty())) {
93             HILOG_ERROR(HILOG_MODULE_ACE, "init array %{public}d failed", i);
94             ReleaseNumArray();
95             return false;
96         }
97         numArray_[i] = StringUtil::Copy(result.c_str());
98     }
99     return true;
100 }
101 
CreateDateTimeFormat(const jerry_value_t func,const jerry_value_t context,const jerry_value_t args[],const jerry_length_t argsNum)102 jerry_value_t DateTimeFormatModule::CreateDateTimeFormat(const jerry_value_t func,
103                                                          const jerry_value_t context,
104                                                          const jerry_value_t args[],
105                                                          const jerry_length_t argsNum)
106 {
107     if (!jerry_value_is_constructor(func)) {
108         return jerry_create_error(JERRY_ERROR_EVAL,
109                                   reinterpret_cast<const jerry_char_t *>("use new to create number format"));
110     }
111     DateTimeFormatModule *dateModel = new DateTimeFormatModule();
112     if (dateModel == nullptr) {
113         return jerry_create_error(JERRY_ERROR_EVAL,
114                                   reinterpret_cast<const jerry_char_t *>("create date format model failed"));
115     }
116     char *value = nullptr;
117     if (argsNum >= 1) {
118         value = MallocStringOf(args[0]);
119     }
120     dateModel->info_ = LocaleUtil::GetLocaleInfo(value);
121     ACE_FREE(value);
122     if (dateModel->info_ == nullptr) {
123         HILOG_ERROR(HILOG_MODULE_ACE, "create LocaleInfo failed");
124         delete dateModel;
125         dateModel = nullptr;
126         return jerry_create_error(JERRY_ERROR_COMMON, reinterpret_cast<const jerry_char_t *>("lack of memory"));
127     }
128     // set the default format pattern year(numeric)-month(numeric)-day(numeric)
129     dateModel->dateFormat_ = new DateTimeFormat(AvailableDateTimeFormatPattern::SHORT, *dateModel->info_);
130     if ((dateModel->dateFormat_ == nullptr) || (!dateModel->InitNumArray(*dateModel->info_))) {
131         delete dateModel;
132         dateModel = nullptr;
133         return jerry_create_error(JERRY_ERROR_EVAL,
134                                   reinterpret_cast<const jerry_char_t *>("create dateTimeFormat failed"));
135     }
136     if (argsNum > 1) {
137         // deal the year month day style
138         const char *dateRes = dateModel->SetDateStyle(args[1]);
139         // deal the hour minute second style
140         const char *timeRes = dateModel->SetTimeStyle(args[1]);
141         // if dateRes or timeRes is not nullptr, the date style or time style is invalid
142         if ((dateRes != nullptr) || (timeRes != nullptr)) {
143             delete dateModel;
144             dateModel = nullptr;
145             const char *result = (dateRes != nullptr) ? dateRes : timeRes;
146             return (result == nullptr)
147                        ? jerry_create_null()
148                        : jerry_create_error(JERRY_ERROR_EVAL, reinterpret_cast<const jerry_char_t *>(result));
149         }
150     }
151     jerry_set_object_native_pointer(context, dateModel, &GC_CALLBACK);
152     return UNDEFINED;
153 }
154 
ConvertLocalToGMT(time_t & time) const155 void DateTimeFormatModule::ConvertLocalToGMT(time_t &time) const
156 {
157     struct tm gmTime = {0};
158     struct tm local = {0};
159     gmtime_r(&time, &gmTime);
160     localtime_r(&time, &local);
161     time += mktime(&local) - mktime(&gmTime);
162 }
163 
Format(const jerry_value_t func,const jerry_value_t context,const jerry_value_t args[],const jerry_length_t argsNum)164 jerry_value_t DateTimeFormatModule::Format(const jerry_value_t func,
165                                            const jerry_value_t context,
166                                            const jerry_value_t args[],
167                                            const jerry_length_t argsNum)
168 {
169     if (!jerry_is_feature_enabled(JERRY_FEATURE_DATE)) {
170         return jerry_create_error(JERRY_ERROR_EVAL, reinterpret_cast<const jerry_char_t *>("the date is not enabled"));
171     }
172     if (argsNum < 1) {
173         return jerry_create_error(JERRY_ERROR_EVAL, reinterpret_cast<const jerry_char_t *>("date is invalid"));
174     }
175     DateTimeFormatModule *formatter = nullptr;
176     if (!(jerry_get_object_native_pointer(context, reinterpret_cast<void **>(&formatter), &GC_CALLBACK)) ||
177         (formatter == nullptr) || (formatter->dateFormat_ == nullptr)) {
178         HILOG_ERROR(HILOG_MODULE_ACE, "get format object failed");
179         return UNDEFINED;
180     }
181     const uint16_t msToSec = 1000;
182     time_t dateTime = static_cast<time_t>(formatter->GetTimeVal(args[0], "getTime") / msToSec);
183     formatter->ConvertLocalToGMT(dateTime);
184     if (formatter->isSetDate_ || formatter->isSetTime_) {
185         uint8_t maxSize = 128;
186         char *res = reinterpret_cast<char *>(ace_malloc(maxSize));
187         if (res == nullptr) {
188             return UNDEFINED;
189         }
190         res[0] = '\0';
191         uint8_t start = 0;
192         if (formatter->isSetDate_) {
193             formatter->FormatDate(dateTime, res, maxSize, start);
194         }
195         if (formatter->isSetTime_) {
196             formatter->FormatTime(dateTime, res, maxSize, start);
197         }
198         jerry_value_t resultProp = jerry_create_string(reinterpret_cast<jerry_char_t *>(res));
199         ace_free(res);
200         res = nullptr;
201         return resultProp;
202     }
203     // the style group is not support, format the lonely support style week or month
204     if (formatter->weekStyle_ != StyleState::UNKNOWN) {
205         int8_t weekIndex = static_cast<int8_t>(formatter->GetTimeVal(args[0], "getDay"));
206         DateTimeDataType type = (formatter->weekStyle_ == StyleState::LONG) ? FORMAT_WIDE : FORMAT_ABBR;
207         std::string weekName = formatter->dateFormat_->GetWeekName(weekIndex, type);
208         return jerry_create_string(reinterpret_cast<const jerry_char_t *>(weekName.c_str()));
209     } else if (formatter->monthStyle_ != StyleState::UNKNOWN) {
210         return formatter->GetMonthVal(args[0]);
211     }
212     // if the style is valid, the style pattern is not support, format the date style as default style
213     std::string result, timeZone;
214     I18nStatus status = I18nStatus::ISUCCESS;
215     formatter->dateFormat_->Format(dateTime, timeZone, result, status);
216     if (status == I18nStatus::IERROR) {
217         return jerry_create_error(JERRY_ERROR_EVAL, reinterpret_cast<const jerry_char_t *>("format date failed"));
218     }
219     return jerry_create_string(reinterpret_cast<const jerry_char_t *>(result.c_str()));
220 }
221 
GetMonthVal(jerry_value_t time) const222 jerry_value_t DateTimeFormatModule::GetMonthVal(jerry_value_t time) const
223 {
224     int month = static_cast<int>(GetTimeVal(time, "getMonth"));
225     // format the long style ans short month style
226     if ((monthStyle_ == StyleState::LONG) || (monthStyle_ == StyleState::SHORT)) {
227         DateTimeDataType type = (monthStyle_ == StyleState::LONG) ? FORMAT_WIDE : FORMAT_ABBR;
228         std::string monthName = dateFormat_->GetMonthName(month, type);
229         return jerry_create_string(reinterpret_cast<const jerry_char_t *>(monthName.c_str()));
230     }
231     const uint8_t monthIndex = 1;
232     const uint8_t maxMonthLen = 20;
233     uint8_t start = 0;
234     char *result = reinterpret_cast<char *>(ace_malloc(maxMonthLen));
235     if (result == nullptr) {
236         HILOG_ERROR(HILOG_MODULE_ACE, "malloc month str failed");
237         return jerry_create_error(JERRY_ERROR_EVAL, reinterpret_cast<const jerry_char_t *>("memory is not enough"));
238     }
239     std::string date = dateFormat_->GetMonthName(month, DateTimeDataType::STANDALONE_ABBR);
240     // format the number month to 2-digit or not through the month digit flag
241     jerry_value_t resultProp = UNDEFINED;
242     if (FormatDigit(date.c_str(), result, maxMonthLen, start, digitArray_[monthIndex]) > 0) {
243         resultProp = jerry_create_string(reinterpret_cast<jerry_char_t *>(result));
244     }
245     ace_free(result);
246     result = nullptr;
247     return resultProp;
248 }
249 
GetNumInDate(const char * date) const250 uint8_t DateTimeFormatModule::GetNumInDate(const char *date) const
251 {
252     if (date == nullptr) {
253         return 0;
254     }
255     uint8_t len = 0;
256     int16_t dateLen = strlen(date);
257     bool check = true;
258     for (int16_t index = 0; index < dateLen; index++) {
259         int16_t numEnd = GetNumberEnd(date, index);
260         if (numEnd >= 0) {
261             if (check) {
262                 len++;
263                 check = false;
264             }
265             index = numEnd; // check the number from the next character
266         } else {
267             check = true;
268         }
269     }
270     return len;
271 }
272 
FormatDate(time_t time,char * res,const uint8_t resSize,uint8_t & start)273 void DateTimeFormatModule::FormatDate(time_t time, char *res, const uint8_t resSize, uint8_t &start)
274 {
275     if (dateFormat_ == nullptr) {
276         HILOG_ERROR(HILOG_MODULE_ACE, "dateFormat is nullptr");
277         return;
278     }
279     std::string result, timeZone, check;
280     I18nStatus status = I18nStatus::ISUCCESS;
281     dateFormat_->ApplyPattern(datePattern_);
282     dateFormat_->Format(time, timeZone, result, status);
283     if (status == I18nStatus::IERROR) {
284         return;
285     }
286     bool isMonthFirst = false;
287     // if month is numeric, format the date to full year-month-day, if the first digit is number, the format string
288     // is day-month-year or year-month-day, else month-day-year
289     const char *dateStr = result.c_str();
290     const uint8_t numMaxInDate = 3;
291     uint8_t numInDate = GetNumInDate(dateStr);
292     if (numInDate == numMaxInDate) {
293         dateFormat_->ApplyPattern(AvailableDateTimeFormatPattern::YEAR_WIDE_MONTH_DAY);
294         dateFormat_->Format(time, timeZone, check, status);
295         if (status == I18nStatus::IERROR) {
296             return;
297         }
298         isMonthFirst = (GetNumberEnd(check.c_str(), 0) < 0);
299     }
300     const uint8_t dayStyleIndex = 2;   // the day number style index
301     const uint8_t monthStyleIndex = 1; // the month style index
302     uint8_t firstFormatIndex = dayStyleIndex;
303     int16_t formatIndex = 0;
304     if (numInDate == numMaxInDate) {
305         uint8_t secondFormatIndex = monthStyleIndex;
306         if (isMonthFirst) {
307             // set the format order month-day-year
308             firstFormatIndex = monthStyleIndex;
309             secondFormatIndex = dayStyleIndex;
310         }
311         formatIndex = FormatDigit(dateStr, res, resSize, start, digitArray_[firstFormatIndex]);
312         if (formatIndex < 0) {
313             HILOG_ERROR(HILOG_MODULE_ACE, "format the first number in date str failed");
314             return;
315         }
316         formatIndex =
317             FormatDigit(dateStr + formatIndex, res, resSize, start, digitArray_[secondFormatIndex]) + formatIndex;
318     } else {
319         // format the day digit or year digit
320         formatIndex = FormatDigit(dateStr, res, resSize, start, digitArray_[dayStyleIndex]);
321     }
322     if (formatIndex < 0) {
323         HILOG_ERROR(HILOG_MODULE_ACE, "format date string failed");
324         return;
325     }
326     // format the year
327     if (FormatDigit(dateStr + formatIndex, res, resSize, start, digitArray_[firstFormatIndex]) < 0) {
328         res[0] = '\0';
329     }
330 }
331 
FormatTime(time_t time,char * res,const uint8_t resSize,uint8_t & start)332 void DateTimeFormatModule::FormatTime(time_t time, char *res, const uint8_t resSize, uint8_t &start)
333 {
334     if (res == nullptr) {
335         return;
336     }
337     if (start != 0) {
338         res[start] = ' ';
339         start++;
340     }
341     std::string result, timeZone;
342     I18nStatus status = I18nStatus::ISUCCESS;
343     dateFormat_->ApplyPattern(timePattern_);
344     dateFormat_->Format(time, timeZone, result, status);
345     if (status == I18nStatus::IERROR) {
346         return;
347     }
348     const uint8_t hourIndex = 3;
349     const uint8_t minuteIndex = 4;
350     const uint8_t secondIndex = 5;
351     const char *timeStr = result.c_str();
352     int16_t curIndex = 0;
353     curIndex = FormatDigit(timeStr, res, resSize, start, digitArray_[hourIndex]);
354     if (curIndex < 0) {
355         HILOG_ERROR(HILOG_MODULE_ACE, "format hour style failed");
356         return;
357     }
358     curIndex = FormatDigit(timeStr + curIndex, res, resSize, start, digitArray_[minuteIndex]) + curIndex;
359     if (curIndex < 0) {
360         HILOG_ERROR(HILOG_MODULE_ACE, "format minute style failed");
361         return;
362     }
363     if (FormatDigit(timeStr + curIndex, res, resSize, start, digitArray_[secondIndex]) < 0) {
364         res[0] = '\0';
365     }
366 }
367 
FormatDigit(const char * time,char * res,const uint8_t resSize,uint8_t & start,bool is2Digit) const368 int16_t DateTimeFormatModule::FormatDigit(const char *time,
369                                           char *res,
370                                           const uint8_t resSize,
371                                           uint8_t &start,
372                                           bool is2Digit) const
373 {
374     if ((time == nullptr) || (strlen(time) == 0)) {
375         return 0;
376     }
377     int16_t index = GetNum(time);
378     if (index >= 0) {
379         if (strncpy_s(res + start, resSize - start + 1, time, index + 1) != 0) {
380             HILOG_ERROR(HILOG_MODULE_ACE, "copy string before number failed");
381             return -1;
382         }
383         start = start + index + 1;
384     }
385     index = (index < 0) ? 0 : (index + 1);
386     int16_t num1 = GetNumberEnd(time, index);
387     if (num1 < 0) {
388         return -1;
389     }
390     int16_t num2 = GetNumberEnd(time, num1 + 1);
391     int16_t numEnd = num1;
392     if (num2 < 0) {
393         if (is2Digit && (numArray_[0] != nullptr)) {
394             uint8_t zeroLen = strlen(numArray_[0]);
395             if (strncpy_s(res + start, resSize - start + 1, numArray_[0], zeroLen)) {
396                 HILOG_ERROR(HILOG_MODULE_ACE, "add zero failed");
397                 return -1;
398             }
399             start = start + zeroLen;
400         }
401     } else {
402         int num3 = GetNumberEnd(time, num2 + 1);
403         // format the 4 digit year
404         if (num3 >= 0) {
405             // the year style is 2-digit
406             if (digitArray_[0]) {
407                 index = num2 + 1;
408             }
409             numEnd = GetNumberEnd(time, num3 + 1);
410         } else {
411             numEnd = num2;
412         }
413     }
414     numEnd = GetNum(time + numEnd + 1) + numEnd + 1;
415     if (numEnd >= index) {
416         if (strncpy_s(res + start, resSize - start + 1, time + index, numEnd - index + 1) != 0) {
417             HILOG_ERROR(HILOG_MODULE_ACE, "copy string failed");
418             return -1;
419         }
420         start = start + numEnd - index + 1;
421     }
422     res[start] = '\0';
423     return numEnd + 1;
424 }
425 
GetNum(const char * format) const426 int16_t DateTimeFormatModule::GetNum(const char *format) const
427 {
428     uint8_t len = strlen(format);
429     int16_t res = -1;
430     for (uint8_t index = 0; index < len; index++) {
431         int16_t numIndex = GetNumberEnd(format, index);
432         if (numIndex >= 0) {
433             break;
434         } else {
435             res = index;
436         }
437     }
438     return res;
439 }
440 
GetNumberEnd(const char * compare,uint8_t start) const441 int16_t DateTimeFormatModule::GetNumberEnd(const char *compare, uint8_t start) const
442 {
443     for (uint8_t index = 0; index < MAX_NUM_LEN; index++) {
444         const char *str = compare + start;
445         if (StringUtil::StartsWith(str, numArray_[index])) {
446             return start + strlen(numArray_[index]) - 1;
447         }
448     }
449     return -1;
450 }
451 
GetTimeVal(jerry_value_t time,const char * funcName) const452 double DateTimeFormatModule::GetTimeVal(jerry_value_t time, const char *funcName) const
453 {
454     jerry_value_t funcProp = jerryx_get_property_str(time, funcName);
455     if (IS_UNDEFINED(funcProp)) {
456         return 0;
457     }
458     jerry_value_t result = CallJSFunction(funcProp, time, nullptr, 0);
459     double timeVal = jerry_get_number_value(result);
460     ReleaseJerryValue(funcProp, result, VA_ARG_END_FLAG);
461     return timeVal;
462 }
463 
DeleteDateFormat(void * pointer)464 void DateTimeFormatModule::DeleteDateFormat(void *pointer)
465 {
466     DateTimeFormatModule *formatter = reinterpret_cast<DateTimeFormatModule *>(pointer);
467     if (formatter != nullptr) {
468         delete formatter;
469         formatter = nullptr;
470     }
471 }
472 
SetDateStyle(jerry_value_t style)473 const char *DateTimeFormatModule::SetDateStyle(jerry_value_t style)
474 {
475     weekStyle_ = GetWeekdayStyle(style);
476     if (weekStyle_ == StyleState::ERROR) {
477         return "the weekday style value is out of range";
478     }
479     const uint8_t yearIndex = 0;
480     StyleState yearStyle = GetStyle(style, "year", yearIndex);
481     if (yearStyle == StyleState::ERROR) {
482         return "the year style value is out of range";
483     }
484     monthStyle_ = GetMonthStyle(style);
485     if (monthStyle_ == StyleState::ERROR) {
486         return "the month style value is out of range";
487     }
488     const uint8_t dayIndex = 2;
489     StyleState dayStyle = GetStyle(style, "day", dayIndex);
490     if (dayStyle == StyleState::ERROR) {
491         return "the day style value is out of range";
492     }
493     isSetDate_ = SetDatePattern(weekStyle_, yearStyle, monthStyle_, dayStyle);
494     return nullptr;
495 }
496 
GetWeekdayStyle(jerry_value_t style) const497 DateTimeFormatModule::StyleState DateTimeFormatModule::GetWeekdayStyle(jerry_value_t style) const
498 {
499     if (!jerryx_has_property_str(style, "weekday")) {
500         return StyleState::UNKNOWN;
501     }
502     StyleState weekdayStyle = StyleState::UNKNOWN;
503     jerry_value_t weekProp = jerryx_get_property_str(style, "weekday");
504     uint16_t len = 0;
505     char *weekStyle = MallocStringOf(weekProp, &len);
506     jerry_release_value(weekProp);
507     uint16_t weekId = KeyParser::ParseKeyId(weekStyle, len);
508     ACE_FREE(weekStyle);
509     if (!KeyParser::IsKeyValid(weekId)) {
510         return StyleState::ERROR;
511     }
512     switch (weekId) {
513         case K_SHORT: {
514             weekdayStyle = StyleState::SHORT;
515             break;
516         }
517         case K_LONG: {
518             weekdayStyle = StyleState::LONG;
519             break;
520         }
521         default: {
522             weekdayStyle = StyleState::ERROR;
523             break;
524         }
525     }
526     return weekdayStyle;
527 }
528 
GetMonthStyle(jerry_value_t style)529 DateTimeFormatModule::StyleState DateTimeFormatModule::GetMonthStyle(jerry_value_t style)
530 {
531     if (!jerryx_has_property_str(style, "month")) {
532         return StyleState::UNKNOWN;
533     }
534     jerry_value_t monthProp = jerryx_get_property_str(style, "month");
535     uint16_t len = 0;
536     char *monthStyle = MallocStringOf(monthProp, &len);
537     jerry_release_value(monthProp);
538     uint16_t monthId = KeyParser::ParseKeyId(monthStyle, len);
539     ACE_FREE(monthStyle);
540     if (!KeyParser::IsKeyValid(monthId)) {
541         return StyleState::ERROR;
542     }
543     StyleState monthStyleState = StyleState::UNKNOWN;
544     switch (monthId) {
545         case K_LONG: {
546             monthStyleState = StyleState::LONG;
547             break;
548         }
549         case K_SHORT: {
550             monthStyleState = StyleState::SHORT;
551             break;
552         }
553         case K_NUMERIC: {
554             monthStyleState = StyleState::NUMERIC;
555             break;
556         }
557         case K_DIGIT2: {
558             const uint8_t monthIndex = 1;
559             digitArray_[monthIndex] = true;
560             monthStyleState = StyleState::NUMERIC;
561             break;
562         }
563         default: {
564             monthStyleState = StyleState::ERROR;
565             break;
566         }
567     }
568     return monthStyleState;
569 }
570 
GetStyle(jerry_value_t style,const char * attrName,const uint8_t index)571 DateTimeFormatModule::StyleState DateTimeFormatModule::GetStyle(jerry_value_t style,
572                                                                 const char *attrName,
573                                                                 const uint8_t index)
574 {
575     if (!jerryx_has_property_str(style, attrName)) {
576         return StyleState::UNKNOWN;
577     }
578     jerry_value_t attrProp = jerryx_get_property_str(style, attrName);
579     uint16_t len = 0;
580     char *attrVal = MallocStringOf(attrProp, &len);
581     jerry_release_value(attrProp);
582     uint16_t attrId = KeyParser::ParseKeyId(attrVal, len);
583     ACE_FREE(attrVal);
584     if (!KeyParser::IsKeyValid(attrId)) {
585         return StyleState::ERROR;
586     }
587     StyleState styleState = StyleState::UNKNOWN;
588     switch (attrId) {
589         case K_NUMERIC: {
590             styleState = StyleState::NUMERIC;
591             break;
592         }
593         case K_DIGIT2: {
594             digitArray_[index] = true;
595             styleState = StyleState::NUMERIC;
596             break;
597         }
598         default: {
599             styleState = StyleState::ERROR;
600             break;
601         }
602     }
603     return styleState;
604 }
605 
SetTimeStyle(jerry_value_t style)606 const char *DateTimeFormatModule::SetTimeStyle(jerry_value_t style)
607 {
608     const uint8_t hourIndex = 3;
609     StyleState hourStyle = GetStyle(style, "hour", hourIndex);
610     if (hourStyle == StyleState::ERROR) {
611         return "the hour style value is out of range";
612     }
613     const uint8_t minuteIndex = 4;
614     StyleState minuteStyle = GetStyle(style, "minute", minuteIndex);
615     if (minuteStyle == StyleState::ERROR) {
616         return "the minute style value is out of range";
617     }
618     const uint8_t secondIndex = 5;
619     StyleState secondStyle = GetStyle(style, "second", secondIndex);
620     if (secondStyle == StyleState::ERROR) {
621         return "the second style value is out of range";
622     }
623     // the hour12 style is invalid when hour style is not set
624     if (hourStyle != StyleState::UNKNOWN) {
625         if (jerryx_has_property_str(style, "hour12")) {
626             jerry_value_t hour12Style = jerryx_get_property_str(style, "hour12");
627             bool isHour12 = BoolOf(hour12Style);
628             jerry_release_value(hour12Style);
629             hourStyle = isHour12 ? StyleState::HOUR12 : StyleState::HOUR24;
630         } else {
631             hourStyle = StyleState::HOUR;
632         }
633     }
634     // find the most suitable mode for hour minute second style
635     isSetTime_ = GetTimePattern(hourStyle, minuteStyle, secondStyle);
636     if ((!isSetTime_) && (weekStyle_ == StyleState::UNKNOWN) && (monthStyle_ == StyleState::UNKNOWN)) {
637         isSetTime_ = true;
638         timePattern_ = AvailableDateTimeFormatPattern::SHORT;
639     }
640     return nullptr;
641 }
642 
SetMonthPattern(StyleState monthStyle,AvailableDateTimeFormatPattern widePattern,AvailableDateTimeFormatPattern shortPattern,AvailableDateTimeFormatPattern numberPattern)643 bool DateTimeFormatModule::SetMonthPattern(StyleState monthStyle,
644                                            AvailableDateTimeFormatPattern widePattern,
645                                            AvailableDateTimeFormatPattern shortPattern,
646                                            AvailableDateTimeFormatPattern numberPattern)
647 {
648     bool result = true;
649     switch (monthStyle) {
650         case StyleState::LONG: {
651             datePattern_ = widePattern;
652             break;
653         }
654         case StyleState::SHORT: {
655             datePattern_ = shortPattern;
656             break;
657         }
658         case StyleState::NUMERIC: {
659             datePattern_ = numberPattern;
660             break;
661         }
662         default: {
663             result = false;
664             break;
665         }
666     }
667     return result;
668 }
669 
SetDatePattern(StyleState weekdayStyle,StyleState yearStyle,StyleState monthStyle,StyleState dayStyle)670 bool DateTimeFormatModule::SetDatePattern(StyleState weekdayStyle,
671                                           StyleState yearStyle,
672                                           StyleState monthStyle,
673                                           StyleState dayStyle)
674 {
675     // the pattern support is (weekday)-year-month-day
676     if ((yearStyle == StyleState::UNKNOWN) || (dayStyle == StyleState::UNKNOWN) ||
677         (monthStyle == StyleState::UNKNOWN)) {
678         return false;
679     }
680     bool result = true;
681     switch (weekdayStyle) {
682         case StyleState::LONG: {
683             result = SetMonthPattern(monthStyle, AvailableDateTimeFormatPattern::FULL,
684                                      AvailableDateTimeFormatPattern::YEAR_ABBR_MONTH_WIDE_WEEKDAY_DAY,
685                                      AvailableDateTimeFormatPattern::YEAR_SHORT_MONTH_WIDE_WEEKDAY_DAY);
686             break;
687         }
688         case StyleState::SHORT: {
689             result = SetMonthPattern(monthStyle, AvailableDateTimeFormatPattern::YEAR_WIDE_MONTH_ABBR_WEEKDAY_DAY,
690                                      AvailableDateTimeFormatPattern::YEAR_ABBR_MONTH_ABBR_WEEKDAY_DAY,
691                                      AvailableDateTimeFormatPattern::YEAR_SHORT_MONTH_ABBR_WEEKDAY_DAY);
692             break;
693         }
694         default: {
695             result = SetMonthPattern(monthStyle, AvailableDateTimeFormatPattern::YEAR_WIDE_MONTH_DAY,
696                                      AvailableDateTimeFormatPattern::MEDIUM, AvailableDateTimeFormatPattern::SHORT);
697             break;
698         }
699     }
700     return result;
701 }
702 
GetTimePattern(StyleState hourStyle,StyleState minuteStyle,StyleState secondStyle)703 bool DateTimeFormatModule::GetTimePattern(StyleState hourStyle, StyleState minuteStyle, StyleState secondStyle)
704 {
705     // the support pattern is hour-minute-(second)
706     if ((hourStyle == StyleState::UNKNOWN) || (minuteStyle == StyleState::UNKNOWN)) {
707         return false;
708     }
709     bool result = true;
710     switch (hourStyle) {
711         case StyleState::HOUR12: {
712             timePattern_ = (secondStyle == StyleState::UNKNOWN) ? AvailableDateTimeFormatPattern::HOUR12_MINUTE
713                                                                 : AvailableDateTimeFormatPattern::HOUR12_MINUTE_SECOND;
714             break;
715         }
716         case StyleState::HOUR24: {
717             timePattern_ = (secondStyle == StyleState::UNKNOWN) ? AvailableDateTimeFormatPattern::HOUR24_MINUTE
718                                                                 : AvailableDateTimeFormatPattern::HOUR24_MINUTE_SECOND;
719             break;
720         }
721         case StyleState::HOUR: {
722             timePattern_ =
723                 (secondStyle == StyleState::UNKNOWN) ? AvailableDateTimeFormatPattern::HOUR_MINUTE : HOUR_MINUTE_SECOND;
724             break;
725         }
726         default: {
727             result = false;
728             break;
729         }
730     }
731     return result;
732 }
733 } // namespace ACELite
734 } // namespace OHOS
735 #endif
736