Forward ported from 2.3-gae: \= escape in string literals
Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/782eed0b Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/782eed0b Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/782eed0b Branch: refs/heads/3 Commit: 782eed0b4ac12545715580cfe08dbda119ad9871 Parents: 8093cb6 Author: ddekany <ddek...@apache.org> Authored: Sun Mar 18 19:08:22 2018 +0100 Committer: ddekany <ddek...@apache.org> Committed: Sun Mar 18 19:08:22 2018 +0100 ---------------------------------------------------------------------- .../core/InterpolationSyntaxTest.java | 4 +++ .../core/util/TemplateLanguageUtilsTest.java | 21 ++++++++++++++- .../core/util/TemplateLanguageUtils.java | 27 ++++++++++++-------- freemarker-core/src/main/javacc/FTL.jj | 2 +- 4 files changed, 42 insertions(+), 12 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/782eed0b/freemarker-core-test/src/test/java/org/apache/freemarker/core/InterpolationSyntaxTest.java ---------------------------------------------------------------------- diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/InterpolationSyntaxTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/InterpolationSyntaxTest.java index d187bb5..e6b0eeb 100644 --- a/freemarker-core-test/src/test/java/org/apache/freemarker/core/InterpolationSyntaxTest.java +++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/InterpolationSyntaxTest.java @@ -91,6 +91,10 @@ public class InterpolationSyntaxTest extends TemplateTest { assertErrorContains("[=", "end of file"); assertErrorContains("[=1", "unclosed \"[\""); + assertOutput("[='[\\=1]']", "[=1]"); + assertOutput("[='[\\=1][=2]']", "12"); // Usual legacy interpolation escaping glitch... + assertOutput("[=r'[=1]']", "[=1]"); + StringWriter sw = new StringWriter(); new Template(null, "[= 1 + '[= 2 ]' ]", getConfiguration()).dump(sw); assertEquals("[=1 + \"[=2]\"]", sw.toString()); http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/782eed0b/freemarker-core-test/src/test/java/org/apache/freemarker/core/util/TemplateLanguageUtilsTest.java ---------------------------------------------------------------------- diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/util/TemplateLanguageUtilsTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/util/TemplateLanguageUtilsTest.java index aae4699..1e6f171 100644 --- a/freemarker-core-test/src/test/java/org/apache/freemarker/core/util/TemplateLanguageUtilsTest.java +++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/util/TemplateLanguageUtilsTest.java @@ -20,8 +20,11 @@ package org.apache.freemarker.core.util; import static junit.framework.TestCase.assertFalse; import static junit.framework.TestCase.assertNull; +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import org.junit.Test; @@ -43,8 +46,10 @@ public class TemplateLanguageUtilsTest { assertEquals("a\\'c\"d", TemplateLanguageUtils.escapeStringLiteralPart("a'c\"d", '\'')); assertEquals("\\n\\r\\t\\f\\x0002\\\\", TemplateLanguageUtils.escapeStringLiteralPart("\n\r\t\f\u0002\\")); assertEquals("\\l\\g\\a", TemplateLanguageUtils.escapeStringLiteralPart("<>&")); + assertEquals("=[\\=]=", TemplateLanguageUtils.escapeStringLiteralPart("=[=]=")); + assertEquals("[\\=", TemplateLanguageUtils.escapeStringLiteralPart("[=")); } - + @Test public void testEscapeStringLiteralAll() { assertFTLEsc("", "", "", "", "\"\""); @@ -79,6 +84,20 @@ public class TemplateLanguageUtilsTest { assertEquals( "'\"\n\b\u0000c><&{\\", TemplateLanguageUtils.unescapeStringLiteralPart("\\'\\\"\\n\\b\\x0000c\\g\\l\\a\\{\\\\")); + + assertEquals("\nq", TemplateLanguageUtils.unescapeStringLiteralPart("\\x0Aq")); + assertEquals("\n\r1", TemplateLanguageUtils.unescapeStringLiteralPart("\\x0A\\x000D1")); + assertEquals("\n\r\t", TemplateLanguageUtils.unescapeStringLiteralPart("\\n\\r\\t")); + assertEquals("${1}#{2}[=3]", TemplateLanguageUtils.unescapeStringLiteralPart("$\\{1}#\\{2}[\\=3]")); + assertEquals("{=", TemplateLanguageUtils.unescapeStringLiteralPart("\\{\\=")); + assertEquals("\\=", TemplateLanguageUtils.unescapeStringLiteralPart("\\\\=")); + + try { + TemplateLanguageUtils.unescapeStringLiteralPart("\\["); + fail(); + } catch (GenericParseException e) { + assertThat(e.getMessage(), containsString("\\[")); + } } @Test http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/782eed0b/freemarker-core/src/main/java/org/apache/freemarker/core/util/TemplateLanguageUtils.java ---------------------------------------------------------------------- diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/util/TemplateLanguageUtils.java b/freemarker-core/src/main/java/org/apache/freemarker/core/util/TemplateLanguageUtils.java index e2e32e4..f06276b 100644 --- a/freemarker-core/src/main/java/org/apache/freemarker/core/util/TemplateLanguageUtils.java +++ b/freemarker-core/src/main/java/org/apache/freemarker/core/util/TemplateLanguageUtils.java @@ -53,6 +53,10 @@ import org.apache.freemarker.core.model.impl.JavaMethodModel; // TODO [FM3] This name won't be good if the template language isn't called "FTL"... public final class TemplateLanguageUtils { + /** + * Used to look up if the chars with low code needs to be escaped, but note that it gives bad result for '=', as + * there the it matters if it's after '['. + */ private static final char[] ESCAPES = createEscapes(); private TemplateLanguageUtils() { @@ -68,6 +72,7 @@ public final class TemplateLanguageUtils { escapes['\''] = '\''; escapes['"'] = '"'; escapes['<'] = 'l'; + // As '=' is only escaped if it's after '[', we can't handle it here escapes['>'] = 'g'; escapes['&'] = 'a'; escapes['\b'] = 'b'; @@ -139,10 +144,16 @@ public final class TemplateLanguageUtils { StringBuilder buf = null; for (int i = 0; i < ln; i++) { char c = s.charAt(i); - char escape = - c < escLn ? ESCAPES[c] : - c == '{' && i > 0 && isInterpolationStart(s.charAt(i - 1)) ? '{' : - 0; + char escape; + if (c == '=') { + escape = i > 0 && s.charAt(i - 1) == '[' ? '=' : 0; + } else if (c < escLn) { + escape = ESCAPES[c]; // + } else if (c == '{' && i > 0 && s.charAt(i - 1) == '$') { + escape = '{'; + } else { + escape = 0; + } if (escape == 0 || escape == otherQuotation || c == '&' && !escapeAmp || c == '<' && !escapeLT || c == '>' && !escapeGT) { if (buf != null) { @@ -181,11 +192,6 @@ public final class TemplateLanguageUtils { } } - private static boolean isInterpolationStart(char c) { - // Find related: [interpolation prefixes] - return c == '$'; - } - /** * Unescapes a string that was escaped to be part of an FTL string literal. The string to unescape must not include * the two quotation marks or two apostrophe-quotes that delimit the literal. @@ -267,7 +273,8 @@ public final class TemplateLanguageUtils { bidx = idx + 2; break; case '{': - buf.append('{'); + case '=': + buf.append(c); bidx = idx + 2; break; case 'x': { http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/782eed0b/freemarker-core/src/main/javacc/FTL.jj ---------------------------------------------------------------------- diff --git a/freemarker-core/src/main/javacc/FTL.jj b/freemarker-core/src/main/javacc/FTL.jj index 46782d6..531253e 100644 --- a/freemarker-core/src/main/javacc/FTL.jj +++ b/freemarker-core/src/main/javacc/FTL.jj @@ -985,7 +985,7 @@ TOKEN: <#ESCAPED_CHAR : "\\" ( - ("n" | "t" | "r" | "f" | "b" | "g" | "l" | "a" | "\\" | "'" | "\"" | "$" | "{") + ("n" | "t" | "r" | "f" | "b" | "g" | "l" | "a" | "\\" | "'" | "\"" | "$" | "{" | "=") | ("x" ["0"-"9", "A"-"F", "a"-"f"]) )