15c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/*
25c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Copyright (C) 2012 Google Inc. All rights reserved.
35c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
45c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Redistribution and use in source and binary forms, with or without
55c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * modification, are permitted provided that the following conditions
65c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * are met:
75c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 1.  Redistributions of source code must retain the above copyright
85c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *     notice, this list of conditions and the following disclaimer.
95c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 2.  Redistributions in binary form must reproduce the above copyright
105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *     notice, this list of conditions and the following disclaimer in the
115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *     documentation and/or other materials provided with the distribution.
125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE
175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * SUCH DAMAGE.
245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "config.h"
271e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)#include "platform/text/DateTimeFormat.h"
285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
297757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#include "wtf/ASCIICType.h"
307757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#include "wtf/text/StringBuilder.h"
315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
32c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)namespace blink {
335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static const DateTimeFormat::FieldType lowerCaseToFieldTypeMap[26] = {
355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    DateTimeFormat::FieldTypePeriod, // a
365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    DateTimeFormat::FieldTypeInvalid, // b
375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    DateTimeFormat::FieldTypeLocalDayOfWeekStandAlon, // c
385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    DateTimeFormat::FieldTypeDayOfMonth, // d
395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    DateTimeFormat::FieldTypeLocalDayOfWeek, // e
405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    DateTimeFormat::FieldTypeInvalid, // f
415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    DateTimeFormat::FieldTypeModifiedJulianDay, // g
425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    DateTimeFormat::FieldTypeHour12, // h
435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    DateTimeFormat::FieldTypeInvalid, // i
445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    DateTimeFormat::FieldTypeInvalid, // j
455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    DateTimeFormat::FieldTypeHour24, // k
465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    DateTimeFormat::FieldTypeInvalid, // l
475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    DateTimeFormat::FieldTypeMinute, // m
485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    DateTimeFormat::FieldTypeInvalid, // n
495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    DateTimeFormat::FieldTypeInvalid, // o
505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    DateTimeFormat::FieldTypeInvalid, // p
515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    DateTimeFormat::FieldTypeQuaterStandAlone, // q
525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    DateTimeFormat::FieldTypeInvalid, // r
535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    DateTimeFormat::FieldTypeSecond, // s
545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    DateTimeFormat::FieldTypeInvalid, // t
555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    DateTimeFormat::FieldTypeExtendedYear, // u
565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    DateTimeFormat::FieldTypeNonLocationZone, // v
575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    DateTimeFormat::FieldTypeWeekOfYear, // w
585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    DateTimeFormat::FieldTypeInvalid, // x
595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    DateTimeFormat::FieldTypeYear, // y
605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    DateTimeFormat::FieldTypeZone, // z
615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)};
625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static const DateTimeFormat::FieldType upperCaseToFieldTypeMap[26] = {
645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    DateTimeFormat::FieldTypeMillisecondsInDay, // A
655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    DateTimeFormat::FieldTypeInvalid, // B
665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    DateTimeFormat::FieldTypeInvalid, // C
675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    DateTimeFormat::FieldTypeDayOfYear, // D
685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    DateTimeFormat::FieldTypeDayOfWeek, // E
695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    DateTimeFormat::FieldTypeDayOfWeekInMonth, // F
705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    DateTimeFormat::FieldTypeEra, // G
715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    DateTimeFormat::FieldTypeHour23, // H
725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    DateTimeFormat::FieldTypeInvalid, // I
735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    DateTimeFormat::FieldTypeInvalid, // J
745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    DateTimeFormat::FieldTypeHour11, // K
755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    DateTimeFormat::FieldTypeMonthStandAlone, // L
765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    DateTimeFormat::FieldTypeMonth, // M
775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    DateTimeFormat::FieldTypeInvalid, // N
785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    DateTimeFormat::FieldTypeInvalid, // O
795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    DateTimeFormat::FieldTypeInvalid, // P
805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    DateTimeFormat::FieldTypeQuater, // Q
815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    DateTimeFormat::FieldTypeInvalid, // R
825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    DateTimeFormat::FieldTypeFractionalSecond, // S
835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    DateTimeFormat::FieldTypeInvalid, // T
845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    DateTimeFormat::FieldTypeInvalid, // U
855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    DateTimeFormat::FieldTypeInvalid, // V
865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    DateTimeFormat::FieldTypeWeekOfMonth, // W
875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    DateTimeFormat::FieldTypeInvalid, // X
885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    DateTimeFormat::FieldTypeYearOfWeekOfYear, // Y
895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    DateTimeFormat::FieldTypeRFC822Zone, // Z
905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)};
915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static DateTimeFormat::FieldType mapCharacterToFieldType(const UChar ch)
935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (isASCIIUpper(ch))
955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return upperCaseToFieldTypeMap[ch - 'A'];
965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (isASCIILower(ch))
985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return lowerCaseToFieldTypeMap[ch - 'a'];
995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return DateTimeFormat::FieldTypeLiteral;
1015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)bool DateTimeFormat::parse(const String& source, TokenHandler& tokenHandler)
1045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    enum State {
1065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        StateInQuote,
1075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        StateInQuoteQuote,
1085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        StateLiteral,
1095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        StateQuote,
1105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        StateSymbol,
1115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    } state = StateLiteral;
1125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    FieldType fieldType = FieldTypeLiteral;
1145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    StringBuilder literalBuffer;
1155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int fieldCounter = 0;
1165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1171e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    for (unsigned index = 0; index < source.length(); ++index) {
1185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        const UChar ch = source[index];
1195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        switch (state) {
1205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        case StateInQuote:
1215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (ch == '\'') {
1225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                state = StateInQuoteQuote;
1235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                break;
1245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            }
1255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            literalBuffer.append(ch);
1275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            break;
1285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        case StateInQuoteQuote:
1305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (ch == '\'') {
1315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                literalBuffer.append('\'');
1325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                state = StateInQuote;
1335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                break;
1345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            }
1355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            fieldType = mapCharacterToFieldType(ch);
1375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (fieldType == FieldTypeInvalid)
1385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                return false;
1395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (fieldType == FieldTypeLiteral) {
1415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                literalBuffer.append(ch);
1425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                state = StateLiteral;
1435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                break;
1445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            }
1455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (literalBuffer.length()) {
1475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                tokenHandler.visitLiteral(literalBuffer.toString());
1485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                literalBuffer.clear();
1495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            }
1505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            fieldCounter = 1;
1525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            state = StateSymbol;
1535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            break;
1545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        case StateLiteral:
1565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (ch == '\'') {
1575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                state = StateQuote;
1585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                break;
1595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            }
1605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            fieldType = mapCharacterToFieldType(ch);
1625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (fieldType == FieldTypeInvalid)
1635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                return false;
1645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (fieldType == FieldTypeLiteral) {
1665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                literalBuffer.append(ch);
1675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                break;
1685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            }
1695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (literalBuffer.length()) {
1715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                tokenHandler.visitLiteral(literalBuffer.toString());
1725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                literalBuffer.clear();
1735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            }
1745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            fieldCounter = 1;
1765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            state = StateSymbol;
1775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            break;
1785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        case StateQuote:
1805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            literalBuffer.append(ch);
1815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            state = ch == '\'' ? StateLiteral : StateInQuote;
1825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            break;
1835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        case StateSymbol: {
1855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            ASSERT(fieldType != FieldTypeInvalid);
1865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            ASSERT(fieldType != FieldTypeLiteral);
1875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            ASSERT(literalBuffer.isEmpty());
1885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            FieldType fieldType2 = mapCharacterToFieldType(ch);
1905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (fieldType2 == FieldTypeInvalid)
1915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                return false;
1925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (fieldType == fieldType2) {
1945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                ++fieldCounter;
1955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                break;
1965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            }
1975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            tokenHandler.visitField(fieldType, fieldCounter);
1995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (fieldType2 == FieldTypeLiteral) {
2011e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)                if (ch == '\'') {
2025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    state = StateQuote;
2031e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)                } else {
2045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    literalBuffer.append(ch);
2055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                    state = StateLiteral;
2065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                }
2075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                break;
2085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            }
2095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            fieldCounter = 1;
2115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            fieldType = fieldType2;
2125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            break;
2135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
2145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
2155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
2165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ASSERT(fieldType != FieldTypeInvalid);
2185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    switch (state) {
2205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    case StateLiteral:
2215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    case StateInQuoteQuote:
2225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (literalBuffer.length())
2235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            tokenHandler.visitLiteral(literalBuffer.toString());
2245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return true;
2255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    case StateQuote:
2275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    case StateInQuote:
2285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (literalBuffer.length())
2295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            tokenHandler.visitLiteral(literalBuffer.toString());
2305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
2315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    case StateSymbol:
2335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        ASSERT(fieldType != FieldTypeLiteral);
2345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        ASSERT(!literalBuffer.length());
2355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        tokenHandler.visitField(fieldType, fieldCounter);
2365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return true;
2375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
2385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ASSERT_NOT_REACHED();
2405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return false;
2415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static bool isASCIIAlphabetOrQuote(UChar ch)
2445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
2455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return isASCIIAlpha(ch) || ch == '\'';
2465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void DateTimeFormat::quoteAndAppendLiteral(const String& literal, StringBuilder& buffer)
2495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
2505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (literal.length() <= 0)
2515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
2525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
25306f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)    if (literal.find(isASCIIAlphabetOrQuote) == kNotFound) {
2545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        buffer.append(literal);
2555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
2565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
25702772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch
25806f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)    if (literal.find('\'') == kNotFound) {
2599e12abdf8c3a23d52091ea54ebb6a04d327f9300Torne (Richard Coles)        buffer.append('\'');
2605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        buffer.append(literal);
2619e12abdf8c3a23d52091ea54ebb6a04d327f9300Torne (Richard Coles)        buffer.append('\'');
2625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
2635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
2645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (unsigned i = 0; i < literal.length(); ++i) {
2661e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)        if (literal[i] == '\'') {
2679e12abdf8c3a23d52091ea54ebb6a04d327f9300Torne (Richard Coles)            buffer.appendLiteral("''");
2681e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)        } else {
2695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            String escaped = literal.substring(i);
2703c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch            escaped.replace("'", "''");
2719e12abdf8c3a23d52091ea54ebb6a04d327f9300Torne (Richard Coles)            buffer.append('\'');
2725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            buffer.append(escaped);
2739e12abdf8c3a23d52091ea54ebb6a04d327f9300Torne (Richard Coles)            buffer.append('\'');
2745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return;
2755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
2765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
2775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
279c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)} // namespace blink
280