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