This source file includes following definitions.
- mapCharacterToFieldType
- parse
- isASCIIAlphabetOrQuote
- quoteAndAppendLiteral
#include "config.h"
#include "platform/text/DateTimeFormat.h"
#include "wtf/ASCIICType.h"
#include "wtf/text/StringBuilder.h"
namespace WebCore {
static const DateTimeFormat::FieldType lowerCaseToFieldTypeMap[26] = {
DateTimeFormat::FieldTypePeriod,
DateTimeFormat::FieldTypeInvalid,
DateTimeFormat::FieldTypeLocalDayOfWeekStandAlon,
DateTimeFormat::FieldTypeDayOfMonth,
DateTimeFormat::FieldTypeLocalDayOfWeek,
DateTimeFormat::FieldTypeInvalid,
DateTimeFormat::FieldTypeModifiedJulianDay,
DateTimeFormat::FieldTypeHour12,
DateTimeFormat::FieldTypeInvalid,
DateTimeFormat::FieldTypeInvalid,
DateTimeFormat::FieldTypeHour24,
DateTimeFormat::FieldTypeInvalid,
DateTimeFormat::FieldTypeMinute,
DateTimeFormat::FieldTypeInvalid,
DateTimeFormat::FieldTypeInvalid,
DateTimeFormat::FieldTypeInvalid,
DateTimeFormat::FieldTypeQuaterStandAlone,
DateTimeFormat::FieldTypeInvalid,
DateTimeFormat::FieldTypeSecond,
DateTimeFormat::FieldTypeInvalid,
DateTimeFormat::FieldTypeExtendedYear,
DateTimeFormat::FieldTypeNonLocationZone,
DateTimeFormat::FieldTypeWeekOfYear,
DateTimeFormat::FieldTypeInvalid,
DateTimeFormat::FieldTypeYear,
DateTimeFormat::FieldTypeZone,
};
static const DateTimeFormat::FieldType upperCaseToFieldTypeMap[26] = {
DateTimeFormat::FieldTypeMillisecondsInDay,
DateTimeFormat::FieldTypeInvalid,
DateTimeFormat::FieldTypeInvalid,
DateTimeFormat::FieldTypeDayOfYear,
DateTimeFormat::FieldTypeDayOfWeek,
DateTimeFormat::FieldTypeDayOfWeekInMonth,
DateTimeFormat::FieldTypeEra,
DateTimeFormat::FieldTypeHour23,
DateTimeFormat::FieldTypeInvalid,
DateTimeFormat::FieldTypeInvalid,
DateTimeFormat::FieldTypeHour11,
DateTimeFormat::FieldTypeMonthStandAlone,
DateTimeFormat::FieldTypeMonth,
DateTimeFormat::FieldTypeInvalid,
DateTimeFormat::FieldTypeInvalid,
DateTimeFormat::FieldTypeInvalid,
DateTimeFormat::FieldTypeQuater,
DateTimeFormat::FieldTypeInvalid,
DateTimeFormat::FieldTypeFractionalSecond,
DateTimeFormat::FieldTypeInvalid,
DateTimeFormat::FieldTypeInvalid,
DateTimeFormat::FieldTypeInvalid,
DateTimeFormat::FieldTypeWeekOfMonth,
DateTimeFormat::FieldTypeInvalid,
DateTimeFormat::FieldTypeYearOfWeekOfYear,
DateTimeFormat::FieldTypeRFC822Zone,
};
static DateTimeFormat::FieldType mapCharacterToFieldType(const UChar ch)
{
if (isASCIIUpper(ch))
return upperCaseToFieldTypeMap[ch - 'A'];
if (isASCIILower(ch))
return lowerCaseToFieldTypeMap[ch - 'a'];
return DateTimeFormat::FieldTypeLiteral;
}
bool DateTimeFormat::parse(const String& source, TokenHandler& tokenHandler)
{
enum State {
StateInQuote,
StateInQuoteQuote,
StateLiteral,
StateQuote,
StateSymbol,
} state = StateLiteral;
FieldType fieldType = FieldTypeLiteral;
StringBuilder literalBuffer;
int fieldCounter = 0;
for (unsigned index = 0; index < source.length(); ++index) {
const UChar ch = source[index];
switch (state) {
case StateInQuote:
if (ch == '\'') {
state = StateInQuoteQuote;
break;
}
literalBuffer.append(ch);
break;
case StateInQuoteQuote:
if (ch == '\'') {
literalBuffer.append('\'');
state = StateInQuote;
break;
}
fieldType = mapCharacterToFieldType(ch);
if (fieldType == FieldTypeInvalid)
return false;
if (fieldType == FieldTypeLiteral) {
literalBuffer.append(ch);
state = StateLiteral;
break;
}
if (literalBuffer.length()) {
tokenHandler.visitLiteral(literalBuffer.toString());
literalBuffer.clear();
}
fieldCounter = 1;
state = StateSymbol;
break;
case StateLiteral:
if (ch == '\'') {
state = StateQuote;
break;
}
fieldType = mapCharacterToFieldType(ch);
if (fieldType == FieldTypeInvalid)
return false;
if (fieldType == FieldTypeLiteral) {
literalBuffer.append(ch);
break;
}
if (literalBuffer.length()) {
tokenHandler.visitLiteral(literalBuffer.toString());
literalBuffer.clear();
}
fieldCounter = 1;
state = StateSymbol;
break;
case StateQuote:
literalBuffer.append(ch);
state = ch == '\'' ? StateLiteral : StateInQuote;
break;
case StateSymbol: {
ASSERT(fieldType != FieldTypeInvalid);
ASSERT(fieldType != FieldTypeLiteral);
ASSERT(literalBuffer.isEmpty());
FieldType fieldType2 = mapCharacterToFieldType(ch);
if (fieldType2 == FieldTypeInvalid)
return false;
if (fieldType == fieldType2) {
++fieldCounter;
break;
}
tokenHandler.visitField(fieldType, fieldCounter);
if (fieldType2 == FieldTypeLiteral) {
if (ch == '\'') {
state = StateQuote;
} else {
literalBuffer.append(ch);
state = StateLiteral;
}
break;
}
fieldCounter = 1;
fieldType = fieldType2;
break;
}
}
}
ASSERT(fieldType != FieldTypeInvalid);
switch (state) {
case StateLiteral:
case StateInQuoteQuote:
if (literalBuffer.length())
tokenHandler.visitLiteral(literalBuffer.toString());
return true;
case StateQuote:
case StateInQuote:
if (literalBuffer.length())
tokenHandler.visitLiteral(literalBuffer.toString());
return false;
case StateSymbol:
ASSERT(fieldType != FieldTypeLiteral);
ASSERT(!literalBuffer.length());
tokenHandler.visitField(fieldType, fieldCounter);
return true;
}
ASSERT_NOT_REACHED();
return false;
}
static bool isASCIIAlphabetOrQuote(UChar ch)
{
return isASCIIAlpha(ch) || ch == '\'';
}
void DateTimeFormat::quoteAndAppendLiteral(const String& literal, StringBuilder& buffer)
{
if (literal.length() <= 0)
return;
if (literal.find(isASCIIAlphabetOrQuote) == kNotFound) {
buffer.append(literal);
return;
}
if (literal.find('\'') == kNotFound) {
buffer.append("'");
buffer.append(literal);
buffer.append("'");
return;
}
for (unsigned i = 0; i < literal.length(); ++i) {
if (literal[i] == '\'') {
buffer.append("''");
} else {
String escaped = literal.substring(i);
escaped.replace("'", "''");
buffer.append("'");
buffer.append(escaped);
buffer.append("'");
return;
}
}
}
}