// Copyright (c) 2010 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/phone_number.h" #include "base/basictypes.h" #include "base/string_util.h" #include "chrome/browser/autofill/autofill_type.h" #include "chrome/browser/autofill/field_types.h" static const string16 kPhoneNumberSeparators = ASCIIToUTF16(" .()-"); static const AutoFillType::FieldTypeSubGroup kAutoFillPhoneTypes[] = { AutoFillType::PHONE_NUMBER, AutoFillType::PHONE_CITY_CODE, AutoFillType::PHONE_COUNTRY_CODE, AutoFillType::PHONE_CITY_AND_NUMBER, AutoFillType::PHONE_WHOLE_NUMBER, }; static const int kAutoFillPhoneLength = arraysize(kAutoFillPhoneTypes); void PhoneNumber::GetPossibleFieldTypes(const string16& text, FieldTypeSet* possible_types) const { string16 stripped_text(text); StripPunctuation(&stripped_text); if (!Validate(stripped_text)) return; if (IsNumber(stripped_text)) possible_types->insert(GetNumberType()); if (IsCityCode(stripped_text)) possible_types->insert(GetCityCodeType()); if (IsCountryCode(stripped_text)) possible_types->insert(GetCountryCodeType()); if (IsCityAndNumber(stripped_text)) possible_types->insert(GetCityAndNumberType()); if (IsWholeNumber(stripped_text)) possible_types->insert(GetWholeNumberType()); } string16 PhoneNumber::GetFieldText(const AutoFillType& type) const { AutoFillFieldType field_type = type.field_type(); if (field_type == GetNumberType()) return number(); if (field_type == GetCityCodeType()) return city_code(); if (field_type == GetCountryCodeType()) return country_code(); if (field_type == GetCityAndNumberType()) return CityAndNumber(); if (field_type == GetWholeNumberType()) return WholeNumber(); return EmptyString16(); } void PhoneNumber::FindInfoMatches(const AutoFillType& type, const string16& info, std::vector* matched_text) const { if (matched_text == NULL) { DLOG(ERROR) << "NULL matched vector passed in"; return; } string16 number(info); StripPunctuation(&number); if (!Validate(number)) return; string16 match; if (type.field_type() == UNKNOWN_TYPE) { for (int i = 0; i < kAutoFillPhoneLength; ++i) { if (FindInfoMatchesHelper(kAutoFillPhoneTypes[i], info, &match)) matched_text->push_back(match); } } else { if (FindInfoMatchesHelper(type.subgroup(), info, &match)) matched_text->push_back(match); } } void PhoneNumber::SetInfo(const AutoFillType& type, const string16& value) { string16 number(value); StripPunctuation(&number); if (!Validate(number)) return; FieldTypeSubGroup subgroup = type.subgroup(); if (subgroup == AutoFillType::PHONE_NUMBER) set_number(number); else if (subgroup == AutoFillType::PHONE_CITY_CODE) set_city_code(number); else if (subgroup == AutoFillType::PHONE_COUNTRY_CODE) set_country_code(number); else NOTREACHED(); // TODO(jhawkins): Add extension support. // else if (subgroup == AutoFillType::PHONE_EXTENSION) // set_extension(number); } string16 PhoneNumber::WholeNumber() const { string16 whole_number; if (!country_code_.empty()) whole_number.append(country_code_); if (!city_code_.empty()) whole_number.append(city_code_); if (!number_.empty()) whole_number.append(number_); return whole_number; } void PhoneNumber::set_number(const string16& number) { string16 digits(number); StripPunctuation(&digits); number_ = digits; } PhoneNumber::PhoneNumber(const PhoneNumber& phone_number) : FormGroup(), country_code_(phone_number.country_code_), city_code_(phone_number.city_code_), number_(phone_number.number_), extension_(phone_number.extension_) { } bool PhoneNumber::FindInfoMatchesHelper(const FieldTypeSubGroup& subgroup, const string16& info, string16* match) const { if (match == NULL) { DLOG(ERROR) << "NULL match string passed in"; return false; } match->clear(); if (subgroup == AutoFillType::PHONE_NUMBER && StartsWith(number(), info, true)) { *match = number(); } else if (subgroup == AutoFillType::PHONE_CITY_CODE && StartsWith(city_code(), info, true)) { *match = city_code(); } else if (subgroup == AutoFillType::PHONE_COUNTRY_CODE && StartsWith(country_code(), info, true)) { *match = country_code(); } else if (subgroup == AutoFillType::PHONE_CITY_AND_NUMBER && StartsWith(CityAndNumber(), info, true)) { *match = CityAndNumber(); } else if (subgroup == AutoFillType::PHONE_WHOLE_NUMBER && StartsWith(WholeNumber(), info, true)) { *match = WholeNumber(); } return !match->empty(); } bool PhoneNumber::IsNumber(const string16& text) const { if (text.length() <= number_.length()) return false; return StartsWith(number_, text, false); } bool PhoneNumber::IsCityCode(const string16& text) const { if (text.length() <= city_code_.length()) return false; return StartsWith(city_code_, text, false); } bool PhoneNumber::IsCountryCode(const string16& text) const { if (text.length() <= country_code_.length()) return false; return StartsWith(country_code_, text, false); } bool PhoneNumber::IsCityAndNumber(const string16& text) const { string16 city_and_number(CityAndNumber()); if (text.length() > city_and_number.length()) return false; return StartsWith(city_and_number, text, false); } bool PhoneNumber::IsWholeNumber(const string16& text) const { string16 whole_number(WholeNumber()); if (text.length() > whole_number.length()) return false; return StartsWith(whole_number, text, false); } bool PhoneNumber::Validate(const string16& number) const { for (size_t i = 0; i < number.length(); ++i) { if (!IsAsciiDigit(number[i])) return false; } return true; } void PhoneNumber::StripPunctuation(string16* number) const { RemoveChars(*number, kPhoneNumberSeparators.c_str(), number); }