// Copyright (c) 2011 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 "chrome/browser/autofill/address.h" #include <stddef.h> #include "base/basictypes.h" #include "base/logging.h" #include "base/string_util.h" #include "chrome/browser/autofill/autofill_country.h" #include "chrome/browser/autofill/autofill_type.h" #include "chrome/browser/autofill/field_types.h" namespace { const char16 kAddressSplitChars[] = {'-', ',', '#', '.', ' ', 0}; const AutofillType::FieldTypeSubGroup kAutofillAddressTypes[] = { AutofillType::ADDRESS_LINE1, AutofillType::ADDRESS_LINE2, AutofillType::ADDRESS_CITY, AutofillType::ADDRESS_STATE, AutofillType::ADDRESS_ZIP, AutofillType::ADDRESS_COUNTRY, }; const int kAutofillAddressLength = arraysize(kAutofillAddressTypes); } // namespace Address::Address() {} Address::Address(const Address& address) : FormGroup() { *this = address; } Address::~Address() {} Address& Address::operator=(const Address& address) { if (this == &address) return *this; line1_tokens_ = address.line1_tokens_; line2_tokens_= address.line2_tokens_; line1_ = address.line1_; line2_ = address.line2_; city_ = address.city_; state_ = address.state_; country_code_ = address.country_code_; zip_code_ = address.zip_code_; return *this; } void Address::GetPossibleFieldTypes(const string16& text, FieldTypeSet* possible_types) const { DCHECK(possible_types); // If the text to match against the field types is empty, then no results will // match. if (text.empty()) return; if (IsLine1(text)) possible_types->insert(ADDRESS_HOME_LINE1); if (IsLine2(text)) possible_types->insert(ADDRESS_HOME_LINE2); if (IsCity(text)) possible_types->insert(ADDRESS_HOME_CITY); if (IsState(text)) possible_types->insert(ADDRESS_HOME_STATE); if (IsZipCode(text)) possible_types->insert(ADDRESS_HOME_ZIP); if (IsCountry(text)) possible_types->insert(ADDRESS_HOME_COUNTRY); } void Address::GetAvailableFieldTypes(FieldTypeSet* available_types) const { DCHECK(available_types); if (!line1_.empty()) available_types->insert(ADDRESS_HOME_LINE1); if (!line2_.empty()) available_types->insert(ADDRESS_HOME_LINE2); if (!city_.empty()) available_types->insert(ADDRESS_HOME_CITY); if (!state_.empty()) available_types->insert(ADDRESS_HOME_STATE); if (!zip_code_.empty()) available_types->insert(ADDRESS_HOME_ZIP); if (!country_code_.empty()) available_types->insert(ADDRESS_HOME_COUNTRY); } string16 Address::GetInfo(AutofillFieldType type) const { if (type == ADDRESS_HOME_LINE1) return line1_; if (type == ADDRESS_HOME_LINE2) return line2_; if (type == ADDRESS_HOME_CITY) return city_; if (type == ADDRESS_HOME_STATE) return state_; if (type == ADDRESS_HOME_ZIP) return zip_code_; if (type == ADDRESS_HOME_COUNTRY) return Country(); return string16(); } void Address::SetInfo(AutofillFieldType type, const string16& value) { FieldTypeSubGroup subgroup = AutofillType(type).subgroup(); if (subgroup == AutofillType::ADDRESS_LINE1) set_line1(value); else if (subgroup == AutofillType::ADDRESS_LINE2) set_line2(value); else if (subgroup == AutofillType::ADDRESS_CITY) city_ = value; else if (subgroup == AutofillType::ADDRESS_STATE) state_ = value; else if (subgroup == AutofillType::ADDRESS_COUNTRY) SetCountry(value); else if (subgroup == AutofillType::ADDRESS_ZIP) zip_code_ = value; else NOTREACHED(); } void Address::Clear() { line1_tokens_.clear(); line1_.clear(); line2_tokens_.clear(); line2_.clear(); city_.clear(); state_.clear(); country_code_.clear(); zip_code_.clear(); } string16 Address::Country() const { if (country_code().empty()) return string16(); std::string app_locale = AutofillCountry::ApplicationLocale(); return AutofillCountry(country_code(), app_locale).name(); } void Address::set_line1(const string16& line1) { line1_ = line1; line1_tokens_.clear(); Tokenize(line1, kAddressSplitChars, &line1_tokens_); LineTokens::iterator iter; for (iter = line1_tokens_.begin(); iter != line1_tokens_.end(); ++iter) *iter = StringToLowerASCII(*iter); } void Address::set_line2(const string16& line2) { line2_ = line2; line2_tokens_.clear(); Tokenize(line2, kAddressSplitChars, &line2_tokens_); LineTokens::iterator iter; for (iter = line2_tokens_.begin(); iter != line2_tokens_.end(); ++iter) *iter = StringToLowerASCII(*iter); } void Address::SetCountry(const string16& country) { std::string app_locale = AutofillCountry::ApplicationLocale(); country_code_ = AutofillCountry::GetCountryCode(country, app_locale); } bool Address::IsLine1(const string16& text) const { return IsLineMatch(text, line1_tokens_); } bool Address::IsLine2(const string16& text) const { return IsLineMatch(text, line2_tokens_); } bool Address::IsCity(const string16& text) const { return (StringToLowerASCII(city_) == StringToLowerASCII(text)); } bool Address::IsState(const string16& text) const { return (StringToLowerASCII(state_) == StringToLowerASCII(text)); } bool Address::IsCountry(const string16& text) const { std::string app_locale = AutofillCountry::ApplicationLocale(); std::string country_code = AutofillCountry::GetCountryCode(text, app_locale); return (!country_code.empty() && country_code_ == country_code); } bool Address::IsZipCode(const string16& text) const { return zip_code_ == text; } bool Address::IsLineMatch(const string16& text, const LineTokens& line_tokens) const { size_t line_tokens_size = line_tokens.size(); if (line_tokens_size == 0) return false; LineTokens text_tokens; Tokenize(text, kAddressSplitChars, &text_tokens); size_t text_tokens_size = text_tokens.size(); if (text_tokens_size == 0) return false; if (text_tokens_size > line_tokens_size) return false; // If each of the 'words' contained in the text are also present in the line, // then we will consider the text to match the line. LineTokens::iterator iter; for (iter = text_tokens.begin(); iter != text_tokens.end(); ++iter) { if (!IsWordInLine(*iter, line_tokens)) return false; } return true; } bool Address::IsWordInLine(const string16& word, const LineTokens& line_tokens) const { LineTokens::const_iterator iter; for (iter = line_tokens.begin(); iter != line_tokens.end(); ++iter) { if (StringToLowerASCII(word) == *iter) return true; } return false; }