1 // Copyright (c) 2011 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 "chrome/browser/autofill/address.h" 6 7 #include <stddef.h> 8 9 #include "base/basictypes.h" 10 #include "base/logging.h" 11 #include "base/string_util.h" 12 #include "chrome/browser/autofill/autofill_country.h" 13 #include "chrome/browser/autofill/autofill_type.h" 14 #include "chrome/browser/autofill/field_types.h" 15 16 namespace { 17 18 const char16 kAddressSplitChars[] = {'-', ',', '#', '.', ' ', 0}; 19 20 const AutofillType::FieldTypeSubGroup kAutofillAddressTypes[] = { 21 AutofillType::ADDRESS_LINE1, 22 AutofillType::ADDRESS_LINE2, 23 AutofillType::ADDRESS_CITY, 24 AutofillType::ADDRESS_STATE, 25 AutofillType::ADDRESS_ZIP, 26 AutofillType::ADDRESS_COUNTRY, 27 }; 28 29 const int kAutofillAddressLength = arraysize(kAutofillAddressTypes); 30 31 } // namespace 32 33 Address::Address() {} 34 35 Address::Address(const Address& address) : FormGroup() { 36 *this = address; 37 } 38 39 Address::~Address() {} 40 41 Address& Address::operator=(const Address& address) { 42 if (this == &address) 43 return *this; 44 45 line1_tokens_ = address.line1_tokens_; 46 line2_tokens_= address.line2_tokens_; 47 line1_ = address.line1_; 48 line2_ = address.line2_; 49 city_ = address.city_; 50 state_ = address.state_; 51 country_code_ = address.country_code_; 52 zip_code_ = address.zip_code_; 53 return *this; 54 } 55 56 void Address::GetPossibleFieldTypes(const string16& text, 57 FieldTypeSet* possible_types) const { 58 DCHECK(possible_types); 59 60 // If the text to match against the field types is empty, then no results will 61 // match. 62 if (text.empty()) 63 return; 64 65 if (IsLine1(text)) 66 possible_types->insert(ADDRESS_HOME_LINE1); 67 68 if (IsLine2(text)) 69 possible_types->insert(ADDRESS_HOME_LINE2); 70 71 if (IsCity(text)) 72 possible_types->insert(ADDRESS_HOME_CITY); 73 74 if (IsState(text)) 75 possible_types->insert(ADDRESS_HOME_STATE); 76 77 if (IsZipCode(text)) 78 possible_types->insert(ADDRESS_HOME_ZIP); 79 80 if (IsCountry(text)) 81 possible_types->insert(ADDRESS_HOME_COUNTRY); 82 } 83 84 void Address::GetAvailableFieldTypes(FieldTypeSet* available_types) const { 85 DCHECK(available_types); 86 87 if (!line1_.empty()) 88 available_types->insert(ADDRESS_HOME_LINE1); 89 90 if (!line2_.empty()) 91 available_types->insert(ADDRESS_HOME_LINE2); 92 93 if (!city_.empty()) 94 available_types->insert(ADDRESS_HOME_CITY); 95 96 if (!state_.empty()) 97 available_types->insert(ADDRESS_HOME_STATE); 98 99 if (!zip_code_.empty()) 100 available_types->insert(ADDRESS_HOME_ZIP); 101 102 if (!country_code_.empty()) 103 available_types->insert(ADDRESS_HOME_COUNTRY); 104 } 105 106 string16 Address::GetInfo(AutofillFieldType type) const { 107 if (type == ADDRESS_HOME_LINE1) 108 return line1_; 109 110 if (type == ADDRESS_HOME_LINE2) 111 return line2_; 112 113 if (type == ADDRESS_HOME_CITY) 114 return city_; 115 116 if (type == ADDRESS_HOME_STATE) 117 return state_; 118 119 if (type == ADDRESS_HOME_ZIP) 120 return zip_code_; 121 122 if (type == ADDRESS_HOME_COUNTRY) 123 return Country(); 124 125 return string16(); 126 } 127 128 void Address::SetInfo(AutofillFieldType type, const string16& value) { 129 FieldTypeSubGroup subgroup = AutofillType(type).subgroup(); 130 if (subgroup == AutofillType::ADDRESS_LINE1) 131 set_line1(value); 132 else if (subgroup == AutofillType::ADDRESS_LINE2) 133 set_line2(value); 134 else if (subgroup == AutofillType::ADDRESS_CITY) 135 city_ = value; 136 else if (subgroup == AutofillType::ADDRESS_STATE) 137 state_ = value; 138 else if (subgroup == AutofillType::ADDRESS_COUNTRY) 139 SetCountry(value); 140 else if (subgroup == AutofillType::ADDRESS_ZIP) 141 zip_code_ = value; 142 else 143 NOTREACHED(); 144 } 145 146 void Address::Clear() { 147 line1_tokens_.clear(); 148 line1_.clear(); 149 line2_tokens_.clear(); 150 line2_.clear(); 151 city_.clear(); 152 state_.clear(); 153 country_code_.clear(); 154 zip_code_.clear(); 155 } 156 157 string16 Address::Country() const { 158 if (country_code().empty()) 159 return string16(); 160 161 std::string app_locale = AutofillCountry::ApplicationLocale(); 162 return AutofillCountry(country_code(), app_locale).name(); 163 } 164 165 void Address::set_line1(const string16& line1) { 166 line1_ = line1; 167 line1_tokens_.clear(); 168 Tokenize(line1, kAddressSplitChars, &line1_tokens_); 169 LineTokens::iterator iter; 170 for (iter = line1_tokens_.begin(); iter != line1_tokens_.end(); ++iter) 171 *iter = StringToLowerASCII(*iter); 172 } 173 174 void Address::set_line2(const string16& line2) { 175 line2_ = line2; 176 line2_tokens_.clear(); 177 Tokenize(line2, kAddressSplitChars, &line2_tokens_); 178 LineTokens::iterator iter; 179 for (iter = line2_tokens_.begin(); iter != line2_tokens_.end(); ++iter) 180 *iter = StringToLowerASCII(*iter); 181 } 182 183 void Address::SetCountry(const string16& country) { 184 std::string app_locale = AutofillCountry::ApplicationLocale(); 185 country_code_ = AutofillCountry::GetCountryCode(country, app_locale); 186 } 187 188 bool Address::IsLine1(const string16& text) const { 189 return IsLineMatch(text, line1_tokens_); 190 } 191 192 bool Address::IsLine2(const string16& text) const { 193 return IsLineMatch(text, line2_tokens_); 194 } 195 196 bool Address::IsCity(const string16& text) const { 197 return (StringToLowerASCII(city_) == StringToLowerASCII(text)); 198 } 199 200 bool Address::IsState(const string16& text) const { 201 return (StringToLowerASCII(state_) == StringToLowerASCII(text)); 202 } 203 204 bool Address::IsCountry(const string16& text) const { 205 std::string app_locale = AutofillCountry::ApplicationLocale(); 206 std::string country_code = AutofillCountry::GetCountryCode(text, app_locale); 207 return (!country_code.empty() && country_code_ == country_code); 208 } 209 210 bool Address::IsZipCode(const string16& text) const { 211 return zip_code_ == text; 212 } 213 214 bool Address::IsLineMatch(const string16& text, 215 const LineTokens& line_tokens) const { 216 size_t line_tokens_size = line_tokens.size(); 217 if (line_tokens_size == 0) 218 return false; 219 220 LineTokens text_tokens; 221 Tokenize(text, kAddressSplitChars, &text_tokens); 222 size_t text_tokens_size = text_tokens.size(); 223 if (text_tokens_size == 0) 224 return false; 225 226 if (text_tokens_size > line_tokens_size) 227 return false; 228 229 // If each of the 'words' contained in the text are also present in the line, 230 // then we will consider the text to match the line. 231 LineTokens::iterator iter; 232 for (iter = text_tokens.begin(); iter != text_tokens.end(); ++iter) { 233 if (!IsWordInLine(*iter, line_tokens)) 234 return false; 235 } 236 237 return true; 238 } 239 240 bool Address::IsWordInLine(const string16& word, 241 const LineTokens& line_tokens) const { 242 LineTokens::const_iterator iter; 243 for (iter = line_tokens.begin(); iter != line_tokens.end(); ++iter) { 244 if (StringToLowerASCII(word) == *iter) 245 return true; 246 } 247 248 return false; 249 } 250