blob: cb47cf53d8c61a932d967116c5bab4a5ed3ddc6b [file] [log] [blame]
// Copyright 2020 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_assistant/browser/field_formatter.h"
#include "base/i18n/case_conversion.h"
#include "base/logging.h"
#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/browser/autofill_data_util.h"
#include "components/autofill/core/browser/autofill_type.h"
#include "components/autofill/core/browser/field_types.h"
#include "components/autofill/core/browser/geo/state_names.h"
#include "components/autofill_assistant/browser/generic_ui.pb.h"
#include "third_party/re2/src/re2/re2.h"
#include "third_party/re2/src/re2/stringpiece.h"
namespace {
// Regex to find placeholders of the form ${key}, where key is an arbitrary
// string that does not contain curly braces. The first capture group is for
// the prefix before the key, the second for the key itself.
const char kPlaceholderExtractor[] = R"re(([^$]*)\$\{([^{}]+)\})re";
base::Optional<std::string> GetFieldValue(
const std::map<std::string, std::string>& mappings,
const std::string& key) {
auto it = mappings.find(key);
if (it == mappings.end()) {
return base::nullopt;
}
return it->second;
}
std::map<std::string, std::string> CreateFormGroupMappings(
const autofill::FormGroup& form_group,
const std::string& locale) {
std::map<std::string, std::string> mappings;
autofill::ServerFieldTypeSet available_fields;
form_group.GetNonEmptyTypes(locale, &available_fields);
for (const auto& field : available_fields) {
mappings.emplace(base::NumberToString(static_cast<int>(field)),
base::UTF16ToUTF8(form_group.GetInfo(
autofill::AutofillType(field), locale)));
}
return mappings;
}
} // namespace
namespace autofill_assistant {
namespace field_formatter {
base::Optional<std::string> FormatString(
const std::string& pattern,
const std::map<std::string, std::string>& mappings,
bool strict) {
if (pattern.empty()) {
return std::string();
}
std::string out;
re2::StringPiece input(pattern);
std::string prefix;
std::string key;
while (
re2::RE2::FindAndConsume(&input, kPlaceholderExtractor, &prefix, &key)) {
auto rewrite_value = GetFieldValue(mappings, key);
if (!rewrite_value.has_value()) {
if (strict) {
VLOG(2) << "No value for " << key << " in " << pattern;
return base::nullopt;
}
// Leave placeholder unchanged.
rewrite_value = "${" + key + "}";
}
out = out + prefix + *rewrite_value;
}
// Append remaining unmatched suffix (if any).
out = out + input.ToString();
return out;
}
template <>
std::map<std::string, std::string>
CreateAutofillMappings<autofill::AutofillProfile>(
const autofill::AutofillProfile& profile,
const std::string& locale) {
auto mappings = CreateFormGroupMappings(profile, locale);
auto state = profile.GetInfo(
autofill::AutofillType(autofill::ADDRESS_HOME_STATE), locale);
if (!state.empty()) {
std::u16string full_name;
std::u16string abbreviation;
autofill::state_names::GetNameAndAbbreviation(state, &full_name,
&abbreviation);
mappings[base::NumberToString(
static_cast<int>(AutofillFormatProto::ADDRESS_HOME_STATE_NAME))] =
base::UTF16ToUTF8(
full_name.length() > 1
? base::StrCat({base::i18n::ToUpper(full_name.substr(0, 1)),
full_name.substr(1)})
: base::i18n::ToUpper(full_name));
if (abbreviation.empty()) {
mappings.erase(
base::NumberToString(static_cast<int>(autofill::ADDRESS_HOME_STATE)));
} else {
mappings[base::NumberToString(
static_cast<int>(autofill::ADDRESS_HOME_STATE))] =
base::UTF16ToUTF8(base::i18n::ToUpper(abbreviation));
}
}
return mappings;
}
template <>
std::map<std::string, std::string> CreateAutofillMappings<autofill::CreditCard>(
const autofill::CreditCard& credit_card,
const std::string& locale) {
auto mappings = CreateFormGroupMappings(credit_card, locale);
auto network = std::string(
autofill::data_util::GetPaymentRequestData(credit_card.network())
.basic_card_issuer_network);
if (!network.empty()) {
mappings[base::NumberToString(
static_cast<int>(AutofillFormatProto::CREDIT_CARD_NETWORK))] = network;
}
auto network_for_display = base::UTF16ToUTF8(credit_card.NetworkForDisplay());
if (!network_for_display.empty()) {
mappings[base::NumberToString(static_cast<int>(
AutofillFormatProto::CREDIT_CARD_NETWORK_FOR_DISPLAY))] =
network_for_display;
}
auto last_four_digits = base::UTF16ToUTF8(credit_card.LastFourDigits());
if (!last_four_digits.empty()) {
mappings[base::NumberToString(static_cast<int>(
AutofillFormatProto::CREDIT_CARD_NUMBER_LAST_FOUR_DIGITS))] =
last_four_digits;
}
int month;
if (base::StringToInt(
credit_card.GetInfo(autofill::CREDIT_CARD_EXP_MONTH, locale),
&month)) {
mappings[base::NumberToString(static_cast<int>(
AutofillFormatProto::CREDIT_CARD_NON_PADDED_EXP_MONTH))] =
base::NumberToString(month);
}
return mappings;
}
} // namespace field_formatter
} // namespace autofill_assistant