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. 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|. 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|. 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. 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 143 NameInfo::NameInfo() {} 144 145 NameInfo::NameInfo(const NameInfo& info) : FormGroup() { 146 *this = info; 147 } 148 149 NameInfo::~NameInfo() {} 150 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 162 bool NameInfo::EqualsIgnoreCase(const NameInfo& info) { 163 return (StringToLowerASCII(given_) == StringToLowerASCII(info.given_) && 164 StringToLowerASCII(middle_) == StringToLowerASCII(info.middle_) && 165 StringToLowerASCII(family_) == StringToLowerASCII(info.family_)); 166 } 167 168 void 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 176 base::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 FullName(); 193 194 default: 195 return base::string16(); 196 } 197 } 198 199 void NameInfo::SetRawInfo(ServerFieldType type, const base::string16& value) { 200 DCHECK_EQ(NAME, AutofillType(type).group()); 201 202 // Always clear out the full name if we're making a change. 203 if (value != GetRawInfo(type)) 204 full_.clear(); 205 206 switch (type) { 207 case NAME_FIRST: 208 given_ = value; 209 break; 210 211 case NAME_MIDDLE: 212 case NAME_MIDDLE_INITIAL: 213 middle_ = value; 214 break; 215 216 case NAME_LAST: 217 family_ = value; 218 break; 219 220 case NAME_FULL: 221 // TODO(estade): this should just set |full_|; only SetInfo should attempt 222 // to be smart. http://crbug.com/384640 223 SetFullName(value); 224 break; 225 226 default: 227 NOTREACHED(); 228 } 229 } 230 231 base::string16 NameInfo::FullName() const { 232 if (!full_.empty()) 233 return full_; 234 235 std::vector<base::string16> full_name; 236 if (!given_.empty()) 237 full_name.push_back(given_); 238 239 if (!middle_.empty()) 240 full_name.push_back(middle_); 241 242 if (!family_.empty()) 243 full_name.push_back(family_); 244 245 return JoinString(full_name, ' '); 246 } 247 248 base::string16 NameInfo::MiddleInitial() const { 249 if (middle_.empty()) 250 return base::string16(); 251 252 base::string16 middle_name(middle_); 253 base::string16 initial; 254 initial.push_back(middle_name[0]); 255 return initial; 256 } 257 258 void NameInfo::SetFullName(const base::string16& full) { 259 // Hack: don't do anything if this wouldn't change the full, concatenated 260 // name. Otherwise when unpickling data from the database, "First|Middle|" 261 // will get parsed as "First||Middle". 262 // TODO(estade): we should be able to remove this when fixing the TODO in 263 // SetRawInfo. http://crbug.com/384640 264 if (FullName() == full) 265 return; 266 267 full_ = full; 268 269 // If |full| is empty, leave the other name parts alone. This might occur 270 // due to a migrated database with an empty |full_name| value. 271 if (full.empty()) 272 return; 273 274 NameParts parts = SplitName(full); 275 given_ = parts.given; 276 middle_ = parts.middle; 277 family_ = parts.family; 278 } 279 280 EmailInfo::EmailInfo() {} 281 282 EmailInfo::EmailInfo(const EmailInfo& info) : FormGroup() { 283 *this = info; 284 } 285 286 EmailInfo::~EmailInfo() {} 287 288 EmailInfo& EmailInfo::operator=(const EmailInfo& info) { 289 if (this == &info) 290 return *this; 291 292 email_ = info.email_; 293 return *this; 294 } 295 296 void EmailInfo::GetSupportedTypes(ServerFieldTypeSet* supported_types) const { 297 supported_types->insert(EMAIL_ADDRESS); 298 } 299 300 base::string16 EmailInfo::GetRawInfo(ServerFieldType type) const { 301 if (type == EMAIL_ADDRESS) 302 return email_; 303 304 return base::string16(); 305 } 306 307 void EmailInfo::SetRawInfo(ServerFieldType type, const base::string16& value) { 308 DCHECK_EQ(EMAIL_ADDRESS, type); 309 email_ = value; 310 } 311 312 CompanyInfo::CompanyInfo() {} 313 314 CompanyInfo::CompanyInfo(const CompanyInfo& info) : FormGroup() { 315 *this = info; 316 } 317 318 CompanyInfo::~CompanyInfo() {} 319 320 CompanyInfo& CompanyInfo::operator=(const CompanyInfo& info) { 321 if (this == &info) 322 return *this; 323 324 company_name_ = info.company_name_; 325 return *this; 326 } 327 328 void CompanyInfo::GetSupportedTypes(ServerFieldTypeSet* supported_types) const { 329 supported_types->insert(COMPANY_NAME); 330 } 331 332 base::string16 CompanyInfo::GetRawInfo(ServerFieldType type) const { 333 if (type == COMPANY_NAME) 334 return company_name_; 335 336 return base::string16(); 337 } 338 339 void CompanyInfo::SetRawInfo(ServerFieldType type, 340 const base::string16& value) { 341 DCHECK_EQ(COMPANY_NAME, type); 342 company_name_ = value; 343 } 344 345 } // namespace autofill 346