• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.h"
6 
7 #include "base/basictypes.h"
8 #include "base/string_util.h"
9 #include "chrome/browser/autofill/autofill_profile.h"
10 #include "chrome/browser/autofill/autofill_type.h"
11 #include "chrome/browser/autofill/field_types.h"
12 
13 namespace {
14 
15 const char16 kPhoneNumberSeparators[] = { ' ', '.', '(', ')', '-', 0 };
16 
17 // The number of digits in a phone number.
18 const size_t kPhoneNumberLength = 7;
19 
20 // The number of digits in an area code.
21 const size_t kPhoneCityCodeLength = 3;
22 
23 const AutofillType::FieldTypeSubGroup kAutofillPhoneTypes[] = {
24   AutofillType::PHONE_NUMBER,
25   AutofillType::PHONE_CITY_CODE,
26   AutofillType::PHONE_COUNTRY_CODE,
27   AutofillType::PHONE_CITY_AND_NUMBER,
28   AutofillType::PHONE_WHOLE_NUMBER,
29 };
30 
31 const int kAutofillPhoneLength = arraysize(kAutofillPhoneTypes);
32 
33 }  // namespace
34 
PhoneNumber()35 PhoneNumber::PhoneNumber() {}
36 
PhoneNumber(const PhoneNumber & number)37 PhoneNumber::PhoneNumber(const PhoneNumber& number) : FormGroup() {
38   *this = number;
39 }
40 
~PhoneNumber()41 PhoneNumber::~PhoneNumber() {}
42 
operator =(const PhoneNumber & number)43 PhoneNumber& PhoneNumber::operator=(const PhoneNumber& number) {
44   if (this == &number)
45     return *this;
46   country_code_ = number.country_code_;
47   city_code_ = number.city_code_;
48   number_ = number.number_;
49   extension_ = number.extension_;
50   return *this;
51 }
52 
GetPossibleFieldTypes(const string16 & text,FieldTypeSet * possible_types) const53 void PhoneNumber::GetPossibleFieldTypes(const string16& text,
54                                         FieldTypeSet* possible_types) const {
55   string16 stripped_text(text);
56   StripPunctuation(&stripped_text);
57   if (!Validate(stripped_text))
58     return;
59 
60   if (IsNumber(stripped_text))
61     possible_types->insert(GetNumberType());
62 
63   if (IsCityCode(stripped_text))
64     possible_types->insert(GetCityCodeType());
65 
66   if (IsCountryCode(stripped_text))
67     possible_types->insert(GetCountryCodeType());
68 
69   if (IsCityAndNumber(stripped_text))
70     possible_types->insert(GetCityAndNumberType());
71 
72   if (IsWholeNumber(stripped_text))
73     possible_types->insert(GetWholeNumberType());
74 }
75 
GetAvailableFieldTypes(FieldTypeSet * available_types) const76 void PhoneNumber::GetAvailableFieldTypes(FieldTypeSet* available_types) const {
77   DCHECK(available_types);
78 
79   if (!number().empty())
80     available_types->insert(GetNumberType());
81 
82   if (!city_code().empty())
83     available_types->insert(GetCityCodeType());
84 
85   if (!country_code().empty())
86     available_types->insert(GetCountryCodeType());
87 
88   if (!CityAndNumber().empty())
89     available_types->insert(GetCityAndNumberType());
90 
91   if (!WholeNumber().empty())
92     available_types->insert(GetWholeNumberType());
93 }
94 
GetInfo(AutofillFieldType type) const95 string16 PhoneNumber::GetInfo(AutofillFieldType type) const {
96   if (type == GetNumberType())
97     return number();
98 
99   if (type == GetCityCodeType())
100     return city_code();
101 
102   if (type == GetCountryCodeType())
103     return country_code();
104 
105   if (type == GetCityAndNumberType())
106     return CityAndNumber();
107 
108   if (type == GetWholeNumberType())
109     return WholeNumber();
110 
111   return string16();
112 }
113 
SetInfo(AutofillFieldType type,const string16 & value)114 void PhoneNumber::SetInfo(AutofillFieldType type, const string16& value) {
115   string16 number(value);
116   StripPunctuation(&number);
117   if (!Validate(number))
118     return;
119 
120   FieldTypeSubGroup subgroup = AutofillType(type).subgroup();
121   if (subgroup == AutofillType::PHONE_NUMBER)
122     set_number(number);
123   else if (subgroup == AutofillType::PHONE_CITY_CODE)
124     set_city_code(number);
125   else if (subgroup == AutofillType::PHONE_COUNTRY_CODE)
126     set_country_code(number);
127   else if (subgroup == AutofillType::PHONE_CITY_AND_NUMBER ||
128            subgroup == AutofillType::PHONE_WHOLE_NUMBER)
129     set_whole_number(number);
130   else
131     NOTREACHED();
132 }
133 
134 // Static.
ParsePhoneNumber(const string16 & value,string16 * number,string16 * city_code,string16 * country_code)135 bool PhoneNumber::ParsePhoneNumber(const string16& value,
136                                    string16* number,
137                                    string16* city_code,
138                                    string16* country_code) {
139   DCHECK(number);
140   DCHECK(city_code);
141   DCHECK(country_code);
142 
143   // Make a working copy of value.
144   string16 working = value;
145 
146   *number = string16();
147   *city_code = string16();
148   *country_code = string16();
149 
150   // First remove any punctuation.
151   StripPunctuation(&working);
152 
153   if (working.size() < kPhoneNumberLength)
154     return false;
155 
156   // Treat the last 7 digits as the number.
157   *number = working.substr(working.size() - kPhoneNumberLength,
158                            kPhoneNumberLength);
159   working.resize(working.size() - kPhoneNumberLength);
160   if (working.size() < kPhoneCityCodeLength)
161     return true;
162 
163   // Treat the next three digits as the city code.
164   *city_code = working.substr(working.size() - kPhoneCityCodeLength,
165                               kPhoneCityCodeLength);
166   working.resize(working.size() - kPhoneCityCodeLength);
167   if (working.empty())
168     return true;
169 
170   // Treat any remaining digits as the country code.
171   *country_code = working;
172   return true;
173 }
174 
WholeNumber() const175 string16 PhoneNumber::WholeNumber() const {
176   string16 whole_number;
177   if (!country_code_.empty())
178     whole_number.append(country_code_);
179 
180   if (!city_code_.empty())
181     whole_number.append(city_code_);
182 
183   if (!number_.empty())
184     whole_number.append(number_);
185 
186   return whole_number;
187 }
188 
set_number(const string16 & number)189 void PhoneNumber::set_number(const string16& number) {
190   string16 digits(number);
191   StripPunctuation(&digits);
192   number_ = digits;
193 }
194 
set_whole_number(const string16 & whole_number)195 void PhoneNumber::set_whole_number(const string16& whole_number) {
196   string16 number, city_code, country_code;
197   ParsePhoneNumber(whole_number, &number, &city_code, &country_code);
198   set_number(number);
199   set_city_code(city_code);
200   set_country_code(country_code);
201 }
202 
IsNumber(const string16 & text) const203 bool PhoneNumber::IsNumber(const string16& text) const {
204   // TODO(isherman): This will need to be updated once we add support for
205   // international phone numbers.
206   const size_t kPhoneNumberPrefixLength = 3;
207   const size_t kPhoneNumberSuffixLength = 4;
208   return
209       (text == number_) ||
210       (text.length() == kPhoneNumberPrefixLength &&
211        StartsWith(number_, text, true)) ||
212       (text.length() == kPhoneNumberSuffixLength &&
213        EndsWith(number_, text, true));
214 }
215 
IsCityCode(const string16 & text) const216 bool PhoneNumber::IsCityCode(const string16& text) const {
217   return text == city_code_;
218 }
219 
IsCountryCode(const string16 & text) const220 bool PhoneNumber::IsCountryCode(const string16& text) const {
221   return text == country_code_;
222 }
223 
IsCityAndNumber(const string16 & text) const224 bool PhoneNumber::IsCityAndNumber(const string16& text) const {
225   return text == CityAndNumber();
226 }
227 
IsWholeNumber(const string16 & text) const228 bool PhoneNumber::IsWholeNumber(const string16& text) const {
229   return text == WholeNumber();
230 }
231 
Validate(const string16 & number) const232 bool PhoneNumber::Validate(const string16& number) const {
233   for (size_t i = 0; i < number.length(); ++i) {
234     if (!IsAsciiDigit(number[i]))
235       return false;
236   }
237 
238   return true;
239 }
240 
241 // Static.
StripPunctuation(string16 * number)242 void PhoneNumber::StripPunctuation(string16* number) {
243   RemoveChars(*number, kPhoneNumberSeparators, number);
244 }
245