@@ -13,6 +13,39 @@ namespace {
1313 return static_cast <double >((value > 0.0 ) - (value < 0.0 ));
1414 }
1515
16+ bool parseFixedPointSpecifier (const QString &displayTemplate, qsizetype index,
17+ qsizetype *specifierLength, int *precision = nullptr ) {
18+ if (index + 2 >= displayTemplate.size () || displayTemplate.at (index) != u' %'
19+ || displayTemplate.at (index + 1 ) != u' .' ) {
20+ return false ;
21+ }
22+
23+ auto cursor = index + 2 ;
24+ int parsedPrecision{};
25+ bool hasDigit{};
26+ while (cursor < displayTemplate.size ()) {
27+ const auto character = displayTemplate.at (cursor);
28+ if (character < u' 0' || character > u' 9' )
29+ break ;
30+
31+ const auto digit = character.unicode () - u' 0' ;
32+ if (parsedPrecision > (std::numeric_limits<int >::max () - digit) / 10 )
33+ return false ;
34+ parsedPrecision = parsedPrecision * 10 + digit;
35+ hasDigit = true ;
36+ ++cursor;
37+ }
38+
39+ if (!hasDigit || cursor >= displayTemplate.size () || displayTemplate.at (cursor) != u' f' )
40+ return false ;
41+
42+ if (specifierLength)
43+ *specifierLength = cursor - index + 1 ;
44+ if (precision)
45+ *precision = parsedPrecision;
46+ return true ;
47+ }
48+
1649}
1750
1851namespace Synth ::Internal::ParameterExpressionUtils {
@@ -62,10 +95,9 @@ namespace Synth::Internal::ParameterExpressionUtils {
6295 index += 2 ;
6396 continue ;
6497 }
65- if (index + 3 < displayTemplate.size ()
66- && (displayTemplate.mid (index, 4 ) == QStringLiteral (" %.2f" )
67- || displayTemplate.mid (index, 4 ) == QStringLiteral (" %.3f" ))) {
68- index += 4 ;
98+ qsizetype specifierLength{};
99+ if (parseFixedPointSpecifier (displayTemplate, index, &specifierLength)) {
100+ index += specifierLength;
69101 continue ;
70102 }
71103 if (errorPosition)
@@ -99,13 +131,15 @@ namespace Synth::Internal::ParameterExpressionUtils {
99131 integerValue = static_cast <qint64>(std::round (value));
100132 result.append (locale.toString (integerValue));
101133 index += 2 ;
102- } else if (index + 3 < displayTemplate.size ()
103- && (displayTemplate.mid (index, 4 ) == QStringLiteral (" %.2f" )
104- || displayTemplate.mid (index, 4 ) == QStringLiteral (" %.3f" ))) {
105- const int precision = displayTemplate.at (index + 2 ).digitValue ();
106- result.append (locale.toString (value, ' f' , precision));
107- index += 4 ;
108134 } else {
135+ qsizetype specifierLength{};
136+ int precision{};
137+ if (parseFixedPointSpecifier (displayTemplate, index, &specifierLength, &precision)) {
138+ result.append (locale.toString (value, ' f' , precision));
139+ index += specifierLength;
140+ continue ;
141+ }
142+
109143 // Configurations are validated before reaching runtime. Keeping an inert literal
110144 // fallback here prevents an untrusted template from becoming a format string.
111145 result.append (u' %' );
0 commit comments