Skip to content

Commit d5b0e93

Browse files
glenn.volckaertUbuntu
authored andcommitted
Adds escaping of single quotes and support for .net style escaping
DEVSIX-6308
1 parent ae8cf77 commit d5b0e93

File tree

2 files changed

+158
-1
lines changed

2 files changed

+158
-1
lines changed

commons/src/main/java/com/itextpdf/commons/utils/MessageFormatUtil.java

Lines changed: 81 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,87 @@ private MessageFormatUtil() {
5656
// Empty constructor.
5757
}
5858

59+
/**
60+
* This method provides a generic way for formatting strings.
61+
* Indexed arguments can be referred with {index},
62+
* to escape curly braces you have to double them.
63+
*
64+
* @param pattern to format
65+
* @param arguments arguments
66+
*
67+
* @return The formatted string
68+
*/
5969
public static String format(String pattern, Object... arguments) {
60-
return new MessageFormat(pattern, Locale.ROOT).format(arguments);
70+
boolean mustClose = false;
71+
StringBuilder result = new StringBuilder(pattern.length());
72+
int i = 0;
73+
int n = pattern.length();
74+
while (i < n) {
75+
char current = pattern.charAt(i);
76+
switch (current) {
77+
case '{': {
78+
int curlyCount = 0;
79+
int j;
80+
for (j = i; j < n && pattern.charAt(j) == '{'; j++, curlyCount++)
81+
;
82+
i += curlyCount - 1;
83+
if (curlyCount > 1) {
84+
if (!mustClose) {
85+
result.append("'");
86+
}
87+
while (curlyCount >= 2) {
88+
result.append('{');
89+
curlyCount -= 2;
90+
}
91+
mustClose = true;
92+
}
93+
if (curlyCount == 1) {
94+
if (mustClose) {
95+
result.append('\'');
96+
}
97+
result.append('{');
98+
mustClose = false;
99+
}
100+
}
101+
break;
102+
case '}': {
103+
int curlyCount = 0;
104+
int j;
105+
for (j = i; j < n && pattern.charAt(j) == '}'; j++, curlyCount++)
106+
;
107+
i += curlyCount - 1;
108+
if (curlyCount % 2 == 1) {
109+
if (mustClose) {
110+
result.append('\'');
111+
}
112+
result.append('}');
113+
mustClose = false;
114+
}
115+
if (curlyCount > 1) {
116+
result.append("'");
117+
while (curlyCount >= 2) {
118+
result.append('}');
119+
curlyCount -= 2;
120+
}
121+
mustClose = true;
122+
}
123+
}
124+
break;
125+
case '\'':
126+
result.append("''");
127+
break;
128+
default:
129+
if (mustClose) {
130+
result.append('\'');
131+
mustClose = false;
132+
}
133+
result.append(current);
134+
}
135+
i++;
136+
}
137+
if (mustClose) {
138+
result.append('\'');
139+
}
140+
return new MessageFormat(result.toString(), Locale.ROOT).format(arguments);
61141
}
62142
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*
2+
This file is part of the iText (R) project.
3+
Copyright (c) 1998-2022 iText Group NV
4+
Authors: iText Software.
5+
6+
This program is offered under a commercial and under the AGPL license.
7+
For commercial licensing, contact us at https://itextpdf.com/sales. For AGPL licensing, see below.
8+
9+
AGPL licensing:
10+
This program is free software: you can redistribute it and/or modify
11+
it under the terms of the GNU Affero General Public License as published by
12+
the Free Software Foundation, either version 3 of the License, or
13+
(at your option) any later version.
14+
15+
This program is distributed in the hope that it will be useful,
16+
but WITHOUT ANY WARRANTY; without even the implied warranty of
17+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18+
GNU Affero General Public License for more details.
19+
20+
You should have received a copy of the GNU Affero General Public License
21+
along with this program. If not, see <https://www.gnu.org/licenses/>.
22+
*/
23+
package com.itextpdf.commons.utils;
24+
25+
import com.itextpdf.test.ExtendedITextTest;
26+
27+
import java.awt.SystemTray;
28+
import java.io.Console;
29+
import java.text.MessageFormat;
30+
import java.util.ArrayList;
31+
import java.util.Arrays;
32+
import java.util.List;
33+
import java.util.Locale;
34+
import java.util.Stack;
35+
import org.junit.Assert;
36+
import org.junit.Test;
37+
import org.junit.runner.RunWith;
38+
import org.junit.runners.Parameterized;
39+
import org.junit.runners.Parameterized.Parameters;
40+
41+
@RunWith(Parameterized.class)
42+
public class MessageFormatUtilTest extends ExtendedITextTest {
43+
44+
private String expectedResult;
45+
private String pattern;
46+
private Object[] arguments;
47+
48+
49+
public MessageFormatUtilTest(Object expectedResult, Object pattern, Object arguments, Object name) {
50+
this.expectedResult = (String)expectedResult;
51+
this.pattern = (String)pattern;
52+
this.arguments = (Object[]) arguments;
53+
}
54+
55+
56+
@Parameterized.Parameters(name = "{index}: {3} format: {1}; {0}")
57+
public static Iterable<Object[]> dataSource() {
58+
return Arrays.asList(new Object[][]{
59+
{"Plain message with params 1 test", "Plain message with params {0} {1}", new Object[] {1, "test"},"test with simple params"},
60+
{"Message with 'single quotes'", "Message with 'single quotes'", new Object[0],"test with single quotes"},
61+
{"Message with ''doubled single quotes''", "Message with ''doubled single quotes''", new Object[0],"test with doubled single quotes"},
62+
{"Message with {curly braces} and a parameter {I'm between curly braces too}", "Message with {{curly braces}} and a parameter {{{0}}}", new Object[]{"I'm between curly braces too"},"Test with curly braces"},
63+
{"Message with {{multiple curly braces}}", "Message with {{{{multiple curly braces}}}}", new Object[]{},"Test with multiple curly braces"},
64+
{"Message with {Value between brackets} and {{Value between double brackets}}", "Message with {{{0}}} and {{{{{1}}}}}", new Object[]{"Value between brackets", "Value between double brackets"},"Test with multiple curly braces"},
65+
{"Lets go wild 'value 1', {value 2}, '{value 3}', {'{value 4}'}", "Lets go wild '{0}', {{{1}}}, '{{{2}}}', {{'{{{3}}}'}}", new Object[]{"value 1", "value 2","value 3","value 4"},"Some of all"},
66+
{"{'{value}'}", "{{'{{{0}}}'}}", new Object[]{"value"},"Mix om multiple brackets and quotes 1"},
67+
{"'{value}'", "'{{{0}}}'", new Object[]{"value"},"Mix om multiple brackets and quotes 1"},
68+
{"a '{'{123}'}''' b", "a '{{'{{{0}}}'}}''' b", new Object[]{123},"Mix om multiple brackets and quotes 1"},
69+
});
70+
}
71+
72+
@Test
73+
public void testFormatting() {
74+
Assert.assertEquals(expectedResult, MessageFormatUtil.format(pattern, arguments));
75+
}
76+
77+
}

0 commit comments

Comments
 (0)