| // Copyright 2013 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 "components/autofill/core/browser/autofill_data_model.h" |
| |
| #include "base/basictypes.h" |
| #include "base/logging.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/strings/string_util.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "components/autofill/core/browser/autofill_country.h" |
| #include "components/autofill/core/browser/autofill_field.h" |
| #include "components/autofill/core/browser/autofill_type.h" |
| #include "components/autofill/core/browser/state_names.h" |
| #include "components/autofill/core/browser/validation.h" |
| #include "components/autofill/core/common/form_field_data.h" |
| #include "grit/component_strings.h" |
| #include "ui/base/l10n/l10n_util.h" |
| #include "url/gurl.h" |
| |
| namespace autofill { |
| namespace { |
| |
| const char* const kMonthsAbbreviated[] = { |
| NULL, // Padding so index 1 = month 1 = January. |
| "Jan", "Feb", "Mar", "Apr", "May", "Jun", |
| "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", |
| }; |
| |
| const char* const kMonthsFull[] = { |
| NULL, // Padding so index 1 = month 1 = January. |
| "January", "February", "March", "April", "May", "June", |
| "July", "August", "September", "October", "November", "December", |
| }; |
| |
| const char* const kMonthsNumeric[] = { |
| NULL, // Padding so index 1 = month 1 = January. |
| "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", |
| }; |
| |
| // Returns true if the value was successfully set, meaning |value| was found in |
| // the list of select options in |field|. |
| bool SetSelectControlValue(const base::string16& value, |
| FormFieldData* field) { |
| base::string16 value_lowercase = StringToLowerASCII(value); |
| |
| DCHECK_EQ(field->option_values.size(), field->option_contents.size()); |
| for (size_t i = 0; i < field->option_values.size(); ++i) { |
| if (value_lowercase == StringToLowerASCII(field->option_values[i]) || |
| value_lowercase == StringToLowerASCII(field->option_contents[i])) { |
| field->value = field->option_values[i]; |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| bool FillStateSelectControl(const base::string16& value, |
| FormFieldData* field) { |
| base::string16 full, abbreviation; |
| state_names::GetNameAndAbbreviation(value, &full, &abbreviation); |
| |
| // Try the abbreviation first. |
| if (!abbreviation.empty() && SetSelectControlValue(abbreviation, field)) |
| return true; |
| |
| return !full.empty() && SetSelectControlValue(full, field); |
| } |
| |
| bool FillExpirationMonthSelectControl(const base::string16& value, |
| FormFieldData* field) { |
| int index = 0; |
| if (!base::StringToInt(value, &index) || |
| index <= 0 || |
| static_cast<size_t>(index) >= arraysize(kMonthsFull)) |
| return false; |
| |
| bool filled = |
| SetSelectControlValue(ASCIIToUTF16(kMonthsAbbreviated[index]), field) || |
| SetSelectControlValue(ASCIIToUTF16(kMonthsFull[index]), field) || |
| SetSelectControlValue(ASCIIToUTF16(kMonthsNumeric[index]), field); |
| return filled; |
| } |
| |
| // Try to fill a credit card type |value| (Visa, MasterCard, etc.) into the |
| // given |field|. |
| bool FillCreditCardTypeSelectControl(const base::string16& value, |
| FormFieldData* field) { |
| // Try stripping off spaces. |
| base::string16 value_stripped; |
| RemoveChars(StringToLowerASCII(value), kWhitespaceUTF16, &value_stripped); |
| |
| for (size_t i = 0; i < field->option_values.size(); ++i) { |
| base::string16 option_value_lowercase; |
| RemoveChars(StringToLowerASCII(field->option_values[i]), kWhitespaceUTF16, |
| &option_value_lowercase); |
| base::string16 option_contents_lowercase; |
| RemoveChars(StringToLowerASCII(field->option_contents[i]), kWhitespaceUTF16, |
| &option_contents_lowercase); |
| |
| // Perform a case-insensitive comparison; but fill the form with the |
| // original text, not the lowercased version. |
| if (value_stripped == option_value_lowercase || |
| value_stripped == option_contents_lowercase) { |
| field->value = field->option_values[i]; |
| return true; |
| } |
| } |
| |
| // For American Express, also try filling as "AmEx". |
| if (value == l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_AMEX)) |
| return FillCreditCardTypeSelectControl(ASCIIToUTF16("AmEx"), field); |
| |
| return false; |
| } |
| |
| } // namespace |
| |
| AutofillDataModel::AutofillDataModel(const std::string& guid, |
| const std::string& origin) |
| : guid_(guid), |
| origin_(origin) {} |
| AutofillDataModel::~AutofillDataModel() {} |
| |
| void AutofillDataModel::FillSelectControl(const AutofillType& type, |
| const std::string& app_locale, |
| FormFieldData* field) const { |
| DCHECK(field); |
| DCHECK_EQ("select-one", field->form_control_type); |
| DCHECK_EQ(field->option_values.size(), field->option_contents.size()); |
| |
| base::string16 field_text = GetInfo(type, app_locale); |
| base::string16 field_text_lower = StringToLowerASCII(field_text); |
| if (field_text.empty()) |
| return; |
| |
| base::string16 value; |
| for (size_t i = 0; i < field->option_values.size(); ++i) { |
| if (field_text == field->option_values[i] || |
| field_text == field->option_contents[i]) { |
| // An exact match, use it. |
| value = field->option_values[i]; |
| break; |
| } |
| |
| if (field_text_lower == StringToLowerASCII(field->option_values[i]) || |
| field_text_lower == StringToLowerASCII(field->option_contents[i])) { |
| // A match, but not in the same case. Save it in case an exact match is |
| // not found. |
| value = field->option_values[i]; |
| } |
| } |
| |
| if (!value.empty()) { |
| field->value = value; |
| return; |
| } |
| |
| ServerFieldType storable_type = type.GetStorableType(); |
| if (storable_type == ADDRESS_HOME_STATE) { |
| FillStateSelectControl(field_text, field); |
| } else if (storable_type == ADDRESS_HOME_COUNTRY) { |
| FillCountrySelectControl(app_locale, field); |
| } else if (storable_type == CREDIT_CARD_EXP_MONTH) { |
| FillExpirationMonthSelectControl(field_text, field); |
| } else if (storable_type == CREDIT_CARD_EXP_4_DIGIT_YEAR) { |
| // Attempt to fill the year as a 2-digit year. This compensates for the |
| // fact that our heuristics do not always correctly detect when a website |
| // requests a 2-digit rather than a 4-digit year. |
| FillSelectControl(AutofillType(CREDIT_CARD_EXP_2_DIGIT_YEAR), app_locale, |
| field); |
| } else if (storable_type == CREDIT_CARD_TYPE) { |
| FillCreditCardTypeSelectControl(field_text, field); |
| } |
| } |
| |
| bool AutofillDataModel::FillCountrySelectControl( |
| const std::string& app_locale, |
| FormFieldData* field_data) const { |
| return false; |
| } |
| |
| bool AutofillDataModel::IsVerified() const { |
| return !origin_.empty() && !GURL(origin_).is_valid(); |
| } |
| |
| } // namespace autofill |