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