OLD | NEW |
| (Empty) |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "components/autofill/browser/phone_field.h" | |
6 | |
7 #include "base/logging.h" | |
8 #include "base/memory/scoped_ptr.h" | |
9 #include "base/strings/string16.h" | |
10 #include "base/strings/string_util.h" | |
11 #include "base/strings/utf_string_conversions.h" | |
12 #include "components/autofill/browser/autofill_field.h" | |
13 #include "components/autofill/browser/autofill_regex_constants.h" | |
14 #include "components/autofill/browser/autofill_scanner.h" | |
15 #include "ui/base/l10n/l10n_util.h" | |
16 | |
17 namespace autofill { | |
18 namespace { | |
19 | |
20 // This string includes all area code separators, including NoText. | |
21 base::string16 GetAreaRegex() { | |
22 base::string16 area_code = UTF8ToUTF16(autofill::kAreaCodeRe); | |
23 area_code.append(ASCIIToUTF16("|")); // Regexp separator. | |
24 area_code.append(UTF8ToUTF16(autofill::kAreaCodeNotextRe)); | |
25 return area_code; | |
26 } | |
27 | |
28 } // namespace | |
29 | |
30 PhoneField::~PhoneField() {} | |
31 | |
32 // Phone field grammars - first matched grammar will be parsed. Grammars are | |
33 // separated by { REGEX_SEPARATOR, FIELD_NONE, 0 }. Suffix and extension are | |
34 // parsed separately unless they are necessary parts of the match. | |
35 // The following notation is used to describe the patterns: | |
36 // <cc> - country code field. | |
37 // <ac> - area code field. | |
38 // <phone> - phone or prefix. | |
39 // <suffix> - suffix. | |
40 // <ext> - extension. | |
41 // :N means field is limited to N characters, otherwise it is unlimited. | |
42 // (pattern <field>)? means pattern is optional and matched separately. | |
43 const PhoneField::Parser PhoneField::kPhoneFieldGrammars[] = { | |
44 // Country code: <cc> Area Code: <ac> Phone: <phone> (- <suffix> | |
45 // (Ext: <ext>)?)? | |
46 { REGEX_COUNTRY, FIELD_COUNTRY_CODE, 0 }, | |
47 { REGEX_AREA, FIELD_AREA_CODE, 0 }, | |
48 { REGEX_PHONE, FIELD_PHONE, 0 }, | |
49 { REGEX_SEPARATOR, FIELD_NONE, 0 }, | |
50 // \( <ac> \) <phone>:3 <suffix>:4 (Ext: <ext>)? | |
51 { REGEX_AREA_NOTEXT, FIELD_AREA_CODE, 3 }, | |
52 { REGEX_PREFIX_SEPARATOR, FIELD_PHONE, 3 }, | |
53 { REGEX_PHONE, FIELD_SUFFIX, 4 }, | |
54 { REGEX_SEPARATOR, FIELD_NONE, 0 }, | |
55 // Phone: <cc> <ac>:3 - <phone>:3 - <suffix>:4 (Ext: <ext>)? | |
56 { REGEX_PHONE, FIELD_COUNTRY_CODE, 0 }, | |
57 { REGEX_PHONE, FIELD_AREA_CODE, 3 }, | |
58 { REGEX_PREFIX_SEPARATOR, FIELD_PHONE, 3 }, | |
59 { REGEX_SUFFIX_SEPARATOR, FIELD_SUFFIX, 4 }, | |
60 { REGEX_SEPARATOR, FIELD_NONE, 0 }, | |
61 // Phone: <cc>:3 <ac>:3 <phone>:3 <suffix>:4 (Ext: <ext>)? | |
62 { REGEX_PHONE, FIELD_COUNTRY_CODE, 3 }, | |
63 { REGEX_PHONE, FIELD_AREA_CODE, 3 }, | |
64 { REGEX_PHONE, FIELD_PHONE, 3 }, | |
65 { REGEX_PHONE, FIELD_SUFFIX, 4 }, | |
66 { REGEX_SEPARATOR, FIELD_NONE, 0 }, | |
67 // Area Code: <ac> Phone: <phone> (- <suffix> (Ext: <ext>)?)? | |
68 { REGEX_AREA, FIELD_AREA_CODE, 0 }, | |
69 { REGEX_PHONE, FIELD_PHONE, 0 }, | |
70 { REGEX_SEPARATOR, FIELD_NONE, 0 }, | |
71 // Phone: <ac> <phone>:3 <suffix>:4 (Ext: <ext>)? | |
72 { REGEX_PHONE, FIELD_AREA_CODE, 0 }, | |
73 { REGEX_PHONE, FIELD_PHONE, 3 }, | |
74 { REGEX_PHONE, FIELD_SUFFIX, 4 }, | |
75 { REGEX_SEPARATOR, FIELD_NONE, 0 }, | |
76 // Phone: <cc> \( <ac> \) <phone> (- <suffix> (Ext: <ext>)?)? | |
77 { REGEX_PHONE, FIELD_COUNTRY_CODE, 0 }, | |
78 { REGEX_AREA_NOTEXT, FIELD_AREA_CODE, 0 }, | |
79 { REGEX_PREFIX_SEPARATOR, FIELD_PHONE, 0 }, | |
80 { REGEX_SEPARATOR, FIELD_NONE, 0 }, | |
81 // Phone: \( <ac> \) <phone> (- <suffix> (Ext: <ext>)?)? | |
82 { REGEX_PHONE, FIELD_COUNTRY_CODE, 0 }, | |
83 { REGEX_AREA_NOTEXT, FIELD_AREA_CODE, 0 }, | |
84 { REGEX_PREFIX_SEPARATOR, FIELD_PHONE, 0 }, | |
85 { REGEX_SEPARATOR, FIELD_NONE, 0 }, | |
86 // Phone: <cc> - <ac> - <phone> - <suffix> (Ext: <ext>)? | |
87 { REGEX_PHONE, FIELD_COUNTRY_CODE, 0 }, | |
88 { REGEX_PREFIX_SEPARATOR, FIELD_AREA_CODE, 0 }, | |
89 { REGEX_PREFIX_SEPARATOR, FIELD_PHONE, 0 }, | |
90 { REGEX_SUFFIX_SEPARATOR, FIELD_SUFFIX, 0 }, | |
91 { REGEX_SEPARATOR, FIELD_NONE, 0 }, | |
92 // Phone: <ac> Prefix: <phone> Suffix: <suffix> (Ext: <ext>)? | |
93 { REGEX_PHONE, FIELD_AREA_CODE, 0 }, | |
94 { REGEX_PREFIX, FIELD_PHONE, 0 }, | |
95 { REGEX_SUFFIX, FIELD_SUFFIX, 0 }, | |
96 { REGEX_SEPARATOR, FIELD_NONE, 0 }, | |
97 // Phone: <ac> - <phone>:3 - <suffix>:4 (Ext: <ext>)? | |
98 { REGEX_PHONE, FIELD_AREA_CODE, 0 }, | |
99 { REGEX_PREFIX_SEPARATOR, FIELD_PHONE, 3 }, | |
100 { REGEX_SUFFIX_SEPARATOR, FIELD_SUFFIX, 4 }, | |
101 { REGEX_SEPARATOR, FIELD_NONE, 0 }, | |
102 // Phone: <cc> - <ac> - <phone> (Ext: <ext>)? | |
103 { REGEX_PHONE, FIELD_COUNTRY_CODE, 0 }, | |
104 { REGEX_PREFIX_SEPARATOR, FIELD_AREA_CODE, 0 }, | |
105 { REGEX_SUFFIX_SEPARATOR, FIELD_PHONE, 0 }, | |
106 { REGEX_SEPARATOR, FIELD_NONE, 0 }, | |
107 // Phone: <ac> - <phone> (Ext: <ext>)? | |
108 { REGEX_AREA, FIELD_AREA_CODE, 0 }, | |
109 { REGEX_PHONE, FIELD_PHONE, 0 }, | |
110 { REGEX_SEPARATOR, FIELD_NONE, 0 }, | |
111 // Phone: <cc>:3 - <phone>:10 (Ext: <ext>)? | |
112 { REGEX_PHONE, FIELD_COUNTRY_CODE, 3 }, | |
113 { REGEX_PHONE, FIELD_PHONE, 10 }, | |
114 { REGEX_SEPARATOR, FIELD_NONE, 0 }, | |
115 // Phone: <phone> (Ext: <ext>)? | |
116 { REGEX_PHONE, FIELD_PHONE, 0 }, | |
117 { REGEX_SEPARATOR, FIELD_NONE, 0 }, | |
118 }; | |
119 | |
120 // static | |
121 FormField* PhoneField::Parse(AutofillScanner* scanner) { | |
122 if (scanner->IsEnd()) | |
123 return NULL; | |
124 | |
125 scanner->SaveCursor(); | |
126 | |
127 // The form owns the following variables, so they should not be deleted. | |
128 const AutofillField* parsed_fields[FIELD_MAX]; | |
129 | |
130 for (size_t i = 0; i < arraysize(kPhoneFieldGrammars); ++i) { | |
131 memset(parsed_fields, 0, sizeof(parsed_fields)); | |
132 scanner->SaveCursor(); | |
133 | |
134 // Attempt to parse according to the next grammar. | |
135 for (; i < arraysize(kPhoneFieldGrammars) && | |
136 kPhoneFieldGrammars[i].regex != REGEX_SEPARATOR; ++i) { | |
137 if (!ParseFieldSpecifics( | |
138 scanner, | |
139 GetRegExp(kPhoneFieldGrammars[i].regex), | |
140 MATCH_DEFAULT | MATCH_TELEPHONE, | |
141 &parsed_fields[kPhoneFieldGrammars[i].phone_part])) | |
142 break; | |
143 if (kPhoneFieldGrammars[i].max_size && | |
144 (!parsed_fields[kPhoneFieldGrammars[i].phone_part]->max_length || | |
145 kPhoneFieldGrammars[i].max_size < | |
146 parsed_fields[kPhoneFieldGrammars[i].phone_part]->max_length)) { | |
147 break; | |
148 } | |
149 } | |
150 | |
151 if (i >= arraysize(kPhoneFieldGrammars)) { | |
152 scanner->Rewind(); | |
153 return NULL; // Parsing failed. | |
154 } | |
155 if (kPhoneFieldGrammars[i].regex == REGEX_SEPARATOR) | |
156 break; // Parsing succeeded. | |
157 | |
158 // Proceed to the next grammar. | |
159 do { | |
160 ++i; | |
161 } while (i < arraysize(kPhoneFieldGrammars) && | |
162 kPhoneFieldGrammars[i].regex != REGEX_SEPARATOR); | |
163 | |
164 if (i + 1 == arraysize(kPhoneFieldGrammars)) { | |
165 scanner->Rewind(); | |
166 return NULL; // Tried through all the possibilities - did not match. | |
167 } | |
168 | |
169 scanner->Rewind(); | |
170 } | |
171 | |
172 if (!parsed_fields[FIELD_PHONE]) { | |
173 scanner->Rewind(); | |
174 return NULL; | |
175 } | |
176 | |
177 scoped_ptr<PhoneField> phone_field(new PhoneField); | |
178 for (int i = 0; i < FIELD_MAX; ++i) | |
179 phone_field->parsed_phone_fields_[i] = parsed_fields[i]; | |
180 | |
181 // Look for optional fields. | |
182 | |
183 // Look for a third text box. | |
184 if (!phone_field->parsed_phone_fields_[FIELD_SUFFIX]) { | |
185 if (!ParseField(scanner, UTF8ToUTF16(autofill::kPhoneSuffixRe), | |
186 &phone_field->parsed_phone_fields_[FIELD_SUFFIX])) { | |
187 ParseField(scanner, UTF8ToUTF16(autofill::kPhoneSuffixSeparatorRe), | |
188 &phone_field->parsed_phone_fields_[FIELD_SUFFIX]); | |
189 } | |
190 } | |
191 | |
192 // Now look for an extension. | |
193 ParseField(scanner, UTF8ToUTF16(autofill::kPhoneExtensionRe), | |
194 &phone_field->parsed_phone_fields_[FIELD_EXTENSION]); | |
195 | |
196 return phone_field.release(); | |
197 } | |
198 | |
199 bool PhoneField::ClassifyField(FieldTypeMap* map) const { | |
200 bool ok = true; | |
201 | |
202 DCHECK(parsed_phone_fields_[FIELD_PHONE]); // Phone was correctly parsed. | |
203 | |
204 if ((parsed_phone_fields_[FIELD_COUNTRY_CODE] != NULL) || | |
205 (parsed_phone_fields_[FIELD_AREA_CODE] != NULL) || | |
206 (parsed_phone_fields_[FIELD_SUFFIX] != NULL)) { | |
207 if (parsed_phone_fields_[FIELD_COUNTRY_CODE] != NULL) { | |
208 ok = ok && AddClassification(parsed_phone_fields_[FIELD_COUNTRY_CODE], | |
209 PHONE_HOME_COUNTRY_CODE, | |
210 map); | |
211 } | |
212 | |
213 AutofillFieldType field_number_type = PHONE_HOME_NUMBER; | |
214 if (parsed_phone_fields_[FIELD_AREA_CODE] != NULL) { | |
215 ok = ok && AddClassification(parsed_phone_fields_[FIELD_AREA_CODE], | |
216 PHONE_HOME_CITY_CODE, | |
217 map); | |
218 } else if (parsed_phone_fields_[FIELD_COUNTRY_CODE] != NULL) { | |
219 // Only if we can find country code without city code, it means the phone | |
220 // number include city code. | |
221 field_number_type = PHONE_HOME_CITY_AND_NUMBER; | |
222 } | |
223 // We tag the prefix as PHONE_HOME_NUMBER, then when filling the form | |
224 // we fill only the prefix depending on the size of the input field. | |
225 ok = ok && AddClassification(parsed_phone_fields_[FIELD_PHONE], | |
226 field_number_type, | |
227 map); | |
228 // We tag the suffix as PHONE_HOME_NUMBER, then when filling the form | |
229 // we fill only the suffix depending on the size of the input field. | |
230 if (parsed_phone_fields_[FIELD_SUFFIX] != NULL) { | |
231 ok = ok && AddClassification(parsed_phone_fields_[FIELD_SUFFIX], | |
232 PHONE_HOME_NUMBER, | |
233 map); | |
234 } | |
235 } else { | |
236 ok = AddClassification(parsed_phone_fields_[FIELD_PHONE], | |
237 PHONE_HOME_WHOLE_NUMBER, | |
238 map); | |
239 } | |
240 | |
241 return ok; | |
242 } | |
243 | |
244 PhoneField::PhoneField() { | |
245 memset(parsed_phone_fields_, 0, sizeof(parsed_phone_fields_)); | |
246 } | |
247 | |
248 // static | |
249 base::string16 PhoneField::GetRegExp(RegexType regex_id) { | |
250 switch (regex_id) { | |
251 case REGEX_COUNTRY: | |
252 return UTF8ToUTF16(autofill::kCountryCodeRe); | |
253 case REGEX_AREA: | |
254 return GetAreaRegex(); | |
255 case REGEX_AREA_NOTEXT: | |
256 return UTF8ToUTF16(autofill::kAreaCodeNotextRe); | |
257 case REGEX_PHONE: | |
258 return UTF8ToUTF16(autofill::kPhoneRe); | |
259 case REGEX_PREFIX_SEPARATOR: | |
260 return UTF8ToUTF16(autofill::kPhonePrefixSeparatorRe); | |
261 case REGEX_PREFIX: | |
262 return UTF8ToUTF16(autofill::kPhonePrefixRe); | |
263 case REGEX_SUFFIX_SEPARATOR: | |
264 return UTF8ToUTF16(autofill::kPhoneSuffixSeparatorRe); | |
265 case REGEX_SUFFIX: | |
266 return UTF8ToUTF16(autofill::kPhoneSuffixRe); | |
267 case REGEX_EXTENSION: | |
268 return UTF8ToUTF16(autofill::kPhoneExtensionRe); | |
269 default: | |
270 NOTREACHED(); | |
271 break; | |
272 } | |
273 return base::string16(); | |
274 } | |
275 | |
276 } // namespace autofill | |
OLD | NEW |