|  | // Copyright 2013 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "components/autofill/core/browser/contact_info.h" | 
|  |  | 
|  | #include <stddef.h> | 
|  | #include <ostream> | 
|  | #include <string> | 
|  |  | 
|  | #include "base/basictypes.h" | 
|  | #include "base/logging.h" | 
|  | #include "base/strings/string_util.h" | 
|  | #include "base/strings/utf_string_conversions.h" | 
|  | #include "components/autofill/core/browser/autofill_type.h" | 
|  |  | 
|  | namespace autofill { | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | const char* const name_prefixes[] = { | 
|  | "1lt", "1st", "2lt", "2nd", "3rd", "admiral", "capt", "captain", "col", | 
|  | "cpt", "dr", "gen", "general", "lcdr", "lt", "ltc", "ltg", "ltjg", "maj", | 
|  | "major", "mg", "mr", "mrs", "ms", "pastor", "prof", "rep", "reverend", | 
|  | "rev", "sen", "st" }; | 
|  |  | 
|  | const char* const name_suffixes[] = { | 
|  | "b.a", "ba", "d.d.s", "dds", "i", "ii", "iii", "iv", "ix", "jr", "m.a", | 
|  | "m.d", "ma", "md", "ms", "ph.d", "phd", "sr", "v", "vi", "vii", "viii", | 
|  | "x" }; | 
|  |  | 
|  | const char* const family_name_prefixes[] = { | 
|  | "d'", "de", "del", "der", "di", "la", "le", "mc", "san", "st", "ter", | 
|  | "van", "von" }; | 
|  |  | 
|  | // Returns true if |set| contains |element|, modulo a final period. | 
|  | bool ContainsString(const char* const set[], | 
|  | size_t set_size, | 
|  | const base::string16& element) { | 
|  | if (!base::IsStringASCII(element)) | 
|  | return false; | 
|  |  | 
|  | base::string16 trimmed_element; | 
|  | base::TrimString(element, base::ASCIIToUTF16("."), &trimmed_element); | 
|  |  | 
|  | for (size_t i = 0; i < set_size; ++i) { | 
|  | if (LowerCaseEqualsASCII(trimmed_element, set[i])) | 
|  | return true; | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Removes common name prefixes from |name_tokens|. | 
|  | void StripPrefixes(std::vector<base::string16>* name_tokens) { | 
|  | std::vector<base::string16>::iterator iter = name_tokens->begin(); | 
|  | while(iter != name_tokens->end()) { | 
|  | if (!ContainsString(name_prefixes, arraysize(name_prefixes), *iter)) | 
|  | break; | 
|  | ++iter; | 
|  | } | 
|  |  | 
|  | std::vector<base::string16> copy_vector; | 
|  | copy_vector.assign(iter, name_tokens->end()); | 
|  | *name_tokens = copy_vector; | 
|  | } | 
|  |  | 
|  | // Removes common name suffixes from |name_tokens|. | 
|  | void StripSuffixes(std::vector<base::string16>* name_tokens) { | 
|  | while(!name_tokens->empty()) { | 
|  | if (!ContainsString(name_suffixes, arraysize(name_suffixes), | 
|  | name_tokens->back())) { | 
|  | break; | 
|  | } | 
|  | name_tokens->pop_back(); | 
|  | } | 
|  | } | 
|  |  | 
|  | struct NameParts { | 
|  | base::string16 given; | 
|  | base::string16 middle; | 
|  | base::string16 family; | 
|  | }; | 
|  |  | 
|  | // TODO(estade): This does Western name splitting. It should do different | 
|  | // splitting based on the app locale. | 
|  | NameParts SplitName(const base::string16& name) { | 
|  | std::vector<base::string16> name_tokens; | 
|  | Tokenize(name, base::ASCIIToUTF16(" ,"), &name_tokens); | 
|  |  | 
|  | StripPrefixes(&name_tokens); | 
|  |  | 
|  | // Don't assume "Ma" is a suffix in John Ma. | 
|  | if (name_tokens.size() > 2) | 
|  | StripSuffixes(&name_tokens); | 
|  |  | 
|  | NameParts parts; | 
|  |  | 
|  | if (name_tokens.empty()) { | 
|  | // Bad things have happened; just assume the whole thing is a given name. | 
|  | parts.given = name; | 
|  | return parts; | 
|  | } | 
|  |  | 
|  | // Only one token, assume given name. | 
|  | if (name_tokens.size() == 1) { | 
|  | parts.given = name_tokens[0]; | 
|  | return parts; | 
|  | } | 
|  |  | 
|  | // 2 or more tokens. Grab the family, which is the last word plus any | 
|  | // recognizable family prefixes. | 
|  | std::vector<base::string16> reverse_family_tokens; | 
|  | reverse_family_tokens.push_back(name_tokens.back()); | 
|  | name_tokens.pop_back(); | 
|  | while (name_tokens.size() >= 1 && | 
|  | ContainsString(family_name_prefixes, | 
|  | arraysize(family_name_prefixes), | 
|  | name_tokens.back())) { | 
|  | reverse_family_tokens.push_back(name_tokens.back()); | 
|  | name_tokens.pop_back(); | 
|  | } | 
|  |  | 
|  | std::vector<base::string16> family_tokens(reverse_family_tokens.rbegin(), | 
|  | reverse_family_tokens.rend()); | 
|  | parts.family = JoinString(family_tokens, base::char16(' ')); | 
|  |  | 
|  | // Take the last remaining token as the middle name (if there are at least 2 | 
|  | // tokens). | 
|  | if (name_tokens.size() >= 2) { | 
|  | parts.middle = name_tokens.back(); | 
|  | name_tokens.pop_back(); | 
|  | } | 
|  |  | 
|  | // Remainder is given name. | 
|  | parts.given = JoinString(name_tokens, base::char16(' ')); | 
|  |  | 
|  | return parts; | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | NameInfo::NameInfo() {} | 
|  |  | 
|  | NameInfo::NameInfo(const NameInfo& info) : FormGroup() { | 
|  | *this = info; | 
|  | } | 
|  |  | 
|  | NameInfo::~NameInfo() {} | 
|  |  | 
|  | NameInfo& NameInfo::operator=(const NameInfo& info) { | 
|  | if (this == &info) | 
|  | return *this; | 
|  |  | 
|  | given_ = info.given_; | 
|  | middle_ = info.middle_; | 
|  | family_ = info.family_; | 
|  | full_ = info.full_; | 
|  | return *this; | 
|  | } | 
|  |  | 
|  | bool NameInfo::ParsedNamesAreEqual(const NameInfo& info) { | 
|  | return (base::StringToLowerASCII(given_) == | 
|  | base::StringToLowerASCII(info.given_) && | 
|  | base::StringToLowerASCII(middle_) == | 
|  | base::StringToLowerASCII(info.middle_) && | 
|  | base::StringToLowerASCII(family_) == | 
|  | base::StringToLowerASCII(info.family_)); | 
|  | } | 
|  |  | 
|  | void NameInfo::GetSupportedTypes(ServerFieldTypeSet* supported_types) const { | 
|  | supported_types->insert(NAME_FIRST); | 
|  | supported_types->insert(NAME_MIDDLE); | 
|  | supported_types->insert(NAME_LAST); | 
|  | supported_types->insert(NAME_MIDDLE_INITIAL); | 
|  | supported_types->insert(NAME_FULL); | 
|  | } | 
|  |  | 
|  | base::string16 NameInfo::GetRawInfo(ServerFieldType type) const { | 
|  | DCHECK_EQ(NAME, AutofillType(type).group()); | 
|  | switch (type) { | 
|  | case NAME_FIRST: | 
|  | return given_; | 
|  |  | 
|  | case NAME_MIDDLE: | 
|  | return middle_; | 
|  |  | 
|  | case NAME_LAST: | 
|  | return family_; | 
|  |  | 
|  | case NAME_MIDDLE_INITIAL: | 
|  | return MiddleInitial(); | 
|  |  | 
|  | case NAME_FULL: | 
|  | return full_; | 
|  |  | 
|  | default: | 
|  | return base::string16(); | 
|  | } | 
|  | } | 
|  |  | 
|  | void NameInfo::SetRawInfo(ServerFieldType type, const base::string16& value) { | 
|  | DCHECK_EQ(NAME, AutofillType(type).group()); | 
|  |  | 
|  | switch (type) { | 
|  | case NAME_FIRST: | 
|  | given_ = value; | 
|  | break; | 
|  |  | 
|  | case NAME_MIDDLE: | 
|  | case NAME_MIDDLE_INITIAL: | 
|  | middle_ = value; | 
|  | break; | 
|  |  | 
|  | case NAME_LAST: | 
|  | family_ = value; | 
|  | break; | 
|  |  | 
|  | case NAME_FULL: | 
|  | full_ = value; | 
|  | break; | 
|  |  | 
|  | default: | 
|  | NOTREACHED(); | 
|  | } | 
|  | } | 
|  |  | 
|  | base::string16 NameInfo::GetInfo(const AutofillType& type, | 
|  | const std::string& app_locale) const { | 
|  | if (type.GetStorableType() == NAME_FULL) | 
|  | return FullName(); | 
|  |  | 
|  | return GetRawInfo(type.GetStorableType()); | 
|  | } | 
|  |  | 
|  | bool NameInfo::SetInfo(const AutofillType& type, | 
|  | const base::string16& value, | 
|  | const std::string& app_locale) { | 
|  | // Always clear out the full name if we're making a change. | 
|  | if (value != GetInfo(type, app_locale)) | 
|  | full_.clear(); | 
|  |  | 
|  | if (type.GetStorableType() == NAME_FULL) { | 
|  | SetFullName(value); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | return FormGroup::SetInfo(type, value, app_locale); | 
|  | } | 
|  |  | 
|  | base::string16 NameInfo::FullName() const { | 
|  | if (!full_.empty()) | 
|  | return full_; | 
|  |  | 
|  | std::vector<base::string16> full_name; | 
|  | if (!given_.empty()) | 
|  | full_name.push_back(given_); | 
|  |  | 
|  | if (!middle_.empty()) | 
|  | full_name.push_back(middle_); | 
|  |  | 
|  | if (!family_.empty()) | 
|  | full_name.push_back(family_); | 
|  |  | 
|  | return JoinString(full_name, ' '); | 
|  | } | 
|  |  | 
|  | base::string16 NameInfo::MiddleInitial() const { | 
|  | if (middle_.empty()) | 
|  | return base::string16(); | 
|  |  | 
|  | base::string16 middle_name(middle_); | 
|  | base::string16 initial; | 
|  | initial.push_back(middle_name[0]); | 
|  | return initial; | 
|  | } | 
|  |  | 
|  | void NameInfo::SetFullName(const base::string16& full) { | 
|  | full_ = full; | 
|  |  | 
|  | // If |full| is empty, leave the other name parts alone. This might occur | 
|  | // due to a migrated database with an empty |full_name| value. | 
|  | if (full.empty()) | 
|  | return; | 
|  |  | 
|  | NameParts parts = SplitName(full); | 
|  | given_ = parts.given; | 
|  | middle_ = parts.middle; | 
|  | family_ = parts.family; | 
|  | } | 
|  |  | 
|  | EmailInfo::EmailInfo() {} | 
|  |  | 
|  | EmailInfo::EmailInfo(const EmailInfo& info) : FormGroup() { | 
|  | *this = info; | 
|  | } | 
|  |  | 
|  | EmailInfo::~EmailInfo() {} | 
|  |  | 
|  | EmailInfo& EmailInfo::operator=(const EmailInfo& info) { | 
|  | if (this == &info) | 
|  | return *this; | 
|  |  | 
|  | email_ = info.email_; | 
|  | return *this; | 
|  | } | 
|  |  | 
|  | void EmailInfo::GetSupportedTypes(ServerFieldTypeSet* supported_types) const { | 
|  | supported_types->insert(EMAIL_ADDRESS); | 
|  | } | 
|  |  | 
|  | base::string16 EmailInfo::GetRawInfo(ServerFieldType type) const { | 
|  | if (type == EMAIL_ADDRESS) | 
|  | return email_; | 
|  |  | 
|  | return base::string16(); | 
|  | } | 
|  |  | 
|  | void EmailInfo::SetRawInfo(ServerFieldType type, const base::string16& value) { | 
|  | DCHECK_EQ(EMAIL_ADDRESS, type); | 
|  | email_ = value; | 
|  | } | 
|  |  | 
|  | CompanyInfo::CompanyInfo() {} | 
|  |  | 
|  | CompanyInfo::CompanyInfo(const CompanyInfo& info) : FormGroup() { | 
|  | *this = info; | 
|  | } | 
|  |  | 
|  | CompanyInfo::~CompanyInfo() {} | 
|  |  | 
|  | CompanyInfo& CompanyInfo::operator=(const CompanyInfo& info) { | 
|  | if (this == &info) | 
|  | return *this; | 
|  |  | 
|  | company_name_ = info.company_name_; | 
|  | return *this; | 
|  | } | 
|  |  | 
|  | void CompanyInfo::GetSupportedTypes(ServerFieldTypeSet* supported_types) const { | 
|  | supported_types->insert(COMPANY_NAME); | 
|  | } | 
|  |  | 
|  | base::string16 CompanyInfo::GetRawInfo(ServerFieldType type) const { | 
|  | if (type == COMPANY_NAME) | 
|  | return company_name_; | 
|  |  | 
|  | return base::string16(); | 
|  | } | 
|  |  | 
|  | void CompanyInfo::SetRawInfo(ServerFieldType type, | 
|  | const base::string16& value) { | 
|  | DCHECK_EQ(COMPANY_NAME, type); | 
|  | company_name_ = value; | 
|  | } | 
|  |  | 
|  | }  // namespace autofill |