Line 0
Link Here
|
|
|
1 |
/* |
2 |
* Licensed to the Apache Software Foundation (ASF) under one or more |
3 |
* contributor license agreements. See the NOTICE file distributed with |
4 |
* this work for additional information regarding copyright ownership. |
5 |
* The ASF licenses this file to You under the Apache License, Version 2.0 |
6 |
* (the "License"); you may not use this file except in compliance with |
7 |
* the License. You may obtain a copy of the License at |
8 |
* |
9 |
* http://www.apache.org/licenses/LICENSE-2.0 |
10 |
* |
11 |
* Unless required by applicable law or agreed to in writing, software |
12 |
* distributed under the License is distributed on an "AS IS" BASIS, |
13 |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
14 |
* See the License for the specific language governing permissions and |
15 |
* limitations under the License. |
16 |
*/ |
17 |
package org.apache.taglibs.standard.util; |
18 |
|
19 |
import javax.servlet.jsp.JspWriter; |
20 |
import java.io.IOException; |
21 |
import java.io.Reader; |
22 |
|
23 |
/** |
24 |
* Handles escaping of characters that could be interpreted as XML markup. |
25 |
* |
26 |
* The specification for <code><c:out></code> defines the following |
27 |
* character conversions to be applied: |
28 |
* |
29 |
* <table rules="all" frame="border"> |
30 |
* <thead align="center"> |
31 |
* <tr><th>Character</th><th>Character Entity Code</th></tr> |
32 |
* </thead> |
33 |
* <tbody align="center"> |
34 |
* <tr><td><</td><td>&lt;</td></tr> |
35 |
* <tr><td>></td><td>&gt;</td></tr> |
36 |
* <tr><td>&</td><td>&amp;</td></tr> |
37 |
* <tr><td>'</td><td>&#039;</td></tr> |
38 |
* <tr><td>"</td><td>&#034;</td></tr> |
39 |
* </tbody> |
40 |
* </table> |
41 |
*/ |
42 |
public class EscapeXML { |
43 |
|
44 |
private static final String[] ESCAPES; |
45 |
static { |
46 |
int size = '>' + 1; // '>' is the largest escaped value |
47 |
ESCAPES = new String[size]; |
48 |
ESCAPES['<'] = "<"; |
49 |
ESCAPES['>'] = ">"; |
50 |
ESCAPES['&'] = "&"; |
51 |
ESCAPES['\''] = "'"; |
52 |
ESCAPES['"'] = """; |
53 |
} |
54 |
|
55 |
private static String getEscape(char c) { |
56 |
if (c < ESCAPES.length) { |
57 |
return ESCAPES[c]; |
58 |
} else { |
59 |
return null; |
60 |
} |
61 |
} |
62 |
|
63 |
/** |
64 |
* Escape a string. |
65 |
* |
66 |
* @param src the string to escape; must not be null |
67 |
* @return the escaped string |
68 |
*/ |
69 |
public static String escape(String src) { |
70 |
// first pass to determine the length of the buffer so we only allocate once |
71 |
int length = 0; |
72 |
for (int i = 0; i < src.length(); i++) { |
73 |
char c = src.charAt(i); |
74 |
String escape = getEscape(c); |
75 |
if (escape != null) { |
76 |
length += escape.length(); |
77 |
} else { |
78 |
length += 1; |
79 |
} |
80 |
} |
81 |
|
82 |
// skip copy if no escaping is needed |
83 |
if (length == src.length()) { |
84 |
return src; |
85 |
} |
86 |
|
87 |
// second pass to build the escaped string |
88 |
StringBuilder buf = new StringBuilder(length); |
89 |
for (int i = 0; i < src.length(); i++) { |
90 |
char c = src.charAt(i); |
91 |
String escape = getEscape(c); |
92 |
if (escape != null) { |
93 |
buf.append(escape); |
94 |
} else { |
95 |
buf.append(c); |
96 |
} |
97 |
} |
98 |
return buf.toString(); |
99 |
} |
100 |
|
101 |
/** |
102 |
* Emit the supplied object to the specified writer, escaping characters if needed. |
103 |
* @param src the object to write |
104 |
* @param escapeXml if true, escape unsafe characters before writing |
105 |
* @param out the JspWriter to emit to |
106 |
* @throws IOException if there was a problem emitting the content |
107 |
*/ |
108 |
public static void emit(Object src, boolean escapeXml, JspWriter out) throws IOException { |
109 |
if (src instanceof Reader) { |
110 |
emit((Reader) src, escapeXml, out); |
111 |
} else { |
112 |
emit(String.valueOf(src), escapeXml, out); |
113 |
} |
114 |
} |
115 |
|
116 |
/** |
117 |
* Emit the supplied String to the specified writer, escaping characters if needed. |
118 |
* @param src the String to write |
119 |
* @param escapeXml if true, escape unsafe characters before writing |
120 |
* @param out the JspWriter to emit to |
121 |
* @throws IOException if there was a problem emitting the content |
122 |
*/ |
123 |
public static void emit(String src, boolean escapeXml, JspWriter out) throws IOException { |
124 |
if (escapeXml) { |
125 |
emit(src, out); |
126 |
} else { |
127 |
out.write(src); |
128 |
} |
129 |
} |
130 |
|
131 |
/** |
132 |
* Emit escaped content into the specified JSPWriter. |
133 |
* |
134 |
* @param src the string to escape; must not be null |
135 |
* @param out the JspWriter to emit to |
136 |
* @throws IOException if there was a problem emitting the content |
137 |
*/ |
138 |
public static void emit(String src, JspWriter out) throws IOException { |
139 |
int end = src.length(); |
140 |
int from = 0; |
141 |
for (int to = from ; to < end; to++) { |
142 |
String escape = getEscape(src.charAt(to)); |
143 |
if (escape != null) { |
144 |
if (to != from) { |
145 |
out.write(src, from, to-from); |
146 |
} |
147 |
out.write(escape); |
148 |
from = to + 1; |
149 |
} |
150 |
} |
151 |
if (from != end) { |
152 |
out.write(src, from, end-from); |
153 |
} |
154 |
} |
155 |
|
156 |
/** |
157 |
* Copy the content of a Reader into the specified JSPWriter escaping characters if needed. |
158 |
* |
159 |
* @param src the Reader to read from |
160 |
* @param escapeXml if true, escape characters |
161 |
* @param out the JspWriter to emit to |
162 |
* @throws IOException if there was a problem emitting the content |
163 |
*/ |
164 |
public static void emit(Reader src, boolean escapeXml, JspWriter out) throws IOException { |
165 |
int bufferSize = out.getBufferSize(); |
166 |
if (bufferSize == 0) { |
167 |
bufferSize = 4096; |
168 |
} |
169 |
char[] buffer = new char[bufferSize]; |
170 |
int count; |
171 |
while ((count = src.read(buffer)) > 0) { |
172 |
if (escapeXml) { |
173 |
emit(buffer, 0, count, out); |
174 |
} else { |
175 |
out.write(buffer, 0, count); |
176 |
} |
177 |
} |
178 |
} |
179 |
|
180 |
/** |
181 |
* Emit escaped content into the specified JSPWriter. |
182 |
* |
183 |
* @param buffer characters to escape |
184 |
* @param from start position in the buffer |
185 |
* @param count number of characters to emit |
186 |
* @param out the JspWriter to emit to |
187 |
* @throws IOException if there was a problem emitting the content |
188 |
*/ |
189 |
public static void emit(char[] buffer, int from, int count, JspWriter out) throws IOException { |
190 |
int end = from + count; |
191 |
for (int to = from ; to < end; to++) { |
192 |
String escape = getEscape(buffer[to]); |
193 |
if (escape != null) { |
194 |
if (to != from) { |
195 |
out.write(buffer, from, to-from); |
196 |
} |
197 |
out.write(escape); |
198 |
from = to + 1; |
199 |
} |
200 |
} |
201 |
if (from != end) { |
202 |
out.write(buffer, from, end-from); |
203 |
} |
204 |
} |
205 |
} |