View Javadoc

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>&lt;c:out&gt;</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>&lt;</td><td>&amp;lt;</td></tr>
26   * <tr><td>&gt;</td><td>&amp;gt;</td></tr>
27   * <tr><td>&amp;</td><td>&amp;amp;</td></tr>
28   * <tr><td>&#039;</td><td>&amp;#039;</td></tr>
29   * <tr><td>&#034;</td><td>&amp;#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['<'] = "&lt;";
40          ESCAPES['>'] = "&gt;";
41          ESCAPES['&'] = "&amp;";
42          ESCAPES['\''] = "&#039;";
43          ESCAPES['"'] = "&#034;";
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  }