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
);