blob: b320a81ee5552a51f97e01438ee0400fa79770de [file] [log] [blame]
// 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