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 net.ramapuram.thomas.webapp.jsp;
18
19 /**
20 * Handles escaping of characters that could be interpreted as XML markup.
21 * <p>The specification for <code><c:out></code> defines the following
22 * character conversions to be applied:
23 * <table rules="all" frame="border">
24 * <tr><th>Character</th><th>Character Entity Code</th></tr>
25 * <tr><td><</td><td>&lt;</td></tr>
26 * <tr><td>></td><td>&gt;</td></tr>
27 * <tr><td>&</td><td>&amp;</td></tr>
28 * <tr><td>'</td><td>&#039;</td></tr>
29 * <tr><td>"</td><td>&#034;</td></tr>
30 * </table>
31 */
32 public class EscapeXml {
33
34 private static final String[] ESCAPES;
35
36 static {
37 int size = '>' + 1; // '>' is the largest escaped value
38 ESCAPES = new String[size];
39 ESCAPES['<'] = "<";
40 ESCAPES['>'] = ">";
41 ESCAPES['&'] = "&";
42 ESCAPES['\''] = "'";
43 ESCAPES['"'] = """;
44 }
45
46 private static String getEscape(char c) {
47 if (c < ESCAPES.length) {
48 return ESCAPES[c];
49 } else {
50 return null;
51 }
52 }
53
54 /**
55 * Escape a string.
56 *
57 * @param src
58 * the string to escape; must not be null
59 * @return the escaped string
60 */
61 public static String escape(String src) {
62 // first pass to determine the length of the buffer so we only allocate once
63 int length = 0;
64 for (int i = 0; i < src.length(); i++) {
65 char c = src.charAt(i);
66 String escape = getEscape(c);
67 if (escape != null) {
68 length += escape.length();
69 } else {
70 length += 1;
71 }
72 }
73
74 // skip copy if no escaping is needed
75 if (length == src.length()) {
76 return src;
77 }
78
79 // second pass to build the escaped string
80 StringBuilder buf = new StringBuilder(length);
81 for (int i = 0; i < src.length(); i++) {
82 char c = src.charAt(i);
83 String escape = getEscape(c);
84 if (escape != null) {
85 buf.append(escape);
86 } else {
87 buf.append(c);
88 }
89 }
90 return buf.toString();
91 }
92 }