1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.util;
20
21 import java.io.FilterWriter;
22 import java.io.IOException;
23 import java.io.Writer;
24 import org.apache.myfaces.shared.util.ClassUtils;
25 import org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement;
26
27
28
29
30
31
32
33
34 public class IllegalXmlCharacterFilterWriter extends FilterWriter
35 {
36 private static final char BLANK_CHAR = ' ';
37
38
39 private static boolean java16;
40
41 static
42 {
43 try
44 {
45 java16 = ClassUtils.classForName("java.util.Objects") == null;
46 }
47 catch (Throwable e)
48 {
49 java16 = true;
50 }
51
52 if (java16)
53 {
54 System.err.println("Skip using " + IllegalXmlCharacterFilterWriter.class.getName()
55 + ", it's only available in Java 1.6+");
56 }
57 }
58
59 public IllegalXmlCharacterFilterWriter(Writer out)
60 {
61 super(out);
62 }
63
64 @Override
65 public void write(int c) throws IOException
66 {
67 if (java16)
68 {
69 super.write(c);
70 return;
71 }
72
73 if (isInvalidChar(c))
74 {
75 super.write((int) BLANK_CHAR);
76 }
77 else
78 {
79 super.write(c);
80 }
81 }
82
83 @Override
84 public void write(char[] cbuf, int off, int len) throws IOException
85 {
86 if (java16)
87 {
88 super.write(cbuf, off, len);
89 return;
90 }
91
92 super.write(encodeCharArray(cbuf, off, len), off, len);
93 }
94
95 @Override
96 public void write(String str, int off, int len) throws IOException
97 {
98 if (java16)
99 {
100 super.write(str, off, len);
101 return;
102 }
103
104 super.write(encodeString(str, off, len), off, len);
105 }
106
107 @IgnoreJRERequirement
108 private static String encodeString(String str, int off, int len)
109 {
110 if (str == null)
111 {
112 return null;
113 }
114
115 int to = off + len;
116 boolean surrogateResolved = false;
117 char c;
118 int codePoint;
119 char cNext;
120
121 char[] encoded = null;
122 for (int i = off; i < to; i++)
123 {
124 if (surrogateResolved == true)
125 {
126 surrogateResolved = false;
127 continue;
128 }
129
130 c = str.charAt(i);
131 codePoint = c;
132
133 if (Character.isHighSurrogate(c) && i + 1 < to)
134 {
135 cNext = str.charAt(i + 1);
136 if (Character.isLowSurrogate(cNext))
137 {
138 codePoint = Character.toCodePoint(c, cNext);
139 surrogateResolved = true;
140 }
141 }
142
143
144 if ((!surrogateResolved && Character.isSurrogate(c)) || isInvalidChar(codePoint))
145 {
146 if (encoded == null)
147 {
148 encoded = str.toCharArray();
149 }
150 encoded[i] = BLANK_CHAR;
151
152 if (surrogateResolved)
153 {
154 encoded[i + 1] = BLANK_CHAR;
155 }
156 }
157 }
158
159 if (encoded != null)
160 {
161 return String.valueOf(encoded);
162 }
163
164 return str;
165 }
166
167 @IgnoreJRERequirement
168 private static char[] encodeCharArray(char[] cbuf, int off, int len)
169 {
170 if (cbuf == null)
171 {
172 return null;
173 }
174
175 int to = off + len;
176
177 boolean surrogateResolved = false;
178 char c;
179 int codePoint;
180 char cNext;
181
182 for (int i = off; i < to; i++)
183 {
184 if (surrogateResolved == true)
185 {
186 surrogateResolved = false;
187 continue;
188 }
189
190 c = cbuf[i];
191 codePoint = c;
192
193
194 if (Character.isHighSurrogate(c) && i + 1 < to)
195 {
196 cNext = cbuf[i + 1];
197 if (Character.isLowSurrogate(cNext))
198 {
199 codePoint = Character.toCodePoint(c, cNext);
200 surrogateResolved = true;
201 }
202 }
203
204 if ((!surrogateResolved && Character.isSurrogate(c)) || isInvalidChar(codePoint))
205 {
206 cbuf[i] = BLANK_CHAR;
207
208 if (surrogateResolved)
209 {
210 cbuf[i + 1] = BLANK_CHAR;
211 }
212 }
213 }
214 return cbuf;
215 }
216
217 private static boolean isInvalidChar(int codePoint)
218 {
219 if (codePoint == 1113088)
220 {
221 return true;
222 }
223
224 if (codePoint == 0x9 || codePoint == 0xA || codePoint == 0xD)
225 {
226 return false;
227 }
228 if (codePoint >= 0x20 && codePoint <= 0xD7FF)
229 {
230 return false;
231 }
232 if (codePoint >= 0xE000 && codePoint <= 0xFFFD)
233 {
234 return false;
235 }
236 if (codePoint >= 0x10000 && codePoint <= 0x10FFFF)
237 {
238 return false;
239 }
240
241 return true;
242 }
243 }