Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(99)

Side by Side Diff: chrome/browser/autofill/phone_number_i18n.cc

Issue 12434004: Move remaining Autofill code to //components/autofill. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix long lines Created 7 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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/phone_number_i18n.h"
6
7 #include "base/basictypes.h"
8 #include "base/logging.h"
9 #include "base/string_util.h"
10 #include "base/stringprintf.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/utf_string_conversions.h"
13 #include "chrome/browser/autofill/autofill_country.h"
14 #include "third_party/libphonenumber/src/phonenumber_api.h"
15
16 using i18n::phonenumbers::PhoneNumber;
17 using i18n::phonenumbers::PhoneNumberUtil;
18
19 namespace {
20
21 std::string SanitizeRegion(const std::string& region) {
22 if (region.length() == 2)
23 return region;
24
25 return AutofillCountry::CountryCodeForLocale(
26 AutofillCountry::ApplicationLocale());
27 }
28
29 // Returns true if |phone_number| is valid.
30 bool IsValidPhoneNumber(const PhoneNumber& phone_number) {
31 PhoneNumberUtil* phone_util = PhoneNumberUtil::GetInstance();
32 if (!phone_util->IsPossibleNumber(phone_number))
33 return false;
34
35 // Verify that the number has a valid area code (that in some cases could be
36 // empty) for the parsed country code. Also verify that this is a valid
37 // number (for example, in the US 1234567 is not valid, because numbers do not
38 // start with 1).
39 if (!phone_util->IsValidNumber(phone_number))
40 return false;
41
42 return true;
43 }
44
45 // Formats the given |number| as a human-readable string, and writes the result
46 // into |formatted_number|. Also, normalizes the formatted number, and writes
47 // that result into |normalized_number|. This function should only be called
48 // with numbers already known to be valid, i.e. validation should be done prior
49 // to calling this function. Note that the |country_code|, which determines
50 // whether to format in the national or in the international format, is passed
51 // in explicitly, as |number| might have an implicit country code set, even
52 // though the original input lacked a country code.
53 void FormatValidatedNumber(const PhoneNumber& number,
54 const string16& country_code,
55 string16* formatted_number,
56 string16* normalized_number) {
57 PhoneNumberUtil::PhoneNumberFormat format =
58 country_code.empty() ?
59 PhoneNumberUtil::NATIONAL :
60 PhoneNumberUtil::INTERNATIONAL;
61
62 PhoneNumberUtil* phone_util = PhoneNumberUtil::GetInstance();
63 std::string processed_number;
64 phone_util->Format(number, format, &processed_number);
65
66 if (formatted_number)
67 *formatted_number = UTF8ToUTF16(processed_number);
68
69 if (normalized_number) {
70 phone_util->NormalizeDigitsOnly(&processed_number);
71 *normalized_number = UTF8ToUTF16(processed_number);
72 }
73 }
74
75 } // namespace
76
77 namespace autofill_i18n {
78
79 // Parses the number stored in |value| as it should be interpreted in the given
80 // |region|, and stores the results into the remaining arguments. The |region|
81 // should be sanitized prior to calling this function.
82 bool ParsePhoneNumber(const string16& value,
83 const std::string& region,
84 string16* country_code,
85 string16* city_code,
86 string16* number,
87 PhoneNumber* i18n_number) {
88 country_code->clear();
89 city_code->clear();
90 number->clear();
91 *i18n_number = PhoneNumber();
92
93 std::string number_text(UTF16ToUTF8(value));
94
95 // Parse phone number based on the region.
96 PhoneNumberUtil* phone_util = PhoneNumberUtil::GetInstance();
97
98 // The |region| should already be sanitized.
99 DCHECK_EQ(2U, region.size());
100 if (phone_util->Parse(number_text, region.c_str(), i18n_number) !=
101 PhoneNumberUtil::NO_PARSING_ERROR) {
102 return false;
103 }
104
105 if (!IsValidPhoneNumber(*i18n_number))
106 return false;
107
108 std::string national_significant_number;
109 phone_util->GetNationalSignificantNumber(*i18n_number,
110 &national_significant_number);
111
112 int area_length = phone_util->GetLengthOfGeographicalAreaCode(*i18n_number);
113 int destination_length =
114 phone_util->GetLengthOfNationalDestinationCode(*i18n_number);
115 // Some phones have a destination code in lieu of area code: mobile operators
116 // in Europe, toll and toll-free numbers in USA, etc. From our point of view
117 // these two types of codes are the same.
118 if (destination_length > area_length)
119 area_length = destination_length;
120
121 std::string area_code;
122 std::string subscriber_number;
123 if (area_length > 0) {
124 area_code = national_significant_number.substr(0, area_length);
125 subscriber_number = national_significant_number.substr(area_length);
126 } else {
127 subscriber_number = national_significant_number;
128 }
129 *number = UTF8ToUTF16(subscriber_number);
130 *city_code = UTF8ToUTF16(area_code);
131 *country_code = string16();
132
133 phone_util->NormalizeDigitsOnly(&number_text);
134 string16 normalized_number(UTF8ToUTF16(number_text));
135
136 // Check if parsed number has a country code that was not inferred from the
137 // region.
138 if (i18n_number->has_country_code()) {
139 *country_code = UTF8ToUTF16(
140 base::StringPrintf("%d", i18n_number->country_code()));
141 if (normalized_number.length() <= national_significant_number.length() &&
142 !StartsWith(normalized_number, *country_code,
143 true /* case_sensitive */)) {
144 country_code->clear();
145 }
146 }
147
148 return true;
149 }
150
151 string16 NormalizePhoneNumber(const string16& value,
152 std::string const& region) {
153 string16 country_code;
154 string16 unused_city_code;
155 string16 unused_number;
156 PhoneNumber phone_number;
157 if (!ParsePhoneNumber(value, SanitizeRegion(region), &country_code,
158 &unused_city_code, &unused_number, &phone_number)) {
159 return string16(); // Parsing failed - do not store phone.
160 }
161
162 string16 normalized_number;
163 FormatValidatedNumber(phone_number, country_code, NULL, &normalized_number);
164 return normalized_number;
165 }
166
167 bool ConstructPhoneNumber(const string16& country_code,
168 const string16& city_code,
169 const string16& number,
170 const std::string& region,
171 string16* whole_number) {
172 whole_number->clear();
173
174 string16 unused_country_code;
175 string16 unused_city_code;
176 string16 unused_number;
177 PhoneNumber phone_number;
178 if (!ParsePhoneNumber(country_code + city_code + number,
179 SanitizeRegion(region),
180 &unused_country_code, &unused_city_code, &unused_number,
181 &phone_number)) {
182 return false;
183 }
184
185 FormatValidatedNumber(phone_number, country_code, whole_number, NULL);
186 return true;
187 }
188
189 bool PhoneNumbersMatch(const string16& number_a,
190 const string16& number_b,
191 const std::string& raw_region) {
192 // Sanitize the provided |raw_region| before trying to use it for parsing.
193 const std::string region = SanitizeRegion(raw_region);
194
195 PhoneNumberUtil* phone_util = PhoneNumberUtil::GetInstance();
196
197 // Parse phone numbers based on the region
198 PhoneNumber i18n_number1;
199 if (phone_util->Parse(UTF16ToUTF8(number_a), region.c_str(), &i18n_number1) !=
200 PhoneNumberUtil::NO_PARSING_ERROR) {
201 return false;
202 }
203
204 PhoneNumber i18n_number2;
205 if (phone_util->Parse(UTF16ToUTF8(number_b), region.c_str(), &i18n_number2) !=
206 PhoneNumberUtil::NO_PARSING_ERROR) {
207 return false;
208 }
209
210 switch (phone_util->IsNumberMatch(i18n_number1, i18n_number2)) {
211 case PhoneNumberUtil::INVALID_NUMBER:
212 case PhoneNumberUtil::NO_MATCH:
213 return false;
214 case PhoneNumberUtil::SHORT_NSN_MATCH:
215 return false;
216 case PhoneNumberUtil::NSN_MATCH:
217 case PhoneNumberUtil::EXACT_MATCH:
218 return true;
219 }
220
221 NOTREACHED();
222 return false;
223 }
224
225 PhoneObject::PhoneObject(const string16& number, const std::string& region)
226 : region_(SanitizeRegion(region)),
227 i18n_number_(NULL) {
228 // TODO(isherman): Autofill profiles should always have a |region| set, but in
229 // some cases it should be marked as implicit. Otherwise, phone numbers
230 // might behave differently when they are synced across computers:
231 // [ http://crbug.com/100845 ]. Once the bug is fixed, add a DCHECK here to
232 // verify.
233
234 scoped_ptr<PhoneNumber> i18n_number(new PhoneNumber);
235 if (ParsePhoneNumber(number, region_, &country_code_, &city_code_, &number_,
236 i18n_number.get())) {
237 // The phone number was successfully parsed, so store the parsed version.
238 // The formatted and normalized versions will be set on the first call to
239 // the coresponding methods.
240 i18n_number_.reset(i18n_number.release());
241 } else {
242 // Parsing failed. Store passed phone "as is" into |whole_number_|.
243 whole_number_ = number;
244 }
245 }
246
247 PhoneObject::PhoneObject(const PhoneObject& other) : i18n_number_(NULL) {
248 *this = other;
249 }
250
251 PhoneObject::PhoneObject() : i18n_number_(NULL) {
252 }
253
254 PhoneObject::~PhoneObject() {
255 }
256
257 string16 PhoneObject::GetFormattedNumber() const {
258 if (i18n_number_ && formatted_number_.empty()) {
259 FormatValidatedNumber(*i18n_number_, country_code_, &formatted_number_,
260 &whole_number_);
261 }
262
263 return formatted_number_;
264 }
265
266 string16 PhoneObject::GetWholeNumber() const {
267 if (i18n_number_ && whole_number_.empty()) {
268 FormatValidatedNumber(*i18n_number_, country_code_, &formatted_number_,
269 &whole_number_);
270 }
271
272 return whole_number_;
273 }
274
275 PhoneObject& PhoneObject::operator=(const PhoneObject& other) {
276 if (this == &other)
277 return *this;
278
279 region_ = other.region_;
280
281 if (other.i18n_number_.get())
282 i18n_number_.reset(new PhoneNumber(*other.i18n_number_));
283 else
284 i18n_number_.reset();
285
286 country_code_ = other.country_code_;
287 city_code_ = other.city_code_;
288 number_ = other.number_;
289
290 formatted_number_ = other.formatted_number_;
291 whole_number_ = other.whole_number_;
292
293 return *this;
294 }
295
296 } // namespace autofill_i18n
OLDNEW
« no previous file with comments | « chrome/browser/autofill/phone_number_i18n.h ('k') | chrome/browser/autofill/phone_number_i18n_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698