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
Address()33 Address::Address() {}
34
Address(const Address & address)35 Address::Address(const Address& address) : FormGroup() {
36 *this = address;
37 }
38
~Address()39 Address::~Address() {}
40
operator =(const Address & address)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
GetPossibleFieldTypes(const string16 & text,FieldTypeSet * possible_types) const56 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
GetAvailableFieldTypes(FieldTypeSet * available_types) const84 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
GetInfo(AutofillFieldType type) const106 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
SetInfo(AutofillFieldType type,const string16 & value)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
Clear()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
Country() const157 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
set_line1(const string16 & line1)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
set_line2(const string16 & line2)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
SetCountry(const string16 & country)183 void Address::SetCountry(const string16& country) {
184 std::string app_locale = AutofillCountry::ApplicationLocale();
185 country_code_ = AutofillCountry::GetCountryCode(country, app_locale);
186 }
187
IsLine1(const string16 & text) const188 bool Address::IsLine1(const string16& text) const {
189 return IsLineMatch(text, line1_tokens_);
190 }
191
IsLine2(const string16 & text) const192 bool Address::IsLine2(const string16& text) const {
193 return IsLineMatch(text, line2_tokens_);
194 }
195
IsCity(const string16 & text) const196 bool Address::IsCity(const string16& text) const {
197 return (StringToLowerASCII(city_) == StringToLowerASCII(text));
198 }
199
IsState(const string16 & text) const200 bool Address::IsState(const string16& text) const {
201 return (StringToLowerASCII(state_) == StringToLowerASCII(text));
202 }
203
IsCountry(const string16 & text) const204 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
IsZipCode(const string16 & text) const210 bool Address::IsZipCode(const string16& text) const {
211 return zip_code_ == text;
212 }
213
IsLineMatch(const string16 & text,const LineTokens & line_tokens) const214 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
IsWordInLine(const string16 & word,const LineTokens & line_tokens) const240 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