| Index: components/autofill/core/browser/legal_message_line.cc
|
| diff --git a/components/autofill/core/browser/legal_message_line.cc b/components/autofill/core/browser/legal_message_line.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..1a06b5ee06aedad2583efeadf90bc74a9c9d5a54
|
| --- /dev/null
|
| +++ b/components/autofill/core/browser/legal_message_line.cc
|
| @@ -0,0 +1,152 @@
|
| +// Copyright 2016 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/legal_message_line.h"
|
| +
|
| +#include "base/i18n/message_formatter.h"
|
| +#include "base/logging.h"
|
| +#include "base/strings/string_util.h"
|
| +#include "base/strings/utf_string_conversions.h"
|
| +#include "base/values.h"
|
| +
|
| +namespace autofill {
|
| +namespace {
|
| +
|
| +// Replace "{0}", "{1}", ... in |template_icu| with corresponding strings
|
| +// from |display_texts|. Sets |out_message| to the resulting string, with
|
| +// start position of each replacement in |out_offsets|.
|
| +// Return false on failure. If false is returned then contents of |out_message|
|
| +// and |out_offsets| are undefined.
|
| +bool ReplaceTemplatePlaceholders(
|
| + const base::string16& template_icu,
|
| + const std::vector<base::string16>& display_texts,
|
| + base::string16* out_message,
|
| + std::vector<size_t>* out_offsets) {
|
| + // Escape "$" -> "$$" for ReplaceStringPlaceholders().
|
| + //
|
| + // Edge cases:
|
| + // 1. Two or more consecutive $ characters will be incorrectly expanded
|
| + // ("$$" -> "$$$$", which ReplaceStringPlaceholders() then turns into
|
| + // "$$$").
|
| + //
|
| + // 2. "${" will cause false to be returned. "${0}" will expand to "$${0}".
|
| + // FormatWithNumberedArgs() turns it into "$$$1", which
|
| + // ReplaceStringPlaceholders() then turns into "$$1" without doing the
|
| + // parameter replacement. This causes false to be returned because each
|
| + // parameter is not used exactly once.
|
| + //
|
| + // Both of these cases are noted in the header file, and are unlikely to
|
| + // occur in any actual legal message.
|
| + base::string16 template_icu_escaped;
|
| + base::ReplaceChars(template_icu, base::ASCIIToUTF16("$"),
|
| + base::ASCIIToUTF16("$$"), &template_icu_escaped);
|
| +
|
| + // Replace "{0}" -> "$1", "{1}" -> "$2", ... to prepare |template_dollars|
|
| + // for ReplaceStringPlaceholders().
|
| + base::string16 template_dollars =
|
| + base::i18n::MessageFormatter::FormatWithNumberedArgs(
|
| + template_icu_escaped, "$1", "$2", "$3", "$4", "$5", "$6", "$7");
|
| +
|
| + // FormatWithNumberedArgs() returns an empty string on failure.
|
| + if (template_dollars.empty() && !template_icu.empty())
|
| + return false;
|
| +
|
| + // Replace "$1", "$2", ... with the display text of each parameter.
|
| + *out_message = base::ReplaceStringPlaceholders(template_dollars,
|
| + display_texts, out_offsets);
|
| +
|
| + // Each parameter must be used exactly once. If a parameter is unused or
|
| + // used more than once then it can't be determined which |offsets| entry
|
| + // corresponds to which parameter.
|
| + return out_offsets->size() == display_texts.size();
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +LegalMessageLine::Link::Link(size_t start,
|
| + size_t end,
|
| + const std::string& url_spec)
|
| + : range(start, end), url(url_spec) {}
|
| +
|
| +LegalMessageLine::Link::~Link() {}
|
| +
|
| +LegalMessageLine::LegalMessageLine() {}
|
| +
|
| +LegalMessageLine::~LegalMessageLine() {}
|
| +
|
| +// static
|
| +bool LegalMessageLine::Parse(const base::DictionaryValue& legal_message,
|
| + LegalMessageLines* out) {
|
| + const base::ListValue* lines_list = nullptr;
|
| + if (legal_message.GetList("line", &lines_list)) {
|
| + LegalMessageLines lines;
|
| + lines.reserve(lines_list->GetSize());
|
| + for (size_t i = 0; i < lines_list->GetSize(); ++i) {
|
| + lines.emplace_back(LegalMessageLine());
|
| + const base::DictionaryValue* single_line;
|
| + if (!lines_list->GetDictionary(i, &single_line) ||
|
| + !lines.back().ParseLine(*single_line))
|
| + return false;
|
| + }
|
| +
|
| + out->swap(lines);
|
| + }
|
| +
|
| + return true;
|
| +}
|
| +
|
| +bool LegalMessageLine::ParseLine(const base::DictionaryValue& line) {
|
| + DCHECK(text_.empty());
|
| + DCHECK(links_.empty());
|
| +
|
| + // |display_texts| elements are the strings that will be substituted for
|
| + // "{0}", "{1}", etc. in the template string.
|
| + std::vector<base::string16> display_texts;
|
| +
|
| + // Process all the template parameters.
|
| + const base::ListValue* template_parameters = nullptr;
|
| + if (line.GetList("template_parameter", &template_parameters)) {
|
| + display_texts.resize(template_parameters->GetSize());
|
| + links_.reserve(template_parameters->GetSize());
|
| +
|
| + for (size_t parameter_index = 0;
|
| + parameter_index < template_parameters->GetSize(); ++parameter_index) {
|
| + const base::DictionaryValue* single_parameter;
|
| + std::string url;
|
| + if (!template_parameters->GetDictionary(parameter_index,
|
| + &single_parameter) ||
|
| + !single_parameter->GetString("display_text",
|
| + &display_texts[parameter_index]) ||
|
| + !single_parameter->GetString("url", &url))
|
| + return false;
|
| +
|
| + links_.emplace_back(0, 0, url);
|
| + }
|
| + }
|
| +
|
| + // Read the template string. It's a small subset of the ICU message format
|
| + // syntax.
|
| + base::string16 template_icu;
|
| + if (!line.GetString("template", &template_icu))
|
| + return false;
|
| +
|
| + // Replace the placeholders in |template_icu| with strings from
|
| + // |display_texts|, and store the start position of each replacement in
|
| + // |offsets|.
|
| + std::vector<size_t> offsets;
|
| + if (!ReplaceTemplatePlaceholders(template_icu, display_texts, &text_,
|
| + &offsets))
|
| + return false;
|
| +
|
| + // Fill in range values for all links.
|
| + for (size_t offset_index = 0; offset_index < offsets.size(); ++offset_index) {
|
| + size_t range_start = offsets[offset_index];
|
| + links_[offset_index].range = gfx::Range(
|
| + range_start, range_start + display_texts[offset_index].size());
|
| + }
|
| +
|
| + return true;
|
| +}
|
| +
|
| +} // namespace autofill
|
|
|