OLD | NEW |
(Empty) | |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "components/autofill/core/browser/legal_message_line.h" |
| 6 |
| 7 #include "base/i18n/message_formatter.h" |
| 8 #include "base/strings/string_util.h" |
| 9 #include "base/strings/utf_string_conversions.h" |
| 10 #include "base/values.h" |
| 11 |
| 12 namespace autofill { |
| 13 namespace { |
| 14 |
| 15 // Replace "{0}", "{1}", ... in |template_icu| with corresponding strings |
| 16 // from |display_texts|. Sets |out_message| to the resulting string, with |
| 17 // start position of each replacement in |out_offsets|. |
| 18 // Return false on failure. If false is returned then contents of |out_message| |
| 19 // and |out_offsets| are undefined. |
| 20 bool ReplaceTemplatePlaceholders( |
| 21 const base::string16& template_icu, |
| 22 const std::vector<base::string16>& display_texts, |
| 23 base::string16* out_message, |
| 24 std::vector<size_t>* out_offsets) { |
| 25 // Escape "$" -> "$$" for ReplaceStringPlaceholders(). |
| 26 // |
| 27 // Edge cases: |
| 28 // 1. Two or more consecutive $ characters will be incorrectly expanded |
| 29 // ("$$" -> "$$$$", which ReplaceStringPlaceholders() then turns into |
| 30 // "$$$"). |
| 31 // |
| 32 // 2. "${" will cause false to be returned. "${0}" will expand to "$${0}". |
| 33 // FormatWithNumberedArgs() turns it into "$$$1", which |
| 34 // ReplaceStringPlaceholders() then turns into "$$1" without doing the |
| 35 // parameter replacement. This causes false to be returned because each |
| 36 // parameter is not used exactly once. |
| 37 // |
| 38 // Both of these cases are noted in the header file, and are unlikely to |
| 39 // occur in any actual legal message. |
| 40 base::string16 template_icu_escaped; |
| 41 base::ReplaceChars(template_icu, base::ASCIIToUTF16("$"), |
| 42 base::ASCIIToUTF16("$$"), &template_icu_escaped); |
| 43 |
| 44 // Replace "{0}" -> "$1", "{1}" -> "$2", ... to prepare |template_dollars| |
| 45 // for ReplaceStringPlaceholders(). |
| 46 base::string16 template_dollars = |
| 47 base::i18n::MessageFormatter::FormatWithNumberedArgs( |
| 48 template_icu_escaped, "$1", "$2", "$3", "$4", "$5", "$6", "$7"); |
| 49 |
| 50 // FormatWithNumberedArgs() returns an empty string on failure. |
| 51 if (template_dollars.empty() && !template_icu.empty()) |
| 52 return false; |
| 53 |
| 54 // Replace "$1", "$2", ... with the display text of each parameter. |
| 55 *out_message = base::ReplaceStringPlaceholders(template_dollars, |
| 56 display_texts, out_offsets); |
| 57 |
| 58 // Each parameter must be used exactly once. If a parameter is unused or |
| 59 // used more than once then it can't be determined which |offsets| entry |
| 60 // corresponds to which parameter. |
| 61 return out_offsets->size() == display_texts.size(); |
| 62 } |
| 63 |
| 64 } // namespace |
| 65 |
| 66 // static |
| 67 bool LegalMessageLine::Parse(const base::DictionaryValue& legal_message, |
| 68 std::vector<scoped_ptr<LegalMessageLine>>* out) { |
| 69 const base::ListValue* lines = nullptr; |
| 70 if (legal_message.GetList("line", &lines)) { |
| 71 out->resize(lines->GetSize()); |
| 72 for (size_t i = 0; i < lines->GetSize(); ++i) { |
| 73 out->at(i).reset(new LegalMessageLine); |
| 74 const base::DictionaryValue* single_line; |
| 75 if (!lines->GetDictionary(i, &single_line) || |
| 76 !out->at(i)->ParseLine(*single_line)) { |
| 77 out->clear(); |
| 78 return false; |
| 79 } |
| 80 } |
| 81 } |
| 82 |
| 83 return true; |
| 84 } |
| 85 |
| 86 LegalMessageLine::LegalMessageLine() {} |
| 87 |
| 88 LegalMessageLine::~LegalMessageLine() {} |
| 89 |
| 90 bool LegalMessageLine::ParseLine(const base::DictionaryValue& line) { |
| 91 // |display_texts| elements are the strings that will be substituted for |
| 92 // "{0}", "{1}", etc. in the template string. |
| 93 std::vector<base::string16> display_texts; |
| 94 |
| 95 // Process all the template parameters. |
| 96 const base::ListValue* template_parameters = nullptr; |
| 97 if (line.GetList("template_parameter", &template_parameters)) { |
| 98 display_texts.resize(template_parameters->GetSize()); |
| 99 links_.resize(template_parameters->GetSize()); |
| 100 |
| 101 for (size_t parameter_index = 0; |
| 102 parameter_index < template_parameters->GetSize(); ++parameter_index) { |
| 103 const base::DictionaryValue* single_parameter; |
| 104 std::string url; |
| 105 if (!template_parameters->GetDictionary(parameter_index, |
| 106 &single_parameter) || |
| 107 !single_parameter->GetString("display_text", |
| 108 &display_texts[parameter_index]) || |
| 109 !single_parameter->GetString("url", &url)) { |
| 110 return false; |
| 111 } |
| 112 links_[parameter_index].url = GURL(url); |
| 113 } |
| 114 } |
| 115 |
| 116 // Read the template string. It's a small subset of the ICU message format |
| 117 // syntax. |
| 118 base::string16 template_icu; |
| 119 if (!line.GetString("template", &template_icu)) |
| 120 return false; |
| 121 |
| 122 // Replace the placeholders in |template_icu| with strings from |
| 123 // |display_texts|, and store the start position of each replacement in |
| 124 // |offsets|. |
| 125 std::vector<size_t> offsets; |
| 126 if (!ReplaceTemplatePlaceholders(template_icu, display_texts, &text_, |
| 127 &offsets)) { |
| 128 return false; |
| 129 } |
| 130 |
| 131 // Fill in range values for all links. |
| 132 for (size_t offset_index = 0; offset_index < offsets.size(); ++offset_index) { |
| 133 size_t range_start = offsets[offset_index]; |
| 134 links_[offset_index].range = gfx::Range( |
| 135 range_start, range_start + display_texts[offset_index].size()); |
| 136 } |
| 137 |
| 138 return true; |
| 139 } |
| 140 |
| 141 } // namespace autofill |
OLD | NEW |