2 * Copyright (C) 2012 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
20 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 #include "platform/text/DateTimeFormat.h"
29 #include "wtf/ASCIICType.h"
30 #include "wtf/text/StringBuilder.h"
34 static const DateTimeFormat::FieldType lowerCaseToFieldTypeMap[26] = {
35 DateTimeFormat::FieldTypePeriod, // a
36 DateTimeFormat::FieldTypeInvalid, // b
37 DateTimeFormat::FieldTypeLocalDayOfWeekStandAlon, // c
38 DateTimeFormat::FieldTypeDayOfMonth, // d
39 DateTimeFormat::FieldTypeLocalDayOfWeek, // e
40 DateTimeFormat::FieldTypeInvalid, // f
41 DateTimeFormat::FieldTypeModifiedJulianDay, // g
42 DateTimeFormat::FieldTypeHour12, // h
43 DateTimeFormat::FieldTypeInvalid, // i
44 DateTimeFormat::FieldTypeInvalid, // j
45 DateTimeFormat::FieldTypeHour24, // k
46 DateTimeFormat::FieldTypeInvalid, // l
47 DateTimeFormat::FieldTypeMinute, // m
48 DateTimeFormat::FieldTypeInvalid, // n
49 DateTimeFormat::FieldTypeInvalid, // o
50 DateTimeFormat::FieldTypeInvalid, // p
51 DateTimeFormat::FieldTypeQuaterStandAlone, // q
52 DateTimeFormat::FieldTypeInvalid, // r
53 DateTimeFormat::FieldTypeSecond, // s
54 DateTimeFormat::FieldTypeInvalid, // t
55 DateTimeFormat::FieldTypeExtendedYear, // u
56 DateTimeFormat::FieldTypeNonLocationZone, // v
57 DateTimeFormat::FieldTypeWeekOfYear, // w
58 DateTimeFormat::FieldTypeInvalid, // x
59 DateTimeFormat::FieldTypeYear, // y
60 DateTimeFormat::FieldTypeZone, // z
63 static const DateTimeFormat::FieldType upperCaseToFieldTypeMap[26] = {
64 DateTimeFormat::FieldTypeMillisecondsInDay, // A
65 DateTimeFormat::FieldTypeInvalid, // B
66 DateTimeFormat::FieldTypeInvalid, // C
67 DateTimeFormat::FieldTypeDayOfYear, // D
68 DateTimeFormat::FieldTypeDayOfWeek, // E
69 DateTimeFormat::FieldTypeDayOfWeekInMonth, // F
70 DateTimeFormat::FieldTypeEra, // G
71 DateTimeFormat::FieldTypeHour23, // H
72 DateTimeFormat::FieldTypeInvalid, // I
73 DateTimeFormat::FieldTypeInvalid, // J
74 DateTimeFormat::FieldTypeHour11, // K
75 DateTimeFormat::FieldTypeMonthStandAlone, // L
76 DateTimeFormat::FieldTypeMonth, // M
77 DateTimeFormat::FieldTypeInvalid, // N
78 DateTimeFormat::FieldTypeInvalid, // O
79 DateTimeFormat::FieldTypeInvalid, // P
80 DateTimeFormat::FieldTypeQuater, // Q
81 DateTimeFormat::FieldTypeInvalid, // R
82 DateTimeFormat::FieldTypeFractionalSecond, // S
83 DateTimeFormat::FieldTypeInvalid, // T
84 DateTimeFormat::FieldTypeInvalid, // U
85 DateTimeFormat::FieldTypeInvalid, // V
86 DateTimeFormat::FieldTypeWeekOfMonth, // W
87 DateTimeFormat::FieldTypeInvalid, // X
88 DateTimeFormat::FieldTypeYearOfWeekOfYear, // Y
89 DateTimeFormat::FieldTypeRFC822Zone, // Z
92 static DateTimeFormat::FieldType mapCharacterToFieldType(const UChar ch)
95 return upperCaseToFieldTypeMap[ch - 'A'];
98 return lowerCaseToFieldTypeMap[ch - 'a'];
100 return DateTimeFormat::FieldTypeLiteral;
103 bool DateTimeFormat::parse(const String& source, TokenHandler& tokenHandler)
111 } state = StateLiteral;
113 FieldType fieldType = FieldTypeLiteral;
114 StringBuilder literalBuffer;
115 int fieldCounter = 0;
117 for (unsigned index = 0; index < source.length(); ++index) {
118 const UChar ch = source[index];
122 state = StateInQuoteQuote;
126 literalBuffer.append(ch);
129 case StateInQuoteQuote:
131 literalBuffer.append('\'');
132 state = StateInQuote;
136 fieldType = mapCharacterToFieldType(ch);
137 if (fieldType == FieldTypeInvalid)
140 if (fieldType == FieldTypeLiteral) {
141 literalBuffer.append(ch);
142 state = StateLiteral;
146 if (literalBuffer.length()) {
147 tokenHandler.visitLiteral(literalBuffer.toString());
148 literalBuffer.clear();
161 fieldType = mapCharacterToFieldType(ch);
162 if (fieldType == FieldTypeInvalid)
165 if (fieldType == FieldTypeLiteral) {
166 literalBuffer.append(ch);
170 if (literalBuffer.length()) {
171 tokenHandler.visitLiteral(literalBuffer.toString());
172 literalBuffer.clear();
180 literalBuffer.append(ch);
181 state = ch == '\'' ? StateLiteral : StateInQuote;
185 ASSERT(fieldType != FieldTypeInvalid);
186 ASSERT(fieldType != FieldTypeLiteral);
187 ASSERT(literalBuffer.isEmpty());
189 FieldType fieldType2 = mapCharacterToFieldType(ch);
190 if (fieldType2 == FieldTypeInvalid)
193 if (fieldType == fieldType2) {
198 tokenHandler.visitField(fieldType, fieldCounter);
200 if (fieldType2 == FieldTypeLiteral) {
204 literalBuffer.append(ch);
205 state = StateLiteral;
211 fieldType = fieldType2;
217 ASSERT(fieldType != FieldTypeInvalid);
221 case StateInQuoteQuote:
222 if (literalBuffer.length())
223 tokenHandler.visitLiteral(literalBuffer.toString());
228 if (literalBuffer.length())
229 tokenHandler.visitLiteral(literalBuffer.toString());
233 ASSERT(fieldType != FieldTypeLiteral);
234 ASSERT(!literalBuffer.length());
235 tokenHandler.visitField(fieldType, fieldCounter);
239 ASSERT_NOT_REACHED();
243 static bool isASCIIAlphabetOrQuote(UChar ch)
245 return isASCIIAlpha(ch) || ch == '\'';
248 void DateTimeFormat::quoteAndAppendLiteral(const String& literal, StringBuilder& buffer)
250 if (literal.length() <= 0)
253 if (literal.find(isASCIIAlphabetOrQuote) == kNotFound) {
254 buffer.append(literal);
258 if (literal.find('\'') == kNotFound) {
260 buffer.append(literal);
265 for (unsigned i = 0; i < literal.length(); ++i) {
266 if (literal[i] == '\'') {
267 buffer.appendLiteral("''");
269 String escaped = literal.substring(i);
270 escaped.replace("'", "''");
272 buffer.append(escaped);