contact_info.cc revision 116680a4aac90f2aa7413d9095a592090648e557
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 17namespace autofill { 18 19namespace { 20 21const 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 27const 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 32const 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. 37bool 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|. 55void 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|. 69void 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 79struct 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. 87NameParts 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 143NameInfo::NameInfo() {} 144 145NameInfo::NameInfo(const NameInfo& info) : FormGroup() { 146 *this = info; 147} 148 149NameInfo::~NameInfo() {} 150 151NameInfo& 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 162bool NameInfo::ParsedNamesAreEqual(const NameInfo& info) { 163 return (StringToLowerASCII(given_) == StringToLowerASCII(info.given_) && 164 StringToLowerASCII(middle_) == StringToLowerASCII(info.middle_) && 165 StringToLowerASCII(family_) == StringToLowerASCII(info.family_)); 166} 167 168void NameInfo::GetSupportedTypes(ServerFieldTypeSet* supported_types) const { 169 supported_types->insert(NAME_FIRST); 170 supported_types->insert(NAME_MIDDLE); 171 supported_types->insert(NAME_LAST); 172 supported_types->insert(NAME_MIDDLE_INITIAL); 173 supported_types->insert(NAME_FULL); 174} 175 176base::string16 NameInfo::GetRawInfo(ServerFieldType type) const { 177 DCHECK_EQ(NAME, AutofillType(type).group()); 178 switch (type) { 179 case NAME_FIRST: 180 return given_; 181 182 case NAME_MIDDLE: 183 return middle_; 184 185 case NAME_LAST: 186 return family_; 187 188 case NAME_MIDDLE_INITIAL: 189 return MiddleInitial(); 190 191 case NAME_FULL: 192 return full_; 193 194 default: 195 return base::string16(); 196 } 197} 198 199void NameInfo::SetRawInfo(ServerFieldType type, const base::string16& value) { 200 DCHECK_EQ(NAME, AutofillType(type).group()); 201 202 switch (type) { 203 case NAME_FIRST: 204 given_ = value; 205 break; 206 207 case NAME_MIDDLE: 208 case NAME_MIDDLE_INITIAL: 209 middle_ = value; 210 break; 211 212 case NAME_LAST: 213 family_ = value; 214 break; 215 216 case NAME_FULL: 217 full_ = value; 218 break; 219 220 default: 221 NOTREACHED(); 222 } 223} 224 225base::string16 NameInfo::GetInfo(const AutofillType& type, 226 const std::string& app_locale) const { 227 if (type.GetStorableType() == NAME_FULL) 228 return FullName(); 229 230 return GetRawInfo(type.GetStorableType()); 231} 232 233bool NameInfo::SetInfo(const AutofillType& type, 234 const base::string16& value, 235 const std::string& app_locale) { 236 // Always clear out the full name if we're making a change. 237 if (value != GetInfo(type, app_locale)) 238 full_.clear(); 239 240 if (type.GetStorableType() == NAME_FULL) { 241 SetFullName(value); 242 return true; 243 } 244 245 return FormGroup::SetInfo(type, value, app_locale); 246} 247 248base::string16 NameInfo::FullName() const { 249 if (!full_.empty()) 250 return full_; 251 252 std::vector<base::string16> full_name; 253 if (!given_.empty()) 254 full_name.push_back(given_); 255 256 if (!middle_.empty()) 257 full_name.push_back(middle_); 258 259 if (!family_.empty()) 260 full_name.push_back(family_); 261 262 return JoinString(full_name, ' '); 263} 264 265base::string16 NameInfo::MiddleInitial() const { 266 if (middle_.empty()) 267 return base::string16(); 268 269 base::string16 middle_name(middle_); 270 base::string16 initial; 271 initial.push_back(middle_name[0]); 272 return initial; 273} 274 275void NameInfo::SetFullName(const base::string16& full) { 276 full_ = full; 277 278 // If |full| is empty, leave the other name parts alone. This might occur 279 // due to a migrated database with an empty |full_name| value. 280 if (full.empty()) 281 return; 282 283 NameParts parts = SplitName(full); 284 given_ = parts.given; 285 middle_ = parts.middle; 286 family_ = parts.family; 287} 288 289EmailInfo::EmailInfo() {} 290 291EmailInfo::EmailInfo(const EmailInfo& info) : FormGroup() { 292 *this = info; 293} 294 295EmailInfo::~EmailInfo() {} 296 297EmailInfo& EmailInfo::operator=(const EmailInfo& info) { 298 if (this == &info) 299 return *this; 300 301 email_ = info.email_; 302 return *this; 303} 304 305void EmailInfo::GetSupportedTypes(ServerFieldTypeSet* supported_types) const { 306 supported_types->insert(EMAIL_ADDRESS); 307} 308 309base::string16 EmailInfo::GetRawInfo(ServerFieldType type) const { 310 if (type == EMAIL_ADDRESS) 311 return email_; 312 313 return base::string16(); 314} 315 316void EmailInfo::SetRawInfo(ServerFieldType type, const base::string16& value) { 317 DCHECK_EQ(EMAIL_ADDRESS, type); 318 email_ = value; 319} 320 321CompanyInfo::CompanyInfo() {} 322 323CompanyInfo::CompanyInfo(const CompanyInfo& info) : FormGroup() { 324 *this = info; 325} 326 327CompanyInfo::~CompanyInfo() {} 328 329CompanyInfo& CompanyInfo::operator=(const CompanyInfo& info) { 330 if (this == &info) 331 return *this; 332 333 company_name_ = info.company_name_; 334 return *this; 335} 336 337void CompanyInfo::GetSupportedTypes(ServerFieldTypeSet* supported_types) const { 338 supported_types->insert(COMPANY_NAME); 339} 340 341base::string16 CompanyInfo::GetRawInfo(ServerFieldType type) const { 342 if (type == COMPANY_NAME) 343 return company_name_; 344 345 return base::string16(); 346} 347 348void CompanyInfo::SetRawInfo(ServerFieldType type, 349 const base::string16& value) { 350 DCHECK_EQ(COMPANY_NAME, type); 351 company_name_ = value; 352} 353 354} // namespace autofill 355