DateTimeFormat.cpp [plain text]
#include "config.h"
#include "DateTimeFormat.h"
#if ENABLE(DATE_AND_TIME_INPUT_TYPES)
#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 int 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) == notFound) {
buffer.append(literal);
return;
}
if (literal.find('\'') == notFound) {
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(ASCIILiteral("'"), ASCIILiteral("''"));
buffer.append("'");
buffer.append(escaped);
buffer.append("'");
return;
}
}
}
}
#endif