• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 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/core/browser/contact_info.h"
6 
7 #include <stddef.h>
8 #include <ostream>
9 #include <string>
10 
11 #include "base/basictypes.h"
12 #include "base/logging.h"
13 #include "base/strings/string_util.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "components/autofill/core/browser/autofill_type.h"
16 
17 namespace autofill {
18 
19 namespace {
20 
21 const char* const name_prefixes[] = {
22     "1lt", "1st", "2lt", "2nd", "3rd", "admiral", "capt", "captain", "col",
23     "cpt", "dr", "gen", "general", "lcdr", "lt", "ltc", "ltg", "ltjg", "maj",
24     "major", "mg", "mr", "mrs", "ms", "pastor", "prof", "rep", "reverend",
25     "rev", "sen", "st" };
26 
27 const char* const name_suffixes[] = {
28     "b.a", "ba", "d.d.s", "dds", "i", "ii", "iii", "iv", "ix", "jr", "m.a",
29     "m.d", "ma", "md", "ms", "ph.d", "phd", "sr", "v", "vi", "vii", "viii",
30     "x" };
31 
32 const char* const family_name_prefixes[] = {
33     "d'", "de", "del", "der", "di", "la", "le", "mc", "san", "st", "ter",
34     "van", "von" };
35 
36 // Returns true if |set| contains |element|, modulo a final period.
ContainsString(const char * const set[],size_t set_size,const base::string16 & element)37 bool ContainsString(const char* const set[],
38                     size_t set_size,
39                     const base::string16& element) {
40   if (!base::IsStringASCII(element))
41     return false;
42 
43   base::string16 trimmed_element;
44   base::TrimString(element, base::ASCIIToUTF16("."), &trimmed_element);
45 
46   for (size_t i = 0; i < set_size; ++i) {
47     if (LowerCaseEqualsASCII(trimmed_element, set[i]))
48       return true;
49   }
50 
51   return false;
52 }
53 
54 // Removes common name prefixes from |name_tokens|.
StripPrefixes(std::vector<base::string16> * name_tokens)55 void StripPrefixes(std::vector<base::string16>* name_tokens) {
56   std::vector<base::string16>::iterator iter = name_tokens->begin();
57   while(iter != name_tokens->end()) {
58     if (!ContainsString(name_prefixes, arraysize(name_prefixes), *iter))
59       break;
60     ++iter;
61   }
62 
63   std::vector<base::string16> copy_vector;
64   copy_vector.assign(iter, name_tokens->end());
65   *name_tokens = copy_vector;
66 }
67 
68 // Removes common name suffixes from |name_tokens|.
StripSuffixes(std::vector<base::string16> * name_tokens)69 void StripSuffixes(std::vector<base::string16>* name_tokens) {
70   while(!name_tokens->empty()) {
71     if (!ContainsString(name_suffixes, arraysize(name_suffixes),
72                         name_tokens->back())) {
73       break;
74     }
75     name_tokens->pop_back();
76   }
77 }
78 
79 struct NameParts {
80   base::string16 given;
81   base::string16 middle;
82   base::string16 family;
83 };
84 
85 // TODO(estade): This does Western name splitting. It should do different
86 // splitting based on the app locale.
SplitName(const base::string16 & name)87 NameParts SplitName(const base::string16& name) {
88   std::vector<base::string16> name_tokens;
89   Tokenize(name, base::ASCIIToUTF16(" ,"), &name_tokens);
90 
91   StripPrefixes(&name_tokens);
92 
93   // Don't assume "Ma" is a suffix in John Ma.
94   if (name_tokens.size() > 2)
95     StripSuffixes(&name_tokens);
96 
97   NameParts parts;
98 
99   if (name_tokens.empty()) {
100     // Bad things have happened; just assume the whole thing is a given name.
101     parts.given = name;
102     return parts;
103   }
104 
105   // Only one token, assume given name.
106   if (name_tokens.size() == 1) {
107     parts.given = name_tokens[0];
108     return parts;
109   }
110 
111   // 2 or more tokens. Grab the family, which is the last word plus any
112   // recognizable family prefixes.
113   std::vector<base::string16> reverse_family_tokens;
114   reverse_family_tokens.push_back(name_tokens.back());
115   name_tokens.pop_back();
116   while (name_tokens.size() >= 1 &&
117          ContainsString(family_name_prefixes,
118                         arraysize(family_name_prefixes),
119                         name_tokens.back())) {
120     reverse_family_tokens.push_back(name_tokens.back());
121     name_tokens.pop_back();
122   }
123 
124   std::vector<base::string16> family_tokens(reverse_family_tokens.rbegin(),
125                                             reverse_family_tokens.rend());
126   parts.family = JoinString(family_tokens, base::char16(' '));
127 
128   // Take the last remaining token as the middle name (if there are at least 2
129   // tokens).
130   if (name_tokens.size() >= 2) {
131     parts.middle = name_tokens.back();
132     name_tokens.pop_back();
133   }
134 
135   // Remainder is given name.
136   parts.given = JoinString(name_tokens, base::char16(' '));
137 
138   return parts;
139 }
140 
141 }  // namespace
142 
NameInfo()143 NameInfo::NameInfo() {}
144 
NameInfo(const NameInfo & info)145 NameInfo::NameInfo(const NameInfo& info) : FormGroup() {
146   *this = info;
147 }
148 
~NameInfo()149 NameInfo::~NameInfo() {}
150 
operator =(const NameInfo & info)151 NameInfo& NameInfo::operator=(const NameInfo& info) {
152   if (this == &info)
153     return *this;
154 
155   given_ = info.given_;
156   middle_ = info.middle_;
157   family_ = info.family_;
158   full_ = info.full_;
159   return *this;
160 }
161 
ParsedNamesAreEqual(const NameInfo & info)162 bool NameInfo::ParsedNamesAreEqual(const NameInfo& info) {
163   return (base::StringToLowerASCII(given_) ==
164               base::StringToLowerASCII(info.given_) &&
165           base::StringToLowerASCII(middle_) ==
166               base::StringToLowerASCII(info.middle_) &&
167           base::StringToLowerASCII(family_) ==
168               base::StringToLowerASCII(info.family_));
169 }
170 
GetSupportedTypes(ServerFieldTypeSet * supported_types) const171 void NameInfo::GetSupportedTypes(ServerFieldTypeSet* supported_types) const {
172   supported_types->insert(NAME_FIRST);
173   supported_types->insert(NAME_MIDDLE);
174   supported_types->insert(NAME_LAST);
175   supported_types->insert(NAME_MIDDLE_INITIAL);
176   supported_types->insert(NAME_FULL);
177 }
178 
GetRawInfo(ServerFieldType type) const179 base::string16 NameInfo::GetRawInfo(ServerFieldType type) const {
180   DCHECK_EQ(NAME, AutofillType(type).group());
181   switch (type) {
182     case NAME_FIRST:
183       return given_;
184 
185     case NAME_MIDDLE:
186       return middle_;
187 
188     case NAME_LAST:
189       return family_;
190 
191     case NAME_MIDDLE_INITIAL:
192       return MiddleInitial();
193 
194     case NAME_FULL:
195       return full_;
196 
197     default:
198       return base::string16();
199   }
200 }
201 
SetRawInfo(ServerFieldType type,const base::string16 & value)202 void NameInfo::SetRawInfo(ServerFieldType type, const base::string16& value) {
203   DCHECK_EQ(NAME, AutofillType(type).group());
204 
205   switch (type) {
206     case NAME_FIRST:
207       given_ = value;
208       break;
209 
210     case NAME_MIDDLE:
211     case NAME_MIDDLE_INITIAL:
212       middle_ = value;
213       break;
214 
215     case NAME_LAST:
216       family_ = value;
217       break;
218 
219     case NAME_FULL:
220       full_ = value;
221       break;
222 
223     default:
224       NOTREACHED();
225   }
226 }
227 
GetInfo(const AutofillType & type,const std::string & app_locale) const228 base::string16 NameInfo::GetInfo(const AutofillType& type,
229                                  const std::string& app_locale) const {
230   if (type.GetStorableType() == NAME_FULL)
231     return FullName();
232 
233   return GetRawInfo(type.GetStorableType());
234 }
235 
SetInfo(const AutofillType & type,const base::string16 & value,const std::string & app_locale)236 bool NameInfo::SetInfo(const AutofillType& type,
237                        const base::string16& value,
238                        const std::string& app_locale) {
239   // Always clear out the full name if we're making a change.
240   if (value != GetInfo(type, app_locale))
241     full_.clear();
242 
243   if (type.GetStorableType() == NAME_FULL) {
244     SetFullName(value);
245     return true;
246   }
247 
248   return FormGroup::SetInfo(type, value, app_locale);
249 }
250 
FullName() const251 base::string16 NameInfo::FullName() const {
252   if (!full_.empty())
253     return full_;
254 
255   std::vector<base::string16> full_name;
256   if (!given_.empty())
257     full_name.push_back(given_);
258 
259   if (!middle_.empty())
260     full_name.push_back(middle_);
261 
262   if (!family_.empty())
263     full_name.push_back(family_);
264 
265   return JoinString(full_name, ' ');
266 }
267 
MiddleInitial() const268 base::string16 NameInfo::MiddleInitial() const {
269   if (middle_.empty())
270     return base::string16();
271 
272   base::string16 middle_name(middle_);
273   base::string16 initial;
274   initial.push_back(middle_name[0]);
275   return initial;
276 }
277 
SetFullName(const base::string16 & full)278 void NameInfo::SetFullName(const base::string16& full) {
279   full_ = full;
280 
281   // If |full| is empty, leave the other name parts alone. This might occur
282   // due to a migrated database with an empty |full_name| value.
283   if (full.empty())
284     return;
285 
286   NameParts parts = SplitName(full);
287   given_ = parts.given;
288   middle_ = parts.middle;
289   family_ = parts.family;
290 }
291 
EmailInfo()292 EmailInfo::EmailInfo() {}
293 
EmailInfo(const EmailInfo & info)294 EmailInfo::EmailInfo(const EmailInfo& info) : FormGroup() {
295   *this = info;
296 }
297 
~EmailInfo()298 EmailInfo::~EmailInfo() {}
299 
operator =(const EmailInfo & info)300 EmailInfo& EmailInfo::operator=(const EmailInfo& info) {
301   if (this == &info)
302     return *this;
303 
304   email_ = info.email_;
305   return *this;
306 }
307 
GetSupportedTypes(ServerFieldTypeSet * supported_types) const308 void EmailInfo::GetSupportedTypes(ServerFieldTypeSet* supported_types) const {
309   supported_types->insert(EMAIL_ADDRESS);
310 }
311 
GetRawInfo(ServerFieldType type) const312 base::string16 EmailInfo::GetRawInfo(ServerFieldType type) const {
313   if (type == EMAIL_ADDRESS)
314     return email_;
315 
316   return base::string16();
317 }
318 
SetRawInfo(ServerFieldType type,const base::string16 & value)319 void EmailInfo::SetRawInfo(ServerFieldType type, const base::string16& value) {
320   DCHECK_EQ(EMAIL_ADDRESS, type);
321   email_ = value;
322 }
323 
CompanyInfo()324 CompanyInfo::CompanyInfo() {}
325 
CompanyInfo(const CompanyInfo & info)326 CompanyInfo::CompanyInfo(const CompanyInfo& info) : FormGroup() {
327   *this = info;
328 }
329 
~CompanyInfo()330 CompanyInfo::~CompanyInfo() {}
331 
operator =(const CompanyInfo & info)332 CompanyInfo& CompanyInfo::operator=(const CompanyInfo& info) {
333   if (this == &info)
334     return *this;
335 
336   company_name_ = info.company_name_;
337   return *this;
338 }
339 
GetSupportedTypes(ServerFieldTypeSet * supported_types) const340 void CompanyInfo::GetSupportedTypes(ServerFieldTypeSet* supported_types) const {
341   supported_types->insert(COMPANY_NAME);
342 }
343 
GetRawInfo(ServerFieldType type) const344 base::string16 CompanyInfo::GetRawInfo(ServerFieldType type) const {
345   if (type == COMPANY_NAME)
346     return company_name_;
347 
348   return base::string16();
349 }
350 
SetRawInfo(ServerFieldType type,const base::string16 & value)351 void CompanyInfo::SetRawInfo(ServerFieldType type,
352                              const base::string16& value) {
353   DCHECK_EQ(COMPANY_NAME, type);
354   company_name_ = value;
355 }
356 
357 }  // namespace autofill
358