| // 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/address.h" |
| |
| #include "base/basictypes.h" |
| #include "base/string_util.h" |
| #include "chrome/browser/autofill/autofill_type.h" |
| #include "chrome/browser/autofill/field_types.h" |
| |
| namespace { |
| |
| const char16 kAddressSplitChars[] = {'-', ',', '#', '.', ' ', 0}; |
| |
| const AutoFillType::FieldTypeSubGroup kAutoFillAddressTypes[] = { |
| AutoFillType::ADDRESS_LINE1, |
| AutoFillType::ADDRESS_LINE2, |
| AutoFillType::ADDRESS_APT_NUM, |
| AutoFillType::ADDRESS_CITY, |
| AutoFillType::ADDRESS_STATE, |
| AutoFillType::ADDRESS_ZIP, |
| AutoFillType::ADDRESS_COUNTRY, |
| }; |
| |
| const int kAutoFillAddressLength = arraysize(kAutoFillAddressTypes); |
| |
| } // namespace |
| |
| Address::Address() {} |
| |
| Address::~Address() {} |
| |
| void Address::GetPossibleFieldTypes(const string16& text, |
| FieldTypeSet* possible_types) const { |
| DCHECK(possible_types); |
| |
| // If the text to match against the field types is empty, then no results will |
| // match. |
| if (text.empty()) |
| return; |
| |
| if (IsLine1(text)) |
| possible_types->insert(GetLine1Type()); |
| |
| if (IsLine2(text)) |
| possible_types->insert(GetLine2Type()); |
| |
| if (IsAptNum(text)) |
| possible_types->insert(GetAptNumType()); |
| |
| if (IsCity(text)) |
| possible_types->insert(GetCityType()); |
| |
| if (IsState(text)) |
| possible_types->insert(GetStateType()); |
| |
| if (IsZipCode(text)) |
| possible_types->insert(GetZipCodeType()); |
| |
| if (IsCountry(text)) |
| possible_types->insert(GetCountryType()); |
| } |
| |
| void Address::GetAvailableFieldTypes(FieldTypeSet* available_types) const { |
| DCHECK(available_types); |
| |
| if (!line1().empty()) |
| available_types->insert(GetLine1Type()); |
| |
| if (!line2().empty()) |
| available_types->insert(GetLine2Type()); |
| |
| if (!apt_num().empty()) |
| available_types->insert(GetAptNumType()); |
| |
| if (!city().empty()) |
| available_types->insert(GetCityType()); |
| |
| if (!state().empty()) |
| available_types->insert(GetStateType()); |
| |
| if (!zip_code().empty()) |
| available_types->insert(GetZipCodeType()); |
| |
| if (!country().empty()) |
| available_types->insert(GetCountryType()); |
| } |
| |
| void Address::FindInfoMatches(const AutoFillType& type, |
| const string16& info, |
| std::vector<string16>* matched_text) const { |
| DCHECK(matched_text); |
| |
| string16 match; |
| if (type.field_type() == UNKNOWN_TYPE) { |
| for (int i = 0; i < kAutoFillAddressLength; ++i) { |
| if (FindInfoMatchesHelper(kAutoFillAddressTypes[i], info, &match)) |
| matched_text->push_back(match); |
| } |
| } else { |
| if (FindInfoMatchesHelper(type.subgroup(), info, &match)) |
| matched_text->push_back(match); |
| } |
| } |
| |
| string16 Address::GetFieldText(const AutoFillType& type) const { |
| AutoFillFieldType field_type = type.field_type(); |
| if (field_type == GetLine1Type()) |
| return line1(); |
| |
| if (field_type == GetLine2Type()) |
| return line2(); |
| |
| if (field_type == GetAptNumType()) |
| return apt_num(); |
| |
| if (field_type == GetCityType()) |
| return city(); |
| |
| if (field_type == GetStateType()) |
| return state(); |
| |
| if (field_type == GetZipCodeType()) |
| return zip_code(); |
| |
| if (field_type == GetCountryType()) |
| return country(); |
| |
| return string16(); |
| } |
| |
| void Address::SetInfo(const AutoFillType& type, const string16& value) { |
| FieldTypeSubGroup subgroup = type.subgroup(); |
| if (subgroup == AutoFillType::ADDRESS_LINE1) |
| set_line1(value); |
| else if (subgroup == AutoFillType::ADDRESS_LINE2) |
| set_line2(value); |
| else if (subgroup == AutoFillType::ADDRESS_APT_NUM) |
| set_apt_num(value); |
| else if (subgroup == AutoFillType::ADDRESS_CITY) |
| set_city(value); |
| else if (subgroup == AutoFillType::ADDRESS_STATE) |
| set_state(value); |
| else if (subgroup == AutoFillType::ADDRESS_COUNTRY) |
| set_country(value); |
| else if (subgroup == AutoFillType::ADDRESS_ZIP) |
| set_zip_code(value); |
| else |
| NOTREACHED(); |
| } |
| |
| void Address::Clear() { |
| line1_tokens_.clear(); |
| line1_.clear(); |
| line2_tokens_.clear(); |
| line2_.clear(); |
| apt_num_.clear(); |
| city_.clear(); |
| state_.clear(); |
| country_.clear(); |
| zip_code_.clear(); |
| } |
| |
| void Address::Clone(const Address& address) { |
| set_line1(address.line1()); |
| set_line2(address.line2()); |
| set_apt_num(address.apt_num()); |
| set_city(address.city()); |
| set_state(address.state()); |
| set_country(address.country()); |
| set_zip_code(address.zip_code()); |
| } |
| |
| Address::Address(const Address& address) |
| : FormGroup(), |
| line1_tokens_(address.line1_tokens_), |
| line2_tokens_(address.line2_tokens_), |
| line1_(address.line1_), |
| line2_(address.line2_), |
| apt_num_(address.apt_num_), |
| city_(address.city_), |
| state_(address.state_), |
| country_(address.country_), |
| zip_code_(address.zip_code_) { |
| } |
| |
| void Address::set_line1(const string16& line1) { |
| line1_ = line1; |
| line1_tokens_.clear(); |
| Tokenize(line1, kAddressSplitChars, &line1_tokens_); |
| LineTokens::iterator iter; |
| for (iter = line1_tokens_.begin(); iter != line1_tokens_.end(); ++iter) |
| *iter = StringToLowerASCII(*iter); |
| } |
| |
| void Address::set_line2(const string16& line2) { |
| line2_ = line2; |
| line2_tokens_.clear(); |
| Tokenize(line2, kAddressSplitChars, &line2_tokens_); |
| LineTokens::iterator iter; |
| for (iter = line2_tokens_.begin(); iter != line2_tokens_.end(); ++iter) |
| *iter = StringToLowerASCII(*iter); |
| } |
| |
| bool Address::IsLine1(const string16& text) const { |
| return IsLineMatch(text, line1_tokens_); |
| } |
| |
| bool Address::IsLine2(const string16& text) const { |
| return IsLineMatch(text, line2_tokens_); |
| } |
| |
| bool Address::IsAptNum(const string16& text) const { |
| return (StringToLowerASCII(apt_num_) == StringToLowerASCII(text)); |
| } |
| |
| bool Address::IsCity(const string16& text) const { |
| return (StringToLowerASCII(city_) == StringToLowerASCII(text)); |
| } |
| |
| bool Address::IsState(const string16& text) const { |
| return (StringToLowerASCII(state_) == StringToLowerASCII(text)); |
| } |
| |
| bool Address::IsCountry(const string16& text) const { |
| return (StringToLowerASCII(country_) == StringToLowerASCII(text)); |
| } |
| |
| bool Address::IsZipCode(const string16& text) const { |
| return zip_code_ == text; |
| } |
| |
| bool Address::FindInfoMatchesHelper(const FieldTypeSubGroup& subgroup, |
| const string16& info, |
| string16* match) const { |
| DCHECK(match); |
| |
| match->clear(); |
| if (subgroup == AutoFillType::ADDRESS_LINE1 && |
| StartsWith(line1(), info, false)) { |
| *match = line1(); |
| } else if (subgroup == AutoFillType::ADDRESS_LINE2 && |
| StartsWith(line2(), info, false)) { |
| *match = line2(); |
| } else if (subgroup == AutoFillType::ADDRESS_APT_NUM && |
| StartsWith(apt_num(), info, false)) { |
| *match = apt_num(); |
| } else if (subgroup == AutoFillType::ADDRESS_CITY && |
| StartsWith(city(), info, false)) { |
| *match = city(); |
| } else if (subgroup == AutoFillType::ADDRESS_STATE && |
| StartsWith(state(), info, false)) { |
| *match = state(); |
| } else if (subgroup == AutoFillType::ADDRESS_COUNTRY && |
| StartsWith(country(), info, false)) { |
| *match = country(); |
| } else if (subgroup == AutoFillType::ADDRESS_ZIP && |
| StartsWith(zip_code(), info, true)) { |
| *match = zip_code(); |
| } |
| |
| return !match->empty(); |
| } |
| |
| bool Address::IsLineMatch(const string16& text, |
| const LineTokens& line_tokens) const { |
| size_t line_tokens_size = line_tokens.size(); |
| if (line_tokens_size == 0) |
| return false; |
| |
| LineTokens text_tokens; |
| Tokenize(text, kAddressSplitChars, &text_tokens); |
| size_t text_tokens_size = text_tokens.size(); |
| if (text_tokens_size == 0) |
| return false; |
| |
| if (text_tokens_size > line_tokens_size) |
| return false; |
| |
| // If each of the 'words' contained in the text are also present in the line, |
| // then we will consider the text to match the line. |
| LineTokens::iterator iter; |
| for (iter = text_tokens.begin(); iter != text_tokens.end(); ++iter) { |
| if (!IsWordInLine(*iter, line_tokens)) |
| return false; |
| } |
| |
| return true; |
| } |
| |
| bool Address::IsWordInLine(const string16& word, |
| const LineTokens& line_tokens) const { |
| LineTokens::const_iterator iter; |
| for (iter = line_tokens.begin(); iter != line_tokens.end(); ++iter) { |
| if (StringToLowerASCII(word) == *iter) |
| return true; |
| } |
| |
| return false; |
| } |