1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.krad.uif.freemarker;
17
18 import freemarker.core.Environment;
19 import freemarker.template.TemplateDirectiveBody;
20 import freemarker.template.TemplateDirectiveModel;
21 import freemarker.template.TemplateException;
22 import freemarker.template.TemplateModel;
23 import freemarker.template.TemplateModelException;
24
25 import java.io.IOException;
26 import java.io.Writer;
27 import java.util.Map;
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48 public class JsonStringEscapeDirective implements TemplateDirectiveModel {
49
50 @Override
51 public void execute(Environment env, Map params, TemplateModel[] loopVars,
52 TemplateDirectiveBody body) throws TemplateException, IOException {
53
54 if (!params.isEmpty()) {
55 throw new TemplateModelException(
56 getClass().getSimpleName() + " doesn't allow parameters.");
57 }
58 if (loopVars.length != 0) {
59 throw new TemplateModelException(
60 getClass().getSimpleName() + " doesn't allow loop variables.");
61 }
62
63
64 if (body != null) {
65
66
67 body.render(new JsonEscapingFilterWriter(env.getOut()));
68 } else {
69 throw new RuntimeException("missing body");
70 }
71 }
72
73
74
75
76 private static class JsonEscapingFilterWriter extends Writer {
77
78 private final Writer out;
79
80
81
82
83
84
85 JsonEscapingFilterWriter(Writer out) {
86 this.out = out;
87 }
88
89 @Override
90 public void write(char[] cbuf, int off, int len) throws IOException {
91
92
93 int needsEscapingCount = 0;
94
95 for (int i=0; i<len; i++) {
96 if (isNeedsEscaping(cbuf[i + off])) { needsEscapingCount += 1; }
97 }
98
99 char[] transformedCbuf = new char[len + needsEscapingCount];
100 int escapesAddedCount = 0;
101
102 for (int i = 0; i < len; i++) {
103 if (isNeedsEscaping(cbuf[i + off])) {
104 transformedCbuf[i+escapesAddedCount] = '\\';
105 escapesAddedCount += 1;
106 }
107
108 if (cbuf[i + off] == '\n') {
109
110 transformedCbuf[i+escapesAddedCount] = 'n';
111 } else if (cbuf[i + off] == '\r') {
112
113 transformedCbuf[i+escapesAddedCount] = 'r';
114 } else {
115
116 transformedCbuf[i+escapesAddedCount] = cbuf[i + off];
117 }
118 }
119
120 out.write(transformedCbuf);
121 }
122
123 @Override
124 public void flush() throws IOException {
125 out.flush();
126 }
127
128 @Override
129 public void close() throws IOException {
130 out.close();
131 }
132
133
134
135
136
137
138
139 private static boolean isNeedsEscaping(char c) {
140 return (c == '"' || c == '\n' || c == '\r');
141 }
142 }
143 }