1 /* 2 * Copyright (c) 2023 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 16 #ifndef ECMASCRIPT_DATE_PARSE_H 17 #define ECMASCRIPT_DATE_PARSE_H 18 19 #include "ecmascript/js_date.h" 20 21 namespace panda::ecmascript { 22 class DateParse { 23 public: 24 static const std::array<CString, MOUTH_PER_YEAR> MONTH_NAME; 25 static bool ParseDateString(const char *str, int length, int *time); 26 27 private: IsBetween(int n,int lower,int hign)28 static bool IsBetween(int n, int lower, int hign) 29 { 30 if (n < lower || n > hign) { 31 return false; 32 } 33 return true; 34 } 35 class StringReader { 36 public: StringReader(const char * str,int length)37 explicit StringReader(const char *str, int length) : data_(str), length_(length) 38 { 39 NextChar(); 40 } 41 NextChar()42 void NextChar() 43 { 44 value_ = (index_ < length_) ? data_[index_] : DEL; 45 index_++; 46 } 47 GetIndex()48 int GetIndex() const 49 { 50 return index_; 51 } 52 ReadNumber(int * len)53 int ReadNumber(int *len) 54 { 55 int index = 0; 56 int num = 0; 57 while (IsDigit()) { 58 num = (value_ - '0') + num * JSDate::TEN; 59 index++; 60 const int maxDecimal = (std::numeric_limits<int>::max() - JSDate::NUM_NINE) / JSDate::TEN; 61 if (num > maxDecimal) { 62 break; 63 } 64 NextChar(); 65 } 66 // read the followed digit 67 while (IsDigit()) { 68 NextChar(); 69 } 70 *len = index; 71 return num; 72 } 73 ReadAlphabet(char * word,int size)74 int ReadAlphabet(char *word, int size) 75 { 76 int length = 0; 77 for (; IsAlpha(); length++) { 78 if (length < size) { 79 word[length] = GetLower(value_); 80 } 81 NextChar(); 82 } 83 return length; 84 } 85 GetLower(char ch)86 char GetLower(char ch) 87 { 88 if (ch >= 'A' && ch <= 'Z') { 89 // 32: 'a' - 'A' 90 return ch + 32; 91 } 92 return ch; 93 } 94 IsDigit()95 bool IsDigit() const 96 { 97 if (value_ >= '0' && value_ <= '9') { 98 return true; 99 } 100 return false; 101 } 102 IsSign()103 bool IsSign() const 104 { 105 if (value_ == '+' || value_ == '-') { 106 return true; 107 } 108 return false; 109 } 110 IsEnd()111 bool IsEnd() const 112 { 113 return value_ == DEL; 114 } 115 IsThisChar(char ch)116 bool IsThisChar(char ch) const 117 { 118 return value_ == ch; 119 } 120 IsAlpha()121 bool IsAlpha() const 122 { 123 if (value_ >= 'A' && value_ <= 'z') { 124 return true; 125 } 126 return false; 127 } 128 IsSpaceOrTab()129 bool IsSpaceOrTab() const 130 { 131 if (value_ == ' ' || value_ == '\t') { 132 return true; 133 } 134 return false; 135 } 136 IsChar(char ch)137 bool IsChar(char ch) 138 { 139 if (value_ != ch) { 140 return false; 141 } 142 return true; 143 } 144 private: 145 const char *data_; 146 int index_ {0}; 147 int length_; 148 char value_; 149 }; 150 151 enum DateValueType : int8_t { 152 DATE_INVALID, 153 DATE_UNKNOWN, 154 DATE_NUMBER, 155 DATE_SYMBOL, 156 DATE_SPACE, 157 DATE_STRING_END, 158 DATE_TIME_ZONE, 159 DATE_TIME_FALG, 160 DATE_MONTH, 161 DATE_INVALID_WORD, 162 DATE_WORD_START = DATE_TIME_ZONE, 163 }; 164 165 class DateUnit { 166 public: IsInvalid()167 bool IsInvalid() const 168 { 169 return type_ == DATE_INVALID; 170 } 171 IsUnknown()172 bool IsUnknown() const 173 { 174 return type_ == DATE_UNKNOWN; 175 } 176 IsNumber()177 bool IsNumber() const 178 { 179 return type_ == DATE_NUMBER; 180 } 181 IsSymbol()182 bool IsSymbol() const 183 { 184 return type_ == DATE_SYMBOL; 185 } 186 IsSymbol(char ch)187 bool IsSymbol(char ch) const 188 { 189 return type_ == DATE_SYMBOL && static_cast<int>(ch) == value_; 190 } 191 IsStringEnd()192 bool IsStringEnd() const 193 { 194 return type_ == DATE_STRING_END; 195 } 196 IsTimeZone()197 bool IsTimeZone() const 198 { 199 return type_ == DATE_TIME_ZONE; 200 } 201 IsTimeFlag()202 bool IsTimeFlag() const 203 { 204 return type_ == DATE_TIME_FALG; 205 } 206 IsInvalidWord()207 bool IsInvalidWord() const 208 { 209 return type_ == DATE_INVALID_WORD; 210 } 211 IsMonth()212 bool IsMonth() const 213 { 214 return type_ == DATE_MONTH; 215 } 216 IsWord()217 bool IsWord() const 218 { 219 return type_ >= DATE_TIME_ZONE; 220 } 221 IsSign()222 bool IsSign() const 223 { 224 return type_ == DATE_SYMBOL && (value_ == '-' || value_ == '+'); 225 } 226 IsSixDecimalDigit()227 bool IsSixDecimalDigit() const 228 { 229 // 6: 6 decimal digit 230 return type_ == DATE_NUMBER && len_ == 6; 231 } 232 IsFourDecimalDigit()233 bool IsFourDecimalDigit() const 234 { 235 // 4: 4 decimal digit 236 return type_ == DATE_NUMBER && len_ == 4; 237 } 238 IsTwoDecimalDigit()239 bool IsTwoDecimalDigit() const 240 { 241 // 2: 2 decimal digit 242 return type_ == DATE_NUMBER && len_ == 2; 243 } 244 IsWordZ()245 bool IsWordZ() const 246 { 247 return type_ == DATE_TIME_ZONE && value_ == 0; 248 } 249 IsSpaceOrTab()250 bool IsSpaceOrTab() const 251 { 252 return type_ == DATE_SPACE; 253 } 254 IsValidFinallyTime()255 bool IsValidFinallyTime() 256 { 257 return IsStringEnd() || IsSign() || IsWordZ() || IsSpaceOrTab(); 258 } 259 Number(int value,int len)260 static DateUnit Number(int value, int len) 261 { 262 return DateUnit(DATE_NUMBER, value, len); 263 } 264 Symbol(char ch)265 static DateUnit Symbol(char ch) 266 { 267 return DateUnit(DATE_SYMBOL, static_cast<int>(ch), 1); 268 } 269 Word(DateValueType type,int value,int len)270 static DateUnit Word(DateValueType type, int value, int len) 271 { 272 return DateUnit(type, value, len); 273 } 274 Space()275 static DateUnit Space() 276 { 277 return DateUnit(DATE_SPACE, 0, 1); 278 } 279 StringEnd()280 static DateUnit StringEnd() 281 { 282 return DateUnit(DATE_STRING_END, 0, 0); 283 } 284 Invalid()285 static DateUnit Invalid() 286 { 287 return DateUnit(DATE_INVALID, 0, 0); 288 } 289 Unknown()290 static DateUnit Unknown() 291 { 292 return DateUnit(DATE_UNKNOWN, 0, 1); 293 } 294 GetValue()295 int GetValue() const 296 { 297 return value_; 298 } 299 GetSymbol()300 char GetSymbol() const 301 { 302 return static_cast<char>(value_); 303 } 304 GetType()305 DateValueType GetType() const 306 { 307 return type_; 308 } 309 GetLength()310 uint32_t GetLength() const 311 { 312 return len_; 313 } 314 private: DateUnit(DateValueType type,int value,int len)315 explicit DateUnit(DateValueType type, int value, int len) : type_(type), value_(value), len_(len) {} 316 DateValueType type_; 317 int value_; 318 uint32_t len_; 319 }; 320 321 class DateProxy { 322 public: DateProxy(StringReader * str)323 explicit DateProxy(StringReader *str) : str_(str), date_(Read()) {} GetDate()324 DateUnit GetDate() const 325 { 326 return date_; 327 } 328 NextDate()329 DateUnit NextDate() 330 { 331 DateUnit cur = GetDate(); 332 date_ = Read(); 333 return cur; 334 } 335 IgnoreSymbol(char ch)336 bool IgnoreSymbol(char ch) 337 { 338 if (!date_.IsSymbol(ch)) { 339 return false; 340 } 341 date_ = Read(); 342 return true; 343 } 344 private: 345 DateUnit Read(); 346 DateValueType MatchKeyWord(const CString &str, int *value); 347 348 StringReader *str_; 349 DateUnit date_; 350 }; 351 352 class TimeZone { 353 public: SetSign(int sign)354 void SetSign(int sign) 355 { 356 sign_ = sign; 357 } 358 SetHour(int hour)359 void SetHour(int hour) 360 { 361 hour_ = hour; 362 } 363 SetMin(int min)364 void SetMin(int min) 365 { 366 min_ = min; 367 } 368 SetUTC()369 void SetUTC() 370 { 371 sign_ = 1; 372 hour_ = 0; 373 min_ = 0; 374 } 375 IsUTC()376 bool IsUTC() 377 { 378 return (hour_ == 0 && min_ == 0); 379 } 380 IsLocal()381 bool IsLocal() const 382 { 383 return hour_ == INT_MAX; 384 } 385 386 bool SetTimeZone(int *time); 387 private: 388 int sign_ {INT_MAX}; 389 int hour_ {INT_MAX}; 390 int min_ {INT_MAX}; 391 }; 392 393 class TimeValue { 394 public: SetData(int data)395 bool SetData(int data) 396 { 397 if (index_ < TIME_LEN) { 398 data_[index_] = data; 399 index_++; 400 return true; 401 } 402 return false; 403 } 404 MinuteIsValid(int n)405 static bool MinuteIsValid(int n) 406 { 407 // 59 : max min 408 return IsBetween(n, 0, 59); 409 } 410 SecondIsValid(int n)411 static bool SecondIsValid(int n) 412 { 413 // 59 : max sec 414 return IsBetween(n, 0, 59); 415 } 416 HourIsValid(int n)417 static bool HourIsValid(int n) 418 { 419 // 24: max hour 420 return IsBetween(n, 0, 24); 421 } 422 MilliSecondIsValid(int n)423 static bool MilliSecondIsValid(int n) 424 { 425 // 999 : max millisecond 426 return IsBetween(n, 0, 999); 427 } 428 NormMilliSecond(DateUnit sec)429 static int NormMilliSecond(DateUnit sec) 430 { 431 uint32_t len = sec.GetLength(); 432 int value = sec.GetValue(); 433 // 3: "sss" norm length 434 if (len == 3) { 435 return value; 436 } 437 // 2: ms length 438 if (len == 2) { 439 return value * JSDate::TEN; 440 } 441 if (len == 1) { 442 return value * JSDate::HUNDRED; 443 } 444 int divisor = 1; 445 // 3: "sss" norm length 446 while (len > 3) { 447 divisor *= JSDate::TEN; 448 len--; 449 } 450 return value / divisor; 451 } 452 GetIndex()453 int GetIndex() const 454 { 455 return index_; 456 } 457 IsValid(int n)458 bool IsValid(int n) const 459 { 460 // 2: index of second 461 return (index_ == 1 && MinuteIsValid(n)) || (index_ == 2 && SecondIsValid(n)); 462 } 463 IsValidSecond(int n)464 bool IsValidSecond(int n) const 465 { 466 // 2: index of second 467 return (index_ == 2 && SecondIsValid(n)); 468 } 469 470 bool SetTimeValue(int *time); 471 private: 472 static constexpr int TIME_LEN = 4; 473 int data_[TIME_LEN]; 474 int index_ {0}; 475 }; 476 477 class DayValue { 478 public: SetData(int data)479 bool SetData(int data) 480 { 481 if (index_ < DAY_LEN) { 482 data_[index_++] = data; 483 return true; 484 } 485 return false; 486 } 487 SetIsoFlag(bool flag)488 void SetIsoFlag(bool flag) 489 { 490 isIsoFlag_ = flag; 491 } 492 SetMonth(int month)493 void SetMonth(int month) 494 { 495 month_ = month; 496 } 497 MonthIsValid(int n)498 static bool MonthIsValid(int n) 499 { 500 return IsBetween(n, 1, MOUTH_PER_YEAR); 501 } 502 DayIsValid(int n)503 static bool DayIsValid(int n) 504 { 505 return IsBetween(n, 1, JSDate::MAX_DAYS_MONTH); 506 } 507 IsIso()508 bool IsIso() const 509 { 510 return isIsoFlag_; 511 } 512 IsFull()513 bool IsFull() const 514 { 515 return index_ == DAY_LEN; 516 } 517 GetIndex()518 int GetIndex() const 519 { 520 return index_; 521 } 522 523 bool SetDayValue(int *time); 524 private: 525 static constexpr int DAY_LEN = 3; 526 int data_[DAY_LEN]; 527 int index_ {0}; 528 int month_ {INT_MAX}; 529 bool isIsoFlag_ {false}; 530 }; 531 static bool IsIsoDateTime(DateProxy *proxy, DayValue *dayValue); 532 static bool ParseIsoDateTime(DateProxy *proxy, DayValue *dayValue, TimeValue *timeValue, 533 TimeZone *timeZone); 534 static bool ParseLegacyDates(DateProxy *proxy, DayValue *dayValue, TimeValue *timeValue, 535 TimeZone *timeZone); 536 }; 537 } // namespace panda::ecmascript 538 539 #endif // ECMASCRIPT_DATE_PARSE_H 540