mirror of
https://gitee.com/openharmony/arkcompiler_ets_runtime
synced 2024-11-30 13:40:51 +00:00
ca6c6dd737
description:overwrite Date parse issue:https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I6CB3T?from=project-issue Signed-off-by: wupengyong <wupengyong@huawei.com> Change-Id: Ib8266580ed60e9040183ef10ee0c2a190b3809e2
532 lines
14 KiB
C++
532 lines
14 KiB
C++
/*
|
|
* Copyright (c) 2023 Huawei Device Co., Ltd.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#ifndef ECMASCRIPT_DATE_PARSE_H
|
|
#define ECMASCRIPT_DATE_PARSE_H
|
|
|
|
#include "ecmascript/js_date.h"
|
|
|
|
namespace panda::ecmascript {
|
|
class DateParse {
|
|
public:
|
|
static bool ParseDateString(const char *str, int length, int *time);
|
|
|
|
private:
|
|
static bool IsBetween(int n, int lower, int hign)
|
|
{
|
|
if (n < lower || n > hign) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
class StringReader {
|
|
public:
|
|
explicit StringReader(const char *str, int length) : data_(str), length_(length)
|
|
{
|
|
NextChar();
|
|
}
|
|
|
|
void NextChar()
|
|
{
|
|
value_ = (index_ < length_) ? data_[index_] : DEL;
|
|
index_++;
|
|
}
|
|
|
|
int GetIndex() const
|
|
{
|
|
return index_;
|
|
}
|
|
|
|
int ReadNumber(int *len)
|
|
{
|
|
int index = 0;
|
|
int num = 0;
|
|
while (IsDigit()) {
|
|
// 9 : max decimal of int
|
|
if (index < 9) {
|
|
num = (value_ - '0') + num * JSDate::TEN;
|
|
index++;
|
|
}
|
|
NextChar();
|
|
}
|
|
*len = index;
|
|
return num;
|
|
}
|
|
|
|
int ReadAlphabet(char *word, int size)
|
|
{
|
|
int length = 0;
|
|
for (; IsAlpha(); length++) {
|
|
if (length < size) {
|
|
word[length] = GetLower(value_);
|
|
}
|
|
NextChar();
|
|
}
|
|
return length;
|
|
}
|
|
|
|
char GetLower(char ch)
|
|
{
|
|
if (ch >= 'A' && ch <= 'Z') {
|
|
// 32: 'a' - 'A'
|
|
return ch + 32;
|
|
}
|
|
return ch;
|
|
}
|
|
|
|
bool IsDigit() const
|
|
{
|
|
if (value_ >= '0' && value_ <= '9') {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool IsSign() const
|
|
{
|
|
if (value_ == '+' || value_ == '-') {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool IsEnd() const
|
|
{
|
|
return value_ == DEL;
|
|
}
|
|
|
|
bool IsThisChar(char ch) const
|
|
{
|
|
return value_ == ch;
|
|
}
|
|
|
|
bool IsAlpha() const
|
|
{
|
|
if (value_ >= 'A' && value_ <= 'z') {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool IsSpaceOrTab() const
|
|
{
|
|
if (value_ == ' ' || value_ == '\t') {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool IsChar(char ch)
|
|
{
|
|
if (value_ != ch) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
private:
|
|
const char *data_;
|
|
int index_ {0};
|
|
int length_;
|
|
char value_;
|
|
};
|
|
|
|
enum DateValueType : int8_t{
|
|
DATE_INVALID,
|
|
DATE_UNKNOWN,
|
|
DATE_NUMBER,
|
|
DATE_SYMBOL,
|
|
DATE_SPACE,
|
|
DATE_STRING_END,
|
|
DATE_TIME_ZONE,
|
|
DATE_TIME_FALG,
|
|
DATE_MONTH,
|
|
DATE_INVALID_WORD,
|
|
DATE_WORD_START = DATE_TIME_ZONE,
|
|
};
|
|
|
|
class DateUnit {
|
|
public:
|
|
bool IsInvalid() const
|
|
{
|
|
return type_ == DATE_INVALID;
|
|
}
|
|
|
|
bool IsUnknown() const
|
|
{
|
|
return type_ == DATE_UNKNOWN;
|
|
}
|
|
|
|
bool IsNumber() const
|
|
{
|
|
return type_ == DATE_NUMBER;
|
|
}
|
|
|
|
bool IsSymbol() const
|
|
{
|
|
return type_ == DATE_SYMBOL;
|
|
}
|
|
|
|
bool IsSymbol(char ch) const
|
|
{
|
|
return type_ == DATE_SYMBOL && static_cast<int>(ch) == value_;
|
|
}
|
|
|
|
bool IsStringEnd() const
|
|
{
|
|
return type_ == DATE_STRING_END;
|
|
}
|
|
|
|
bool IsTimeZone() const
|
|
{
|
|
return type_ == DATE_TIME_ZONE;
|
|
}
|
|
|
|
bool IsTimeFlag() const
|
|
{
|
|
return type_ == DATE_TIME_FALG;
|
|
}
|
|
|
|
bool IsInvalidWord() const
|
|
{
|
|
return type_ == DATE_INVALID_WORD;
|
|
}
|
|
|
|
bool IsMonth() const
|
|
{
|
|
return type_ == DATE_MONTH;
|
|
}
|
|
|
|
bool IsWord() const
|
|
{
|
|
return type_ >= DATE_TIME_ZONE;
|
|
}
|
|
|
|
bool IsSign() const
|
|
{
|
|
return type_ == DATE_SYMBOL && (value_ == '-' || value_ == '+');
|
|
}
|
|
|
|
bool IsSixDecimalDigit() const
|
|
{
|
|
// 6: 6 decimal digit
|
|
return type_ == DATE_NUMBER && len_ == 6;
|
|
}
|
|
|
|
bool IsFourDecimalDigit() const
|
|
{
|
|
// 4: 4 decimal digit
|
|
return type_ == DATE_NUMBER && len_ == 4;
|
|
}
|
|
|
|
bool IsTwoDecimalDigit() const
|
|
{
|
|
// 2: 2 decimal digit
|
|
return type_ == DATE_NUMBER && len_ == 2;
|
|
}
|
|
|
|
bool IsWordZ() const
|
|
{
|
|
return type_ == DATE_TIME_ZONE && value_ == 0;
|
|
}
|
|
|
|
bool IsSpaceOrTab() const
|
|
{
|
|
return type_ == DATE_SPACE;
|
|
}
|
|
|
|
bool IsValidFinallyTime()
|
|
{
|
|
return IsStringEnd() || IsSign() || IsWordZ() || IsSpaceOrTab();
|
|
}
|
|
|
|
static DateUnit Number(int value, int len)
|
|
{
|
|
return DateUnit(DATE_NUMBER, value, len);
|
|
}
|
|
|
|
static DateUnit Symbol(char ch)
|
|
{
|
|
return DateUnit(DATE_SYMBOL, static_cast<int>(ch), 1);
|
|
}
|
|
|
|
static DateUnit Word(DateValueType type, int value, int len)
|
|
{
|
|
return DateUnit(type, value, len);
|
|
}
|
|
|
|
static DateUnit Space()
|
|
{
|
|
return DateUnit(DATE_SPACE, 0, 1);
|
|
}
|
|
|
|
static DateUnit StringEnd()
|
|
{
|
|
return DateUnit(DATE_STRING_END, 0, 0);
|
|
}
|
|
|
|
static DateUnit Invalid()
|
|
{
|
|
return DateUnit(DATE_INVALID, 0, 0);
|
|
}
|
|
|
|
static DateUnit Unknown()
|
|
{
|
|
return DateUnit(DATE_UNKNOWN, 0, 1);
|
|
}
|
|
|
|
int GetValue() const
|
|
{
|
|
return value_;
|
|
}
|
|
|
|
char GetSymbol() const
|
|
{
|
|
return static_cast<char>(value_);
|
|
}
|
|
|
|
DateValueType GetType() const
|
|
{
|
|
return type_;
|
|
}
|
|
|
|
int GetLength() const
|
|
{
|
|
return len_;
|
|
}
|
|
private:
|
|
explicit DateUnit(DateValueType type, int value, int len) : type_(type), value_(value), len_(len) {}
|
|
DateValueType type_;
|
|
int value_;
|
|
int len_;
|
|
};
|
|
|
|
class DateProxy {
|
|
public:
|
|
explicit DateProxy(StringReader *str) : str_(str), date_(Read()) {}
|
|
DateUnit GetDate() const
|
|
{
|
|
return date_;
|
|
}
|
|
|
|
DateUnit NextDate()
|
|
{
|
|
DateUnit cur = GetDate();
|
|
date_ = Read();
|
|
return cur;
|
|
}
|
|
|
|
bool IgnoreSymbol(char ch)
|
|
{
|
|
if (!date_.IsSymbol(ch)) {
|
|
return false;
|
|
}
|
|
date_ = Read();
|
|
return true;
|
|
}
|
|
private:
|
|
DateUnit Read();
|
|
DateValueType MatchKeyWord(const CString &str, int *value);
|
|
|
|
StringReader *str_;
|
|
DateUnit date_;
|
|
};
|
|
|
|
class TimeZone {
|
|
public:
|
|
void SetSign(int sign)
|
|
{
|
|
sign_ = sign;
|
|
}
|
|
|
|
void SetHour(int hour)
|
|
{
|
|
hour_ = hour;
|
|
}
|
|
|
|
void SetMin(int min)
|
|
{
|
|
min_ = min;
|
|
}
|
|
|
|
void SetUTC()
|
|
{
|
|
sign_ = 1;
|
|
hour_ = 0;
|
|
min_ = 0;
|
|
}
|
|
|
|
bool IsUTC()
|
|
{
|
|
return (hour_ == 0 && min_ == 0);
|
|
}
|
|
|
|
bool IsLocal() const
|
|
{
|
|
return hour_ == INT_MAX;
|
|
}
|
|
|
|
bool SetTimeZone(int *time);
|
|
private:
|
|
int sign_ {INT_MAX};
|
|
int hour_ {INT_MAX};
|
|
int min_ {INT_MAX};
|
|
};
|
|
|
|
class TimeValue {
|
|
public:
|
|
bool SetData(int data)
|
|
{
|
|
if (index_ < TIME_LEN) {
|
|
data_[index_] = data;
|
|
index_++;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static bool MinuteIsValid(int n)
|
|
{
|
|
// 59 : max min
|
|
return IsBetween(n, 0, 59);
|
|
}
|
|
|
|
static bool SecondIsValid(int n)
|
|
{
|
|
// 59 : max sec
|
|
return IsBetween(n, 0, 59);
|
|
}
|
|
|
|
static bool HourIsValid(int n)
|
|
{
|
|
// 24: max hour
|
|
return IsBetween(n, 0, 24);
|
|
}
|
|
|
|
static bool MilliSecondIsValid(int n)
|
|
{
|
|
// 999 : max millisecond
|
|
return IsBetween(n, 0, 999);
|
|
}
|
|
|
|
static int NormMilliSecond(DateUnit sec)
|
|
{
|
|
int len = sec.GetLength();
|
|
int value = sec.GetValue();
|
|
// 3: "sss" norm length
|
|
if (len == 3) {
|
|
return value;
|
|
}
|
|
// 2: ms length
|
|
if (len == 2) {
|
|
return value * JSDate::TEN;
|
|
}
|
|
if (len == 1) {
|
|
return value * JSDate::HUNDRED;
|
|
}
|
|
int divisor = 1;
|
|
// 3: "sss" norm length
|
|
while (len > 3) {
|
|
divisor *= JSDate::TEN;
|
|
len--;
|
|
}
|
|
return value / divisor;
|
|
}
|
|
|
|
int GetIndex() const
|
|
{
|
|
return index_;
|
|
}
|
|
|
|
bool IsValid(int n) const
|
|
{
|
|
// 2: index of second
|
|
return (index_ == 1 && MinuteIsValid(n)) || (index_ == 2 && SecondIsValid(n));
|
|
}
|
|
|
|
bool IsValidSecond(int n) const
|
|
{
|
|
// 2: index of second
|
|
return (index_ == 2 && SecondIsValid(n));
|
|
}
|
|
|
|
bool SetTimeValue(int *time);
|
|
private:
|
|
static constexpr int TIME_LEN = 4;
|
|
int data_[TIME_LEN];
|
|
int index_ {0};
|
|
};
|
|
|
|
class DayValue {
|
|
public:
|
|
bool SetData(int data)
|
|
{
|
|
if (index_ < DAY_LEN) {
|
|
data_[index_++] = data;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void SetIsoFlag(bool flag)
|
|
{
|
|
is_iso_flag_ = flag;
|
|
}
|
|
|
|
void SetMonth(int month)
|
|
{
|
|
month_ = month;
|
|
}
|
|
|
|
static bool MonthIsValid(int n) {
|
|
return IsBetween(n, 1, MOUTH_PER_YEAR);
|
|
}
|
|
|
|
static bool DayIsValid(int n) {
|
|
return IsBetween(n, 1, JSDate::MAX_DAYS_MONTH);
|
|
}
|
|
|
|
bool IsIso() const
|
|
{
|
|
return is_iso_flag_;
|
|
}
|
|
|
|
bool IsFull() const
|
|
{
|
|
return index_ == DAY_LEN;
|
|
}
|
|
|
|
int GetIndex() const
|
|
{
|
|
return index_;
|
|
}
|
|
|
|
bool SetDayValue(int *time);
|
|
private:
|
|
static constexpr int DAY_LEN = 3;
|
|
int data_[DAY_LEN];
|
|
int index_ {0};
|
|
int month_ {INT_MAX};
|
|
bool is_iso_flag_ {false};
|
|
};
|
|
static bool IsIsoDateTime(DateProxy *proxy, DayValue *dayValue);
|
|
static bool ParseIsoDateTime(DateProxy *proxy, DayValue *dayValue, TimeValue *timeValue,
|
|
TimeZone *timeZone);
|
|
static bool ParseLegacyDates(DateProxy *proxy, DayValue *dayValue, TimeValue *timeValue,
|
|
TimeZone *timeZone);
|
|
};
|
|
} // namespace panda::ecmascript
|
|
|
|
#endif // ECMASCRIPT_DATE_PARSE_H
|