diff --git a/src/api/metadata/yaml/message.h b/src/api/metadata/yaml/message.h index effb1f3e..8991082f 100644 --- a/src/api/metadata/yaml/message.h +++ b/src/api/metadata/yaml/message.h @@ -110,10 +110,38 @@ struct convert { formatArgStore.push_back(sub); } + static const std::regex boostSyntax( + "%(\\d+)%", std::regex::ECMAScript | std::regex::icase); + for (auto& mc : content) { + // Replace the old Boost.Format placeholder syntax for backward + // compatibility. To be removed after at least one major release of + // libloot to allow migration to the new syntax. + auto text = mc.GetText(); + std::smatch match; + while ( + std::regex_search(text.cbegin(), text.cend(), match, boostSyntax)) { + if (match.size() > 1) { + const auto n = std::stoul(match[1]); + if (n > 0) { + const auto newPlaceholder = "{" + std::to_string(n - 1) + "}"; + text.replace(match[0].first, match[0].second, newPlaceholder); + } else { + throw RepresentationException( + node.Mark(), + "bad conversion: found zero-indexed placeholder using old " + "syntax"); + } + } else { + throw RepresentationException(node.Mark(), + "bad conversion: only partially " + "matched old placeholder syntax"); + } + } + try { - const auto text = fmt::vformat(mc.GetText(), formatArgStore); - mc = loot::MessageContent(text, mc.GetLanguage()); + const auto formattedText = fmt::vformat(text, formatArgStore); + mc = loot::MessageContent(formattedText, mc.GetLanguage()); } catch (const fmt::format_error& e) { throw RepresentationException( node.Mark(), diff --git a/src/tests/api/internals/metadata/message_test.h b/src/tests/api/internals/metadata/message_test.h index 0a6e4d8d..b531264e 100644 --- a/src/tests/api/internals/metadata/message_test.h +++ b/src/tests/api/internals/metadata/message_test.h @@ -669,6 +669,28 @@ TEST_P(MessageTest, message.GetContent()); } +TEST_P(MessageTest, decodingFromYamlShouldAcceptPercentagePlaceholderSyntax) { + YAML::Node node = YAML::Load( + "type: say\n" + "content: content %1% %2% %3% %4% %5% %6% %7% %8% %9% %10% %11%\n" + "subs:\n" + " - a\n" + " - b\n" + " - c\n" + " - d\n" + " - e\n" + " - f\n" + " - g\n" + " - h\n" + " - i\n" + " - j\n" + " - k"); + Message message = node.as(); + + ASSERT_EQ(1, message.GetContent().size()); + EXPECT_EQ("content a b c d e f g h i j k", message.GetContent()[0].GetText()); +} + TEST_P(MessageTest, decodingFromYamlShouldThrowIfAnInvalidConditionIsGiven) { YAML::Node node = YAML::Load( "type: say\n"