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 (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 171void 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 179base::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 202void 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 228base::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 236bool 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 251base::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 268base::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 278void 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 292EmailInfo::EmailInfo() {} 293 294EmailInfo::EmailInfo(const EmailInfo& info) : FormGroup() { 295 *this = info; 296} 297 298EmailInfo::~EmailInfo() {} 299 300EmailInfo& EmailInfo::operator=(const EmailInfo& info) { 301 if (this == &info) 302 return *this; 303 304 email_ = info.email_; 305 return *this; 306} 307 308void EmailInfo::GetSupportedTypes(ServerFieldTypeSet* supported_types) const { 309 supported_types->insert(EMAIL_ADDRESS); 310} 311 312base::string16 EmailInfo::GetRawInfo(ServerFieldType type) const { 313 if (type == EMAIL_ADDRESS) 314 return email_; 315 316 return base::string16(); 317} 318 319void EmailInfo::SetRawInfo(ServerFieldType type, const base::string16& value) { 320 DCHECK_EQ(EMAIL_ADDRESS, type); 321 email_ = value; 322} 323 324CompanyInfo::CompanyInfo() {} 325 326CompanyInfo::CompanyInfo(const CompanyInfo& info) : FormGroup() { 327 *this = info; 328} 329 330CompanyInfo::~CompanyInfo() {} 331 332CompanyInfo& CompanyInfo::operator=(const CompanyInfo& info) { 333 if (this == &info) 334 return *this; 335 336 company_name_ = info.company_name_; 337 return *this; 338} 339 340void CompanyInfo::GetSupportedTypes(ServerFieldTypeSet* supported_types) const { 341 supported_types->insert(COMPANY_NAME); 342} 343 344base::string16 CompanyInfo::GetRawInfo(ServerFieldType type) const { 345 if (type == COMPANY_NAME) 346 return company_name_; 347 348 return base::string16(); 349} 350 351void 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